Kernel/LibC: Implement symlink{,at}
This commit is contained in:
parent
11b6ee423e
commit
d58ca5f37a
|
@ -39,6 +39,7 @@ namespace Kernel
|
||||||
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override;
|
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override;
|
||||||
|
|
||||||
virtual BAN::ErrorOr<BAN::String> link_target_impl() 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> read_impl(off_t, BAN::ByteSpan) override;
|
||||||
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
|
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
|
||||||
|
|
|
@ -99,6 +99,7 @@ namespace Kernel
|
||||||
|
|
||||||
// Link API
|
// Link API
|
||||||
BAN::ErrorOr<BAN::String> link_target();
|
BAN::ErrorOr<BAN::String> link_target();
|
||||||
|
BAN::ErrorOr<void> set_link_target(BAN::StringView);
|
||||||
|
|
||||||
// Socket API
|
// Socket API
|
||||||
BAN::ErrorOr<long> accept(sockaddr* address, socklen_t* address_len, int flags);
|
BAN::ErrorOr<long> accept(sockaddr* address, socklen_t* address_len, int flags);
|
||||||
|
@ -134,6 +135,7 @@ namespace Kernel
|
||||||
|
|
||||||
// Link API
|
// Link API
|
||||||
virtual BAN::ErrorOr<BAN::String> link_target_impl() { return BAN::Error::from_errno(ENOTSUP); }
|
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
|
// Socket API
|
||||||
virtual BAN::ErrorOr<long> accept_impl(sockaddr*, socklen_t*, int) { return BAN::Error::from_errno(ENOTSUP); }
|
virtual BAN::ErrorOr<long> accept_impl(sockaddr*, socklen_t*, int) { return BAN::Error::from_errno(ENOTSUP); }
|
||||||
|
|
|
@ -113,6 +113,8 @@ namespace Kernel
|
||||||
BAN::ErrorOr<long> sys_unlink(const char*);
|
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_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_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);
|
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);
|
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_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_string_access(const char*);
|
||||||
BAN::ErrorOr<void> validate_pointer_access_check(const void*, size_t, bool needs_write);
|
BAN::ErrorOr<void> validate_pointer_access_check(const void*, size_t, bool needs_write);
|
||||||
|
|
|
@ -104,7 +104,27 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
ASSERT(mode().iflnk());
|
ASSERT(mode().iflnk());
|
||||||
if (m_inode.size < sizeof(m_inode.block))
|
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);
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,8 +460,15 @@ done:
|
||||||
if (!find_inode_impl(name).is_error())
|
if (!find_inode_impl(name).is_error())
|
||||||
return BAN::Error::from_errno(EEXIST);
|
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);
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
const uint32_t new_ino = TRY(m_fs.create_inode(initialize_new_inode_info(mode, uid, gid)));
|
const uint32_t new_ino = TRY(m_fs.create_inode(initialize_new_inode_info(mode, uid, gid)));
|
||||||
|
|
||||||
|
|
|
@ -111,6 +111,14 @@ namespace Kernel
|
||||||
return link_target_impl();
|
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)
|
BAN::ErrorOr<long> Inode::accept(sockaddr* address, socklen_t* address_len, int flags)
|
||||||
{
|
{
|
||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
|
|
|
@ -368,6 +368,26 @@ namespace Kernel
|
||||||
return read_from_vec_of_str(m_environ, offset, buffer);
|
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)
|
BAN::ErrorOr<VirtualFileSystem::File> Process::find_file(int fd, const char* path, int flags)
|
||||||
{
|
{
|
||||||
ASSERT(m_process_lock.is_locked());
|
ASSERT(m_process_lock.is_locked());
|
||||||
|
@ -375,14 +395,7 @@ namespace Kernel
|
||||||
if (path)
|
if (path)
|
||||||
TRY(validate_string_access(path));
|
TRY(validate_string_access(path));
|
||||||
|
|
||||||
VirtualFileSystem::File parent_file;
|
auto parent_file = TRY(find_parent(fd, path));
|
||||||
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 file = path
|
auto file = path
|
||||||
? TRY(VirtualFileSystem::get().file_from_relative_path(parent_file, m_credentials, path, flags))
|
? TRY(VirtualFileSystem::get().file_from_relative_path(parent_file, m_credentials, path, flags))
|
||||||
: BAN::move(parent_file);
|
: BAN::move(parent_file);
|
||||||
|
@ -854,10 +867,12 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
switch (mode & Inode::Mode::TYPE_MASK)
|
switch (mode & Inode::Mode::TYPE_MASK)
|
||||||
{
|
{
|
||||||
case Inode::Mode::IFREG: break;
|
case Inode::Mode::IFREG:
|
||||||
case Inode::Mode::IFDIR: break;
|
case Inode::Mode::IFDIR:
|
||||||
case Inode::Mode::IFIFO: break;
|
case Inode::Mode::IFLNK:
|
||||||
case Inode::Mode::IFSOCK: break;
|
case Inode::Mode::IFIFO:
|
||||||
|
case Inode::Mode::IFSOCK:
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return BAN::Error::from_errno(ENOTSUP);
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
}
|
}
|
||||||
|
@ -925,21 +940,7 @@ namespace Kernel
|
||||||
|
|
||||||
TRY(validate_string_access(path));
|
TRY(validate_string_access(path));
|
||||||
|
|
||||||
VirtualFileSystem::File parent_file;
|
auto parent_file = TRY(find_parent(fd, path));
|
||||||
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 file_or_error = VirtualFileSystem::get().file_from_relative_path(parent_file, m_credentials, path, flags | O_NOFOLLOW);
|
auto file_or_error = VirtualFileSystem::get().file_from_relative_path(parent_file, m_credentials, path, flags | O_NOFOLLOW);
|
||||||
|
|
||||||
VirtualFileSystem::File file;
|
VirtualFileSystem::File file;
|
||||||
|
@ -1077,6 +1078,25 @@ namespace Kernel
|
||||||
return byte_count;
|
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)
|
BAN::ErrorOr<long> Process::sys_pread(int fd, void* buffer, size_t count, off_t offset)
|
||||||
{
|
{
|
||||||
LockGuard _(m_process_lock);
|
LockGuard _(m_process_lock);
|
||||||
|
|
|
@ -89,6 +89,7 @@ __BEGIN_DECLS
|
||||||
O(SYS_POSIX_OPENPT, posix_openpt) \
|
O(SYS_POSIX_OPENPT, posix_openpt) \
|
||||||
O(SYS_PTSNAME, ptsname) \
|
O(SYS_PTSNAME, ptsname) \
|
||||||
O(SYS_FSYNC, fsync) \
|
O(SYS_FSYNC, fsync) \
|
||||||
|
O(SYS_SYMLINKAT, symlinkat) \
|
||||||
|
|
||||||
enum Syscall
|
enum Syscall
|
||||||
{
|
{
|
||||||
|
|
|
@ -623,6 +623,10 @@ unsigned alarm(unsigned seconds)
|
||||||
|
|
||||||
int symlink(const char* path1, const char* path2)
|
int symlink(const char* path1, const char* path2)
|
||||||
{
|
{
|
||||||
dwarnln("FIXME: symlink({}, {})", path1, path2);
|
return symlinkat(path1, AT_FDCWD, path2);
|
||||||
ASSERT_NOT_REACHED();
|
}
|
||||||
|
|
||||||
|
int symlinkat(const char* path1, int fd, const char* path2)
|
||||||
|
{
|
||||||
|
return syscall(SYS_SYMLINKAT, path1, fd, path2);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue