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(&mut self) -> Result<()>17 fn fsync(&mut 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(&mut self) -> Result<()>21 fn fdatasync(&mut self) -> Result<()>; 22 } 23 24 impl FileSync for File { fsync(&mut self) -> Result<()>25 fn fsync(&mut self) -> Result<()> { 26 self.sync_all() 27 } 28 fdatasync(&mut self) -> Result<()>29 fn fdatasync(&mut 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(&mut self, offset: u64, len: u64) -> Result<()>54 fn allocate(&mut 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(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize>168 fn read_at_volatile(&mut 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(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>177 fn read_vectored_at_volatile(&mut 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(&mut self, mut slice: VolatileSlice, mut offset: u64) -> Result<()>188 fn read_exact_at_volatile(&mut 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(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize>206 fn write_at_volatile(&mut 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(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>215 fn write_vectored_at_volatile(&mut 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(&mut self, mut slice: VolatileSlice, mut offset: u64) -> Result<()>226 fn write_all_at_volatile(&mut 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(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize>243 fn read_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize> { 244 (**self).read_at_volatile(slice, offset) 245 } 246 read_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>247 fn read_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> { 248 (**self).read_vectored_at_volatile(bufs, offset) 249 } 250 read_exact_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<()>251 fn read_exact_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<()> { 252 (**self).read_exact_at_volatile(slice, offset) 253 } 254 write_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize>255 fn write_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<usize> { 256 (**self).write_at_volatile(slice, offset) 257 } 258 write_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize>259 fn write_vectored_at_volatile(&mut self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> { 260 (**self).write_vectored_at_volatile(bufs, offset) 261 } 262 write_all_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<()>263 fn write_all_at_volatile(&mut self, slice: VolatileSlice, offset: u64) -> Result<()> { 264 (**self).write_all_at_volatile(slice, offset) 265 } 266 } 267 268 #[cfg(test)] 269 mod tests { 270 use std::io::Read; 271 use std::io::Seek; 272 use std::io::SeekFrom; 273 use std::io::Write; 274 275 use tempfile::tempfile; 276 277 use super::*; 278 279 #[test] read_file() -> Result<()>280 fn read_file() -> Result<()> { 281 let mut f = tempfile()?; 282 f.write_all(b"AAAAAAAAAAbbbbbbbbbbAAAAA") 283 .expect("Failed to write bytes"); 284 f.seek(SeekFrom::Start(0))?; 285 286 let mut omem = [0u8; 30]; 287 let om = &mut omem[..]; 288 let buf = VolatileSlice::new(om); 289 f.read_volatile(buf).expect("read_volatile failed."); 290 291 f.seek(SeekFrom::Start(0))?; 292 293 let mut mem = [0u8; 30]; 294 let (m1, rest) = mem.split_at_mut(10); 295 let (m2, m3) = rest.split_at_mut(10); 296 let buf1 = VolatileSlice::new(m1); 297 let buf2 = VolatileSlice::new(m2); 298 let buf3 = VolatileSlice::new(m3); 299 let bufs = [buf1, buf2, buf3]; 300 301 f.read_vectored_volatile(&bufs) 302 .expect("read_vectored_volatile failed."); 303 304 assert_eq!(&mem[..], b"AAAAAAAAAAbbbbbbbbbbAAAAA\0\0\0\0\0"); 305 Ok(()) 306 } 307 308 #[test] write_file() -> Result<()>309 fn write_file() -> Result<()> { 310 let mut f = tempfile()?; 311 312 let mut omem = [0u8; 25]; 313 let om = &mut omem[..]; 314 let buf = VolatileSlice::new(om); 315 buf.write_bytes(65); 316 f.write_volatile(buf).expect("write_volatile failed."); 317 318 f.seek(SeekFrom::Start(0))?; 319 320 let mut filebuf = [0u8; 25]; 321 f.read_exact(&mut filebuf).expect("Failed to read filebuf"); 322 assert_eq!(&filebuf, b"AAAAAAAAAAAAAAAAAAAAAAAAA"); 323 Ok(()) 324 } 325 326 #[test] write_vectored_file() -> Result<()>327 fn write_vectored_file() -> Result<()> { 328 let mut f = tempfile()?; 329 330 let mut mem = [0u8; 30]; 331 let (m1, rest) = mem.split_at_mut(10); 332 let (m2, m3) = rest.split_at_mut(10); 333 let buf1 = VolatileSlice::new(m1); 334 let buf2 = VolatileSlice::new(m2); 335 let buf3 = VolatileSlice::new(m3); 336 buf1.write_bytes(65); 337 buf2.write_bytes(98); 338 buf3.write_bytes(65); 339 let bufs = [buf1, buf2, buf3]; 340 f.write_vectored_volatile(&bufs) 341 .expect("write_vectored_volatile failed."); 342 343 f.seek(SeekFrom::Start(0))?; 344 345 let mut filebuf = [0u8; 30]; 346 f.read_exact(&mut filebuf).expect("Failed to read filebuf."); 347 assert_eq!(&filebuf, b"AAAAAAAAAAbbbbbbbbbbAAAAAAAAAA"); 348 Ok(()) 349 } 350 351 #[test] read_at_file() -> Result<()>352 fn read_at_file() -> Result<()> { 353 let mut f = tempfile()?; 354 f.write_all(b"AAAAAAAAAAbbbbbbbbbbAAAAA") 355 .expect("Failed to write bytes."); 356 357 let mut omem = [0u8; 20]; 358 let om = &mut omem[..]; 359 let buf = VolatileSlice::new(om); 360 f.read_at_volatile(buf, 10) 361 .expect("read_at_volatile failed."); 362 363 assert_eq!(om, b"bbbbbbbbbbAAAAA\0\0\0\0\0"); 364 365 let mut mem = [0u8; 20]; 366 let (m1, m2) = mem.split_at_mut(10); 367 let buf1 = VolatileSlice::new(m1); 368 let buf2 = VolatileSlice::new(m2); 369 let bufs = [buf1, buf2]; 370 371 f.read_vectored_at_volatile(&bufs, 10) 372 .expect("read_vectored_at_volatile failed."); 373 374 assert_eq!(&mem[..], b"bbbbbbbbbbAAAAA\0\0\0\0\0"); 375 Ok(()) 376 } 377 378 #[test] write_at_file() -> Result<()>379 fn write_at_file() -> Result<()> { 380 let mut f = tempfile()?; 381 f.write_all(b"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ") 382 .expect("Failed to write bytes"); 383 384 let mut omem = [0u8; 15]; 385 let om = &mut omem[..]; 386 let buf = VolatileSlice::new(om); 387 buf.write_bytes(65); 388 f.write_at_volatile(buf, 10) 389 .expect("write_at_volatile failed."); 390 391 f.seek(SeekFrom::Start(0))?; 392 393 let mut filebuf = [0u8; 30]; 394 f.read_exact(&mut filebuf).expect("Failed to read filebuf."); 395 assert_eq!(&filebuf, b"ZZZZZZZZZZAAAAAAAAAAAAAAAZZZZZ"); 396 Ok(()) 397 } 398 399 #[test] write_vectored_at_file() -> Result<()>400 fn write_vectored_at_file() -> Result<()> { 401 let mut f = tempfile()?; 402 f.write_all(b"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ") 403 .expect("Failed to write bytes"); 404 405 let mut mem = [0u8; 30]; 406 let (m1, m2) = mem.split_at_mut(10); 407 let buf1 = VolatileSlice::new(m1); 408 let buf2 = VolatileSlice::new(m2); 409 buf1.write_bytes(65); 410 buf2.write_bytes(98); 411 let bufs = [buf1, buf2]; 412 f.write_vectored_at_volatile(&bufs, 10) 413 .expect("write_vectored_at_volatile failed."); 414 415 f.seek(SeekFrom::Start(0))?; 416 417 let mut filebuf = [0u8; 30]; 418 f.read_exact(&mut filebuf).expect("Failed to read filebuf."); 419 assert_eq!(&filebuf, b"ZZZZZZZZZZAAAAAAAAAAbbbbbbbbbb"); 420 Ok(()) 421 } 422 } 423