Skip to content

Commit 1d2dace

Browse files
bors[bot]jmmv
andcommitted
Merge #967
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 <[email protected]>
2 parents 6920394 + 12f10c7 commit 1d2dace

File tree

3 files changed

+42
-2
lines changed

3 files changed

+42
-2
lines changed

CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
2020
([#916](https://github.com/nix-rust/nix/pull/916))
2121
- Added `kmod` module that allows loading and unloading kernel modules on Linux.
2222
([#930](https://github.com/nix-rust/nix/pull/930))
23-
- Added `futimens` and `utimesat` wrappers ([#944](https://github.com/nix-rust/nix/pull/944))
23+
- Added `futimens` and `utimesat` wrappers ([#944](https://github.com/nix-rust/nix/pull/944)),
24+
an `lutimes` wrapper ([#967](https://github.com/nix-rust/nix/pull/967)),
2425
and a `utimes` wrapper ([#946](https://github.com/nix-rust/nix/pull/946)).
2526
- Added `AF_UNSPEC` wrapper to `AddressFamily` ([#948](https://github.com/nix-rust/nix/pull/948))
2627
- Added the `mode_t` public alias within `sys::stat`.

src/sys/stat.rs

+20
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,26 @@ pub fn utimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -
199199
Errno::result(res).map(|_| ())
200200
}
201201

202+
/// Change the access and modification times of a file without following symlinks.
203+
///
204+
/// `lutimes(path, times)` is identical to
205+
/// `utimensat(None, path, times, UtimensatFlags::NoFollowSymlink)`. The former
206+
/// is a deprecated API so prefer using the latter if the platforms you care
207+
/// about support it.
208+
///
209+
/// # References
210+
///
211+
/// [lutimes(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lutimes.html).
212+
#[cfg(not(target_os = "android"))]
213+
pub fn lutimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> {
214+
let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
215+
let res = path.with_nix_path(|cstr| unsafe {
216+
libc::lutimes(cstr.as_ptr(), &times[0])
217+
})?;
218+
219+
Errno::result(res).map(|_| ())
220+
}
221+
202222
/// Change the access and modification times of the file specified by a file descriptor.
203223
///
204224
/// # References

test/test_stat.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::time::{Duration, UNIX_EPOCH};
66
use libc::{S_IFMT, S_IFLNK};
77

88
use nix::fcntl;
9-
use nix::sys::stat::{self, fchmod, fchmodat, fstat, futimens, lstat, stat, utimes, utimensat};
9+
use nix::sys::stat::{self, fchmod, fchmodat, fstat, futimens, lstat, lutimes, stat, utimes, utimensat};
1010
use nix::sys::stat::{FileStat, Mode, FchmodatFlags, UtimensatFlags};
1111
use nix::sys::time::{TimeSpec, TimeVal, TimeValLike};
1212
use nix::unistd::chdir;
@@ -178,6 +178,25 @@ fn test_utimes() {
178178
assert_times_eq(9990, 5550, &fs::metadata(&fullpath).unwrap());
179179
}
180180

181+
#[test]
182+
fn test_lutimes() {
183+
let tempdir = tempfile::tempdir().unwrap();
184+
let target = tempdir.path().join("target");
185+
let fullpath = tempdir.path().join("symlink");
186+
drop(File::create(&target).unwrap());
187+
symlink(&target, &fullpath).unwrap();
188+
189+
let exp_target_metadata = fs::symlink_metadata(&target).unwrap();
190+
lutimes(&fullpath, &TimeVal::seconds(4560), &TimeVal::seconds(1230)).unwrap();
191+
assert_times_eq(4560, 1230, &fs::symlink_metadata(&fullpath).unwrap());
192+
193+
let target_metadata = fs::symlink_metadata(&target).unwrap();
194+
assert_eq!(exp_target_metadata.accessed().unwrap(), target_metadata.accessed().unwrap(),
195+
"atime of symlink target was unexpectedly modified");
196+
assert_eq!(exp_target_metadata.modified().unwrap(), target_metadata.modified().unwrap(),
197+
"mtime of symlink target was unexpectedly modified");
198+
}
199+
181200
#[test]
182201
fn test_futimens() {
183202
let tempdir = tempfile::tempdir().unwrap();

0 commit comments

Comments
 (0)