diff --git a/CHANGELOG.md b/CHANGELOG.md index 326f5e3172..4de6ade247 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,8 +16,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#916](https://github.com/nix-rust/nix/pull/916)) - Added `kmod` module that allows loading and unloading kernel modules on Linux. ([#930](https://github.com/nix-rust/nix/pull/930)) -- Added `futimens` and `utimesat` wrappers. - ([#944](https://github.com/nix-rust/nix/pull/944)) +- Added `futimens` and `utimesat` wrappers ([#944](https://github.com/nix-rust/nix/pull/944)) + and a `utimes` wrapper ([#946](https://github.com/nix-rust/nix/pull/946)). ### Changed - Increased required Rust version to 1.22.1/ diff --git a/src/sys/stat.rs b/src/sys/stat.rs index 6ac4444e71..b810c16731 100644 --- a/src/sys/stat.rs +++ b/src/sys/stat.rs @@ -8,7 +8,7 @@ use libc::{self, mode_t}; use std::mem; use std::os::raw; use std::os::unix::io::RawFd; -use sys::time::TimeSpec; +use sys::time::{TimeSpec, TimeVal}; libc_bitflags!( pub struct SFlag: mode_t { @@ -190,6 +190,25 @@ pub fn fchmodat( Errno::result(res).map(|_| ()) } +/// Change the access and modification times of a file. +/// +/// `utimes(path, times)` is identical to +/// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)`. The former +/// is a deprecated API so prefer using the latter if the platforms you care +/// about support it. +/// +/// # References +/// +/// [utimes(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/utimes.html). +pub fn utimes(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> { + let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()]; + let res = path.with_nix_path(|cstr| unsafe { + libc::utimes(cstr.as_ptr(), ×[0]) + })?; + + Errno::result(res).map(|_| ()) +} + /// Change the access and modification times of the file specified by a file descriptor. /// /// # References @@ -220,7 +239,8 @@ pub enum UtimensatFlags { /// then the mode of the symbolic link is changed. /// /// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)` is identical to -/// `libc::utimes(path, times)`. That's why `utimes` is unimplemented in the `nix` crate. +/// `utimes(path, times)`. The latter is a deprecated API so prefer using the +/// former if the platforms you care about support it. /// /// # References /// diff --git a/test/test_stat.rs b/test/test_stat.rs index 49cc49fded..e72dffd382 100644 --- a/test/test_stat.rs +++ b/test/test_stat.rs @@ -6,9 +6,9 @@ use std::time::{Duration, UNIX_EPOCH}; use libc::{S_IFMT, S_IFLNK}; use nix::fcntl; -use nix::sys::stat::{self, fchmod, fchmodat, fstat, futimens, lstat, stat, utimensat}; +use nix::sys::stat::{self, fchmod, fchmodat, fstat, futimens, lstat, stat, utimes, utimensat}; use nix::sys::stat::{FileStat, Mode, FchmodatFlags, UtimensatFlags}; -use nix::sys::time::{TimeSpec, TimeValLike}; +use nix::sys::time::{TimeSpec, TimeVal, TimeValLike}; use nix::unistd::chdir; use nix::Result; use tempfile; @@ -168,6 +168,16 @@ fn assert_times_eq(exp_atime_sec: u64, exp_mtime_sec: u64, attr: &fs::Metadata) attr.modified().unwrap().duration_since(UNIX_EPOCH).unwrap()); } +#[test] +fn test_utimes() { + let tempdir = tempfile::tempdir().unwrap(); + let fullpath = tempdir.path().join("file"); + drop(File::create(&fullpath).unwrap()); + + utimes(&fullpath, &TimeVal::seconds(9990), &TimeVal::seconds(5550)); + assert_times_eq(9990, 5550, &fs::metadata(&fullpath).unwrap()); +} + #[test] fn test_futimens() { let tempdir = tempfile::tempdir().unwrap();