From 9a6bd859243df604c1b1f1762bb701165917f367 Mon Sep 17 00:00:00 2001 From: Ariel Don Date: Mon, 2 May 2022 15:26:10 -0500 Subject: Kernel+LibC+VFS: Implement utimensat(3) Create POSIX utimensat() library call and corresponding system call to update file access and modification times. --- Userland/Libraries/LibC/fcntl.cpp | 47 +++++++++++++++++++++++++++++++++++++++ Userland/Libraries/LibC/fcntl.h | 3 +++ 2 files changed, 50 insertions(+) (limited to 'Userland/Libraries/LibC') diff --git a/Userland/Libraries/LibC/fcntl.cpp b/Userland/Libraries/LibC/fcntl.cpp index 9ce5039f18..4a421178d0 100644 --- a/Userland/Libraries/LibC/fcntl.cpp +++ b/Userland/Libraries/LibC/fcntl.cpp @@ -11,6 +11,7 @@ #include #include #include +#include extern "C" { @@ -102,4 +103,50 @@ int posix_fadvise(int fd, off_t offset, off_t len, int advice) (void)advice; return 0; } + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimensat.html +int utimensat(int dirfd, char const* path, struct timespec const times[2], int flag) +{ + if (!path) { + errno = EFAULT; + return -1; + } + + size_t path_length = strlen(path); + if (path_length > INT32_MAX) { + errno = EINVAL; + return -1; + } + + // POSIX allows AT_SYMLINK_NOFOLLOW flag or no flags. + if (flag & ~AT_SYMLINK_NOFOLLOW) { + errno = EINVAL; + return -1; + } + + // Return early without error since both changes are to be omitted. + if (times && times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT) + return 0; + + // According to POSIX, when times is a nullptr, it's equivalent to setting + // both last access time and last modification time to the current time. + // Setting the times argument to nullptr if it matches this case prevents + // the need to copy it in the kernel. + if (times && times[0].tv_nsec == UTIME_NOW && times[1].tv_nsec == UTIME_NOW) + times = nullptr; + + if (times) { + for (int i = 0; i < 2; ++i) { + if ((times[i].tv_nsec != UTIME_NOW && times[i].tv_nsec != UTIME_OMIT) + && (times[i].tv_nsec < 0 || times[i].tv_nsec >= 1'000'000'000L)) { + errno = EINVAL; + return -1; + } + } + } + + Syscall::SC_utimensat_params params { dirfd, { path, path_length }, times, flag }; + int rc = syscall(SC_utimensat, ¶ms); + __RETURN_WITH_ERRNO(rc, rc, -1); +} } diff --git a/Userland/Libraries/LibC/fcntl.h b/Userland/Libraries/LibC/fcntl.h index 8681676945..3704d6a7a7 100644 --- a/Userland/Libraries/LibC/fcntl.h +++ b/Userland/Libraries/LibC/fcntl.h @@ -8,6 +8,7 @@ #pragma once #include +#include __BEGIN_DECLS @@ -29,4 +30,6 @@ int inode_watcher_remove_watch(int fd, int wd); int posix_fadvise(int fd, off_t offset, off_t len, int advice); +int utimensat(int dirfd, char const* path, struct timespec const times[2], int flag); + __END_DECLS -- cgit v1.2.3