Nothing to see here, move along
1use crate::cap::{CapError, FsCap, FsRights};
2
3const MAX_HANDLES_PER_CLIENT: usize = 64;
4const MAX_CLIENTS: usize = 64;
5
6#[derive(Debug, Clone, Copy)]
7pub struct HandleEntry {
8 pub object_id: u64,
9 pub generation: u64,
10 pub rights: FsRights,
11 pub cursor_offset: u64,
12 pub inode_block: u64,
13 pub occupied: bool,
14}
15
16impl HandleEntry {
17 const EMPTY: Self = Self {
18 object_id: 0,
19 generation: 0,
20 rights: FsRights::EMPTY,
21 cursor_offset: 0,
22 inode_block: 0,
23 occupied: false,
24 };
25
26 pub fn to_cap(self) -> FsCap {
27 FsCap::new(self.object_id, self.generation, self.rights)
28 }
29}
30
31pub struct ClientHandleTable {
32 handles: [HandleEntry; MAX_HANDLES_PER_CLIENT],
33}
34
35impl ClientHandleTable {
36 const fn new() -> Self {
37 Self {
38 handles: [HandleEntry::EMPTY; MAX_HANDLES_PER_CLIENT],
39 }
40 }
41
42 pub fn allocate(
43 &mut self,
44 object_id: u64,
45 generation: u64,
46 rights: FsRights,
47 inode_block: u64,
48 ) -> Result<u8, CapError> {
49 (0..MAX_HANDLES_PER_CLIENT as u8)
50 .find(|&i| !self.handles[i as usize].occupied)
51 .inspect(|&idx| {
52 self.handles[idx as usize] = HandleEntry {
53 object_id,
54 generation,
55 rights,
56 cursor_offset: 0,
57 inode_block,
58 occupied: true,
59 };
60 })
61 .ok_or(CapError::HandleTableFull)
62 }
63
64 pub fn get(&self, handle: u8) -> Result<&HandleEntry, CapError> {
65 match (handle as usize) < MAX_HANDLES_PER_CLIENT {
66 true => match self.handles[handle as usize].occupied {
67 true => Ok(&self.handles[handle as usize]),
68 false => Err(CapError::InvalidHandle),
69 },
70 false => Err(CapError::InvalidHandle),
71 }
72 }
73
74 pub fn get_mut(&mut self, handle: u8) -> Result<&mut HandleEntry, CapError> {
75 match (handle as usize) < MAX_HANDLES_PER_CLIENT {
76 true => match self.handles[handle as usize].occupied {
77 true => Ok(&mut self.handles[handle as usize]),
78 false => Err(CapError::InvalidHandle),
79 },
80 false => Err(CapError::InvalidHandle),
81 }
82 }
83
84 pub fn release(&mut self, handle: u8) -> Result<(), CapError> {
85 match (handle as usize) < MAX_HANDLES_PER_CLIENT {
86 true => match self.handles[handle as usize].occupied {
87 true => {
88 self.handles[handle as usize] = HandleEntry::EMPTY;
89 Ok(())
90 }
91 false => Err(CapError::InvalidHandle),
92 },
93 false => Err(CapError::InvalidHandle),
94 }
95 }
96
97 pub fn validate(&self, handle: u8, required: FsRights) -> Result<&HandleEntry, CapError> {
98 let entry = self.get(handle)?;
99 match entry.rights.contains(required) {
100 true => Ok(entry),
101 false => Err(CapError::InsufficientRights),
102 }
103 }
104
105 pub fn validate_generation(
106 &self,
107 handle: u8,
108 required: FsRights,
109 current_generation: u64,
110 ) -> Result<&HandleEntry, CapError> {
111 let entry = self.validate(handle, required)?;
112 match entry.generation == current_generation {
113 true => Ok(entry),
114 false => Err(CapError::StaleGeneration),
115 }
116 }
117}
118
119pub struct HandleTableSet {
120 clients: [ClientHandleTable; MAX_CLIENTS],
121}
122
123impl HandleTableSet {
124 pub const fn new() -> Self {
125 Self {
126 clients: [const { ClientHandleTable::new() }; MAX_CLIENTS],
127 }
128 }
129}
130
131impl Default for HandleTableSet {
132 fn default() -> Self {
133 Self::new()
134 }
135}
136
137impl HandleTableSet {
138 pub fn client(&self, pid: u16) -> Option<&ClientHandleTable> {
139 match (pid as usize) < MAX_CLIENTS {
140 true => Some(&self.clients[pid as usize]),
141 false => None,
142 }
143 }
144
145 pub fn client_mut(&mut self, pid: u16) -> Option<&mut ClientHandleTable> {
146 match (pid as usize) < MAX_CLIENTS {
147 true => Some(&mut self.clients[pid as usize]),
148 false => None,
149 }
150 }
151
152 pub fn install_root_handle(
153 &mut self,
154 pid: u16,
155 root_object_id: u64,
156 root_generation: u64,
157 root_inode_block: u64,
158 ) -> Result<u8, CapError> {
159 self.client_mut(pid)
160 .ok_or(CapError::InvalidHandle)?
161 .allocate(
162 root_object_id,
163 root_generation,
164 FsRights::ALL,
165 root_inode_block,
166 )
167 }
168}
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173
174 #[test]
175 fn allocate_and_get() {
176 let mut table = ClientHandleTable::new();
177 let h = table.allocate(42, 1, FsRights::ALL, 100).unwrap();
178 let entry = table.get(h).unwrap();
179 assert_eq!(entry.object_id, 42);
180 assert_eq!(entry.generation, 1);
181 assert_eq!(entry.inode_block, 100);
182 }
183
184 #[test]
185 fn release_and_reuse() {
186 let mut table = ClientHandleTable::new();
187 let h = table.allocate(1, 1, FsRights::ALL, 10).unwrap();
188 table.release(h).unwrap();
189 assert!(table.get(h).is_err());
190 let h2 = table.allocate(2, 2, FsRights::ALL, 20).unwrap();
191 assert_eq!(h, h2);
192 }
193
194 #[test]
195 fn validate_checks_rights() {
196 let mut table = ClientHandleTable::new();
197 let h = table.allocate(1, 1, FsRights::READ, 10).unwrap();
198 assert!(table.validate(h, FsRights::READ).is_ok());
199 assert!(table.validate(h, FsRights::WRITE).is_err());
200 }
201
202 #[test]
203 fn table_full_returns_error() {
204 let mut table = ClientHandleTable::new();
205 (0..MAX_HANDLES_PER_CLIENT as u8).for_each(|i| {
206 table
207 .allocate(i as u64, 1, FsRights::ALL, i as u64)
208 .unwrap();
209 });
210 assert!(matches!(
211 table.allocate(999, 1, FsRights::ALL, 999),
212 Err(CapError::HandleTableFull)
213 ));
214 }
215
216 #[test]
217 fn handle_set_install_root() {
218 let mut set = HandleTableSet::new();
219 let h = set.install_root_handle(0, 1, 1, 5).unwrap();
220 let entry = set.client(0).unwrap().get(h).unwrap();
221 assert_eq!(entry.object_id, 1);
222 assert!(entry.rights.contains(FsRights::ALL));
223 }
224}