diff --git a/CHANGELOG.md b/CHANGELOG.md index e1e0c01d3e..7e16278a2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added `AF_UNSPEC` wrapper to `AddressFamily` ([#948](https://github.com/nix-rust/nix/pull/948)) - Added the `mode_t` public alias within `sys::stat`. ([#954](https://github.com/nix-rust/nix/pull/954)) +- Added a `truncate` wrapper. + ([#956](https://github.com/nix-rust/nix/pull/956)) ### Changed - Increased required Rust version to 1.22.1/ diff --git a/src/unistd.rs b/src/unistd.rs index ad06a3c0eb..7088260448 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -986,6 +986,20 @@ fn pipe2_setflags(fd1: RawFd, fd2: RawFd, flags: OFlag) -> Result<()> { } } +/// Truncate a file to a specified length +/// +/// See also +/// [truncate(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html) +pub fn truncate(path: &P, len: off_t) -> Result<()> { + let res = try!(path.with_nix_path(|cstr| { + unsafe { + libc::truncate(cstr.as_ptr(), len) + } + })); + + Errno::result(res).map(drop) +} + /// Truncate a file to a specified length /// /// See also diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 54cbff8dcf..981ab53deb 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -6,7 +6,7 @@ use nix::sys::wait::*; use nix::sys::stat::{self, Mode, SFlag}; use std::{env, iter}; use std::ffi::CString; -use std::fs::File; +use std::fs::{self, File}; use std::io::Write; use std::os::unix::prelude::*; use tempfile::{self, tempfile}; @@ -390,6 +390,42 @@ fn test_pipe2() { assert!(f1.contains(FdFlag::FD_CLOEXEC)); } +#[test] +fn test_truncate() { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("file"); + + { + let mut tmp = File::create(&path).unwrap(); + const CONTENTS: &[u8] = b"12345678"; + tmp.write_all(CONTENTS).unwrap(); + } + + truncate(&path, 4).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + assert_eq!(4, metadata.len()); +} + +#[test] +fn test_ftruncate() { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("file"); + + let tmpfd = { + let mut tmp = File::create(&path).unwrap(); + const CONTENTS: &[u8] = b"12345678"; + tmp.write_all(CONTENTS).unwrap(); + tmp.into_raw_fd() + }; + + ftruncate(tmpfd, 2).unwrap(); + close(tmpfd).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + assert_eq!(2, metadata.len()); +} + // Used in `test_alarm`. static mut ALARM_CALLED: bool = false;