1 // Copyright 2019 Intel Corporation. All Rights Reserved.
2 //
3 // Copyright 2017 The Chromium OS Authors. All rights reserved.
4 //
5 // SPDX-License-Identifier: BSD-3-Clause
6 
7 //! Enum and function for dealing with an allocated disk space
8 //! by [`fallocate`](http://man7.org/linux/man-pages/man2/fallocate.2.html).
9 
10 use std::os::unix::io::AsRawFd;
11 
12 use crate::errno::{errno_result, Error, Result};
13 
14 /// Operation to be performed on a given range when calling [`fallocate`]
15 ///
16 /// [`fallocate`]: fn.fallocate.html
17 #[derive(Debug)]
18 pub enum FallocateMode {
19     /// Deallocating file space.
20     PunchHole,
21     /// Zeroing file space.
22     ZeroRange,
23 }
24 
25 /// A safe wrapper for [`fallocate`](http://man7.org/linux/man-pages/man2/fallocate.2.html).
26 ///
27 /// Manipulate the file space with specified operation parameters.
28 ///
29 /// # Arguments
30 ///
31 /// * `file`: the file to be manipulate.
32 /// * `mode`: specify the operation to be performed on the given range.
33 /// * `keep_size`: file size won't be changed even if `offset` + `len` is greater
34 /// than the file size.
35 /// * `offset`: the position that manipulates the file from.
36 /// * `size`: the bytes of the operation range.
37 ///
38 /// # Examples
39 ///
40 /// ```
41 /// extern crate vmm_sys_util;
42 /// # use std::fs::OpenOptions;
43 /// # use std::path::PathBuf;
44 /// use vmm_sys_util::fallocate::{fallocate, FallocateMode};
45 /// use vmm_sys_util::tempdir::TempDir;
46 ///
47 /// let tempdir = TempDir::new_with_prefix("/tmp/fallocate_test").unwrap();
48 /// let mut path = PathBuf::from(tempdir.as_path());
49 /// path.push("file");
50 /// let mut f = OpenOptions::new()
51 ///     .read(true)
52 ///     .write(true)
53 ///     .create(true)
54 ///     .open(&path)
55 ///     .unwrap();
56 /// fallocate(&f, FallocateMode::PunchHole, true, 0, 1).unwrap();
57 /// ```
fallocate( file: &dyn AsRawFd, mode: FallocateMode, keep_size: bool, offset: u64, len: u64, ) -> Result<()>58 pub fn fallocate(
59     file: &dyn AsRawFd,
60     mode: FallocateMode,
61     keep_size: bool,
62     offset: u64,
63     len: u64,
64 ) -> Result<()> {
65     let offset = if offset > libc::off64_t::max_value() as u64 {
66         return Err(Error::new(libc::EINVAL));
67     } else {
68         offset as libc::off64_t
69     };
70 
71     let len = if len > libc::off64_t::max_value() as u64 {
72         return Err(Error::new(libc::EINVAL));
73     } else {
74         len as libc::off64_t
75     };
76 
77     let mut mode = match mode {
78         FallocateMode::PunchHole => libc::FALLOC_FL_PUNCH_HOLE,
79         FallocateMode::ZeroRange => libc::FALLOC_FL_ZERO_RANGE,
80     };
81 
82     if keep_size {
83         mode |= libc::FALLOC_FL_KEEP_SIZE;
84     }
85 
86     // SAFETY: Safe since we pass in a valid fd and fallocate mode, validate offset and len,
87     // and check the return value.
88     let ret = unsafe { libc::fallocate64(file.as_raw_fd(), mode, offset, len) };
89     if ret < 0 {
90         errno_result()
91     } else {
92         Ok(())
93     }
94 }
95