From 7aba041004480677294d22080fe40f3dc1185ad1 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Tue, 5 May 2026 02:02:43 +0700 Subject: [PATCH] Implement utimensat --- src/header/sys_stat/mod.rs | 21 ++++++++++- tests/Makefile.tests.mk | 1 + .../bins_dynamic/sys_stat/utimensat.stdout | 0 .../bins_static/sys_stat/utimensat.stdout | 0 tests/sys_stat/utimensat.c | 36 +++++++++++++++++++ 5 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 tests/expected/bins_dynamic/sys_stat/utimensat.stdout create mode 100644 tests/expected/bins_static/sys_stat/utimensat.stdout create mode 100644 tests/sys_stat/utimensat.c diff --git a/src/header/sys_stat/mod.rs b/src/header/sys_stat/mod.rs index df1417a5bd..542208feb3 100644 --- a/src/header/sys_stat/mod.rs +++ b/src/header/sys_stat/mod.rs @@ -6,7 +6,7 @@ use crate::{ c_str::CStr, error::ResultExt, header::{ - fcntl::{O_NOFOLLOW, O_PATH}, + fcntl::{AT_SYMLINK_NOFOLLOW, O_NOFOLLOW, O_PATH}, time::timespec, }, out::Out, @@ -240,3 +240,22 @@ pub unsafe extern "C" fn stat(file: *const c_char, buf: *mut stat) -> c_int { pub extern "C" fn umask(mask: mode_t) -> mode_t { Sys::umask(mask) } + +/// See . +#[unsafe(no_mangle)] +pub unsafe extern "C" fn utimensat( + fd: c_int, + path: *const c_char, + times: *const timespec, + flag: c_int, +) -> c_int { + let path = unsafe { CStr::from_ptr(path) }; + match Sys::openat(fd, path, flag & AT_SYMLINK_NOFOLLOW, 0) { + Ok(fd) => unsafe { + let r = Sys::futimens(fd, times).map(|()| 0).or_minus_one_errno(); + let _ = Sys::close(fd); + r + }, + r => r.or_minus_one_errno(), + } +} diff --git a/tests/Makefile.tests.mk b/tests/Makefile.tests.mk index 2e5f19fe34..9f127db95f 100644 --- a/tests/Makefile.tests.mk +++ b/tests/Makefile.tests.mk @@ -147,6 +147,7 @@ EXPECT_NAMES=\ sys_stat/lstat \ sys_stat/fstatat \ sys_stat/umask \ + sys_stat/utimensat \ sys_syslog/syslog \ time/asctime \ time/constants \ diff --git a/tests/expected/bins_dynamic/sys_stat/utimensat.stdout b/tests/expected/bins_dynamic/sys_stat/utimensat.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/sys_stat/utimensat.stdout b/tests/expected/bins_static/sys_stat/utimensat.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/sys_stat/utimensat.c b/tests/sys_stat/utimensat.c new file mode 100644 index 0000000000..4f091536a6 --- /dev/null +++ b/tests/sys_stat/utimensat.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include +#include +#include "test_helpers.h" + +int main() { + const char *test_file = "utimensat.txt"; + struct stat st; + struct timespec times[2]; + + int fd = open(test_file, O_WRONLY | O_CREAT | O_TRUNC, 0666); + ERROR_IF(open, fd, == -1); + close(fd); + + times[0].tv_sec = 100; + times[0].tv_nsec = 0; + times[1].tv_sec = 200; + times[1].tv_nsec = 0; + + int utime_status = utimensat(AT_FDCWD, test_file, times, 0); + ERROR_IF(utimensat, utime_status, == -1); + + int stat_status = stat(test_file, &st); + ERROR_IF(stat, stat_status, == -1); + + UNEXP_IF(utimensat_atime, st.st_atime, != times[0].tv_sec); + UNEXP_IF(utimensat_mtime, st.st_mtime, != times[1].tv_sec); + + int unlink_status = unlink(test_file); + ERROR_IF(unlink, unlink_status, == -1); + + return 0; +} \ No newline at end of file