2023-03-30 14:22:15 +03:00
|
|
|
#include <BAN/ScopeGuard.h>
|
2023-02-22 01:23:11 +02:00
|
|
|
#include <BAN/StringView.h>
|
2023-03-30 22:39:45 +03:00
|
|
|
#include <kernel/DeviceManager.h>
|
2023-02-26 03:00:29 +02:00
|
|
|
#include <kernel/FS/Ext2.h>
|
2023-02-20 01:46:00 +02:00
|
|
|
#include <kernel/FS/VirtualFileSystem.h>
|
2023-03-30 22:02:16 +03:00
|
|
|
#include <kernel/LockGuard.h>
|
2023-02-26 03:00:29 +02:00
|
|
|
#include <kernel/PCI.h>
|
2023-02-20 01:46:00 +02:00
|
|
|
|
|
|
|
namespace Kernel
|
|
|
|
{
|
|
|
|
|
|
|
|
static VirtualFileSystem* s_instance = nullptr;
|
|
|
|
|
2023-03-30 16:37:53 +03:00
|
|
|
BAN::ErrorOr<void> VirtualFileSystem::initialize(BAN::StringView root)
|
2023-02-20 01:46:00 +02:00
|
|
|
{
|
|
|
|
ASSERT(s_instance == nullptr);
|
2023-02-26 03:00:29 +02:00
|
|
|
s_instance = new VirtualFileSystem();
|
|
|
|
if (s_instance == nullptr)
|
2023-03-02 21:10:44 +02:00
|
|
|
return BAN::Error::from_errno(ENOMEM);
|
2023-03-30 14:22:15 +03:00
|
|
|
BAN::ScopeGuard guard([] { delete s_instance; s_instance = nullptr; } );
|
2023-03-09 02:17:42 +02:00
|
|
|
|
2023-03-30 16:37:53 +03:00
|
|
|
if (root.size() < 5 || root.substring(0, 5) != "/dev/")
|
|
|
|
return BAN::Error::from_c_string("root must be in /dev/");
|
|
|
|
root = root.substring(5);
|
|
|
|
|
|
|
|
auto partition_inode = TRY(DeviceManager::get().read_directory_inode(root));
|
2023-03-30 14:22:15 +03:00
|
|
|
s_instance->m_root_fs = TRY(Ext2FS::create(*(Partition*)partition_inode.ptr()));
|
2023-03-30 16:37:53 +03:00
|
|
|
|
2023-03-30 14:22:15 +03:00
|
|
|
TRY(s_instance->mount(&DeviceManager::get(), "/dev"));
|
|
|
|
|
|
|
|
guard.disable();
|
2023-03-09 02:17:42 +02:00
|
|
|
|
|
|
|
return {};
|
2023-02-20 01:46:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
VirtualFileSystem& VirtualFileSystem::get()
|
|
|
|
{
|
|
|
|
ASSERT(s_instance);
|
|
|
|
return *s_instance;
|
|
|
|
}
|
|
|
|
|
2023-03-30 15:06:41 +03:00
|
|
|
BAN::ErrorOr<void> VirtualFileSystem::mount(BAN::StringView partition, BAN::StringView target)
|
|
|
|
{
|
|
|
|
auto partition_file = TRY(file_from_absolute_path(partition));
|
|
|
|
if (partition_file.inode->inode_type() != Inode::InodeType::Device)
|
|
|
|
return BAN::Error::from_c_string("Not a partition");
|
2023-03-30 22:02:16 +03:00
|
|
|
|
2023-03-30 15:06:41 +03:00
|
|
|
Device* device = (Device*)partition_file.inode.ptr();
|
|
|
|
if (device->device_type() != Device::DeviceType::Partition)
|
|
|
|
return BAN::Error::from_c_string("Not a partition");
|
2023-03-30 22:02:16 +03:00
|
|
|
|
2023-03-30 15:06:41 +03:00
|
|
|
auto* file_system = TRY(Ext2FS::create(*(Partition*)device));
|
|
|
|
return mount(file_system, target);
|
|
|
|
}
|
|
|
|
|
2023-03-29 11:50:46 +03:00
|
|
|
BAN::ErrorOr<void> VirtualFileSystem::mount(FileSystem* file_system, BAN::StringView path)
|
|
|
|
{
|
|
|
|
auto file = TRY(file_from_absolute_path(path));
|
2023-03-30 14:41:15 +03:00
|
|
|
if (!file.inode->mode().ifdir())
|
2023-03-29 11:50:46 +03:00
|
|
|
return BAN::Error::from_errno(ENOTDIR);
|
2023-03-30 22:02:16 +03:00
|
|
|
|
|
|
|
LockGuard _(m_lock);
|
2023-03-29 21:34:48 +03:00
|
|
|
TRY(m_mount_points.push_back({ file, file_system }));
|
2023-03-30 22:02:16 +03:00
|
|
|
|
2023-03-19 05:51:25 +02:00
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2023-03-29 21:34:48 +03:00
|
|
|
VirtualFileSystem::MountPoint* VirtualFileSystem::mount_point_for_inode(BAN::RefPtr<Inode> inode)
|
|
|
|
{
|
2023-03-30 22:02:16 +03:00
|
|
|
ASSERT(m_lock.is_locked());
|
2023-03-29 21:34:48 +03:00
|
|
|
for (MountPoint& mount : m_mount_points)
|
|
|
|
if (*mount.host.inode == *inode)
|
|
|
|
return &mount;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2023-03-17 21:16:22 +02:00
|
|
|
BAN::ErrorOr<VirtualFileSystem::File> VirtualFileSystem::file_from_absolute_path(BAN::StringView path)
|
2023-02-22 01:23:11 +02:00
|
|
|
{
|
2023-03-30 22:02:16 +03:00
|
|
|
LockGuard _(m_lock);
|
|
|
|
|
2023-03-16 15:31:33 +02:00
|
|
|
ASSERT(path.front() == '/');
|
2023-02-22 01:23:11 +02:00
|
|
|
|
|
|
|
auto inode = root_inode();
|
2023-03-09 02:31:24 +02:00
|
|
|
if (!inode)
|
|
|
|
return BAN::Error::from_c_string("No root inode available");
|
|
|
|
|
2023-03-29 21:34:48 +03:00
|
|
|
BAN::String canonical_path;
|
2023-03-16 15:31:33 +02:00
|
|
|
|
2023-03-29 21:34:48 +03:00
|
|
|
const auto path_parts = TRY(path.split('/'));
|
|
|
|
|
2023-03-30 16:37:53 +03:00
|
|
|
for (auto path_part : path_parts)
|
2023-03-17 21:16:22 +02:00
|
|
|
{
|
2023-03-29 21:34:48 +03:00
|
|
|
if (path_part.empty() || path_part == "."sv)
|
2023-03-17 21:16:22 +02:00
|
|
|
{
|
2023-03-29 21:34:48 +03:00
|
|
|
continue;
|
2023-03-17 21:16:22 +02:00
|
|
|
}
|
2023-03-29 21:34:48 +03:00
|
|
|
else if (path_part == ".."sv)
|
2023-03-17 21:16:22 +02:00
|
|
|
{
|
2023-03-29 21:34:48 +03:00
|
|
|
if (auto* mount_point = mount_point_for_inode(inode))
|
|
|
|
inode = TRY(mount_point->host.inode->read_directory_inode(".."sv));
|
|
|
|
else
|
|
|
|
inode = TRY(inode->read_directory_inode(".."sv));
|
|
|
|
|
|
|
|
if (!canonical_path.empty())
|
2023-03-17 21:16:22 +02:00
|
|
|
{
|
2023-03-29 21:34:48 +03:00
|
|
|
while (canonical_path.back() != '/')
|
|
|
|
canonical_path.pop_back();
|
|
|
|
canonical_path.pop_back();
|
2023-03-17 21:16:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-03-29 21:34:48 +03:00
|
|
|
inode = TRY(inode->read_directory_inode(path_part));
|
|
|
|
TRY(canonical_path.push_back('/'));
|
|
|
|
TRY(canonical_path.append(path_part));
|
2023-03-17 21:16:22 +02:00
|
|
|
}
|
2023-03-29 21:34:48 +03:00
|
|
|
|
|
|
|
if (auto* mount_point = mount_point_for_inode(inode))
|
|
|
|
inode = mount_point->target->root_inode();
|
2023-03-17 21:16:22 +02:00
|
|
|
}
|
|
|
|
|
2023-03-29 21:34:48 +03:00
|
|
|
if (canonical_path.empty())
|
|
|
|
TRY(canonical_path.push_back('/'));
|
|
|
|
|
2023-03-17 21:16:22 +02:00
|
|
|
File file;
|
|
|
|
file.inode = inode;
|
2023-03-29 21:34:48 +03:00
|
|
|
file.canonical_path = BAN::move(canonical_path);
|
2023-03-17 21:16:22 +02:00
|
|
|
|
|
|
|
if (file.canonical_path.empty())
|
|
|
|
TRY(file.canonical_path.push_back('/'));
|
|
|
|
|
|
|
|
return file;
|
2023-02-22 01:23:11 +02:00
|
|
|
}
|
|
|
|
|
2023-02-20 01:46:00 +02:00
|
|
|
}
|