mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-23 09:51:57 -05:00
01e1af732b
The VFSRootContext class, as its name suggests, holds a context for a root directory with its mount table and the root custody/inode in the same class. The idea is derived from the Linux mount namespace mechanism. It mimicks the concept of the ProcessList object, but it is adjusted for a root directory tree context. In contrast to the ProcessList concept, processes that share the default VFSRootContext can't see other VFSRootContext related properties such as as the mount table and root custody/inode. To accommodate to this change progressively, we internally create 2 main VFS root contexts for now - one for kernel processes (as they don't need to care about VFS root contexts for the most part), and another for all userspace programs. This separation allows us to continue pretending for userspace that everything is "normal" as it is used to be, until we introduce proper interfaces in the mount-related syscalls as well as in the SysFS. We make VFSRootContext objects being listed, as another preparation before we could expose interfaces to userspace. As a result, the PowerStateSwitchTask now iterates on all contexts and tear them down one by one.
131 lines
4.2 KiB
C++
131 lines
4.2 KiB
C++
/*
|
|
* Copyright (c) 2018-2022, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <AK/StringView.h>
|
|
#include <Kernel/API/Ioctl.h>
|
|
#include <Kernel/API/POSIX/errno.h>
|
|
#include <Kernel/FileSystem/Inode.h>
|
|
#include <Kernel/FileSystem/InodeFile.h>
|
|
#include <Kernel/FileSystem/OpenFileDescription.h>
|
|
#include <Kernel/FileSystem/VFSRootContext.h>
|
|
#include <Kernel/FileSystem/VirtualFileSystem.h>
|
|
#include <Kernel/Memory/PrivateInodeVMObject.h>
|
|
#include <Kernel/Memory/SharedInodeVMObject.h>
|
|
#include <Kernel/Tasks/Process.h>
|
|
|
|
namespace Kernel {
|
|
|
|
InodeFile::InodeFile(NonnullRefPtr<Inode> inode)
|
|
: m_inode(move(inode))
|
|
{
|
|
}
|
|
|
|
InodeFile::~InodeFile() = default;
|
|
|
|
ErrorOr<size_t> InodeFile::read(OpenFileDescription& description, u64 offset, UserOrKernelBuffer& buffer, size_t count)
|
|
{
|
|
if (Checked<off_t>::addition_would_overflow(offset, count))
|
|
return EOVERFLOW;
|
|
|
|
auto nread = TRY(m_inode->read_bytes(offset, count, buffer, &description));
|
|
if (nread > 0) {
|
|
Thread::current()->did_file_read(nread);
|
|
evaluate_block_conditions();
|
|
}
|
|
return nread;
|
|
}
|
|
|
|
ErrorOr<size_t> InodeFile::write(OpenFileDescription& description, u64 offset, UserOrKernelBuffer const& data, size_t count)
|
|
{
|
|
if (Checked<off_t>::addition_would_overflow(offset, count))
|
|
return EOVERFLOW;
|
|
|
|
size_t nwritten = TRY(m_inode->write_bytes(offset, count, data, &description));
|
|
if (nwritten > 0) {
|
|
auto mtime_result = m_inode->update_timestamps({}, {}, kgettimeofday());
|
|
Thread::current()->did_file_write(nwritten);
|
|
evaluate_block_conditions();
|
|
if (mtime_result.is_error())
|
|
return mtime_result.release_error();
|
|
}
|
|
return nwritten;
|
|
}
|
|
|
|
ErrorOr<void> InodeFile::ioctl(OpenFileDescription& description, unsigned request, Userspace<void*> arg)
|
|
{
|
|
switch (request) {
|
|
case FIBMAP: {
|
|
auto current_process_credentials = Process::current().credentials();
|
|
if (!current_process_credentials->is_superuser())
|
|
return EPERM;
|
|
|
|
auto user_block_number = static_ptr_cast<int*>(arg);
|
|
int block_number = 0;
|
|
TRY(copy_from_user(&block_number, user_block_number));
|
|
|
|
if (block_number < 0)
|
|
return EINVAL;
|
|
|
|
auto block_address = TRY(inode().get_block_address(block_number));
|
|
return copy_to_user(user_block_number, &block_address);
|
|
}
|
|
case FIONREAD: {
|
|
int remaining_bytes = inode().size() - description.offset();
|
|
return copy_to_user(static_ptr_cast<int*>(arg), &remaining_bytes);
|
|
}
|
|
default:
|
|
return EINVAL;
|
|
}
|
|
}
|
|
|
|
ErrorOr<NonnullLockRefPtr<Memory::VMObject>> InodeFile::vmobject_for_mmap(Process&, Memory::VirtualRange const& range, u64& offset, bool shared)
|
|
{
|
|
if (shared)
|
|
return TRY(Memory::SharedInodeVMObject::try_create_with_inode_and_range(inode(), offset, range.size()));
|
|
return TRY(Memory::PrivateInodeVMObject::try_create_with_inode_and_range(inode(), offset, range.size()));
|
|
}
|
|
|
|
ErrorOr<NonnullOwnPtr<KString>> InodeFile::pseudo_path(OpenFileDescription const&) const
|
|
{
|
|
// If it has an inode, then it has a path, and therefore the caller should have been able to get a custody at some point.
|
|
VERIFY_NOT_REACHED();
|
|
}
|
|
|
|
ErrorOr<void> InodeFile::truncate(u64 size)
|
|
{
|
|
TRY(m_inode->truncate(size));
|
|
// FIXME: Make sure that the timestamps are updated by Inode::truncate for all filesystems before removing this.
|
|
auto truncated_at = kgettimeofday();
|
|
TRY(m_inode->update_timestamps({}, truncated_at, truncated_at));
|
|
return {};
|
|
}
|
|
|
|
ErrorOr<void> InodeFile::sync()
|
|
{
|
|
m_inode->sync();
|
|
return {};
|
|
}
|
|
|
|
ErrorOr<void> InodeFile::chown(Credentials const& credentials, OpenFileDescription& description, UserID uid, GroupID gid)
|
|
{
|
|
VERIFY(description.inode() == m_inode);
|
|
VERIFY(description.custody());
|
|
return VirtualFileSystem::the().chown(credentials, *description.custody(), uid, gid);
|
|
}
|
|
|
|
ErrorOr<void> InodeFile::chmod(Credentials const& credentials, OpenFileDescription& description, mode_t mode)
|
|
{
|
|
VERIFY(description.inode() == m_inode);
|
|
VERIFY(description.custody());
|
|
return VirtualFileSystem::the().chmod(credentials, *description.custody(), mode);
|
|
}
|
|
|
|
bool InodeFile::is_regular_file() const
|
|
{
|
|
return inode().metadata().is_regular_file();
|
|
}
|
|
|
|
}
|