Skip to content

Commit 6aa502e

Browse files
committed
add support for futimens/utimensat
1 parent 7c1225e commit 6aa502e

File tree

3 files changed

+90
-1
lines changed

3 files changed

+90
-1
lines changed

CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
1212
([#582](https://github.com/nix-rust/nix/pull/582)
1313
- Added `nix::unistd::{openat, fstatat, readlink, readlinkat, rename, renameat, mknodat, unlinkat, mkdirat, link, linkat, symlink, symlinkat, access, faccessat}`
1414
([#552](https://github.com/nix-rust/nix/pull/552), [#561](https://github.com/nix-rust/nix/pull/561))
15-
- Added `nix::stat::{chmod, fchmod, fchmodat}` ([#561](https://github.com/nix-rust/nix/pull/561))
15+
- Added `nix::stat::{chmod, fchmod, fchmodat, futimens, utimensat}` ([#561](https://github.com/nix-rust/nix/pull/561))
1616
- Added `nix::unistd::{chown, lchown, fchown, fchownat}` ([#561](https://github.com/nix-rust/nix/pull/561))
1717
- Added `nix::pty::{grantpt, posix_openpt, ptsname/ptsname_r, unlockpt}`
1818
([#556](https://github.com/nix-rust/nix/pull/556)

src/sys/stat.rs

+72
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use libc::{self, mode_t};
77
use std::mem;
88
use std::os::unix::io::RawFd;
99

10+
pub use self::linux::*;
11+
1012
mod ffi {
1113
use libc::{c_char, c_int, mode_t, dev_t};
1214
pub use libc::{stat, fstat, lstat};
@@ -179,3 +181,73 @@ pub fn fchmodat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, mode: Mode, fla
179181

180182
Errno::result(res).map(drop)
181183
}
184+
185+
#[cfg(target_os = "linux")]
186+
mod linux {
187+
use {Errno, Result, NixPath};
188+
use std::os::unix::io::RawFd;
189+
use libc;
190+
use fcntl::AtFlags;
191+
use sys::time::TimeSpec;
192+
193+
/// A file timestamp.
194+
pub enum UtimeSpec {
195+
/// File timestamp is set to the current time.
196+
Now,
197+
/// The corresponding file timestamp is left unchanged.
198+
Omit,
199+
/// File timestamp is set to value
200+
Time(TimeSpec)
201+
}
202+
203+
impl <'a> From<&'a UtimeSpec> for libc::timespec {
204+
fn from(time: &'a UtimeSpec) -> libc::timespec {
205+
match time {
206+
&UtimeSpec::Now => libc::timespec {
207+
tv_sec: 0,
208+
tv_nsec: libc::UTIME_NOW,
209+
},
210+
&UtimeSpec::Omit => libc::timespec {
211+
tv_sec: 0,
212+
tv_nsec: libc::UTIME_OMIT,
213+
},
214+
&UtimeSpec::Time(spec) => *spec.as_ref()
215+
}
216+
}
217+
}
218+
219+
/// Change file timestamps with nanosecond precision
220+
/// (see [utimensat(2)](http://man7.org/linux/man-pages/man2/utimensat.2.html)).
221+
pub fn utimensat<P: ?Sized + NixPath>(dirfd: RawFd,
222+
pathname: &P,
223+
atime: &UtimeSpec,
224+
mtime: &UtimeSpec,
225+
flags: AtFlags) -> Result<()> {
226+
let time = [atime.into(), mtime.into()];
227+
let res = try!(pathname.with_nix_path(|cstr| {
228+
unsafe {
229+
libc::utimensat(dirfd,
230+
cstr.as_ptr(),
231+
time.as_ptr() as *const libc::timespec,
232+
flags.bits())
233+
}
234+
}));
235+
236+
Errno::result(res).map(drop)
237+
}
238+
239+
/// Change file timestamps with nanosecond precision
240+
/// (see [futimens(2)](http://man7.org/linux/man-pages/man2/futimens.2.html)).
241+
pub fn futimens(fd: RawFd,
242+
atime: &UtimeSpec,
243+
mtime: &UtimeSpec) -> Result<()> {
244+
let time = [atime.into(), mtime.into()];
245+
let res = unsafe {
246+
libc::futimens(fd, time.as_ptr() as *const libc::timespec)
247+
};
248+
249+
Errno::result(res).map(drop)
250+
}
251+
}
252+
#[cfg(not(target_os = "linux"))]
253+
mod linux { }

test/test_stat.rs

+17
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,20 @@ fn test_chmod() {
137137
fcntl::AtFlags::empty()).unwrap();
138138
assert_mode(&tempfile, 0o600);
139139
}
140+
141+
#[test]
142+
#[cfg(target_os = "linux")]
143+
fn test_utime() {
144+
use std::time::UNIX_EPOCH;
145+
use nix::sys::time::{TimeSpec, TimeValLike};
146+
147+
let tempfile = NamedTempFile::new().unwrap();
148+
utimensat(0, // is ignored, if pathname is absolute path
149+
tempfile.path(),
150+
&UtimeSpec::Time(TimeSpec::zero()),
151+
&UtimeSpec::Time(TimeSpec::zero()),
152+
fcntl::AtFlags::empty()).unwrap();
153+
let mtime = tempfile.metadata().unwrap().modified().unwrap();
154+
155+
assert_eq!(mtime, UNIX_EPOCH);
156+
}

0 commit comments

Comments
 (0)