Kernel: Implement read-only FAT12/16/32 driver with long name support
You can now mount FAT filesystems! This code might not work perfectly but my quick testing seemed to work on all (FAT12/16/32) variants.
This commit is contained in:
276
kernel/kernel/FS/FAT/FileSystem.cpp
Normal file
276
kernel/kernel/FS/FAT/FileSystem.cpp
Normal file
@@ -0,0 +1,276 @@
|
||||
#include <kernel/FS/FAT/FileSystem.h>
|
||||
#include <kernel/Lock/LockGuard.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
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<bool> FATFS::probe(BAN::RefPtr<BlockDevice> block_device)
|
||||
{
|
||||
// support only block devices with sectors at least 512 bytes
|
||||
if (block_device->blksize() < 512)
|
||||
return false;
|
||||
|
||||
BAN::Vector<uint8_t> 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<const FAT::BPB>());
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<FATFS>> FATFS::create(BAN::RefPtr<BlockDevice> 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<uint8_t> 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<const FAT::BPB>();
|
||||
if (!validate_bpb(bpb))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
auto fatfs = TRY(BAN::RefPtr<FATFS>::create(
|
||||
block_device,
|
||||
bpb
|
||||
));
|
||||
TRY(fatfs->initialize());
|
||||
return fatfs;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> 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<BAN::RefPtr<FATInode>> FATFS::open_inode(BAN::RefPtr<FATInode> 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<uint32_t>(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<uint32_t>(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<ino_t>(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<FATInode>::create(*this, entry, ino, block_count));
|
||||
TRY(m_inode_cache.insert(ino, TRY(inode->get_weak_ptr())));
|
||||
return inode;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> 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<uint32_t> 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<uint16_t>()[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<uint32_t>()[ent_offset];
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> FATFS::inode_read_cluster(BAN::RefPtr<FATInode> file, size_t index, BAN::ByteSpan buffer)
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
if (buffer.size() < static_cast<BAN::make_unsigned_t<decltype(file->blksize())>>(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_sector_count());
|
||||
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<uint32_t>(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<const FATInode> 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();
|
||||
}
|
||||
|
||||
}
|
||||
280
kernel/kernel/FS/FAT/Inode.cpp
Normal file
280
kernel/kernel/FS/FAT/Inode.cpp
Normal file
@@ -0,0 +1,280 @@
|
||||
#include <BAN/Time.h>
|
||||
|
||||
#include <kernel/FS/FAT/FileSystem.h>
|
||||
#include <kernel/FS/FAT/Inode.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
static uint64_t fat_date_to_epoch(FAT::Date date, FAT::Time time)
|
||||
{
|
||||
BAN::Time ban_time {};
|
||||
|
||||
ban_time.year = (date.year % 128) + 1980;
|
||||
ban_time.month = ((date.month - 1) % 12) + 1;
|
||||
ban_time.day = ((date.day - 1) % 31) + 1;
|
||||
|
||||
ban_time.hour = (time.hour % 24);
|
||||
ban_time.minute = (time.minute % 60);
|
||||
ban_time.second = (time.second % 30) * 2;
|
||||
|
||||
return BAN::to_unix_time(ban_time);
|
||||
}
|
||||
|
||||
blksize_t FATInode::blksize() const
|
||||
{
|
||||
return m_fs.inode_block_size(this);
|
||||
}
|
||||
|
||||
timespec FATInode::atime() const
|
||||
{
|
||||
uint64_t epoch = fat_date_to_epoch(m_entry.last_access_date, {});
|
||||
return timespec { .tv_sec = epoch, .tv_nsec = 0 };
|
||||
}
|
||||
|
||||
timespec FATInode::mtime() const
|
||||
{
|
||||
uint64_t epoch = fat_date_to_epoch(m_entry.write_date, m_entry.write_time);
|
||||
return timespec { .tv_sec = epoch, .tv_nsec = 0 };
|
||||
}
|
||||
|
||||
timespec FATInode::ctime() const
|
||||
{
|
||||
uint64_t epoch = fat_date_to_epoch(m_entry.creation_date, m_entry.creation_time);
|
||||
return timespec { .tv_sec = epoch, .tv_nsec = 0 };
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> FATInode::for_each_directory_entry(BAN::ConstByteSpan entry_span, BAN::Function<BAN::Iteration(const FAT::DirectoryEntry&)> callback)
|
||||
{
|
||||
ASSERT(mode().ifdir());
|
||||
|
||||
auto directory_entries = entry_span.as_span<const FAT::DirectoryEntry>();
|
||||
for (uint32_t i = 0; i < directory_entries.size(); i++)
|
||||
{
|
||||
const auto& directory_entry = directory_entries[i];
|
||||
if ((uint8_t)directory_entry.name[0] == 0xE5)
|
||||
continue;
|
||||
if (directory_entry.name[0] == 0)
|
||||
break;
|
||||
if ((directory_entry.attr & 0x3F) == 0x0F)
|
||||
continue;
|
||||
if (callback(directory_entry) == BAN::Iteration::Break)
|
||||
return {};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> FATInode::for_each_directory_entry(BAN::ConstByteSpan entry_span, BAN::Function<BAN::Iteration(const FAT::DirectoryEntry&, BAN::String, uint32_t)> callback)
|
||||
{
|
||||
ASSERT(mode().ifdir());
|
||||
|
||||
BAN::String long_name;
|
||||
|
||||
auto directory_entries = entry_span.as_span<const FAT::DirectoryEntry>();
|
||||
auto long_name_entries = entry_span.as_span<const FAT::LongNameEntry>();
|
||||
for (uint32_t i = 0; i < directory_entries.size(); i++)
|
||||
{
|
||||
const auto& directory_entry = directory_entries[i];
|
||||
if ((uint8_t)directory_entry.name[0] == 0xE5)
|
||||
continue;
|
||||
if (directory_entry.name[0] == 0)
|
||||
break;
|
||||
|
||||
if ((directory_entry.attr & 0x3F) == 0x0F)
|
||||
{
|
||||
if (!long_name.empty())
|
||||
{
|
||||
dwarnln("Invalid long name entry");
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& long_name_entry = long_name_entries[i];
|
||||
if (!(long_name_entry.order & 0x40))
|
||||
{
|
||||
dwarnln("Invalid long name entry");
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint32_t long_name_entry_count = long_name_entry.order & ~0x40;
|
||||
if (i + long_name_entry_count >= directory_entries.size())
|
||||
{
|
||||
dwarnln("Invalid long name entry");
|
||||
continue;
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j < long_name_entry_count; j++)
|
||||
TRY(long_name.insert(long_name_entries[i + j].name_as_string(), 0));
|
||||
i += long_name_entry_count - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto ret = callback(directory_entry, BAN::move(long_name), i);
|
||||
if (ret == BAN::Iteration::Break)
|
||||
return {};
|
||||
long_name.clear();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<Inode>> FATInode::find_inode_impl(BAN::StringView name)
|
||||
{
|
||||
ASSERT(mode().ifdir());
|
||||
|
||||
BAN::Vector<uint8_t> cluster_buffer;
|
||||
TRY(cluster_buffer.resize(blksize()));
|
||||
auto cluster_span = BAN::ByteSpan(cluster_buffer.span());
|
||||
|
||||
for (uint32_t cluster_index = 0;; cluster_index++)
|
||||
{
|
||||
// Returns ENOENT if this cluster is out of bounds
|
||||
TRY(m_fs.inode_read_cluster(this, cluster_index, cluster_span));
|
||||
|
||||
auto error = BAN::Error::from_errno(0);
|
||||
BAN::RefPtr<FATInode> result;
|
||||
|
||||
TRY(for_each_directory_entry(cluster_span,
|
||||
[&](const FAT::DirectoryEntry& entry, BAN::String long_name, uint32_t entry_index)
|
||||
{
|
||||
BAN::String file_name = long_name.empty() ? entry.name_as_string() : BAN::move(long_name);
|
||||
|
||||
if (file_name.size() != name.size())
|
||||
return BAN::Iteration::Continue;
|
||||
|
||||
for (size_t i = 0; i < name.size(); i++)
|
||||
if (tolower(name[i]) != tolower(file_name[i]))
|
||||
return BAN::Iteration::Continue;
|
||||
|
||||
auto new_inode = m_fs.open_inode(this, entry, cluster_index, entry_index);
|
||||
if (new_inode.is_error())
|
||||
error = new_inode.release_error();
|
||||
else
|
||||
result = new_inode.release_value();
|
||||
return BAN::Iteration::Break;
|
||||
}
|
||||
));
|
||||
|
||||
if (error.get_error_code())
|
||||
return error;
|
||||
if (result)
|
||||
return BAN::RefPtr<Inode>(result);
|
||||
}
|
||||
|
||||
return BAN::Error::from_errno(ENOENT);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> FATInode::list_next_inodes_impl(off_t offset, struct dirent* list, size_t list_size)
|
||||
{
|
||||
ASSERT(mode().ifdir());
|
||||
ASSERT(offset >= 0);
|
||||
|
||||
BAN::Vector<uint8_t> cluster_buffer;
|
||||
TRY(cluster_buffer.resize(blksize()));
|
||||
auto cluster_span = BAN::ByteSpan(cluster_buffer.span());
|
||||
|
||||
{
|
||||
auto maybe_error = m_fs.inode_read_cluster(this, offset, cluster_span);
|
||||
if (maybe_error.is_error())
|
||||
{
|
||||
if (maybe_error.error().get_error_code() == ENOENT)
|
||||
return 0;
|
||||
return maybe_error.release_error();
|
||||
}
|
||||
}
|
||||
|
||||
size_t valid_entry_count = 0;
|
||||
TRY(for_each_directory_entry(cluster_span,
|
||||
[&](const FAT::DirectoryEntry&)
|
||||
{
|
||||
valid_entry_count++;
|
||||
return BAN::Iteration::Continue;
|
||||
}
|
||||
));
|
||||
|
||||
if (valid_entry_count > list_size)
|
||||
return BAN::Error::from_errno(ENOBUFS);
|
||||
|
||||
TRY(for_each_directory_entry(cluster_span,
|
||||
[&](const FAT::DirectoryEntry& entry, const BAN::String& long_name, uint32_t)
|
||||
{
|
||||
BAN::String name = long_name.empty() ? entry.name_as_string() : BAN::move(long_name);
|
||||
list->d_ino = 0;
|
||||
list->d_type = (entry.attr & FAT::FileAttr::DIRECTORY) ? DT_DIR : DT_REG;
|
||||
strncpy(list->d_name, name.data(), sizeof(list->d_name));
|
||||
list++;
|
||||
return BAN::Iteration::Continue;
|
||||
}
|
||||
));
|
||||
|
||||
return valid_entry_count;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> FATInode::read_impl(off_t offset, BAN::ByteSpan buffer)
|
||||
{
|
||||
ASSERT(offset >= 0);
|
||||
|
||||
if (offset >= m_entry.file_size)
|
||||
return 0;
|
||||
if (offset + buffer.size() > m_entry.file_size)
|
||||
buffer = buffer.slice(0, m_entry.file_size - offset);
|
||||
|
||||
BAN::Vector<uint8_t> cluster_buffer;
|
||||
TRY(cluster_buffer.resize(blksize()));
|
||||
auto cluster_span = BAN::ByteSpan(cluster_buffer.span());
|
||||
|
||||
const uint32_t block_size = blksize();
|
||||
|
||||
size_t nread = 0;
|
||||
if (auto rem = offset % block_size)
|
||||
{
|
||||
const uint32_t to_read = BAN::Math::min<uint32_t>(buffer.size(), block_size - rem);
|
||||
|
||||
if (auto ret = m_fs.inode_read_cluster(this, offset / block_size, cluster_span); ret.is_error())
|
||||
{
|
||||
if (ret.error().get_error_code() == ENOENT)
|
||||
return nread;
|
||||
return ret.release_error();
|
||||
}
|
||||
memcpy(buffer.data(), cluster_span.data() + rem, to_read);
|
||||
|
||||
nread += to_read;
|
||||
offset += to_read;
|
||||
buffer = buffer.slice(to_read);
|
||||
}
|
||||
|
||||
while (buffer.size() >= block_size)
|
||||
{
|
||||
if (auto ret = m_fs.inode_read_cluster(this, offset / block_size, buffer); ret.is_error())
|
||||
{
|
||||
if (ret.error().get_error_code() == ENOENT)
|
||||
return nread;
|
||||
return ret.release_error();
|
||||
}
|
||||
|
||||
nread += block_size;
|
||||
offset += block_size;
|
||||
buffer = buffer.slice(block_size);
|
||||
}
|
||||
|
||||
if (buffer.size() > 0)
|
||||
{
|
||||
if (auto ret = m_fs.inode_read_cluster(this, offset / block_size, cluster_span); ret.is_error())
|
||||
{
|
||||
if (ret.error().get_error_code() == ENOENT)
|
||||
return nread;
|
||||
return ret.release_error();
|
||||
}
|
||||
memcpy(buffer.data(), cluster_span.data(), buffer.size());
|
||||
|
||||
nread += buffer.size();
|
||||
offset += buffer.size();
|
||||
buffer = buffer.slice(buffer.size());
|
||||
}
|
||||
|
||||
return nread;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <kernel/FS/Ext2/FileSystem.h>
|
||||
#include <kernel/FS/FAT/FileSystem.h>
|
||||
#include <kernel/FS/FileSystem.h>
|
||||
|
||||
namespace Kernel
|
||||
@@ -8,6 +9,8 @@ namespace Kernel
|
||||
{
|
||||
if (auto res = Ext2FS::probe(block_device); !res.is_error() && res.value())
|
||||
return BAN::RefPtr<FileSystem>(TRY(Ext2FS::create(block_device)));
|
||||
if (auto res = FATFS::probe(block_device); !res.is_error() && res.value())
|
||||
return BAN::RefPtr<FileSystem>(TRY(FATFS::create(block_device)));
|
||||
dprintln("Unsupported filesystem");
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user