From 1350c555f60ebcdef3a5098c42a13a635ac32567 Mon Sep 17 00:00:00 2001 From: Undefine Date: Sat, 13 Jan 2024 17:26:03 +0100 Subject: [PATCH] Kernel/FATFS: Factor out the FAT reading to a function Move the FAT reading code to a fat_read function in FATFS and move the required functions to FATFS too. --- Kernel/FileSystem/FATFS/FileSystem.cpp | 87 +++++++++++++++++++++++++- Kernel/FileSystem/FATFS/FileSystem.h | 9 ++- Kernel/FileSystem/FATFS/Inode.cpp | 79 +---------------------- Kernel/FileSystem/FATFS/Inode.h | 7 +-- 4 files changed, 97 insertions(+), 85 deletions(-) diff --git a/Kernel/FileSystem/FATFS/FileSystem.cpp b/Kernel/FileSystem/FATFS/FileSystem.cpp index 246ac4bfa5d..f5057918af1 100644 --- a/Kernel/FileSystem/FATFS/FileSystem.cpp +++ b/Kernel/FileSystem/FATFS/FileSystem.cpp @@ -1,9 +1,11 @@ /* - * Copyright (c) 2022, Undefine + * Copyright (c) 2022-2024, Undefine * * SPDX-License-Identifier: BSD-2-Clause */ +#include +#include #include #include #include @@ -270,6 +272,89 @@ FatBlockSpan FATFS::first_block_of_cluster(u32 cluster) const } } +size_t FATFS::fat_offset_for_cluster(u32 cluster) const +{ + switch (m_fat_version) { + case FATVersion::FAT12: { + // In FAT12, a cluster entry is stored in a byte, plus + // the low/high nibble of an adjacent byte. + // + // CLSTR: 0 1 2 3 4 5 + // INDEX: [0 1 2], [3 4 5], [6 7 8] + + // Every 2 clusters are represented using 3 bytes. + return (cluster * 3) / 2; + } break; + case FATVersion::FAT16: + return cluster * 2; // Each cluster is stored in 2 bytes. + case FATVersion::FAT32: + return cluster * 4; // Each cluster is stored in 4 bytes. + default: + VERIFY_NOT_REACHED(); + } +} + +u32 FATFS::cluster_number(KBuffer const& fat_sector, u32 entry_cluster_number, u32 entry_offset) const +{ + u32 cluster = 0; + switch (m_fat_version) { + case FATVersion::FAT12: { + u16 fat12_bytes_le = 0; + // Two FAT12 entries get stored in a total of 3 bytes, as follows: + // AB CD EF are grouped as [D AB] and [E FC] (little-endian). + // For a given cluster, we interpret the associated 2 bytes as a little-endian + // 16-bit value ({CD AB} or {EF CD}), and then shift/mask the extra high or low nibble. + ByteReader::load(fat_sector.bytes().offset(entry_offset), fat12_bytes_le); + cluster = AK::convert_between_host_and_little_endian(fat12_bytes_le); + if (entry_cluster_number % 2 == 0) { + // CD AB -> D AB + cluster &= 0x0FFF; + } else { + // EF CD -> E FC. + cluster = cluster >> 4; + } + break; + } + case FATVersion::FAT16: { + u16 cluster_u16_le = 0; + ByteReader::load(fat_sector.bytes().offset(entry_offset), cluster_u16_le); + cluster = AK::convert_between_host_and_little_endian(cluster_u16_le); + break; + } + case FATVersion::FAT32: { + u32 cluster_u32_le = 0; + ByteReader::load(fat_sector.bytes().offset(entry_offset), cluster_u32_le); + cluster = AK::convert_between_host_and_little_endian(cluster_u32_le); + // FAT32 entries use 28-bits to represent the cluster number. The top 4 bits + // may contain flags or other data and must be masked off. + cluster &= 0x0FFFFFFF; + break; + } + default: + VERIFY_NOT_REACHED(); + } + return cluster; +} + +ErrorOr FATFS::fat_read(u32 cluster) +{ + dbgln_if(FAT_DEBUG, "FATFS: Reading FAT entry for cluster {}", cluster); + + auto fat_sector = TRY(KBuffer::try_create_with_size("FATFS: FAT read buffer"sv, m_device_block_size)); + auto fat_sector_buffer = UserOrKernelBuffer::for_kernel_buffer(fat_sector->data()); + + u32 fat_offset = fat_offset_for_cluster(cluster); + u32 fat_sector_index = m_parameter_block->common_bpb()->reserved_sector_count + (fat_offset / m_device_block_size); + u32 entry_offset = fat_offset % m_device_block_size; + + MutexLocker locker(m_lock); + + TRY(read_block(fat_sector_index, &fat_sector_buffer, m_device_block_size)); + + // Look up the next cluster to read, or read End of Chain marker from table. + return cluster_number(*fat_sector, cluster, entry_offset); +} + u8 FATFS::internal_file_type_to_directory_entry_type(DirectoryEntryView const& entry) const { FATAttributes attrib = static_cast(entry.file_type); diff --git a/Kernel/FileSystem/FATFS/FileSystem.h b/Kernel/FileSystem/FATFS/FileSystem.h index a9e681b3974..01781ec099f 100644 --- a/Kernel/FileSystem/FATFS/FileSystem.h +++ b/Kernel/FileSystem/FATFS/FileSystem.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Undefine + * Copyright (c) 2022-2024, Undefine * * SPDX-License-Identifier: BSD-2-Clause */ @@ -82,6 +82,13 @@ private: FatBlockSpan first_block_of_cluster(u32 cluster) const; + size_t fat_offset_for_cluster(u32 cluster) const; + + // Reads the cluster number located at the offset within the table. + u32 cluster_number(KBuffer const& fat_sector, u32 entry_cluster_number, u32 entry_offset) const; + + ErrorOr fat_read(u32 cluster); + OwnPtr m_boot_record; OwnPtr m_parameter_block; RefPtr m_root_inode; diff --git a/Kernel/FileSystem/FATFS/Inode.cpp b/Kernel/FileSystem/FATFS/Inode.cpp index 2556d19bd08..90b5c4eeaa5 100644 --- a/Kernel/FileSystem/FATFS/Inode.cpp +++ b/Kernel/FileSystem/FATFS/Inode.cpp @@ -1,11 +1,9 @@ /* - * Copyright (c) 2022, Undefine + * Copyright (c) 2022-2024, Undefine * * SPDX-License-Identifier: BSD-2-Clause */ -#include -#include #include #include #include @@ -54,9 +52,6 @@ ErrorOr> FATInode::compute_block_list() Vector block_list; - auto fat_sector = TRY(KBuffer::try_create_with_size("FATFS: FAT read buffer"sv, fs().m_device_block_size)); - auto fat_sector_buffer = UserOrKernelBuffer::for_kernel_buffer(fat_sector->data()); - while (cluster < end_of_chain_marker()) { dbgln_if(FAT_DEBUG, "FATFS: Appending cluster {} to inode {}'s cluster chain", cluster, index()); @@ -80,14 +75,8 @@ ErrorOr> FATInode::compute_block_list() break; } - u32 fat_offset = fat_offset_for_cluster(cluster); - u32 fat_sector_index = fs().m_parameter_block->common_bpb()->reserved_sector_count + (fat_offset / fs().m_device_block_size); - u32 entry_offset = fat_offset % fs().m_device_block_size; - - TRY(fs().read_block(fat_sector_index, &fat_sector_buffer, m_device_block_size)); - // Look up the next cluster to read, or read End of Chain marker from table. - cluster = cluster_number(*fat_sector, cluster, entry_offset); + cluster = TRY(fs().fat_read(cluster)); } return block_list; @@ -110,70 +99,6 @@ u32 FATInode::end_of_chain_marker() const } } -size_t FATInode::fat_offset_for_cluster(u32 cluster) const -{ - switch (fs().m_fat_version) { - case FATVersion::FAT12: { - // In FAT12, a cluster entry is stored in a byte, plus - // the low/high nybble of an adjacent byte. - // - // CLSTR: 0 1 2 3 4 5 - // INDEX: [0 1 2], [3 4 5], [6 7 8] - - // Every 2 clusters are represented using 3 bytes. - return (cluster * 3) / 2; - } break; - case FATVersion::FAT16: - return cluster * 2; // Each cluster is stored in 2 bytes. - case FATVersion::FAT32: - return cluster * 4; // Each cluster is stored in 4 bytes. - default: - VERIFY_NOT_REACHED(); - } -} - -u32 FATInode::cluster_number(KBuffer const& fat_sector, u32 entry_cluster_number, u32 entry_offset) const -{ - u32 cluster = 0; - switch (fs().m_fat_version) { - case FATVersion::FAT12: { - u16 fat12_bytes_le = 0; - // Two FAT12 entries get stored in a total of 3 bytes, as follows: - // AB CD EF are grouped as [D AB] and [E FC] (little-endian). - // For a given cluster, we interpret the associated 2 bytes as a little-endian - // 16-bit value ({CD AB} or {EF CD}), and then shift/mask the extra high or low nybble. - ByteReader::load(fat_sector.bytes().offset(entry_offset), fat12_bytes_le); - cluster = LittleEndian { fat12_bytes_le }; - if (entry_cluster_number % 2 == 0) { - // CD AB -> D AB - cluster &= 0x0FFF; - } else { - // EF CD -> E FC. - cluster = cluster >> 4; - } - break; - } - case FATVersion::FAT16: { - u16 cluster_u16_le = 0; - ByteReader::load(fat_sector.bytes().offset(entry_offset), cluster_u16_le); - cluster = LittleEndian { cluster_u16_le }; - break; - } - case FATVersion::FAT32: { - u32 cluster_u32_le = 0; - ByteReader::load(fat_sector.bytes().offset(entry_offset), cluster_u32_le); - cluster = LittleEndian { cluster_u32_le }; - // FAT32 entries use 28-bits to represent the cluster number. The top 4 bits - // may contain flags or other data and must be masked off. - cluster &= 0x0FFFFFFF; - break; - } - default: - VERIFY_NOT_REACHED(); - } - return cluster; -} - ErrorOr> FATInode::read_block_list() { VERIFY(m_inode_lock.is_locked()); diff --git a/Kernel/FileSystem/FATFS/Inode.h b/Kernel/FileSystem/FATFS/Inode.h index 8573f624950..80a51888486 100644 --- a/Kernel/FileSystem/FATFS/Inode.h +++ b/Kernel/FileSystem/FATFS/Inode.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Undefine + * Copyright (c) 2022-2024, Undefine * * SPDX-License-Identifier: BSD-2-Clause */ @@ -30,16 +30,11 @@ public: private: FATInode(FATFS&, FATEntry, NonnullOwnPtr filename); - size_t fat_offset_for_cluster(u32 cluster) const; - // Returns cluster number value that indicates the end of the chain // has been reached. Any cluster value >= this value indicates this // is the last cluster. u32 end_of_chain_marker() const; - // Reads the cluster number located at the offset within the table. - u32 cluster_number(KBuffer const& fat_sector, u32 entry_cluster_number, u32 entry_offset) const; - static constexpr u8 end_entry_byte = 0x00; static constexpr u8 unused_entry_byte = 0xE5;