1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-28 10:47:34 +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

@ -70,6 +70,9 @@ struct stat {
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
#define UTIME_OMIT -1
#define UTIME_NOW -2
#ifdef __cplusplus
}
#endif

View file

@ -185,6 +185,7 @@ enum class NeedsBigProcessLock {
S(unlink, NeedsBigProcessLock::No) \
S(unveil, NeedsBigProcessLock::Yes) \
S(utime, NeedsBigProcessLock::Yes) \
S(utimensat, NeedsBigProcessLock::Yes) \
S(waitid, NeedsBigProcessLock::Yes) \
S(write, NeedsBigProcessLock::Yes) \
S(writev, NeedsBigProcessLock::Yes) \
@ -416,6 +417,13 @@ struct SC_unveil_params {
StringArgument permissions;
};
struct SC_utimensat_params {
int dirfd;
StringArgument path;
struct timespec const* times;
int flag;
};
struct SC_waitid_params {
int idtype;
int id;

View file

@ -281,6 +281,7 @@ set(KERNEL_SOURCES
Syscalls/unlink.cpp
Syscalls/unveil.cpp
Syscalls/utime.cpp
Syscalls/utimensat.cpp
Syscalls/waitid.cpp
Syscalls/inode_watcher.cpp
Syscalls/write.cpp

View file

@ -1545,6 +1545,8 @@ ErrorOr<void> Ext2FSInode::set_atime(time_t t)
MutexLocker locker(m_inode_lock);
if (fs().is_readonly())
return EROFS;
if (t > INT32_MAX)
return EINVAL;
m_raw_inode.i_atime = t;
set_metadata_dirty(true);
return {};

View file

@ -196,6 +196,25 @@ ErrorOr<void> VirtualFileSystem::utime(StringView path, Custody& base, time_t at
return {};
}
ErrorOr<void> VirtualFileSystem::utimensat(StringView path, Custody& base, timespec const& atime, timespec const& mtime, int options)
{
auto custody = TRY(resolve_path(path, base, nullptr, options));
auto& inode = custody->inode();
auto& current_process = Process::current();
if (!current_process.is_superuser() && inode.metadata().uid != current_process.euid())
return EACCES;
if (custody->is_readonly())
return EROFS;
// NOTE: A standard ext2 inode cannot store nanosecond timestamps.
if (atime.tv_nsec != UTIME_OMIT)
TRY(inode.set_atime(atime.tv_sec));
if (mtime.tv_nsec != UTIME_OMIT)
TRY(inode.set_mtime(mtime.tv_sec));
return {};
}
ErrorOr<InodeMetadata> VirtualFileSystem::lookup_metadata(StringView path, Custody& base, int options)
{
auto custody = TRY(resolve_path(path, base, nullptr, options));

View file

@ -64,6 +64,7 @@ public:
ErrorOr<void> access(StringView path, int mode, Custody& base);
ErrorOr<InodeMetadata> lookup_metadata(StringView path, Custody& base, int options = 0);
ErrorOr<void> utime(StringView path, Custody& base, time_t atime, time_t mtime);
ErrorOr<void> utimensat(StringView path, Custody& base, timespec const& atime, timespec const& mtime, int options = 0);
ErrorOr<void> rename(StringView oldpath, StringView newpath, Custody& base);
ErrorOr<void> mknod(StringView path, mode_t, dev_t, Custody& base);
ErrorOr<NonnullRefPtr<Custody>> open_directory(StringView path, Custody& base);

View file

@ -353,6 +353,7 @@ public:
ErrorOr<FlatPtr> sys$mkdir(Userspace<char const*> pathname, size_t path_length, mode_t mode);
ErrorOr<FlatPtr> sys$times(Userspace<tms*>);
ErrorOr<FlatPtr> sys$utime(Userspace<char const*> pathname, size_t path_length, Userspace<const struct utimbuf*>);
ErrorOr<FlatPtr> sys$utimensat(Userspace<Syscall::SC_utimensat_params const*>);
ErrorOr<FlatPtr> sys$link(Userspace<Syscall::SC_link_params const*>);
ErrorOr<FlatPtr> sys$unlink(int dirfd, Userspace<char const*> pathname, size_t path_length, int flags);
ErrorOr<FlatPtr> sys$symlink(Userspace<Syscall::SC_symlink_params const*>);

View file

@ -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;
}
}