Compare commits

..

No commits in common. "7177da7d62891fc1ccf30c81f9983414a1dd2e23" and "a084f83f4c1b24af1bf207e340d68ebb48c7cc06" have entirely different histories.

11 changed files with 168 additions and 224 deletions

View File

@ -61,17 +61,17 @@ namespace Kernel
BAN::ErrorOr<void> initialize_root_inode();
BAN::ErrorOr<uint32_t> create_inode(const Ext2::Inode&);
BAN::ErrorOr<void> delete_inode(uint32_t ino);
void delete_inode(uint32_t ino);
BAN::ErrorOr<void> resize_inode(uint32_t, size_t);
BAN::ErrorOr<void> read_block(uint32_t, BlockBufferWrapper&);
BAN::ErrorOr<void> write_block(uint32_t, const BlockBufferWrapper&);
BAN::ErrorOr<void> sync_superblock();
void read_block(uint32_t, BlockBufferWrapper&);
void write_block(uint32_t, const BlockBufferWrapper&);
void sync_superblock();
BlockBufferWrapper get_block_buffer();
BAN::ErrorOr<uint32_t> reserve_free_block(uint32_t primary_bgd);
BAN::ErrorOr<void> release_block(uint32_t block);
void release_block(uint32_t block);
BAN::HashMap<ino_t, BAN::RefPtr<Ext2Inode>>& inode_cache() { return m_inode_cache; }
@ -82,7 +82,7 @@ namespace Kernel
uint32_t block;
uint32_t offset;
};
BAN::ErrorOr<BlockLocation> locate_inode(uint32_t);
BlockLocation locate_inode(uint32_t);
BlockLocation locate_block_group_descriptior(uint32_t);
uint32_t block_size() const { return 1024 << superblock().log_block_size; }

View File

@ -52,19 +52,19 @@ namespace Kernel
// NOTE: the inode might have more blocks than what this suggests if it has been shrinked
uint32_t max_used_data_block_count() const { return size() / blksize(); }
BAN::ErrorOr<BAN::Optional<uint32_t>> block_from_indirect_block(uint32_t block, uint32_t index, uint32_t depth);
BAN::ErrorOr<BAN::Optional<uint32_t>> fs_block_of_data_block_index(uint32_t data_block_index);
BAN::Optional<uint32_t> block_from_indirect_block(uint32_t block, uint32_t index, uint32_t depth);
BAN::Optional<uint32_t> fs_block_of_data_block_index(uint32_t data_block_index);
BAN::ErrorOr<void> link_inode_to_directory(Ext2Inode&, BAN::StringView name);
BAN::ErrorOr<bool> is_directory_empty();
BAN::ErrorOr<void> cleanup_indirect_block(uint32_t block, uint32_t depth);
void cleanup_indirect_block(uint32_t block, uint32_t depth);
BAN::ErrorOr<void> cleanup_default_links();
BAN::ErrorOr<void> cleanup_from_fs();
void cleanup_from_fs();
BAN::ErrorOr<uint32_t> allocate_new_block_to_indirect_block(uint32_t& block, uint32_t index, uint32_t depth);
BAN::ErrorOr<uint32_t> allocate_new_block(uint32_t data_block_index);
BAN::ErrorOr<void> sync();
void sync();
uint32_t block_group() const;

View File

@ -109,6 +109,7 @@ namespace Kernel
BAN::ErrorOr<long> sys_read(int fd, void* buffer, size_t count);
BAN::ErrorOr<long> sys_write(int fd, const void* buffer, size_t count);
BAN::ErrorOr<long> sys_access(const char* path, int amode);
BAN::ErrorOr<long> sys_create(const char*, mode_t);
BAN::ErrorOr<long> sys_create_dir(const char*, mode_t);
BAN::ErrorOr<long> sys_unlink(const char*);
BAN::ErrorOr<long> readlink_impl(BAN::RefPtr<Inode>, char* buffer, size_t bufsize);

View File

