diff --git a/CHANGELOG.md b/CHANGELOG.md index af2069a0cb..74ecba0b9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] - ReleaseDate ### Added +- Added `posix_fallocate`. + ([#1105](https://github.com/nix-rust/nix/pull/1105)) + - Implemented `Default` for `FdSet` ([#1107](https://github.com/nix-rust/nix/pull/1107)) diff --git a/src/fcntl.rs b/src/fcntl.rs index 2cb7f50575..7d745b068b 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -505,3 +505,24 @@ mod posix_fadvise { Errno::result(res) } } + +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + any(target_os = "wasi", target_env = "wasi"), + target_os = "freebsd" +))] +pub fn posix_fallocate( + fd: RawFd, + offset: libc::off_t, + len: libc::off_t +) -> Result<()> { + let res = unsafe { libc::posix_fallocate(fd, offset, len) }; + match Errno::result(res) { + Err(err) => Err(err), + Ok(0) => Ok(()), + Ok(errno) => Err(crate::Error::Sys(Errno::from_i32(errno))), + } +} diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index 1bcf12cb5b..38a1e7b95a 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -231,3 +231,60 @@ mod test_posix_fadvise { assert_eq!(errno, Errno::ESPIPE as i32); } } + +#[cfg(any(target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "fuchsia", + any(target_os = "wasi", target_env = "wasi"), + target_os = "freebsd"))] +mod test_posix_fallocate { + + use tempfile::NamedTempFile; + use std::{io::Read, os::unix::io::{RawFd, AsRawFd}}; + use nix::errno::Errno; + use nix::fcntl::*; + use nix::unistd::pipe; + + #[test] + fn success() { + const LEN: usize = 100; + let mut tmp = NamedTempFile::new().unwrap(); + let fd = tmp.as_raw_fd(); + let res = posix_fallocate(fd, 0, LEN as libc::off_t); + match res { + Ok(_) => { + let mut data = [1u8; LEN]; + assert_eq!(tmp.read(&mut data).expect("read failure"), LEN); + assert_eq!(&data[..], &[0u8; LEN][..]); + } + Err(nix::Error::Sys(Errno::EINVAL)) => { + // POSIX requires posix_fallocate to return EINVAL both for + // invalid arguments (i.e. len < 0) and if the operation is not + // supported by the file system. + // There's no way to tell for sure whether the file system + // supports posix_fallocate, so we must pass the test if it + // returns EINVAL. + } + _ => res.unwrap(), + } + } + + #[test] + fn errno() { + let (rd, _wr) = pipe().unwrap(); + let err = posix_fallocate(rd as RawFd, 0, 100).unwrap_err(); + use nix::Error::Sys; + match err { + Sys(Errno::EINVAL) + | Sys(Errno::ENODEV) + | Sys(Errno::ESPIPE) + | Sys(Errno::EBADF) => (), + errno => + panic!( + "unexpected errno {}", + errno, + ), + } + } +}