diff options
author | Ariel Don <ariel@arieldon.com> | 2022-05-02 15:26:10 -0500 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-05-21 18:15:00 +0200 |
commit | 9a6bd859243df604c1b1f1762bb701165917f367 (patch) | |
tree | 45e15f48dcc9c2b996e02ac925da99b278226d0c /Kernel/Syscalls/utimensat.cpp | |
parent | 7550017f97d7892f8b7d26074046a87144f491dd (diff) | |
download | serenity-9a6bd859243df604c1b1f1762bb701165917f367.zip |
Kernel+LibC+VFS: Implement utimensat(3)
Create POSIX utimensat() library call and corresponding system call to
update file access and modification times.
Diffstat (limited to 'Kernel/Syscalls/utimensat.cpp')
-rw-r--r-- | Kernel/Syscalls/utimensat.cpp | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/Kernel/Syscalls/utimensat.cpp b/Kernel/Syscalls/utimensat.cpp new file mode 100644 index 0000000000..4a6ca189a3 --- /dev/null +++ b/Kernel/Syscalls/utimensat.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2022, Ariel Don <ariel@arieldon.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <AK/Assertions.h> +#include <AK/StringView.h> +#include <Kernel/FileSystem/VirtualFileSystem.h> +#include <Kernel/KLexicalPath.h> +#include <Kernel/Process.h> + +namespace Kernel { + +ErrorOr<FlatPtr> Process::sys$utimensat(Userspace<Syscall::SC_utimensat_params const*> user_params) +{ + VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); + TRY(require_promise(Pledge::fattr)); + + auto params = TRY(copy_typed_from_user(user_params)); + auto now = kgettimeofday().to_truncated_seconds(); + + timespec times[2]; + if (params.times) { + TRY(copy_from_user(times, params.times, sizeof(times))); + if (times[0].tv_nsec == UTIME_NOW) + times[0].tv_sec = now; + if (times[1].tv_nsec == UTIME_NOW) + times[1].tv_sec = now; + } else { + // According to POSIX, both access and modification times are set to + // the current time given a nullptr. + times[0].tv_sec = now; + times[0].tv_nsec = UTIME_NOW; + times[1].tv_sec = now; + times[1].tv_nsec = UTIME_NOW; + } + + int dirfd = params.dirfd; + auto path = TRY(get_syscall_path_argument(params.path)); + + RefPtr<Custody> base; + if (dirfd == AT_FDCWD) { + base = current_directory(); + } 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(); + } + + 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; +} + +} |