Kernel: Implement relative file searching in VFS
This commit is contained in:
parent
dce2436b2c
commit
6060b39548
|
@ -27,7 +27,12 @@ namespace Kernel
|
||||||
BAN::RefPtr<Inode> inode;
|
BAN::RefPtr<Inode> inode;
|
||||||
BAN::String canonical_path;
|
BAN::String canonical_path;
|
||||||
};
|
};
|
||||||
BAN::ErrorOr<File> file_from_absolute_path(const Credentials&, BAN::StringView, int);
|
|
||||||
|
BAN::ErrorOr<File> file_from_relative_path(const File& parent, const Credentials&, BAN::StringView, int);
|
||||||
|
BAN::ErrorOr<File> file_from_absolute_path(const Credentials& credentials, BAN::StringView path, int flags)
|
||||||
|
{
|
||||||
|
return file_from_relative_path({ .inode = root_inode(), .canonical_path = {} }, credentials, path, flags);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VirtualFileSystem() = default;
|
VirtualFileSystem() = default;
|
||||||
|
|
|
@ -105,7 +105,7 @@ namespace Kernel
|
||||||
return BAN::Error::from_errno(ENOTDIR);
|
return BAN::Error::from_errno(ENOTDIR);
|
||||||
|
|
||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
TRY(m_mount_points.push_back({ file_system, file }));
|
TRY(m_mount_points.emplace_back(file_system, BAN::move(file)));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,81 +127,91 @@ namespace Kernel
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<VirtualFileSystem::File> VirtualFileSystem::file_from_absolute_path(const Credentials& credentials, BAN::StringView path, int flags)
|
BAN::ErrorOr<VirtualFileSystem::File> VirtualFileSystem::file_from_relative_path(const File& parent, const Credentials& credentials, BAN::StringView path, int flags)
|
||||||
{
|
{
|
||||||
LockGuard _(m_mutex);
|
LockGuard _(m_mutex);
|
||||||
|
|
||||||
ASSERT(path.front() == '/');
|
auto inode = parent.inode;
|
||||||
|
|
||||||
auto inode = root_inode();
|
|
||||||
ASSERT(inode);
|
ASSERT(inode);
|
||||||
|
|
||||||
BAN::String canonical_path;
|
BAN::String canonical_path;
|
||||||
|
TRY(canonical_path.append(parent.canonical_path));
|
||||||
|
if (!canonical_path.empty() && canonical_path.back() == '/')
|
||||||
|
canonical_path.pop_back();
|
||||||
|
ASSERT(canonical_path.empty() || canonical_path.back() != '/');
|
||||||
|
|
||||||
BAN::Vector<BAN::String> path_parts;
|
BAN::Vector<BAN::String> path_parts;
|
||||||
|
|
||||||
{
|
const auto append_string_view_in_reverse =
|
||||||
auto temp = TRY(path.split('/'));
|
[&path_parts](BAN::StringView path) -> BAN::ErrorOr<void>
|
||||||
for (size_t i = 0; i < temp.size(); i++)
|
{
|
||||||
TRY(path_parts.emplace_back(temp[temp.size() - i - 1]));
|
auto split_path = TRY(path.split('/'));
|
||||||
}
|
split_path.reverse();
|
||||||
|
for (auto part : split_path)
|
||||||
|
{
|
||||||
|
TRY(path_parts.emplace_back());
|
||||||
|
TRY(path_parts.back().append(part));
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
TRY(append_string_view_in_reverse(path));
|
||||||
|
|
||||||
size_t link_depth = 0;
|
size_t link_depth = 0;
|
||||||
|
|
||||||
while (!path_parts.empty())
|
while (!path_parts.empty())
|
||||||
{
|
{
|
||||||
const auto& path_part = path_parts.back();
|
BAN::String path_part = BAN::move(path_parts.back());
|
||||||
auto orig = inode;
|
|
||||||
|
|
||||||
if (path_part.empty() || path_part == "."_sv)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (path_part == ".."_sv)
|
|
||||||
{
|
|
||||||
if (auto* mount_point = mount_from_root_inode(inode))
|
|
||||||
inode = TRY(mount_point->host.inode->find_inode(".."_sv));
|
|
||||||
else
|
|
||||||
inode = TRY(inode->find_inode(".."_sv));
|
|
||||||
|
|
||||||
if (!canonical_path.empty())
|
|
||||||
{
|
|
||||||
ASSERT(canonical_path.front() == '/');
|
|
||||||
while (canonical_path.back() != '/')
|
|
||||||
canonical_path.pop_back();
|
|
||||||
canonical_path.pop_back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!inode->can_access(credentials, O_SEARCH))
|
|
||||||
return BAN::Error::from_errno(EACCES);
|
|
||||||
|
|
||||||
inode = TRY(inode->find_inode(path_part));
|
|
||||||
|
|
||||||
if (auto* mount_point = mount_from_host_inode(inode))
|
|
||||||
inode = mount_point->target->root_inode();
|
|
||||||
|
|
||||||
TRY(canonical_path.push_back('/'));
|
|
||||||
TRY(canonical_path.append(path_part));
|
|
||||||
}
|
|
||||||
|
|
||||||
path_parts.pop_back();
|
path_parts.pop_back();
|
||||||
|
|
||||||
if (inode->mode().iflnk() && (!(flags & O_NOFOLLOW) || !path_parts.empty()))
|
if (path_part.empty() || path_part == "."_sv)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto orig = inode;
|
||||||
|
|
||||||
|
// resolve file name
|
||||||
{
|
{
|
||||||
auto target = TRY(inode->link_target());
|
auto parent_inode = inode;
|
||||||
if (target.empty())
|
if (path_part == ".."_sv)
|
||||||
|
if (auto* mount_point = mount_from_root_inode(inode))
|
||||||
|
parent_inode = mount_point->host.inode;
|
||||||
|
if (!parent_inode->can_access(credentials, O_SEARCH))
|
||||||
|
return BAN::Error::from_errno(EACCES);
|
||||||
|
inode = TRY(parent_inode->find_inode(path_part));
|
||||||
|
|
||||||
|
if (path_part == ".."_sv)
|
||||||
|
{
|
||||||
|
if (!canonical_path.empty())
|
||||||
|
{
|
||||||
|
ASSERT(canonical_path.front() == '/');
|
||||||
|
while (canonical_path.back() != '/')
|
||||||
|
canonical_path.pop_back();
|
||||||
|
canonical_path.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (auto* mount_point = mount_from_host_inode(inode))
|
||||||
|
inode = mount_point->target->root_inode();
|
||||||
|
TRY(canonical_path.push_back('/'));
|
||||||
|
TRY(canonical_path.append(path_part));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!inode->mode().iflnk())
|
||||||
|
continue;
|
||||||
|
if ((flags & O_NOFOLLOW) && path_parts.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// resolve symbolic links
|
||||||
|
{
|
||||||
|
auto link_target = TRY(inode->link_target());
|
||||||
|
if (link_target.empty())
|
||||||
return BAN::Error::from_errno(ENOENT);
|
return BAN::Error::from_errno(ENOENT);
|
||||||
|
|
||||||
if (target.front() == '/')
|
if (link_target.front() == '/')
|
||||||
{
|
{
|
||||||
inode = root_inode();
|
inode = root_inode();
|
||||||
canonical_path.clear();
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -210,12 +220,10 @@ namespace Kernel
|
||||||
while (canonical_path.back() != '/')
|
while (canonical_path.back() != '/')
|
||||||
canonical_path.pop_back();
|
canonical_path.pop_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]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TRY(append_string_view_in_reverse(link_target.sv()));
|
||||||
|
|
||||||
link_depth++;
|
link_depth++;
|
||||||
if (link_depth > 100)
|
if (link_depth > 100)
|
||||||
return BAN::Error::from_errno(ELOOP);
|
return BAN::Error::from_errno(ELOOP);
|
||||||
|
|
Loading…
Reference in New Issue