diff --git a/kernel/include/kernel/FS/ProcFS/Inode.h b/kernel/include/kernel/FS/ProcFS/Inode.h index ca55a92c..91b63c54 100644 --- a/kernel/include/kernel/FS/ProcFS/Inode.h +++ b/kernel/include/kernel/FS/ProcFS/Inode.h @@ -69,10 +69,6 @@ namespace Kernel protected: virtual BAN::ErrorOr link_target_impl() override; - // You may not write here and this is always non blocking - virtual BAN::ErrorOr write_impl(off_t, BAN::ConstByteSpan) override { return BAN::Error::from_errno(EINVAL); } - virtual BAN::ErrorOr truncate_impl(size_t) override { return BAN::Error::from_errno(EINVAL); } - virtual bool can_read_impl() const override { return false; } virtual bool can_write_impl() const override { return false; } virtual bool has_error_impl() const override { return false; } @@ -114,27 +110,54 @@ namespace Kernel class ProcSymlinkInode final : public TmpInode { public: - static BAN::ErrorOr> create_new(BAN::ErrorOr (*)(void*), void* data, TmpFileSystem&, mode_t, uid_t, gid_t); - ~ProcSymlinkInode() = default; + static BAN::ErrorOr> create_new(BAN::ErrorOr (*)(void*), void (*)(void*), void* data, TmpFileSystem&, mode_t, uid_t, gid_t); + ~ProcSymlinkInode(); protected: virtual BAN::ErrorOr link_target_impl() override; - // You may not write here and this is always non blocking - virtual BAN::ErrorOr write_impl(off_t, BAN::ConstByteSpan) override { return BAN::Error::from_errno(EINVAL); } - virtual BAN::ErrorOr truncate_impl(size_t) override { return BAN::Error::from_errno(EINVAL); } - virtual bool can_read_impl() const override { return false; } virtual bool can_write_impl() const override { return false; } virtual bool has_error_impl() const override { return false; } virtual bool has_hungup_impl() const override { return false; } private: - ProcSymlinkInode(BAN::ErrorOr (*callback)(void*), void* data, TmpFileSystem&, const TmpInodeInfo&); + ProcSymlinkInode(BAN::ErrorOr (*callback)(void*), void (*destructor)(void*), void* data, TmpFileSystem&, const TmpInodeInfo&); private: BAN::ErrorOr (*m_callback)(void*); + void (*m_destructor)(void*); void* m_data; }; + class ProcFDDirectoryInode final : public TmpInode + { + public: + static BAN::ErrorOr> create_new(Process&, TmpFileSystem&, mode_t); + ~ProcFDDirectoryInode() = default; + + virtual uid_t uid() const override { return m_process.credentials().ruid(); } + virtual gid_t gid() const override { return m_process.credentials().rgid(); } + + protected: + virtual BAN::ErrorOr> find_inode_impl(BAN::StringView) override; + virtual BAN::ErrorOr list_next_inodes_impl(off_t, struct dirent*, size_t) override; + virtual BAN::ErrorOr create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override { return BAN::Error::from_errno(EPERM); } + virtual BAN::ErrorOr create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override { return BAN::Error::from_errno(EPERM); } + virtual BAN::ErrorOr link_inode_impl(BAN::StringView, BAN::RefPtr) override { return BAN::Error::from_errno(EPERM); } + virtual BAN::ErrorOr rename_inode_impl(BAN::RefPtr, BAN::StringView, BAN::StringView) override { return BAN::Error::from_errno(EPERM); } + virtual BAN::ErrorOr unlink_impl(BAN::StringView) override { return BAN::Error::from_errno(EPERM); } + + virtual bool can_read_impl() const override { return false; } + virtual bool can_write_impl() const override { return false; } + virtual bool has_error_impl() const override { return false; } + virtual bool has_hungup_impl() const override { return false; } + + private: + ProcFDDirectoryInode(Process&, TmpFileSystem&, const TmpInodeInfo&); + + private: + Process& m_process; + }; + } diff --git a/kernel/kernel/FS/ProcFS/FileSystem.cpp b/kernel/kernel/FS/ProcFS/FileSystem.cpp index c9452320..55f224b9 100644 --- a/kernel/kernel/FS/ProcFS/FileSystem.cpp +++ b/kernel/kernel/FS/ProcFS/FileSystem.cpp @@ -43,7 +43,7 @@ namespace Kernel [](void*) -> BAN::ErrorOr { return BAN::String::formatted("{}", Process::current().pid()); }, - nullptr, *s_instance, 0444, 0, 0) + nullptr, nullptr, *s_instance, 0444, 0, 0) ); MUST(static_cast(s_instance->root_inode().ptr())->link_inode(*self_inode, "self"_sv)); } diff --git a/kernel/kernel/FS/ProcFS/Inode.cpp b/kernel/kernel/FS/ProcFS/Inode.cpp index 02545507..252fcda7 100644 --- a/kernel/kernel/FS/ProcFS/Inode.cpp +++ b/kernel/kernel/FS/ProcFS/Inode.cpp @@ -1,5 +1,7 @@ #include +#include + namespace Kernel { @@ -19,6 +21,7 @@ namespace Kernel TRY(inode->link_inode(*MUST(ProcROProcessInode::create_new(process, &Process::proc_environ, fs, 0400)), "environ"_sv)); TRY(inode->link_inode(*MUST(ProcSymlinkProcessInode::create_new(process, &Process::proc_cwd, fs, 0777)), "cwd"_sv)); TRY(inode->link_inode(*MUST(ProcSymlinkProcessInode::create_new(process, &Process::proc_exe, fs, 0777)), "exe"_sv)); + TRY(inode->link_inode(*MUST(ProcFDDirectoryInode::create_new(process, fs, 0777)), "fd"_sv)); return inode; } @@ -36,6 +39,7 @@ namespace Kernel (void)TmpDirectoryInode::unlink_impl("environ"_sv); (void)TmpDirectoryInode::unlink_impl("cwd"_sv); (void)TmpDirectoryInode::unlink_impl("exe"_sv); + (void)TmpDirectoryInode::unlink_impl("fd"_sv); } BAN::ErrorOr> ProcROProcessInode::create_new(Process& process, size_t (Process::*callback)(off_t, BAN::ByteSpan) const, TmpFileSystem& fs, mode_t mode) @@ -110,27 +114,123 @@ namespace Kernel return m_callback(offset, buffer); } - BAN::ErrorOr> ProcSymlinkInode::create_new(BAN::ErrorOr (*callback)(void*), void* data, TmpFileSystem& fs, mode_t mode, uid_t uid, gid_t gid) + BAN::ErrorOr> ProcSymlinkInode::create_new(BAN::ErrorOr (*callback)(void*), void (*destructor)(void*), void* data, TmpFileSystem& fs, mode_t mode, uid_t uid, gid_t gid) { auto inode_info = create_inode_info(Mode::IFLNK | mode, uid, gid); - auto* inode_ptr = new ProcSymlinkInode(callback, data, fs, inode_info); + auto* inode_ptr = new ProcSymlinkInode(callback, destructor, data, fs, inode_info); if (inode_ptr == nullptr) return BAN::Error::from_errno(ENOMEM); return BAN::RefPtr::adopt(inode_ptr); } - ProcSymlinkInode::ProcSymlinkInode(BAN::ErrorOr (*callback)(void*), void* data, TmpFileSystem& fs, const TmpInodeInfo& inode_info) + ProcSymlinkInode::ProcSymlinkInode(BAN::ErrorOr (*callback)(void*), void (*destructor)(void*), void* data, TmpFileSystem& fs, const TmpInodeInfo& inode_info) : TmpInode(fs, MUST(fs.allocate_inode(inode_info)), inode_info) , m_callback(callback) + , m_destructor(destructor) , m_data(data) { m_inode_info.mode |= Inode::Mode::IFLNK; } + ProcSymlinkInode::~ProcSymlinkInode() + { + if (m_destructor) + m_destructor(m_data); + } + BAN::ErrorOr ProcSymlinkInode::link_target_impl() { return m_callback(m_data); } + BAN::ErrorOr> ProcFDDirectoryInode::create_new(Process& process, TmpFileSystem& fs, mode_t mode) + { + auto inode_info = create_inode_info(Mode::IFDIR | mode, 0, 0); + + auto* inode_ptr = new ProcFDDirectoryInode(process, fs, inode_info); + if (inode_ptr == nullptr) + return BAN::Error::from_errno(ENOMEM); + return BAN::RefPtr::adopt(inode_ptr); + } + + ProcFDDirectoryInode::ProcFDDirectoryInode(Process& process, TmpFileSystem& fs, const TmpInodeInfo& inode_info) + : TmpInode(fs, MUST(fs.allocate_inode(inode_info)), inode_info) + , m_process(process) + { + ASSERT(mode().ifdir()); + } + + BAN::ErrorOr> ProcFDDirectoryInode::find_inode_impl(BAN::StringView name) + { + int fd = 0; + for (char ch : name) + { + if (!isdigit(ch)) + return BAN::Error::from_errno(ENOENT); + fd = (fd * 10) + (ch - '0'); + if (fd > OPEN_MAX) + return BAN::Error::from_errno(ENOENT); + } + + auto path_or_error = m_process.open_file_descriptor_set().path_of(fd); + if (path_or_error.is_error()) + return BAN::Error::from_errno(ENOENT); + + auto* data = new BAN::String(); + if (data == nullptr) + return BAN::Error::from_errno(ENOMEM); + *data = BAN::move(path_or_error.release_value()); + + auto inode = TRY(ProcSymlinkInode::create_new( + [](void* data) -> BAN::ErrorOr + { + BAN::String result; + TRY(result.append(*static_cast(data))); + return result; + }, + [](void* data) -> void + { + delete static_cast(data); + }, + data, m_fs, 0777, uid(), gid() + )); + + return BAN::RefPtr(BAN::move(inode)); + } + + BAN::ErrorOr ProcFDDirectoryInode::list_next_inodes_impl(off_t offset, struct dirent* list, size_t list_len) + { + if (list_len == 0) + return BAN::Error::from_errno(ENOBUFS); + + auto& ofds = m_process.open_file_descriptor_set(); + + for (size_t fd = 0; fd < OPEN_MAX; fd++) + { + if (ofds.inode_of(fd).is_error()) + continue; + if (offset-- > 0) + continue; + + list[0] = { + .d_ino = 0, + .d_type = DT_LNK, + .d_name = {}, + }; + + size_t index = 0; + BAN::Formatter::print( + [&](char ch) { + list[0].d_name[index++] = ch; + list[0].d_name[index] = '\0'; + }, "{}", fd + ); + + return 1; + } + + return 0; + } + }