summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulio Merino <julio@meroh.net>2018-10-02 06:11:33 -0400
committerJulio Merino <jmmv@google.com>2018-10-02 10:50:05 -0400
commit06be3ee604ace2a49c9cc35edd55c058f18b7534 (patch)
treec908ae299cee0a61394945a996189bd1718232c6
parenta32b46ead6b22699e842226f0fac19de745a8219 (diff)
downloadnix-06be3ee604ace2a49c9cc35edd55c058f18b7534.zip
Add a wrapper for utimes(2)
PR #944 added wrappers for the more-modern futimens(2) and utimesat(2), but unfortunately these APIs are not available on old-ish systems. In particular, macOS Sierra and below don't implement them, making the new APIs unusable. Whether we should care about such "old" systems is debatable, but the problem is that, at the moment, this is the only macOS version usable on Travis to test kexts and, thus, to test FUSE file systems.
-rw-r--r--CHANGELOG.md4
-rw-r--r--src/sys/stat.rs24
-rw-r--r--test/test_stat.rs14
3 files changed, 36 insertions, 6 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 326f5e31..4de6ade2 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 6ac4444e..b810c167 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<P: ?Sized + NixPath>(
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<P: ?Sized + NixPath>(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(), &times[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 49cc49fd..e72dffd3 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;
@@ -169,6 +169,16 @@ fn assert_times_eq(exp_atime_sec: u64, exp_mtime_sec: u64, attr: &fs::Metadata)
}
#[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();
let fullpath = tempdir.path().join("file");