diff --git a/Kernel/Syscalls/utimensat.cpp b/Kernel/Syscalls/utimensat.cpp index 4a6ca189a32516..1cd3760bb019e5 100644 --- a/Kernel/Syscalls/utimensat.cpp +++ b/Kernel/Syscalls/utimensat.cpp @@ -20,6 +20,9 @@ ErrorOr Process::sys$utimensat(Userspace Process::sys$utimensat(Userspace path; + RefPtr description; RefPtr base; - if (dirfd == AT_FDCWD) { - base = current_directory(); + + auto path_or_error = get_syscall_path_argument(params.path); + if (path_or_error.is_error()) { + // If the path is empty ("") but not a nullptr, attempt to get a path + // from the file descriptor. This allows futimens() to be implemented + // in terms of utimensat(). + if (params.path.characters && params.path.length == 0) { + description = TRY(open_file_description(dirfd)); + path = TRY(description->original_absolute_path()); + base = description->custody(); + } else { + return path_or_error.release_error(); + } } else { - auto base_description = TRY(open_file_description(dirfd)); - if (!KLexicalPath::is_absolute(path->view()) && !base_description->is_directory()) - return ENOTDIR; - if (!base_description->custody()) - return EINVAL; - base = base_description->custody(); + path = path_or_error.release_value(); + if (dirfd == AT_FDCWD) { + base = current_directory(); + } else { + description = TRY(open_file_description(dirfd)); + if (!KLexicalPath::is_absolute(path->view()) && !description->is_directory()) + return ENOTDIR; + if (!description->custody()) + return EINVAL; + base = description->custody(); + } } auto& atime = times[0]; auto& mtime = times[1]; - int follow_symlink = params.flag & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW_NOERROR : 0; TRY(VirtualFileSystem::the().utimensat(path->view(), *base, atime, mtime, follow_symlink)); return 0; } diff --git a/Userland/Libraries/LibC/stat.cpp b/Userland/Libraries/LibC/stat.cpp index bcb52fd898e2b1..d1ce13ea902405 100644 --- a/Userland/Libraries/LibC/stat.cpp +++ b/Userland/Libraries/LibC/stat.cpp @@ -109,4 +109,10 @@ int fstatat(int fd, char const* path, struct stat* statbuf, int flags) { return do_stat(fd, path, statbuf, !(flags & AT_SYMLINK_NOFOLLOW)); } + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html +int futimens(int fd, struct timespec const times[2]) +{ + return utimensat(fd, "", times, 0); +} } diff --git a/Userland/Libraries/LibC/sys/stat.h b/Userland/Libraries/LibC/sys/stat.h index 4ada8057088183..16b8a2c2e819aa 100644 --- a/Userland/Libraries/LibC/sys/stat.h +++ b/Userland/Libraries/LibC/sys/stat.h @@ -23,5 +23,6 @@ int fstat(int fd, struct stat* statbuf); int lstat(char const* path, struct stat* statbuf); int stat(char const* path, struct stat* statbuf); int fstatat(int fd, char const* path, struct stat* statbuf, int flags); +int futimens(int fd, struct timespec const times[2]); __END_DECLS