From de4604ac95261fe95f5921b0d16ee65fb501332a Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 18 Nov 2018 14:57:41 +0100 Subject: [PATCH] Finally hook up the mkdir code to a syscall. Added a /bin/mkdir that makes directories. How very neat :^) There are various limitations because of missing functionality. --- AK/FileSystemPath.cpp | 29 ++++- AK/FileSystemPath.h | 5 + AK/StringBuilder.cpp | 5 + AK/StringBuilder.h | 1 + Kernel/IDEDiskDevice.cpp | 53 +++++++- Kernel/IDEDiskDevice.h | 3 +- Kernel/Makefile | 3 +- Kernel/Process.cpp | 12 ++ Kernel/Process.h | 1 + Kernel/Syscall.cpp | 2 + Kernel/Syscall.h | 1 + Kernel/sync.sh | 1 + LibC/errno_numbers.h | 1 + LibC/stat.cpp | 7 ++ LibC/sys/stat.h | 1 + Userland/.gitignore | 1 + Userland/Makefile | 9 +- Userland/mkdir.cpp | 21 ++++ VirtualFileSystem/Ext2FileSystem.cpp | 144 +++++++++------------- VirtualFileSystem/Ext2FileSystem.h | 14 +-- VirtualFileSystem/FileSystem.cpp | 2 +- VirtualFileSystem/FileSystem.h | 4 +- VirtualFileSystem/SyntheticFileSystem.cpp | 12 +- VirtualFileSystem/SyntheticFileSystem.h | 4 +- VirtualFileSystem/VirtualFileSystem.cpp | 29 +++-- VirtualFileSystem/VirtualFileSystem.h | 5 +- 26 files changed, 238 insertions(+), 132 deletions(-) create mode 100644 Userland/mkdir.cpp diff --git a/AK/FileSystemPath.cpp b/AK/FileSystemPath.cpp index 88dce0aa56..fcba78420e 100644 --- a/AK/FileSystemPath.cpp +++ b/AK/FileSystemPath.cpp @@ -30,15 +30,32 @@ bool FileSystemPath::canonicalize(bool resolveSymbolicLinks) canonicalParts.append(part); } if (canonicalParts.isEmpty()) { - m_string = "/"; + m_string = m_basename = m_dirname = "/"; return true; } - StringBuilder builder; - for (auto& cpart : canonicalParts) { - builder.append('/'); - builder.append(move(cpart)); + + m_basename = canonicalParts.last(); + + if (canonicalParts.size() == 1) { + m_dirname = "/"; + } else { + StringBuilder builder; + for (size_t i = 0; i < canonicalParts.size() - 1; ++i) { + auto& cpart = canonicalParts[i]; + builder.append('/'); + builder.append(cpart); + } + m_dirname = builder.build(); + } + + { + StringBuilder builder; + for (auto& cpart : canonicalParts) { + builder.append('/'); + builder.append(move(cpart)); + } + m_string = builder.build(); } - m_string = builder.build(); return true; } diff --git a/AK/FileSystemPath.h b/AK/FileSystemPath.h index 46c9e694c5..f53ec22d26 100644 --- a/AK/FileSystemPath.h +++ b/AK/FileSystemPath.h @@ -12,10 +12,15 @@ public: bool isValid() const { return m_isValid; } String string() const { return m_string; } + String basename() const { return m_basename; } + String dirname() const { return m_dirname; } + private: bool canonicalize(bool resolveSymbolicLinks = false); String m_string; + String m_dirname; + String m_basename; bool m_isValid { false }; }; diff --git a/AK/StringBuilder.cpp b/AK/StringBuilder.cpp index 6414d84090..fec2b7e3e8 100644 --- a/AK/StringBuilder.cpp +++ b/AK/StringBuilder.cpp @@ -7,6 +7,11 @@ void StringBuilder::append(String&& str) m_strings.append(move(str)); } +void StringBuilder::append(const String& str) +{ + m_strings.append(str); +} + void StringBuilder::append(char ch) { m_strings.append(StringImpl::create(&ch, 1)); diff --git a/AK/StringBuilder.h b/AK/StringBuilder.h index a468eb0a2a..2eb8b1880e 100644 --- a/AK/StringBuilder.h +++ b/AK/StringBuilder.h @@ -10,6 +10,7 @@ public: StringBuilder() { } ~StringBuilder() { } + void append(const String&); void append(String&&); void append(char); diff --git a/Kernel/IDEDiskDevice.cpp b/Kernel/IDEDiskDevice.cpp index c387f3b39c..360cebcf7f 100644 --- a/Kernel/IDEDiskDevice.cpp +++ b/Kernel/IDEDiskDevice.cpp @@ -18,6 +18,7 @@ enum IDECommand : byte { IDENTIFY_DRIVE = 0xEC, READ_SECTORS = 0x21, + WRITE_SECTORS = 0x30, }; enum IDEStatus : byte { @@ -64,11 +65,8 @@ bool IDEDiskDevice::readBlock(unsigned index, byte* out) const bool IDEDiskDevice::writeBlock(unsigned index, const byte* data) { - (void) index; - (void) data; - kprintf("IDEDiskDevice: writeBlock not implemented()\n"); - notImplemented(); - return false; + write_sectors(index, 1, data); + return true; } #ifdef DISK_DEBUG @@ -221,3 +219,48 @@ bool IDEDiskDevice::read_sectors(dword start_sector, word count, byte* outbuf) return true; } + +bool IDEDiskDevice::write_sectors(dword start_sector, word count, const byte* data) +{ + LOCKER(m_lock); + dbgprintf("%s(%u): IDEDiskDevice::write_sectors request (%u sector(s) @ %u)\n", + current->name().characters(), + current->pid(), + count, + start_sector); + disableIRQ(); + + auto chs = lba_to_chs(start_sector); + + while (IO::in8(IDE0_STATUS) & BUSY); + + //dbgprintf("IDEDiskDevice: Writing %u sector(s) @ LBA %u (%u/%u/%u)\n", count, start_sector, chs.cylinder, chs.head, chs.sector); + + IO::out8(0x1F2, count == 256 ? 0 : LSB(count)); + IO::out8(0x1F3, chs.sector); + IO::out8(0x1F4, LSB(chs.cylinder)); + IO::out8(0x1F5, MSB(chs.cylinder)); + + IO::out8(0x1F6, 0xA0 | chs.head); /* 0xB0 for 2nd device */ + + IO::out8(0x3F6, 0x08); + + IO::out8(IDE0_COMMAND, WRITE_SECTORS); + + while (!(IO::in8(IDE0_STATUS) & DRQ)); + + byte status = IO::in8(0x1f7); + if (status & DRQ) { + //dbgprintf("Sending %u bytes (status=%b), data=%p...\n", count * 512, status, data); + auto* data_as_words = (const word*)data; + for (dword i = 0; i < (count * 512) / 2; ++i) { + IO::out16(IDE0_DATA, data_as_words[i]); + } + } + + m_interrupted = false; + enableIRQ(); + wait_for_irq(); + + return true; +} diff --git a/Kernel/IDEDiskDevice.h b/Kernel/IDEDiskDevice.h index 3419e12260..6da8d2305a 100644 --- a/Kernel/IDEDiskDevice.h +++ b/Kernel/IDEDiskDevice.h @@ -34,7 +34,8 @@ private: void initialize(); bool wait_for_irq(); - bool read_sectors(dword start_sector, word count, byte* outbuf); + bool read_sectors(dword start_sector, word count, byte* buffer); + bool write_sectors(dword start_sector, word count, const byte* data); SpinLock m_lock; word m_cylinders { 0 }; diff --git a/Kernel/Makefile b/Kernel/Makefile index 4cf8ef2f8b..47e3769bb8 100644 --- a/Kernel/Makefile +++ b/Kernel/Makefile @@ -44,7 +44,8 @@ ELFLOADER_OBJS = \ AK_OBJS = \ ../AK/String.o \ ../AK/StringImpl.o \ - ../AK/StringBuilder.o + ../AK/StringBuilder.o \ + ../AK/FileSystemPath.o OBJS = $(KERNEL_OBJS) $(VFS_OBJS) $(AK_OBJS) $(ELFLOADER_OBJS) diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 94ab2fdd6b..8dd94efec1 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -1751,3 +1751,15 @@ int Process::sys$setgroups(size_t count, const gid_t* gids) m_gids.set(gids[i]); return 0; } + +int Process::sys$mkdir(const char* pathname, mode_t mode) +{ + if (!validate_read_str(pathname)) + return -EFAULT; + if (strlen(pathname) >= 255) + return -ENAMETOOLONG; + int error; + if (!VFS::the().mkdir(pathname, mode, cwd_inode()->identifier(), error)) + return error; + return 0; +} diff --git a/Kernel/Process.h b/Kernel/Process.h index 47a5c5e7fd..e5d8929228 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -172,6 +172,7 @@ public: int sys$access(const char* pathname, int mode); int sys$fcntl(int fd, int cmd, dword extra_arg); int sys$ioctl(int fd, unsigned request, unsigned arg); + int sys$mkdir(const char* pathname, mode_t mode); static void initialize(); diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index 99e9969a9d..945a7915d6 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -175,6 +175,8 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2, return current->sys$ioctl((int)arg1, (unsigned)arg2, (unsigned)arg3); case Syscall::SC_fstat: return current->sys$fstat((int)arg1, (Unix::stat*)arg2); + case Syscall::SC_mkdir: + return current->sys$mkdir((const char*)arg1, (mode_t)arg2); default: kprintf("<%u> int0x80: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3); break; diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index 548bd4d1c8..0349b609de 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -63,6 +63,7 @@ __ENUMERATE_SYSCALL(access) \ __ENUMERATE_SYSCALL(fcntl) \ __ENUMERATE_SYSCALL(ioctl) \ + __ENUMERATE_SYSCALL(mkdir) \ #define DO_SYSCALL_A0(function) Syscall::invoke((dword)(function)) diff --git a/Kernel/sync.sh b/Kernel/sync.sh index 37fc24edbc..de4586d43e 100755 --- a/Kernel/sync.sh +++ b/Kernel/sync.sh @@ -29,6 +29,7 @@ cp -v ../Userland/mm mnt/bin/mm cp -v ../Userland/kill mnt/bin/kill cp -v ../Userland/tty mnt/bin/tty cp -v ../Userland/strsignal mnt/bin/strsignal +cp -v ../Userland/mkdir mnt/bin/mkdir sh sync-local.sh cp -v kernel.map mnt/ umount mnt diff --git a/LibC/errno_numbers.h b/LibC/errno_numbers.h index 87f09a748d..fde1369071 100644 --- a/LibC/errno_numbers.h +++ b/LibC/errno_numbers.h @@ -41,6 +41,7 @@ __ERROR(ENOSYS, "No such syscall") \ __ERROR(ENOTIMPL, "Not implemented") \ __ERROR(EAFNOSUPPORT, "Address family not supported") \ + __ERROR(EWHYTHO, "Failed without setting an error code (Bug!)") \ enum __errno_values { #undef __ERROR diff --git a/LibC/stat.cpp b/LibC/stat.cpp index 9dd53da298..7ddd35314c 100644 --- a/LibC/stat.cpp +++ b/LibC/stat.cpp @@ -1,4 +1,5 @@ #include +#include #include extern "C" { @@ -8,5 +9,11 @@ mode_t umask(mode_t mask) return Syscall::invoke(Syscall::SC_umask, (dword)mask); } +int mkdir(const char* pathname, mode_t mode) +{ + int rc = Syscall::invoke(Syscall::SC_mkdir, (dword)pathname, (dword)mode); + __RETURN_WITH_ERRNO(rc, rc, -1); +} + } diff --git a/LibC/sys/stat.h b/LibC/sys/stat.h index 0cba204b11..e5fc40e5e5 100644 --- a/LibC/sys/stat.h +++ b/LibC/sys/stat.h @@ -7,5 +7,6 @@ __BEGIN_DECLS mode_t umask(mode_t); int chmod(const char* pathname, mode_t); +int mkdir(const char* pathname, mode_t); __END_DECLS diff --git a/Userland/.gitignore b/Userland/.gitignore index ab59c7d305..5bb5aee8b9 100644 --- a/Userland/.gitignore +++ b/Userland/.gitignore @@ -20,3 +20,4 @@ ft ft2 strsignal fgrep +mkdir diff --git a/Userland/Makefile b/Userland/Makefile index 355dee1d8f..e8f5195036 100644 --- a/Userland/Makefile +++ b/Userland/Makefile @@ -18,7 +18,8 @@ OBJS = \ ft2.o \ strsignal.o \ fgrep.o \ - tty.o + tty.o \ + mkdir.o APPS = \ id \ @@ -40,7 +41,8 @@ APPS = \ ft2 \ strsignal \ fgrep \ - tty + tty \ + mkdir ARCH_FLAGS = STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib -nostdinc @@ -120,6 +122,9 @@ tty: tty.o strsignal: strsignal.o $(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a +mkdir: mkdir.o + $(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a + .cpp.o: @echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $< diff --git a/Userland/mkdir.cpp b/Userland/mkdir.cpp new file mode 100644 index 0000000000..c370a1486b --- /dev/null +++ b/Userland/mkdir.cpp @@ -0,0 +1,21 @@ +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + if (argc != 2) { + printf("usage: mkdir \n"); + return 1; + } + int rc = mkdir(argv[1], 0755); + if (rc < 0) { + perror("mkdir"); + return 1; + } + return 0; +} diff --git a/VirtualFileSystem/Ext2FileSystem.cpp b/VirtualFileSystem/Ext2FileSystem.cpp index fb292beb32..2a21a423c1 100644 --- a/VirtualFileSystem/Ext2FileSystem.cpp +++ b/VirtualFileSystem/Ext2FileSystem.cpp @@ -11,31 +11,6 @@ //#define EXT2_DEBUG -class Ext2FS::CachedExt2InodeImpl : public Retainable { -public: - CachedExt2InodeImpl(OwnPtr&& e2i) : e2inode(move(e2i)) { } - ~CachedExt2InodeImpl() { } - OwnPtr e2inode; -}; - -class Ext2FS::CachedExt2Inode { -public: - const ext2_inode* operator->() const { return ptr->e2inode.ptr(); } - const ext2_inode& operator*() const { return *ptr->e2inode; } - ext2_inode* operator->() { return ptr->e2inode.ptr(); } - ext2_inode& operator*() { return *ptr->e2inode; } - bool operator!() const { return !ptr; } - operator bool() const { return !!ptr; } - CachedExt2Inode() { } - explicit CachedExt2Inode(OwnPtr&& e2inode) - : ptr(adopt(*new CachedExt2InodeImpl(move(e2inode)))) - { } - explicit CachedExt2Inode(RetainPtr p) - : ptr(p) - { } - RetainPtr ptr; -}; - RetainPtr Ext2FS::create(RetainPtr&& device) { return adopt(*new Ext2FS(move(device))); @@ -187,16 +162,8 @@ ByteBuffer Ext2FS::readBlockContainingInode(unsigned inode, unsigned& blockIndex return readBlock(blockIndex); } -auto Ext2FS::lookupExt2Inode(unsigned inode) const -> CachedExt2Inode +OwnPtr Ext2FS::lookupExt2Inode(unsigned inode) const { - { - LOCKER(m_inodeCacheLock); - auto it = m_inodeCache.find(inode); - if (it != m_inodeCache.end()) { - return CachedExt2Inode{ (*it).value }; - } - } - unsigned blockIndex; unsigned offset; auto block = readBlockContainingInode(inode, blockIndex, offset); @@ -210,12 +177,7 @@ auto Ext2FS::lookupExt2Inode(unsigned inode) const -> CachedExt2Inode dumpExt2Inode(*e2inode); #endif - LOCKER(m_inodeCacheLock); - if (m_inodeCache.size() >= 128) - m_inodeCache.removeOneRandomly(); - auto cachedInode = adopt(*new CachedExt2InodeImpl(OwnPtr(e2inode))); - m_inodeCache.set(inode, cachedInode.copyRef()); - return CachedExt2Inode{ cachedInode }; + return OwnPtr(e2inode); } InodeMetadata Ext2FS::inodeMetadata(InodeIdentifier inode) const @@ -528,7 +490,7 @@ bool Ext2FS::writeInode(InodeIdentifier inode, const ByteBuffer& data) for (unsigned i = 0; i < list.size(); ++i) { auto section = data.slice(i * blockSize(), blockSize()); - kprintf("section = %p (%u)\n", section.pointer(), section.size()); + //kprintf("section = %p (%u)\n", section.pointer(), section.size()); bool success = writeBlock(list[i], section); ASSERT(success); } @@ -587,14 +549,14 @@ bool Ext2FS::deprecated_enumerateDirectoryInode(InodeIdentifier inode, Function< return true; } -bool Ext2FS::addInodeToDirectory(unsigned directoryInode, unsigned inode, const String& name, byte fileType) +bool Ext2FS::addInodeToDirectory(unsigned directoryInode, unsigned inode, const String& name, byte fileType, int& error) { auto e2inodeForDirectory = lookupExt2Inode(directoryInode); ASSERT(e2inodeForDirectory); ASSERT(isDirectory(e2inodeForDirectory->i_mode)); //#ifdef EXT2_DEBUG - kprintf("ext2fs: Adding inode %u with name '%s' to directory %u\n", inode, name.characters(), directoryInode); + dbgprintf("Ext2FS: Adding inode %u with name '%s' to directory %u\n", inode, name.characters(), directoryInode); //#endif Vector entries; @@ -608,7 +570,8 @@ bool Ext2FS::addInodeToDirectory(unsigned directoryInode, unsigned inode, const return true; }); if (nameAlreadyExists) { - kprintf("ext2fs: Name '%s' already exists in directory inode %u\n", name.characters(), directoryInode); + kprintf("Ext2FS: Name '%s' already exists in directory inode %u\n", name.characters(), directoryInode); + error = -EEXIST; return false; } @@ -618,18 +581,18 @@ bool Ext2FS::addInodeToDirectory(unsigned directoryInode, unsigned inode, const bool Ext2FS::writeDirectoryInode(unsigned directoryInode, Vector&& entries) { - kprintf("ext2fs: New directory inode %u contents to write:\n", directoryInode); + dbgprintf("Ext2FS: New directory inode %u contents to write:\n", directoryInode); unsigned directorySize = 0; for (auto& entry : entries) { - kprintf(" - %08u %s\n", entry.inode.index(), entry.name); + //kprintf(" - %08u %s\n", entry.inode.index(), entry.name); directorySize += EXT2_DIR_REC_LEN(entry.name_length); } unsigned blocksNeeded = ceilDiv(directorySize, blockSize()); unsigned occupiedSize = blocksNeeded * blockSize(); - kprintf("ext2fs: directory size: %u (occupied: %u)\n", directorySize, occupiedSize); + dbgprintf("Ext2FS: directory size: %u (occupied: %u)\n", directorySize, occupiedSize); auto directoryData = ByteBuffer::createUninitialized(occupiedSize); @@ -641,11 +604,11 @@ bool Ext2FS::writeDirectoryInode(unsigned directoryInode, Vector if (i == entries.size() - 1) recordLength += occupiedSize - directorySize; - kprintf("* inode: %u", entry.inode.index()); - kprintf(", name_len: %u", word(entry.name_length)); - kprintf(", rec_len: %u", word(recordLength)); - kprintf(", file_type: %u", byte(entry.fileType)); - kprintf(", name: %s\n", entry.name); + dbgprintf("* inode: %u", entry.inode.index()); + dbgprintf(", name_len: %u", word(entry.name_length)); + dbgprintf(", rec_len: %u", word(recordLength)); + dbgprintf(", file_type: %u", byte(entry.fileType)); + dbgprintf(", name: %s\n", entry.name); stream << dword(entry.inode.index()); stream << word(recordLength); @@ -654,7 +617,7 @@ bool Ext2FS::writeDirectoryInode(unsigned directoryInode, Vector stream << entry.name; unsigned padding = recordLength - entry.name_length - 8; - kprintf(" *** pad %u bytes\n", padding); + //dbgprintf(" *** pad %u bytes\n", padding); for (unsigned j = 0; j < padding; ++j) { stream << byte(0); } @@ -772,7 +735,7 @@ bool Ext2FS::modifyLinkCount(InodeIndex inode, int delta) return false; auto newLinkCount = e2inode->i_links_count + delta; - kprintf("changing inode %u link count from %u to %u\n", inode, e2inode->i_links_count, newLinkCount); + dbgprintf("Ext2FS: 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); @@ -799,6 +762,18 @@ bool Ext2FS::writeExt2Inode(unsigned inode, const ext2_inode& e2inode) auto block = readBlockContainingInode(inode, blockIndex, offset); if (!block) return false; + { + LOCKER(m_inode_cache_lock); + auto it = m_inode_cache.find(inode); + if (it != m_inode_cache.end()) { + auto& cached_inode = *(*it).value; + LOCKER(cached_inode.m_lock); + cached_inode.m_raw_inode = e2inode; + cached_inode.populate_metadata(); + if (cached_inode.is_directory()) + cached_inode.m_lookup_cache.clear(); + } + } memcpy(reinterpret_cast(block.offsetPointer(offset)), &e2inode, inodeSize()); writeBlock(blockIndex, block); return true; @@ -813,11 +788,11 @@ bool Ext2FS::isDirectoryInode(unsigned inode) const Vector Ext2FS::allocateBlocks(unsigned group, unsigned count) { - kprintf("ext2fs: allocateBlocks(group: %u, count: %u)\n", group, count); + dbgprintf("Ext2FS: allocateBlocks(group: %u, count: %u)\n", group, count); auto& bgd = blockGroupDescriptor(group); if (bgd.bg_free_blocks_count < count) { - kprintf("ext2fs: allocateBlocks can't allocate out of group %u, wanted %u but only %u available\n", group, count, bgd.bg_free_blocks_count); + kprintf("ExtFS: allocateBlocks can't allocate out of group %u, wanted %u but only %u available\n", group, count, bgd.bg_free_blocks_count); return { }; } @@ -833,9 +808,9 @@ Vector Ext2FS::allocateBlocks(unsigned group, unsigned count } return true; }); - kprintf("ext2fs: allocateBlock found these blocks:\n"); + dbgprintf("Ext2FS: allocateBlock found these blocks:\n"); for (auto& bi : blocks) { - kprintf(" > %u\n", bi); + dbgprintf(" > %u\n", bi); } return blocks; @@ -843,11 +818,11 @@ Vector Ext2FS::allocateBlocks(unsigned group, unsigned count unsigned Ext2FS::allocateInode(unsigned preferredGroup, unsigned expectedSize) { - kprintf("ext2fs: allocateInode(preferredGroup: %u, expectedSize: %u)\n", preferredGroup, expectedSize); + dbgprintf("Ext2FS: allocateInode(preferredGroup: %u, expectedSize: %u)\n", preferredGroup, expectedSize); unsigned neededBlocks = ceilDiv(expectedSize, blockSize()); - kprintf("ext2fs: minimum needed blocks: %u\n", neededBlocks); + dbgprintf("Ext2FS: minimum needed blocks: %u\n", neededBlocks); unsigned groupIndex = 0; @@ -866,11 +841,11 @@ unsigned Ext2FS::allocateInode(unsigned preferredGroup, unsigned expectedSize) } if (!groupIndex) { - kprintf("ext2fs: allocateInode: no suitable group found for new inode with %u blocks needed :(\n", neededBlocks); + kprintf("Ext2FS: allocateInode: no suitable group found for new inode with %u blocks needed :(\n", neededBlocks); return 0; } - kprintf("ext2fs: allocateInode: found suitable group [%u] for new inode with %u blocks needed :^)\n", groupIndex, neededBlocks); + dbgprintf("Ext2FS: allocateInode: found suitable group [%u] for new inode with %u blocks needed :^)\n", groupIndex, neededBlocks); unsigned firstFreeInodeInGroup = 0; traverseInodeBitmap(groupIndex, [&firstFreeInodeInGroup] (unsigned firstInodeInBitmap, const Bitmap& bitmap) { @@ -884,12 +859,12 @@ unsigned Ext2FS::allocateInode(unsigned preferredGroup, unsigned expectedSize) }); if (!firstFreeInodeInGroup) { - kprintf("ext2fs: firstFreeInodeInGroup returned no inode, despite bgd claiming there are inodes :(\n"); + kprintf("Ext2FS: firstFreeInodeInGroup returned no inode, despite bgd claiming there are inodes :(\n"); return 0; } unsigned inode = firstFreeInodeInGroup; - kprintf("ext2fs: found suitable inode %u\n", inode); + dbgprintf("Ext2FS: found suitable inode %u\n", inode); // FIXME: allocate blocks if needed! @@ -915,7 +890,7 @@ bool Ext2FS::setInodeAllocationState(unsigned inode, bool newState) ASSERT(block); auto bitmap = Bitmap::wrap(block.pointer(), block.size()); bool currentState = bitmap.get(bitIndex); - kprintf("ext2fs: setInodeAllocationState(%u) %u -> %u\n", inode, currentState, newState); + dbgprintf("ext2fs: setInodeAllocationState(%u) %u -> %u\n", inode, currentState, newState); if (currentState == newState) return true; @@ -925,7 +900,7 @@ bool Ext2FS::setInodeAllocationState(unsigned inode, bool newState) // Update superblock auto& sb = *reinterpret_cast(m_cachedSuperBlock.pointer()); - kprintf("ext2fs: superblock free inode count %u -> %u\n", sb.s_free_inodes_count, sb.s_free_inodes_count - 1); + dbgprintf("Ext2FS: superblock free inode count %u -> %u\n", sb.s_free_inodes_count, sb.s_free_inodes_count - 1); if (newState) --sb.s_free_inodes_count; else @@ -938,7 +913,7 @@ bool Ext2FS::setInodeAllocationState(unsigned inode, bool newState) --mutableBGD.bg_free_inodes_count; else ++mutableBGD.bg_free_inodes_count; - kprintf("ext2fs: group free inode count %u -> %u\n", bgd.bg_free_inodes_count, bgd.bg_free_inodes_count - 1); + 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; @@ -959,7 +934,7 @@ bool Ext2FS::setBlockAllocationState(GroupIndex group, BlockIndex bi, bool newSt ASSERT(block); auto bitmap = Bitmap::wrap(block.pointer(), block.size()); bool currentState = bitmap.get(bitIndex); - kprintf("ext2fs: setBlockAllocationState(%u) %u -> %u\n", bi, currentState, newState); + dbgprintf("Ext2FS: setBlockAllocationState(%u) %u -> %u\n", bi, currentState, newState); if (currentState == newState) return true; @@ -969,7 +944,7 @@ bool Ext2FS::setBlockAllocationState(GroupIndex group, BlockIndex bi, bool newSt // Update superblock auto& sb = *reinterpret_cast(m_cachedSuperBlock.pointer()); - kprintf("ext2fs: superblock free block count %u -> %u\n", sb.s_free_blocks_count, sb.s_free_blocks_count - 1); + dbgprintf("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 @@ -982,7 +957,7 @@ bool Ext2FS::setBlockAllocationState(GroupIndex group, BlockIndex bi, bool newSt --mutableBGD.bg_free_blocks_count; else ++mutableBGD.bg_free_blocks_count; - kprintf("ext2fs: group free block count %u -> %u\n", bgd.bg_free_blocks_count, bgd.bg_free_blocks_count - 1); + 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; @@ -991,7 +966,7 @@ bool Ext2FS::setBlockAllocationState(GroupIndex group, BlockIndex bi, bool newSt return true; } -InodeIdentifier Ext2FS::create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t mode) +InodeIdentifier Ext2FS::create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t mode, int& error) { ASSERT(parentInode.fsid() == id()); ASSERT(isDirectoryInode(parentInode.index())); @@ -1003,11 +978,11 @@ InodeIdentifier Ext2FS::create_directory(InodeIdentifier parentInode, const Stri // 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 = create_inode(parentInode, name, mode, blockSize()); + auto inode = create_inode(parentInode, name, mode, blockSize(), error); if (!inode.isValid()) return { }; - kprintf("ext2fs: makeDirectory: created new directory named '%s' with inode %u\n", name.characters(), inode.index()); + dbgprintf("Ext2FS: create_directory: created new directory named '%s' with inode %u\n", name.characters(), inode.index()); Vector entries; entries.append({ ".", inode, EXT2_FT_DIR }); @@ -1021,34 +996,35 @@ InodeIdentifier Ext2FS::create_directory(InodeIdentifier parentInode, const Stri auto& bgd = const_cast(blockGroupDescriptor(groupIndexFromInode(inode.index()))); ++bgd.bg_used_dirs_count; - kprintf("ext2fs: incremented bg_used_dirs_count %u -> %u\n", bgd.bg_used_dirs_count - 1, 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_cachedBlockGroupDescriptorTable); + error = 0; return inode; } -InodeIdentifier Ext2FS::create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t mode, unsigned size) +InodeIdentifier Ext2FS::create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t mode, unsigned size, int& error) { ASSERT(parentInode.fsid() == id()); ASSERT(isDirectoryInode(parentInode.index())); -//#ifdef EXT2_DEBUG - kprintf("ext2fs: Adding inode '%s' (mode %o) to parent directory %u:\n", name.characters(), mode, parentInode.index()); -//#endif + dbgprintf("Ext2FS: Adding inode '%s' (mode %o) to parent directory %u:\n", name.characters(), mode, parentInode.index()); // NOTE: This doesn't commit the inode allocation just yet! auto inode = allocateInode(0, 0); if (!inode) { - kprintf("ext2fs: createInode: allocateInode failed\n"); + kprintf("Ext2FS: createInode: allocateInode failed\n"); + error = -ENOSPC; return { }; } auto blocks = allocateBlocks(groupIndexFromInode(inode), ceilDiv(size, blockSize())); if (blocks.isEmpty()) { - kprintf("ext2fs: createInode: allocateBlocks failed\n"); + kprintf("Ext2FS: createInode: allocateBlocks failed\n"); + error = -ENOSPC; return { }; } @@ -1069,11 +1045,9 @@ InodeIdentifier Ext2FS::create_inode(InodeIdentifier parentInode, const String& fileType = EXT2_FT_SYMLINK; // Try adding it to the directory first, in case the name is already in use. - bool success = addInodeToDirectory(parentInode.index(), inode, name, fileType); - if (!success) { - kprintf("ext2fs: failed to add inode to directory :(\n"); + bool success = addInodeToDirectory(parentInode.index(), inode, name, fileType, error); + if (!success) return { }; - } // Looks like we're good, time to update the inode bitmap and group+global inode counters. success = setInodeAllocationState(inode, true); @@ -1107,7 +1081,7 @@ InodeIdentifier Ext2FS::create_inode(InodeIdentifier parentInode, const String& // FIXME: Implement writing out indirect blocks! ASSERT(blocks.size() < EXT2_NDIR_BLOCKS); - kprintf("[XXX] writing %zu blocks to i_block array\n", min((size_t)EXT2_NDIR_BLOCKS, blocks.size())); + dbgprintf("Ext2FS: writing %zu blocks to i_block array\n", min((size_t)EXT2_NDIR_BLOCKS, blocks.size())); for (unsigned i = 0; i < min((size_t)EXT2_NDIR_BLOCKS, blocks.size()); ++i) { e2inode->i_block[i] = blocks[i]; } diff --git a/VirtualFileSystem/Ext2FileSystem.h b/VirtualFileSystem/Ext2FileSystem.h index c24974b33c..194451e079 100644 --- a/VirtualFileSystem/Ext2FileSystem.h +++ b/VirtualFileSystem/Ext2FileSystem.h @@ -51,9 +51,6 @@ private: typedef unsigned BlockIndex; typedef unsigned GroupIndex; typedef unsigned InodeIndex; - class CachedExt2Inode; - class CachedExt2InodeImpl; - explicit Ext2FS(RetainPtr&&); const ext2_super_block& superBlock() const; @@ -64,7 +61,7 @@ private: unsigned blocksPerGroup() const; unsigned inodeSize() const; - CachedExt2Inode lookupExt2Inode(unsigned) const; + OwnPtr lookupExt2Inode(unsigned) const; bool writeExt2Inode(unsigned, const ext2_inode&); ByteBuffer readBlockContainingInode(unsigned inode, unsigned& blockIndex, unsigned& offset) const; @@ -76,9 +73,9 @@ private: virtual bool writeInode(InodeIdentifier, const ByteBuffer&) override; virtual InodeMetadata inodeMetadata(InodeIdentifier) const override; virtual bool set_mtime(InodeIdentifier, dword timestamp) override; - virtual InodeIdentifier create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size) override; + virtual InodeIdentifier create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size, int& error) override; virtual Unix::ssize_t read_inode_bytes(InodeIdentifier, Unix::off_t offset, Unix::size_t count, byte* buffer, FileDescriptor*) const override; - virtual InodeIdentifier create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t) override; + virtual InodeIdentifier create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t, int& error) override; virtual InodeIdentifier find_parent_of_inode(InodeIdentifier) const override; virtual RetainPtr get_inode(InodeIdentifier) const override; @@ -95,7 +92,7 @@ private: template void traverseInodeBitmap(unsigned groupIndex, F) const; template void traverseBlockBitmap(unsigned groupIndex, F) const; - bool addInodeToDirectory(unsigned directoryInode, unsigned inode, const String& name, byte fileType); + bool addInodeToDirectory(unsigned directoryInode, unsigned inode, const String& name, byte fileType, int& error); bool writeDirectoryInode(unsigned directoryInode, Vector&&); bool setInodeAllocationState(unsigned inode, bool); bool setBlockAllocationState(GroupIndex, BlockIndex, bool); @@ -109,9 +106,6 @@ private: mutable ByteBuffer m_cachedSuperBlock; mutable ByteBuffer m_cachedBlockGroupDescriptorTable; - mutable SpinLock m_inodeCacheLock; - mutable HashMap> m_inodeCache; - mutable SpinLock m_inode_cache_lock; mutable HashMap> m_inode_cache; }; diff --git a/VirtualFileSystem/FileSystem.cpp b/VirtualFileSystem/FileSystem.cpp index 7941e0b2a7..e454fd352b 100644 --- a/VirtualFileSystem/FileSystem.cpp +++ b/VirtualFileSystem/FileSystem.cpp @@ -107,7 +107,7 @@ ByteBuffer FS::readEntireInode(InodeIdentifier inode, FileDescriptor* handle) co } FS::DirectoryEntry::DirectoryEntry(const char* n, InodeIdentifier i, byte ft) - : name_length(strlen(name)) + : name_length(strlen(n)) , inode(i) , fileType(ft) { diff --git a/VirtualFileSystem/FileSystem.h b/VirtualFileSystem/FileSystem.h index eedcb0f9ed..2245fd650d 100644 --- a/VirtualFileSystem/FileSystem.h +++ b/VirtualFileSystem/FileSystem.h @@ -45,8 +45,8 @@ public: }; virtual bool set_mtime(InodeIdentifier, dword timestamp) = 0; - virtual InodeIdentifier create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size) = 0; - virtual InodeIdentifier create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t) = 0; + virtual InodeIdentifier create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size, int& error) = 0; + virtual InodeIdentifier create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t, int& error) = 0; virtual InodeIdentifier find_parent_of_inode(InodeIdentifier) const = 0; diff --git a/VirtualFileSystem/SyntheticFileSystem.cpp b/VirtualFileSystem/SyntheticFileSystem.cpp index 97ba97386b..d6498288d7 100644 --- a/VirtualFileSystem/SyntheticFileSystem.cpp +++ b/VirtualFileSystem/SyntheticFileSystem.cpp @@ -1,5 +1,6 @@ #include "SyntheticFileSystem.h" #include "FileDescriptor.h" +#include #include #ifndef SERENITY @@ -152,13 +153,14 @@ bool SynthFS::set_mtime(InodeIdentifier, dword timestamp) return false; } -InodeIdentifier SynthFS::create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t mode, unsigned size) +InodeIdentifier SynthFS::create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t mode, unsigned size, int& error) { (void) parentInode; (void) name; (void) mode; (void) size; - kprintf("FIXME: Implement SyntheticFileSystem::createDirectoryInode().\n"); + (void) error; + kprintf("FIXME: Implement SyntheticFileSystem::create_inode().\n"); return { }; } @@ -205,11 +207,9 @@ Unix::ssize_t SynthFS::read_inode_bytes(InodeIdentifier inode, Unix::off_t offse return nread; } -InodeIdentifier SynthFS::create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t) +InodeIdentifier SynthFS::create_directory(InodeIdentifier, const String&, Unix::mode_t, int& error) { - (void) parentInode; - (void) name; - kprintf("FIXME: Implement SyntheticFileSystem::makeDirectory().\n"); + error = -EROFS; return { }; } diff --git a/VirtualFileSystem/SyntheticFileSystem.h b/VirtualFileSystem/SyntheticFileSystem.h index 8a675d1def..f5b528b028 100644 --- a/VirtualFileSystem/SyntheticFileSystem.h +++ b/VirtualFileSystem/SyntheticFileSystem.h @@ -17,9 +17,9 @@ public: virtual bool writeInode(InodeIdentifier, const ByteBuffer&) override; virtual InodeMetadata inodeMetadata(InodeIdentifier) const override; virtual bool set_mtime(InodeIdentifier, dword timestamp) override; - virtual InodeIdentifier create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size) override; + virtual InodeIdentifier create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size, int& error) override; virtual Unix::ssize_t read_inode_bytes(InodeIdentifier, Unix::off_t offset, Unix::size_t count, byte* buffer, FileDescriptor*) const override; - virtual InodeIdentifier create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t) override; + virtual InodeIdentifier create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t, int& error) override; virtual InodeIdentifier find_parent_of_inode(InodeIdentifier) const override; virtual RetainPtr get_inode(InodeIdentifier) const override; diff --git a/VirtualFileSystem/VirtualFileSystem.cpp b/VirtualFileSystem/VirtualFileSystem.cpp index d1e6e5ad80..34504dfa21 100644 --- a/VirtualFileSystem/VirtualFileSystem.cpp +++ b/VirtualFileSystem/VirtualFileSystem.cpp @@ -1,6 +1,7 @@ #include "VirtualFileSystem.h" #include "FileDescriptor.h" #include "FileSystem.h" +#include #include #include #include @@ -419,22 +420,34 @@ RetainPtr VFS::open(const String& path, int& error, int options, return FileDescriptor::create(move(vnode)); } -RetainPtr VFS::create(const String& path, InodeIdentifier base) +RetainPtr VFS::create(const String& path, InodeIdentifier base, int& error) { // FIXME: Do the real thing, not just this fake thing! (void) path; (void) base; - m_root_vnode->fileSystem()->create_inode(m_root_vnode->fileSystem()->rootInode(), "empty", 0100644, 0); + m_root_vnode->fileSystem()->create_inode(m_root_vnode->fileSystem()->rootInode(), "empty", 0100644, 0, error); return nullptr; } -RetainPtr VFS::mkdir(const String& path, InodeIdentifier base) +bool VFS::mkdir(const String& path, mode_t mode, InodeIdentifier base, int& error) { - // FIXME: Do the real thing, not just this fake thing! - (void) path; - (void) base; - m_root_vnode->fileSystem()->create_directory(m_root_vnode->fileSystem()->rootInode(), "mydir", 0400755); - return nullptr; + error = EWHYTHO; + // FIXME: This won't work nicely across mount boundaries. + FileSystemPath p(path); + if (!p.isValid()) { + error = -EINVAL; + return false; + } + dbgprintf("VFS::mkdir: '%s' in '%s'\n", p.basename().characters(), p.dirname().characters()); + auto parent_dir = resolve_path(p.dirname(), error, m_root_vnode->inode); + if (!parent_dir.isValid()) + return false; + auto new_dir = base.fileSystem()->create_directory(parent_dir, p.basename(), mode, error); + if (new_dir.isValid()) { + error = 0; + return true; + } + return false; } InodeIdentifier VFS::resolveSymbolicLink(InodeIdentifier base, InodeIdentifier symlinkInode, int& error) diff --git a/VirtualFileSystem/VirtualFileSystem.h b/VirtualFileSystem/VirtualFileSystem.h index a5c49b680e..a85f09c2c7 100644 --- a/VirtualFileSystem/VirtualFileSystem.h +++ b/VirtualFileSystem/VirtualFileSystem.h @@ -115,8 +115,8 @@ public: RetainPtr open(CharacterDevice&, int options); RetainPtr open(const String& path, int& error, int options = 0, InodeIdentifier base = InodeIdentifier()); - RetainPtr create(const String& path, InodeIdentifier base = InodeIdentifier()); - RetainPtr mkdir(const String& path, InodeIdentifier base = InodeIdentifier()); + RetainPtr create(const String& path, InodeIdentifier base, int& error); + bool mkdir(const String& path, mode_t mode, InodeIdentifier base, int& error); bool touch(const String&path); @@ -136,7 +136,6 @@ private: bool is_vfs_root(InodeIdentifier) const; void traverse_directory_inode(CoreInode&, Function); - InodeIdentifier resolve_path(const String& path, int& error, CoreInode& base, int options = 0); InodeIdentifier resolve_path(const String& path, int& error, InodeIdentifier base = InodeIdentifier(), int options = 0); InodeIdentifier resolveSymbolicLink(InodeIdentifier base, InodeIdentifier symlinkInode, int& error);