1 // Copyright 2019 Intel Corporation. All Rights Reserved.
2 //
3 // Copyright 2018 The Chromium OS Authors. All rights reserved.
4 //
5 // SPDX-License-Identifier: BSD-3-Clause
6 
7 //! Traits for handling file synchronization and length.
8 
9 use std::fs::File;
10 use std::io::Result;
11 
12 /// A trait for flushing the contents of a file to disk.
13 ///
14 /// This is equivalent to
15 /// [`std::fd::File::sync_all`](https://doc.rust-lang.org/std/fs/struct.File.html#method.sync_all)
16 /// method, but wrapped in a trait so that it can be implemented for other types.
17 pub trait FileSync {
18     /// Flush buffers related to this file to disk.
fsync(&mut self) -> Result<()>19     fn fsync(&mut self) -> Result<()>;
20 }
21 
22 impl FileSync for File {
fsync(&mut self) -> Result<()>23     fn fsync(&mut self) -> Result<()> {
24         self.sync_all()
25     }
26 }
27 
28 /// A trait for setting the size of a file.
29 ///
30 /// This is equivalent to
31 /// [`std::fd::File::set_len`](https://doc.rust-lang.org/std/fs/struct.File.html#method.set_len)
32 /// method, but wrapped in a trait so that it can be implemented for other types.
33 pub trait FileSetLen {
34     /// Set the size of this file.
35     ///
36     /// This is the moral equivalent of
37     /// [`ftruncate`](http://man7.org/linux/man-pages/man3/ftruncate.3p.html).
38     ///
39     /// # Arguments
40     ///
41     /// * `len`: the size to set for file.
set_len(&self, len: u64) -> Result<()>42     fn set_len(&self, len: u64) -> Result<()>;
43 }
44 
45 impl FileSetLen for File {
set_len(&self, len: u64) -> Result<()>46     fn set_len(&self, len: u64) -> Result<()> {
47         File::set_len(self, len)
48     }
49 }
50 
51 #[cfg(test)]
52 mod tests {
53     use super::*;
54     use std::fs::OpenOptions;
55     use std::io::{Seek, SeekFrom, Write};
56     use std::path::PathBuf;
57 
58     use crate::tempdir::TempDir;
59 
60     #[test]
test_fsync()61     fn test_fsync() {
62         let tempdir = TempDir::new_with_prefix("/tmp/fsync_test").unwrap();
63         let mut path = PathBuf::from(tempdir.as_path());
64         path.push("file");
65         let mut f = OpenOptions::new()
66             .read(true)
67             .write(true)
68             .create(true)
69             .open(&path)
70             .unwrap();
71         f.write_all(b"Hello, world!").unwrap();
72         f.fsync().unwrap();
73         assert_eq!(f.metadata().unwrap().len(), 13);
74     }
75 
76     #[test]
test_set_len()77     fn test_set_len() {
78         let tempdir = TempDir::new_with_prefix("/tmp/set_len_test").unwrap();
79         let mut path = PathBuf::from(tempdir.as_path());
80         path.push("file");
81         let mut f = OpenOptions::new()
82             .read(true)
83             .write(true)
84             .create(true)
85             .open(&path)
86             .unwrap();
87         f.set_len(10).unwrap();
88         assert_eq!(f.seek(SeekFrom::End(0)).unwrap(), 10);
89     }
90 
91     #[test]
test_set_len_fails_when_file_not_opened_for_writing()92     fn test_set_len_fails_when_file_not_opened_for_writing() {
93         let tempdir = TempDir::new_with_prefix("/tmp/set_len_test").unwrap();
94         let mut path = PathBuf::from(tempdir.as_path());
95         path.push("file");
96         File::create(path.clone()).unwrap();
97         let f = OpenOptions::new().read(true).open(&path).unwrap();
98         let result = f.set_len(10);
99         assert!(result.is_err());
100     }
101 }
102