/* * Copyright (c) 2018-2020, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include namespace Kernel { InodeFile::InodeFile(NonnullLockRefPtr&& inode) : m_inode(move(inode)) { } InodeFile::~InodeFile() = default; ErrorOr InodeFile::read(OpenFileDescription& description, u64 offset, UserOrKernelBuffer& buffer, size_t count) { if (Checked::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 InodeFile::write(OpenFileDescription& description, u64 offset, UserOrKernelBuffer const& data, size_t count) { if (Checked::addition_would_overflow(offset, count)) return EOVERFLOW; size_t nwritten = 0; { MutexLocker locker(m_inode->m_inode_lock); TRY(m_inode->prepare_to_write_data()); nwritten = TRY(m_inode->write_bytes(offset, count, data, &description)); } if (nwritten > 0) { auto mtime_result = m_inode->update_timestamps({}, {}, kgettimeofday().to_truncated_seconds()); Thread::current()->did_file_write(nwritten); evaluate_block_conditions(); if (mtime_result.is_error()) return mtime_result.release_error(); } return nwritten; } ErrorOr InodeFile::ioctl(OpenFileDescription& description, unsigned request, Userspace 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(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(arg), &remaining_bytes); } default: return EINVAL; } } ErrorOr InodeFile::mmap(Process&, Memory::AddressSpace& address_space, OpenFileDescription& description, Memory::VirtualRange const& range, u64 offset, int prot, bool shared) { // FIXME: If PROT_EXEC, check that the underlying file system isn't mounted noexec. LockRefPtr vmobject; if (shared) vmobject = TRY(Memory::SharedInodeVMObject::try_create_with_inode(inode())); else vmobject = TRY(Memory::PrivateInodeVMObject::try_create_with_inode(inode())); auto path = TRY(description.pseudo_path()); return address_space.allocate_region_with_vmobject(range, vmobject.release_nonnull(), offset, path->view(), prot, shared); } ErrorOr> 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 InodeFile::truncate(u64 size) { TRY(m_inode->truncate(size)); TRY(m_inode->update_timestamps({}, {}, kgettimeofday().to_truncated_seconds())); return {}; } ErrorOr InodeFile::sync() { m_inode->sync(); return {}; } ErrorOr 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 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); } }