1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 04:27:45 +00:00

Kernel+LibC+VFS: Implement utimensat(3)

Create POSIX utimensat() library call and corresponding system call to
update file access and modification times.
This commit is contained in:
Ariel Don 2022-05-02 15:26:10 -05:00 committed by Andreas Kling
parent 7550017f97
commit 9a6bd85924
10 changed files with 146 additions and 0 deletions

View file

@ -11,6 +11,7 @@
#include <stdarg.h>
#include <string.h>
#include <syscall.h>
#include <time.h>
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, &params);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
}