@ -63,7 +63,7 @@ namespace Kernel
if (m_superblock.rev_level == Ext2::Enum::GOOD_OLD_REV)
{
memset(m_superblock.__extension_start, 0, sizeof(Ext2::Superblock) - offsetof(Ext2::Superblock, __extension_start));
memset(m_superblock.__extension_start, 0, sizeof(Ext2::Superblock) - offsetof(Ext2::Superblock, Ext2::Superblock::__extension_start));
m_superblock.first_ino = Ext2::Enum::GOOD_OLD_FIRST_INO;
m_superblock.inode_size = Ext2::Enum::GOOD_OLD_INODE_SIZE;
}
@ -140,7 +140,7 @@ namespace Kernel
for (uint32_t bg : m_superblock_backups)
{
TRY(read_block(superblock().first_data_block + superblock().blocks_per_group * bg, block_buffer));
read_block(superblock().first_data_block + superblock().blocks_per_group * bg, block_buffer);
Ext2::Superblock& superblock_backup = *(Ext2::Superblock*)block_buffer.data();
if (superblock_backup.magic != Ext2::Enum::SUPER_MAGIC)
derrorln("superblock backup at block {} is invalid ({4H})", bg, superblock_backup.magic);
@ -184,7 +184,7 @@ namespace Kernel
current_group = ino_group;
bgd_location = locate_block_group_descriptior(current_group);
TRY(read_block(bgd_location.block, bgd_buffer));
read_block(bgd_location.block, bgd_buffer);
bgd = (Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset);
if (bgd->free_inodes_count == 0)
@ -193,7 +193,7 @@ namespace Kernel
continue;
}
TRY(read_block(bgd->inode_bitmap, inode_bitmap));
read_block(bgd->inode_bitmap, inode_bitmap);
}
const uint32_t ino_bitmap_byte = ino_index / 8;
@ -202,15 +202,16 @@ namespace Kernel
continue;
inode_bitmap[ino_bitmap_byte] |= 1 << ino_bitmap_bit;
TRY(write_block(bgd->inode_bitmap, inode_bitmap));
write_block(bgd->inode_bitmap, inode_bitmap);
bgd->free_inodes_count--;
if (Inode::Mode(ext2_inode.mode).ifdir())
bgd->used_dirs_count++;
TRY(write_block(bgd_location.block, bgd_buffer));
write_block(bgd_location.block, bgd_buffer);
const uint32_t inode_table_offset = ino_index * superblock().inode_size;
const BlockLocation inode_location {
const BlockLocation inode_location
{
.block = inode_table_offset / block_size + bgd->inode_table,
.offset = inode_table_offset % block_size
};
@ -218,14 +219,14 @@ namespace Kernel
// NOTE: we don't need inode bitmap anymore, so we can reuse it
auto& inode_buffer = inode_bitmap;
TRY(read_block(inode_location.block, inode_buffer));
read_block(inode_location.block, inode_buffer);
memcpy(inode_buffer.data() + inode_location.offset, &ext2_inode, sizeof(Ext2::Inode));
if (superblock().inode_size > sizeof(Ext2::Inode))
memset(inode_buffer.data() + inode_location.offset + sizeof(Ext2::Inode), 0, superblock().inode_size - sizeof(Ext2::Inode));
TRY(write_block(inode_location.block, inode_buffer));
write_block(inode_location.block, inode_buffer);
m_superblock.free_inodes_count--;
TRY(sync_superblock());
sync_superblock();
return ino;
}
@ -234,7 +235,7 @@ namespace Kernel
return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted);
}
BAN::ErrorOr<void> Ext2FS::delete_inode(uint32_t ino)
void Ext2FS::delete_inode(uint32_t ino)
{
LockGuard _(m_mutex);
@ -249,20 +250,20 @@ namespace Kernel
const uint32_t inode_index = (ino - 1) % superblock().inodes_per_group;
auto bgd_location = locate_block_group_descriptior(inode_group);
TRY(read_block(bgd_location.block, bgd_buffer));
read_block(bgd_location.block, bgd_buffer);
auto& bgd = bgd_buffer.span().slice(bgd_location.offset).as<Ext2::BlockGroupDescriptor>();
// update inode bitmap
TRY(read_block(bgd.inode_bitmap, bitmap_buffer));
read_block(bgd.inode_bitmap, bitmap_buffer);
const uint32_t byte = inode_index / 8;
const uint32_t bit = inode_index % 8;
ASSERT(bitmap_buffer[byte] & (1 << bit));
bitmap_buffer[byte] &= ~(1 << bit);
TRY(write_block(bgd.inode_bitmap, bitmap_buffer));
write_block(bgd.inode_bitmap, bitmap_buffer);
// memset inode to zero or fsck will complain
auto inode_location = TRY(locate_inode(ino));
TRY(read_block(inode_location.block, inode_buffer));
auto inode_location = locate_inode(ino);
read_block(inode_location.block, inode_buffer);
auto& inode = inode_buffer.span().slice(inode_location.offset).as<Ext2::Inode>();
#if EXT2_VERIFY_NO_BLOCKS
static const char zero_buffer[sizeof(inode.block)] {};
@ -270,26 +271,24 @@ namespace Kernel
#endif
bool is_directory = Inode::Mode(inode.mode).ifdir();
memset(&inode, 0x00, m_superblock.inode_size);
TRY(write_block(inode_location.block, inode_buffer));
write_block(inode_location.block, inode_buffer);
// update bgd counts
bgd.free_inodes_count++;
if (is_directory)
bgd.used_dirs_count--;
TRY(write_block(bgd_location.block, bgd_buffer));
write_block(bgd_location.block, bgd_buffer);
// update superblock inode count
m_superblock.free_inodes_count++;
TRY(sync_superblock());
sync_superblock();
// remove inode from cache
if (m_inode_cache.contains(ino))
m_inode_cache.remove(ino);
return {};
}
BAN::ErrorOr<void> Ext2FS::read_block(uint32_t block, BlockBufferWrapper& buffer)
void Ext2FS::read_block(uint32_t block, BlockBufferWrapper& buffer)
{
LockGuard _(m_mutex);
@ -299,12 +298,10 @@ namespace Kernel
ASSERT(block >= superblock().first_data_block + 1);
ASSERT(buffer.size() >= block_size);
TRY(m_block_device->read_blocks(block * sectors_per_block, sectors_per_block, buffer.span()));
return {};
MUST(m_block_device->read_blocks(block * sectors_per_block, sectors_per_block, buffer.span()));
}
BAN::ErrorOr<void> Ext2FS::write_block(uint32_t block, const BlockBufferWrapper& buffer)
void Ext2FS::write_block(uint32_t block, const BlockBufferWrapper& buffer)
{
LockGuard _(m_mutex);
@ -314,12 +311,10 @@ namespace Kernel
ASSERT(block >= superblock().first_data_block + 1);
ASSERT(buffer.size() >= block_size);
TRY(m_block_device->write_blocks(block * sectors_per_block, sectors_per_block, buffer.span()));
return {};
MUST(m_block_device->write_blocks(block * sectors_per_block, sectors_per_block, buffer.span()));
}
BAN::ErrorOr<void> Ext2FS::sync_superblock()
void Ext2FS::sync_superblock()
{
LockGuard _(m_mutex);
@ -336,14 +331,12 @@ namespace Kernel
auto superblock_buffer = get_block_buffer();
TRY(m_block_device->read_blocks(lba, sector_count, superblock_buffer.span()));
MUST(m_block_device->read_blocks(lba, sector_count, superblock_buffer.span()));
if (memcmp(superblock_buffer.data(), &m_superblock, superblock_bytes))
{
memcpy(superblock_buffer.data(), &m_superblock, superblock_bytes);
TRY(m_block_device->write_blocks(lba, sector_count, superblock_buffer.span()));
MUST(m_block_device->write_blocks(lba, sector_count, superblock_buffer.span()));
}
return {};
}
Ext2FS::BlockBufferWrapper Ext2FS::get_block_buffer()
@ -363,16 +356,16 @@ namespace Kernel
auto block_bitmap = m_buffer_manager.get_buffer();
auto check_block_group =
[&](uint32_t block_group) -> BAN::ErrorOr<uint32_t>
[&](uint32_t block_group) -> uint32_t
{
auto bgd_location = locate_block_group_descriptior(block_group);
TRY(read_block(bgd_location.block, bgd_buffer));
read_block(bgd_location.block, bgd_buffer);
auto& bgd = *(Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset);
if (bgd.free_blocks_count == 0)
return 0;
TRY(read_block(bgd.block_bitmap, block_bitmap));
read_block(bgd.block_bitmap, block_bitmap);
for (uint32_t block_offset = 0; block_offset < m_superblock.blocks_per_group; block_offset++)
{
const uint32_t fs_block_index = m_superblock.first_data_block + m_superblock.blocks_per_group * block_group + block_offset;
@ -385,13 +378,13 @@ namespace Kernel
continue;
block_bitmap[byte] |= 1 << bit;
TRY(write_block(bgd.block_bitmap, block_bitmap));
write_block(bgd.block_bitmap, block_bitmap);
bgd.free_blocks_count--;
TRY(write_block(bgd_location.block, bgd_buffer));
write_block(bgd_location.block, bgd_buffer);
m_superblock.free_blocks_count--;
TRY(sync_superblock());
sync_superblock();
return fs_block_index;
}
@ -400,20 +393,20 @@ namespace Kernel
return 0;
};
if (auto ret = TRY(check_block_group(primary_bgd)))
if (auto ret = check_block_group(primary_bgd))
return ret;
uint32_t number_of_block_groups = BAN::Math::div_round_up(m_superblock.blocks_count, m_superblock.blocks_per_group);
for (uint32_t block_group = 0; block_group < number_of_block_groups; block_group++)
if (block_group != primary_bgd)
if (auto ret = TRY(check_block_group(block_group)))
if (auto ret = check_block_group(block_group))
return ret;
derrorln("Corrupted file system. Superblock indicates free blocks but none were found.");
return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted);
}
BAN::ErrorOr<void> Ext2FS::release_block(uint32_t block)
void Ext2FS::release_block(uint32_t block)
{
LockGuard _(m_mutex);
@ -427,28 +420,26 @@ namespace Kernel
auto bitmap_buffer = get_block_buffer();
auto bgd_location = locate_block_group_descriptior(block_group);
TRY(read_block(bgd_location.block, bgd_buffer));
read_block(bgd_location.block, bgd_buffer);
auto& bgd = bgd_buffer.span().slice(bgd_location.offset).as<Ext2::BlockGroupDescriptor>();
TRY(read_block(bgd.block_bitmap, bitmap_buffer));
read_block(bgd.block_bitmap, bitmap_buffer);
const uint32_t byte = block_offset / 8;
const uint32_t bit = block_offset % 8;
ASSERT(bitmap_buffer[byte] & (1 << bit));
bitmap_buffer[byte] &= ~(1 << bit);
TRY(write_block(bgd.block_bitmap, bitmap_buffer));
write_block(bgd.block_bitmap, bitmap_buffer);
bgd.free_blocks_count++;
TRY(write_block(bgd_location.block, bgd_buffer));
write_block(bgd_location.block, bgd_buffer);
m_superblock.free_blocks_count++;
TRY(sync_superblock());
return {};
sync_superblock();
}
BAN::ErrorOr<Ext2FS::BlockLocation> Ext2FS::locate_inode(uint32_t ino)
Ext2FS::BlockLocation Ext2FS::locate_inode(uint32_t ino)
{
LockGuard _(m_mutex);
@ -463,7 +454,7 @@ namespace Kernel
auto bgd_location = locate_block_group_descriptior(inode_group);
TRY(read_block(bgd_location.block, bgd_buffer));
read_block(bgd_location.block, bgd_buffer);
auto& bgd = *(Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset);

View File

@ -27,10 +27,10 @@ namespace Kernel
if (fs.inode_cache().contains(inode_ino))
return fs.inode_cache()[inode_ino];
auto inode_location = TRY(fs.locate_inode(inode_ino));
auto inode_location = fs.locate_inode(inode_ino);
auto block_buffer = fs.get_block_buffer();
TRY(fs.read_block(inode_location.block, block_buffer));
fs.read_block(inode_location.block, block_buffer);
auto& inode = block_buffer.span().slice(inode_location.offset).as<Ext2::Inode>();
@ -41,20 +41,18 @@ namespace Kernel
Ext2Inode::~Ext2Inode()
{
if (m_inode.links_count > 0)
return;
if (auto ret = cleanup_from_fs(); ret.is_error())
dwarnln("Could not cleanup inode from FS: {}", ret.error());
if (m_inode.links_count == 0)
cleanup_from_fs();
}
BAN::ErrorOr<BAN::Optional<uint32_t>> Ext2Inode::block_from_indirect_block(uint32_t block, uint32_t index, uint32_t depth)
BAN::Optional<uint32_t> Ext2Inode::block_from_indirect_block(uint32_t block, uint32_t index, uint32_t depth)
{
if (block == 0)
return BAN::Optional<uint32_t>();
return {};
ASSERT(depth >= 1);
auto block_buffer = m_fs.get_block_buffer();
TRY(m_fs.read_block(block, block_buffer));
m_fs.read_block(block, block_buffer);
const uint32_t indices_per_block = blksize() / sizeof(uint32_t);
@ -62,22 +60,22 @@ namespace Kernel
const uint32_t next_block = block_buffer.span().as_span<uint32_t>()[(index / divisor) % indices_per_block];
if (next_block == 0)
return BAN::Optional<uint32_t>();
return {};
if (depth == 1)
return BAN::Optional<uint32_t>(next_block);
return next_block;
return block_from_indirect_block(next_block, index, depth - 1);
}
BAN::ErrorOr<BAN::Optional<uint32_t>> Ext2Inode::fs_block_of_data_block_index(uint32_t data_block_index)
BAN::Optional<uint32_t> Ext2Inode::fs_block_of_data_block_index(uint32_t data_block_index)
{
const uint32_t indices_per_block = blksize() / sizeof(uint32_t);
if (data_block_index < 12)
{
if (m_inode.block[data_block_index] == 0)
return BAN::Optional<uint32_t>();
return BAN::Optional<uint32_t>(m_inode.block[data_block_index]);
return {};
return m_inode.block[data_block_index];
}
data_block_index -= 12;
@ -131,9 +129,9 @@ namespace Kernel
for (uint32_t data_block_index = first_block; data_block_index < last_block; data_block_index++)
{
auto block_index = TRY(fs_block_of_data_block_index(data_block_index));
auto block_index = fs_block_of_data_block_index(data_block_index);
if (block_index.has_value())
TRY(m_fs.read_block(block_index.value(), block_buffer));
m_fs.read_block(block_index.value(), block_buffer);
else
memset(block_buffer.data(), 0x00, block_buffer.size());
@ -170,9 +168,9 @@ namespace Kernel
// Write partial block
if (offset % block_size)
{
auto block_index = TRY(fs_block_of_data_block_index(offset / block_size));
auto block_index = fs_block_of_data_block_index(offset / block_size);
if (block_index.has_value())
TRY(m_fs.read_block(block_index.value(), block_buffer));
m_fs.read_block(block_index.value(), block_buffer);
else
{
block_index = TRY(allocate_new_block(offset / block_size));;
@ -183,7 +181,7 @@ namespace Kernel
uint32_t to_copy = BAN::Math::min<uint32_t>(block_size - block_offset, to_write);
memcpy(block_buffer.data() + block_offset, buffer.data(), to_copy);
TRY(m_fs.write_block(block_index.value(), block_buffer));
m_fs.write_block(block_index.value(), block_buffer);
written += to_copy;
offset += to_copy;
@ -192,12 +190,12 @@ namespace Kernel
while (to_write >= block_size)
{
auto block_index = TRY(fs_block_of_data_block_index(offset / block_size));
auto block_index = fs_block_of_data_block_index(offset / block_size);
if (!block_index.has_value())
block_index = TRY(allocate_new_block(offset / block_size));
memcpy(block_buffer.data(), buffer.data() + written, block_buffer.size());
TRY(m_fs.write_block(block_index.value(), block_buffer));
m_fs.write_block(block_index.value(), block_buffer);
written += block_size;
offset += block_size;
@ -206,9 +204,9 @@ namespace Kernel
if (to_write > 0)
{
auto block_index = TRY(fs_block_of_data_block_index(offset / block_size));
auto block_index = fs_block_of_data_block_index(offset / block_size);
if (block_index.has_value())
TRY(m_fs.read_block(block_index.value(), block_buffer));
m_fs.read_block(block_index.value(), block_buffer);
else
{
block_index = TRY(allocate_new_block(offset / block_size));
@ -216,7 +214,7 @@ namespace Kernel
}
memcpy(block_buffer.data(), buffer.data() + written, to_write);
TRY(m_fs.write_block(block_index.value(), block_buffer));
m_fs.write_block(block_index.value(), block_buffer);
}
return buffer.size();
@ -229,14 +227,8 @@ namespace Kernel
// TODO: we should remove unused blocks on shrink
const auto old_size = m_inode.size;
m_inode.size = new_size;
if (auto ret = sync(); ret.is_error())
{
m_inode.size = old_size;
return ret.release_error();
}
sync();
return {};
}
@ -246,31 +238,23 @@ namespace Kernel
ASSERT((mode & Inode::Mode::TYPE_MASK) == 0);
if (m_inode.mode == mode)
return {};
const auto old_mode = m_inode.mode;
m_inode.mode = (m_inode.mode & Inode::Mode::TYPE_MASK) | mode;
if (auto ret = sync(); ret.is_error())
{
m_inode.mode = old_mode;
return ret.release_error();
}
sync();
return {};
}
BAN::ErrorOr<void> Ext2Inode::cleanup_indirect_block(uint32_t block, uint32_t depth)
void Ext2Inode::cleanup_indirect_block(uint32_t block, uint32_t depth)
{
ASSERT(block);
if (depth == 0)
{
TRY(m_fs.release_block(block));
return {};
m_fs.release_block(block);
return;
}
auto block_buffer = m_fs.get_block_buffer();
TRY(m_fs.read_block(block, block_buffer));
m_fs.read_block(block, block_buffer);
const uint32_t ids_per_block = blksize() / sizeof(uint32_t);
for (uint32_t i = 0; i < ids_per_block; i++)
@ -278,14 +262,13 @@ namespace Kernel
const uint32_t next_block = block_buffer.span().as_span<uint32_t>()[i];
if (next_block == 0)
continue;
TRY(cleanup_indirect_block(next_block, depth - 1));
cleanup_indirect_block(next_block, depth - 1);
}
TRY(m_fs.release_block(block));
return {};
m_fs.release_block(block);
}
BAN::ErrorOr<void> Ext2Inode::cleanup_from_fs()
void Ext2Inode::cleanup_from_fs()
{
ASSERT(m_inode.links_count == 0);
@ -295,15 +278,15 @@ namespace Kernel
// cleanup direct blocks
for (uint32_t i = 0; i < 12; i++)
if (m_inode.block[i])
TRY(m_fs.release_block(m_inode.block[i]));
m_fs.release_block(m_inode.block[i]);
// cleanup indirect blocks
if (m_inode.block[12])
TRY(cleanup_indirect_block(m_inode.block[12], 1));
cleanup_indirect_block(m_inode.block[12], 1);
if (m_inode.block[13])
TRY(cleanup_indirect_block(m_inode.block[13], 2));
cleanup_indirect_block(m_inode.block[13], 2);
if (m_inode.block[14])
TRY(cleanup_indirect_block(m_inode.block[14], 3));
cleanup_indirect_block(m_inode.block[14], 3);
done:
// mark blocks as deleted
@ -311,11 +294,9 @@ done:
// FIXME: this is only required since fs does not get
// deleting inode from its cache
TRY(sync());
sync();
TRY(m_fs.delete_inode(ino()));
return {};
m_fs.delete_inode(ino());
}
BAN::ErrorOr<size_t> Ext2Inode::list_next_inodes_impl(off_t offset, struct dirent* list, size_t list_size)
@ -327,11 +308,11 @@ done:
return 0;
// FIXME: can we actually assume directories have all their blocks allocated
const uint32_t block_index = TRY(fs_block_of_data_block_index(offset)).value();
const uint32_t block_index = fs_block_of_data_block_index(offset).value();
auto block_buffer = m_fs.get_block_buffer();
TRY(m_fs.read_block(block_index, block_buffer));
m_fs.read_block(block_index, block_buffer);
// First determine if we have big enough list
size_t entry_count = 0;
@ -350,9 +331,6 @@ done:
return BAN::Error::from_errno(ENOBUFS);
}
if (entry_count == 0)
return BAN::Error::from_errno(ENODATA);
// Second fill the list
{
dirent* dirp = list;
@ -432,7 +410,7 @@ done:
auto inode_or_error = Ext2Inode::create(m_fs, new_ino);
if (inode_or_error.is_error())
{
TRY(m_fs.delete_inode(new_ino));
m_fs.delete_inode(new_ino);
return inode_or_error.release_error();
}
@ -453,21 +431,19 @@ done:
auto inode_or_error = Ext2Inode::create(m_fs, new_ino);
if (inode_or_error.is_error())
{
TRY(m_fs.delete_inode(new_ino));
m_fs.delete_inode(new_ino);
return inode_or_error.release_error();
}
auto inode = inode_or_error.release_value();
BAN::ScopeGuard cleanup([&] { inode->cleanup_from_fs(); });
// link . and ..
if (auto ret = inode->link_inode_to_directory(*inode, "."_sv); ret.is_error())
return ({ TRY(inode->cleanup_from_fs()); ret.release_error(); });
if (auto ret = inode->link_inode_to_directory(*this, ".."_sv); ret.is_error())
return ({ TRY(inode->cleanup_from_fs()); ret.release_error(); });
TRY(inode->link_inode_to_directory(*inode, "."_sv));
TRY(inode->link_inode_to_directory(*this, ".."_sv));
// link to parent
if (auto ret = link_inode_to_directory(*inode, name); ret.is_error())
return ({ TRY(inode->cleanup_from_fs()); ret.release_error(); });
TRY(link_inode_to_directory(*inode, name));
cleanup.disable();
return {};
}
@ -496,8 +472,7 @@ done:
auto block_buffer = m_fs.get_block_buffer();
auto write_inode =
[&](uint32_t entry_offset, uint32_t entry_rec_len) -> BAN::ErrorOr<void>
auto write_inode = [&](uint32_t entry_offset, uint32_t entry_rec_len)
{
auto typed_mode = inode.mode();
uint8_t file_type = (m_fs.superblock().rev_level == Ext2::Enum::GOOD_OLD_REV) ? 0
@ -518,9 +493,7 @@ done:
memcpy(new_entry.name, name.data(), name.size());
inode.m_inode.links_count++;
TRY(inode.sync());
return {};
inode.sync();
};
uint32_t block_index = 0;
@ -536,8 +509,8 @@ done:
goto needs_new_block;
// Try to insert inode to last data block
block_index = TRY(fs_block_of_data_block_index(data_block_count - 1)).value();
TRY(m_fs.read_block(block_index, block_buffer));
block_index = fs_block_of_data_block_index(data_block_count - 1).value();
m_fs.read_block(block_index, block_buffer);
while (entry_offset < block_size)
{
@ -549,8 +522,8 @@ done:
if (entry.inode == 0 && needed_entry_len <= entry.rec_len)
{
TRY(write_inode(entry_offset, entry.rec_len));
TRY(m_fs.write_block(block_index, block_buffer));
write_inode(entry_offset, entry.rec_len);
m_fs.write_block(block_index, block_buffer);
return {};
}
else if (needed_entry_len <= entry.rec_len - entry_min_rec_len)
@ -558,8 +531,8 @@ done:
uint32_t new_rec_len = entry.rec_len - entry_min_rec_len;
entry.rec_len = entry_min_rec_len;
TRY(write_inode(entry_offset + entry.rec_len, new_rec_len));
TRY(m_fs.write_block(block_index, block_buffer));
write_inode(entry_offset + entry.rec_len, new_rec_len);
m_fs.write_block(block_index, block_buffer);
return {};
}
@ -571,8 +544,8 @@ needs_new_block:
m_inode.size += blksize();
memset(block_buffer.data(), 0x00, block_buffer.size());
TRY(write_inode(0, block_size));
TRY(m_fs.write_block(block_index, block_buffer));
write_inode(0, block_size);
m_fs.write_block(block_index, block_buffer);
return {};
}
@ -587,8 +560,8 @@ needs_new_block:
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
{
// FIXME: can we actually assume directories have all their blocks allocated
const uint32_t block_index = TRY(fs_block_of_data_block_index(i)).value();
TRY(m_fs.read_block(block_index, block_buffer));
const uint32_t block_index = fs_block_of_data_block_index(i).value();
m_fs.read_block(block_index, block_buffer);
blksize_t offset = 0;
while (offset < blksize())
@ -623,8 +596,8 @@ needs_new_block:
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
{
// FIXME: can we actually assume directories have all their blocks allocated
const uint32_t block_index = TRY(fs_block_of_data_block_index(i)).value();
TRY(m_fs.read_block(block_index, block_buffer));
const uint32_t block_index = fs_block_of_data_block_index(i).value();
m_fs.read_block(block_index, block_buffer);
bool modified = false;
@ -640,13 +613,13 @@ needs_new_block:
if (entry_name == "."_sv)
{
m_inode.links_count--;
TRY(sync());
sync();
}
else if (entry_name == ".."_sv)
{
auto parent = TRY(Ext2Inode::create(m_fs, entry.inode));
parent->m_inode.links_count--;
TRY(parent->sync());
parent->sync();
}
else
ASSERT_NOT_REACHED();
@ -659,7 +632,7 @@ needs_new_block:
}
if (modified)
TRY(m_fs.write_block(block_index, block_buffer));
m_fs.write_block(block_index, block_buffer);
}
return {};
@ -679,8 +652,8 @@ needs_new_block:
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
{
// FIXME: can we actually assume directories have all their blocks allocated
const uint32_t block_index = TRY(fs_block_of_data_block_index(i)).value();
TRY(m_fs.read_block(block_index, block_buffer));
const uint32_t block_index = fs_block_of_data_block_index(i).value();
m_fs.read_block(block_index, block_buffer);
blksize_t offset = 0;
while (offset < blksize())
@ -701,7 +674,7 @@ needs_new_block:
else
inode->m_inode.links_count--;
TRY(sync());
sync();
// NOTE: If this was the last link to inode we must
// remove it from inode cache to trigger cleanup
@ -714,7 +687,7 @@ needs_new_block:
// FIXME: This should expand the last inode if exists
entry.inode = 0;
TRY(m_fs.write_block(block_index, block_buffer));
m_fs.write_block(block_index, block_buffer);
}
offset += entry.rec_len;
}
@ -738,14 +711,14 @@ needs_new_block:
auto block_buffer = m_fs.get_block_buffer();
memset(block_buffer.data(), 0x00, block_buffer.size());
TRY(m_fs.write_block(block, block_buffer));
m_fs.write_block(block, block_buffer);
}
if (depth == 0)
return block;
auto block_buffer = m_fs.get_block_buffer();
TRY(m_fs.read_block(block, block_buffer));
m_fs.read_block(block, block_buffer);
uint32_t divisor = 1;
for (uint32_t i = 1; i < depth; i++)
@ -754,9 +727,7 @@ needs_new_block:
uint32_t& new_block = block_buffer.span().as_span<uint32_t>()[(index / divisor) % indices_per_fs_block];
uint32_t allocated_block = TRY(allocate_new_block_to_indirect_block(new_block, index, depth - 1));
TRY(m_fs.write_block(block, block_buffer));
TRY(sync());
m_fs.write_block(block, block_buffer);
return allocated_block;
}
@ -766,12 +737,13 @@ needs_new_block:
const uint32_t inode_blocks_per_fs_block = blksize() / 512;
const uint32_t indices_per_fs_block = blksize() / sizeof(uint32_t);
BAN::ScopeGuard syncer([&] { sync(); });
if (data_block_index < 12)
{
ASSERT(m_inode.block[data_block_index] == 0);
m_inode.block[data_block_index] = TRY(m_fs.reserve_free_block(block_group()));
m_inode.blocks += inode_blocks_per_fs_block;
TRY(sync());
return m_inode.block[data_block_index];
}
data_block_index -= 12;
@ -790,19 +762,17 @@ needs_new_block:
ASSERT_NOT_REACHED();
}
BAN::ErrorOr<void> Ext2Inode::sync()
void Ext2Inode::sync()
{
auto inode_location = TRY(m_fs.locate_inode(ino()));
auto inode_location = m_fs.locate_inode(ino());
auto block_buffer = m_fs.get_block_buffer();
TRY(m_fs.read_block(inode_location.block, block_buffer));
m_fs.read_block(inode_location.block, block_buffer);
if (memcmp(block_buffer.data() + inode_location.offset, &m_inode, sizeof(Ext2::Inode)))
{
memcpy(block_buffer.data() + inode_location.offset, &m_inode, sizeof(Ext2::Inode));
TRY(m_fs.write_block(inode_location.block, block_buffer));
m_fs.write_block(inode_location.block, block_buffer);
}
return {};
}
BAN::ErrorOr<BAN::RefPtr<Inode>> Ext2Inode::find_inode_impl(BAN::StringView file_name)
@ -814,8 +784,8 @@ needs_new_block:
for (uint32_t i = 0; i < max_used_data_block_count(); i++)
{
// FIXME: can we actually assume directories have all their blocks allocated
const uint32_t block_index = TRY(fs_block_of_data_block_index(i)).value();
TRY(m_fs.read_block(block_index, block_buffer));
const uint32_t block_index = fs_block_of_data_block_index(i).value();
m_fs.read_block(block_index, block_buffer);
BAN::ConstByteSpan entry_span = block_buffer.span();
while (entry_span.size() >= sizeof(Ext2::LinkedDirectoryEntry))

View File

@ -475,8 +475,6 @@ namespace Kernel
}
});
if (entry_count == 0)
return BAN::Error::from_errno(ENODATA);
return entry_count;
}

