Compare commits
11 Commits
4f4b8ada8c
...
1ec341e2dd
Author | SHA1 | Date |
---|---|---|
Bananymous | 1ec341e2dd | |
Bananymous | d09310f388 | |
Bananymous | 126edea119 | |
Bananymous | 74bfb930f2 | |
Bananymous | 091c5b6a66 | |
Bananymous | fda4a4ad24 | |
Bananymous | 8bb47aee02 | |
Bananymous | 1f794e4ac0 | |
Bananymous | e85f9ac6a1 | |
Bananymous | 6ee5576dcc | |
Bananymous | b890e2fc14 |
|
@ -87,9 +87,12 @@ namespace BAN
|
||||||
return *reinterpret_cast<S*>(m_data);
|
return *reinterpret_cast<S*>(m_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteSpanGeneral slice(size_type offset, size_type length)
|
ByteSpanGeneral slice(size_type offset, size_type length = size_type(-1))
|
||||||
{
|
{
|
||||||
ASSERT(m_data);
|
ASSERT(m_data);
|
||||||
|
ASSERT(m_size >= offset);
|
||||||
|
if (length == size_type(-1))
|
||||||
|
length = m_size - offset;
|
||||||
ASSERT(m_size >= offset + length);
|
ASSERT(m_size >= offset + length);
|
||||||
return ByteSpanGeneral(m_data + offset, length);
|
return ByteSpanGeneral(m_data + offset, length);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ add_subdirectory(LibELF)
|
||||||
add_subdirectory(userspace)
|
add_subdirectory(userspace)
|
||||||
|
|
||||||
add_custom_target(sysroot
|
add_custom_target(sysroot
|
||||||
COMMAND mkdir -p ${BANAN_SYSROOT}
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${BANAN_SYSROOT}
|
||||||
COMMAND cd ${BANAN_SYSROOT} && sudo tar xf ${BANAN_BASE_SYSROOT}
|
COMMAND cd ${BANAN_SYSROOT} && sudo tar xf ${BANAN_BASE_SYSROOT}
|
||||||
USES_TERMINAL
|
USES_TERMINAL
|
||||||
)
|
)
|
||||||
|
|
|
@ -58,7 +58,7 @@ 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&);
|
||||||
BAN::ErrorOr<void> delete_inode(uint32_t);
|
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&);
|
void read_block(uint32_t, BlockBufferWrapper&);
|
||||||
|
@ -68,8 +68,9 @@ namespace Kernel
|
||||||
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::HashMap<ino_t, BAN::RefPtr<Inode>>& inode_cache() { return m_inode_cache; }
|
BAN::HashMap<ino_t, BAN::RefPtr<Ext2Inode>>& inode_cache() { return m_inode_cache; }
|
||||||
|
|
||||||
const Ext2::Superblock& superblock() const { return m_superblock; }
|
const Ext2::Superblock& superblock() const { return m_superblock; }
|
||||||
|
|
||||||
|
@ -110,7 +111,7 @@ namespace Kernel
|
||||||
BAN::RefPtr<Inode> m_root_inode;
|
BAN::RefPtr<Inode> m_root_inode;
|
||||||
BAN::Vector<uint32_t> m_superblock_backups;
|
BAN::Vector<uint32_t> m_superblock_backups;
|
||||||
|
|
||||||
BAN::HashMap<ino_t, BAN::RefPtr<Inode>> m_inode_cache;
|
BAN::HashMap<ino_t, BAN::RefPtr<Ext2Inode>> m_inode_cache;
|
||||||
|
|
||||||
BlockBufferManager m_buffer_manager;
|
BlockBufferManager m_buffer_manager;
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,8 @@ namespace Kernel
|
||||||
class Ext2Inode final : public Inode
|
class Ext2Inode final : public Inode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
~Ext2Inode();
|
||||||
|
|
||||||
virtual ino_t ino() const override { return m_ino; };
|
virtual ino_t ino() const override { return m_ino; };
|
||||||
virtual Mode mode() const override { return { m_inode.mode }; }
|
virtual Mode mode() const override { return { m_inode.mode }; }
|
||||||
virtual nlink_t nlink() const override { return m_inode.links_count; }
|
virtual nlink_t nlink() const override { return m_inode.links_count; }
|
||||||
|
@ -31,6 +33,8 @@ namespace Kernel
|
||||||
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) override;
|
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) override;
|
||||||
virtual BAN::ErrorOr<void> list_next_inodes_impl(off_t, DirectoryEntryList*, size_t) override;
|
virtual BAN::ErrorOr<void> list_next_inodes_impl(off_t, DirectoryEntryList*, size_t) override;
|
||||||
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override;
|
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override;
|
||||||
|
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override;
|
||||||
|
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override;
|
||||||
|
|
||||||
virtual BAN::ErrorOr<BAN::String> link_target_impl() override;
|
virtual BAN::ErrorOr<BAN::String> link_target_impl() override;
|
||||||
|
|
||||||
|
@ -42,8 +46,14 @@ namespace Kernel
|
||||||
private:
|
private:
|
||||||
uint32_t fs_block_of_data_block_index(uint32_t data_block_index);
|
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_default_links();
|
||||||
|
void cleanup_from_fs();
|
||||||
|
|
||||||
BAN::ErrorOr<uint32_t> allocate_new_block();
|
BAN::ErrorOr<uint32_t> allocate_new_block();
|
||||||
BAN::ErrorOr<void> sync();
|
void sync();
|
||||||
|
|
||||||
uint32_t block_group() const;
|
uint32_t block_group() const;
|
||||||
|
|
||||||
|
@ -53,7 +63,7 @@ namespace Kernel
|
||||||
, m_inode(inode)
|
, m_inode(inode)
|
||||||
, m_ino(ino)
|
, m_ino(ino)
|
||||||
{}
|
{}
|
||||||
static BAN::ErrorOr<BAN::RefPtr<Inode>> create(Ext2FS&, uint32_t);
|
static BAN::ErrorOr<BAN::RefPtr<Ext2Inode>> create(Ext2FS&, uint32_t);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ext2FS& m_fs;
|
Ext2FS& m_fs;
|
||||||
|
|
|
@ -90,7 +90,8 @@ namespace Kernel
|
||||||
BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode(BAN::StringView);
|
BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode(BAN::StringView);
|
||||||
BAN::ErrorOr<void> list_next_inodes(off_t, DirectoryEntryList*, size_t);
|
BAN::ErrorOr<void> list_next_inodes(off_t, DirectoryEntryList*, size_t);
|
||||||
BAN::ErrorOr<void> create_file(BAN::StringView, mode_t, uid_t, gid_t);
|
BAN::ErrorOr<void> create_file(BAN::StringView, mode_t, uid_t, gid_t);
|
||||||
BAN::ErrorOr<void> delete_inode(BAN::StringView);
|
BAN::ErrorOr<void> create_directory(BAN::StringView, mode_t, uid_t, gid_t);
|
||||||
|
BAN::ErrorOr<void> unlink(BAN::StringView);
|
||||||
|
|
||||||
// Link API
|
// Link API
|
||||||
BAN::ErrorOr<BAN::String> link_target();
|
BAN::ErrorOr<BAN::String> link_target();
|
||||||
|
@ -107,7 +108,8 @@ namespace Kernel
|
||||||
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
|
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
|
||||||
virtual BAN::ErrorOr<void> list_next_inodes_impl(off_t, DirectoryEntryList*, size_t) { return BAN::Error::from_errno(ENOTSUP); }
|
virtual BAN::ErrorOr<void> list_next_inodes_impl(off_t, DirectoryEntryList*, size_t) { return BAN::Error::from_errno(ENOTSUP); }
|
||||||
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); }
|
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); }
|
||||||
virtual BAN::ErrorOr<void> delete_inode_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
|
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); }
|
||||||
|
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
|
||||||
|
|
||||||
// Link API
|
// Link API
|
||||||
virtual BAN::ErrorOr<BAN::String> link_target_impl() { return BAN::Error::from_errno(ENOTSUP); }
|
virtual BAN::ErrorOr<BAN::String> link_target_impl() { return BAN::Error::from_errno(ENOTSUP); }
|
||||||
|
|
|
@ -96,7 +96,8 @@ namespace Kernel
|
||||||
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) override;
|
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) override;
|
||||||
virtual BAN::ErrorOr<void> list_next_inodes_impl(off_t, DirectoryEntryList*, size_t) override;
|
virtual BAN::ErrorOr<void> list_next_inodes_impl(off_t, DirectoryEntryList*, size_t) override;
|
||||||
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override;
|
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override;
|
||||||
virtual BAN::ErrorOr<void> delete_inode_impl(BAN::StringView) override;
|
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override;
|
||||||
|
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr size_t m_name_max = NAME_MAX;
|
static constexpr size_t m_name_max = NAME_MAX;
|
||||||
|
|
|
@ -89,13 +89,16 @@ namespace Kernel
|
||||||
BAN::ErrorOr<long> sys_getegid() const { return m_credentials.egid(); }
|
BAN::ErrorOr<long> sys_getegid() const { return m_credentials.egid(); }
|
||||||
BAN::ErrorOr<long> sys_getpgid(pid_t);
|
BAN::ErrorOr<long> sys_getpgid(pid_t);
|
||||||
|
|
||||||
BAN::ErrorOr<void> create_file(BAN::StringView name, mode_t mode);
|
BAN::ErrorOr<void> create_file_or_dir(BAN::StringView name, mode_t mode);
|
||||||
BAN::ErrorOr<long> open_file(BAN::StringView path, int, mode_t = 0);
|
BAN::ErrorOr<long> open_file(BAN::StringView path, int, mode_t = 0);
|
||||||
BAN::ErrorOr<long> sys_open(const char* path, int, mode_t);
|
BAN::ErrorOr<long> sys_open(const char* path, int, mode_t);
|
||||||
BAN::ErrorOr<long> sys_openat(int, const char* path, int, mode_t);
|
BAN::ErrorOr<long> sys_openat(int, const char* path, int, mode_t);
|
||||||
BAN::ErrorOr<long> sys_close(int fd);
|
BAN::ErrorOr<long> sys_close(int fd);
|
||||||
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_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> sys_chmod(const char*, mode_t);
|
BAN::ErrorOr<long> sys_chmod(const char*, mode_t);
|
||||||
|
|
||||||
|
|
|
@ -184,6 +184,8 @@ namespace Kernel
|
||||||
write_block(bgd->inode_bitmap, inode_bitmap);
|
write_block(bgd->inode_bitmap, inode_bitmap);
|
||||||
|
|
||||||
bgd->free_inodes_count--;
|
bgd->free_inodes_count--;
|
||||||
|
if (Inode::Mode(ext2_inode.mode).ifdir())
|
||||||
|
bgd->used_dirs_count++;
|
||||||
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 uint32_t inode_table_offset = ino_index * superblock().inode_size;
|
||||||
|
@ -212,6 +214,55 @@ 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)
|
||||||
|
{
|
||||||
|
LockGuard _(m_lock);
|
||||||
|
|
||||||
|
ASSERT(ino >= superblock().first_ino);
|
||||||
|
ASSERT(ino <= superblock().inodes_count);
|
||||||
|
|
||||||
|
auto bgd_buffer = get_block_buffer();
|
||||||
|
auto bitmap_buffer = get_block_buffer();
|
||||||
|
auto inode_buffer = get_block_buffer();
|
||||||
|
|
||||||
|
const uint32_t inode_group = (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);
|
||||||
|
read_block(bgd_location.block, bgd_buffer);
|
||||||
|
auto& bgd = bgd_buffer.span().slice(bgd_location.offset).as<Ext2::BlockGroupDescriptor>();
|
||||||
|
|
||||||
|
// update inode bitmap
|
||||||
|
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);
|
||||||
|
write_block(bgd.inode_bitmap, bitmap_buffer);
|
||||||
|
|
||||||
|
// memset inode to zero or fsck will complain
|
||||||
|
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>();
|
||||||
|
bool is_directory = Inode::Mode(inode.mode).ifdir();
|
||||||
|
memset(&inode, 0x00, m_superblock.inode_size);
|
||||||
|
write_block(inode_location.block, inode_buffer);
|
||||||
|
|
||||||
|
// update bgd counts
|
||||||
|
bgd.free_inodes_count++;
|
||||||
|
if (is_directory)
|
||||||
|
bgd.used_dirs_count--;
|
||||||
|
write_block(bgd_location.block, bgd_buffer);
|
||||||
|
|
||||||
|
// update superblock inode count
|
||||||
|
m_superblock.free_inodes_count++;
|
||||||
|
sync_superblock();
|
||||||
|
|
||||||
|
// remove inode from cache
|
||||||
|
if (m_inode_cache.contains(ino))
|
||||||
|
m_inode_cache.remove(ino);
|
||||||
|
}
|
||||||
|
|
||||||
void Ext2FS::read_block(uint32_t block, BlockBufferWrapper& buffer)
|
void Ext2FS::read_block(uint32_t block, BlockBufferWrapper& buffer)
|
||||||
{
|
{
|
||||||
LockGuard _(m_lock);
|
LockGuard _(m_lock);
|
||||||
|
@ -255,8 +306,7 @@ namespace Kernel
|
||||||
const uint32_t lba = 1024 / sector_size;
|
const uint32_t lba = 1024 / sector_size;
|
||||||
const uint32_t sector_count = BAN::Math::div_round_up<uint32_t>(superblock_bytes, sector_size);
|
const uint32_t sector_count = BAN::Math::div_round_up<uint32_t>(superblock_bytes, sector_size);
|
||||||
|
|
||||||
BAN::Vector<uint8_t> superblock_buffer;
|
auto superblock_buffer = get_block_buffer();
|
||||||
MUST(superblock_buffer.resize(sector_count * sector_size));
|
|
||||||
|
|
||||||
MUST(m_partition.read_sectors(lba, sector_count, superblock_buffer.span()));
|
MUST(m_partition.read_sectors(lba, sector_count, superblock_buffer.span()));
|
||||||
if (memcmp(superblock_buffer.data(), &m_superblock, superblock_bytes))
|
if (memcmp(superblock_buffer.data(), &m_superblock, superblock_bytes))
|
||||||
|
@ -266,7 +316,6 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Ext2FS::BlockBufferWrapper Ext2FS::get_block_buffer()
|
Ext2FS::BlockBufferWrapper Ext2FS::get_block_buffer()
|
||||||
{
|
{
|
||||||
LockGuard _(m_lock);
|
LockGuard _(m_lock);
|
||||||
|
@ -334,6 +383,39 @@ namespace Kernel
|
||||||
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)
|
||||||
|
{
|
||||||
|
LockGuard _(m_lock);
|
||||||
|
|
||||||
|
ASSERT(block >= m_superblock.first_data_block);
|
||||||
|
ASSERT(block < m_superblock.blocks_count);
|
||||||
|
|
||||||
|
const uint32_t block_group = (block - m_superblock.first_data_block) / m_superblock.blocks_per_group;
|
||||||
|
const uint32_t block_offset = (block - m_superblock.first_data_block) % m_superblock.blocks_per_group;
|
||||||
|
|
||||||
|
auto bgd_buffer = get_block_buffer();
|
||||||
|
auto bitmap_buffer = get_block_buffer();
|
||||||
|
|
||||||
|
auto bgd_location = locate_block_group_descriptior(block_group);
|
||||||
|
read_block(bgd_location.block, bgd_buffer);
|
||||||
|
|
||||||
|
auto& bgd = bgd_buffer.span().slice(bgd_location.offset).as<Ext2::BlockGroupDescriptor>();
|
||||||
|
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);
|
||||||
|
write_block(bgd.block_bitmap, bitmap_buffer);
|
||||||
|
|
||||||
|
bgd.free_blocks_count++;
|
||||||
|
write_block(bgd_location.block, bgd_buffer);
|
||||||
|
|
||||||
|
m_superblock.free_blocks_count++;
|
||||||
|
sync_superblock();
|
||||||
|
}
|
||||||
|
|
||||||
Ext2FS::BlockLocation Ext2FS::locate_inode(uint32_t ino)
|
Ext2FS::BlockLocation Ext2FS::locate_inode(uint32_t ino)
|
||||||
{
|
{
|
||||||
LockGuard _(m_lock);
|
LockGuard _(m_lock);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <BAN/Function.h>
|
#include <BAN/Function.h>
|
||||||
|
#include <BAN/ScopeGuard.h>
|
||||||
#include <kernel/FS/Ext2/FileSystem.h>
|
#include <kernel/FS/Ext2/FileSystem.h>
|
||||||
#include <kernel/FS/Ext2/Inode.h>
|
#include <kernel/FS/Ext2/Inode.h>
|
||||||
#include <kernel/Timer/Timer.h>
|
#include <kernel/Timer/Timer.h>
|
||||||
|
@ -21,7 +22,7 @@ namespace Kernel
|
||||||
return (m_ino - 1) / m_fs.superblock().blocks_per_group;
|
return (m_ino - 1) / m_fs.superblock().blocks_per_group;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::RefPtr<Inode>> Ext2Inode::create(Ext2FS& fs, uint32_t inode_ino)
|
BAN::ErrorOr<BAN::RefPtr<Ext2Inode>> Ext2Inode::create(Ext2FS& fs, uint32_t inode_ino)
|
||||||
{
|
{
|
||||||
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];
|
||||||
|
@ -36,11 +37,17 @@ namespace Kernel
|
||||||
Ext2Inode* result_ptr = new Ext2Inode(fs, inode, inode_ino);
|
Ext2Inode* result_ptr = new Ext2Inode(fs, inode, inode_ino);
|
||||||
if (result_ptr == nullptr)
|
if (result_ptr == nullptr)
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
auto result = BAN::RefPtr<Inode>::adopt(result_ptr);
|
auto result = BAN::RefPtr<Ext2Inode>::adopt(result_ptr);
|
||||||
TRY(fs.inode_cache().insert(inode_ino, result));
|
TRY(fs.inode_cache().insert(inode_ino, result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ext2Inode::~Ext2Inode()
|
||||||
|
{
|
||||||
|
if (m_inode.links_count == 0)
|
||||||
|
cleanup_from_fs();
|
||||||
|
}
|
||||||
|
|
||||||
#define VERIFY_AND_READ_BLOCK(expr) do { const uint32_t block_index = expr; ASSERT(block_index); m_fs.read_block(block_index, block_buffer); } while (false)
|
#define VERIFY_AND_READ_BLOCK(expr) do { const uint32_t block_index = expr; ASSERT(block_index); m_fs.read_block(block_index, block_buffer); } while (false)
|
||||||
#define VERIFY_AND_RETURN(expr) ({ const uint32_t result = expr; ASSERT(result); return result; })
|
#define VERIFY_AND_RETURN(expr) ({ const uint32_t result = expr; ASSERT(result); return result; })
|
||||||
|
|
||||||
|
@ -214,7 +221,7 @@ namespace Kernel
|
||||||
if (new_size < m_inode.size)
|
if (new_size < m_inode.size)
|
||||||
{
|
{
|
||||||
m_inode.size = new_size;
|
m_inode.size = new_size;
|
||||||
TRY(sync());
|
sync();
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,7 +244,7 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
|
|
||||||
m_inode.size = new_size;
|
m_inode.size = new_size;
|
||||||
TRY(sync());
|
sync();
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -248,10 +255,18 @@ namespace Kernel
|
||||||
if (m_inode.mode == mode)
|
if (m_inode.mode == mode)
|
||||||
return {};
|
return {};
|
||||||
m_inode.mode = (m_inode.mode & Inode::Mode::TYPE_MASK) | mode;
|
m_inode.mode = (m_inode.mode & Inode::Mode::TYPE_MASK) | mode;
|
||||||
TRY(sync());
|
sync();
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Ext2Inode::cleanup_from_fs()
|
||||||
|
{
|
||||||
|
ASSERT(m_inode.links_count == 0);
|
||||||
|
for (uint32_t i = 0; i < blocks(); i++)
|
||||||
|
m_fs.release_block(fs_block_of_data_block_index(i));
|
||||||
|
m_fs.delete_inode(ino());
|
||||||
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> Ext2Inode::list_next_inodes_impl(off_t offset, DirectoryEntryList* list, size_t list_size)
|
BAN::ErrorOr<void> Ext2Inode::list_next_inodes_impl(off_t offset, DirectoryEntryList* list, size_t list_size)
|
||||||
{
|
{
|
||||||
ASSERT(mode().ifdir());
|
ASSERT(mode().ifdir());
|
||||||
|
@ -317,7 +332,100 @@ namespace Kernel
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool mode_has_valid_type(mode_t mode)
|
||||||
|
{
|
||||||
|
switch (mode & Inode::Mode::TYPE_MASK)
|
||||||
|
{
|
||||||
|
case Inode::Mode::IFIFO: return true;
|
||||||
|
case Inode::Mode::IFCHR: return true;
|
||||||
|
case Inode::Mode::IFDIR: return true;
|
||||||
|
case Inode::Mode::IFBLK: return true;
|
||||||
|
case Inode::Mode::IFREG: return true;
|
||||||
|
case Inode::Mode::IFLNK: return true;
|
||||||
|
case Inode::Mode::IFSOCK: return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Ext2::Inode initialize_new_inode_info(mode_t mode, uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
|
ASSERT(mode_has_valid_type(mode));
|
||||||
|
|
||||||
|
timespec current_time = SystemTimer::get().real_time();
|
||||||
|
return Ext2::Inode
|
||||||
|
{
|
||||||
|
.mode = (uint16_t)mode,
|
||||||
|
.uid = (uint16_t)uid,
|
||||||
|
.size = 0,
|
||||||
|
.atime = (uint32_t)current_time.tv_sec,
|
||||||
|
.ctime = (uint32_t)current_time.tv_sec,
|
||||||
|
.mtime = (uint32_t)current_time.tv_sec,
|
||||||
|
.dtime = 0,
|
||||||
|
.gid = (uint16_t)gid,
|
||||||
|
.links_count = 0,
|
||||||
|
.blocks = 0,
|
||||||
|
.flags = 0,
|
||||||
|
.osd1 = 0,
|
||||||
|
.block = {},
|
||||||
|
.generation = 0,
|
||||||
|
.file_acl = 0,
|
||||||
|
.dir_acl = 0,
|
||||||
|
.faddr = 0,
|
||||||
|
.osd2 = {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> Ext2Inode::create_file_impl(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid)
|
BAN::ErrorOr<void> Ext2Inode::create_file_impl(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
|
ASSERT(this->mode().ifdir());
|
||||||
|
|
||||||
|
if (!(Mode(mode).ifreg()))
|
||||||
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
|
|
||||||
|
const uint32_t new_ino = TRY(m_fs.create_inode(initialize_new_inode_info(mode, uid, gid)));
|
||||||
|
|
||||||
|
auto inode_or_error = Ext2Inode::create(m_fs, new_ino);
|
||||||
|
if (inode_or_error.is_error())
|
||||||
|
{
|
||||||
|
m_fs.delete_inode(new_ino);
|
||||||
|
return inode_or_error.release_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto inode = inode_or_error.release_value();
|
||||||
|
|
||||||
|
TRY(link_inode_to_directory(*inode, name));
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> Ext2Inode::create_directory_impl(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
|
ASSERT(this->mode().ifdir());
|
||||||
|
ASSERT(Mode(mode).ifdir());
|
||||||
|
|
||||||
|
const uint32_t new_ino = TRY(m_fs.create_inode(initialize_new_inode_info(mode, uid, gid)));
|
||||||
|
|
||||||
|
auto inode_or_error = Ext2Inode::create(m_fs, new_ino);
|
||||||
|
if (inode_or_error.is_error())
|
||||||
|
{
|
||||||
|
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(); });
|
||||||
|
|
||||||
|
TRY(inode->link_inode_to_directory(*inode, "."sv));
|
||||||
|
TRY(inode->link_inode_to_directory(*this, ".."sv));
|
||||||
|
|
||||||
|
TRY(link_inode_to_directory(*inode, name));
|
||||||
|
|
||||||
|
cleanup.disable();
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> Ext2Inode::link_inode_to_directory(Ext2Inode& inode, BAN::StringView name)
|
||||||
{
|
{
|
||||||
if (!this->mode().ifdir())
|
if (!this->mode().ifdir())
|
||||||
return BAN::Error::from_errno(ENOTDIR);
|
return BAN::Error::from_errno(ENOTDIR);
|
||||||
|
@ -325,9 +433,6 @@ namespace Kernel
|
||||||
if (name.size() > 255)
|
if (name.size() > 255)
|
||||||
return BAN::Error::from_errno(ENAMETOOLONG);
|
return BAN::Error::from_errno(ENAMETOOLONG);
|
||||||
|
|
||||||
if (!(Mode(mode).ifreg()))
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
|
|
||||||
if (m_inode.flags & Ext2::Enum::INDEX_FL)
|
if (m_inode.flags & Ext2::Enum::INDEX_FL)
|
||||||
{
|
{
|
||||||
dwarnln("file creation to indexed directory not supported");
|
dwarnln("file creation to indexed directory not supported");
|
||||||
|
@ -340,39 +445,13 @@ namespace Kernel
|
||||||
if (error_or.error().get_error_code() != ENOENT)
|
if (error_or.error().get_error_code() != ENOENT)
|
||||||
return error_or.error();
|
return error_or.error();
|
||||||
|
|
||||||
timespec current_time = SystemTimer::get().real_time();
|
|
||||||
|
|
||||||
Ext2::Inode ext2_inode
|
|
||||||
{
|
|
||||||
.mode = (uint16_t)mode,
|
|
||||||
.uid = (uint16_t)uid,
|
|
||||||
.size = 0,
|
|
||||||
.atime = (uint32_t)current_time.tv_sec,
|
|
||||||
.ctime = (uint32_t)current_time.tv_sec,
|
|
||||||
.mtime = (uint32_t)current_time.tv_sec,
|
|
||||||
.dtime = 0,
|
|
||||||
.gid = (uint16_t)gid,
|
|
||||||
.links_count = 1,
|
|
||||||
.blocks = 0,
|
|
||||||
.flags = 0,
|
|
||||||
.osd1 = 0,
|
|
||||||
.block = {},
|
|
||||||
.generation = 0,
|
|
||||||
.file_acl = 0,
|
|
||||||
.dir_acl = 0,
|
|
||||||
.faddr = 0,
|
|
||||||
.osd2 = {}
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint32_t inode_index = TRY(m_fs.create_inode(ext2_inode));
|
|
||||||
|
|
||||||
const uint32_t block_size = m_fs.block_size();
|
const uint32_t block_size = m_fs.block_size();
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
auto typed_mode = Mode(mode);
|
auto typed_mode = inode.mode();
|
||||||
uint8_t file_type = (m_fs.superblock().rev_level == Ext2::Enum::GOOD_OLD_REV) ? 0
|
uint8_t file_type = (m_fs.superblock().rev_level == Ext2::Enum::GOOD_OLD_REV) ? 0
|
||||||
: typed_mode.ifreg() ? Ext2::Enum::REG_FILE
|
: typed_mode.ifreg() ? Ext2::Enum::REG_FILE
|
||||||
: typed_mode.ifdir() ? Ext2::Enum::DIR
|
: typed_mode.ifdir() ? Ext2::Enum::DIR
|
||||||
|
@ -384,11 +463,14 @@ namespace Kernel
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
auto& new_entry = *(Ext2::LinkedDirectoryEntry*)(block_buffer.data() + entry_offset);
|
auto& new_entry = *(Ext2::LinkedDirectoryEntry*)(block_buffer.data() + entry_offset);
|
||||||
new_entry.inode = inode_index;
|
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.sync();
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t block_index = 0;
|
uint32_t block_index = 0;
|
||||||
|
@ -443,6 +525,149 @@ needs_new_block:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<bool> Ext2Inode::is_directory_empty()
|
||||||
|
{
|
||||||
|
ASSERT(mode().ifdir());
|
||||||
|
if (m_inode.flags & Ext2::Enum::INDEX_FL)
|
||||||
|
{
|
||||||
|
dwarnln("deletion of indexed directory is not supported");
|
||||||
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto block_buffer = m_fs.get_block_buffer();
|
||||||
|
|
||||||
|
// Confirm that this doesn't contain anything else than '.' or '..'
|
||||||
|
for (uint32_t i = 0; i < blocks(); i++)
|
||||||
|
{
|
||||||
|
const uint32_t block = fs_block_of_data_block_index(i);
|
||||||
|
m_fs.read_block(block, block_buffer);
|
||||||
|
|
||||||
|
blksize_t offset = 0;
|
||||||
|
while (offset < blksize())
|
||||||
|
{
|
||||||
|
auto& entry = block_buffer.span().slice(offset).as<Ext2::LinkedDirectoryEntry>();
|
||||||
|
|
||||||
|
if (entry.inode)
|
||||||
|
{
|
||||||
|
BAN::StringView entry_name(entry.name, entry.name_len);
|
||||||
|
if (entry_name != "."sv && entry_name != ".."sv)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += entry.rec_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> Ext2Inode::cleanup_default_links()
|
||||||
|
{
|
||||||
|
ASSERT(mode().ifdir());
|
||||||
|
|
||||||
|
auto block_buffer = m_fs.get_block_buffer();
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < blocks(); i++)
|
||||||
|
{
|
||||||
|
const uint32_t block = fs_block_of_data_block_index(i);
|
||||||
|
m_fs.read_block(block, block_buffer);
|
||||||
|
|
||||||
|
bool modified = false;
|
||||||
|
|
||||||
|
blksize_t offset = 0;
|
||||||
|
while (offset < blksize())
|
||||||
|
{
|
||||||
|
auto& entry = block_buffer.span().slice(offset).as<Ext2::LinkedDirectoryEntry>();
|
||||||
|
|
||||||
|
if (entry.inode)
|
||||||
|
{
|
||||||
|
BAN::StringView entry_name(entry.name, entry.name_len);
|
||||||
|
|
||||||
|
if (entry_name == "."sv)
|
||||||
|
{
|
||||||
|
m_inode.links_count--;
|
||||||
|
sync();
|
||||||
|
}
|
||||||
|
else if (entry_name == ".."sv)
|
||||||
|
{
|
||||||
|
auto parent = TRY(Ext2Inode::create(m_fs, entry.inode));
|
||||||
|
parent->m_inode.links_count--;
|
||||||
|
parent->sync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
|
||||||
|
modified = true;
|
||||||
|
entry.inode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += entry.rec_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modified)
|
||||||
|
m_fs.write_block(block, block_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> Ext2Inode::unlink_impl(BAN::StringView name)
|
||||||
|
{
|
||||||
|
ASSERT(mode().ifdir());
|
||||||
|
if (m_inode.flags & Ext2::Enum::INDEX_FL)
|
||||||
|
{
|
||||||
|
dwarnln("deletion from indexed directory is not supported");
|
||||||
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto block_buffer = m_fs.get_block_buffer();
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < blocks(); i++)
|
||||||
|
{
|
||||||
|
const uint32_t block = fs_block_of_data_block_index(i);
|
||||||
|
m_fs.read_block(block, block_buffer);
|
||||||
|
|
||||||
|
blksize_t offset = 0;
|
||||||
|
while (offset < blksize())
|
||||||
|
{
|
||||||
|
auto& entry = block_buffer.span().slice(offset).as<Ext2::LinkedDirectoryEntry>();
|
||||||
|
if (entry.inode && name == BAN::StringView(entry.name, entry.name_len))
|
||||||
|
{
|
||||||
|
auto inode = TRY(Ext2Inode::create(m_fs, entry.inode));
|
||||||
|
if (inode->mode().ifdir())
|
||||||
|
{
|
||||||
|
if (!TRY(inode->is_directory_empty()))
|
||||||
|
return BAN::Error::from_errno(ENOTEMPTY);
|
||||||
|
TRY(inode->cleanup_default_links());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inode->nlink() == 0)
|
||||||
|
dprintln("Corrupted filesystem. Deleting inode with 0 links");
|
||||||
|
else
|
||||||
|
inode->m_inode.links_count--;
|
||||||
|
|
||||||
|
sync();
|
||||||
|
|
||||||
|
// NOTE: If this was the last link to inode we must
|
||||||
|
// remove it from inode cache to trigger cleanup
|
||||||
|
if (inode->nlink() == 0)
|
||||||
|
{
|
||||||
|
auto& cache = m_fs.inode_cache();
|
||||||
|
if (cache.contains(inode->ino()))
|
||||||
|
cache.remove(inode->ino());
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: This should expand the last inode if exists
|
||||||
|
entry.inode = 0;
|
||||||
|
m_fs.write_block(block, block_buffer);
|
||||||
|
}
|
||||||
|
offset += entry.rec_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
#define READ_OR_ALLOCATE_BASE_BLOCK(index_) \
|
#define READ_OR_ALLOCATE_BASE_BLOCK(index_) \
|
||||||
do { \
|
do { \
|
||||||
if (m_inode.block[index_] != 0) \
|
if (m_inode.block[index_] != 0) \
|
||||||
|
@ -496,7 +721,7 @@ needs_new_block:
|
||||||
{
|
{
|
||||||
if (mode().ifdir())
|
if (mode().ifdir())
|
||||||
m_inode.size += blksize();
|
m_inode.size += blksize();
|
||||||
MUST(sync());
|
sync();
|
||||||
};
|
};
|
||||||
|
|
||||||
// direct block
|
// direct block
|
||||||
|
@ -552,7 +777,7 @@ needs_new_block:
|
||||||
#undef READ_OR_ALLOCATE_INDIRECT_BLOCK
|
#undef READ_OR_ALLOCATE_INDIRECT_BLOCK
|
||||||
#undef WRITE_BLOCK_AND_RETURN
|
#undef WRITE_BLOCK_AND_RETURN
|
||||||
|
|
||||||
BAN::ErrorOr<void> Ext2Inode::sync()
|
void Ext2Inode::sync()
|
||||||
{
|
{
|
||||||
auto inode_location = m_fs.locate_inode(ino());
|
auto inode_location = m_fs.locate_inode(ino());
|
||||||
auto block_buffer = m_fs.get_block_buffer();
|
auto block_buffer = m_fs.get_block_buffer();
|
||||||
|
@ -563,8 +788,6 @@ needs_new_block:
|
||||||
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);
|
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)
|
||||||
|
@ -589,7 +812,7 @@ needs_new_block:
|
||||||
const auto& entry = *(const Ext2::LinkedDirectoryEntry*)entry_addr;
|
const auto& entry = *(const Ext2::LinkedDirectoryEntry*)entry_addr;
|
||||||
BAN::StringView entry_name(entry.name, entry.name_len);
|
BAN::StringView entry_name(entry.name, entry.name_len);
|
||||||
if (entry.inode && entry_name == file_name)
|
if (entry.inode && entry_name == file_name)
|
||||||
return TRY(Ext2Inode::create(m_fs, entry.inode));
|
return BAN::RefPtr<Inode>(TRY(Ext2Inode::create(m_fs, entry.inode)));
|
||||||
entry_addr += entry.rec_len;
|
entry_addr += entry.rec_len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,16 +81,31 @@ namespace Kernel
|
||||||
Thread::TerminateBlocker blocker(Thread::current());
|
Thread::TerminateBlocker blocker(Thread::current());
|
||||||
if (!this->mode().ifdir())
|
if (!this->mode().ifdir())
|
||||||
return BAN::Error::from_errno(ENOTDIR);
|
return BAN::Error::from_errno(ENOTDIR);
|
||||||
|
if (Mode(mode).ifdir())
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
return create_file_impl(name, mode, uid, gid);
|
return create_file_impl(name, mode, uid, gid);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> Inode::delete_inode(BAN::StringView name)
|
BAN::ErrorOr<void> Inode::create_directory(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
|
LockGuard _(m_lock);
|
||||||
|
Thread::TerminateBlocker blocker(Thread::current());
|
||||||
|
if (!this->mode().ifdir())
|
||||||
|
return BAN::Error::from_errno(ENOTDIR);
|
||||||
|
if (!Mode(mode).ifdir())
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
return create_directory_impl(name, mode, uid, gid);
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> Inode::unlink(BAN::StringView name)
|
||||||
{
|
{
|
||||||
LockGuard _(m_lock);
|
LockGuard _(m_lock);
|
||||||
Thread::TerminateBlocker blocker(Thread::current());
|
Thread::TerminateBlocker blocker(Thread::current());
|
||||||
if (!mode().ifdir())
|
if (!mode().ifdir())
|
||||||
return BAN::Error::from_errno(ENOTDIR);
|
return BAN::Error::from_errno(ENOTDIR);
|
||||||
return delete_inode_impl(name);
|
if (name == "."sv || name == ".."sv)
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
return unlink_impl(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::String> Inode::link_target()
|
BAN::ErrorOr<BAN::String> Inode::link_target()
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace Kernel
|
||||||
void ProcFileSystem::on_process_delete(Process& process)
|
void ProcFileSystem::on_process_delete(Process& process)
|
||||||
{
|
{
|
||||||
auto path = BAN::String::formatted("{}", process.pid());
|
auto path = BAN::String::formatted("{}", process.pid());
|
||||||
MUST(m_root_inode->delete_inode(path));
|
MUST(m_root_inode->unlink(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,16 +202,23 @@ namespace Kernel
|
||||||
BAN::RefPtr<RamInode> inode;
|
BAN::RefPtr<RamInode> inode;
|
||||||
if (Mode(mode).ifreg())
|
if (Mode(mode).ifreg())
|
||||||
inode = TRY(RamFileInode::create(m_fs, mode & ~Inode::Mode::TYPE_MASK, uid, gid));
|
inode = TRY(RamFileInode::create(m_fs, mode & ~Inode::Mode::TYPE_MASK, uid, gid));
|
||||||
else if (Mode(mode).ifdir())
|
|
||||||
inode = TRY(RamDirectoryInode::create(m_fs, ino(), mode & ~Inode::Mode::TYPE_MASK, uid, gid));
|
|
||||||
else
|
else
|
||||||
ASSERT_NOT_REACHED();
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
|
|
||||||
TRY(add_inode(name, inode));
|
TRY(add_inode(name, inode));
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> RamDirectoryInode::create_directory_impl(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
|
if (!Mode(mode).ifdir())
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
auto inode = TRY(RamDirectoryInode::create(m_fs, ino(), mode & ~Inode::Mode::TYPE_MASK, uid, gid));
|
||||||
|
TRY(add_inode(name, inode));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t get_type(Inode::Mode mode)
|
static uint8_t get_type(Inode::Mode mode)
|
||||||
{
|
{
|
||||||
if (mode.ifreg())
|
if (mode.ifreg())
|
||||||
|
@ -256,8 +263,9 @@ namespace Kernel
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> RamDirectoryInode::delete_inode_impl(BAN::StringView name)
|
BAN::ErrorOr<void> RamDirectoryInode::unlink_impl(BAN::StringView name)
|
||||||
{
|
{
|
||||||
|
// FIXME: delete inodes contents only after they are closed
|
||||||
for (size_t i = 0; i < m_entries.size(); i++)
|
for (size_t i = 0; i < m_entries.size(); i++)
|
||||||
{
|
{
|
||||||
if (name == m_entries[i].name)
|
if (name == m_entries[i].name)
|
||||||
|
|
|
@ -611,8 +611,17 @@ namespace Kernel
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> Process::create_file(BAN::StringView path, mode_t mode)
|
BAN::ErrorOr<void> Process::create_file_or_dir(BAN::StringView path, mode_t mode)
|
||||||
{
|
{
|
||||||
|
switch (mode & Inode::Mode::TYPE_MASK)
|
||||||
|
{
|
||||||
|
case Inode::Mode::IFREG: break;
|
||||||
|
case Inode::Mode::IFDIR: break;
|
||||||
|
case Inode::Mode::IFIFO: break;
|
||||||
|
default:
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
LockGuard _(m_lock);
|
LockGuard _(m_lock);
|
||||||
|
|
||||||
auto absolute_path = TRY(absolute_path_of(path));
|
auto absolute_path = TRY(absolute_path_of(path));
|
||||||
|
@ -625,8 +634,12 @@ namespace Kernel
|
||||||
auto directory = absolute_path.sv().substring(0, index);
|
auto directory = absolute_path.sv().substring(0, index);
|
||||||
auto file_name = absolute_path.sv().substring(index);
|
auto file_name = absolute_path.sv().substring(index);
|
||||||
|
|
||||||
auto parent_inode = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, directory, O_WRONLY)).inode;
|
auto parent_inode = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, directory, O_EXEC | O_WRONLY)).inode;
|
||||||
TRY(parent_inode->create_file(file_name, S_IFREG | (mode & 0777), m_credentials.euid(), m_credentials.egid()));
|
|
||||||
|
if (Inode::Mode(mode).ifdir())
|
||||||
|
TRY(parent_inode->create_directory(file_name, mode, m_credentials.euid(), m_credentials.egid()));
|
||||||
|
else
|
||||||
|
TRY(parent_inode->create_file(file_name, mode, m_credentials.euid(), m_credentials.egid()));
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -672,7 +685,7 @@ namespace Kernel
|
||||||
if (file_or_error.is_error())
|
if (file_or_error.is_error())
|
||||||
{
|
{
|
||||||
if (file_or_error.error().get_error_code() == ENOENT)
|
if (file_or_error.error().get_error_code() == ENOENT)
|
||||||
TRY(create_file(path, mode));
|
TRY(create_file_or_dir(path, Inode::Mode::IFREG | mode));
|
||||||
else
|
else
|
||||||
return file_or_error.release_error();
|
return file_or_error.release_error();
|
||||||
}
|
}
|
||||||
|
@ -733,6 +746,42 @@ namespace Kernel
|
||||||
return TRY(m_open_file_descriptors.write(fd, BAN::ByteSpan((uint8_t*)buffer, count)));
|
return TRY(m_open_file_descriptors.write(fd, BAN::ByteSpan((uint8_t*)buffer, count)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<long> Process::sys_create(const char* path, mode_t mode)
|
||||||
|
{
|
||||||
|
LockGuard _(m_lock);
|
||||||
|
validate_string_access(path);
|
||||||
|
TRY(create_file_or_dir(path, mode));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<long> Process::sys_create_dir(const char* path, mode_t mode)
|
||||||
|
{
|
||||||
|
LockGuard _(m_lock);
|
||||||
|
validate_string_access(path);
|
||||||
|
TRY(create_file_or_dir(path, Inode::Mode::IFDIR | mode));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<long> Process::sys_unlink(const char* path)
|
||||||
|
{
|
||||||
|
LockGuard _(m_lock);
|
||||||
|
validate_string_access(path);
|
||||||
|
|
||||||
|
auto absolute_path = TRY(absolute_path_of(path));
|
||||||
|
|
||||||
|
size_t index = absolute_path.size();
|
||||||
|
for (; index > 0; index--)
|
||||||
|
if (absolute_path[index - 1] == '/')
|
||||||
|
break;
|
||||||
|
auto directory = absolute_path.sv().substring(0, index);
|
||||||
|
auto file_name = absolute_path.sv().substring(index);
|
||||||
|
|
||||||
|
auto parent = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, directory, O_EXEC | O_WRONLY)).inode;
|
||||||
|
TRY(parent->unlink(file_name));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_chmod(const char* path, mode_t mode)
|
BAN::ErrorOr<long> Process::sys_chmod(const char* path, mode_t mode)
|
||||||
{
|
{
|
||||||
if (mode & S_IFMASK)
|
if (mode & S_IFMASK)
|
||||||
|
|
|
@ -202,6 +202,15 @@ namespace Kernel
|
||||||
case SYS_CHMOD:
|
case SYS_CHMOD:
|
||||||
ret = Process::current().sys_chmod((const char*)arg1, (mode_t)arg2);
|
ret = Process::current().sys_chmod((const char*)arg1, (mode_t)arg2);
|
||||||
break;
|
break;
|
||||||
|
case SYS_CREATE:
|
||||||
|
ret = Process::current().sys_create((const char*)arg1, (mode_t)arg2);
|
||||||
|
break;
|
||||||
|
case SYS_CREATE_DIR:
|
||||||
|
ret = Process::current().sys_create_dir((const char*)arg1, (mode_t)arg2);
|
||||||
|
break;
|
||||||
|
case SYS_UNLINK:
|
||||||
|
ret = Process::current().sys_unlink((const char*)arg1);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
dwarnln("Unknown syscall {}", syscall);
|
dwarnln("Unknown syscall {}", syscall);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -4,6 +4,11 @@
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int creat(const char* path, mode_t mode)
|
||||||
|
{
|
||||||
|
return syscall(SYS_CREATE, path, S_IFREG | mode);
|
||||||
|
}
|
||||||
|
|
||||||
int open(const char* path, int oflag, ...)
|
int open(const char* path, int oflag, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
|
@ -56,6 +56,9 @@ __BEGIN_DECLS
|
||||||
#define SYS_TTY_CTRL 53
|
#define SYS_TTY_CTRL 53
|
||||||
#define SYS_POWEROFF 54
|
#define SYS_POWEROFF 54
|
||||||
#define SYS_CHMOD 55
|
#define SYS_CHMOD 55
|
||||||
|
#define SYS_CREATE 56 // creat, mkfifo
|
||||||
|
#define SYS_CREATE_DIR 57 // mkdir
|
||||||
|
#define SYS_UNLINK 58
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
|
|
|
@ -28,3 +28,8 @@ int stat(const char* __restrict path, struct stat* __restrict buf)
|
||||||
{
|
{
|
||||||
return syscall(SYS_STAT, path, buf, 0);
|
return syscall(SYS_STAT, path, buf, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mkdir(const char* path, mode_t mode)
|
||||||
|
{
|
||||||
|
return syscall(SYS_CREATE_DIR, path, mode);
|
||||||
|
}
|
||||||
|
|
|
@ -210,6 +210,11 @@ void syncsync(int should_block)
|
||||||
syscall(SYS_SYNC, should_block);
|
syscall(SYS_SYNC, should_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int unlink(const char* path)
|
||||||
|
{
|
||||||
|
return syscall(SYS_UNLINK, path);
|
||||||
|
}
|
||||||
|
|
||||||
pid_t getpid(void)
|
pid_t getpid(void)
|
||||||
{
|
{
|
||||||
return syscall(SYS_GET_PID);
|
return syscall(SYS_GET_PID);
|
||||||
|
|
|
@ -13,8 +13,10 @@ set(USERSPACE_PROJECTS
|
||||||
init
|
init
|
||||||
ls
|
ls
|
||||||
meminfo
|
meminfo
|
||||||
|
mkdir
|
||||||
mmap-shared-test
|
mmap-shared-test
|
||||||
poweroff
|
poweroff
|
||||||
|
rm
|
||||||
Shell
|
Shell
|
||||||
snake
|
snake
|
||||||
stat
|
stat
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
cmake_minimum_required(VERSION 3.26)
|
||||||
|
|
||||||
|
project(mkdir CXX)
|
||||||
|
|
||||||
|
set(SOURCES
|
||||||
|
main.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(mkdir ${SOURCES})
|
||||||
|
target_compile_options(mkdir PUBLIC -O2 -g)
|
||||||
|
target_link_libraries(mkdir PUBLIC libc)
|
||||||
|
|
||||||
|
add_custom_target(mkdir-install
|
||||||
|
COMMAND sudo cp ${CMAKE_CURRENT_BINARY_DIR}/mkdir ${BANAN_BIN}/
|
||||||
|
DEPENDS mkdir
|
||||||
|
USES_TERMINAL
|
||||||
|
)
|
|
@ -0,0 +1,23 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if (argc <= 1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Missing operand\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
for (int i = 1; i < argc; i++)
|
||||||
|
{
|
||||||
|
if (mkdir(argv[i], 0755) == -1)
|
||||||
|
{
|
||||||
|
perror("mkdir");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
cmake_minimum_required(VERSION 3.26)
|
||||||
|
|
||||||
|
project(rm CXX)
|
||||||
|
|
||||||
|
set(SOURCES
|
||||||
|
main.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(rm ${SOURCES})
|
||||||
|
target_compile_options(rm PUBLIC -O2 -g)
|
||||||
|
target_link_libraries(rm PUBLIC libc ban)
|
||||||
|
|
||||||
|
add_custom_target(rm-install
|
||||||
|
COMMAND sudo cp ${CMAKE_CURRENT_BINARY_DIR}/rm ${BANAN_BIN}/
|
||||||
|
DEPENDS rm
|
||||||
|
USES_TERMINAL
|
||||||
|
)
|
|
@ -0,0 +1,131 @@
|
||||||
|
#include <BAN/String.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
bool delete_recursive(const char* path)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
if (stat(path, &st) == -1)
|
||||||
|
{
|
||||||
|
perror(path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ret = true;
|
||||||
|
|
||||||
|
if (S_ISDIR(st.st_mode))
|
||||||
|
{
|
||||||
|
DIR* dir = opendir(path);
|
||||||
|
while (struct dirent* dirent = readdir(dir))
|
||||||
|
{
|
||||||
|
if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
BAN::String dirent_path;
|
||||||
|
MUST(dirent_path.append(path));
|
||||||
|
MUST(dirent_path.push_back('/'));
|
||||||
|
MUST(dirent_path.append(dirent->d_name));
|
||||||
|
|
||||||
|
if (dirent->d_type == DT_DIR)
|
||||||
|
{
|
||||||
|
if (!delete_recursive(dirent_path.data()))
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (unlink(dirent_path.data()) == -1)
|
||||||
|
{
|
||||||
|
perror(dirent_path.data());
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlink(path) == -1)
|
||||||
|
{
|
||||||
|
perror(path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usage(const char* argv0, int ret)
|
||||||
|
{
|
||||||
|
FILE* out = (ret == 0) ? stdout : stderr;
|
||||||
|
fprintf(out, "usage: %s [OPTIONS]... FILE...\n");
|
||||||
|
fprintf(out, " remove each FILE\n");
|
||||||
|
fprintf(out, "OPTIONS:\n");
|
||||||
|
fprintf(out, " -r remove directories and their contents recursively\n");
|
||||||
|
fprintf(out, " -h, --help show this message and exit\n");
|
||||||
|
exit(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
bool recursive = false;
|
||||||
|
|
||||||
|
int i = 1;
|
||||||
|
for (; i < argc; i++)
|
||||||
|
{
|
||||||
|
if (argv[i][0] != '-')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (strcmp(argv[i], "-r") == 0)
|
||||||
|
recursive = true;
|
||||||
|
else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0)
|
||||||
|
usage(argv[0], 0);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "unrecognized argument %s. use --help for more information\n", argv[i]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= argc)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "missing operand. use --help for more information\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
for (; i < argc; i++)
|
||||||
|
{
|
||||||
|
if (recursive)
|
||||||
|
{
|
||||||
|
if (!delete_recursive(argv[i]))
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
if (stat(argv[i], &st) == -1)
|
||||||
|
{
|
||||||
|
perror(argv[i]);
|
||||||
|
ret = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_ISDIR(st.st_mode))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: %s\n", argv[i], strerror(EISDIR));
|
||||||
|
ret = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlink(argv[i]) == -1)
|
||||||
|
{
|
||||||
|
perror(argv[i]);
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -4,18 +4,14 @@
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
int ret = 0;
|
||||||
for (int i = 1; i < argc; i++)
|
for (int i = 1; i < argc; i++)
|
||||||
{
|
{
|
||||||
int fd = open(argv[i], O_WRONLY | O_CREAT, 0644);
|
if (creat(argv[i], 0644) == -1 && errno != EEXIST)
|
||||||
if (fd == -1)
|
|
||||||
{
|
{
|
||||||
if (errno != EEXISTS)
|
|
||||||
perror(argv[i]);
|
perror(argv[i]);
|
||||||
}
|
ret = 1;
|
||||||
else
|
|
||||||
{
|
|
||||||
close(fd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue