Skip to content

Commit 2d9dac3

Browse files
committed
add support for futimens/utimensat
1 parent 8ead93e commit 2d9dac3

File tree

3 files changed

+88
-1
lines changed

3 files changed

+88
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
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

Lines changed: 70 additions & 0 deletions
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};
@@ -53,6 +55,7 @@ bitflags! {
5355
}
5456
}
5557

58+
5659
pub fn mknod<P: ?Sized + NixPath>(path: &P, kind: SFlag, perm: Mode, dev: dev_t) -> Result<()> {
5760
let res = try!(path.with_nix_path(|cstr| {
5861
unsafe {
@@ -179,3 +182,70 @@ pub fn fchmodat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, mode: Mode, fla
179182

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

test/test_stat.rs

Lines changed: 17 additions & 0 deletions
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)