Compare commits

...

5 Commits

Author SHA1 Message Date
Bananymous 7177da7d62 LibC: Implement dummy get_rusage
One port seems to use this function. This dummy just reports no used CPU
time for current process nor children
2024-09-17 15:59:22 +03:00
Bananymous 5e4aa75e03 Kernel: Perform access checks when creating a file or a directory
Also SYS_CREATE_DIR now uses correct relative path. It used to always
create files relative to root. And as no permission checks were tested,
file creation succeeded to root as long as path did not contain '/' :D
2024-09-17 15:57:07 +03:00
Bananymous d88ee5c9ee Kernel/LibC: Implement `creat` with `open`
This allows getting rid of unnecessary SYS_CREATE. Directory creation
still has its own syscall, but I could combine it with SYS_OPEN also.
2024-09-17 15:55:53 +03:00
Bananymous d4ea720239 Kernel: Don't crash the kernel if ext2 encounters disk error
This will most likely result in a corrupted filesystem, but crashing the
kernel is too much :D
2024-09-17 15:54:33 +03:00
Bananymous 97ee370ffe Kernel: Allow listing files even if one of directories blocks are empty 2024-09-17 15:53:14 +03:00
11 changed files with 224 additions and 168 deletions

View File

@ -61,17 +61,17 @@ namespace Kernel
BAN::ErrorOr<void> initialize_root_inode(); BAN::ErrorOr<void> initialize_root_inode();
BAN::ErrorOr<uint32_t> create_inode(const Ext2::Inode&); BAN::ErrorOr<uint32_t> create_inode(const Ext2::Inode&);
void delete_inode(uint32_t ino); BAN::ErrorOr<void> delete_inode(uint32_t ino);
BAN::ErrorOr<void> resize_inode(uint32_t, size_t); BAN::ErrorOr<void> resize_inode(uint32_t, size_t);
void read_block(uint32_t, BlockBufferWrapper&); BAN::ErrorOr<void> read_block(uint32_t, BlockBufferWrapper&);
void write_block(uint32_t, const BlockBufferWrapper&); BAN::ErrorOr<void> write_block(uint32_t, const BlockBufferWrapper&);
void sync_superblock(); BAN::ErrorOr<void> sync_superblock();
BlockBufferWrapper get_block_buffer(); BlockBufferWrapper get_block_buffer();
BAN::ErrorOr<uint32_t> reserve_free_block(uint32_t primary_bgd); BAN::ErrorOr<uint32_t> reserve_free_block(uint32_t primary_bgd);
void release_block(uint32_t block); BAN::ErrorOr<void> release_block(uint32_t block);
BAN::HashMap<ino_t, BAN::RefPtr<Ext2Inode>>& inode_cache() { return m_inode_cache; } BAN::HashMap<ino_t, BAN::RefPtr<Ext2Inode>>& inode_cache() { return m_inode_cache; }
@ -82,7 +82,7 @@ namespace Kernel
uint32_t block; uint32_t block;
uint32_t offset; uint32_t offset;
}; };
BlockLocation locate_inode(uint32_t); BAN::ErrorOr<BlockLocation> locate_inode(uint32_t);
BlockLocation locate_block_group_descriptior(uint32_t); BlockLocation locate_block_group_descriptior(uint32_t);
uint32_t block_size() const { return 1024 << superblock().log_block_size; } 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 // 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(); } uint32_t max_used_data_block_count() const { return size() / blksize(); }
BAN::Optional<uint32_t> block_from_indirect_block(uint32_t block, uint32_t index, uint32_t depth); BAN::ErrorOr<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<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<void> link_inode_to_directory(Ext2Inode&, BAN::StringView name);
BAN::ErrorOr<bool> is_directory_empty(); BAN::ErrorOr<bool> is_directory_empty();
void cleanup_indirect_block(uint32_t block, uint32_t depth); BAN::ErrorOr<void> cleanup_indirect_block(uint32_t block, uint32_t depth);
BAN::ErrorOr<void> cleanup_default_links(); BAN::ErrorOr<void> cleanup_default_links();
void cleanup_from_fs(); BAN::ErrorOr<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_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<uint32_t> allocate_new_block(uint32_t data_block_index);
void sync(); BAN::ErrorOr<void> sync();
uint32_t block_group() const; uint32_t block_group() const;

View File

