1 // Copyright 2022 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use std::fs::File; 6 use std::io::Error; 7 use std::io::ErrorKind; 8 use std::io::Result; 9 10 use data_model::VolatileSlice; 11 12 /// A trait for flushing the contents of a file to disk. 13 /// This is equivalent to File's `sync_all` method, but 14 /// wrapped in a trait so that it can be implemented for 15 /// other types. 16 pub trait FileSync { 17 // Flush buffers related to this file to disk. fsync(&mut self) -> Result<()>18 fn fsync(&mut self) -> Result<()>; 19 } 20 21 impl FileSync for File { fsync(&mut self) -> Result<()>22 fn fsync(&mut self) -> Result<()> { 23 self.sync_all() 24 } 25 } 26 27 /// A trait for setting the size of a file. 28 /// This is equivalent to File's `set_len` method, but 29 /// wrapped in a trait so that it can be implemented for 30 /// other types. 31 pub trait FileSetLen { 32 // Set the size of this file. 33 // This is the moral equivalent of `ftruncate()`. set_len(&self, _len: u64) -> Result<()>34 fn set_len(&self, _len: u64) -> Result<()>; 35 } 36 37 impl FileSetLen for File { set_len(&self, len: u64) -> Result<()>38 fn set_len(&self, len: u64) -> Result<()> { 39 File::set_len(self, len) 40 } 41 } 42 43 /// A trait for allocating disk space in a sparse file. 44 /// This is equivalent to fallocate() with no special flags. 45 pub trait FileAllocate { 46 /// Allocate storage for the region of the file starting at `offset` and extending `len` bytes. allocate(&mut self, offset: u64, len: u64) -> Result<()>47 fn allocate(&mut self, offset: u64, len: u64) -> Result<()>; 48 } 49 50 /// A trait for getting the size of a file. 51 /// This is equivalent to File's metadata().len() method, 52 /// but wrapped in a trait so that it can be implemented for 53 /// other types. 54 pub trait FileGetLen { 55 /// Get the current length of the file in bytes. get_len(&self) -> Result<u64>56 fn get_len(&self) -> Result<u64>; 57 } 58 59 impl FileGetLen for File { get_len(&self) -> Result<u64>60 fn get_len(&self) -> Result<u64> { 61 Ok(self.metadata()?.len()) 62 } 63 } 64 65 /// A trait similar to `Read` and `Write`, but uses volatile memory as buffers. 66 pub trait FileReadWriteVolatile { 67 /// Read bytes from this file into the given slice, returning the number of bytes read on 68 /// success. read_volatile(&mut self, slice: VolatileSlice) -> Result<usize>69 fn read_volatile(&mut self, slice: VolatileSlice) -> Result<usize>; 70 71 /// Like `read_volatile`, except it reads to a slice of buffers. Data is copied to fill each 72 /// buffer in order, with the final buffer written to possibly being only partially filled. This 73 /// method must behave as a single call to `read_volatile` with the buffers concatenated would. 74 /// The default implementation calls `read_volatile` with either the first nonempty buffer 75 /// provided, or returns `Ok(0)` if none exists. read_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize>76 fn read_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize> { 77 bufs.iter() 78 .find(|b| b.size() > 0) 79 .map(|&b| self.read_volatile(b)) 80 .unwrap_or(Ok(0)) 81 } 82 83 /// Reads bytes from this into the given slice until all bytes in the slice are written, or an 84 /// error is returned. read_exact_volatile(&mut self, mut slice: VolatileSlice) -> Result<()>85 fn read_exact_volatile(&mut self, mut slice: VolatileSlice) -> Result<()> { 86 while slice.size() > 0 { 87 let bytes_read = self.read_volatile(slice)?; 88 if bytes_read == 0 { 89 return Err(Error::from(ErrorKind::UnexpectedEof)); 90 } 91 // Will panic if read_volatile read more bytes than we gave it, which would be worthy of 92 // a panic. 93 slice = slice.offset(bytes_read).unwrap(); 94 } 95 Ok(()) 96 } 97 98 /// Write bytes from the slice to the given file, returning the number of bytes written on 99 /// success. write_volatile(&mut self, slice: VolatileSlice) -> Result<usize>100 fn write_volatile(&mut self, slice: VolatileSlice) -> Result<usize>; 101 102 /// Like `write_volatile`, except that it writes from a slice of buffers. Data is copied from 103 /// each buffer in order, with the final buffer read from possibly being only partially 104 /// consumed. This method must behave as a call to `write_volatile` with the buffers 105 /// concatenated would. The default implementation calls `write_volatile` with either the first 106 /// nonempty buffer provided, or returns `Ok(0)` if none exists. write_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize>107 fn write_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize> { 108 bufs.iter() 109 .find(|b| b.size() > 0) 110 .map(|&b| self.write_volatile(b)) 111 .unwrap_or(Ok(0)) 112 } 113 114 /// Write bytes from the slice to the given file until all the bytes from the slice have been 115 /// written, or an error is returned. write_all_volatile(&mut self, mut slice: VolatileSlice) -> Result<()>116 fn write_all_volatile(&mut self, mut slice: VolatileSlice) -> Result<()> { 117 while slice.size() > 0 { 118 let bytes_written = self.write_volatile(slice)?; 119 if bytes_written == 0 { 120 return Err(Error::from(ErrorKind::WriteZero)); 121 } 122 // Will panic if read_volatile read more bytes than we gave it, which would be worthy of 123 // a panic. 124 slice = slice.offset(bytes_written).unwrap(); 125 } 126 Ok(()) 127 } 128 } 129 130 impl<'a, T: FileReadWriteVolatile + ?Sized> FileReadWriteVolatile for &'a mut T { read_volatile(&mut self, slice: VolatileSlice) -> Result<usize>131 fn read_volatile(&mut self, slice: VolatileSlice) -> Result<usize> { 132 (**self).read_volatile(slice) 133 } 134 read_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize>135 fn read_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize> { 136 (**self).read_vectored_volatile(bufs) 137 } 138 read_exact_volatile(&mut self, slice: VolatileSlice) -> Result<()>139 fn read_exact_volatile(&mut self, slice: VolatileSlice) -> Result<()> { 140 (**self).read_exact_volatile(slice) 141 } 142 write_volatile(&mut self, slice: VolatileSlice) -> Result<usize>143 fn write_volatile(&mut self, slice: VolatileSlice) -> Result<usize> { 144 (**self).write_volatile(slice) 145 } 146 write_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize>147 fn write_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize> { 148 (**self).write_vectored_volatile(bufs) 149 } 150 write_all_volatile(&mut self, slice: VolatileSlice) -> Result<()>151 fn write_all_volatile(&mut self, slice: VolatileSlice) -> Result<()> { 152 (**self).write_all_volatile(slice) 153 } 154 } 155 156 /// A trait similar to the unix `ReadExt` and `WriteExt` traits, but for volatile memory. 157 pub trait FileReadWriteAtVolatile { 158 /// Reads bytes from this file at `offset` into the given slice, returning the number of bytes 159 /// read on success. On Windows file pointer will update with the read, but on Linux the 160 /// file pointer will not change. read_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize>161 fn read_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize>; 162 163 /// Like `read_at_volatile`, except it reads to a slice of buffers. Data is copied to fill each 164 /// buffer in order, with the final buffer written to possibly being only partially filled. This 165 /// method must behave as a single call to `read_at_volatile` with the buffers concatenated 166 /// would. The default implementation calls `read_at_volatile` with either the first nonempty 167 /// buffer provided, or returns `Ok(0)` if none exists. 168 /// On Windows file pointer will update with the read, but on Linux the file pointer will not change. read_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>169 fn read_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> { 170 if let Some(&slice) = bufs.first() { 171 self.read_at_volatile(slice, offset) 172 } else { 173 Ok(0) 174 } 175 } 176 177 /// Reads bytes from this file at `offset` into the given slice until all bytes in the slice are 178 /// read, or an error is returned. On Windows file pointer will update with the read, but on Linux the 179 /// file pointer will not change. read_exact_at_volatile(&mut self, mut slice: VolatileSlice, mut offset: u64) -> Result<()>180 fn read_exact_at_volatile(&mut self, mut slice: VolatileSlice, mut offset: u64) -> Result<()> { 181 while slice.size() > 0 { 182 match self.read_at_volatile(slice, offset) { 183 Ok(0) => return Err(Error::from(ErrorKind::UnexpectedEof)), 184 Ok(n) => { 185 slice = slice.offset(n).unwrap(); 186 offset = offset.checked_add(n as u64).unwrap(); 187 } 188 Err(ref e) if e.kind() == ErrorKind::Interrupted => {} 189 Err(e) => return Err(e), 190 } 191 } 192 Ok(()) 193 } 194 195 /// Writes bytes to this file at `offset` from the given slice, returning the number of bytes 196 /// written on success. On Windows file pointer will update with the write, but on Linux the 197 /// file pointer will not change. write_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize>198 fn write_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize>; 199 200 /// Like `write_at_volatile`, except that it writes from a slice of buffers. Data is copied 201 /// from each buffer in order, with the final buffer read from possibly being only partially 202 /// consumed. This method must behave as a call to `write_at_volatile` with the buffers 203 /// concatenated would. The default implementation calls `write_at_volatile` with either the 204 /// first nonempty buffer provided, or returns `Ok(0)` if none exists. 205 /// On Windows file pointer will update with the write, but on Linux the file pointer will not change. write_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>206 fn write_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> { 207 if let Some(&slice) = bufs.first() { 208 self.write_at_volatile(slice, offset) 209 } else { 210 Ok(0) 211 } 212 } 213 214 /// Writes bytes to this file at `offset` from the given slice until all bytes in the slice 215 /// are written, or an error is returned. On Windows file pointer will update with the write, 216 /// but on Linux the file pointer will not change. write_all_at_volatile(&mut self, mut slice: VolatileSlice, mut offset: u64) -> Result<()>217 fn write_all_at_volatile(&mut self, mut slice: VolatileSlice, mut offset: u64) -> Result<()> { 218 while slice.size() > 0 { 219 match self.write_at_volatile(slice, offset) { 220 Ok(0) => return Err(Error::from(ErrorKind::WriteZero)), 221 Ok(n) => { 222 slice = slice.offset(n).unwrap(); 223 offset = offset.checked_add(n as u64).unwrap(); 224 } 225 Err(ref e) if e.kind() == ErrorKind::Interrupted => {} 226 Err(e) => return Err(e), 227 } 228 } 229 Ok(()) 230 } 231 } 232 233 impl<'a, T: FileReadWriteAtVolatile + ?Sized> FileReadWriteAtVolatile for &'a mut T { read_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize>234 fn read_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize> { 235 (**self).read_at_volatile(slice, offset) 236 } 237 read_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>238 fn read_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> { 239 (**self).read_vectored_at_volatile(bufs, offset) 240 } 241 read_exact_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<()>242 fn read_exact_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<()> { 243 (**self).read_exact_at_volatile(slice, offset) 244 } 245 write_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize>246 fn write_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize> { 247 (**self).write_at_volatile(slice, offset) 248 } 249 write_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>250 fn write_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> { 251 (**self).write_vectored_at_volatile(bufs, offset) 252 } 253 write_all_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<()>254 fn write_all_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<()> { 255 (**self).write_all_at_volatile(slice, offset) 256 } 257 } 258 259 #[cfg(test)] 260 mod tests { 261 use std::io::Read; 262 use std::io::Seek; 263 use std::io::SeekFrom; 264 use std::io::Write; 265 266 use tempfile::tempfile; 267 268 use super::*; 269 270 #[test] read_file() -> Result<()>271 fn read_file() -> Result<()> { 272 let mut f = tempfile()?; 273 f.write_all(b"AAAAAAAAAAbbbbbbbbbbAAAAA") 274 .expect("Failed to write bytes"); 275 f.seek(SeekFrom::Start(0))?; 276 277 let mut omem = [0u8; 30]; 278 let om = &mut omem[..]; 279 let buf = VolatileSlice::new(om); 280 f.read_volatile(buf).expect("read_volatile failed."); 281 282 f.seek(SeekFrom::Start(0))?; 283 284 let mut mem = [0u8; 30]; 285 let (m1, rest) = mem.split_at_mut(10); 286 let (m2, m3) = rest.split_at_mut(10); 287 let buf1 = VolatileSlice::new(m1); 288 let buf2 = VolatileSlice::new(m2); 289 let buf3 = VolatileSlice::new(m3); 290 let bufs = [buf1, buf2, buf3]; 291 292 f.read_vectored_volatile(&bufs) 293 .expect("read_vectored_volatile failed."); 294 295 assert_eq!(&mem[..], b"AAAAAAAAAAbbbbbbbbbbAAAAA\0\0\0\0\0"); 296 Ok(()) 297 } 298 299 #[test] write_file() -> Result<()>300 fn write_file() -> Result<()> { 301 let mut f = tempfile()?; 302 303 let mut omem = [0u8; 25]; 304 let om = &mut omem[..]; 305 let buf = VolatileSlice::new(om); 306 buf.write_bytes(65); 307 f.write_volatile(buf).expect("write_volatile failed."); 308 309 f.seek(SeekFrom::Start(0))?; 310 311 let mut filebuf = [0u8; 25]; 312 f.read_exact(&mut filebuf).expect("Failed to read filebuf"); 313 assert_eq!(&filebuf, b"AAAAAAAAAAAAAAAAAAAAAAAAA"); 314 Ok(()) 315 } 316 317 #[test] write_vectored_file() -> Result<()>318 fn write_vectored_file() -> Result<()> { 319 let mut f = tempfile()?; 320 321 let mut mem = [0u8; 30]; 322 let (m1, rest) = mem.split_at_mut(10); 323 let (m2, m3) = rest.split_at_mut(10); 324 let buf1 = VolatileSlice::new(m1); 325 let buf2 = VolatileSlice::new(m2); 326 let buf3 = VolatileSlice::new(m3); 327 buf1.write_bytes(65); 328 buf2.write_bytes(98); 329 buf3.write_bytes(65); 330 let bufs = [buf1, buf2, buf3]; 331 f.write_vectored_volatile(&bufs) 332 .expect("write_vectored_volatile failed."); 333 334 f.seek(SeekFrom::Start(0))?; 335 336 let mut filebuf = [0u8; 30]; 337 f.read_exact(&mut filebuf).expect("Failed to read filebuf."); 338 assert_eq!(&filebuf, b"AAAAAAAAAAbbbbbbbbbbAAAAAAAAAA"); 339 Ok(()) 340 } 341 342 #[test] read_at_file() -> Result<()>343 fn read_at_file() -> Result<()> { 344 let mut f = tempfile()?; 345 f.write_all(b"AAAAAAAAAAbbbbbbbbbbAAAAA") 346 .expect("Failed to write bytes."); 347 348 let mut omem = [0u8; 20]; 349 let om = &mut omem[..]; 350 let buf = VolatileSlice::new(om); 351 f.read_at_volatile(buf, 10) 352 .expect("read_at_volatile failed."); 353 354 assert_eq!(om, b"bbbbbbbbbbAAAAA\0\0\0\0\0"); 355 356 let mut mem = [0u8; 20]; 357 let (m1, m2) = mem.split_at_mut(10); 358 let buf1 = VolatileSlice::new(m1); 359 let buf2 = VolatileSlice::new(m2); 360 let bufs = [buf1, buf2]; 361 362 f.read_vectored_at_volatile(&bufs, 10) 363 .expect("read_vectored_at_volatile failed."); 364 365 assert_eq!(&mem[..], b"bbbbbbbbbbAAAAA\0\0\0\0\0"); 366 Ok(()) 367 } 368 369 #[test] write_at_file() -> Result<()>370 fn write_at_file() -> Result<()> { 371 let mut f = tempfile()?; 372 f.write_all(b"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ") 373 .expect("Failed to write bytes"); 374 375 let mut omem = [0u8; 15]; 376 let om = &mut omem[..]; 377 let buf = VolatileSlice::new(om); 378 buf.write_bytes(65); 379 f.write_at_volatile(buf, 10) 380 .expect("write_at_volatile failed."); 381 382 f.seek(SeekFrom::Start(0))?; 383 384 let mut filebuf = [0u8; 30]; 385 f.read_exact(&mut filebuf).expect("Failed to read filebuf."); 386 assert_eq!(&filebuf, b"ZZZZZZZZZZAAAAAAAAAAAAAAAZZZZZ"); 387 Ok(()) 388 } 389 390 #[test] write_vectored_at_file() -> Result<()>391 fn write_vectored_at_file() -> Result<()> { 392 let mut f = tempfile()?; 393 f.write_all(b"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ") 394 .expect("Failed to write bytes"); 395 396 let mut mem = [0u8; 30]; 397 let (m1, m2) = mem.split_at_mut(10); 398 let buf1 = VolatileSlice::new(m1); 399 let buf2 = VolatileSlice::new(m2); 400 buf1.write_bytes(65); 401 buf2.write_bytes(98); 402 let bufs = [buf1, buf2]; 403 f.write_vectored_at_volatile(&bufs, 10) 404 .expect("write_vectored_at_volatile failed."); 405 406 f.seek(SeekFrom::Start(0))?; 407 408 let mut filebuf = [0u8; 30]; 409 f.read_exact(&mut filebuf).expect("Failed to read filebuf."); 410 assert_eq!(&filebuf, b"ZZZZZZZZZZAAAAAAAAAAbbbbbbbbbb"); 411 Ok(()) 412 } 413 } 414