mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-06 09:36:08 +00:00
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.
This commit is contained in:
parent
b9d7e2db93
commit
1350c555f6
Notes:
sideshowbarker
2024-07-17 07:16:27 +09:00
Author: https://github.com/cqundefine
Commit: 1350c555f6
Pull-request: https://github.com/SerenityOS/serenity/pull/23907
Reviewed-by: https://github.com/Hendiadyoin1
Reviewed-by: https://github.com/implicitfield
Reviewed-by: https://github.com/nico
Reviewed-by: https://github.com/timschumi ✅
4 changed files with 97 additions and 85 deletions
|
@ -1,9 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2022, Undefine <undefine@undefine.pl>
|
* Copyright (c) 2022-2024, Undefine <undefine@undefine.pl>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <AK/ByteReader.h>
|
||||||
|
#include <AK/Endian.h>
|
||||||
#include <Kernel/Debug.h>
|
#include <Kernel/Debug.h>
|
||||||
#include <Kernel/FileSystem/FATFS/FileSystem.h>
|
#include <Kernel/FileSystem/FATFS/FileSystem.h>
|
||||||
#include <Kernel/FileSystem/FATFS/Inode.h>
|
#include <Kernel/FileSystem/FATFS/Inode.h>
|
||||||
|
@ -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<u16>(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<u16>(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<u32>(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<u32> 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
|
u8 FATFS::internal_file_type_to_directory_entry_type(DirectoryEntryView const& entry) const
|
||||||
{
|
{
|
||||||
FATAttributes attrib = static_cast<FATAttributes>(entry.file_type);
|
FATAttributes attrib = static_cast<FATAttributes>(entry.file_type);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2022, Undefine <undefine@undefine.pl>
|
* Copyright (c) 2022-2024, Undefine <undefine@undefine.pl>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -82,6 +82,13 @@ private:
|
||||||
|
|
||||||
FatBlockSpan first_block_of_cluster(u32 cluster) const;
|
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<u32> fat_read(u32 cluster);
|
||||||
|
|
||||||
OwnPtr<KBuffer> m_boot_record;
|
OwnPtr<KBuffer> m_boot_record;
|
||||||
OwnPtr<DOSBIOSParameterBlock> m_parameter_block;
|
OwnPtr<DOSBIOSParameterBlock> m_parameter_block;
|
||||||
RefPtr<FATInode> m_root_inode;
|
RefPtr<FATInode> m_root_inode;
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2022, Undefine <undefine@undefine.pl>
|
* Copyright (c) 2022-2024, Undefine <undefine@undefine.pl>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/ByteReader.h>
|
|
||||||
#include <AK/Endian.h>
|
|
||||||
#include <AK/Time.h>
|
#include <AK/Time.h>
|
||||||
#include <Kernel/Debug.h>
|
#include <Kernel/Debug.h>
|
||||||
#include <Kernel/FileSystem/FATFS/Inode.h>
|
#include <Kernel/FileSystem/FATFS/Inode.h>
|
||||||
|
@ -54,9 +52,6 @@ ErrorOr<Vector<BlockBasedFileSystem::BlockIndex>> FATInode::compute_block_list()
|
||||||
|
|
||||||
Vector<BlockBasedFileSystem::BlockIndex> block_list;
|
Vector<BlockBasedFileSystem::BlockIndex> 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()) {
|
while (cluster < end_of_chain_marker()) {
|
||||||
dbgln_if(FAT_DEBUG, "FATFS: Appending cluster {} to inode {}'s cluster chain", cluster, index());
|
dbgln_if(FAT_DEBUG, "FATFS: Appending cluster {} to inode {}'s cluster chain", cluster, index());
|
||||||
|
|
||||||
|
@ -80,14 +75,8 @@ ErrorOr<Vector<BlockBasedFileSystem::BlockIndex>> FATInode::compute_block_list()
|
||||||
break;
|
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.
|
// 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;
|
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<u16>(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<u16>(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<u32>(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<NonnullOwnPtr<KBuffer>> FATInode::read_block_list()
|
ErrorOr<NonnullOwnPtr<KBuffer>> FATInode::read_block_list()
|
||||||
{
|
{
|
||||||
VERIFY(m_inode_lock.is_locked());
|
VERIFY(m_inode_lock.is_locked());
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2022, Undefine <undefine@undefine.pl>
|
* Copyright (c) 2022-2024, Undefine <undefine@undefine.pl>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -30,16 +30,11 @@ public:
|
||||||
private:
|
private:
|
||||||
FATInode(FATFS&, FATEntry, NonnullOwnPtr<KString> filename);
|
FATInode(FATFS&, FATEntry, NonnullOwnPtr<KString> filename);
|
||||||
|
|
||||||
size_t fat_offset_for_cluster(u32 cluster) const;
|
|
||||||
|
|
||||||
// Returns cluster number value that indicates the end of the chain
|
// Returns cluster number value that indicates the end of the chain
|
||||||
// has been reached. Any cluster value >= this value indicates this
|
// has been reached. Any cluster value >= this value indicates this
|
||||||
// is the last cluster.
|
// is the last cluster.
|
||||||
u32 end_of_chain_marker() const;
|
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 end_entry_byte = 0x00;
|
||||||
static constexpr u8 unused_entry_byte = 0xE5;
|
static constexpr u8 unused_entry_byte = 0xE5;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue