Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/base/src/file_traits.rs
5394 views
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.
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.
21
fn fdatasync(&self) -> Result<()>;
22
}
23
24
impl FileSync for File {
25
fn fsync(&self) -> Result<()> {
26
self.sync_all()
27
}
28
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()`.
41
fn set_len(&self, _len: u64) -> Result<()>;
42
}
43
44
impl FileSetLen for File {
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.
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.
63
fn get_len(&self) -> Result<u64>;
64
}
65
66
impl FileGetLen for File {
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.
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.
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.
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.
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.
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.
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<T: FileReadWriteVolatile + ?Sized> FileReadWriteVolatile for &mut T {
138
fn read_volatile(&mut self, slice: VolatileSlice) -> Result<usize> {
139
(**self).read_volatile(slice)
140
}
141
142
fn read_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize> {
143
(**self).read_vectored_volatile(bufs)
144
}
145
146
fn read_exact_volatile(&mut self, slice: VolatileSlice) -> Result<()> {
147
(**self).read_exact_volatile(slice)
148
}
149
150
fn write_volatile(&mut self, slice: VolatileSlice) -> Result<usize> {
151
(**self).write_volatile(slice)
152
}
153
154
fn write_vectored_volatile(&mut self, bufs: &[VolatileSlice]) -> Result<usize> {
155
(**self).write_vectored_volatile(bufs)
156
}
157
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.
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.
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.
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.
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.
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.
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<T: FileReadWriteAtVolatile + ?Sized> FileReadWriteAtVolatile for &mut T {
243
fn read_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize> {
244
(**self).read_at_volatile(slice, offset)
245
}
246
247
fn read_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
248
(**self).read_vectored_at_volatile(bufs, offset)
249
}
250
251
fn read_exact_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<()> {
252
(**self).read_exact_at_volatile(slice, offset)
253
}
254
255
fn write_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize> {
256
(**self).write_at_volatile(slice, offset)
257
}
258
259
fn write_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
260
(**self).write_vectored_at_volatile(bufs, offset)
261
}
262
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<T: FileReadWriteAtVolatile + ?Sized> FileReadWriteAtVolatile for &T {
269
fn read_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize> {
270
(**self).read_at_volatile(slice, offset)
271
}
272
273
fn read_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
274
(**self).read_vectored_at_volatile(bufs, offset)
275
}
276
277
fn read_exact_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<()> {
278
(**self).read_exact_at_volatile(slice, offset)
279
}
280
281
fn write_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize> {
282
(**self).write_at_volatile(slice, offset)
283
}
284
285
fn write_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
286
(**self).write_vectored_at_volatile(bufs, offset)
287
}
288
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]
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]
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]
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]
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]
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]
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
450