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}