aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authormanuel <manuel.bott@eps.ch>2026-10-11 08:55:01 +0000
committermanuel <manuel.bott@eps.ch>2026-10-11 08:55:01 +0000
commit8457adfed9eb4e95e12fda70ff8156c1283f8747 (patch)
treec25629110440052dffe76d9b7d2df0324e095597 /kernel
parent2d7acbf819aa1377c240c874539151001a5f96ce (diff)
downloadkernel-8457adfed9eb4e95e12fda70ff8156c1283f8747.tar.xz
kernel-8457adfed9eb4e95e12fda70ff8156c1283f8747.zip
kernel/filesystems: mount fat32 and read file allocation table entriesfeature/readFatTableEntries
Diffstat (limited to 'kernel')
-rw-r--r--kernel/CMakeLists.txt1
-rw-r--r--kernel/kernel/filesystems/fat32/driver_state.hpp15
-rw-r--r--kernel/kernel/filesystems/fat32/error.cpp9
-rw-r--r--kernel/kernel/filesystems/fat32/error.hpp5
-rw-r--r--kernel/kernel/filesystems/fat32/file_allocation_table.cpp113
-rw-r--r--kernel/kernel/filesystems/fat32/file_allocation_table.hpp79
-rw-r--r--kernel/kernel/filesystems/fat32/filesystem.cpp115
-rw-r--r--kernel/kernel/filesystems/fat32/filesystem.hpp2
-rw-r--r--kernel/kernel/filesystems/fat32/inode.cpp13
-rw-r--r--kernel/kernel/filesystems/fat32/inode.hpp22
-rw-r--r--kernel/kernel/main.cpp63
11 files changed, 415 insertions, 22 deletions
diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt
index aacb5d97..4b2d96da 100644
--- a/kernel/CMakeLists.txt
+++ b/kernel/CMakeLists.txt
@@ -87,6 +87,7 @@ target_sources("kernel_lib" PRIVATE
# fat32 Filesystem
"kernel/filesystems/fat32/error.cpp"
+ "kernel/filesystems/fat32/file_allocation_table.cpp"
"kernel/filesystems/fat32/filesystem.cpp"
"kernel/filesystems/fat32/inode.cpp"
"kernel/filesystems/fat32/module.cpp"
diff --git a/kernel/kernel/filesystems/fat32/driver_state.hpp b/kernel/kernel/filesystems/fat32/driver_state.hpp
index 55b90724..09e2fed2 100644
--- a/kernel/kernel/filesystems/fat32/driver_state.hpp
+++ b/kernel/kernel/filesystems/fat32/driver_state.hpp
@@ -8,7 +8,9 @@
#include <kapi/tracked_mutex.hpp>
#include <kstd/memory.hpp>
-#include <kstd/vector.hpp>
+#include <kstd/units.hpp>
+
+#include <cstdint>
namespace kernel::filesystems::fat32
{
@@ -16,8 +18,17 @@ namespace kernel::filesystems::fat32
struct driver_state : vfs::driver_state
{
struct boot_sector boot_sector{};
+ kstd::shared_ptr<kernel::vfs::inode> backing_inode{};
+
+ kstd::bytes sector_size{};
+ kstd::bytes cluster_size{};
+ std::uint32_t fat_start_sector{};
+ std::uint32_t data_start_sector{};
+ std::uint32_t cluster_count{};
+
+ mutable kapi::tracked_mutex lock{};
};
} // namespace kernel::filesystems::fat32
-#endif \ No newline at end of file
+#endif
diff --git a/kernel/kernel/filesystems/fat32/error.cpp b/kernel/kernel/filesystems/fat32/error.cpp
index 4a18eb9e..e8e72fb7 100644
--- a/kernel/kernel/filesystems/fat32/error.cpp
+++ b/kernel/kernel/filesystems/fat32/error.cpp
@@ -24,6 +24,12 @@ namespace kernel::filesystems::fat32
{
case errc::invalid_boot_signature:
return "invalid boot signature";
+ case errc::invalid_boot_sector:
+ return "invalid boot sector";
+ case errc::invalid_cluster:
+ return "invalid cluster";
+ case errc::corrupted_cluster_chain:
+ return "corrupted cluster chain";
default:
return "unknown fat32 error";
};
@@ -35,6 +41,9 @@ namespace kernel::filesystems::fat32
switch (static_cast<errc>(code))
{
case errc::invalid_boot_signature:
+ case errc::invalid_boot_sector:
+ case errc::invalid_cluster:
+ case errc::corrupted_cluster_chain:
if (condition.category() == kernel::vfs::category())
{
return condition.value() == static_cast<int>(kernel::vfs::errc::invalid_filesystem);
diff --git a/kernel/kernel/filesystems/fat32/error.hpp b/kernel/kernel/filesystems/fat32/error.hpp
index 6955be3f..0b06c503 100644
--- a/kernel/kernel/filesystems/fat32/error.hpp
+++ b/kernel/kernel/filesystems/fat32/error.hpp
@@ -11,7 +11,10 @@ namespace kernel::filesystems::fat32
{
enum struct errc : int
{
- invalid_boot_signature = 1
+ invalid_boot_signature = 1,
+ invalid_boot_sector,
+ invalid_cluster,
+ corrupted_cluster_chain,
};
[[nodiscard]] auto category() noexcept -> kstd::error_category const &;
diff --git a/kernel/kernel/filesystems/fat32/file_allocation_table.cpp b/kernel/kernel/filesystems/fat32/file_allocation_table.cpp
new file mode 100644
index 00000000..02410ac8
--- /dev/null
+++ b/kernel/kernel/filesystems/fat32/file_allocation_table.cpp
@@ -0,0 +1,113 @@
+#include <kernel/filesystems/fat32/file_allocation_table.hpp>
+
+#include <kernel/filesystems/fat32/driver_state.hpp>
+#include <kernel/filesystems/fat32/error.hpp>
+
+#include <kstd/result.hpp>
+#include <kstd/span.hpp>
+#include <kstd/units.hpp>
+#include <kstd/vector.hpp>
+
+#include <cstdint>
+#include <optional>
+
+namespace kernel::filesystems::fat32
+{
+ auto is_valid_cluster(std::uint32_t cluster, driver_state const & state) -> bool
+ {
+ return cluster >= constants::first_data_cluster && cluster - constants::first_data_cluster < state.cluster_count;
+ }
+
+ auto cluster_offset(std::uint32_t cluster, driver_state const & state) -> kstd::bytes
+ {
+ auto const cluster_index = cluster - constants::first_data_cluster;
+ return state.data_start_sector * state.sector_size + cluster_index * state.cluster_size;
+ }
+
+ auto read_fat_entry(std::uint32_t cluster, driver_state const & state) -> kstd::result<fat_entry>
+ {
+ if (!is_valid_cluster(cluster, state))
+ {
+ return kstd::failure(errc::invalid_cluster);
+ }
+
+ auto const entry_offset = state.fat_start_sector * state.sector_size + cluster * constants::fat_entry_size;
+ auto raw_entry = std::uint32_t{};
+ if (auto read_result = state.backing_inode->read(kstd::raw_bytes(raw_entry), entry_offset); !read_result)
+ {
+ return kstd::failure(read_result.error());
+ }
+
+ auto const value = raw_entry & constants::cluster_mask;
+
+ if (value == constants::free_cluster)
+ {
+ return fat_entry{fat_entry_type::free, value};
+ }
+
+ if (value == constants::reserved_cluster)
+ {
+ return fat_entry{fat_entry_type::reserved, value};
+ }
+
+ if (value == constants::bad_cluster)
+ {
+ return fat_entry{fat_entry_type::bad_cluster, value};
+ }
+
+ if (value >= constants::end_of_chain)
+ {
+ return fat_entry{fat_entry_type::end_of_chain, value};
+ }
+
+ return fat_entry{fat_entry_type::allocated, value};
+ }
+
+ auto next_cluster(std::uint32_t cluster, driver_state const & state) -> kstd::result<std::optional<std::uint32_t>>
+ {
+ auto const entry = read_fat_entry(cluster, state);
+ if (!entry)
+ {
+ return kstd::failure(entry.error());
+ }
+
+ if (entry->type == fat_entry_type::end_of_chain)
+ {
+ return std::nullopt;
+ }
+
+ if (entry->type != fat_entry_type::allocated || !is_valid_cluster(entry->value, state))
+ {
+ return kstd::failure(errc::corrupted_cluster_chain);
+ }
+
+ return entry->value;
+ }
+
+ auto cluster_chain(std::uint32_t first_cluster, driver_state const & state)
+ -> kstd::result<kstd::vector<std::uint32_t>>
+ {
+ auto chain = kstd::vector<std::uint32_t>{};
+ auto current = std::optional{first_cluster};
+
+ while (current)
+ {
+ if (chain.size() >= state.cluster_count)
+ {
+ return kstd::failure(errc::corrupted_cluster_chain);
+ }
+
+ chain.push_back(*current);
+
+ auto const next = next_cluster(*current, state);
+ if (!next)
+ {
+ return kstd::failure(next.error());
+ }
+
+ current = *next;
+ }
+
+ return chain;
+ }
+} // namespace kernel::filesystems::fat32
diff --git a/kernel/kernel/filesystems/fat32/file_allocation_table.hpp b/kernel/kernel/filesystems/fat32/file_allocation_table.hpp
new file mode 100644
index 00000000..df5c723d
--- /dev/null
+++ b/kernel/kernel/filesystems/fat32/file_allocation_table.hpp
@@ -0,0 +1,79 @@
+#ifndef TEACHOS_KERNEL_FILESYSTEMS_FAT32_FILE_ALLOCATION_TABLE_HPP
+#define TEACHOS_KERNEL_FILESYSTEMS_FAT32_FILE_ALLOCATION_TABLE_HPP
+
+#include <kernel/filesystems/fat32/driver_state.hpp>
+
+#include <kstd/result.hpp>
+#include <kstd/units.hpp>
+#include <kstd/vector.hpp>
+
+#include <cstdint>
+#include <optional>
+
+namespace kernel::filesystems::fat32
+{
+ namespace constants
+ {
+ constexpr std::uint32_t inline first_data_cluster = 2;
+ constexpr std::uint32_t inline cluster_mask = 0x0FFF'FFFF;
+ constexpr std::uint32_t inline free_cluster = 0x0000'0000;
+ constexpr std::uint32_t inline reserved_cluster = 0x0000'0001;
+ constexpr std::uint32_t inline bad_cluster = 0x0FFF'FFF7;
+ constexpr std::uint32_t inline end_of_chain = 0x0FFF'FFF8;
+ constexpr kstd::bytes inline fat_entry_size = kstd::bytes{sizeof(std::uint32_t)};
+ } // namespace constants
+
+ enum struct fat_entry_type : std::uint8_t
+ {
+ free,
+ reserved,
+ allocated,
+ bad_cluster,
+ end_of_chain,
+ };
+
+ struct fat_entry
+ {
+ fat_entry_type type;
+ std::uint32_t value;
+ };
+
+ //! Check if a cluster number refers to a cluster inside the data region.
+ //!
+ //! @param cluster The cluster number to check.
+ //! @param state The driver state to operate on.
+ //! @return @c true iff. the cluster lies within the data region, @c false otherwise.
+ [[nodiscard]] auto is_valid_cluster(std::uint32_t cluster, driver_state const & state) -> bool;
+
+ //! Get the offset of a cluster's data on the backing inode.
+ //!
+ //! @param cluster The cluster number, which must be valid.
+ //! @param state The driver state to operate on.
+ //! @return The byte offset of the first byte of the cluster.
+ [[nodiscard]] auto cluster_offset(std::uint32_t cluster, driver_state const & state) -> kstd::bytes;
+
+ //! Read and classify the file allocation table entry of a cluster.
+ //!
+ //! @param cluster The cluster whose entry to read.
+ //! @param state The driver state to operate on.
+ //! @return The classified entry on success, an error otherwise.
+ [[nodiscard]] auto read_fat_entry(std::uint32_t cluster, driver_state const & state) -> kstd::result<fat_entry>;
+
+ //! Look up the successor of a cluster in the file allocation table.
+ //!
+ //! @param cluster The cluster whose successor to look up.
+ //! @param state The driver state to operate on.
+ //! @return The next cluster in the chain, @c std::nullopt if @p cluster is the last one, an error otherwise.
+ [[nodiscard]] auto next_cluster(std::uint32_t cluster, driver_state const & state)
+ -> kstd::result<std::optional<std::uint32_t>>;
+
+ //! Collect all clusters of the chain starting at a given cluster.
+ //!
+ //! @param first_cluster The first cluster of the chain.
+ //! @param state The driver state to operate on.
+ //! @return The clusters of the chain in order on success, an error otherwise.
+ [[nodiscard]] auto cluster_chain(std::uint32_t first_cluster, driver_state const & state)
+ -> kstd::result<kstd::vector<std::uint32_t>>;
+} // namespace kernel::filesystems::fat32
+
+#endif
diff --git a/kernel/kernel/filesystems/fat32/filesystem.cpp b/kernel/kernel/filesystems/fat32/filesystem.cpp
index 30f1b286..743968fa 100644
--- a/kernel/kernel/filesystems/fat32/filesystem.cpp
+++ b/kernel/kernel/filesystems/fat32/filesystem.cpp
@@ -1,7 +1,9 @@
#include <kernel/filesystems/fat32/filesystem.hpp>
#include <kernel/filesystems/fat32/boot_sector.hpp>
+#include <kernel/filesystems/fat32/driver_state.hpp>
#include <kernel/filesystems/fat32/error.hpp>
+#include <kernel/filesystems/fat32/file_allocation_table.hpp>
#include <kernel/filesystems/fat32/inode.hpp>
#include <kernel/vfs/error.hpp>
#include <kernel/vfs/filesystem.hpp>
@@ -16,6 +18,7 @@
#include <kstd/units.hpp>
#include <array>
+#include <bit>
#include <cstddef>
#include <cstdint>
#include <optional>
@@ -38,9 +41,7 @@ namespace kernel::filesystems::fat32
return {array.data(), array.size()};
}
- //! Print all fields of a boot sector.
- //!
- //! @param boot_sector The boot sector to print.
+ // TODO: Remove later, just for demo
auto print_boot_sector(boot_sector const & boot_sector) -> void
{
kstd::println("[OS:FAT32] jump_boot: {:#04X} {:#04X} {:#04X}", boot_sector.jump_boot[0], boot_sector.jump_boot[1],
@@ -71,33 +72,113 @@ namespace kernel::filesystems::fat32
kstd::println("[OS:FAT32] filesystem_type: '{}'", to_string_view(boot_sector.filesystem_type));
kstd::println("[OS:FAT32] boot_signature: {:#06X}", boot_sector.boot_signature);
}
- } // namespace
- auto filesystem::probe(inode_ptr const & inode) const -> kstd::result<std::uint32_t>
- {
- auto boot_sector = fat32::boot_sector{};
- auto const bytes = kstd::raw_bytes(boot_sector);
- auto const read_result = inode->read(bytes, constants::boot_sector_offset);
+ //! Read the boot sector from a backing inode and check its signature.
+ //!
+ //! @param backing_inode The inode to read the boot sector from.
+ //! @return The boot sector on success, an error otherwise.
+ [[nodiscard]] auto read_boot_sector(kernel::vfs::filesystem::inode_ptr const & backing_inode)
+ -> kstd::result<boot_sector>
+ {
+ auto boot_sector = fat32::boot_sector{};
+ if (auto read_result = backing_inode->read(kstd::raw_bytes(boot_sector), constants::boot_sector_offset);
+ !read_result)
+ {
+ return kstd::failure(read_result.error());
+ }
+
+ if (boot_sector.boot_signature != constants::boot_signature)
+ {
+ return kstd::failure(errc::invalid_boot_signature);
+ }
+
+ return boot_sector;
+ }
- if (!read_result)
+ //! Derive the location of the file allocation table and the data region from the boot sector.
+ //!
+ //! @param state The driver state whose boot sector to use and whose layout fields to fill.
+ //! @return Nothing on success, an error if the boot sector describes an impossible layout.
+ [[nodiscard]] auto compute_layout(driver_state & state) -> kstd::result<void>
{
- return kstd::failure(read_result.error());
+ auto const & boot_sector = state.boot_sector;
+
+ auto const bytes_per_sector = boot_sector.bytes_per_sector;
+ auto const sectors_per_cluster = boot_sector.sectors_per_cluster;
+ auto const total_sectors = boot_sector.total_sectors_32 != 0 ? std::uint64_t{boot_sector.total_sectors_32}
+ : std::uint64_t{boot_sector.total_sectors_16};
+ auto const fat_sectors = std::uint64_t{boot_sector.number_of_fats} * boot_sector.fat_size_32;
+ auto const data_start_sector = boot_sector.reserved_sector_count + fat_sectors;
+
+ if (bytes_per_sector < constants::min_bytes_per_sector || bytes_per_sector > constants::max_bytes_per_sector ||
+ !std::has_single_bit(bytes_per_sector) || !std::has_single_bit(sectors_per_cluster) ||
+ boot_sector.reserved_sector_count == 0 || fat_sectors == 0 || data_start_sector >= total_sectors)
+ {
+ return kstd::failure(errc::invalid_boot_sector);
+ }
+
+ auto const cluster_count = (total_sectors - data_start_sector) / sectors_per_cluster;
+ auto const fat_capacity =
+ std::uint64_t{boot_sector.fat_size_32} * bytes_per_sector / constants::fat_entry_size.value;
+
+ if (cluster_count == 0 || cluster_count + constants::first_data_cluster > fat_capacity)
+ {
+ return kstd::failure(errc::invalid_boot_sector);
+ }
+
+ state.sector_size = kstd::bytes{bytes_per_sector};
+ state.cluster_size = state.sector_size * sectors_per_cluster;
+ state.fat_start_sector = boot_sector.reserved_sector_count;
+ state.data_start_sector = static_cast<std::uint32_t>(data_start_sector);
+ state.cluster_count = static_cast<std::uint32_t>(cluster_count);
+
+ return {};
}
+ } // namespace
- if (boot_sector.boot_signature != constants::boot_signature)
+ auto filesystem::probe(inode_ptr const & inode) const -> kstd::result<std::uint32_t>
+ {
+ auto const boot_sector = read_boot_sector(inode);
+ if (!boot_sector)
{
- return kstd::failure(errc::invalid_boot_signature);
+ return kstd::failure(boot_sector.error());
}
- print_boot_sector(boot_sector);
+ print_boot_sector(*boot_sector);
return 0;
}
- auto filesystem::mount(inode_ptr const &) -> kstd::result<mount_result>
+ auto filesystem::mount(inode_ptr const & backing_inode) -> kstd::result<mount_result>
{
- auto root = kstd::make_shared<inode>();
- return mount_result{root, nullptr};
+ if (!backing_inode)
+ {
+ return kstd::failure(vfs::errc::invalid_inode);
+ }
+
+ auto const driver_state = kstd::make_shared<fat32::driver_state>();
+ driver_state->backing_inode = backing_inode;
+
+ auto const boot_sector = read_boot_sector(backing_inode);
+ if (!boot_sector)
+ {
+ return kstd::failure(boot_sector.error());
+ }
+ driver_state->boot_sector = *boot_sector;
+
+ if (auto layout_result = compute_layout(*driver_state); !layout_result)
+ {
+ return kstd::failure(layout_result.error());
+ }
+
+ auto const root_cluster = std::uint32_t{driver_state->boot_sector.root_cluster};
+ if (!is_valid_cluster(root_cluster, *driver_state))
+ {
+ return kstd::failure(errc::invalid_cluster);
+ }
+
+ auto root = kstd::make_shared<inode>(root_cluster, constants::attribute_directory);
+ return mount_result{root, driver_state};
}
auto filesystem::lookup(inode_ptr const &, std::string_view, driver_data_ptr) const -> kstd::result<inode_ptr>
diff --git a/kernel/kernel/filesystems/fat32/filesystem.hpp b/kernel/kernel/filesystems/fat32/filesystem.hpp
index 54c8035c..a392d0fd 100644
--- a/kernel/kernel/filesystems/fat32/filesystem.hpp
+++ b/kernel/kernel/filesystems/fat32/filesystem.hpp
@@ -24,6 +24,8 @@ namespace kernel::filesystems::fat32
{
constexpr kstd::bytes inline boot_sector_offset = kstd::bytes{0};
constexpr std::uint16_t inline boot_signature = 0xAA55;
+ constexpr std::uint16_t inline min_bytes_per_sector = 512;
+ constexpr std::uint16_t inline max_bytes_per_sector = 4096;
} // namespace constants
//! The File Allocation Table 32 Filesystem (fat32)
diff --git a/kernel/kernel/filesystems/fat32/inode.cpp b/kernel/kernel/filesystems/fat32/inode.cpp
index 993256df..20e9ae48 100644
--- a/kernel/kernel/filesystems/fat32/inode.cpp
+++ b/kernel/kernel/filesystems/fat32/inode.cpp
@@ -8,11 +8,17 @@
#include <kstd/units.hpp>
#include <cstddef>
+#include <cstdint>
#include <span>
#include <utility>
namespace kernel::filesystems::fat32
{
+ inode::inode(std::uint32_t first_cluster, std::uint8_t attributes)
+ : m_first_cluster(first_cluster)
+ , m_attributes(attributes)
+ {}
+
auto inode::read(std::span<std::byte>, kstd::bytes) const -> kstd::result<kstd::bytes>
{
return kstd::bytes{};
@@ -25,7 +31,7 @@ namespace kernel::filesystems::fat32
auto inode::is_directory() const -> bool
{
- return true;
+ return (m_attributes & constants::attribute_directory) != 0;
}
auto inode::read_directory(kapi::filesystem::directory_cursor position,
@@ -34,4 +40,9 @@ namespace kernel::filesystems::fat32
{
return std::pair{0, position};
}
+
+ auto inode::first_cluster() const -> std::uint32_t
+ {
+ return m_first_cluster;
+ }
} // namespace kernel::filesystems::fat32
diff --git a/kernel/kernel/filesystems/fat32/inode.hpp b/kernel/kernel/filesystems/fat32/inode.hpp
index 3f9ae37e..87485ffb 100644
--- a/kernel/kernel/filesystems/fat32/inode.hpp
+++ b/kernel/kernel/filesystems/fat32/inode.hpp
@@ -12,14 +12,25 @@
#include <kstd/vector.hpp>
#include <cstddef>
+#include <cstdint>
#include <span>
#include <utility>
namespace kernel::filesystems::fat32
{
- //! An inode in the fat32 filesystem.
+ namespace constants
+ {
+ constexpr std::uint8_t inline attribute_directory = 0x10;
+ } // namespace constants
+
struct inode : kernel::vfs::inode
{
+ //! Create a fat32 inode.
+ //!
+ //! @param first_cluster The first cluster of the inode's data.
+ //! @param attributes The attributes of the directory entry describing the inode.
+ explicit inode(std::uint32_t first_cluster, std::uint8_t attributes);
+
[[nodiscard]] auto read(std::span<std::byte> buffer, kstd::bytes offset) const
-> kstd::result<kstd::bytes> override;
@@ -31,6 +42,15 @@ namespace kernel::filesystems::fat32
[[nodiscard]] auto read_directory(kapi::filesystem::directory_cursor position,
std::span<kapi::filesystem::directory_entry> entries) const
-> kstd::result<std::pair<std::size_t, kapi::filesystem::directory_cursor>> override;
+
+ //! Get the first cluster of the inode's data.
+ //!
+ //! @return The first cluster number.
+ [[nodiscard]] auto first_cluster() const -> std::uint32_t;
+
+ private:
+ std::uint32_t m_first_cluster{};
+ std::uint8_t m_attributes{};
};
} // namespace kernel::filesystems::fat32
diff --git a/kernel/kernel/main.cpp b/kernel/kernel/main.cpp
index 15952547..fb709688 100644
--- a/kernel/kernel/main.cpp
+++ b/kernel/kernel/main.cpp
@@ -1,6 +1,9 @@
#include <kernel/devices/init.hpp>
#include <kernel/devices/storage.hpp>
#include <kernel/drivers/init.hpp>
+#include <kernel/filesystems/fat32/driver_state.hpp>
+#include <kernel/filesystems/fat32/file_allocation_table.hpp>
+#include <kernel/filesystems/fat32/inode.hpp>
#include <kernel/memory.hpp>
#include <kernel/vfs.hpp>
@@ -14,12 +17,14 @@
#include <kapi/system.hpp>
#include <kstd/format.hpp>
+#include <kstd/memory.hpp>
#include <kstd/print.hpp>
#include <kstd/system_error.hpp>
#include <kstd/units.hpp>
#include <kstd/vector.hpp>
#include <cstddef>
+#include <cstdint>
#include <ranges>
#include <string_view>
@@ -38,6 +43,64 @@ auto run_demo_fat32() -> void
{
kapi::system::panic("[OS:DEM] failed to mount /dev/ram3 on /entrance", result.error());
}
+
+ auto entrance = kernel::vfs::vfs::get().open("/entrance");
+ if (!entrance)
+ {
+ kapi::system::panic("[OS:DEM] failed to open /entrance", entrance.error());
+ }
+
+ auto const root = kstd::static_pointer_cast<kernel::filesystems::fat32::inode>((*entrance)->inode());
+ auto const state = kstd::static_pointer_cast<kernel::filesystems::fat32::driver_state>(root->driver_state().lock());
+
+ kstd::println("[OS:DEM] FAT starts at sector {}, data region starts at sector {}, {} clusters of {} bytes",
+ state->fat_start_sector, state->data_start_sector, state->cluster_count, state->cluster_size);
+
+ auto const root_chain = kernel::filesystems::fat32::cluster_chain(root->first_cluster(), *state);
+ if (!root_chain)
+ {
+ kapi::system::panic("[OS:DEM] failed to read the root directory cluster chain", root_chain.error());
+ }
+
+ kstd::println("[OS:DEM] root directory starts at cluster {} and spans {} cluster(s):", root->first_cluster(),
+ root_chain->size());
+ for (auto const cluster : *root_chain)
+ {
+ kstd::println("[OS:DEM] cluster {} at byte offset {}", cluster,
+ kernel::filesystems::fat32::cluster_offset(cluster, *state));
+ }
+
+ constexpr auto demo_cluster_count = std::uint32_t{4};
+ kstd::println("[OS:DEM] reading the FAT entries of the first {} data clusters:", demo_cluster_count);
+ for (auto cluster = kernel::filesystems::fat32::constants::first_data_cluster;
+ cluster < kernel::filesystems::fat32::constants::first_data_cluster + demo_cluster_count; ++cluster)
+ {
+ auto const entry = kernel::filesystems::fat32::read_fat_entry(cluster, *state);
+ if (!entry)
+ {
+ kstd::println("[OS:DEM] cluster {} -> {}", cluster, entry.error());
+ continue;
+ }
+
+ switch (entry->type)
+ {
+ case kernel::filesystems::fat32::fat_entry_type::free:
+ kstd::println("[OS:DEM] cluster {} -> free", cluster);
+ break;
+ case kernel::filesystems::fat32::fat_entry_type::reserved:
+ kstd::println("[OS:DEM] cluster {} -> reserved", cluster);
+ break;
+ case kernel::filesystems::fat32::fat_entry_type::allocated:
+ kstd::println("[OS:DEM] cluster {} -> next cluster {}", cluster, entry->value);
+ break;
+ case kernel::filesystems::fat32::fat_entry_type::bad_cluster:
+ kstd::println("[OS:DEM] cluster {} -> bad cluster", cluster);
+ break;
+ case kernel::filesystems::fat32::fat_entry_type::end_of_chain:
+ kstd::println("[OS:DEM] cluster {} -> end of chain ({:#010X})", cluster, entry->value);
+ break;
+ }
+ }
}
auto run_demo() -> void