vmm_sys_util/linux/
fallocate.rs

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
10use std::os::unix::io::AsRawFd;
11
12use 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)]
18pub 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/// ```
58pub 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}