#include "filesystem/device_file.hpp" #include "kapi/system.hpp" #include "devices/block_device.hpp" #include "devices/device.hpp" #include #include #include #include #include namespace filesystem { device_file::device_file(kstd::shared_ptr const & device) : m_device(device) { if (!m_device) { kapi::system::panic("[FILESYSTEM] device_file constructed with null device."); } } auto device_file::open() -> void { // Hook point for permission checks or lazy metadata loading. } auto device_file::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_file::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_file::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::write called with null buffer."); } if (size == 0) { return 0; } // @Felix rtti not activated why? e.g. dynamic_cast does not work, whats with std::dynamic_pointer_cast // online: rtti overhead, bad design, ... ? 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