View File

@ -327,13 +327,7 @@ namespace Kernel
auto& open_file = m_open_files[fd];
if (!(open_file->flags & O_RDONLY))
return BAN::Error::from_errno(EACCES);
for (;;)
{
auto ret = open_file->inode()->list_next_inodes(open_file->offset++, list, list_len);
if (ret.is_error() && ret.error().get_error_code() == ENODATA)
continue;
return ret;
}
return TRY(open_file->inode()->list_next_inodes(open_file->offset++, list, list_len));
}
BAN::ErrorOr<VirtualFileSystem::File> OpenFileDescriptorSet::file_of(int fd) const

View File

@ -807,8 +807,6 @@ namespace Kernel
{
parent_inode = parent.inode;
file_name = path;
if (!parent_inode->can_access(m_credentials, O_WRONLY))
return BAN::Error::from_errno(EACCES);
}
if (Inode::Mode(mode).ifdir())
@ -972,6 +970,14 @@ namespace Kernel
return 0;
}
BAN::ErrorOr<long> Process::sys_create(const char* path, mode_t mode)
{
LockGuard _(m_process_lock);
TRY(validate_string_access(path));
TRY(create_file_or_dir(VirtualFileSystem::get().root_file(), path, mode));
return 0;
}
BAN::ErrorOr<long> Process::sys_create_dir(const char* path, mode_t mode)
{
LockGuard _(m_process_lock);
@ -979,12 +985,7 @@ namespace Kernel
BAN::StringView path_sv(path);
if (!path_sv.empty() && path_sv.back() == '/')
path_sv = path_sv.substring(0, path_sv.size() - 1);
if (path_sv.empty())
return BAN::Error::from_errno(EINVAL);
if (path[0] == '/')
TRY(create_file_or_dir(VirtualFileSystem::get().root_file(), path_sv, Inode::Mode::IFDIR | mode));
else
TRY(create_file_or_dir(m_working_directory, path_sv, Inode::Mode::IFDIR | mode));
return 0;
}

