Skip to content

Commit 98eb8a0

Browse files
committed
add support for futimens/utimensat
1 parent de9b9c1 commit 98eb8a0

File tree

3 files changed

+81
-1
lines changed

3 files changed

+81
-1
lines changed

CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
88
<!--### Added-->
99
- Added `nix::unistd::{openat, fstatat, readlink, readlinkat, rename, renameat, mknodat, unlinkat, mkdirat, link, linkat, symlink, symlinkat, access, faccessat}`
1010
([#552](https://github.com/nix-rust/nix/pull/552), [#561](https://github.com/nix-rust/nix/pull/561))
11-
- Added `nix::stat::{chmod, fchmod, fchmodat}` ([#561](https://github.com/nix-rust/nix/pull/561))
11+
- Added `nix::stat::{chmod, fchmod, fchmodat, futimens, utimensat}` ([#561](https://github.com/nix-rust/nix/pull/561))
1212
- Added `nix::unistd::{chown, lchown, fchown, fchownat}` ([#561](https://github.com/nix-rust/nix/pull/561))
1313

1414
### Changed

src/sys/stat.rs

+63
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 {
@@ -171,3 +174,63 @@ pub fn fchmodat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, mode: Mode, fla
171174

172175
Errno::result(res).map(drop)
173176
}
177+
178+
#[cfg(target_os = "linux")]
179+
mod linux {
180+
use {Errno, Result, NixPath};
181+
use std::os::unix::io::RawFd;
182+
use libc;
183+
use fcntl::AtFlags;
184+
use sys::time::TimeSpec;
185+
186+
pub enum UtimeSpec {
187+
Now,
188+
Omit,
189+
Time(TimeSpec)
190+
}
191+
192+
fn to_timespec(time: &UtimeSpec) -> libc::timespec {
193+
match time {
194+
&UtimeSpec::Now => libc::timespec {
195+
tv_sec: 0,
196+
tv_nsec: libc::UTIME_NOW,
197+
},
198+
&UtimeSpec::Omit => libc::timespec {
199+
tv_sec: 0,
200+
tv_nsec: libc::UTIME_OMIT,
201+
},
202+
&UtimeSpec::Time(spec) => *spec.as_ref()
203+
}
204+
}
205+
206+
pub fn utimensat<P: ?Sized + NixPath>(dirfd: RawFd,
207+
pathname: &P,
208+
atime: &UtimeSpec,
209+
mtime: &UtimeSpec,
210+
flags: AtFlags) -> Result<()> {
211+
let time = [to_timespec(atime), to_timespec(mtime)];
212+
let res = try!(pathname.with_nix_path(|cstr| {
213+
unsafe {
214+
libc::utimensat(dirfd,
215+
cstr.as_ptr(),
216+
time.as_ptr() as *const libc::timespec,
217+
flags.bits())
218+
}
219+
}));
220+
221+
Errno::result(res).map(drop)
222+
}
223+
224+
pub fn futimens(fd: RawFd,
225+
atime: &UtimeSpec,
226+
mtime: &UtimeSpec) -> Result<()> {
227+
let time = [to_timespec(atime), to_timespec(mtime)];
228+
let res = unsafe {
229+
libc::futimens(fd, time.as_ptr() as *const libc::timespec)
230+
};
231+
232+
Errno::result(res).map(drop)
233+
}
234+
}
235+
#[cfg(not(target_os = "linux"))]
236+
mod linux { }

test/test_stat.rs

+17
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
use std::fs::File;
22
use std::os::unix::fs::{symlink, PermissionsExt};
33
use std::os::unix::prelude::AsRawFd;
4+
use std::time::UNIX_EPOCH;
45
use tempfile::NamedTempFile;
56

67
use libc::{S_IFMT, S_IFLNK};
78

9+
810
use nix::fcntl;
911
use nix::sys::stat::*;
12+
use nix::sys::time::{TimeSpec, TimeValLike};
1013
use nix::Result;
1114
use tempdir::TempDir;
1215

@@ -137,3 +140,17 @@ fn test_chmod() {
137140
fcntl::AtFlags::empty()).unwrap();
138141
assert_mode(&tempfile, 0o600);
139142
}
143+
144+
#[test]
145+
#[cfg(target_os = "linux")]
146+
fn test_utime() {
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)