Kernel/LibC: Implement symlink{,at}

This commit is contained in:
Bananymous 2024-12-02 17:44:25 +02:00
parent 11b6ee423e
commit d58ca5f37a
8 changed files with 97 additions and 31 deletions

View File

@ -39,6 +39,7 @@ namespace Kernel
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override;
virtual BAN::ErrorOr<BAN::String> link_target_impl() override;
virtual BAN::ErrorOr<void> set_link_target_impl(BAN::StringView) override;
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;

View File

@ -99,6 +99,7 @@ namespace Kernel
// Link API
BAN::ErrorOr<BAN::String> link_target();
BAN::ErrorOr<void> set_link_target(BAN::StringView);
// Socket API
BAN::ErrorOr<long> accept(sockaddr* address, socklen_t* address_len, int flags);
@ -134,6 +135,7 @@ namespace Kernel
// Link API
virtual BAN::ErrorOr<BAN::String> link_target_impl() { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> set_link_target_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
// Socket API
virtual BAN::ErrorOr<long> accept_impl(sockaddr*, socklen_t*, int) { return BAN::Error::from_errno(ENOTSUP); }

View File

@ -113,6 +113,8 @@ namespace Kernel
BAN::ErrorOr<long> sys_unlink(const char*);
BAN::ErrorOr<long> sys_readlinkat(int fd, const char* path, char* buffer, size_t bufsize);
BAN::ErrorOr<long> sys_symlinkat(const char* path1, int fd, const char* path2);
BAN::ErrorOr<long> sys_pread(int fd, void* buffer, size_t count, off_t offset);
BAN::ErrorOr<long> sys_fchmodat(int fd, const char* path, mode_t mode, int flag);
@ -221,6 +223,7 @@ namespace Kernel
static Process* create_process(const Credentials&, pid_t parent, pid_t sid = 0, pid_t pgrp = 0);
BAN::ErrorOr<VirtualFileSystem::File> find_file(int fd, const char* path, int flags);
BAN::ErrorOr<VirtualFileSystem::File> find_parent(int fd, const char* path);
BAN::ErrorOr<void> validate_string_access(const char*);
BAN::ErrorOr<void> validate_pointer_access_check(const void*, size_t, bool needs_write);

View File

@ -104,7 +104,27 @@ namespace Kernel
{
ASSERT(mode().iflnk());
if (m_inode.size < sizeof(m_inode.block))
return BAN::String((const char*)m_inode.block);
{
BAN::String result;
TRY(result.append(BAN::StringView(reinterpret_cast<const char*>(m_inode.block), m_inode.size)));
return result;
}
dwarnln("TODO: ext2 get symlink target from {} byte inode", m_inode.size);
return BAN::Error::from_errno(ENOTSUP);
}
BAN::ErrorOr<void> Ext2Inode::set_link_target_impl(BAN::StringView target)
{
ASSERT(mode().iflnk());
if (m_inode.size < sizeof(m_inode.block) && target.size() < sizeof(m_inode.block))
{
memset(m_inode.block, 0, sizeof(m_inode.block));
memcpy(m_inode.block, target.data(), target.size());
m_inode.size = target.size();
TRY(sync());
return {};
}
dwarnln("TODO: ext2 set symlink target to {} bytes from {} byte inode", target.size(), m_inode.size);
return BAN::Error::from_errno(ENOTSUP);
}
@ -440,8 +460,15 @@ done:
if (!find_inode_impl(name).is_error())
return BAN::Error::from_errno(EEXIST);
if (!(Mode(mode).ifreg()))
switch (mode & Inode::Mode::TYPE_MASK)
{
case Inode::Mode::IFLNK:
case Inode::Mode::IFREG:
case Inode::Mode::IFIFO:
case Inode::Mode::IFSOCK:
break;
return BAN::Error::from_errno(ENOTSUP);
}
const uint32_t new_ino = TRY(m_fs.create_inode(initialize_new_inode_info(mode, uid, gid)));

View File

@ -111,6 +111,14 @@ namespace Kernel
return link_target_impl();
}
BAN::ErrorOr<void> Inode::set_link_target(BAN::StringView target)
{
LockGuard _(m_mutex);
if (!mode().iflnk())
return BAN::Error::from_errno(EINVAL);
return set_link_target_impl(target);
}
BAN::ErrorOr<long> Inode::accept(sockaddr* address, socklen_t* address_len, int flags)
{
LockGuard _(m_mutex);

View File

@ -368,6 +368,26 @@ namespace Kernel
return read_from_vec_of_str(m_environ, offset, buffer);
}
BAN::ErrorOr<VirtualFileSystem::File> Process::find_parent(int fd, const char* path)
{
ASSERT(m_process_lock.is_locked());
if (path)
TRY(validate_string_access(path));
if (path && path[0] == '/')
return VirtualFileSystem::get().root_file();
if (fd == AT_FDCWD)
return TRY(m_working_directory.clone());
int flags = TRY(m_open_file_descriptors.flags_of(fd));
if (!(flags & O_RDONLY) && !(flags & O_SEARCH))
return BAN::Error::from_errno(EBADF);
return TRY(m_open_file_descriptors.file_of(fd));
}
BAN::ErrorOr<VirtualFileSystem::File> Process::find_file(int fd, const char* path, int flags)
{
ASSERT(m_process_lock.is_locked());
@ -375,14 +395,7 @@ namespace Kernel
if (path)
TRY(validate_string_access(path));
VirtualFileSystem::File parent_file;
if (path && path[0] == '/')
parent_file = VirtualFileSystem::get().root_file();
else if (fd == AT_FDCWD)
parent_file = TRY(m_working_directory.clone());
else
parent_file = TRY(m_open_file_descriptors.file_of(fd));
auto parent_file = TRY(find_parent(fd, path));
auto file = path
? TRY(VirtualFileSystem::get().file_from_relative_path(parent_file, m_credentials, path, flags))
: BAN::move(parent_file);
@ -854,10 +867,12 @@ namespace Kernel
{
switch (mode & Inode::Mode::TYPE_MASK)
{
case Inode::Mode::IFREG: break;
case Inode::Mode::IFDIR: break;
case Inode::Mode::IFIFO: break;
case Inode::Mode::IFSOCK: break;
case Inode::Mode::IFREG:
case Inode::Mode::IFDIR:
case Inode::Mode::IFLNK:
case Inode::Mode::IFIFO:
case Inode::Mode::IFSOCK:
break;
default:
return BAN::Error::from_errno(ENOTSUP);
}
@ -925,21 +940,7 @@ namespace Kernel
TRY(validate_string_access(path));
VirtualFileSystem::File parent_file;
if (path[0] == '/')
parent_file = VirtualFileSystem::get().root_file();
else if (fd == AT_FDCWD)
parent_file = TRY(m_working_directory.clone());
else
{
int flags = TRY(m_open_file_descriptors.flags_of(fd));
if (!(flags & O_RDONLY) && !(flags & O_SEARCH))
return BAN::Error::from_errno(EBADF);
if (!TRY(m_open_file_descriptors.inode_of(fd))->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);
parent_file = TRY(m_open_file_descriptors.file_of(fd));
}
auto parent_file = TRY(find_parent(fd, path));
auto file_or_error = VirtualFileSystem::get().file_from_relative_path(parent_file, m_credentials, path, flags | O_NOFOLLOW);
VirtualFileSystem::File file;
@ -1077,6 +1078,25 @@ namespace Kernel
return byte_count;
}
BAN::ErrorOr<long> Process::sys_symlinkat(const char* path1, int fd, const char* path2)
{
LockGuard _(m_process_lock);
TRY(validate_string_access(path1));
TRY(validate_string_access(path2));
auto parent_file = TRY(find_parent(fd, path2));
auto file_or_error = VirtualFileSystem::get().file_from_relative_path(parent_file, m_credentials, path2, O_NOFOLLOW);
if (!file_or_error.is_error())
return BAN::Error::from_errno(EEXIST);
TRY(create_file_or_dir(parent_file, path2, 0777 | Inode::Mode::IFLNK));
auto symlink = TRY(VirtualFileSystem::get().file_from_relative_path(parent_file, m_credentials, path2, O_NOFOLLOW));
TRY(symlink.inode->set_link_target(path1));
return 0;
}
BAN::ErrorOr<long> Process::sys_pread(int fd, void* buffer, size_t count, off_t offset)
{
LockGuard _(m_process_lock);

View File

@ -89,6 +89,7 @@ __BEGIN_DECLS
O(SYS_POSIX_OPENPT, posix_openpt) \
O(SYS_PTSNAME, ptsname) \
O(SYS_FSYNC, fsync) \
O(SYS_SYMLINKAT, symlinkat) \
enum Syscall
{

View File

@ -623,6 +623,10 @@ unsigned alarm(unsigned seconds)
int symlink(const char* path1, const char* path2)
{
dwarnln("FIXME: symlink({}, {})", path1, path2);
ASSERT_NOT_REACHED();
return symlinkat(path1, AT_FDCWD, path2);
}
int symlinkat(const char* path1, int fd, const char* path2)
{
return syscall(SYS_SYMLINKAT, path1, fd, path2);
}