Skip to content

Commit

Permalink
Merge #967
Browse files Browse the repository at this point in the history
967: Add a wrapper for lutimes(2) r=asomers a=jmmv

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.

This should have been part of PR #946, which added a wrapper for
utimes(2) following this same rationale, but missed lutimes(2) because
I simply didn't notice it existed.

Co-authored-by: Julio Merino <julio@meroh.net>
  • Loading branch information
bors[bot] and jmmv committed Nov 27, 2018
2 parents 6920394 + 12f10c7 commit 1d2dace
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 2 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Expand Up @@ -20,7 +20,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)),
an `lutimes` wrapper ([#967](https://github.com/nix-rust/nix/pull/967)),
and a `utimes` wrapper ([#946](https://github.com/nix-rust/nix/pull/946)).
- Added `AF_UNSPEC` wrapper to `AddressFamily` ([#948](https://github.com/nix-rust/nix/pull/948))
- Added the `mode_t` public alias within `sys::stat`.
Expand Down
20 changes: 20 additions & 0 deletions src/sys/stat.rs
Expand Up @@ -199,6 +199,26 @@ pub fn utimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -
Errno::result(res).map(|_| ())
}

/// Change the access and modification times of a file without following symlinks.
///
/// `lutimes(path, times)` is identical to
/// `utimensat(None, path, times, UtimensatFlags::NoFollowSymlink)`. The former
/// is a deprecated API so prefer using the latter if the platforms you care
/// about support it.
///
/// # References
///
/// [lutimes(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lutimes.html).
#[cfg(not(target_os = "android"))]
pub fn lutimes<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::lutimes(cstr.as_ptr(), &times[0])
})?;

Errno::result(res).map(|_| ())
}

/// Change the access and modification times of the file specified by a file descriptor.
///
/// # References
Expand Down
21 changes: 20 additions & 1 deletion test/test_stat.rs
Expand Up @@ -6,7 +6,7 @@ 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, utimes, utimensat};
use nix::sys::stat::{self, fchmod, fchmodat, fstat, futimens, lstat, lutimes, stat, utimes, utimensat};
use nix::sys::stat::{FileStat, Mode, FchmodatFlags, UtimensatFlags};
use nix::sys::time::{TimeSpec, TimeVal, TimeValLike};
use nix::unistd::chdir;
Expand Down Expand Up @@ -178,6 +178,25 @@ fn test_utimes() {
assert_times_eq(9990, 5550, &fs::metadata(&fullpath).unwrap());
}

#[test]
fn test_lutimes() {
let tempdir = tempfile::tempdir().unwrap();
let target = tempdir.path().join("target");
let fullpath = tempdir.path().join("symlink");
drop(File::create(&target).unwrap());
symlink(&target, &fullpath).unwrap();

let exp_target_metadata = fs::symlink_metadata(&target).unwrap();
lutimes(&fullpath, &TimeVal::seconds(4560), &TimeVal::seconds(1230)).unwrap();
assert_times_eq(4560, 1230, &fs::symlink_metadata(&fullpath).unwrap());

let target_metadata = fs::symlink_metadata(&target).unwrap();
assert_eq!(exp_target_metadata.accessed().unwrap(), target_metadata.accessed().unwrap(),
"atime of symlink target was unexpectedly modified");
assert_eq!(exp_target_metadata.modified().unwrap(), target_metadata.modified().unwrap(),
"mtime of symlink target was unexpectedly modified");
}

#[test]
fn test_futimens() {
let tempdir = tempfile::tempdir().unwrap();
Expand Down

0 comments on commit 1d2dace

Please sign in to comment.