Kernel/LibC: Implement utime* family functions
This patch adds *working* - utime - utimes - utimensat - futimens
This commit is contained in:
parent
8392472bac
commit
1bd454b8fd
|
@ -46,6 +46,7 @@ namespace Kernel
|
|||
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
|
||||
virtual BAN::ErrorOr<void> truncate_impl(size_t) override;
|
||||
virtual BAN::ErrorOr<void> chmod_impl(mode_t) override;
|
||||
virtual BAN::ErrorOr<void> utimens_impl(const timespec[2]) override;
|
||||
virtual BAN::ErrorOr<void> fsync_impl() override;
|
||||
|
||||
virtual bool can_read_impl() const override { return true; }
|
||||
|
|
|
@ -44,6 +44,7 @@ namespace Kernel
|
|||
//virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
|
||||
//virtual BAN::ErrorOr<void> truncate_impl(size_t) override;
|
||||
//virtual BAN::ErrorOr<void> chmod_impl(mode_t) override;
|
||||
//virtual BAN::ErrorOr<void> utimens_impl(const timespec[2]) override;
|
||||
virtual BAN::ErrorOr<void> fsync_impl() override { return {}; }
|
||||
|
||||
virtual bool can_read_impl() const override { return true; }
|
||||
|
|
|
@ -119,6 +119,7 @@ namespace Kernel
|
|||
BAN::ErrorOr<void> truncate(size_t);
|
||||
BAN::ErrorOr<void> chmod(mode_t);
|
||||
BAN::ErrorOr<void> chown(uid_t, gid_t);
|
||||
BAN::ErrorOr<void> utimens(const timespec[2]);
|
||||
BAN::ErrorOr<void> fsync();
|
||||
|
||||
// Select/Non blocking API
|
||||
|
@ -165,6 +166,7 @@ namespace Kernel
|
|||
virtual BAN::ErrorOr<void> truncate_impl(size_t) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
virtual BAN::ErrorOr<void> chmod_impl(mode_t) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
virtual BAN::ErrorOr<void> chown_impl(uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
virtual BAN::ErrorOr<void> utimens_impl(const timespec[2]) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
virtual BAN::ErrorOr<void> fsync_impl() = 0;
|
||||
|
||||
// Select/Non blocking API
|
||||
|
|
|
@ -47,6 +47,8 @@ namespace Kernel
|
|||
protected:
|
||||
TmpInode(TmpFileSystem&, ino_t, const TmpInodeInfo&);
|
||||
|
||||
virtual BAN::ErrorOr<void> chmod_impl(mode_t) override;
|
||||
virtual BAN::ErrorOr<void> utimens_impl(const timespec[2]) override;
|
||||
virtual BAN::ErrorOr<void> fsync_impl() override { return {}; }
|
||||
|
||||
void sync();
|
||||
|
@ -75,7 +77,6 @@ namespace Kernel
|
|||
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
||||
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
|
||||
virtual BAN::ErrorOr<void> truncate_impl(size_t) override;
|
||||
virtual BAN::ErrorOr<void> chmod_impl(mode_t) override;
|
||||
|
||||
virtual bool can_read_impl() const override { return true; }
|
||||
virtual bool can_write_impl() const override { return true; }
|
||||
|
@ -98,7 +99,6 @@ namespace Kernel
|
|||
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override { return BAN::Error::from_errno(ENODEV); }
|
||||
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override { return BAN::Error::from_errno(ENODEV); }
|
||||
virtual BAN::ErrorOr<void> truncate_impl(size_t) override { return BAN::Error::from_errno(ENODEV); }
|
||||
virtual BAN::ErrorOr<void> chmod_impl(mode_t) override;
|
||||
|
||||
virtual bool can_read_impl() const override { return false; }
|
||||
virtual bool can_write_impl() const override { return false; }
|
||||
|
|
|
@ -116,6 +116,7 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<long> sys_fchmodat(int fd, const char* path, mode_t mode, int flag);
|
||||
BAN::ErrorOr<long> sys_fchownat(int fd, const char* path, uid_t uid, gid_t gid, int flag);
|
||||
BAN::ErrorOr<long> sys_utimensat(int fd, const char* path, const struct timespec times[2], int flag);
|
||||
|
||||
BAN::ErrorOr<long> sys_socket(int domain, int type, int protocol);
|
||||
BAN::ErrorOr<long> sys_socketpair(int domain, int type, int protocol, int socket_vector[2]);
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include <kernel/FS/Ext2/Inode.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
|
@ -287,6 +289,28 @@ namespace Kernel
|
|||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Ext2Inode::utimens_impl(const timespec times[2])
|
||||
{
|
||||
const uint32_t old_times[2] {
|
||||
m_inode.atime,
|
||||
m_inode.mtime,
|
||||
};
|
||||
|
||||
if (times[0].tv_nsec != UTIME_OMIT)
|
||||
m_inode.atime = times[0].tv_sec;
|
||||
if (times[1].tv_nsec != UTIME_OMIT)
|
||||
m_inode.mtime = times[1].tv_sec;
|
||||
|
||||
if (auto ret = sync(); ret.is_error())
|
||||
{
|
||||
m_inode.atime = old_times[0];
|
||||
m_inode.mtime = old_times[1];
|
||||
return ret.release_error();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Ext2Inode::fsync_impl()
|
||||
{
|
||||
for (size_t i = 0; i < max_used_data_block_count(); i++)
|
||||
|
|
|
@ -231,6 +231,12 @@ namespace Kernel
|
|||
return chown_impl(uid, gid);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Inode::utimens(const timespec times[2])
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
return utimens_impl(times);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Inode::fsync()
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#include <kernel/FS/TmpFS/Inode.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
|
@ -90,6 +92,23 @@ namespace Kernel
|
|||
m_fs.delete_inode(ino());
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> TmpInode::chmod_impl(mode_t new_mode)
|
||||
{
|
||||
ASSERT(!(new_mode & Mode::TYPE_MASK));
|
||||
m_inode_info.mode &= ~Mode::TYPE_MASK;
|
||||
m_inode_info.mode |= new_mode;
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> TmpInode::utimens_impl(const timespec times[2])
|
||||
{
|
||||
if (times[0].tv_nsec != UTIME_OMIT)
|
||||
m_inode_info.atime = times[0];
|
||||
if (times[1].tv_nsec != UTIME_OMIT)
|
||||
m_inode_info.atime = times[1];
|
||||
return {};
|
||||
}
|
||||
|
||||
void TmpInode::sync()
|
||||
{
|
||||
m_fs.write_inode(m_ino, m_inode_info);
|
||||
|
@ -219,12 +238,6 @@ namespace Kernel
|
|||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> TmpFileInode::chmod_impl(mode_t new_mode)
|
||||
{
|
||||
m_inode_info.mode = new_mode;
|
||||
return {};
|
||||
}
|
||||
|
||||
/* SOCKET INODE */
|
||||
BAN::ErrorOr<BAN::RefPtr<TmpSocketInode>> TmpSocketInode::create_new(TmpFileSystem& fs, mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
|
@ -248,12 +261,6 @@ namespace Kernel
|
|||
{
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> TmpSocketInode::chmod_impl(mode_t new_mode)
|
||||
{
|
||||
m_inode_info.mode = new_mode;
|
||||
return {};
|
||||
}
|
||||
|
||||
/* SYMLINK INODE */
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<TmpSymlinkInode>> TmpSymlinkInode::create_new(TmpFileSystem& fs, mode_t mode, uid_t uid, gid_t gid, BAN::StringView target)
|
||||
|
|
|
@ -1262,6 +1262,56 @@ namespace Kernel
|
|||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_utimensat(int fd, const char* path, const struct timespec _times[2], int flag)
|
||||
{
|
||||
if (flag & ~AT_SYMLINK_NOFOLLOW)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
if (flag == AT_SYMLINK_NOFOLLOW)
|
||||
flag = O_NOFOLLOW;
|
||||
|
||||
timespec times[2];
|
||||
const uint64_t current_ns = SystemTimer::get().ns_since_boot();
|
||||
times[0] = times[1] = timespec {
|
||||
.tv_sec = static_cast<time_t>(current_ns / 1'000'000),
|
||||
.tv_nsec = static_cast<long>(current_ns % 1'000'000),
|
||||
};
|
||||
|
||||
if (_times)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
TRY(validate_pointer_access(_times, sizeof(timespec) * 2, false));
|
||||
if (_times[0].tv_nsec != UTIME_NOW)
|
||||
{
|
||||
times[0] = _times[0];
|
||||
if (auto ns = times[0].tv_nsec; ns != UTIME_OMIT && (ns < 0 || ns >= 1'000'000'000))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
if (_times[1].tv_nsec != UTIME_NOW)
|
||||
{
|
||||
times[1] = _times[1];
|
||||
if (auto ns = times[1].tv_nsec; ns != UTIME_OMIT && (ns < 0 || ns >= 1'000'000'000))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT)
|
||||
return 0;
|
||||
|
||||
LockGuard _(m_process_lock);
|
||||
|
||||
auto inode = TRY(find_file(fd, path, flag)).inode;
|
||||
|
||||
if (!m_credentials.is_superuser() && inode->uid() != m_credentials.euid())
|
||||
{
|
||||
dwarnln("cannot chmod uid {} vs {}", inode->uid(), m_credentials.euid());
|
||||
return BAN::Error::from_errno(EPERM);
|
||||
}
|
||||
|
||||
TRY(inode->utimens(times));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_socket(int domain, int type, int protocol)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
|
|
|
@ -94,6 +94,7 @@ __BEGIN_DECLS
|
|||
O(SYS_FSYNC, fsync) \
|
||||
O(SYS_SYMLINKAT, symlinkat) \
|
||||
O(SYS_HARDLINKAT, hardlinkat) \
|
||||
O(SYS_UTIMENSAT, utimensat) \
|
||||
O(SYS_YIELD, yield) \
|
||||
O(SYS_SET_TLS, set_tls) \
|
||||
O(SYS_GET_TLS, get_tls) \
|
||||
|
|
|
@ -53,3 +53,13 @@ int mkdir(const char* path, mode_t mode)
|
|||
{
|
||||
return syscall(SYS_CREATE_DIR, path, __UMASKED_MODE(mode));
|
||||
}
|
||||
|
||||
int futimens(int fd, const struct timespec times[2])
|
||||
{
|
||||
return utimensat(fd, nullptr, times, 0);
|
||||
}
|
||||
|
||||
int utimensat(int fd, const char* path, const struct timespec times[2], int flag)
|
||||
{
|
||||
return syscall(SYS_UTIMENSAT, fd, path, times, flag);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include <fcntl.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
@ -26,3 +27,20 @@ int setitimer(int which, const struct itimerval* __restrict value, struct itimer
|
|||
{
|
||||
return syscall(SYS_SETITIMER, which, value, ovalue);
|
||||
}
|
||||
|
||||
int utimes(const char* path, const struct timeval times[2])
|
||||
{
|
||||
if (times == nullptr)
|
||||
return utimensat(AT_FDCWD, path, nullptr, 0);
|
||||
const timespec times_ts[2] {
|
||||
timespec {
|
||||
.tv_sec = times[0].tv_sec,
|
||||
.tv_nsec = times[0].tv_usec * 1000,
|
||||
},
|
||||
timespec {
|
||||
.tv_sec = times[1].tv_sec,
|
||||
.tv_nsec = times[1].tv_usec * 1000,
|
||||
},
|
||||
};
|
||||
return utimensat(AT_FDCWD, path, times_ts, 0);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,20 @@
|
|||
#include <utime.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <utime.h>
|
||||
|
||||
int utime(const char* filename, const struct utimbuf* times)
|
||||
{
|
||||
fprintf(stddbg, "TODO: utime(\"%s\", %p)\n", filename, times);
|
||||
|
||||
struct stat st;
|
||||
return stat(filename, &st);
|
||||
if (times == nullptr)
|
||||
return utimensat(AT_FDCWD, filename, nullptr, 0);
|
||||
const timespec times_ts[2] {
|
||||
timespec {
|
||||
.tv_sec = times->actime,
|
||||
.tv_nsec = 0,
|
||||
},
|
||||
timespec {
|
||||
.tv_sec = times->modtime,
|
||||
.tv_nsec = 0,
|
||||
},
|
||||
};
|
||||
return utimensat(AT_FDCWD, filename, times_ts, 0);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue