#include "kernel/filesystem/device_inode.hpp" #include "kapi/system.hpp" #include "kernel/devices/block_device.hpp" #include "kernel/devices/device.hpp" #include "kernel/filesystem/inode.hpp" #include #include #include #include #include namespace filesystem { device_inode::device_inode(kstd::shared_ptr const & device) : inode(inode_kind::device) , m_device(device) { if (!device) { kapi::system::panic("[FILESYSTEM] device_inode constructed with null device."); } } auto device_inode::read(void * buffer, size_t offset, size_t size) const -> size_t { if (m_device->is_block_device()) { return process_blocks(offset, size, buffer, [](size_t idx, size_t off, size_t len, size_t done, devices::block_device * device, std::byte * scratch, void * buffer) { auto * out = static_cast(buffer); if (off == 0 && len == device->block_size()) { device->read_block(idx, out + done); } else { device->read_block(idx, scratch); kstd::libc::memcpy(out + done, scratch + off, len); } }); } else { kapi::system::panic("[FILESYSTEM] device_file::read called on non-block device."); } } auto device_inode::write(void const * buffer, size_t offset, size_t size) -> size_t { if (m_device->is_block_device()) { return process_blocks(offset, size, const_cast(buffer), [](size_t idx, size_t off, size_t len, size_t done, devices::block_device * device, std::byte * scratch, void * buffer) { auto const * in = static_cast(buffer); if (off == 0 && len == device->block_size()) { device->write_block(idx, in + done); } else { device->read_block(idx, scratch); kstd::libc::memcpy(scratch + off, in + done, len); device->write_block(idx, scratch); } }); } else { kapi::system::panic("[FILESYSTEM] device_file::write called on non-block device."); } } auto device_inode::device() const -> kstd::shared_ptr const & { return m_device; } auto device_inode::process_blocks(size_t offset, size_t size, void * buffer, block_op op) const -> size_t { if (buffer == nullptr) { kapi::system::panic("[FILESYSTEM] device_file::process_blocks called with null buffer."); } if (size == 0) { return 0; } auto * block_dev = static_cast(m_device.get()); if (block_dev == nullptr) { kapi::system::panic("[FILESYSTEM] device_file: expected block_device."); } size_t const block_size = block_dev->block_size(); size_t const capacity = block_dev->capacity(); if (offset >= capacity) return 0; size_t const total_to_process = std::min(size, capacity - offset); kstd::vector scratch_buffer{block_size}; auto processed = 0uz; while (processed < total_to_process) { size_t const absolute_offset = offset + processed; size_t const block_index = absolute_offset / block_size; size_t const in_block_offset = absolute_offset % block_size; size_t const chunk_size = std::min(total_to_process - processed, block_size - in_block_offset); op(block_index, in_block_offset, chunk_size, processed, block_dev, scratch_buffer.data(), buffer); processed += chunk_size; } return processed; } } // namespace filesystem