mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
Kernel: Add support for the FAT32 filesystem
This commit adds read-only support for the FAT32 filesystem. It also includes support for long file names.
This commit is contained in:
parent
9718667bcf
commit
135ca3fa1b
Notes:
sideshowbarker
2024-07-17 07:16:27 +09:00
Author: https://github.com/cqundefine Commit: https://github.com/SerenityOS/serenity/commit/135ca3fa1b Pull-request: https://github.com/SerenityOS/serenity/pull/15278 Reviewed-by: https://github.com/ADKaster Reviewed-by: https://github.com/Quaker762 Reviewed-by: https://github.com/bgianfo Reviewed-by: https://github.com/timschumi
6 changed files with 552 additions and 0 deletions
|
@ -111,6 +111,7 @@ set(KERNEL_SOURCES
|
|||
FileSystem/DevPtsFS.cpp
|
||||
FileSystem/DevTmpFS.cpp
|
||||
FileSystem/Ext2FileSystem.cpp
|
||||
FileSystem/FATFileSystem.cpp
|
||||
FileSystem/FIFO.cpp
|
||||
FileSystem/File.cpp
|
||||
FileSystem/FileBackedFileSystem.cpp
|
||||
|
|
|
@ -91,6 +91,10 @@
|
|||
#cmakedefine01 EXT2_VERY_DEBUG
|
||||
#endif
|
||||
|
||||
#ifndef FAT_DEBUG
|
||||
#cmakedefine01 FAT_DEBUG
|
||||
#endif
|
||||
|
||||
#ifndef FRAMEBUFFER_DEVICE_DEBUG
|
||||
#cmakedefine01 FRAMEBUFFER_DEVICE_DEBUG
|
||||
#endif
|
||||
|
|
348
Kernel/FileSystem/FATFileSystem.cpp
Normal file
348
Kernel/FileSystem/FATFileSystem.cpp
Normal file
|
@ -0,0 +1,348 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Undefine <undefine@undefine.pl>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Time.h>
|
||||
#include <Kernel/Debug.h>
|
||||
#include <Kernel/Devices/BlockDevice.h>
|
||||
#include <Kernel/FileSystem/FATFileSystem.h>
|
||||
#include <Kernel/Memory/Region.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
ErrorOr<NonnullLockRefPtr<FileSystem>> FATFS::try_create(OpenFileDescription& file_description)
|
||||
{
|
||||
return TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) FATFS(file_description)));
|
||||
}
|
||||
|
||||
FATFS::FATFS(OpenFileDescription& file_description)
|
||||
: BlockBasedFileSystem(file_description)
|
||||
{
|
||||
}
|
||||
|
||||
ErrorOr<void> FATFS::initialize()
|
||||
{
|
||||
MutexLocker locker(m_lock);
|
||||
|
||||
m_boot_record = TRY(KBuffer::try_create_with_size("FATFS: Boot Record"sv, m_logical_block_size));
|
||||
auto boot_record_buffer = UserOrKernelBuffer::for_kernel_buffer(m_boot_record->data());
|
||||
TRY(raw_read(0, boot_record_buffer));
|
||||
|
||||
if constexpr (FAT_DEBUG) {
|
||||
dbgln("FATFS: oem_identifier: {}", boot_record()->oem_identifier);
|
||||
dbgln("FATFS: bytes_per_sector: {}", boot_record()->bytes_per_sector);
|
||||
dbgln("FATFS: sectors_per_cluster: {}", boot_record()->sectors_per_cluster);
|
||||
dbgln("FATFS: reserved_sector_count: {}", boot_record()->reserved_sector_count);
|
||||
dbgln("FATFS: fat_count: {}", boot_record()->fat_count);
|
||||
dbgln("FATFS: root_directory_entry_count: {}", boot_record()->root_directory_entry_count);
|
||||
dbgln("FATFS: media_descriptor_type: {}", boot_record()->media_descriptor_type);
|
||||
dbgln("FATFS: sectors_per_track: {}", boot_record()->sectors_per_track);
|
||||
dbgln("FATFS: head_count: {}", boot_record()->head_count);
|
||||
dbgln("FATFS: hidden_sector_count: {}", boot_record()->hidden_sector_count);
|
||||
dbgln("FATFS: sector_count: {}", boot_record()->sector_count);
|
||||
dbgln("FATFS: sectors_per_fat: {}", boot_record()->sectors_per_fat);
|
||||
dbgln("FATFS: flags: {}", boot_record()->flags);
|
||||
dbgln("FATFS: fat_version: {}", boot_record()->fat_version);
|
||||
dbgln("FATFS: root_directory_cluster: {}", boot_record()->root_directory_cluster);
|
||||
dbgln("FATFS: fs_info_sector: {}", boot_record()->fs_info_sector);
|
||||
dbgln("FATFS: backup_boot_sector: {}", boot_record()->backup_boot_sector);
|
||||
dbgln("FATFS: drive_number: {}", boot_record()->drive_number);
|
||||
dbgln("FATFS: volume_id: {}", boot_record()->volume_id);
|
||||
}
|
||||
|
||||
if (boot_record()->signature != signature_1 && boot_record()->signature != signature_2) {
|
||||
dbgln("FATFS: Invalid signature");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
m_logical_block_size = boot_record()->bytes_per_sector;
|
||||
set_block_size(m_logical_block_size);
|
||||
|
||||
u32 root_directory_sectors = ((boot_record()->root_directory_entry_count * sizeof(FATEntry)) + (m_logical_block_size - 1)) / m_logical_block_size;
|
||||
m_first_data_sector = boot_record()->reserved_sector_count + (boot_record()->fat_count * boot_record()->sectors_per_fat) + root_directory_sectors;
|
||||
|
||||
TRY(BlockBasedFileSystem::initialize());
|
||||
|
||||
FATEntry root_entry {};
|
||||
|
||||
root_entry.first_cluster_low = boot_record()->root_directory_cluster & 0xFFFF;
|
||||
root_entry.first_cluster_high = boot_record()->root_directory_cluster >> 16;
|
||||
|
||||
root_entry.attributes = FATAttributes::Directory;
|
||||
m_root_inode = TRY(FATInode::create(*this, root_entry));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Inode& FATFS::root_inode()
|
||||
{
|
||||
return *m_root_inode;
|
||||
}
|
||||
|
||||
BlockBasedFileSystem::BlockIndex FATFS::first_block_of_cluster(u32 cluster) const
|
||||
{
|
||||
return ((cluster - first_data_cluster) * boot_record()->sectors_per_cluster) + m_first_data_sector;
|
||||
}
|
||||
|
||||
ErrorOr<NonnullLockRefPtr<FATInode>> FATInode::create(FATFS& fs, FATEntry entry, Vector<FATLongFileNameEntry> const& lfn_entries)
|
||||
{
|
||||
auto filename = TRY(compute_filename(entry, lfn_entries));
|
||||
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) FATInode(fs, entry, move(filename)));
|
||||
}
|
||||
|
||||
FATInode::FATInode(FATFS& fs, FATEntry entry, NonnullOwnPtr<KString> filename)
|
||||
: Inode(fs, first_cluster())
|
||||
, m_entry(entry)
|
||||
, m_filename(move(filename))
|
||||
{
|
||||
dbgln_if(FAT_DEBUG, "FATFS: Creating inode {} with filename \"{}\"", index(), m_filename);
|
||||
|
||||
m_metadata = {
|
||||
.inode = identifier(),
|
||||
.size = m_entry.file_size,
|
||||
.mode = static_cast<mode_t>((has_flag(m_entry.attributes, FATAttributes::Directory) ? S_IFDIR : S_IFREG) | 0777),
|
||||
.uid = 0,
|
||||
.gid = 0,
|
||||
.link_count = 0,
|
||||
.atime = fat_date_time(m_entry.last_accessed_date, { 0 }),
|
||||
.ctime = fat_date_time(m_entry.creation_date, m_entry.creation_time),
|
||||
.mtime = fat_date_time(m_entry.modification_date, m_entry.modification_time),
|
||||
.dtime = 0,
|
||||
.block_count = 0,
|
||||
.block_size = 0,
|
||||
.major_device = 0,
|
||||
.minor_device = 0,
|
||||
};
|
||||
}
|
||||
|
||||
ErrorOr<Vector<BlockBasedFileSystem::BlockIndex>> FATInode::compute_block_list()
|
||||
{
|
||||
VERIFY(m_inode_lock.is_locked());
|
||||
|
||||
dbgln_if(FAT_DEBUG, "FATFS: computing block list for inode {}", index());
|
||||
|
||||
u32 cluster = first_cluster();
|
||||
|
||||
Vector<BlockBasedFileSystem::BlockIndex> block_list;
|
||||
|
||||
auto fat_sector = TRY(KBuffer::try_create_with_size("FATFS: FAT read buffer"sv, fs().m_logical_block_size));
|
||||
auto fat_sector_buffer = UserOrKernelBuffer::for_kernel_buffer(fat_sector->data());
|
||||
|
||||
while (cluster < no_more_clusters) {
|
||||
dbgln_if(FAT_DEBUG, "FATFS: Appending cluster {} to inode {}'s cluster chain", cluster, index());
|
||||
|
||||
BlockBasedFileSystem::BlockIndex first_block = fs().first_block_of_cluster(cluster);
|
||||
for (u8 i = 0; i < fs().boot_record()->sectors_per_cluster; i++)
|
||||
block_list.append(BlockBasedFileSystem::BlockIndex { first_block.value() + i });
|
||||
|
||||
u32 fat_offset = cluster * sizeof(u32);
|
||||
u32 fat_sector_index = fs().boot_record()->reserved_sector_count + (fat_offset / fs().m_logical_block_size);
|
||||
u32 entry_offset = fat_offset % fs().m_logical_block_size;
|
||||
|
||||
TRY(fs().raw_read(fat_sector_index, fat_sector_buffer));
|
||||
|
||||
cluster = *reinterpret_cast<u32*>(&fat_sector->data()[entry_offset]);
|
||||
cluster &= cluster_number_mask;
|
||||
}
|
||||
|
||||
return block_list;
|
||||
}
|
||||
|
||||
ErrorOr<NonnullOwnPtr<KBuffer>> FATInode::read_block_list()
|
||||
{
|
||||
VERIFY(m_inode_lock.is_locked());
|
||||
|
||||
dbgln_if(FAT_DEBUG, "FATFS: reading block list for inode {} ({} blocks)", index(), m_block_list.size());
|
||||
|
||||
if (m_block_list.is_empty())
|
||||
m_block_list = TRY(compute_block_list());
|
||||
|
||||
auto builder = TRY(KBufferBuilder::try_create());
|
||||
|
||||
u8 buffer[512];
|
||||
VERIFY(fs().m_logical_block_size <= sizeof(buffer));
|
||||
auto buf = UserOrKernelBuffer::for_kernel_buffer(buffer);
|
||||
|
||||
for (BlockBasedFileSystem::BlockIndex block : m_block_list) {
|
||||
dbgln_if(FAT_DEBUG, "FATFS: reading block: {}", block);
|
||||
TRY(fs().raw_read(block, buf));
|
||||
TRY(builder.append((char const*)buffer, fs().m_logical_block_size));
|
||||
}
|
||||
|
||||
auto blocks = builder.build();
|
||||
if (!blocks)
|
||||
return ENOMEM;
|
||||
return blocks.release_nonnull();
|
||||
}
|
||||
|
||||
ErrorOr<LockRefPtr<FATInode>> FATInode::traverse(Function<ErrorOr<bool>(LockRefPtr<FATInode>)> callback)
|
||||
{
|
||||
VERIFY(has_flag(m_entry.attributes, FATAttributes::Directory));
|
||||
|
||||
Vector<FATLongFileNameEntry> lfn_entries;
|
||||
auto blocks = TRY(read_block_list());
|
||||
|
||||
for (u32 i = 0; i < blocks->size() / sizeof(FATEntry); i++) {
|
||||
auto* entry = reinterpret_cast<FATEntry*>(blocks->data() + i * sizeof(FATEntry));
|
||||
if (entry->filename[0] == end_entry_byte) {
|
||||
dbgln_if(FAT_DEBUG, "FATFS: Found end entry");
|
||||
return nullptr;
|
||||
} else if (static_cast<u8>(entry->filename[0]) == unused_entry_byte) {
|
||||
dbgln_if(FAT_DEBUG, "FATFS: Found unused entry");
|
||||
lfn_entries.clear();
|
||||
} else if (entry->attributes == FATAttributes::LongFileName) {
|
||||
dbgln_if(FAT_DEBUG, "FATFS: Found LFN entry");
|
||||
TRY(lfn_entries.try_append(*reinterpret_cast<FATLongFileNameEntry*>(entry)));
|
||||
} else {
|
||||
dbgln_if(FAT_DEBUG, "FATFS: Found 8.3 entry");
|
||||
lfn_entries.reverse();
|
||||
auto inode = TRY(FATInode::create(fs(), *entry, lfn_entries));
|
||||
if (TRY(callback(inode)))
|
||||
return inode;
|
||||
lfn_entries.clear();
|
||||
}
|
||||
}
|
||||
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
ErrorOr<NonnullOwnPtr<KString>> FATInode::compute_filename(FATEntry& entry, Vector<FATLongFileNameEntry> const& lfn_entries)
|
||||
{
|
||||
if (lfn_entries.is_empty()) {
|
||||
StringBuilder filename;
|
||||
filename.append(byte_terminated_string(StringView(entry.filename, normal_filename_length), ' '));
|
||||
if (entry.extension[0] != ' ') {
|
||||
filename.append('.');
|
||||
filename.append(byte_terminated_string(StringView(entry.extension, normal_extension_length), ' '));
|
||||
}
|
||||
return TRY(KString::try_create(filename.string_view()));
|
||||
} else {
|
||||
StringBuilder filename;
|
||||
for (auto& lfn_entry : lfn_entries) {
|
||||
filename.append(lfn_entry.characters1[0]);
|
||||
filename.append(lfn_entry.characters1[1]);
|
||||
filename.append(lfn_entry.characters1[2]);
|
||||
filename.append(lfn_entry.characters1[3]);
|
||||
filename.append(lfn_entry.characters1[4]);
|
||||
filename.append(lfn_entry.characters2[0]);
|
||||
filename.append(lfn_entry.characters2[1]);
|
||||
filename.append(lfn_entry.characters2[2]);
|
||||
filename.append(lfn_entry.characters2[3]);
|
||||
filename.append(lfn_entry.characters2[4]);
|
||||
filename.append(lfn_entry.characters2[5]);
|
||||
filename.append(lfn_entry.characters3[0]);
|
||||
filename.append(lfn_entry.characters3[1]);
|
||||
}
|
||||
|
||||
return TRY(KString::try_create(byte_terminated_string(filename.string_view(), lfn_entry_text_termination)));
|
||||
}
|
||||
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
time_t FATInode::fat_date_time(FATPackedDate date, FATPackedTime time)
|
||||
{
|
||||
if (date.value == 0)
|
||||
return 0;
|
||||
|
||||
return Time::from_timestamp(first_fat_year + date.year, date.month, date.day, time.hour, time.minute, time.second * 2, 0).to_seconds();
|
||||
}
|
||||
|
||||
StringView FATInode::byte_terminated_string(StringView string, u8 fill_byte)
|
||||
{
|
||||
if (auto index = string.find_last_not(fill_byte); index.has_value())
|
||||
return string.substring_view(0, index.value());
|
||||
return string;
|
||||
}
|
||||
|
||||
u32 FATInode::first_cluster() const
|
||||
{
|
||||
return (((u32)m_entry.first_cluster_high) << 16) | m_entry.first_cluster_low;
|
||||
}
|
||||
|
||||
ErrorOr<size_t> FATInode::read_bytes_locked(off_t offset, size_t size, UserOrKernelBuffer& buffer, OpenFileDescription*) const
|
||||
{
|
||||
dbgln_if(FAT_DEBUG, "FATFS: Reading inode {}: size: {} offset: {}", identifier().index(), size, offset);
|
||||
|
||||
// FIXME: Read only the needed blocks instead of the whole file
|
||||
auto blocks = TRY(const_cast<FATInode&>(*this).read_block_list());
|
||||
TRY(buffer.write(blocks->data() + offset, min(size, m_block_list.size() * fs().m_logical_block_size - offset)));
|
||||
|
||||
return min(size, m_block_list.size() * fs().m_logical_block_size - offset);
|
||||
}
|
||||
|
||||
InodeMetadata FATInode::metadata() const
|
||||
{
|
||||
return m_metadata;
|
||||
}
|
||||
|
||||
ErrorOr<void> FATInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
|
||||
{
|
||||
MutexLocker locker(m_inode_lock);
|
||||
|
||||
VERIFY(has_flag(m_entry.attributes, FATAttributes::Directory));
|
||||
|
||||
[[maybe_unused]] auto inode = TRY(const_cast<FATInode&>(*this).traverse([&callback](auto inode) -> ErrorOr<bool> {
|
||||
if (inode->m_filename->view() == "" || inode->m_filename->view() == "." || inode->m_filename->view() == "..")
|
||||
return false;
|
||||
TRY(callback({ inode->m_filename->view(), inode->identifier(), static_cast<u8>(inode->m_entry.attributes) }));
|
||||
return false;
|
||||
}));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<NonnullLockRefPtr<Inode>> FATInode::lookup(StringView name)
|
||||
{
|
||||
MutexLocker locker(m_inode_lock);
|
||||
|
||||
VERIFY(has_flag(m_entry.attributes, FATAttributes::Directory));
|
||||
|
||||
auto inode = TRY(traverse([name](auto child) -> ErrorOr<bool> {
|
||||
return child->m_filename->view() == name;
|
||||
}));
|
||||
|
||||
if (inode.is_null())
|
||||
return ENOENT;
|
||||
else
|
||||
return inode.release_nonnull();
|
||||
}
|
||||
|
||||
ErrorOr<size_t> FATInode::write_bytes_locked(off_t, size_t, UserOrKernelBuffer const&, OpenFileDescription*)
|
||||
{
|
||||
return EROFS;
|
||||
}
|
||||
|
||||
ErrorOr<NonnullLockRefPtr<Inode>> FATInode::create_child(StringView, mode_t, dev_t, UserID, GroupID)
|
||||
{
|
||||
return EROFS;
|
||||
}
|
||||
|
||||
ErrorOr<void> FATInode::add_child(Inode&, StringView, mode_t)
|
||||
{
|
||||
return EROFS;
|
||||
}
|
||||
|
||||
ErrorOr<void> FATInode::remove_child(StringView)
|
||||
{
|
||||
return EROFS;
|
||||
}
|
||||
|
||||
ErrorOr<void> FATInode::chmod(mode_t)
|
||||
{
|
||||
return EROFS;
|
||||
}
|
||||
|
||||
ErrorOr<void> FATInode::chown(UserID, GroupID)
|
||||
{
|
||||
return EROFS;
|
||||
}
|
||||
|
||||
ErrorOr<void> FATInode::flush_metadata()
|
||||
{
|
||||
return EROFS;
|
||||
}
|
||||
|
||||
}
|
196
Kernel/FileSystem/FATFileSystem.h
Normal file
196
Kernel/FileSystem/FATFileSystem.h
Normal file
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Undefine <undefine@undefine.pl>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/RefPtr.h>
|
||||
#include <AK/Types.h>
|
||||
#include <Kernel/FileSystem/BlockBasedFileSystem.h>
|
||||
#include <Kernel/FileSystem/Inode.h>
|
||||
#include <Kernel/KBuffer.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
struct [[gnu::packed]] FAT32BootRecord {
|
||||
u8 boot_jump[3];
|
||||
char oem_identifier[8];
|
||||
u16 bytes_per_sector;
|
||||
u8 sectors_per_cluster;
|
||||
u16 reserved_sector_count;
|
||||
u8 fat_count;
|
||||
u16 root_directory_entry_count;
|
||||
u16 unused1;
|
||||
u8 media_descriptor_type;
|
||||
u16 unused2;
|
||||
u16 sectors_per_track;
|
||||
u16 head_count;
|
||||
u32 hidden_sector_count;
|
||||
u32 sector_count;
|
||||
u32 sectors_per_fat;
|
||||
u16 flags;
|
||||
u16 fat_version;
|
||||
u32 root_directory_cluster;
|
||||
u16 fs_info_sector;
|
||||
u16 backup_boot_sector;
|
||||
u8 unused3[12];
|
||||
u8 drive_number;
|
||||
u8 unused4;
|
||||
u8 signature;
|
||||
u32 volume_id;
|
||||
char volume_label_string[11];
|
||||
char system_identifier_string[8];
|
||||
};
|
||||
static_assert(sizeof(FAT32BootRecord) == 90);
|
||||
|
||||
enum class FATAttributes : u8 {
|
||||
ReadOnly = 0x01,
|
||||
Hidden = 0x02,
|
||||
System = 0x04,
|
||||
VolumeID = 0x08,
|
||||
Directory = 0x10,
|
||||
Archive = 0x20,
|
||||
LongFileName = 0x0F
|
||||
};
|
||||
|
||||
AK_ENUM_BITWISE_OPERATORS(FATAttributes);
|
||||
|
||||
union FATPackedTime {
|
||||
u16 value;
|
||||
struct {
|
||||
u16 second : 5;
|
||||
u16 minute : 6;
|
||||
u16 hour : 5;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(FATPackedTime) == 2);
|
||||
|
||||
union FATPackedDate {
|
||||
u16 value;
|
||||
struct {
|
||||
u16 day : 5;
|
||||
u16 month : 4;
|
||||
u16 year : 7;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(FATPackedDate) == 2);
|
||||
|
||||
struct [[gnu::packed]] FATEntry {
|
||||
char filename[8];
|
||||
char extension[3];
|
||||
FATAttributes attributes;
|
||||
u8 unused1;
|
||||
u8 creation_time_seconds;
|
||||
FATPackedTime creation_time;
|
||||
FATPackedDate creation_date;
|
||||
FATPackedDate last_accessed_date;
|
||||
u16 first_cluster_high;
|
||||
FATPackedTime modification_time;
|
||||
FATPackedDate modification_date;
|
||||
u16 first_cluster_low;
|
||||
u32 file_size;
|
||||
};
|
||||
static_assert(sizeof(FATEntry) == 32);
|
||||
|
||||
struct [[gnu::packed]] FATLongFileNameEntry {
|
||||
u8 entry_index;
|
||||
u16 characters1[5];
|
||||
FATAttributes attributes;
|
||||
u8 entry_type;
|
||||
u8 checksum;
|
||||
u16 characters2[6];
|
||||
u16 zero;
|
||||
u16 characters3[2];
|
||||
};
|
||||
static_assert(sizeof(FATLongFileNameEntry) == 32);
|
||||
|
||||
class FATInode;
|
||||
|
||||
class FATFS final : public BlockBasedFileSystem {
|
||||
friend FATInode;
|
||||
|
||||
public:
|
||||
static ErrorOr<NonnullLockRefPtr<FileSystem>> try_create(OpenFileDescription&);
|
||||
|
||||
virtual ~FATFS() override = default;
|
||||
virtual ErrorOr<void> initialize() override;
|
||||
virtual StringView class_name() const override { return "FATFS"sv; }
|
||||
virtual Inode& root_inode() override;
|
||||
|
||||
private:
|
||||
FATFS(OpenFileDescription&);
|
||||
|
||||
static constexpr u8 signature_1 = 0x28;
|
||||
static constexpr u8 signature_2 = 0x29;
|
||||
|
||||
static constexpr u32 first_data_cluster = 2;
|
||||
|
||||
FAT32BootRecord const* boot_record() const { return reinterpret_cast<FAT32BootRecord const*>(m_boot_record->data()); };
|
||||
|
||||
BlockBasedFileSystem::BlockIndex first_block_of_cluster(u32 cluster) const;
|
||||
|
||||
OwnPtr<KBuffer> m_boot_record;
|
||||
LockRefPtr<FATInode> m_root_inode;
|
||||
u32 m_first_data_sector;
|
||||
};
|
||||
|
||||
class FATInode final : public Inode {
|
||||
friend FATFS;
|
||||
|
||||
public:
|
||||
virtual ~FATInode() override = default;
|
||||
|
||||
static ErrorOr<NonnullLockRefPtr<FATInode>> create(FATFS&, FATEntry, Vector<FATLongFileNameEntry> const& = {});
|
||||
|
||||
FATFS& fs() { return static_cast<FATFS&>(Inode::fs()); }
|
||||
FATFS const& fs() const { return static_cast<FATFS const&>(Inode::fs()); }
|
||||
|
||||
private:
|
||||
FATInode(FATFS&, FATEntry, NonnullOwnPtr<KString> filename);
|
||||
|
||||
static constexpr u32 no_more_clusters = 0x0FFFFFF8;
|
||||
static constexpr u32 cluster_number_mask = 0x0FFFFFFF;
|
||||
|
||||
static constexpr u8 end_entry_byte = 0x00;
|
||||
static constexpr u8 unused_entry_byte = 0xE5;
|
||||
|
||||
static constexpr u8 lfn_entry_text_termination = 0xFF;
|
||||
|
||||
static constexpr u16 first_fat_year = 1980;
|
||||
|
||||
static constexpr u8 normal_filename_length = 8;
|
||||
static constexpr u8 normal_extension_length = 3;
|
||||
|
||||
static ErrorOr<NonnullOwnPtr<KString>> compute_filename(FATEntry&, Vector<FATLongFileNameEntry> const& = {});
|
||||
static StringView byte_terminated_string(StringView, u8);
|
||||
static time_t fat_date_time(FATPackedDate date, FATPackedTime time);
|
||||
|
||||
ErrorOr<Vector<BlockBasedFileSystem::BlockIndex>> compute_block_list();
|
||||
ErrorOr<NonnullOwnPtr<KBuffer>> read_block_list();
|
||||
ErrorOr<LockRefPtr<FATInode>> traverse(Function<ErrorOr<bool>(LockRefPtr<FATInode>)> callback);
|
||||
u32 first_cluster() const;
|
||||
|
||||
// ^Inode
|
||||
virtual ErrorOr<size_t> write_bytes_locked(off_t, size_t, UserOrKernelBuffer const& data, OpenFileDescription*) override;
|
||||
virtual ErrorOr<size_t> read_bytes_locked(off_t, size_t, UserOrKernelBuffer& buffer, OpenFileDescription*) const override;
|
||||
|
||||
virtual InodeMetadata metadata() const override;
|
||||
virtual ErrorOr<void> traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>) const override;
|
||||
virtual ErrorOr<NonnullLockRefPtr<Inode>> lookup(StringView name) override;
|
||||
virtual ErrorOr<NonnullLockRefPtr<Inode>> create_child(StringView name, mode_t, dev_t, UserID, GroupID) override;
|
||||
virtual ErrorOr<void> add_child(Inode&, StringView name, mode_t) override;
|
||||
virtual ErrorOr<void> remove_child(StringView name) override;
|
||||
virtual ErrorOr<void> chmod(mode_t) override;
|
||||
virtual ErrorOr<void> chown(UserID, GroupID) override;
|
||||
virtual ErrorOr<void> flush_metadata() override;
|
||||
|
||||
Vector<BlockBasedFileSystem::BlockIndex> m_block_list;
|
||||
FATEntry m_entry;
|
||||
NonnullOwnPtr<KString> m_filename;
|
||||
InodeMetadata m_metadata;
|
||||
};
|
||||
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
#include <Kernel/FileSystem/DevPtsFS.h>
|
||||
#include <Kernel/FileSystem/DevTmpFS.h>
|
||||
#include <Kernel/FileSystem/Ext2FileSystem.h>
|
||||
#include <Kernel/FileSystem/FATFileSystem.h>
|
||||
#include <Kernel/FileSystem/ISO9660FileSystem.h>
|
||||
#include <Kernel/FileSystem/Plan9FileSystem.h>
|
||||
#include <Kernel/FileSystem/ProcFS.h>
|
||||
|
@ -37,6 +38,7 @@ static constexpr FileSystemInitializer s_initializers[] = {
|
|||
{ "ext2"sv, "Ext2FS"sv, true, true, true, Ext2FS::try_create, {} },
|
||||
{ "9p"sv, "Plan9FS"sv, true, true, true, Plan9FS::try_create, {} },
|
||||
{ "iso9660"sv, "ISO9660FS"sv, true, true, true, ISO9660FS::try_create, {} },
|
||||
{ "fat"sv, "FATFS"sv, true, true, true, FATFS::try_create, {} },
|
||||
};
|
||||
|
||||
static ErrorOr<NonnullLockRefPtr<FileSystem>> create_filesystem_instance(StringView fs_type, OpenFileDescription* possible_description)
|
||||
|
|
|
@ -53,6 +53,7 @@ set(EXEC_DEBUG ON)
|
|||
set(EXT2_BLOCKLIST_DEBUG ON)
|
||||
set(EXT2_DEBUG ON)
|
||||
set(EXT2_VERY_DEBUG ON)
|
||||
set(FAT_DEBUG ON)
|
||||
set(FILE_CONTENT_DEBUG ON)
|
||||
set(FILEDESCRIPTION_DEBUG ON)
|
||||
set(FILE_WATCHER_DEBUG ON)
|
||||
|
|
Loading…
Reference in a new issue