Skip to content

Commit 7eac89f

Browse files
committed
add support for futimens/utimensat
1 parent ab2cf38 commit 7eac89f

File tree

3 files changed

+85
-1
lines changed

3 files changed

+85
-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

+67
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,67 @@ 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+
pub enum UtimeSpec {
195+
Now,
196+
Omit,
197+
Time(TimeSpec)
198+
}
199+
200+
fn to_timespec(time: &UtimeSpec) -> libc::timespec {
201+
match time {
202+
&UtimeSpec::Now => libc::timespec {
203+
tv_sec: 0,
204+
tv_nsec: libc::UTIME_NOW,
205+
},
206+
&UtimeSpec::Omit => libc::timespec {
207+
tv_sec: 0,
208+
tv_nsec: libc::UTIME_OMIT,
209+
},
210+
&UtimeSpec::Time(spec) => *spec.as_ref()
211+
}
212+
}
213+
214+
/// Change file timestamps with nanosecond precision
215+
/// (see [utimensat(2)](http://man7.org/linux/man-pages/man2/utimensat.2.html))
216+
pub fn utimensat<P: ?Sized + NixPath>(dirfd: RawFd,
217+
pathname: &P,
218+
atime: &UtimeSpec,
219+
mtime: &UtimeSpec,
220+
flags: AtFlags) -> Result<()> {
221+
let time = [to_timespec(atime), to_timespec(mtime)];
222+
let res = try!(pathname.with_nix_path(|cstr| {
223+
unsafe {
224+
libc::utimensat(dirfd,
225+
cstr.as_ptr(),
226+
time.as_ptr() as *const libc::timespec,
227+
flags.bits())
228+
}
229+
}));
230+
231+
Errno::result(res).map(drop)
232+
}
233+
234+
/// Change file timestamps with nanosecond precision
235+
/// (see [futimens(2)](http://man7.org/linux/man-pages/man2/futimens.2.html))
236+
pub fn futimens(fd: RawFd,
237+
atime: &UtimeSpec,
238+
mtime: &UtimeSpec) -> Result<()> {
239+
let time = [to_timespec(atime), to_timespec(mtime)];
240+
let res = unsafe {
241+
libc::futimens(fd, time.as_ptr() as *const libc::timespec)
242+
};
243+
244+
Errno::result(res).map(drop)
245+
}
246+
}
247+
#[cfg(not(target_os = "linux"))]
248+
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)