Serenity Operating System
1/*
2 * Copyright (c) 2022, Ariel Don <ariel@arieldon.com>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <AK/Assertions.h>
8#include <AK/StringView.h>
9#include <Kernel/FileSystem/VirtualFileSystem.h>
10#include <Kernel/KLexicalPath.h>
11#include <Kernel/Process.h>
12
13namespace Kernel {
14
15ErrorOr<FlatPtr> Process::sys$utimensat(Userspace<Syscall::SC_utimensat_params const*> user_params)
16{
17 VERIFY_NO_PROCESS_BIG_LOCK(this);
18 TRY(require_promise(Pledge::fattr));
19
20 auto params = TRY(copy_typed_from_user(user_params));
21 auto now = kgettimeofday().to_timespec();
22
23 int dirfd = params.dirfd;
24 int follow_symlink = params.flag & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW_NOERROR : 0;
25
26 timespec times[2];
27 if (params.times) {
28 TRY(copy_from_user(times, params.times, sizeof(times)));
29 if (times[0].tv_nsec == UTIME_NOW)
30 times[0] = now;
31 if (times[1].tv_nsec == UTIME_NOW)
32 times[1] = now;
33 } else {
34 // According to POSIX, both access and modification times are set to
35 // the current time given a nullptr.
36 times[0] = now;
37 times[1] = now;
38 }
39
40 OwnPtr<KString> path;
41 RefPtr<OpenFileDescription> description;
42 RefPtr<Custody> base;
43
44 auto path_or_error = get_syscall_path_argument(params.path);
45 if (path_or_error.is_error()) {
46 // If the path is empty ("") but not a nullptr, attempt to get a path
47 // from the file descriptor. This allows futimens() to be implemented
48 // in terms of utimensat().
49 if (params.path.characters && params.path.length == 0) {
50 description = TRY(open_file_description(dirfd));
51 path = TRY(description->original_absolute_path());
52 base = description->custody();
53 } else {
54 return path_or_error.release_error();
55 }
56 } else {
57 path = path_or_error.release_value();
58 if (dirfd == AT_FDCWD) {
59 base = current_directory();
60 } else {
61 description = TRY(open_file_description(dirfd));
62 if (!KLexicalPath::is_absolute(path->view()) && !description->is_directory())
63 return ENOTDIR;
64 if (!description->custody())
65 return EINVAL;
66 base = description->custody();
67 }
68 }
69
70 auto& atime = times[0];
71 auto& mtime = times[1];
72 TRY(VirtualFileSystem::the().utimensat(credentials(), path->view(), *base, atime, mtime, follow_symlink));
73 return 0;
74}
75
76}