View File

@ -1,11 +1,12 @@
#include <fcntl.h>
#include <errno.h>
#include <stdarg.h>
#include <sys/syscall.h>
#include <unistd.h>
int creat(const char* path, mode_t mode)
{
return open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
return syscall(SYS_CREATE, path, S_IFREG | __UMASKED_MODE(mode));
}
int open(const char* path, int oflag, ...)

View File

@ -56,6 +56,7 @@ __BEGIN_DECLS
O(SYS_POWEROFF, poweroff) \
O(SYS_CHMOD, chmod) \
O(SYS_FCHMOD, fchmod) \
O(SYS_CREATE, create) \
O(SYS_CREATE_DIR, create_dir) \
O(SYS_UNLINK, unlink) \
O(SYS_READLINK, readlink) \

View File

@ -1,20 +1,7 @@
#include <BAN/Assert.h>
#include <errno.h>
#include <sys/resource.h>
int getrusage(int who, struct rusage* r_usage)
int getrusage(int, struct rusage*)
{
if (who != RUSAGE_CHILDREN && who != RUSAGE_SELF)
{
errno = EINVAL;
return -1;
}
r_usage->ru_stime.tv_sec = 0;
r_usage->ru_stime.tv_usec = 0;
r_usage->ru_utime.tv_sec = 0;
r_usage->ru_utime.tv_usec = 0;
return 0;
ASSERT_NOT_REACHED();
}