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