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