Serenity Operating System
at master 128 lines 4.1 kB view raw
1/* 2 * Copyright (c) 2018-2022, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/StringView.h> 8#include <Kernel/API/Ioctl.h> 9#include <Kernel/API/POSIX/errno.h> 10#include <Kernel/FileSystem/Inode.h> 11#include <Kernel/FileSystem/InodeFile.h> 12#include <Kernel/FileSystem/OpenFileDescription.h> 13#include <Kernel/FileSystem/VirtualFileSystem.h> 14#include <Kernel/Memory/PrivateInodeVMObject.h> 15#include <Kernel/Memory/SharedInodeVMObject.h> 16#include <Kernel/Process.h> 17 18namespace Kernel { 19 20InodeFile::InodeFile(NonnullRefPtr<Inode> inode) 21 : m_inode(move(inode)) 22{ 23} 24 25InodeFile::~InodeFile() = default; 26 27ErrorOr<size_t> InodeFile::read(OpenFileDescription& description, u64 offset, UserOrKernelBuffer& buffer, size_t count) 28{ 29 if (Checked<off_t>::addition_would_overflow(offset, count)) 30 return EOVERFLOW; 31 32 auto nread = TRY(m_inode->read_bytes(offset, count, buffer, &description)); 33 if (nread > 0) { 34 Thread::current()->did_file_read(nread); 35 evaluate_block_conditions(); 36 } 37 return nread; 38} 39 40ErrorOr<size_t> InodeFile::write(OpenFileDescription& description, u64 offset, UserOrKernelBuffer const& data, size_t count) 41{ 42 if (Checked<off_t>::addition_would_overflow(offset, count)) 43 return EOVERFLOW; 44 45 size_t nwritten = TRY(m_inode->write_bytes(offset, count, data, &description)); 46 if (nwritten > 0) { 47 auto mtime_result = m_inode->update_timestamps({}, {}, kgettimeofday()); 48 Thread::current()->did_file_write(nwritten); 49 evaluate_block_conditions(); 50 if (mtime_result.is_error()) 51 return mtime_result.release_error(); 52 } 53 return nwritten; 54} 55 56ErrorOr<void> InodeFile::ioctl(OpenFileDescription& description, unsigned request, Userspace<void*> arg) 57{ 58 switch (request) { 59 case FIBMAP: { 60 auto current_process_credentials = Process::current().credentials(); 61 if (!current_process_credentials->is_superuser()) 62 return EPERM; 63 64 auto user_block_number = static_ptr_cast<int*>(arg); 65 int block_number = 0; 66 TRY(copy_from_user(&block_number, user_block_number)); 67 68 if (block_number < 0) 69 return EINVAL; 70 71 auto block_address = TRY(inode().get_block_address(block_number)); 72 return copy_to_user(user_block_number, &block_address); 73 } 74 case FIONREAD: { 75 int remaining_bytes = inode().size() - description.offset(); 76 return copy_to_user(static_ptr_cast<int*>(arg), &remaining_bytes); 77 } 78 default: 79 return EINVAL; 80 } 81} 82 83ErrorOr<NonnullLockRefPtr<Memory::VMObject>> InodeFile::vmobject_for_mmap(Process&, Memory::VirtualRange const& range, u64& offset, bool shared) 84{ 85 if (shared) 86 return TRY(Memory::SharedInodeVMObject::try_create_with_inode_and_range(inode(), offset, range.size())); 87 return TRY(Memory::PrivateInodeVMObject::try_create_with_inode_and_range(inode(), offset, range.size())); 88} 89 90ErrorOr<NonnullOwnPtr<KString>> InodeFile::pseudo_path(OpenFileDescription const&) const 91{ 92 // 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. 93 VERIFY_NOT_REACHED(); 94} 95 96ErrorOr<void> InodeFile::truncate(u64 size) 97{ 98 TRY(m_inode->truncate(size)); 99 TRY(m_inode->update_timestamps({}, {}, kgettimeofday())); 100 return {}; 101} 102 103ErrorOr<void> InodeFile::sync() 104{ 105 m_inode->sync(); 106 return {}; 107} 108 109ErrorOr<void> InodeFile::chown(Credentials const& credentials, OpenFileDescription& description, UserID uid, GroupID gid) 110{ 111 VERIFY(description.inode() == m_inode); 112 VERIFY(description.custody()); 113 return VirtualFileSystem::the().chown(credentials, *description.custody(), uid, gid); 114} 115 116ErrorOr<void> InodeFile::chmod(Credentials const& credentials, OpenFileDescription& description, mode_t mode) 117{ 118 VERIFY(description.inode() == m_inode); 119 VERIFY(description.custody()); 120 return VirtualFileSystem::the().chmod(credentials, *description.custody(), mode); 121} 122 123bool InodeFile::is_regular_file() const 124{ 125 return inode().metadata().is_regular_file(); 126} 127 128}