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-07-10 23:17:14 +03:00
|
|
|
#include <kernel/FS/DevFS/FileSystem.h>
|
2023-09-01 15:10:23 +03:00
|
|
|
#include <kernel/FS/Ext2/FileSystem.h>
|
2023-07-10 13:26:14 +03:00
|
|
|
#include <kernel/FS/RamFS/FileSystem.h>
|
|
|
|
#include <kernel/FS/RamFS/Inode.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-06-11 19:52:13 +03:00
|
|
|
#include <fcntl.h>
|
2023-02-20 01:46:00 +02:00
|
|
|
|
|
|
|
namespace Kernel
|
|
|
|
{
|
|
|
|
|
|
|
|
static VirtualFileSystem* s_instance = nullptr;
|
|
|
|
|
2023-06-11 19:52:13 +03:00
|
|
|
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();
|
2023-06-11 19:52:13 +03:00
|
|
|
ASSERT(s_instance);
|
2023-03-09 02:17:42 +02:00
|
|
|
|
2023-04-11 23:25:21 +03:00
|
|
|
ASSERT(root.size() >= 5 && root.substring(0, 5) == "/dev/"sv);;
|
2023-03-30 16:37:53 +03:00
|
|
|
root = root.substring(5);
|
|
|
|
|
2023-07-10 23:17:14 +03:00
|
|
|
auto partition_inode = MUST(DevFileSystem::get().root_inode()->directory_find_inode(root));
|
2023-06-11 19:52:13 +03:00
|
|
|
s_instance->m_root_fs = MUST(Ext2FS::create(*(Partition*)partition_inode.ptr()));
|
2023-03-30 16:37:53 +03:00
|
|
|
|
2023-07-10 13:26:14 +03:00
|
|
|
Credentials root_creds { 0, 0, 0, 0 };
|
2023-07-10 23:17:14 +03:00
|
|
|
MUST(s_instance->mount(root_creds, &DevFileSystem::get(), "/dev"));
|
2023-07-10 13:26:14 +03:00
|
|
|
|
|
|
|
mode_t tmpfs_mode = Inode::Mode::IFDIR
|
|
|
|
| Inode::Mode::IRUSR | Inode::Mode::IWUSR | Inode::Mode::IXUSR
|
|
|
|
| Inode::Mode::IRGRP | Inode::Mode::IWGRP | Inode::Mode::IXGRP
|
|
|
|
| Inode::Mode::IROTH | Inode::Mode::IWOTH | Inode::Mode::IXOTH;
|
|
|
|
auto* tmpfs = MUST(RamFileSystem::create(1024 * 1024, tmpfs_mode, 0, 0));
|
|
|
|
MUST(s_instance->mount(root_creds, tmpfs, "/tmp"));
|
2023-02-20 01:46:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
VirtualFileSystem& VirtualFileSystem::get()
|
|
|
|
{
|
|
|
|
ASSERT(s_instance);
|
|
|
|
return *s_instance;
|
|
|
|
}
|
|
|
|
|
2023-06-11 19:52:13 +03:00
|
|
|
BAN::ErrorOr<void> VirtualFileSystem::mount(const Credentials& credentials, BAN::StringView partition, BAN::StringView target)
|
2023-03-30 15:06:41 +03:00
|
|
|
{
|
2023-06-11 19:52:13 +03:00
|
|
|
auto partition_file = TRY(file_from_absolute_path(credentials, partition, true));
|
2023-06-03 13:28:15 +03:00
|
|
|
if (!partition_file.inode->is_device())
|
2023-04-11 23:25:21 +03:00
|
|
|
return BAN::Error::from_errno(ENOTBLK);
|
2023-03-30 22:02:16 +03:00
|
|
|
|
2023-03-30 15:06:41 +03:00
|
|
|
Device* device = (Device*)partition_file.inode.ptr();
|
2023-06-03 13:28:15 +03:00
|
|
|
if (!device->is_partition())
|
2023-04-11 23:25:21 +03:00
|
|
|
return BAN::Error::from_errno(ENOTBLK);
|
2023-03-30 22:02:16 +03:00
|
|
|
|
2023-03-30 15:06:41 +03:00
|
|
|
auto* file_system = TRY(Ext2FS::create(*(Partition*)device));
|
2023-06-11 19:52:13 +03:00
|
|
|
return mount(credentials, file_system, target);
|
2023-03-30 15:06:41 +03:00
|
|
|
}
|
|
|
|
|
2023-06-11 19:52:13 +03:00
|
|
|
BAN::ErrorOr<void> VirtualFileSystem::mount(const Credentials& credentials, FileSystem* file_system, BAN::StringView path)
|
2023-03-29 11:50:46 +03:00
|
|
|
{
|
2023-06-11 19:52:13 +03:00
|
|
|
auto file = TRY(file_from_absolute_path(credentials, path, true));
|
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-04-01 01:54:35 +03:00
|
|
|
VirtualFileSystem::MountPoint* VirtualFileSystem::mount_from_host_inode(BAN::RefPtr<Inode> inode)
|
2023-03-29 21:34:48 +03:00
|
|
|
{
|
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-04-01 01:54:35 +03:00
|
|
|
VirtualFileSystem::MountPoint* VirtualFileSystem::mount_from_root_inode(BAN::RefPtr<Inode> inode)
|
|
|
|
{
|
|
|
|
ASSERT(m_lock.is_locked());
|
|
|
|
for (MountPoint& mount : m_mount_points)
|
|
|
|
if (*mount.target->root_inode() == *inode)
|
|
|
|
return &mount;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2023-06-11 19:52:13 +03:00
|
|
|
BAN::ErrorOr<VirtualFileSystem::File> VirtualFileSystem::file_from_absolute_path(const Credentials& credentials, BAN::StringView path, int flags)
|
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-04-11 23:25:21 +03:00
|
|
|
ASSERT(inode);
|
2023-03-09 02:31:24 +02:00
|
|
|
|
2023-03-29 21:34:48 +03:00
|
|
|
BAN::String canonical_path;
|
2023-03-16 15:31:33 +02:00
|
|
|
|
2023-06-02 11:43:46 +03:00
|
|
|
BAN::Vector<BAN::String> path_parts;
|
2023-03-29 21:34:48 +03:00
|
|
|
|
2023-03-17 21:16:22 +02:00
|
|
|
{
|
2023-06-02 11:43:46 +03:00
|
|
|
auto temp = TRY(path.split('/'));
|
|
|
|
for (size_t i = 0; i < temp.size(); i++)
|
2023-06-02 12:50:40 +03:00
|
|
|
TRY(path_parts.emplace_back(temp[temp.size() - i - 1]));
|
2023-06-02 11:43:46 +03:00
|
|
|
}
|
|
|
|
|
2023-06-02 12:50:40 +03:00
|
|
|
size_t link_depth = 0;
|
|
|
|
|
2023-06-02 11:43:46 +03:00
|
|
|
while (!path_parts.empty())
|
|
|
|
{
|
|
|
|
const auto& path_part = path_parts.back();
|
|
|
|
auto orig = inode;
|
|
|
|
|
2023-03-29 21:34:48 +03:00
|
|
|
if (path_part.empty() || path_part == "."sv)
|
2023-03-17 21:16:22 +02:00
|
|
|
{
|
2023-06-02 11:43:46 +03:00
|
|
|
|
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-04-01 01:54:35 +03:00
|
|
|
if (auto* mount_point = mount_from_root_inode(inode))
|
2023-07-10 09:51:13 +03:00
|
|
|
inode = TRY(mount_point->host.inode->directory_find_inode(".."sv));
|
2023-03-29 21:34:48 +03:00
|
|
|
else
|
2023-07-10 09:51:13 +03:00
|
|
|
inode = TRY(inode->directory_find_inode(".."sv));
|
2023-03-29 21:34:48 +03:00
|
|
|
|
|
|
|
if (!canonical_path.empty())
|
2023-03-17 21:16:22 +02:00
|
|
|
{
|
2023-04-01 01:54:35 +03:00
|
|
|
ASSERT(canonical_path.front() == '/');
|
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-09-08 11:46:53 +03:00
|
|
|
if (!inode->can_access(credentials, O_SEARCH))
|
2023-06-11 19:52:13 +03:00
|
|
|
return BAN::Error::from_errno(EACCES);
|
|
|
|
|
2023-07-10 09:51:13 +03:00
|
|
|
inode = TRY(inode->directory_find_inode(path_part));
|
2023-03-29 21:34:48 +03:00
|
|
|
|
2023-04-01 01:54:35 +03:00
|
|
|
if (auto* mount_point = mount_from_host_inode(inode))
|
|
|
|
inode = mount_point->target->root_inode();
|
2023-06-01 00:24:45 +03:00
|
|
|
|
2023-06-02 11:43:46 +03:00
|
|
|
TRY(canonical_path.push_back('/'));
|
|
|
|
TRY(canonical_path.append(path_part));
|
|
|
|
}
|
|
|
|
|
|
|
|
path_parts.pop_back();
|
|
|
|
|
2023-06-11 19:52:13 +03:00
|
|
|
if (inode->mode().iflnk() && (!(flags & O_NOFOLLOW) || !path_parts.empty()))
|
2023-06-02 11:43:46 +03:00
|
|
|
{
|
|
|
|
auto target = TRY(inode->link_target());
|
|
|
|
if (target.empty())
|
|
|
|
return BAN::Error::from_errno(ENOENT);
|
2023-09-08 11:46:53 +03:00
|
|
|
|
2023-06-02 11:43:46 +03:00
|
|
|
if (target.front() == '/')
|
|
|
|
{
|
|
|
|
inode = root_inode();
|
|
|
|
canonical_path.clear();
|
|
|
|
|
|
|
|
auto temp = TRY(target.sv().split('/'));
|
|
|
|
for (size_t i = 0; i < temp.size(); i++)
|
|
|
|
TRY(path_parts.emplace_back(temp[temp.size() - i - 1]));
|
|
|
|
}
|
|
|
|
else
|
2023-06-01 00:24:45 +03:00
|
|
|
{
|
2023-06-02 11:43:46 +03:00
|
|
|
inode = orig;
|
|
|
|
|
|
|
|
while (canonical_path.back() != '/')
|
|
|
|
canonical_path.pop_back();
|
|
|
|
canonical_path.pop_back();
|
|
|
|
|
|
|
|
auto new_parts = TRY(target.sv().split('/'));
|
|
|
|
for (size_t i = 0; i < new_parts.size(); i++)
|
|
|
|
TRY(path_parts.emplace_back(new_parts[new_parts.size() - i - 1]));
|
2023-06-01 00:24:45 +03:00
|
|
|
}
|
2023-06-02 12:50:40 +03:00
|
|
|
|
|
|
|
link_depth++;
|
|
|
|
if (link_depth > 100)
|
|
|
|
return BAN::Error::from_errno(ELOOP);
|
2023-04-01 01:54:35 +03:00
|
|
|
}
|
2023-03-17 21:16:22 +02:00
|
|
|
}
|
|
|
|
|
2023-06-11 19:52:13 +03:00
|
|
|
if (!inode->can_access(credentials, flags))
|
|
|
|
return BAN::Error::from_errno(EACCES);
|
|
|
|
|
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
|
|
|
}
|