diff --git a/Kernel/API/Syscall.h b/Kernel/API/Syscall.h index 1ab7d2d41c..19b7074197 100644 --- a/Kernel/API/Syscall.h +++ b/Kernel/API/Syscall.h @@ -84,6 +84,7 @@ enum class NeedsBigProcessLock { S(fsync, NeedsBigProcessLock::No) \ S(ftruncate, NeedsBigProcessLock::No) \ S(futex, NeedsBigProcessLock::Yes) \ + S(futimens, NeedsBigProcessLock::No) \ S(get_dir_entries, NeedsBigProcessLock::Yes) \ S(get_root_session_id, NeedsBigProcessLock::No) \ S(get_stack_bounds, NeedsBigProcessLock::No) \ @@ -457,6 +458,11 @@ struct SC_utimensat_params { int flag; }; +struct SC_futimens_params { + int fd; + struct timespec const* times; +}; + struct SC_waitid_params { int idtype; int id; diff --git a/Kernel/FileSystem/VirtualFileSystem.cpp b/Kernel/FileSystem/VirtualFileSystem.cpp index 1f9a85ae60..4b66e5f3c3 100644 --- a/Kernel/FileSystem/VirtualFileSystem.cpp +++ b/Kernel/FileSystem/VirtualFileSystem.cpp @@ -313,10 +313,15 @@ ErrorOr VirtualFileSystem::utime(Credentials const& credentials, StringVie ErrorOr VirtualFileSystem::utimensat(Credentials const& credentials, StringView path, Custody& base, timespec const& atime, timespec const& mtime, int options) { auto custody = TRY(resolve_path(credentials, path, base, nullptr, options)); - auto& inode = custody->inode(); + return do_utimens(credentials, custody, atime, mtime); +} + +ErrorOr VirtualFileSystem::do_utimens(Credentials const& credentials, Custody& custody, timespec const& atime, timespec const& mtime) +{ + auto& inode = custody.inode(); if (!credentials.is_superuser() && inode.metadata().uid != credentials.euid()) return EACCES; - if (custody->is_readonly()) + if (custody.is_readonly()) return EROFS; // NOTE: A standard ext2 inode cannot store nanosecond timestamps. diff --git a/Kernel/FileSystem/VirtualFileSystem.h b/Kernel/FileSystem/VirtualFileSystem.h index 361f7809cf..f23d5088bf 100644 --- a/Kernel/FileSystem/VirtualFileSystem.h +++ b/Kernel/FileSystem/VirtualFileSystem.h @@ -75,6 +75,7 @@ public: ErrorOr lookup_metadata(Credentials const&, StringView path, Custody& base, int options = 0); ErrorOr utime(Credentials const&, StringView path, Custody& base, time_t atime, time_t mtime); ErrorOr utimensat(Credentials const&, StringView path, Custody& base, timespec const& atime, timespec const& mtime, int options = 0); + ErrorOr do_utimens(Credentials const& credentials, Custody& custody, timespec const& atime, timespec const& mtime); ErrorOr rename(Credentials const&, Custody& old_base, StringView oldpath, Custody& new_base, StringView newpath); ErrorOr mknod(Credentials const&, StringView path, mode_t, dev_t, Custody& base); ErrorOr> open_directory(Credentials const&, StringView path, Custody& base); diff --git a/Kernel/Process.h b/Kernel/Process.h index 09798c2da6..7251aa5be2 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -334,6 +334,7 @@ public: ErrorOr sys$annotate_mapping(Userspace, int flags); ErrorOr sys$lseek(int fd, Userspace, int whence); ErrorOr sys$ftruncate(int fd, Userspace); + ErrorOr sys$futimens(Userspace); ErrorOr sys$posix_fallocate(int fd, Userspace, Userspace); ErrorOr sys$kill(pid_t pid_or_pgid, int sig); [[noreturn]] void sys$exit(int status); diff --git a/Kernel/Syscalls/utimensat.cpp b/Kernel/Syscalls/utimensat.cpp index 14319ab84d..aa48aaf92e 100644 --- a/Kernel/Syscalls/utimensat.cpp +++ b/Kernel/Syscalls/utimensat.cpp @@ -12,6 +12,40 @@ namespace Kernel { +ErrorOr Process::sys$futimens(Userspace user_params) +{ + VERIFY_NO_PROCESS_BIG_LOCK(this); + TRY(require_promise(Pledge::fattr)); + + auto params = TRY(copy_typed_from_user(user_params)); + auto now = kgettimeofday().to_timespec(); + + timespec times[2]; + if (params.times) { + TRY(copy_from_user(times, params.times, sizeof(times))); + if (times[0].tv_nsec == UTIME_NOW) + times[0] = now; + if (times[1].tv_nsec == UTIME_NOW) + times[1] = now; + } else { + // According to POSIX, both access and modification times are set to + // the current time given a nullptr. + times[0] = now; + times[1] = now; + } + + auto description = TRY(open_file_description(params.fd)); + if (!description->inode()) + return EBADF; + if (!description->custody()) + return EBADF; + + auto& atime = times[0]; + auto& mtime = times[1]; + TRY(VirtualFileSystem::the().do_utimens(credentials(), *description->custody(), atime, mtime)); + return 0; +} + ErrorOr Process::sys$utimensat(Userspace user_params) { VERIFY_NO_PROCESS_BIG_LOCK(this);