diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 8be7a6c3..fce169bf 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -46,6 +46,7 @@ set(SOURCES src/fs/MBR.cpp src/fs/GPT.cpp src/fs/tmpfs/FileSystem.cpp + src/fs/tmpfs/Inode.cpp src/fs/devices/DeviceRegistry.cpp src/fs/devices/NullDevice.cpp src/fs/devices/ZeroDevice.cpp diff --git a/kernel/src/fs/tmpfs/FileSystem.cpp b/kernel/src/fs/tmpfs/FileSystem.cpp index b6739514..465fb5f5 100644 --- a/kernel/src/fs/tmpfs/FileSystem.cpp +++ b/kernel/src/fs/tmpfs/FileSystem.cpp @@ -1,6 +1,6 @@ #include "fs/tmpfs/FileSystem.h" -#include "fs/Mount.h" #include "fs/devices/DeviceRegistry.h" +#include "fs/tmpfs/Inode.h" #include #include #include @@ -76,131 +76,4 @@ namespace TmpFS { m_root_inode = root; } - - Result> DirInode::find(const char* name) const - { - for (const auto& entry : m_entries) - { - if (!strcmp(name, entry.name.chars())) return entry.inode; - } - - return err(ENOENT); - } - - Result DirInode::replace_entry(SharedPtr inode, const char* name) - { - for (auto& entry : m_entries) - { - if (!strcmp(name, entry.name.chars())) - { - entry.inode = inode; - return {}; - } - } - - return err(ENOENT); - } - - Option DirInode::get(usize index) const - { - if (index >= m_entries.size()) return {}; - - return m_entries[index]; - } - - Result DirInode::add_entry(SharedPtr inode, const char* name) - { - if (find(name).has_value()) return err(EEXIST); - - VFS::DirectoryEntry entry { inode, name }; - - TRY(m_entries.try_append(move(entry))); - - inode->did_link(); - - return {}; - } - - Result DirInode::remove_entry(const char* name) - { - SharedPtr inode = TRY(find(name)); - - if (inode->type() == VFS::InodeType::Directory && inode->entries() != 2) return err(ENOTEMPTY); - - if (inode->is_mountpoint()) return err(EBUSY); - - m_entries.remove_first_matching( - [&](const VFS::DirectoryEntry& entry) { return !strcmp(entry.name.chars(), name); }); - - inode->did_unlink(); - - return {}; - } - - Result> DirInode::create_file(const char* name) - { - auto inode = TRY(m_fs->create_file_inode()); - - TRY(add_entry(inode, name)); - - return inode; - } - - Result> DirInode::create_subdirectory(const char* name) - { - auto inode = TRY(m_fs->create_dir_inode(m_self)); - - TRY(add_entry(inode, name)); - - return inode; - } - - Result FileInode::read(u8* buf, usize offset, usize length) const - { - if (length == 0) return 0; - - if (offset > m_data_buffer.size()) return 0; - if (offset + length > m_data_buffer.size()) length = m_data_buffer.size() - offset; - - memcpy(buf, m_data_buffer.data() + offset, length); - - return length; - } - - Result FileInode::write(const u8* buf, usize offset, usize length) - { - if (length == 0) return 0; - - if (offset > m_data_buffer.size()) - { - // Fill the in-between space with zeroes. - usize old_size = m_data_buffer.size(); - usize zeroes = offset - old_size; - - TRY(m_data_buffer.try_resize(offset)); - - memset(m_data_buffer.data() + old_size, 0, zeroes); - } - - u8* slice = TRY(m_data_buffer.slice(offset, length)); - memcpy(slice, buf, length); - - return length; - } - - Result FileInode::truncate(usize size) - { - usize old_size = m_data_buffer.size(); - - TRY(m_data_buffer.try_resize(size)); - - if (size > old_size) memset(m_data_buffer.data() + old_size, 0, size - old_size); - - return {}; - } - - usize FileInode::size() const - { - return m_data_buffer.size(); - } } diff --git a/kernel/src/fs/tmpfs/FileSystem.h b/kernel/src/fs/tmpfs/FileSystem.h index 2e39cead..374b6f44 100644 --- a/kernel/src/fs/tmpfs/FileSystem.h +++ b/kernel/src/fs/tmpfs/FileSystem.h @@ -2,11 +2,6 @@ #include "fs/VFS.h" #include "fs/devices/DeviceRegistry.h" #include -#include -#include -#include -#include -#include namespace TmpFS { @@ -45,466 +40,4 @@ namespace TmpFS dev_t m_host_device_id; }; - - class FileInode : public VFS::FileInode - { - public: - FileInode() = default; - - void set_fs(FileSystem& fs, Badge) - { - m_fs = &fs; - } - - void set_inode_number(usize inum, Badge) - { - m_inode_number = inum; - } - - VFS::FileSystem* fs() const override - { - return m_fs; - } - - usize inode_number() const override - { - return m_inode_number; - } - - Result read(u8*, usize, usize) const override; - - Result write(const u8*, usize, usize) override; - - Result truncate(usize size) override; - - usize size() const override; - - mode_t mode() const override - { - return m_mode; - } - - u32 uid() const override - { - return m_uid; - } - - u32 gid() const override - { - return m_gid; - } - - nlink_t nlinks() const override - { - return (nlink_t)m_nlinks; - } - - Result chmod(mode_t mode) override - { - m_mode = mode; - return {}; - } - - Result chown(u32 uid, u32 gid) override - { - m_uid = uid; - m_gid = gid; - return {}; - } - - void did_link() override - { - m_nlinks++; - } - - void did_unlink() override - { - m_nlinks--; - } - - virtual ~FileInode() = default; - - private: - VFS::FileSystem* m_fs; - Buffer m_data_buffer; - usize m_inode_number; - mode_t m_mode; - u32 m_uid { 0 }; - u32 m_gid { 0 }; - u32 m_nlinks { 0 }; - }; - - class SymlinkInode : public VFS::FileInode - { - public: - SymlinkInode() = default; - - VFS::InodeType type() const override - { - return VFS::InodeType::Symlink; - } - - void set_fs(FileSystem& fs, Badge) - { - m_fs = &fs; - } - - void set_inode_number(usize inum, Badge) - { - m_inode_number = inum; - } - - Result set_link(StringView link, Badge) - { - m_link = TRY(String::from_string_view(link)); - return {}; - } - - VFS::FileSystem* fs() const override - { - return m_fs; - } - - usize inode_number() const override - { - return m_inode_number; - } - - Result read(u8*, usize, usize) const override - { - return err(ENOTSUP); - } - - Result write(const u8*, usize, usize) override - { - return err(ENOTSUP); - } - - Result truncate(usize) override - { - return err(ENOTSUP); - } - - usize size() const override - { - return m_link.length(); - } - - mode_t mode() const override - { - return 0777; - } - - u32 uid() const override - { - return m_uid; - } - - u32 gid() const override - { - return m_gid; - } - - nlink_t nlinks() const override - { - return (nlink_t)m_nlinks; - } - - Result chmod(mode_t) override - { - return {}; - } - - Result chown(u32 uid, u32 gid) override - { - m_uid = uid; - m_gid = gid; - return {}; - } - - void did_link() override - { - m_nlinks++; - } - - void did_unlink() override - { - m_nlinks--; - } - - Result readlink() override - { - return m_link.view(); - } - - virtual ~SymlinkInode() = default; - - private: - VFS::FileSystem* m_fs; - String m_link; - usize m_inode_number; - u32 m_uid { 0 }; - u32 m_gid { 0 }; - u32 m_nlinks { 0 }; - }; - - class DeviceInode : public VFS::DeviceInode - { - public: - DeviceInode() = default; - - VFS::InodeType type() const override - { - return m_device->is_block_device() ? VFS::InodeType::BlockDevice : VFS::InodeType::CharacterDevice; - } - - void set_fs(FileSystem& fs, Badge) - { - m_fs = &fs; - } - - void set_inode_number(usize inum, Badge) - { - m_inode_number = inum; - } - - void set_device(SharedPtr device, Badge) - { - m_device = device; - } - - void set_device_id(dev_t id, Badge) - { - m_device_id = id; - } - - VFS::FileSystem* fs() const override - { - return m_fs; - } - - dev_t device_id() const override - { - return m_device_id; - } - - usize inode_number() const override - { - return m_inode_number; - } - - Result read(u8* buf, usize offset, usize length) const override - { - return m_device->read(buf, offset, length); - } - - Result write(const u8* buf, usize offset, usize length) override - { - return m_device->write(buf, offset, length); - } - - Result truncate(usize) override - { - // POSIX says truncate is for regular files, but doesn't tell us what error to return for non-regular files. - return err(EINVAL); - } - - Result ioctl(int request, void* arg) override - { - return m_device->ioctl(request, arg); - } - - bool blocking() const override - { - return m_device->blocking(); - } - - usize size() const override - { - return m_device->size(); - } - - mode_t mode() const override - { - return m_mode; - } - - u32 uid() const override - { - return m_uid; - } - - u32 gid() const override - { - return m_gid; - } - - nlink_t nlinks() const override - { - return (nlink_t)m_nlinks; - } - - Result chmod(mode_t mode) override - { - m_mode = mode; - return {}; - } - - Result chown(u32 uid, u32 gid) override - { - m_uid = uid; - m_gid = gid; - return {}; - } - - void did_link() override - { - m_nlinks++; - } - - void did_unlink() override - { - m_nlinks--; - } - - virtual ~DeviceInode() = default; - - private: - VFS::FileSystem* m_fs; - SharedPtr m_device; - usize m_inode_number; - mode_t m_mode; - u32 m_uid { 0 }; - u32 m_gid { 0 }; - u32 m_nlinks { 0 }; - dev_t m_device_id { 0 }; - }; - - class DirInode : public VFS::Inode - { - public: - DirInode() = default; - - void set_fs(FileSystem& fs, Badge) - { - m_fs = &fs; - } - - void set_inode_number(usize inum, Badge) - { - m_inode_number = inum; - } - - void set_self(SharedPtr self, Badge) - { - m_self = self; - } - - Result> find(const char* name) const override; - Option get(usize index) const override; - - Result read(u8*, usize, usize) const override - { - return err(EISDIR); - } - - Result write(const u8*, usize, usize) override - { - return err(EISDIR); - } - - Result truncate(usize) override - { - return err(EISDIR); - } - - bool blocking() const override - { - return false; - } - - usize size() const override - { - return 0; - } - - mode_t mode() const override - { - return m_mode; - } - - u32 uid() const override - { - return m_uid; - } - - u32 gid() const override - { - return m_gid; - } - - Result chmod(mode_t mode) override - { - m_mode = mode; - return {}; - } - - Result chown(u32 uid, u32 gid) override - { - m_uid = uid; - m_gid = gid; - return {}; - } - - VFS::FileSystem* fs() const override - { - return m_fs; - } - - usize inode_number() const override - { - return m_inode_number; - } - - VFS::InodeType type() const override - { - return VFS::InodeType::Directory; - } - - void did_link() override - { - } - - void did_unlink() override - { - m_self = {}; - m_entries.clear(); - } - - usize entries() const override - { - return m_entries.size(); - } - - Result remove_entry(const char* name) override; - - Result> create_file(const char* name) override; - Result> create_subdirectory(const char* name) override; - - Result add_entry(SharedPtr inode, const char* name); - Result replace_entry(SharedPtr inode, const char* name); - - virtual ~DirInode() = default; - - private: - VFS::FileSystem* m_fs; - usize m_inode_number; - mode_t m_mode; - u32 m_uid { 0 }; - u32 m_gid { 0 }; - - SharedPtr m_self; - - Vector m_entries; - }; } diff --git a/kernel/src/fs/tmpfs/Inode.cpp b/kernel/src/fs/tmpfs/Inode.cpp new file mode 100644 index 00000000..221dfb99 --- /dev/null +++ b/kernel/src/fs/tmpfs/Inode.cpp @@ -0,0 +1,131 @@ +#include "fs/tmpfs/Inode.h" + +namespace TmpFS +{ + Result> DirInode::find(const char* name) const + { + for (const auto& entry : m_entries) + { + if (!strcmp(name, entry.name.chars())) return entry.inode; + } + + return err(ENOENT); + } + + Result DirInode::replace_entry(SharedPtr inode, const char* name) + { + for (auto& entry : m_entries) + { + if (!strcmp(name, entry.name.chars())) + { + entry.inode = inode; + return {}; + } + } + + return err(ENOENT); + } + + Option DirInode::get(usize index) const + { + if (index >= m_entries.size()) return {}; + + return m_entries[index]; + } + + Result DirInode::add_entry(SharedPtr inode, const char* name) + { + if (find(name).has_value()) return err(EEXIST); + + VFS::DirectoryEntry entry { inode, name }; + + TRY(m_entries.try_append(move(entry))); + + inode->did_link(); + + return {}; + } + + Result DirInode::remove_entry(const char* name) + { + SharedPtr inode = TRY(find(name)); + + if (inode->type() == VFS::InodeType::Directory && inode->entries() != 2) return err(ENOTEMPTY); + + if (inode->is_mountpoint()) return err(EBUSY); + + m_entries.remove_first_matching( + [&](const VFS::DirectoryEntry& entry) { return !strcmp(entry.name.chars(), name); }); + + inode->did_unlink(); + + return {}; + } + + Result> DirInode::create_file(const char* name) + { + auto inode = TRY(m_fs->create_file_inode()); + + TRY(add_entry(inode, name)); + + return inode; + } + + Result> DirInode::create_subdirectory(const char* name) + { + auto inode = TRY(m_fs->create_dir_inode(m_self)); + + TRY(add_entry(inode, name)); + + return inode; + } + + Result FileInode::read(u8* buf, usize offset, usize length) const + { + if (length == 0) return 0; + + if (offset > m_data_buffer.size()) return 0; + if (offset + length > m_data_buffer.size()) length = m_data_buffer.size() - offset; + + memcpy(buf, m_data_buffer.data() + offset, length); + + return length; + } + + Result FileInode::write(const u8* buf, usize offset, usize length) + { + if (length == 0) return 0; + + if (offset > m_data_buffer.size()) + { + // Fill the in-between space with zeroes. + usize old_size = m_data_buffer.size(); + usize zeroes = offset - old_size; + + TRY(m_data_buffer.try_resize(offset)); + + memset(m_data_buffer.data() + old_size, 0, zeroes); + } + + u8* slice = TRY(m_data_buffer.slice(offset, length)); + memcpy(slice, buf, length); + + return length; + } + + Result FileInode::truncate(usize size) + { + usize old_size = m_data_buffer.size(); + + TRY(m_data_buffer.try_resize(size)); + + if (size > old_size) memset(m_data_buffer.data() + old_size, 0, size - old_size); + + return {}; + } + + usize FileInode::size() const + { + return m_data_buffer.size(); + } +} diff --git a/kernel/src/fs/tmpfs/Inode.h b/kernel/src/fs/tmpfs/Inode.h new file mode 100644 index 00000000..082f1a0c --- /dev/null +++ b/kernel/src/fs/tmpfs/Inode.h @@ -0,0 +1,472 @@ +#pragma once +#include "fs/tmpfs/FileSystem.h" +#include +#include +#include +#include +#include + +namespace TmpFS +{ + class FileInode : public VFS::FileInode + { + public: + FileInode() = default; + + void set_fs(FileSystem& fs, Badge) + { + m_fs = &fs; + } + + void set_inode_number(usize inum, Badge) + { + m_inode_number = inum; + } + + VFS::FileSystem* fs() const override + { + return m_fs; + } + + usize inode_number() const override + { + return m_inode_number; + } + + Result read(u8*, usize, usize) const override; + + Result write(const u8*, usize, usize) override; + + Result truncate(usize size) override; + + usize size() const override; + + mode_t mode() const override + { + return m_mode; + } + + u32 uid() const override + { + return m_uid; + } + + u32 gid() const override + { + return m_gid; + } + + nlink_t nlinks() const override + { + return (nlink_t)m_nlinks; + } + + Result chmod(mode_t mode) override + { + m_mode = mode; + return {}; + } + + Result chown(u32 uid, u32 gid) override + { + m_uid = uid; + m_gid = gid; + return {}; + } + + void did_link() override + { + m_nlinks++; + } + + void did_unlink() override + { + m_nlinks--; + } + + virtual ~FileInode() = default; + + private: + VFS::FileSystem* m_fs; + Buffer m_data_buffer; + usize m_inode_number; + mode_t m_mode; + u32 m_uid { 0 }; + u32 m_gid { 0 }; + u32 m_nlinks { 0 }; + }; + + class SymlinkInode : public VFS::FileInode + { + public: + SymlinkInode() = default; + + VFS::InodeType type() const override + { + return VFS::InodeType::Symlink; + } + + void set_fs(FileSystem& fs, Badge) + { + m_fs = &fs; + } + + void set_inode_number(usize inum, Badge) + { + m_inode_number = inum; + } + + Result set_link(StringView link, Badge) + { + m_link = TRY(String::from_string_view(link)); + return {}; + } + + VFS::FileSystem* fs() const override + { + return m_fs; + } + + usize inode_number() const override + { + return m_inode_number; + } + + Result read(u8*, usize, usize) const override + { + return err(ENOTSUP); + } + + Result write(const u8*, usize, usize) override + { + return err(ENOTSUP); + } + + Result truncate(usize) override + { + return err(ENOTSUP); + } + + usize size() const override + { + return m_link.length(); + } + + mode_t mode() const override + { + return 0777; + } + + u32 uid() const override + { + return m_uid; + } + + u32 gid() const override + { + return m_gid; + } + + nlink_t nlinks() const override + { + return (nlink_t)m_nlinks; + } + + Result chmod(mode_t) override + { + return {}; + } + + Result chown(u32 uid, u32 gid) override + { + m_uid = uid; + m_gid = gid; + return {}; + } + + void did_link() override + { + m_nlinks++; + } + + void did_unlink() override + { + m_nlinks--; + } + + Result readlink() override + { + return m_link.view(); + } + + virtual ~SymlinkInode() = default; + + private: + VFS::FileSystem* m_fs; + String m_link; + usize m_inode_number; + u32 m_uid { 0 }; + u32 m_gid { 0 }; + u32 m_nlinks { 0 }; + }; + + class DeviceInode : public VFS::DeviceInode + { + public: + DeviceInode() = default; + + VFS::InodeType type() const override + { + return m_device->is_block_device() ? VFS::InodeType::BlockDevice : VFS::InodeType::CharacterDevice; + } + + void set_fs(FileSystem& fs, Badge) + { + m_fs = &fs; + } + + void set_inode_number(usize inum, Badge) + { + m_inode_number = inum; + } + + void set_device(SharedPtr device, Badge) + { + m_device = device; + } + + void set_device_id(dev_t id, Badge) + { + m_device_id = id; + } + + VFS::FileSystem* fs() const override + { + return m_fs; + } + + dev_t device_id() const override + { + return m_device_id; + } + + usize inode_number() const override + { + return m_inode_number; + } + + Result read(u8* buf, usize offset, usize length) const override + { + return m_device->read(buf, offset, length); + } + + Result write(const u8* buf, usize offset, usize length) override + { + return m_device->write(buf, offset, length); + } + + Result truncate(usize) override + { + // POSIX says truncate is for regular files, but doesn't tell us what error to return for non-regular files. + return err(EINVAL); + } + + Result ioctl(int request, void* arg) override + { + return m_device->ioctl(request, arg); + } + + bool blocking() const override + { + return m_device->blocking(); + } + + usize size() const override + { + return m_device->size(); + } + + mode_t mode() const override + { + return m_mode; + } + + u32 uid() const override + { + return m_uid; + } + + u32 gid() const override + { + return m_gid; + } + + nlink_t nlinks() const override + { + return (nlink_t)m_nlinks; + } + + Result chmod(mode_t mode) override + { + m_mode = mode; + return {}; + } + + Result chown(u32 uid, u32 gid) override + { + m_uid = uid; + m_gid = gid; + return {}; + } + + void did_link() override + { + m_nlinks++; + } + + void did_unlink() override + { + m_nlinks--; + } + + virtual ~DeviceInode() = default; + + private: + VFS::FileSystem* m_fs; + SharedPtr m_device; + usize m_inode_number; + mode_t m_mode; + u32 m_uid { 0 }; + u32 m_gid { 0 }; + u32 m_nlinks { 0 }; + dev_t m_device_id { 0 }; + }; + + class DirInode : public VFS::Inode + { + public: + DirInode() = default; + + void set_fs(FileSystem& fs, Badge) + { + m_fs = &fs; + } + + void set_inode_number(usize inum, Badge) + { + m_inode_number = inum; + } + + void set_self(SharedPtr self, Badge) + { + m_self = self; + } + + Result> find(const char* name) const override; + Option get(usize index) const override; + + Result read(u8*, usize, usize) const override + { + return err(EISDIR); + } + + Result write(const u8*, usize, usize) override + { + return err(EISDIR); + } + + Result truncate(usize) override + { + return err(EISDIR); + } + + bool blocking() const override + { + return false; + } + + usize size() const override + { + return 0; + } + + mode_t mode() const override + { + return m_mode; + } + + u32 uid() const override + { + return m_uid; + } + + u32 gid() const override + { + return m_gid; + } + + Result chmod(mode_t mode) override + { + m_mode = mode; + return {}; + } + + Result chown(u32 uid, u32 gid) override + { + m_uid = uid; + m_gid = gid; + return {}; + } + + VFS::FileSystem* fs() const override + { + return m_fs; + } + + usize inode_number() const override + { + return m_inode_number; + } + + VFS::InodeType type() const override + { + return VFS::InodeType::Directory; + } + + void did_link() override + { + } + + void did_unlink() override + { + m_self = {}; + m_entries.clear(); + } + + usize entries() const override + { + return m_entries.size(); + } + + Result remove_entry(const char* name) override; + + Result> create_file(const char* name) override; + Result> create_subdirectory(const char* name) override; + + Result add_entry(SharedPtr inode, const char* name); + Result replace_entry(SharedPtr inode, const char* name); + + virtual ~DirInode() = default; + + private: + VFS::FileSystem* m_fs; + usize m_inode_number; + mode_t m_mode; + u32 m_uid { 0 }; + u32 m_gid { 0 }; + + SharedPtr m_self; + + Vector m_entries; + }; +}