vmm_sys_util/unix/
file_traits.rs

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
9use std::fs::File;
10use 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.
17pub trait FileSync {
18    /// Flush buffers related to this file to disk.
19    fn fsync(&mut self) -> Result<()>;
20}
21
22impl FileSync for File {
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.
33pub 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.
42    fn set_len(&self, len: u64) -> Result<()>;
43}
44
45impl FileSetLen for File {
46    fn set_len(&self, len: u64) -> Result<()> {
47        File::set_len(self, len)
48    }
49}
50
51#[cfg(test)]
52mod 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]
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            .truncate(true)
70            .open(&path)
71            .unwrap();
72        f.write_all(b"Hello, world!").unwrap();
73        f.fsync().unwrap();
74        assert_eq!(f.metadata().unwrap().len(), 13);
75    }
76
77    #[test]
78    fn test_set_len() {
79        let tempdir = TempDir::new_with_prefix("/tmp/set_len_test").unwrap();
80        let mut path = PathBuf::from(tempdir.as_path());
81        path.push("file");
82        let mut f = OpenOptions::new()
83            .read(true)
84            .write(true)
85            .create(true)
86            .truncate(true)
87            .open(&path)
88            .unwrap();
89        f.set_len(10).unwrap();
90        assert_eq!(f.seek(SeekFrom::End(0)).unwrap(), 10);
91    }
92
93    #[test]
94    fn test_set_len_fails_when_file_not_opened_for_writing() {
95        let tempdir = TempDir::new_with_prefix("/tmp/set_len_test").unwrap();
96        let mut path = PathBuf::from(tempdir.as_path());
97        path.push("file");
98        File::create(path.clone()).unwrap();
99        let f = OpenOptions::new().read(true).open(&path).unwrap();
100        let result = f.set_len(10);
101        assert!(result.is_err());
102    }
103}