From f6065e81811227858970310d15f7ecb38b177926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Thu, 30 Mar 2017 12:32:39 +0200 Subject: [PATCH] add support for `futimens/utimensat` --- CHANGELOG.md | 2 ++ src/sys/stat.rs | 71 +++++++++++++++++++++++++++++++++++++++++++++++ test/test_stat.rs | 17 ++++++++++++ 3 files changed, 90 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36b528ca91..4044391655 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#739](https://github.com/nix-rust/nix/pull/739)) - Added nix::sys::ptrace::detach. ([#749](https://github.com/nix-rust/nix/pull/749)) +- Added `nix::stat::{futimens, utimensat}` + ([#761](https://github.com/nix-rust/nix/pull/761)) ### Changed - Renamed existing `ptrace` wrappers to encourage namespacing ([#692](https://github.com/nix-rust/nix/pull/692)) diff --git a/src/sys/stat.rs b/src/sys/stat.rs index 7a0b3970ce..2b615446fc 100644 --- a/src/sys/stat.rs +++ b/src/sys/stat.rs @@ -7,6 +7,8 @@ use libc::{self, mode_t}; use std::mem; use std::os::unix::io::RawFd; +pub use self::linux::*; + libc_bitflags!( pub struct SFlag: mode_t { S_IFIFO; @@ -121,3 +123,72 @@ pub fn fstatat(dirfd: RawFd, pathname: &P, f: AtFlags) -> R Ok(dst) } +#[cfg(target_os = "linux")] +mod linux { + use {Errno, Result, NixPath}; + use std::os::unix::io::RawFd; + use libc; + use fcntl::AtFlags; + use sys::time::TimeSpec; + + /// A file timestamp. + pub enum UtimeSpec { + /// File timestamp is set to the current time. + Now, + /// The corresponding file timestamp is left unchanged. + Omit, + /// File timestamp is set to value + Time(TimeSpec) + } + + impl <'a> From<&'a UtimeSpec> for libc::timespec { + fn from(time: &'a UtimeSpec) -> libc::timespec { + match time { + &UtimeSpec::Now => libc::timespec { + tv_sec: 0, + tv_nsec: libc::UTIME_NOW, + }, + &UtimeSpec::Omit => libc::timespec { + tv_sec: 0, + tv_nsec: libc::UTIME_OMIT, + }, + &UtimeSpec::Time(spec) => *spec.as_ref() + } + } + } + + /// Change file timestamps with nanosecond precision + /// (see [utimensat(2)](http://man7.org/linux/man-pages/man2/utimensat.2.html)). + pub fn utimensat(dirfd: RawFd, + pathname: &P, + atime: &UtimeSpec, + mtime: &UtimeSpec, + flags: AtFlags) -> Result<()> { + let time = [atime.into(), mtime.into()]; + let res = try!(pathname.with_nix_path(|cstr| { + unsafe { + libc::utimensat(dirfd, + cstr.as_ptr(), + time.as_ptr() as *const libc::timespec, + flags.bits()) + } + })); + + Errno::result(res).map(drop) + } + + /// Change file timestamps with nanosecond precision + /// (see [futimens(2)](http://man7.org/linux/man-pages/man2/futimens.2.html)). + pub fn futimens(fd: RawFd, + atime: &UtimeSpec, + mtime: &UtimeSpec) -> Result<()> { + let time = [atime.into(), mtime.into()]; + let res = unsafe { + libc::futimens(fd, time.as_ptr() as *const libc::timespec) + }; + + Errno::result(res).map(drop) + } +} +#[cfg(not(target_os = "linux"))] +mod linux { } diff --git a/test/test_stat.rs b/test/test_stat.rs index 765d4fa191..462252a519 100644 --- a/test/test_stat.rs +++ b/test/test_stat.rs @@ -110,3 +110,20 @@ fn test_stat_fstat_lstat() { let fstat_result = fstat(link.as_raw_fd()); assert_stat_results(fstat_result); } + +#[test] +#[cfg(target_os = "linux")] +fn test_utime() { + use std::time::UNIX_EPOCH; + use nix::sys::time::{TimeSpec, TimeValLike}; + + let tempfile = NamedTempFile::new().unwrap(); + utimensat(0, // is ignored, if pathname is absolute path + tempfile.path(), + &UtimeSpec::Time(TimeSpec::zero()), + &UtimeSpec::Time(TimeSpec::zero()), + fcntl::AtFlags::empty()).unwrap(); + let mtime = tempfile.metadata().unwrap().modified().unwrap(); + + assert_eq!(mtime, UNIX_EPOCH); +}