#include #include #include namespace Kernel { bool FATFS::validate_bpb(const FAT::BPB& bpb) { bool valid_jump_op = (bpb.jump_op[0] == 0xEB && bpb.jump_op[2] == 0x90) || (bpb.jump_op[0] == 0xE9); if (!valid_jump_op) return false; // This is techincally a strict requirement for (char c : bpb.oem_name) if (!isprint(c)) return false; if (!BAN::Math::is_power_of_two(bpb.bytes_per_sector) || bpb.bytes_per_sector < 512 || bpb.bytes_per_sector > 4096) return false; if (!BAN::Math::is_power_of_two(bpb.sectors_per_cluster) || bpb.sectors_per_cluster > 128) return false; if (bpb.reserved_sector_count == 0) return false; if (bpb.number_of_fats == 0) return false; switch (bpb.media_type) { case 0xF0: case 0xF8: case 0xF9: case 0xFA: case 0xFB: case 0xFC: case 0xFD: case 0xFE: case 0xFF: break; default: return false; } // FIXME: There is more possible checks to do return true; } BAN::ErrorOr FATFS::probe(BAN::RefPtr block_device) { // support only block devices with sectors at least 512 bytes if (block_device->blksize() < 512) return false; BAN::Vector bpb_buffer; TRY(bpb_buffer.resize(block_device->blksize())); auto bpb_span = BAN::ByteSpan(bpb_buffer.span()); TRY(block_device->read_blocks(0, 1, bpb_span)); return validate_bpb(bpb_span.as()); } unsigned long FATFS::bsize() const { return m_bpb.bytes_per_sector; } unsigned long FATFS::frsize() const { return m_bpb.bytes_per_sector; } fsblkcnt_t FATFS::blocks() const { return data_sector_count(); } fsblkcnt_t FATFS::bfree() const { return 0; } // FIXME fsblkcnt_t FATFS::bavail() const { return 0; } // FIXME fsfilcnt_t FATFS::files() const { return m_bpb.number_of_fats * fat_size() * 8 / bits_per_fat_entry(); } fsfilcnt_t FATFS::ffree() const { return 0; } // FIXME fsfilcnt_t FATFS::favail() const { return 0; } // FIXME unsigned long FATFS::fsid() const { return m_type == Type::FAT32 ? m_bpb.ext_32.volume_id : m_bpb.ext_12_16.volume_id; } unsigned long FATFS::flag() const { return 0; } unsigned long FATFS::namemax() const { return 255; } BAN::ErrorOr> FATFS::create(BAN::RefPtr block_device) { // support only block devices with sectors at least 512 bytes if (block_device->blksize() < 512) return BAN::Error::from_errno(EINVAL); BAN::Vector bpb_buffer; TRY(bpb_buffer.resize(block_device->blksize())); auto bpb_span = BAN::ByteSpan(bpb_buffer.span()); TRY(block_device->read_blocks(0, 1, bpb_span)); const auto& bpb = bpb_span.as(); if (!validate_bpb(bpb)) return BAN::Error::from_errno(EINVAL); auto fatfs = TRY(BAN::RefPtr::create( block_device, bpb )); TRY(fatfs->initialize()); return fatfs; } BAN::ErrorOr FATFS::initialize() { if (m_bpb.bytes_per_sector != m_block_device->blksize()) { dwarnln("FileSystem sector size does not match with block device"); return BAN::Error::from_errno(ENOTSUP); } TRY(m_fat_two_sector_buffer.resize(m_bpb.bytes_per_sector * 2)); TRY(m_block_device->read_blocks(first_fat_sector(), 2, BAN::ByteSpan(m_fat_two_sector_buffer.span()))); m_fat_sector_buffer_current = 0; FAT::DirectoryEntry root_entry {}; root_entry.attr = FAT::FileAttr::DIRECTORY; m_root_inode = TRY(open_inode(nullptr, root_entry, 0, 0)); return {}; } BAN::ErrorOr> FATFS::open_inode(BAN::RefPtr parent, const FAT::DirectoryEntry& entry, uint32_t cluster_index, uint32_t entry_index) { LockGuard _(m_mutex); uint32_t block_count = 0; { uint32_t cluster = entry.first_cluster_lo; if (m_type == Type::FAT32) cluster |= static_cast(entry.first_cluster_hi) << 16; while (cluster >= 2 && cluster < cluster_count()) { block_count++; cluster = TRY(get_next_cluster(cluster)); } } uint32_t entry_cluster; switch (m_type) { case Type::FAT12: case Type::FAT16: if (parent == m_root_inode) entry_cluster = 1; else { entry_cluster = parent->entry().first_cluster_lo; for (uint32_t i = 0; i < cluster_index; i++) entry_cluster = TRY(get_next_cluster(entry_cluster)); } break; case Type::FAT32: if (parent == m_root_inode) entry_cluster = m_bpb.ext_32.root_cluster; else entry_cluster = (static_cast(parent->entry().first_cluster_hi) << 16) | parent->entry().first_cluster_lo; for (uint32_t i = 0; i < cluster_index; i++) entry_cluster = TRY(get_next_cluster(entry_cluster)); break; default: ASSERT_NOT_REACHED(); } const ino_t ino = (static_cast(entry_cluster) << 32) | entry_index; auto it = m_inode_cache.find(ino); if (it != m_inode_cache.end()) { if (auto inode = it->value.lock()) return inode; m_inode_cache.remove(it); } auto inode = TRY(BAN::RefPtr::create(*this, entry, ino, block_count)); TRY(m_inode_cache.insert(ino, TRY(inode->get_weak_ptr()))); return inode; } BAN::ErrorOr FATFS::fat_cache_set_sector(uint32_t sector) { if (m_fat_sector_buffer_current != sector) { TRY(m_block_device->read_blocks(first_fat_sector() + sector, 2, BAN::ByteSpan(m_fat_two_sector_buffer.span()))); m_fat_sector_buffer_current = sector; } return {}; } BAN::ErrorOr FATFS::get_next_cluster(uint32_t cluster) { LockGuard _(m_mutex); ASSERT(cluster >= 2 && cluster < cluster_count()); auto fat_span = BAN::ByteSpan(m_fat_two_sector_buffer.span()); switch (m_type) { case Type::FAT12: { const uint32_t fat_byte_offset = cluster + (cluster / 2); const uint32_t ent_offset = fat_byte_offset % m_bpb.bytes_per_sector; TRY(fat_cache_set_sector(fat_byte_offset / m_bpb.bytes_per_sector)); uint16_t next = (fat_span[ent_offset + 1] << 8) | fat_span[ent_offset]; return cluster % 2 ? next >> 4 : next & 0xFFF; } case Type::FAT16: { const uint32_t fat_byte_offset = cluster * sizeof(uint16_t); const uint32_t ent_offset = (fat_byte_offset % m_bpb.bytes_per_sector) / sizeof(uint16_t); TRY(fat_cache_set_sector(fat_byte_offset / m_bpb.bytes_per_sector)); return fat_span.as_span()[ent_offset]; } case Type::FAT32: { const uint32_t fat_byte_offset = cluster * sizeof(uint32_t); const uint32_t ent_offset = (fat_byte_offset % m_bpb.bytes_per_sector) / sizeof(uint32_t); TRY(fat_cache_set_sector(fat_byte_offset / m_bpb.bytes_per_sector)); return fat_span.as_span()[ent_offset]; } } ASSERT_NOT_REACHED(); } BAN::ErrorOr FATFS::inode_read_cluster(BAN::RefPtr file, size_t index, BAN::ByteSpan buffer) { LockGuard _(m_mutex); if (buffer.size() < static_castblksize())>>(file->blksize())) return BAN::Error::from_errno(ENOBUFS); uint32_t cluster; switch (m_type) { case Type::FAT12: case Type::FAT16: { if (file == m_root_inode) { if (index >= root_sector_count()) return BAN::Error::from_errno(ENOENT); const uint32_t first_root_sector = m_bpb.reserved_sector_count + (m_bpb.number_of_fats * fat_size()); TRY(m_block_device->read_blocks(first_root_sector + index, 1, buffer)); return {}; } cluster = file->entry().first_cluster_lo; break; } case Type::FAT32: if (file == m_root_inode) cluster = m_bpb.ext_32.root_cluster; else cluster = (static_cast(file->entry().first_cluster_hi) << 16) | file->entry().first_cluster_lo; break; default: ASSERT_NOT_REACHED(); } if (cluster < 2 || cluster >= cluster_count()) return BAN::Error::from_errno(ENOENT); for (uint32_t i = 0; i < index; i++) { cluster = TRY(get_next_cluster(cluster)); if (cluster < 2 || cluster >= cluster_count()) return BAN::Error::from_errno(ENOENT); } const uint32_t cluster_start_sector = ((cluster - 2) * m_bpb.sectors_per_cluster) + first_data_sector(); TRY(m_block_device->read_blocks(cluster_start_sector, m_bpb.sectors_per_cluster, buffer)); return {}; } blksize_t FATFS::inode_block_size(BAN::RefPtr file) const { switch (m_type) { case Type::FAT12: case Type::FAT16: if (file == m_root_inode) return m_bpb.bytes_per_sector; return m_bpb.bytes_per_sector * m_bpb.sectors_per_cluster; case Type::FAT32: return m_bpb.bytes_per_sector * m_bpb.sectors_per_cluster; } ASSERT_NOT_REACHED(); } }