Add support for removing directories.

It's really only supported in Ext2FS since SynthFS doesn't really want you
mucking around with its files. This is pretty neat though :^)

I ran into some trouble with HashMap while working on this but opted to work
around it and leave that for a separate investigation.
This commit is contained in:
Andreas Kling 2019-01-28 04:16:01 +01:00
parent 031c62a21e
commit c95228b128
Notes: sideshowbarker 2024-07-19 15:55:42 +09:00
19 changed files with 185 additions and 40 deletions

View file

@ -313,6 +313,20 @@ void Ext2FS::free_inode(Ext2FSInode& inode)
set_block_allocation_state(group_index, block_index, false);
set_inode_allocation_state(inode.index(), false);
if (inode.is_directory()) {
auto& bgd = const_cast<ext2_group_desc&>(group_descriptor(group_index_from_inode(inode.index())));
--bgd.bg_used_dirs_count;
dbgprintf("Ext2FS: decremented bg_used_dirs_count %u -> %u\n", bgd.bg_used_dirs_count - 1, bgd.bg_used_dirs_count);
flush_block_group_descriptor_table();
}
}
void Ext2FS::flush_block_group_descriptor_table()
{
unsigned blocks_to_write = ceilDiv(m_blockGroupCount * (unsigned)sizeof(ext2_group_desc), blockSize());
unsigned first_block_of_bgdt = blockSize() == 1024 ? 2 : 1;
writeBlocks(first_block_of_bgdt, blocks_to_write, m_cached_group_descriptor_table);
}
Ext2FSInode::Ext2FSInode(Ext2FS& fs, unsigned index, const ext2_inode& raw_inode)
@ -356,9 +370,15 @@ void Ext2FSInode::flush_metadata()
dbgprintf("Ext2FSInode: flush_metadata for inode %u\n", index());
fs().write_ext2_inode(index(), m_raw_inode);
if (is_directory()) {
// FIXME: This invalidation is way too hardcore.
LOCKER(m_lock);
m_lookup_cache.clear();
// Unless we're about to go away permanently, invalidate the lookup cache.
if (m_raw_inode.i_links_count != 0) {
LOCKER(m_lock);
// FIXME: Something isn't working right when we hit this code path.
// I've seen crashes inside HashMap::clear() all the way down in DoublyLinkedList::clear().
// My guess would be a HashTable bug.
// FIXME: This invalidation is way too hardcore. It's sad to throw away the whole cache.
m_lookup_cache.clear();
}
}
set_metadata_dirty(false);
}
@ -401,7 +421,7 @@ RetainPtr<Inode> Ext2FS::get_inode(InodeIdentifier inode) const
return new_inode;
}
ssize_t Ext2FSInode::read_bytes(off_t offset, size_t count, byte* buffer, FileDescriptor*)
ssize_t Ext2FSInode::read_bytes(off_t offset, size_t count, byte* buffer, FileDescriptor*) const
{
ASSERT(offset >= 0);
if (m_raw_inode.i_size == 0)
@ -550,7 +570,7 @@ ssize_t Ext2FSInode::write_bytes(off_t offset, size_t count, const byte* data, F
return nwritten;
}
bool Ext2FSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntry&)> callback)
bool Ext2FSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntry&)> callback) const
{
ASSERT(metadata().isDirectory());
@ -610,6 +630,9 @@ bool Ext2FSInode::add_child(InodeIdentifier child_id, const String& name, byte f
bool Ext2FSInode::remove_child(const String& name, int& error)
{
#ifdef EXT2_DEBUG
dbgprintf("Ext2FSInode::remove_child(%s) in inode %u\n", name.characters(), index());
#endif
ASSERT(is_directory());
unsigned child_inode_index;
@ -710,7 +733,9 @@ bool Ext2FS::write_directory_inode(unsigned directoryInode, Vector<DirectoryEntr
kprintf("\n");
#endif
return get_inode({ fsid(), directoryInode })->write_bytes(0, directoryData.size(), directoryData.pointer(), nullptr);
auto directory_inode = get_inode({ fsid(), directoryInode });
ssize_t nwritten = directory_inode->write_bytes(0, directoryData.size(), directoryData.pointer(), nullptr);
return nwritten == directoryData.size();
}
unsigned Ext2FS::inodes_per_block() const
@ -955,10 +980,7 @@ bool Ext2FS::set_inode_allocation_state(unsigned index, bool newState)
++mutableBGD.bg_free_inodes_count;
dbgprintf("Ext2FS: group free inode count %u -> %u\n", bgd.bg_free_inodes_count, bgd.bg_free_inodes_count - 1);
unsigned blocksToWrite = ceilDiv(m_blockGroupCount * (unsigned)sizeof(ext2_group_desc), blockSize());
unsigned firstBlockOfBGDT = blockSize() == 1024 ? 2 : 1;
writeBlocks(firstBlockOfBGDT, blocksToWrite, m_cached_group_descriptor_table);
flush_block_group_descriptor_table();
return true;
}
@ -1000,10 +1022,7 @@ bool Ext2FS::set_block_allocation_state(GroupIndex group, BlockIndex bi, bool ne
++mutableBGD.bg_free_blocks_count;
dbgprintf("Ext2FS: group free block count %u -> %u\n", bgd.bg_free_blocks_count, bgd.bg_free_blocks_count - 1);
unsigned blocksToWrite = ceilDiv(m_blockGroupCount * (unsigned)sizeof(ext2_group_desc), blockSize());
unsigned firstBlockOfBGDT = blockSize() == 1024 ? 2 : 1;
writeBlocks(firstBlockOfBGDT, blocksToWrite, m_cached_group_descriptor_table);
flush_block_group_descriptor_table();
return true;
}
@ -1040,9 +1059,7 @@ RetainPtr<Inode> Ext2FS::create_directory(InodeIdentifier parent_id, const Strin
++bgd.bg_used_dirs_count;
dbgprintf("Ext2FS: incremented bg_used_dirs_count %u -> %u\n", bgd.bg_used_dirs_count - 1, bgd.bg_used_dirs_count);
unsigned blocksToWrite = ceilDiv(m_blockGroupCount * (unsigned)sizeof(ext2_group_desc), blockSize());
unsigned firstBlockOfBGDT = blockSize() == 1024 ? 2 : 1;
writeBlocks(firstBlockOfBGDT, blocksToWrite, m_cached_group_descriptor_table);
flush_block_group_descriptor_table();
error = 0;
return inode;
@ -1165,7 +1182,7 @@ RetainPtr<Inode> Ext2FSInode::parent() const
return fs().get_inode(m_parent_id);
}
void Ext2FSInode::populate_lookup_cache()
void Ext2FSInode::populate_lookup_cache() const
{
{
LOCKER(m_lock);
@ -1267,3 +1284,11 @@ void Ext2FS::uncache_inode(InodeIndex index)
LOCKER(m_inode_cache_lock);
m_inode_cache.remove(index);
}
size_t Ext2FSInode::directory_entry_count() const
{
ASSERT(is_directory());
populate_lookup_cache();
LOCKER(m_lock);
return m_lookup_cache.size();
}