mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-29 14:14:45 +03:00
Implement creating a new directory.
This commit is contained in:
parent
5c50d02c2e
commit
f608629704
Notes:
sideshowbarker
2024-07-19 18:47:48 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/f6086297047
@ -63,7 +63,7 @@ const ext2_group_desc& Ext2FileSystem::blockGroupDescriptor(unsigned groupIndex)
|
||||
ASSERT(groupIndex <= m_blockGroupCount);
|
||||
|
||||
if (!m_cachedBlockGroupDescriptorTable) {
|
||||
unsigned blocksToRead = ceilDiv(m_blockGroupCount * sizeof(ext2_group_desc), blockSize());
|
||||
unsigned blocksToRead = ceilDiv(m_blockGroupCount * (unsigned)sizeof(ext2_group_desc), blockSize());
|
||||
printf("[ext2fs] block group count: %u, blocks-to-read: %u\n", m_blockGroupCount, blocksToRead);
|
||||
unsigned firstBlockOfBGDT = blockSize() == 1024 ? 2 : 1;
|
||||
printf("[ext2fs] first block of BGDT: %u\n", firstBlockOfBGDT);
|
||||
@ -350,7 +350,7 @@ bool Ext2FileSystem::writeInode(InodeIdentifier inode, const ByteBuffer& data)
|
||||
ASSERT(!isSymbolicLink(e2inode->i_mode));
|
||||
|
||||
unsigned blocksNeededBefore = ceilDiv(e2inode->i_size, blockSize());
|
||||
unsigned blocksNeededAfter = ceilDiv(data.size(), blockSize());
|
||||
unsigned blocksNeededAfter = ceilDiv((unsigned)data.size(), blockSize());
|
||||
|
||||
// FIXME: Support growing or shrinking the block list.
|
||||
ASSERT(blocksNeededBefore == blocksNeededAfter);
|
||||
@ -604,6 +604,38 @@ void Ext2FileSystem::traverseInodeBitmap(unsigned groupIndex, F callback) const
|
||||
}
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void Ext2FileSystem::traverseBlockBitmap(unsigned groupIndex, F callback) const
|
||||
{
|
||||
ASSERT(groupIndex <= m_blockGroupCount);
|
||||
auto& bgd = blockGroupDescriptor(groupIndex);
|
||||
|
||||
unsigned blocksInGroup = min(blocksPerGroup(), superBlock().s_blocks_count);
|
||||
unsigned blockCount = ceilDiv(blocksInGroup, 8u);
|
||||
|
||||
for (unsigned i = 0; i < blockCount; ++i) {
|
||||
auto block = readBlock(bgd.bg_block_bitmap + i);
|
||||
ASSERT(block);
|
||||
bool shouldContinue = callback(i * (blockSize() / 8) + 1, Bitmap::wrap(block.pointer(), blocksInGroup));
|
||||
if (!shouldContinue)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool Ext2FileSystem::modifyLinkCount(InodeIndex inode, int delta)
|
||||
{
|
||||
ASSERT(inode);
|
||||
auto e2inode = lookupExt2Inode(inode);
|
||||
if (!e2inode)
|
||||
return false;
|
||||
|
||||
auto newLinkCount = e2inode->i_links_count + delta;
|
||||
printf("changing inode %u link count from %u to %u\n", inode, e2inode->i_links_count, newLinkCount);
|
||||
e2inode->i_links_count = newLinkCount;
|
||||
|
||||
return writeExt2Inode(inode, *e2inode);
|
||||
}
|
||||
|
||||
bool Ext2FileSystem::setModificationTime(InodeIdentifier inode, dword timestamp)
|
||||
{
|
||||
ASSERT(inode.fileSystemID() == id());
|
||||
@ -637,6 +669,36 @@ bool Ext2FileSystem::isDirectoryInode(unsigned inode) const
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector<Ext2FileSystem::BlockIndex> Ext2FileSystem::allocateBlocks(unsigned group, unsigned count)
|
||||
{
|
||||
printf("[ext2fs] allocateBlocks(group: %u, count: %u)\n", group, count);
|
||||
|
||||
auto& bgd = blockGroupDescriptor(group);
|
||||
if (bgd.bg_free_blocks_count < count) {
|
||||
printf("[ext2fs] allocateBlocks can't allocate out of group %u, wanted %u but only %u available\n", group, count, bgd.bg_free_blocks_count);
|
||||
return { };
|
||||
}
|
||||
|
||||
// FIXME: Implement a scan that finds consecutive blocks if possible.
|
||||
Vector<BlockIndex> blocks;
|
||||
traverseBlockBitmap(group, [&blocks, count] (unsigned firstBlockInBitmap, const Bitmap& bitmap) {
|
||||
for (unsigned i = 0; i < bitmap.size(); ++i) {
|
||||
if (!bitmap.get(i)) {
|
||||
blocks.append(firstBlockInBitmap + i);
|
||||
if (blocks.size() == count)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
printf("[ext2fs] allocateBlock found these blocks:\n");
|
||||
for (auto& bi : blocks) {
|
||||
printf(" > %u\n", bi);
|
||||
}
|
||||
|
||||
return blocks;
|
||||
}
|
||||
|
||||
unsigned Ext2FileSystem::allocateInode(unsigned preferredGroup, unsigned expectedSize)
|
||||
{
|
||||
printf("[ext2fs] allocateInode(preferredGroup: %u, expectedSize: %u)\n", preferredGroup, expectedSize);
|
||||
@ -736,14 +798,97 @@ bool Ext2FileSystem::setInodeAllocationState(unsigned inode, bool newState)
|
||||
++mutableBGD.bg_free_inodes_count;
|
||||
printf("[ext2fs] group free inode count %u -> %u\n", bgd.bg_free_inodes_count, bgd.bg_free_inodes_count - 1);
|
||||
|
||||
unsigned blocksToWrite = ceilDiv(m_blockGroupCount * sizeof(ext2_group_desc), blockSize());
|
||||
unsigned blocksToWrite = ceilDiv(m_blockGroupCount * (unsigned)sizeof(ext2_group_desc), blockSize());
|
||||
unsigned firstBlockOfBGDT = blockSize() == 1024 ? 2 : 1;
|
||||
writeBlocks(firstBlockOfBGDT, blocksToWrite, m_cachedBlockGroupDescriptorTable);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
InodeIdentifier Ext2FileSystem::createInode(InodeIdentifier parentInode, const String& name, word mode)
|
||||
bool Ext2FileSystem::setBlockAllocationState(GroupIndex group, BlockIndex bi, bool newState)
|
||||
{
|
||||
auto& bgd = blockGroupDescriptor(group);
|
||||
|
||||
// Update block bitmap
|
||||
unsigned blocksPerBitmapBlock = blockSize() * 8;
|
||||
unsigned bitmapBlockIndex = (bi - 1) / blocksPerBitmapBlock;
|
||||
unsigned bitIndex = (bi - 1) % blocksPerBitmapBlock;
|
||||
auto block = readBlock(bgd.bg_block_bitmap + bitmapBlockIndex);
|
||||
ASSERT(block);
|
||||
auto bitmap = Bitmap::wrap(block.pointer(), block.size());
|
||||
bool currentState = bitmap.get(bitIndex);
|
||||
printf("[ext2fs] setBlockAllocationState(%u) %u -> %u\n", block, currentState, newState);
|
||||
|
||||
if (currentState == newState)
|
||||
return true;
|
||||
|
||||
bitmap.set(bitIndex, newState);
|
||||
writeBlock(bgd.bg_block_bitmap + bitmapBlockIndex, block);
|
||||
|
||||
// Update superblock
|
||||
auto& sb = *reinterpret_cast<ext2_super_block*>(m_cachedSuperBlock.pointer());
|
||||
printf("[ext2fs] superblock free block count %u -> %u\n", sb.s_free_blocks_count, sb.s_free_blocks_count - 1);
|
||||
if (newState)
|
||||
--sb.s_free_blocks_count;
|
||||
else
|
||||
++sb.s_free_blocks_count;
|
||||
writeSuperBlock(sb);
|
||||
|
||||
// Update BGD
|
||||
auto& mutableBGD = const_cast<ext2_group_desc&>(bgd);
|
||||
if (newState)
|
||||
--mutableBGD.bg_free_blocks_count;
|
||||
else
|
||||
++mutableBGD.bg_free_blocks_count;
|
||||
printf("[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_cachedBlockGroupDescriptorTable);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
InodeIdentifier Ext2FileSystem::makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t mode)
|
||||
{
|
||||
ASSERT(parentInode.fileSystemID() == id());
|
||||
ASSERT(isDirectoryInode(parentInode.index()));
|
||||
|
||||
// Fix up the mode to definitely be a directory.
|
||||
// FIXME: This is a bit on the hackish side.
|
||||
mode &= ~0170000;
|
||||
mode |= 0040000;
|
||||
|
||||
// NOTE: When creating a new directory, make the size 1 block.
|
||||
// There's probably a better strategy here, but this works for now.
|
||||
auto inode = createInode(parentInode, name, mode, blockSize());
|
||||
if (!inode.isValid())
|
||||
return { };
|
||||
|
||||
printf("[ext2fs] makeDirectory: created new directory named '%s' with inode %u\n", name.characters(), inode.index());
|
||||
|
||||
Vector<DirectoryEntry> entries;
|
||||
entries.append({ ".", inode, EXT2_FT_DIR });
|
||||
entries.append({ "..", parentInode, EXT2_FT_DIR });
|
||||
|
||||
bool success = writeDirectoryInode(inode.index(), std::move(entries));
|
||||
ASSERT(success);
|
||||
|
||||
success = modifyLinkCount(parentInode.index(), 1);
|
||||
ASSERT(success);
|
||||
|
||||
auto& bgd = const_cast<ext2_group_desc&>(blockGroupDescriptor(groupIndexFromInode(inode.index())));
|
||||
++bgd.bg_used_dirs_count;
|
||||
printf("[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_cachedBlockGroupDescriptorTable);
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
||||
InodeIdentifier Ext2FileSystem::createInode(InodeIdentifier parentInode, const String& name, Unix::mode_t mode, unsigned size)
|
||||
{
|
||||
ASSERT(parentInode.fileSystemID() == id());
|
||||
ASSERT(isDirectoryInode(parentInode.index()));
|
||||
@ -754,6 +899,16 @@ InodeIdentifier Ext2FileSystem::createInode(InodeIdentifier parentInode, const S
|
||||
|
||||
// NOTE: This doesn't commit the inode allocation just yet!
|
||||
auto inode = allocateInode(0, 0);
|
||||
if (!inode) {
|
||||
printf("[ext2fs] createInode: allocateInode failed\n");
|
||||
return { };
|
||||
}
|
||||
|
||||
auto blocks = allocateBlocks(groupIndexFromInode(inode), ceilDiv(size, blockSize()));
|
||||
if (blocks.isEmpty()) {
|
||||
printf("[ext2fs] createInode: allocateBlocks failed\n");
|
||||
return { };
|
||||
}
|
||||
|
||||
byte fileType = 0;
|
||||
if (isRegularFile(mode))
|
||||
@ -782,19 +937,39 @@ InodeIdentifier Ext2FileSystem::createInode(InodeIdentifier parentInode, const S
|
||||
success = setInodeAllocationState(inode, true);
|
||||
ASSERT(success);
|
||||
|
||||
for (auto bi : blocks) {
|
||||
success = setBlockAllocationState(groupIndexFromInode(inode), bi, true);
|
||||
ASSERT(success);
|
||||
}
|
||||
|
||||
unsigned initialLinksCount;
|
||||
if (isDirectory(mode))
|
||||
initialLinksCount = 2; // (parent directory + "." entry in self)
|
||||
else
|
||||
initialLinksCount = 1;
|
||||
|
||||
auto timestamp = time(nullptr);
|
||||
auto e2inode = make<ext2_inode>();
|
||||
memset(e2inode.ptr(), 0, sizeof(ext2_inode));
|
||||
e2inode->i_mode = mode;
|
||||
e2inode->i_uid = 0;
|
||||
e2inode->i_size = 0;
|
||||
e2inode->i_size = size;
|
||||
e2inode->i_atime = timestamp;
|
||||
e2inode->i_ctime = timestamp;
|
||||
e2inode->i_mtime = timestamp;
|
||||
e2inode->i_dtime = 0;
|
||||
e2inode->i_gid = 0;
|
||||
e2inode->i_links_count = 1;
|
||||
e2inode->i_blocks = 0;
|
||||
e2inode->i_links_count = initialLinksCount;
|
||||
e2inode->i_blocks = blocks.size() * (blockSize() / 512);
|
||||
|
||||
// FIXME: Implement writing out indirect blocks!
|
||||
ASSERT(blocks.size() < EXT2_NDIR_BLOCKS);
|
||||
|
||||
printf("[XXX] writing %u blocks to i_block array\n", min((unsigned)EXT2_NDIR_BLOCKS, blocks.size()));
|
||||
for (unsigned i = 0; i < min((unsigned)EXT2_NDIR_BLOCKS, blocks.size()); ++i) {
|
||||
e2inode->i_block[i] = blocks[i];
|
||||
}
|
||||
|
||||
e2inode->i_flags = 0;
|
||||
success = writeExt2Inode(inode, *e2inode);
|
||||
ASSERT(success);
|
||||
|
@ -15,6 +15,10 @@ public:
|
||||
virtual ~Ext2FileSystem() override;
|
||||
|
||||
private:
|
||||
typedef unsigned BlockIndex;
|
||||
typedef unsigned GroupIndex;
|
||||
typedef unsigned InodeIndex;
|
||||
|
||||
explicit Ext2FileSystem(RetainPtr<BlockDevice>);
|
||||
|
||||
const ext2_super_block& superBlock() const;
|
||||
@ -39,11 +43,13 @@ private:
|
||||
virtual bool enumerateDirectoryInode(InodeIdentifier, std::function<bool(const DirectoryEntry&)>) const override;
|
||||
virtual InodeMetadata inodeMetadata(InodeIdentifier) const override;
|
||||
virtual bool setModificationTime(InodeIdentifier, dword timestamp) override;
|
||||
virtual InodeIdentifier createInode(InodeIdentifier parentInode, const String& name, word mode) override;
|
||||
virtual ssize_t readInodeBytes(InodeIdentifier, Unix::off_t offset, size_t count, byte* buffer) const override;
|
||||
virtual InodeIdentifier createInode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size) override;
|
||||
virtual Unix::ssize_t readInodeBytes(InodeIdentifier, Unix::off_t offset, Unix::size_t count, byte* buffer) const override;
|
||||
virtual InodeIdentifier makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t) override;
|
||||
|
||||
bool isDirectoryInode(unsigned) const;
|
||||
unsigned allocateInode(unsigned preferredGroup, unsigned expectedSize);
|
||||
Vector<BlockIndex> allocateBlocks(unsigned group, unsigned count);
|
||||
unsigned groupIndexFromInode(unsigned) const;
|
||||
|
||||
Vector<unsigned> blockListForInode(const ext2_inode&) const;
|
||||
@ -51,12 +57,15 @@ private:
|
||||
void dumpBlockBitmap(unsigned groupIndex) const;
|
||||
void dumpInodeBitmap(unsigned groupIndex) const;
|
||||
|
||||
template<typename F>
|
||||
void traverseInodeBitmap(unsigned groupIndex, F) const;
|
||||
template<typename F> void traverseInodeBitmap(unsigned groupIndex, F) const;
|
||||
template<typename F> void traverseBlockBitmap(unsigned groupIndex, F) const;
|
||||
|
||||
bool addInodeToDirectory(unsigned directoryInode, unsigned inode, const String& name, byte fileType);
|
||||
bool writeDirectoryInode(unsigned directoryInode, Vector<DirectoryEntry>&&);
|
||||
bool setInodeAllocationState(unsigned inode, bool);
|
||||
bool setBlockAllocationState(GroupIndex, BlockIndex, bool);
|
||||
|
||||
bool modifyLinkCount(InodeIndex, int delta);
|
||||
|
||||
unsigned m_blockGroupCount { 0 };
|
||||
|
||||
|
@ -28,7 +28,7 @@ public:
|
||||
virtual bool writeInode(InodeIdentifier, const ByteBuffer&) = 0;
|
||||
virtual InodeMetadata inodeMetadata(InodeIdentifier) const = 0;
|
||||
|
||||
virtual ssize_t readInodeBytes(InodeIdentifier, Unix::off_t offset, size_t count, byte* buffer) const = 0;
|
||||
virtual Unix::ssize_t readInodeBytes(InodeIdentifier, Unix::off_t offset, Unix::size_t count, byte* buffer) const = 0;
|
||||
|
||||
struct DirectoryEntry {
|
||||
String name;
|
||||
@ -38,7 +38,8 @@ public:
|
||||
virtual bool enumerateDirectoryInode(InodeIdentifier, std::function<bool(const DirectoryEntry&)>) const = 0;
|
||||
|
||||
virtual bool setModificationTime(InodeIdentifier, dword timestamp) = 0;
|
||||
virtual InodeIdentifier createInode(InodeIdentifier parentInode, const String& name, word mode) = 0;
|
||||
virtual InodeIdentifier createInode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size) = 0;
|
||||
virtual InodeIdentifier makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t) = 0;
|
||||
|
||||
InodeIdentifier childOfDirectoryInodeWithName(InodeIdentifier, const String& name) const;
|
||||
ByteBuffer readEntireInode(InodeIdentifier) const;
|
||||
|
@ -97,7 +97,7 @@ bool SyntheticFileSystem::setModificationTime(InodeIdentifier, dword timestamp)
|
||||
return false;
|
||||
}
|
||||
|
||||
InodeIdentifier SyntheticFileSystem::createInode(InodeIdentifier parentInode, const String& name, word mode)
|
||||
InodeIdentifier SyntheticFileSystem::createInode(InodeIdentifier parentInode, const String& name, Unix::mode_t mode, unsigned size)
|
||||
{
|
||||
(void) parentInode;
|
||||
(void) name;
|
||||
@ -112,7 +112,7 @@ bool SyntheticFileSystem::writeInode(InodeIdentifier, const ByteBuffer&)
|
||||
return false;
|
||||
}
|
||||
|
||||
ssize_t SyntheticFileSystem::readInodeBytes(InodeIdentifier inode, Unix::off_t offset, Unix::size_t count, byte* buffer) const
|
||||
Unix::ssize_t SyntheticFileSystem::readInodeBytes(InodeIdentifier inode, Unix::off_t offset, Unix::size_t count, byte* buffer) const
|
||||
{
|
||||
ASSERT(inode.fileSystemID() == id());
|
||||
#ifdef SYNTHFS_DEBUG
|
||||
@ -124,7 +124,13 @@ ssize_t SyntheticFileSystem::readInodeBytes(InodeIdentifier inode, Unix::off_t o
|
||||
ASSERT(buffer);
|
||||
|
||||
auto& file = *m_files[inode.index() - 1];
|
||||
Unix::ssize_t nread = min(file.data.size() - offset, static_cast<Unix::off_t>(count));
|
||||
Unix::ssize_t nread = min(static_cast<Unix::off_t>(file.data.size() - offset), static_cast<Unix::off_t>(count));
|
||||
memcpy(buffer, file.data.pointer() + offset, nread);
|
||||
return nread;
|
||||
}
|
||||
|
||||
InodeIdentifier SyntheticFileSystem::makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t)
|
||||
{
|
||||
printf("FIXME: Implement SyntheticFileSystem::makeDirectory().\n");
|
||||
return { };
|
||||
}
|
||||
|
@ -16,8 +16,9 @@ public:
|
||||
virtual bool enumerateDirectoryInode(InodeIdentifier, std::function<bool(const DirectoryEntry&)>) const override;
|
||||
virtual InodeMetadata inodeMetadata(InodeIdentifier) const override;
|
||||
virtual bool setModificationTime(InodeIdentifier, dword timestamp) override;
|
||||
virtual InodeIdentifier createInode(InodeIdentifier parentInode, const String& name, word mode) override;
|
||||
virtual ssize_t readInodeBytes(InodeIdentifier, Unix::off_t offset, size_t count, byte* buffer) const override;
|
||||
virtual InodeIdentifier createInode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size) override;
|
||||
virtual Unix::ssize_t readInodeBytes(InodeIdentifier, Unix::off_t offset, Unix::size_t count, byte* buffer) const override;
|
||||
virtual InodeIdentifier makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t) override;
|
||||
|
||||
private:
|
||||
SyntheticFileSystem();
|
||||
|
@ -337,7 +337,14 @@ OwnPtr<FileHandle> VirtualFileSystem::open(const String& path)
|
||||
OwnPtr<FileHandle> VirtualFileSystem::create(const String& path)
|
||||
{
|
||||
// FIXME: Do the real thing, not just this fake thing!
|
||||
m_rootNode->fileSystem()->createInode(m_rootNode->fileSystem()->rootInode(), "empty", 0100644);
|
||||
m_rootNode->fileSystem()->createInode(m_rootNode->fileSystem()->rootInode(), "empty", 0100644, 0);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OwnPtr<FileHandle> VirtualFileSystem::mkdir(const String& path)
|
||||
{
|
||||
// FIXME: Do the real thing, not just this fake thing!
|
||||
m_rootNode->fileSystem()->makeDirectory(m_rootNode->fileSystem()->rootInode(), "mydir", 0400755);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,7 @@ public:
|
||||
|
||||
OwnPtr<FileHandle> open(const String& path);
|
||||
OwnPtr<FileHandle> create(const String& path);
|
||||
OwnPtr<FileHandle> mkdir(const String& path);
|
||||
|
||||
bool isRoot(InodeIdentifier) const;
|
||||
|
||||
|
Binary file not shown.
@ -38,9 +38,13 @@ int main(int c, char** v)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if 1
|
||||
#if 0
|
||||
auto newFile = vfs.create("/empty");
|
||||
printf("vfs.create: %p\n", newFile.ptr());
|
||||
#endif
|
||||
#if 1
|
||||
auto newDir = vfs.mkdir("/mydir");
|
||||
printf("vfs.mkdir: %p\n", newDir.ptr());
|
||||
#endif
|
||||
//return 0;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user