Kernel/LibC: Implement symlink{,at}

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

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);