// Copyright 2019 Intel Corporation. All Rights Reserved. // // Copyright 2017 The Chromium OS Authors. All rights reserved. // // SPDX-License-Identifier: BSD-3-Clause //! Enum and function for dealing with an allocated disk space //! by [`fallocate`](http://man7.org/linux/man-pages/man2/fallocate.2.html). use std::os::unix::io::AsRawFd; use crate::errno::{errno_result, Error, Result}; /// Operation to be performed on a given range when calling [`fallocate`] /// /// [`fallocate`]: fn.fallocate.html #[derive(Debug)] pub enum FallocateMode { /// Deallocating file space. PunchHole, /// Zeroing file space. ZeroRange, } /// A safe wrapper for [`fallocate`](http://man7.org/linux/man-pages/man2/fallocate.2.html). /// /// Manipulate the file space with specified operation parameters. /// /// # Arguments /// /// * `file`: the file to be manipulate. /// * `mode`: specify the operation to be performed on the given range. /// * `keep_size`: file size won't be changed even if `offset` + `len` is greater /// than the file size. /// * `offset`: the position that manipulates the file from. /// * `size`: the bytes of the operation range. /// /// # Examples /// /// ``` /// extern crate vmm_sys_util; /// # use std::fs::OpenOptions; /// # use std::path::PathBuf; /// use vmm_sys_util::fallocate::{fallocate, FallocateMode}; /// use vmm_sys_util::tempdir::TempDir; /// /// let tempdir = TempDir::new_with_prefix("/tmp/fallocate_test").unwrap(); /// let mut path = PathBuf::from(tempdir.as_path()); /// path.push("file"); /// let mut f = OpenOptions::new() /// .read(true) /// .write(true) /// .create(true) /// .open(&path) /// .unwrap(); /// fallocate(&f, FallocateMode::PunchHole, true, 0, 1).unwrap(); /// ``` pub fn fallocate( file: &dyn AsRawFd, mode: FallocateMode, keep_size: bool, offset: u64, len: u64, ) -> Result<()> { let offset = if offset > libc::off64_t::max_value() as u64 { return Err(Error::new(libc::EINVAL)); } else { offset as libc::off64_t }; let len = if len > libc::off64_t::max_value() as u64 { return Err(Error::new(libc::EINVAL)); } else { len as libc::off64_t }; let mut mode = match mode { FallocateMode::PunchHole => libc::FALLOC_FL_PUNCH_HOLE, FallocateMode::ZeroRange => libc::FALLOC_FL_ZERO_RANGE, }; if keep_size { mode |= libc::FALLOC_FL_KEEP_SIZE; } // SAFETY: Safe since we pass in a valid fd and fallocate mode, validate offset and len, // and check the return value. let ret = unsafe { libc::fallocate64(file.as_raw_fd(), mode, offset, len) }; if ret < 0 { errno_result() } else { Ok(()) } }