diff --git a/Kernel/FileSystem/ProcFS.cpp b/Kernel/FileSystem/ProcFS.cpp index 0d18496243..d45c57d164 100644 --- a/Kernel/FileSystem/ProcFS.cpp +++ b/Kernel/FileSystem/ProcFS.cpp @@ -1366,6 +1366,119 @@ ssize_t ProcFSInode::write_bytes(off_t offset, ssize_t size, const u8* buffer, F return 0; } +KResultOr> ProcFSInode::resolve_as_link(Custody& base, RefPtr* out_parent, int options, int symlink_recursion_level) const +{ + if (!is_process_related_file(identifier())) + return Inode::resolve_as_link(base, out_parent, options, symlink_recursion_level); + + // FIXME: We should return a custody for FI_PID or FI_PID_fd here + // for correctness. It's impossible to create files in ProcFS, + // so returning null shouldn't break much. + if (out_parent) + *out_parent = nullptr; + + auto pid = to_pid(identifier()); + auto proc_file_type = to_proc_file_type(identifier()); + auto handle = ProcessInspectionHandle::from_pid(pid); + if (!handle) + return KResult(-ENOENT); + auto& process = handle->process(); + + if (to_proc_parent_directory(identifier()) == PDI_PID_fd) { + if (out_parent) + *out_parent = base; + int fd = to_fd(identifier()); + auto description = process.file_description(fd); + if (!description) + return KResult(-ENOENT); + auto proxy_inode = ProcFSProxyInode::create(const_cast(fs()), *description); + return Custody::create(&base, "", proxy_inode, base.mount_flags()); + } + + Custody* res = nullptr; + + switch (proc_file_type) { + case FI_PID_cwd: + res = &process.current_directory(); + break; + case FI_PID_exe: + res = process.executable(); + break; + case FI_PID_root: + // Note: we open root_directory() here, not + // root_directory_relative_to_global_root(). + // This seems more useful. + res = &process.root_directory(); + break; + default: + ASSERT_NOT_REACHED(); + } + + if (!res) + return KResult(-ENOENT); + + return *res; +} + +ProcFSProxyInode::ProcFSProxyInode(ProcFS& fs, FileDescription& fd) + : Inode(fs, 0) + , m_fd(fd) +{ +} + +ProcFSProxyInode::~ProcFSProxyInode() +{ +} + +InodeMetadata ProcFSProxyInode::metadata() const +{ + InodeMetadata metadata = m_fd->metadata(); + + if (m_fd->is_readable()) + metadata.mode |= 0444; + else + metadata.mode &= ~0444; + + if (m_fd->is_writable()) + metadata.mode |= 0222; + else + metadata.mode &= ~0222; + + if (!metadata.is_directory()) + metadata.mode &= ~0111; + + return metadata; +} + +KResult ProcFSProxyInode::add_child(InodeIdentifier child_id, const StringView& name, mode_t mode) +{ + if (!m_fd->inode()) + return KResult(-EINVAL); + return m_fd->inode()->add_child(child_id, name, mode); +} + +KResult ProcFSProxyInode::remove_child(const StringView& name) +{ + if (!m_fd->inode()) + return KResult(-EINVAL); + return m_fd->inode()->remove_child(name); +} + +InodeIdentifier ProcFSProxyInode::lookup(StringView name) +{ + if (!m_fd->inode()) + return {}; + return m_fd->inode()->lookup(name); +} + +size_t ProcFSProxyInode::directory_entry_count() const +{ + if (!m_fd->inode()) + return 0; + return m_fd->inode()->directory_entry_count(); +} + + KResult ProcFSInode::add_child(InodeIdentifier child_id, const StringView& name, mode_t) { (void)child_id; diff --git a/Kernel/FileSystem/ProcFS.h b/Kernel/FileSystem/ProcFS.h index c68f3c46e7..639f1a2204 100644 --- a/Kernel/FileSystem/ProcFS.h +++ b/Kernel/FileSystem/ProcFS.h @@ -81,8 +81,43 @@ private: virtual size_t directory_entry_count() const override; virtual KResult chmod(mode_t) override; virtual KResult chown(uid_t, gid_t) override; + virtual KResultOr> resolve_as_link(Custody& base, RefPtr* out_parent = nullptr, int options = 0, int symlink_recursion_level = 0) const override; ProcFS& fs() { return static_cast(Inode::fs()); } const ProcFS& fs() const { return static_cast(Inode::fs()); } ProcFSInode(ProcFS&, unsigned index); }; + +class ProcFSProxyInode final : public Inode { + friend class ProcFSInode; + +public: + virtual ~ProcFSProxyInode() override; + +private: + // ^Inode + virtual ssize_t read_bytes(off_t, ssize_t, u8*, FileDescription*) const override { ASSERT_NOT_REACHED(); } + virtual InodeMetadata metadata() const override; + virtual bool traverse_as_directory(Function) const override { ASSERT_NOT_REACHED(); } + virtual InodeIdentifier lookup(StringView name) override; + virtual void flush_metadata() override {}; + virtual ssize_t write_bytes(off_t, ssize_t, const u8*, FileDescription*) override { ASSERT_NOT_REACHED(); } + virtual KResult add_child(InodeIdentifier child_id, const StringView& name, mode_t) override; + virtual KResult remove_child(const StringView& name) override; + virtual size_t directory_entry_count() const override; + virtual KResult chmod(mode_t) override { return KResult(-EINVAL); } + virtual KResult chown(uid_t, gid_t) override { return KResult(-EINVAL); } + virtual KResultOr> resolve_as_link(Custody&, RefPtr*, int, int) const override { ASSERT_NOT_REACHED(); } + virtual FileDescription* preopen_fd() override { return m_fd; } + + ProcFS& fs() { return static_cast(Inode::fs()); } + const ProcFS& fs() const { return static_cast(Inode::fs()); } + + ProcFSProxyInode(ProcFS&, FileDescription&); + static NonnullRefPtr create(ProcFS& fs, FileDescription& fd) + { + return adopt(*new ProcFSProxyInode(fs, fd)); + } + + NonnullRefPtr m_fd; +};