Kernel/LibC: Implement utime* family functions
This patch adds *working* - utime - utimes - utimensat - futimens
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user