/* * Copyright (c) 2018-2021, Andreas Kling * Copyright (c) 2021, sin-ack * Copyright (c) 2022, Idan Horowitz * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include namespace Kernel { static Singleton> s_all_instances; SpinlockProtected& Inode::all_instances() { return s_all_instances; } void Inode::sync_all() { Vector, 32> inodes; Inode::all_instances().with([&](auto& all_inodes) { for (auto& inode : all_inodes) { if (inode.is_metadata_dirty()) inodes.append(inode); } }); for (auto& inode : inodes) { VERIFY(inode->is_metadata_dirty()); (void)inode->flush_metadata(); } } void Inode::sync() { if (is_metadata_dirty()) (void)flush_metadata(); fs().flush_writes(); } ErrorOr> Inode::resolve_as_link(Credentials const& credentials, Custody& base, RefPtr* out_parent, int options, int symlink_recursion_level) const { // The default implementation simply treats the stored // contents as a path and resolves that. That is, it // behaves exactly how you would expect a symlink to work. // Make sure that our assumptions about the path length hold up. // Note that this doesn't mean that the reported size can be trusted, some inodes just report zero. VERIFY(size() <= MAXPATHLEN); Array contents; auto read_bytes = TRY(read_until_filled_or_end(0, contents.size(), UserOrKernelBuffer::for_kernel_buffer(contents.data()), nullptr)); return VirtualFileSystem::the().resolve_path(credentials, StringView { contents.span().trim(read_bytes) }, base, out_parent, options, symlink_recursion_level); } Inode::Inode(FileSystem& fs, InodeIndex index) : m_file_system(fs) , m_index(index) { Inode::all_instances().with([&](auto& all_inodes) { all_inodes.append(*this); }); } Inode::~Inode() { m_watchers.for_each([&](auto& watcher) { watcher->unregister_by_inode({}, identifier()); }); } void Inode::will_be_destroyed() { MutexLocker locker(m_inode_lock); if (m_metadata_dirty) (void)flush_metadata(); } ErrorOr Inode::write_bytes(off_t offset, size_t length, UserOrKernelBuffer const& target_buffer, OpenFileDescription* open_description) { MutexLocker locker(m_inode_lock); TRY(prepare_to_write_data()); return write_bytes_locked(offset, length, target_buffer, open_description); } ErrorOr Inode::read_bytes(off_t offset, size_t length, UserOrKernelBuffer& buffer, OpenFileDescription* open_description) const { MutexLocker locker(m_inode_lock, Mutex::Mode::Shared); return read_bytes_locked(offset, length, buffer, open_description); } ErrorOr Inode::read_until_filled_or_end(off_t offset, size_t length, UserOrKernelBuffer buffer, OpenFileDescription* open_description) const { auto remaining_length = length; while (remaining_length > 0) { auto filled_bytes = TRY(read_bytes(offset, remaining_length, buffer, open_description)); if (filled_bytes == 0) break; offset += filled_bytes; remaining_length -= filled_bytes; } return length - remaining_length; } ErrorOr Inode::update_timestamps([[maybe_unused]] Optional