Nothing to see here, move along
at main 224 lines 6.5 kB view raw
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}