mirror of
https://github.com/SerenityOS/serenity
synced 2024-10-15 12:23:15 +00:00
Kernel: Add the futimens syscall
We have a problem with the original utimensat syscall because when we do call LibC futimens function, internally we provide an empty path, and the Kernel get_syscall_path_argument method will detect this as an invalid path. This happens to spit an error for example in the touch utility, so if a user is running "touch non_existing_file", it will create that file, but the user will still see an error coming from LibC futimens function. This new syscall gets an open file description and it provides the same functionality as utimensat, on the specified open file description. The new syscall will be used later by LibC to properly implement LibC futimens function so the situation described with relation to the "touch" utility could be fixed.
This commit is contained in:
parent
71e665f0f9
commit
cbf78975f1
|
@ -84,6 +84,7 @@ enum class NeedsBigProcessLock {
|
||||||
S(fsync, NeedsBigProcessLock::No) \
|
S(fsync, NeedsBigProcessLock::No) \
|
||||||
S(ftruncate, NeedsBigProcessLock::No) \
|
S(ftruncate, NeedsBigProcessLock::No) \
|
||||||
S(futex, NeedsBigProcessLock::Yes) \
|
S(futex, NeedsBigProcessLock::Yes) \
|
||||||
|
S(futimens, NeedsBigProcessLock::No) \
|
||||||
S(get_dir_entries, NeedsBigProcessLock::Yes) \
|
S(get_dir_entries, NeedsBigProcessLock::Yes) \
|
||||||
S(get_root_session_id, NeedsBigProcessLock::No) \
|
S(get_root_session_id, NeedsBigProcessLock::No) \
|
||||||
S(get_stack_bounds, NeedsBigProcessLock::No) \
|
S(get_stack_bounds, NeedsBigProcessLock::No) \
|
||||||
|
@ -457,6 +458,11 @@ struct SC_utimensat_params {
|
||||||
int flag;
|
int flag;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SC_futimens_params {
|
||||||
|
int fd;
|
||||||
|
struct timespec const* times;
|
||||||
|
};
|
||||||
|
|
||||||
struct SC_waitid_params {
|
struct SC_waitid_params {
|
||||||
int idtype;
|
int idtype;
|
||||||
int id;
|
int id;
|
||||||
|
|
|
@ -313,10 +313,15 @@ ErrorOr<void> VirtualFileSystem::utime(Credentials const& credentials, StringVie
|
||||||
ErrorOr<void> VirtualFileSystem::utimensat(Credentials const& credentials, StringView path, Custody& base, timespec const& atime, timespec const& mtime, int options)
|
ErrorOr<void> VirtualFileSystem::utimensat(Credentials const& credentials, StringView path, Custody& base, timespec const& atime, timespec const& mtime, int options)
|
||||||
{
|
{
|
||||||
auto custody = TRY(resolve_path(credentials, path, base, nullptr, options));
|
auto custody = TRY(resolve_path(credentials, path, base, nullptr, options));
|
||||||
auto& inode = custody->inode();
|
return do_utimens(credentials, custody, atime, mtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> VirtualFileSystem::do_utimens(Credentials const& credentials, Custody& custody, timespec const& atime, timespec const& mtime)
|
||||||
|
{
|
||||||
|
auto& inode = custody.inode();
|
||||||
if (!credentials.is_superuser() && inode.metadata().uid != credentials.euid())
|
if (!credentials.is_superuser() && inode.metadata().uid != credentials.euid())
|
||||||
return EACCES;
|
return EACCES;
|
||||||
if (custody->is_readonly())
|
if (custody.is_readonly())
|
||||||
return EROFS;
|
return EROFS;
|
||||||
|
|
||||||
// NOTE: A standard ext2 inode cannot store nanosecond timestamps.
|
// NOTE: A standard ext2 inode cannot store nanosecond timestamps.
|
||||||
|
|
|
@ -75,6 +75,7 @@ public:
|
||||||
ErrorOr<InodeMetadata> lookup_metadata(Credentials const&, StringView path, Custody& base, int options = 0);
|
ErrorOr<InodeMetadata> lookup_metadata(Credentials const&, StringView path, Custody& base, int options = 0);
|
||||||
ErrorOr<void> utime(Credentials const&, StringView path, Custody& base, time_t atime, time_t mtime);
|
ErrorOr<void> utime(Credentials const&, StringView path, Custody& base, time_t atime, time_t mtime);
|
||||||
ErrorOr<void> utimensat(Credentials const&, StringView path, Custody& base, timespec const& atime, timespec const& mtime, int options = 0);
|
ErrorOr<void> utimensat(Credentials const&, StringView path, Custody& base, timespec const& atime, timespec const& mtime, int options = 0);
|
||||||
|
ErrorOr<void> do_utimens(Credentials const& credentials, Custody& custody, timespec const& atime, timespec const& mtime);
|
||||||
ErrorOr<void> rename(Credentials const&, Custody& old_base, StringView oldpath, Custody& new_base, StringView newpath);
|
ErrorOr<void> rename(Credentials const&, Custody& old_base, StringView oldpath, Custody& new_base, StringView newpath);
|
||||||
ErrorOr<void> mknod(Credentials const&, StringView path, mode_t, dev_t, Custody& base);
|
ErrorOr<void> mknod(Credentials const&, StringView path, mode_t, dev_t, Custody& base);
|
||||||
ErrorOr<NonnullRefPtr<Custody>> open_directory(Credentials const&, StringView path, Custody& base);
|
ErrorOr<NonnullRefPtr<Custody>> open_directory(Credentials const&, StringView path, Custody& base);
|
||||||
|
|
|
@ -334,6 +334,7 @@ public:
|
||||||
ErrorOr<FlatPtr> sys$annotate_mapping(Userspace<void*>, int flags);
|
ErrorOr<FlatPtr> sys$annotate_mapping(Userspace<void*>, int flags);
|
||||||
ErrorOr<FlatPtr> sys$lseek(int fd, Userspace<off_t*>, int whence);
|
ErrorOr<FlatPtr> sys$lseek(int fd, Userspace<off_t*>, int whence);
|
||||||
ErrorOr<FlatPtr> sys$ftruncate(int fd, Userspace<off_t const*>);
|
ErrorOr<FlatPtr> sys$ftruncate(int fd, Userspace<off_t const*>);
|
||||||
|
ErrorOr<FlatPtr> sys$futimens(Userspace<Syscall::SC_futimens_params const*>);
|
||||||
ErrorOr<FlatPtr> sys$posix_fallocate(int fd, Userspace<off_t const*>, Userspace<off_t const*>);
|
ErrorOr<FlatPtr> sys$posix_fallocate(int fd, Userspace<off_t const*>, Userspace<off_t const*>);
|
||||||
ErrorOr<FlatPtr> sys$kill(pid_t pid_or_pgid, int sig);
|
ErrorOr<FlatPtr> sys$kill(pid_t pid_or_pgid, int sig);
|
||||||
[[noreturn]] void sys$exit(int status);
|
[[noreturn]] void sys$exit(int status);
|
||||||
|
|
|
@ -12,6 +12,40 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
ErrorOr<FlatPtr> Process::sys$futimens(Userspace<Syscall::SC_futimens_params const*> user_params)
|
||||||
|
{
|
||||||
|
VERIFY_NO_PROCESS_BIG_LOCK(this);
|
||||||
|
TRY(require_promise(Pledge::fattr));
|
||||||
|
|
||||||
|
auto params = TRY(copy_typed_from_user(user_params));
|
||||||
|
auto now = kgettimeofday().to_timespec();
|
||||||
|
|
||||||
|
timespec times[2];
|
||||||
|
if (params.times) {
|
||||||
|
TRY(copy_from_user(times, params.times, sizeof(times)));
|
||||||
|
if (times[0].tv_nsec == UTIME_NOW)
|
||||||
|
times[0] = now;
|
||||||
|
if (times[1].tv_nsec == UTIME_NOW)
|
||||||
|
times[1] = now;
|
||||||
|
} else {
|
||||||
|
// According to POSIX, both access and modification times are set to
|
||||||
|
// the current time given a nullptr.
|
||||||
|
times[0] = now;
|
||||||
|
times[1] = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto description = TRY(open_file_description(params.fd));
|
||||||
|
if (!description->inode())
|
||||||
|
return EBADF;
|
||||||
|
if (!description->custody())
|
||||||
|
return EBADF;
|
||||||
|
|
||||||
|
auto& atime = times[0];
|
||||||
|
auto& mtime = times[1];
|
||||||
|
TRY(VirtualFileSystem::the().do_utimens(credentials(), *description->custody(), atime, mtime));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
ErrorOr<FlatPtr> Process::sys$utimensat(Userspace<Syscall::SC_utimensat_params const*> user_params)
|
ErrorOr<FlatPtr> Process::sys$utimensat(Userspace<Syscall::SC_utimensat_params const*> user_params)
|
||||||
{
|
{
|
||||||
VERIFY_NO_PROCESS_BIG_LOCK(this);
|
VERIFY_NO_PROCESS_BIG_LOCK(this);
|
||||||
|
|
Loading…
Reference in a new issue