mirror of
https://github.com/RGBCube/serenity
synced 2025-07-28 07: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:
parent
7550017f97
commit
9a6bd85924
10 changed files with 146 additions and 0 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {};
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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*>);
|
||||
|
|
61
Kernel/Syscalls/utimensat.cpp
Normal file
61
Kernel/Syscalls/utimensat.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue