2023-06-20 19:39:22 +00:00
|
|
|
#include "fs/ext2/FileSystem.h"
|
2023-06-21 19:32:28 +00:00
|
|
|
#include "fs/ext2/Inode.h"
|
|
|
|
#include <luna/Alignment.h>
|
|
|
|
|
|
|
|
static VFS::InodeType vfs_type_from_ext2_type(mode_t mode)
|
|
|
|
{
|
|
|
|
auto type = mode & 0xf000;
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case EXT2_FIFO: return VFS::InodeType::FIFO;
|
|
|
|
case EXT2_CHR: return VFS::InodeType::CharacterDevice;
|
|
|
|
case EXT2_DIR: return VFS::InodeType::Directory;
|
|
|
|
case EXT2_BLK: return VFS::InodeType::BlockDevice;
|
|
|
|
case EXT2_REG: return VFS::InodeType::RegularFile;
|
|
|
|
case EXT2_LNK: return VFS::InodeType::Symlink;
|
|
|
|
case EXT2_SOCK: [[fallthrough]]; // TODO: Sockets not supported on Luna at the moment.
|
|
|
|
default: fail("ext2: Unknown or unsupported inode type");
|
|
|
|
}
|
|
|
|
}
|
2023-06-20 19:39:22 +00:00
|
|
|
|
|
|
|
namespace Ext2
|
|
|
|
{
|
|
|
|
FileSystem::FileSystem()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2023-06-21 19:32:28 +00:00
|
|
|
Result<SharedPtr<VFS::Inode>> FileSystem::find_inode_by_number(ino_t inum)
|
2023-06-20 19:39:22 +00:00
|
|
|
{
|
2023-06-21 19:32:28 +00:00
|
|
|
check(inum < m_superblock.nr_inodes);
|
|
|
|
|
|
|
|
auto maybe_inode = m_inode_cache.try_get(inum);
|
2023-06-20 19:39:22 +00:00
|
|
|
if (maybe_inode.has_value()) return maybe_inode.value();
|
|
|
|
|
2023-06-21 19:32:28 +00:00
|
|
|
const u32 block_group = (u32)((inum - 1) / m_superblock.inodes_per_block_group);
|
|
|
|
|
|
|
|
const auto* block_group_descriptor = TRY(find_block_group_descriptor(block_group));
|
|
|
|
check(block_group_descriptor);
|
|
|
|
|
|
|
|
// FIXME: This is determined by a field in the Superblock if the Ext2 revision >= 1.0.
|
|
|
|
static constexpr usize INODE_SIZE = 128;
|
|
|
|
|
|
|
|
const u64 index = (inum - 1) % m_superblock.inodes_per_block_group;
|
|
|
|
|
|
|
|
const u64 inode_address = (block_group_descriptor->inode_table_start * m_block_size) + (index * INODE_SIZE);
|
|
|
|
|
|
|
|
auto inode = TRY(adopt_shared_if_nonnull(new (std::nothrow) Ext2::Inode({}, this)));
|
|
|
|
TRY(m_host_device->read((u8*)&inode->m_raw_inode, inode_address, INODE_SIZE));
|
|
|
|
inode->m_type = vfs_type_from_ext2_type(inode->m_raw_inode.mode);
|
|
|
|
inode->m_inum = inum;
|
|
|
|
|
|
|
|
kdbgln("ext2: Read inode %lu with mode %#x (%#x + %#o), size %lu", inum, inode->m_raw_inode.mode,
|
|
|
|
inode->m_raw_inode.mode & 0xf000, inode->mode(), inode->size());
|
|
|
|
|
2023-06-20 19:39:41 +00:00
|
|
|
// TODO: Locate the inode's block group descriptor and find it in the block group's inode table.
|
2023-06-20 19:39:22 +00:00
|
|
|
return err(ENOENT);
|
|
|
|
}
|
|
|
|
|
2023-06-21 19:32:28 +00:00
|
|
|
Result<const BlockGroupDescriptor*> FileSystem::find_block_group_descriptor(u32 index)
|
|
|
|
{
|
|
|
|
check(index < m_block_groups);
|
|
|
|
|
|
|
|
auto maybe_desc = m_block_group_descriptor_cache.try_get_ref(index);
|
|
|
|
if (maybe_desc) return maybe_desc;
|
|
|
|
|
|
|
|
const u64 address = (m_superblock.first_data_block + 1) * m_block_size + (index * sizeof(BlockGroupDescriptor));
|
|
|
|
|
|
|
|
BlockGroupDescriptor descriptor;
|
|
|
|
TRY(m_host_device->read((u8*)&descriptor, address, sizeof(descriptor)));
|
|
|
|
|
|
|
|
check(TRY(m_block_group_descriptor_cache.try_set(index, descriptor)));
|
|
|
|
|
|
|
|
return m_block_group_descriptor_cache.try_get_ref(index);
|
|
|
|
}
|
|
|
|
|
2023-06-20 19:39:22 +00:00
|
|
|
Result<SharedPtr<VFS::FileSystem>> FileSystem::create(SharedPtr<Device> host_device)
|
|
|
|
{
|
|
|
|
SharedPtr<FileSystem> fs = TRY(adopt_shared_if_nonnull(new (std::nothrow) FileSystem()));
|
|
|
|
const usize nread = TRY(host_device->read((u8*)&fs->m_superblock, 1024, 1024));
|
|
|
|
if (nread != 1024) return err(EINVAL); // Source had an invalid superblock.
|
|
|
|
if (fs->m_superblock.signature != EXT2_MAGIC) return err(EINVAL); // Source had an invalid superblock.
|
|
|
|
|
2023-06-21 19:32:28 +00:00
|
|
|
fs->m_host_device = host_device;
|
|
|
|
|
|
|
|
fs->m_block_size = 1024 << fs->m_superblock.log_block_size;
|
|
|
|
fs->m_block_groups = get_blocks_from_size(fs->m_superblock.nr_blocks, fs->m_superblock.blocks_per_block_group);
|
|
|
|
|
|
|
|
kdbgln("ext2: Mounting new Ext2 file system, block size=%lu, blocks=%u, inodes=%u, block group=(%u blocks, %u "
|
|
|
|
"inodes), %lu block groups",
|
|
|
|
fs->m_block_size, fs->m_superblock.nr_blocks, fs->m_superblock.nr_inodes,
|
|
|
|
fs->m_superblock.blocks_per_block_group, fs->m_superblock.inodes_per_block_group, fs->m_block_groups);
|
|
|
|
|
|
|
|
// Lookup the root inode.
|
|
|
|
fs->find_inode_by_number(2);
|
|
|
|
|
2023-06-20 19:39:22 +00:00
|
|
|
// TODO: Implement basic Ext2 reading, enough to be able to mount a volume.
|
|
|
|
return err(ENOTSUP);
|
|
|
|
}
|
|
|
|
}
|