@ -109,7 +109,6 @@ namespace Kernel
BAN::ErrorOr<long> sys_read(int fd, void* buffer, size_t count); 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_write(int fd, const void* buffer, size_t count);
BAN::ErrorOr<long> sys_access(const char* path, int amode); 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_create_dir(const char*, mode_t);
BAN::ErrorOr<long> sys_unlink(const char*); BAN::ErrorOr<long> sys_unlink(const char*);
BAN::ErrorOr<long> readlink_impl(BAN::RefPtr<Inode>, char* buffer, size_t bufsize); 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) if (m_superblock.rev_level == Ext2::Enum::GOOD_OLD_REV)
{ {
memset(m_superblock.__extension_start, 0, sizeof(Ext2::Superblock) - offsetof(Ext2::Superblock, Ext2::Superblock::__extension_start)); memset(m_superblock.__extension_start, 0, sizeof(Ext2::Superblock) - offsetof(Ext2::Superblock, __extension_start));
m_superblock.first_ino = Ext2::Enum::GOOD_OLD_FIRST_INO; m_superblock.first_ino = Ext2::Enum::GOOD_OLD_FIRST_INO;
m_superblock.inode_size = Ext2::Enum::GOOD_OLD_INODE_SIZE; m_superblock.inode_size = Ext2::Enum::GOOD_OLD_INODE_SIZE;
} }
@ -140,7 +140,7 @@ namespace Kernel
for (uint32_t bg : m_superblock_backups) for (uint32_t bg : m_superblock_backups)
{ {
read_block(superblock().first_data_block + superblock().blocks_per_group * bg, block_buffer); TRY(read_block(superblock().first_data_block + superblock().blocks_per_group * bg, block_buffer));
Ext2::Superblock& superblock_backup = *(Ext2::Superblock*)block_buffer.data(); Ext2::Superblock& superblock_backup = *(Ext2::Superblock*)block_buffer.data();
if (superblock_backup.magic != Ext2::Enum::SUPER_MAGIC) if (superblock_backup.magic != Ext2::Enum::SUPER_MAGIC)
derrorln("superblock backup at block {} is invalid ({4H})", bg, superblock_backup.magic); derrorln("superblock backup at block {} is invalid ({4H})", bg, superblock_backup.magic);
@ -184,7 +184,7 @@ namespace Kernel
current_group = ino_group; current_group = ino_group;
bgd_location = locate_block_group_descriptior(current_group); bgd_location = locate_block_group_descriptior(current_group);
read_block(bgd_location.block, bgd_buffer); TRY(read_block(bgd_location.block, bgd_buffer));
bgd = (Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset); bgd = (Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset);
if (bgd->free_inodes_count == 0) if (bgd->free_inodes_count == 0)
@ -193,7 +193,7 @@ namespace Kernel
continue; continue;
} }
read_block(bgd->inode_bitmap, inode_bitmap); TRY(read_block(bgd->inode_bitmap, inode_bitmap));
} }
const uint32_t ino_bitmap_byte = ino_index / 8; const uint32_t ino_bitmap_byte = ino_index / 8;
@ -202,16 +202,15 @@ namespace Kernel
continue; continue;
inode_bitmap[ino_bitmap_byte] |= 1 << ino_bitmap_bit; inode_bitmap[ino_bitmap_byte] |= 1 << ino_bitmap_bit;
write_block(bgd->inode_bitmap, inode_bitmap); TRY(write_block(bgd->inode_bitmap, inode_bitmap));
bgd->free_inodes_count--; bgd->free_inodes_count--;
if (Inode::Mode(ext2_inode.mode).ifdir()) if (Inode::Mode(ext2_inode.mode).ifdir())
bgd->used_dirs_count++; bgd->used_dirs_count++;
write_block(bgd_location.block, bgd_buffer); TRY(write_block(bgd_location.block, bgd_buffer));
const uint32_t inode_table_offset = ino_index * superblock().inode_size; 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, .block = inode_table_offset / block_size + bgd->inode_table,
.offset = inode_table_offset % block_size .offset = inode_table_offset % block_size
}; };
@ -219,14 +218,14 @@ namespace Kernel
// NOTE: we don't need inode bitmap anymore, so we can reuse it // NOTE: we don't need inode bitmap anymore, so we can reuse it
auto& inode_buffer = inode_bitmap; auto& inode_buffer = inode_bitmap;
read_block(inode_location.block, inode_buffer); TRY(read_block(inode_location.block, inode_buffer));
memcpy(inode_buffer.data() + inode_location.offset, &ext2_inode, sizeof(Ext2::Inode)); memcpy(inode_buffer.data() + inode_location.offset, &ext2_inode, sizeof(Ext2::Inode));
if (superblock().inode_size > 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)); memset(inode_buffer.data() + inode_location.offset + sizeof(Ext2::Inode), 0, superblock().inode_size - sizeof(Ext2::Inode));
write_block(inode_location.block, inode_buffer); TRY(write_block(inode_location.block, inode_buffer));
m_superblock.free_inodes_count--; m_superblock.free_inodes_count--;
sync_superblock(); TRY(sync_superblock());
return ino; return ino;
} }
@ -235,7 +234,7 @@ namespace Kernel
return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted); return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted);
} }
void Ext2FS::delete_inode(uint32_t ino) BAN::ErrorOr<void> Ext2FS::delete_inode(uint32_t ino)
{ {
LockGuard _(m_mutex); LockGuard _(m_mutex);
@ -250,20 +249,20 @@ namespace Kernel
const uint32_t inode_index = (ino - 1) % superblock().inodes_per_group; const uint32_t inode_index = (ino - 1) % superblock().inodes_per_group;
auto bgd_location = locate_block_group_descriptior(inode_group); auto bgd_location = locate_block_group_descriptior(inode_group);
read_block(bgd_location.block, bgd_buffer); TRY(read_block(bgd_location.block, bgd_buffer));
auto& bgd = bgd_buffer.span().slice(bgd_location.offset).as<Ext2::BlockGroupDescriptor>(); auto& bgd = bgd_buffer.span().slice(bgd_location.offset).as<Ext2::BlockGroupDescriptor>();
// update inode bitmap // update inode bitmap
read_block(bgd.inode_bitmap, bitmap_buffer); TRY(read_block(bgd.inode_bitmap, bitmap_buffer));
const uint32_t byte = inode_index / 8; const uint32_t byte = inode_index / 8;
const uint32_t bit = inode_index % 8; const uint32_t bit = inode_index % 8;
ASSERT(bitmap_buffer[byte] & (1 << bit)); ASSERT(bitmap_buffer[byte] & (1 << bit));
bitmap_buffer[byte] &= ~(1 << bit); bitmap_buffer[byte] &= ~(1 << bit);
write_block(bgd.inode_bitmap, bitmap_buffer); TRY(write_block(bgd.inode_bitmap, bitmap_buffer));
// memset inode to zero or fsck will complain // memset inode to zero or fsck will complain
auto inode_location = locate_inode(ino); auto inode_location = TRY(locate_inode(ino));
read_block(inode_location.block, inode_buffer); TRY(read_block(inode_location.block, inode_buffer));
auto& inode = inode_buffer.span().slice(inode_location.offset).as<Ext2::Inode>(); auto& inode = inode_buffer.span().slice(inode_location.offset).as<Ext2::Inode>();
#if EXT2_VERIFY_NO_BLOCKS #if EXT2_VERIFY_NO_BLOCKS
static const char zero_buffer[sizeof(inode.block)] {}; static const char zero_buffer[sizeof(inode.block)] {};
@ -271,24 +270,26 @@ namespace Kernel
#endif #endif
bool is_directory = Inode::Mode(inode.mode).ifdir(); bool is_directory = Inode::Mode(inode.mode).ifdir();
memset(&inode, 0x00, m_superblock.inode_size); memset(&inode, 0x00, m_superblock.inode_size);
write_block(inode_location.block, inode_buffer); TRY(write_block(inode_location.block, inode_buffer));
// update bgd counts // update bgd counts
bgd.free_inodes_count++; bgd.free_inodes_count++;
if (is_directory) if (is_directory)
bgd.used_dirs_count--; bgd.used_dirs_count--;
write_block(bgd_location.block, bgd_buffer); TRY(write_block(bgd_location.block, bgd_buffer));
// update superblock inode count // update superblock inode count
m_superblock.free_inodes_count++; m_superblock.free_inodes_count++;
sync_superblock(); TRY(sync_superblock());
// remove inode from cache // remove inode from cache
if (m_inode_cache.contains(ino)) if (m_inode_cache.contains(ino))
m_inode_cache.remove(ino); m_inode_cache.remove(ino);
return {};
} }
void Ext2FS::read_block(uint32_t block, BlockBufferWrapper& buffer) BAN::ErrorOr<void> Ext2FS::read_block(uint32_t block, BlockBufferWrapper& buffer)
{ {
LockGuard _(m_mutex); LockGuard _(m_mutex);
@ -298,10 +299,12 @@ namespace Kernel
ASSERT(block >= superblock().first_data_block + 1); ASSERT(block >= superblock().first_data_block + 1);
ASSERT(buffer.size() >= block_size); ASSERT(buffer.size() >= block_size);
MUST(m_block_device->read_blocks(block * sectors_per_block, sectors_per_block, buffer.span())); TRY(m_block_device->read_blocks(block * sectors_per_block, sectors_per_block, buffer.span()));
return {};
} }
void Ext2FS::write_block(uint32_t block, const BlockBufferWrapper& buffer) BAN::ErrorOr<void> Ext2FS::write_block(uint32_t block, const BlockBufferWrapper& buffer)
{ {
LockGuard _(m_mutex); LockGuard _(m_mutex);
@ -311,10 +314,12 @@ namespace Kernel
ASSERT(block >= superblock().first_data_block + 1); ASSERT(block >= superblock().first_data_block + 1);
ASSERT(buffer.size() >= block_size); ASSERT(buffer.size() >= block_size);
MUST(m_block_device->write_blocks(block * sectors_per_block, sectors_per_block, buffer.span())); TRY(m_block_device->write_blocks(block * sectors_per_block, sectors_per_block, buffer.span()));
return {};
} }
void Ext2FS::sync_superblock() BAN::ErrorOr<void> Ext2FS::sync_superblock()
{ {
LockGuard _(m_mutex); LockGuard _(m_mutex);
@ -331,12 +336,14 @@ namespace Kernel
auto superblock_buffer = get_block_buffer(); auto superblock_buffer = get_block_buffer();
MUST(m_block_device->read_blocks(lba, sector_count, superblock_buffer.span())); TRY(m_block_device->read_blocks(lba, sector_count, superblock_buffer.span()));
if (memcmp(superblock_buffer.data(), &m_superblock, superblock_bytes)) if (memcmp(superblock_buffer.data(), &m_superblock, superblock_bytes))
{ {
memcpy(superblock_buffer.data(), &m_superblock, superblock_bytes); memcpy(superblock_buffer.data(), &m_superblock, superblock_bytes);
MUST(m_block_device->write_blocks(lba, sector_count, superblock_buffer.span())); TRY(m_block_device->write_blocks(lba, sector_count, superblock_buffer.span()));
} }
return {};
} }
Ext2FS::BlockBufferWrapper Ext2FS::get_block_buffer() Ext2FS::BlockBufferWrapper Ext2FS::get_block_buffer()
@ -356,16 +363,16 @@ namespace Kernel
auto block_bitmap = m_buffer_manager.get_buffer(); auto block_bitmap = m_buffer_manager.get_buffer();
auto check_block_group = auto check_block_group =
[&](uint32_t block_group) -> uint32_t [&](uint32_t block_group) -> BAN::ErrorOr<uint32_t>
{ {
auto bgd_location = locate_block_group_descriptior(block_group); auto bgd_location = locate_block_group_descriptior(block_group);
read_block(bgd_location.block, bgd_buffer); TRY(read_block(bgd_location.block, bgd_buffer));
auto& bgd = *(Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset); auto& bgd = *(Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset);
if (bgd.free_blocks_count == 0) if (bgd.free_blocks_count == 0)
return 0; return 0;
read_block(bgd.block_bitmap, block_bitmap); TRY(read_block(bgd.block_bitmap, block_bitmap));
for (uint32_t block_offset = 0; block_offset < m_superblock.blocks_per_group; block_offset++) 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; const uint32_t fs_block_index = m_superblock.first_data_block + m_superblock.blocks_per_group * block_group + block_offset;
@ -378,13 +385,13 @@ namespace Kernel
continue; continue;
block_bitmap[byte] |= 1 << bit; block_bitmap[byte] |= 1 << bit;
write_block(bgd.block_bitmap, block_bitmap); TRY(write_block(bgd.block_bitmap, block_bitmap));
bgd.free_blocks_count--; bgd.free_blocks_count--;
write_block(bgd_location.block, bgd_buffer); TRY(write_block(bgd_location.block, bgd_buffer));
m_superblock.free_blocks_count--; m_superblock.free_blocks_count--;
sync_superblock(); TRY(sync_superblock());
return fs_block_index; return fs_block_index;
} }
@ -393,20 +400,20 @@ namespace Kernel
return 0; return 0;
}; };
if (auto ret = check_block_group(primary_bgd)) if (auto ret = TRY(check_block_group(primary_bgd)))
return ret; return ret;
uint32_t number_of_block_groups = BAN::Math::div_round_up(m_superblock.blocks_count, m_superblock.blocks_per_group); 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++) for (uint32_t block_group = 0; block_group < number_of_block_groups; block_group++)
if (block_group != primary_bgd) if (block_group != primary_bgd)
if (auto ret = check_block_group(block_group)) if (auto ret = TRY(check_block_group(block_group)))
return ret; return ret;
derrorln("Corrupted file system. Superblock indicates free blocks but none were found."); derrorln("Corrupted file system. Superblock indicates free blocks but none were found.");
return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted); return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted);
} }
void Ext2FS::release_block(uint32_t block) BAN::ErrorOr<void> Ext2FS::release_block(uint32_t block)
{ {
LockGuard _(m_mutex); LockGuard _(m_mutex);
@ -420,26 +427,28 @@ namespace Kernel
auto bitmap_buffer = get_block_buffer(); auto bitmap_buffer = get_block_buffer();
auto bgd_location = locate_block_group_descriptior(block_group); auto bgd_location = locate_block_group_descriptior(block_group);
read_block(bgd_location.block, bgd_buffer); TRY(read_block(bgd_location.block, bgd_buffer));
auto& bgd = bgd_buffer.span().slice(bgd_location.offset).as<Ext2::BlockGroupDescriptor>(); auto& bgd = bgd_buffer.span().slice(bgd_location.offset).as<Ext2::BlockGroupDescriptor>();
read_block(bgd.block_bitmap, bitmap_buffer); TRY(read_block(bgd.block_bitmap, bitmap_buffer));
const uint32_t byte = block_offset / 8; const uint32_t byte = block_offset / 8;
const uint32_t bit = block_offset % 8; const uint32_t bit = block_offset % 8;
ASSERT(bitmap_buffer[byte] & (1 << bit)); ASSERT(bitmap_buffer[byte] & (1 << bit));
bitmap_buffer[byte] &= ~(1 << bit); bitmap_buffer[byte] &= ~(1 << bit);
write_block(bgd.block_bitmap, bitmap_buffer); TRY(write_block(bgd.block_bitmap, bitmap_buffer));
bgd.free_blocks_count++; bgd.free_blocks_count++;
write_block(bgd_location.block, bgd_buffer); TRY(write_block(bgd_location.block, bgd_buffer));
m_superblock.free_blocks_count++; m_superblock.free_blocks_count++;
sync_superblock(); TRY(sync_superblock());
return {};
} }
Ext2FS::BlockLocation Ext2FS::locate_inode(uint32_t ino) BAN::ErrorOr<Ext2FS::BlockLocation> Ext2FS::locate_inode(uint32_t ino)
{ {
LockGuard _(m_mutex); LockGuard _(m_mutex);
@ -454,7 +463,7 @@ namespace Kernel
auto bgd_location = locate_block_group_descriptior(inode_group); auto bgd_location = locate_block_group_descriptior(inode_group);
read_block(bgd_location.block, bgd_buffer); TRY(read_block(bgd_location.block, bgd_buffer));
auto& bgd = *(Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset); 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)) if (fs.inode_cache().contains(inode_ino))
return fs.inode_cache()[inode_ino]; return fs.inode_cache()[inode_ino];
auto inode_location = fs.locate_inode(inode_ino); auto inode_location = TRY(fs.locate_inode(inode_ino));
auto block_buffer = fs.get_block_buffer(); auto block_buffer = fs.get_block_buffer();
fs.read_block(inode_location.block, block_buffer); TRY(fs.read_block(inode_location.block, block_buffer));
auto& inode = block_buffer.span().slice(inode_location.offset).as<Ext2::Inode>(); auto& inode = block_buffer.span().slice(inode_location.offset).as<Ext2::Inode>();
@ -41,18 +41,20 @@ namespace Kernel
Ext2Inode::~Ext2Inode() Ext2Inode::~Ext2Inode()
{ {
if (m_inode.links_count == 0) if (m_inode.links_count > 0)
cleanup_from_fs(); return;
if (auto ret = cleanup_from_fs(); ret.is_error())
dwarnln("Could not cleanup inode from FS: {}", ret.error());
} }
BAN::Optional<uint32_t> Ext2Inode::block_from_indirect_block(uint32_t block, uint32_t index, uint32_t depth) BAN::ErrorOr<BAN::Optional<uint32_t>> Ext2Inode::block_from_indirect_block(uint32_t block, uint32_t index, uint32_t depth)
{ {
if (block == 0) if (block == 0)
return {}; return BAN::Optional<uint32_t>();
ASSERT(depth >= 1); ASSERT(depth >= 1);
auto block_buffer = m_fs.get_block_buffer(); auto block_buffer = m_fs.get_block_buffer();
m_fs.read_block(block, block_buffer); TRY(m_fs.read_block(block, block_buffer));
const uint32_t indices_per_block = blksize() / sizeof(uint32_t); const uint32_t indices_per_block = blksize() / sizeof(uint32_t);
@ -60,22 +62,22 @@ namespace Kernel
const uint32_t next_block = block_buffer.span().as_span<uint32_t>()[(index / divisor) % indices_per_block]; const uint32_t next_block = block_buffer.span().as_span<uint32_t>()[(index / divisor) % indices_per_block];
if (next_block == 0) if (next_block == 0)
return {}; return BAN::Optional<uint32_t>();
if (depth == 1) if (depth == 1)
return next_block; return BAN::Optional<uint32_t>(next_block);
return block_from_indirect_block(next_block, index, depth - 1); return block_from_indirect_block(next_block, index, depth - 1);
} }
BAN::Optional<uint32_t> Ext2Inode::fs_block_of_data_block_index(uint32_t data_block_index) BAN::ErrorOr<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); const uint32_t indices_per_block = blksize() / sizeof(uint32_t);
if (data_block_index < 12) if (data_block_index < 12)
{ {
if (m_inode.block[data_block_index] == 0) if (m_inode.block[data_block_index] == 0)
return {}; return BAN::Optional<uint32_t>();
return m_inode.block[data_block_index]; return BAN::Optional<uint32_t>(m_inode.block[data_block_index]);
} }
data_block_index -= 12; data_block_index -= 12;
@ -129,9 +131,9 @@ namespace Kernel
for (uint32_t data_block_index = first_block; data_block_index < last_block; data_block_index++) for (uint32_t data_block_index = first_block; data_block_index < last_block; data_block_index++)
{ {
auto block_index = fs_block_of_data_block_index(data_block_index); auto block_index = TRY(fs_block_of_data_block_index(data_block_index));
if (block_index.has_value()) if (block_index.has_value())
m_fs.read_block(block_index.value(), block_buffer); TRY(m_fs.read_block(block_index.value(), block_buffer));
else else
memset(block_buffer.data(), 0x00, block_buffer.size()); memset(block_buffer.data(), 0x00, block_buffer.size());
@ -168,9 +170,9 @@ namespace Kernel
// Write partial block // Write partial block
if (offset % block_size) if (offset % block_size)
{ {
auto block_index = fs_block_of_data_block_index(offset / block_size); auto block_index = TRY(fs_block_of_data_block_index(offset / block_size));
if (block_index.has_value()) if (block_index.has_value())
m_fs.read_block(block_index.value(), block_buffer); TRY(m_fs.read_block(block_index.value(), block_buffer));
else else
{ {
block_index = TRY(allocate_new_block(offset / block_size));; block_index = TRY(allocate_new_block(offset / block_size));;
@ -181,7 +183,7 @@ namespace Kernel
uint32_t to_copy = BAN::Math::min<uint32_t>(block_size - block_offset, to_write); 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); memcpy(block_buffer.data() + block_offset, buffer.data(), to_copy);
m_fs.write_block(block_index.value(), block_buffer); TRY(m_fs.write_block(block_index.value(), block_buffer));
written += to_copy; written += to_copy;
offset += to_copy; offset += to_copy;
@ -190,12 +192,12 @@ namespace Kernel
while (to_write >= block_size) while (to_write >= block_size)
{ {
auto block_index = fs_block_of_data_block_index(offset / block_size); auto block_index = TRY(fs_block_of_data_block_index(offset / block_size));
if (!block_index.has_value()) if (!block_index.has_value())
block_index = TRY(allocate_new_block(offset / block_size)); block_index = TRY(allocate_new_block(offset / block_size));
memcpy(block_buffer.data(), buffer.data() + written, block_buffer.size()); memcpy(block_buffer.data(), buffer.data() + written, block_buffer.size());
m_fs.write_block(block_index.value(), block_buffer); TRY(m_fs.write_block(block_index.value(), block_buffer));
written += block_size; written += block_size;
offset += block_size; offset += block_size;
@ -204,9 +206,9 @@ namespace Kernel
if (to_write > 0) if (to_write > 0)
{ {
auto block_index = fs_block_of_data_block_index(offset / block_size); auto block_index = TRY(fs_block_of_data_block_index(offset / block_size));
if (block_index.has_value()) if (block_index.has_value())
m_fs.read_block(block_index.value(), block_buffer); TRY(m_fs.read_block(block_index.value(), block_buffer));
else else
{ {
block_index = TRY(allocate_new_block(offset / block_size)); block_index = TRY(allocate_new_block(offset / block_size));
@ -214,7 +216,7 @@ namespace Kernel
} }
memcpy(block_buffer.data(), buffer.data() + written, to_write); memcpy(block_buffer.data(), buffer.data() + written, to_write);
m_fs.write_block(block_index.value(), block_buffer); TRY(m_fs.write_block(block_index.value(), block_buffer));
} }
return buffer.size(); return buffer.size();
@ -227,8 +229,14 @@ namespace Kernel
// TODO: we should remove unused blocks on shrink // TODO: we should remove unused blocks on shrink
const auto old_size = m_inode.size;
m_inode.size = new_size; m_inode.size = new_size;
sync(); if (auto ret = sync(); ret.is_error())
{
m_inode.size = old_size;
return ret.release_error();
}
return {}; return {};
} }
@ -238,23 +246,31 @@ namespace Kernel
ASSERT((mode & Inode::Mode::TYPE_MASK) == 0); ASSERT((mode & Inode::Mode::TYPE_MASK) == 0);
if (m_inode.mode == mode) if (m_inode.mode == mode)
return {}; return {};
const auto old_mode = m_inode.mode;
m_inode.mode = (m_inode.mode & Inode::Mode::TYPE_MASK) | mode; m_inode.mode = (m_inode.mode & Inode::Mode::TYPE_MASK) | mode;
sync(); if (auto ret = sync(); ret.is_error())
{
m_inode.mode = old_mode;
return ret.release_error();
}
return {}; return {};
} }
void Ext2Inode::cleanup_indirect_block(uint32_t block, uint32_t depth) BAN::ErrorOr<void> Ext2Inode::cleanup_indirect_block(uint32_t block, uint32_t depth)
{ {
ASSERT(block); ASSERT(block);
if (depth == 0) if (depth == 0)
{ {
m_fs.release_block(block); TRY(m_fs.release_block(block));
return; return {};
} }
auto block_buffer = m_fs.get_block_buffer(); auto block_buffer = m_fs.get_block_buffer();
m_fs.read_block(block, block_buffer); TRY(m_fs.read_block(block, block_buffer));
const uint32_t ids_per_block = blksize() / sizeof(uint32_t); const uint32_t ids_per_block = blksize() / sizeof(uint32_t);
for (uint32_t i = 0; i < ids_per_block; i++) for (uint32_t i = 0; i < ids_per_block; i++)
@ -262,13 +278,14 @@ namespace Kernel
const uint32_t next_block = block_buffer.span().as_span<uint32_t>()[i]; const uint32_t next_block = block_buffer.span().as_span<uint32_t>()[i];
if (next_block == 0) if (next_block == 0)
continue; continue;
cleanup_indirect_block(next_block, depth - 1); TRY(cleanup_indirect_block(next_block, depth - 1));
} }
m_fs.release_block(block); TRY(m_fs.release_block(block));
return {};
} }
void Ext2Inode::cleanup_from_fs() BAN::ErrorOr<void> Ext2Inode::cleanup_from_fs()
{ {
ASSERT(m_inode.links_count == 0); ASSERT(m_inode.links_count == 0);
@ -278,15 +295,15 @@ namespace Kernel
// cleanup direct blocks // cleanup direct blocks
for (uint32_t i = 0; i < 12; i++) for (uint32_t i = 0; i < 12; i++)
if (m_inode.block[i]) if (m_inode.block[i])
m_fs.release_block(m_inode.block[i]); TRY(m_fs.release_block(m_inode.block[i]));
// cleanup indirect blocks // cleanup indirect blocks
if (m_inode.block[12]) if (m_inode.block[12])
cleanup_indirect_block(m_inode.block[12], 1); TRY(cleanup_indirect_block(m_inode.block[12], 1));
if (m_inode.block[13]) if (m_inode.block[13])
cleanup_indirect_block(m_inode.block[13], 2); TRY(cleanup_indirect_block(m_inode.block[13], 2));
if (m_inode.block[14]) if (m_inode.block[14])
cleanup_indirect_block(m_inode.block[14], 3); TRY(cleanup_indirect_block(m_inode.block[14], 3));
done: done:
// mark blocks as deleted // mark blocks as deleted
@ -294,9 +311,11 @@ done:
// FIXME: this is only required since fs does not get // FIXME: this is only required since fs does not get
// deleting inode from its cache // deleting inode from its cache
sync(); TRY(sync());
m_fs.delete_inode(ino()); TRY(m_fs.delete_inode(ino()));
return {};
} }
BAN::ErrorOr<size_t> Ext2Inode::list_next_inodes_impl(off_t offset, struct dirent* list, size_t list_size) BAN::ErrorOr<size_t> Ext2Inode::list_next_inodes_impl(off_t offset, struct dirent* list, size_t list_size)
@ -308,11 +327,11 @@ done:
return 0; return 0;
// FIXME: can we actually assume directories have all their blocks allocated // FIXME: can we actually assume directories have all their blocks allocated
const uint32_t block_index = fs_block_of_data_block_index(offset).value(); const uint32_t block_index = TRY(fs_block_of_data_block_index(offset)).value();
auto block_buffer = m_fs.get_block_buffer(); auto block_buffer = m_fs.get_block_buffer();
m_fs.read_block(block_index, block_buffer); TRY(m_fs.read_block(block_index, block_buffer));
// First determine if we have big enough list // First determine if we have big enough list
size_t entry_count = 0; size_t entry_count = 0;
@ -331,6 +350,9 @@ done:
return BAN::Error::from_errno(ENOBUFS); return BAN::Error::from_errno(ENOBUFS);
} }
if (entry_count == 0)
return BAN::Error::from_errno(ENODATA);
// Second fill the list // Second fill the list
{ {
dirent* dirp = list; dirent* dirp = list;
@ -410,7 +432,7 @@ done:
auto inode_or_error = Ext2Inode::create(m_fs, new_ino); auto inode_or_error = Ext2Inode::create(m_fs, new_ino);
if (inode_or_error.is_error()) if (inode_or_error.is_error())
{ {
m_fs.delete_inode(new_ino); TRY(m_fs.delete_inode(new_ino));
return inode_or_error.release_error(); return inode_or_error.release_error();
} }
@ -431,19 +453,21 @@ done:
auto inode_or_error = Ext2Inode::create(m_fs, new_ino); auto inode_or_error = Ext2Inode::create(m_fs, new_ino);
if (inode_or_error.is_error()) if (inode_or_error.is_error())
{ {
m_fs.delete_inode(new_ino); TRY(m_fs.delete_inode(new_ino));
return inode_or_error.release_error(); return inode_or_error.release_error();
} }
auto inode = inode_or_error.release_value(); auto inode = inode_or_error.release_value();
BAN::ScopeGuard cleanup([&] { inode->cleanup_from_fs(); });
TRY(inode->link_inode_to_directory(*inode, "."_sv)); // link . and ..
TRY(inode->link_inode_to_directory(*this, ".."_sv)); 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(link_inode_to_directory(*inode, name)); // link to parent
if (auto ret = link_inode_to_directory(*inode, name); ret.is_error())
cleanup.disable(); return ({ TRY(inode->cleanup_from_fs()); ret.release_error(); });
return {}; return {};
} }
@ -472,29 +496,32 @@ done:
auto block_buffer = m_fs.get_block_buffer(); auto block_buffer = m_fs.get_block_buffer();
auto write_inode = [&](uint32_t entry_offset, uint32_t entry_rec_len) auto write_inode =
{ [&](uint32_t entry_offset, uint32_t entry_rec_len) -> BAN::ErrorOr<void>
auto typed_mode = inode.mode(); {
uint8_t file_type = (m_fs.superblock().rev_level == Ext2::Enum::GOOD_OLD_REV) ? 0 auto typed_mode = inode.mode();
: typed_mode.ifreg() ? Ext2::Enum::REG_FILE uint8_t file_type = (m_fs.superblock().rev_level == Ext2::Enum::GOOD_OLD_REV) ? 0
: typed_mode.ifdir() ? Ext2::Enum::DIR : typed_mode.ifreg() ? Ext2::Enum::REG_FILE
: typed_mode.ifchr() ? Ext2::Enum::CHRDEV : typed_mode.ifdir() ? Ext2::Enum::DIR
: typed_mode.ifblk() ? Ext2::Enum::BLKDEV : typed_mode.ifchr() ? Ext2::Enum::CHRDEV
: typed_mode.ififo() ? Ext2::Enum::FIFO : typed_mode.ifblk() ? Ext2::Enum::BLKDEV
: typed_mode.ifsock() ? Ext2::Enum::SOCK : typed_mode.ififo() ? Ext2::Enum::FIFO
: typed_mode.iflnk() ? Ext2::Enum::SYMLINK : typed_mode.ifsock() ? Ext2::Enum::SOCK
: 0; : typed_mode.iflnk() ? Ext2::Enum::SYMLINK
: 0;
auto& new_entry = block_buffer.span().slice(entry_offset).as<Ext2::LinkedDirectoryEntry>(); auto& new_entry = block_buffer.span().slice(entry_offset).as<Ext2::LinkedDirectoryEntry>();
new_entry.inode = inode.ino(); new_entry.inode = inode.ino();
new_entry.rec_len = entry_rec_len; new_entry.rec_len = entry_rec_len;
new_entry.name_len = name.size(); new_entry.name_len = name.size();
new_entry.file_type = file_type; new_entry.file_type = file_type;
memcpy(new_entry.name, name.data(), name.size()); memcpy(new_entry.name, name.data(), name.size());
inode.m_inode.links_count++; inode.m_inode.links_count++;
inode.sync(); TRY(inode.sync());
};
return {};
};
uint32_t block_index = 0; uint32_t block_index = 0;
uint32_t entry_offset = 0; uint32_t entry_offset = 0;
@ -509,8 +536,8 @@ done:
goto needs_new_block; goto needs_new_block;
// Try to insert inode to last data block // Try to insert inode to last data block
block_index = fs_block_of_data_block_index(data_block_count - 1).value(); block_index = TRY(fs_block_of_data_block_index(data_block_count - 1)).value();
m_fs.read_block(block_index, block_buffer); TRY(m_fs.read_block(block_index, block_buffer));
while (entry_offset < block_size) while (entry_offset < block_size)
{ {
@ -522,8 +549,8 @@ done:
if (entry.inode == 0 && needed_entry_len <= entry.rec_len) if (entry.inode == 0 && needed_entry_len <= entry.rec_len)
{ {
write_inode(entry_offset, entry.rec_len); TRY(write_inode(entry_offset, entry.rec_len));
m_fs.write_block(block_index, block_buffer); TRY(m_fs.write_block(block_index, block_buffer));
return {}; return {};
} }
else if (needed_entry_len <= entry.rec_len - entry_min_rec_len) else if (needed_entry_len <= entry.rec_len - entry_min_rec_len)
@ -531,8 +558,8 @@ done:
uint32_t new_rec_len = entry.rec_len - entry_min_rec_len; uint32_t new_rec_len = entry.rec_len - entry_min_rec_len;
entry.rec_len = entry_min_rec_len; entry.rec_len = entry_min_rec_len;
write_inode(entry_offset + entry.rec_len, new_rec_len); TRY(write_inode(entry_offset + entry.rec_len, new_rec_len));
m_fs.write_block(block_index, block_buffer); TRY(m_fs.write_block(block_index, block_buffer));
return {}; return {};
} }
@ -544,8 +571,8 @@ needs_new_block:
m_inode.size += blksize(); m_inode.size += blksize();
memset(block_buffer.data(), 0x00, block_buffer.size()); memset(block_buffer.data(), 0x00, block_buffer.size());
write_inode(0, block_size); TRY(write_inode(0, block_size));
m_fs.write_block(block_index, block_buffer); TRY(m_fs.write_block(block_index, block_buffer));
return {}; return {};
} }
@ -560,8 +587,8 @@ needs_new_block:
for (uint32_t i = 0; i < max_used_data_block_count(); i++) for (uint32_t i = 0; i < max_used_data_block_count(); i++)
{ {
// FIXME: can we actually assume directories have all their blocks allocated // FIXME: can we actually assume directories have all their blocks allocated
const uint32_t block_index = fs_block_of_data_block_index(i).value(); const uint32_t block_index = TRY(fs_block_of_data_block_index(i)).value();
m_fs.read_block(block_index, block_buffer); TRY(m_fs.read_block(block_index, block_buffer));
blksize_t offset = 0; blksize_t offset = 0;
while (offset < blksize()) while (offset < blksize())
@ -596,8 +623,8 @@ needs_new_block:
for (uint32_t i = 0; i < max_used_data_block_count(); i++) for (uint32_t i = 0; i < max_used_data_block_count(); i++)
{ {
// FIXME: can we actually assume directories have all their blocks allocated // FIXME: can we actually assume directories have all their blocks allocated
const uint32_t block_index = fs_block_of_data_block_index(i).value(); const uint32_t block_index = TRY(fs_block_of_data_block_index(i)).value();
m_fs.read_block(block_index, block_buffer); TRY(m_fs.read_block(block_index, block_buffer));
bool modified = false; bool modified = false;
@ -613,13 +640,13 @@ needs_new_block:
if (entry_name == "."_sv) if (entry_name == "."_sv)
{ {
m_inode.links_count--; m_inode.links_count--;
sync(); TRY(sync());
} }
else if (entry_name == ".."_sv) else if (entry_name == ".."_sv)
{ {
auto parent = TRY(Ext2Inode::create(m_fs, entry.inode)); auto parent = TRY(Ext2Inode::create(m_fs, entry.inode));
parent->m_inode.links_count--; parent->m_inode.links_count--;
parent->sync(); TRY(parent->sync());
} }
else else
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
@ -632,7 +659,7 @@ needs_new_block:
} }
if (modified) if (modified)
m_fs.write_block(block_index, block_buffer); TRY(m_fs.write_block(block_index, block_buffer));
} }
return {}; return {};
@ -652,8 +679,8 @@ needs_new_block:
for (uint32_t i = 0; i < max_used_data_block_count(); i++) for (uint32_t i = 0; i < max_used_data_block_count(); i++)
{ {
// FIXME: can we actually assume directories have all their blocks allocated // FIXME: can we actually assume directories have all their blocks allocated
const uint32_t block_index = fs_block_of_data_block_index(i).value(); const uint32_t block_index = TRY(fs_block_of_data_block_index(i)).value();
m_fs.read_block(block_index, block_buffer); TRY(m_fs.read_block(block_index, block_buffer));
blksize_t offset = 0; blksize_t offset = 0;
while (offset < blksize()) while (offset < blksize())
@ -674,7 +701,7 @@ needs_new_block:
else else
inode->m_inode.links_count--; inode->m_inode.links_count--;
sync(); TRY(sync());
// NOTE: If this was the last link to inode we must // NOTE: If this was the last link to inode we must
// remove it from inode cache to trigger cleanup // remove it from inode cache to trigger cleanup
@ -687,7 +714,7 @@ needs_new_block:
// FIXME: This should expand the last inode if exists // FIXME: This should expand the last inode if exists
entry.inode = 0; entry.inode = 0;
m_fs.write_block(block_index, block_buffer); TRY(m_fs.write_block(block_index, block_buffer));
} }
offset += entry.rec_len; offset += entry.rec_len;
} }
@ -711,14 +738,14 @@ needs_new_block:
auto block_buffer = m_fs.get_block_buffer(); auto block_buffer = m_fs.get_block_buffer();
memset(block_buffer.data(), 0x00, block_buffer.size()); memset(block_buffer.data(), 0x00, block_buffer.size());
m_fs.write_block(block, block_buffer); TRY(m_fs.write_block(block, block_buffer));
} }
if (depth == 0) if (depth == 0)
return block; return block;
auto block_buffer = m_fs.get_block_buffer(); auto block_buffer = m_fs.get_block_buffer();
m_fs.read_block(block, block_buffer); TRY(m_fs.read_block(block, block_buffer));
uint32_t divisor = 1; uint32_t divisor = 1;
for (uint32_t i = 1; i < depth; i++) for (uint32_t i = 1; i < depth; i++)
@ -727,7 +754,9 @@ needs_new_block:
uint32_t& new_block = block_buffer.span().as_span<uint32_t>()[(index / divisor) % indices_per_fs_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)); uint32_t allocated_block = TRY(allocate_new_block_to_indirect_block(new_block, index, depth - 1));
m_fs.write_block(block, block_buffer); TRY(m_fs.write_block(block, block_buffer));
TRY(sync());
return allocated_block; return allocated_block;
} }
@ -737,13 +766,12 @@ needs_new_block:
const uint32_t inode_blocks_per_fs_block = blksize() / 512; const uint32_t inode_blocks_per_fs_block = blksize() / 512;
const uint32_t indices_per_fs_block = blksize() / sizeof(uint32_t); const uint32_t indices_per_fs_block = blksize() / sizeof(uint32_t);
BAN::ScopeGuard syncer([&] { sync(); });
if (data_block_index < 12) if (data_block_index < 12)
{ {
ASSERT(m_inode.block[data_block_index] == 0); ASSERT(m_inode.block[data_block_index] == 0);
m_inode.block[data_block_index] = TRY(m_fs.reserve_free_block(block_group())); m_inode.block[data_block_index] = TRY(m_fs.reserve_free_block(block_group()));
m_inode.blocks += inode_blocks_per_fs_block; m_inode.blocks += inode_blocks_per_fs_block;
TRY(sync());
return m_inode.block[data_block_index]; return m_inode.block[data_block_index];
} }
data_block_index -= 12; data_block_index -= 12;
@ -762,17 +790,19 @@ needs_new_block:
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
void Ext2Inode::sync() BAN::ErrorOr<void> Ext2Inode::sync()
{ {
auto inode_location = m_fs.locate_inode(ino()); auto inode_location = TRY(m_fs.locate_inode(ino()));
auto block_buffer = m_fs.get_block_buffer(); auto block_buffer = m_fs.get_block_buffer();
m_fs.read_block(inode_location.block, block_buffer); TRY(m_fs.read_block(inode_location.block, block_buffer));
if (memcmp(block_buffer.data() + inode_location.offset, &m_inode, sizeof(Ext2::Inode))) 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)); memcpy(block_buffer.data() + inode_location.offset, &m_inode, sizeof(Ext2::Inode));
m_fs.write_block(inode_location.block, block_buffer); TRY(m_fs.write_block(inode_location.block, block_buffer));
} }
return {};
} }
BAN::ErrorOr<BAN::RefPtr<Inode>> Ext2Inode::find_inode_impl(BAN::StringView file_name) BAN::ErrorOr<BAN::RefPtr<Inode>> Ext2Inode::find_inode_impl(BAN::StringView file_name)
@ -784,8 +814,8 @@ needs_new_block:
for (uint32_t i = 0; i < max_used_data_block_count(); i++) for (uint32_t i = 0; i < max_used_data_block_count(); i++)
{ {
// FIXME: can we actually assume directories have all their blocks allocated // FIXME: can we actually assume directories have all their blocks allocated
const uint32_t block_index = fs_block_of_data_block_index(i).value(); const uint32_t block_index = TRY(fs_block_of_data_block_index(i)).value();
m_fs.read_block(block_index, block_buffer); TRY(m_fs.read_block(block_index, block_buffer));
BAN::ConstByteSpan entry_span = block_buffer.span(); BAN::ConstByteSpan entry_span = block_buffer.span();
while (entry_span.size() >= sizeof(Ext2::LinkedDirectoryEntry)) while (entry_span.size() >= sizeof(Ext2::LinkedDirectoryEntry))

View File

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

View File

@ -327,7 +327,13 @@ namespace Kernel
auto& open_file = m_open_files[fd]; auto& open_file = m_open_files[fd];
if (!(open_file->flags & O_RDONLY)) if (!(open_file->flags & O_RDONLY))
return BAN::Error::from_errno(EACCES); return BAN::Error::from_errno(EACCES);
return TRY(open_file->inode()->list_next_inodes(open_file->offset++, list, list_len)); 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;
}
} }
BAN::ErrorOr<VirtualFileSystem::File> OpenFileDescriptorSet::file_of(int fd) const BAN::ErrorOr<VirtualFileSystem::File> OpenFileDescriptorSet::file_of(int fd) const

View File

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

View File

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

View File

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

View File

@ -1,7 +1,20 @@
#include <BAN/Assert.h> #include <BAN/Assert.h>
#include <errno.h>
#include <sys/resource.h> #include <sys/resource.h>
int getrusage(int, struct rusage*) int getrusage(int who, struct rusage* r_usage)
{ {
ASSERT_NOT_REACHED(); 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;
} }