From bca4b71bfa1e3db74aaa706a9849e36768282a95 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 24 Oct 2018 12:43:52 +0200 Subject: [PATCH] Lots of hacking to make a very simple "ls" utility. I added a dead-simple malloc that only allows allocations < 4096 bytes. It just forwards the request to mmap() every time. I also added simplified versions of opendir() and readdir(). --- AK/BufferStream.h | 54 +++++++++++++++++++ Kernel/ProcFileSystem.cpp | 7 +-- Kernel/Syscall.cpp | 2 + Kernel/Syscall.h | 1 + Kernel/Task.cpp | 16 ++++++ Kernel/Task.h | 3 ++ Kernel/_fs_contents | Bin 1024000 -> 1024000 bytes LibC/Makefile | 2 + LibC/dirent.cpp | 67 ++++++++++++++++++++++++ LibC/dirent.h | 27 ++++++++++ LibC/stdlib.cpp | 24 +++++++++ LibC/stdlib.h | 11 ++++ LibC/types.h | 3 ++ Userland/ls.cpp | 18 +++---- VirtualFileSystem/Ext2FileSystem.cpp | 44 +--------------- VirtualFileSystem/FileHandle.cpp | 29 +++++++++- VirtualFileSystem/FileHandle.h | 2 + VirtualFileSystem/VirtualFileSystem.cpp | 19 +++++-- VirtualFileSystem/VirtualFileSystem.h | 15 ++++-- 19 files changed, 277 insertions(+), 67 deletions(-) create mode 100644 AK/BufferStream.h create mode 100644 LibC/dirent.cpp create mode 100644 LibC/dirent.h create mode 100644 LibC/stdlib.cpp create mode 100644 LibC/stdlib.h diff --git a/AK/BufferStream.h b/AK/BufferStream.h new file mode 100644 index 00000000000..379fcb57926 --- /dev/null +++ b/AK/BufferStream.h @@ -0,0 +1,54 @@ +#pragma once + +#include "ByteBuffer.h" + +namespace AK { + +class BufferStream { +public: + explicit BufferStream(ByteBuffer& buffer) + : m_buffer(buffer) + { + } + + void operator<<(byte value) + { + m_buffer[m_offset++] = value & 0xffu; + } + + void operator<<(word value) + { + m_buffer[m_offset++] = value & 0xffu; + m_buffer[m_offset++] = (byte)(value >> 8) & 0xffu; + } + + void operator<<(dword value) + { + m_buffer[m_offset++] = value & 0xffu; + m_buffer[m_offset++] = (byte)(value >> 8) & 0xffu; + m_buffer[m_offset++] = (byte)(value >> 16) & 0xffu; + m_buffer[m_offset++] = (byte)(value >> 24) & 0xffu; + } + + void operator<<(const String& value) + { + for (unsigned i = 0; i < value.length(); ++i) + m_buffer[m_offset++] = value[i]; + } + + void fillToEnd(byte ch) + { + while (m_offset < m_buffer.size()) + m_buffer[m_offset++] = ch; + } + + Unix::size_t offset() const { return m_offset; } + +private: + ByteBuffer& m_buffer; + Unix::size_t m_offset { 0 }; +}; + +} + +using AK::BufferStream; diff --git a/Kernel/ProcFileSystem.cpp b/Kernel/ProcFileSystem.cpp index 57d7493fd1c..039d8c897d4 100644 --- a/Kernel/ProcFileSystem.cpp +++ b/Kernel/ProcFileSystem.cpp @@ -21,17 +21,18 @@ bool ProcFileSystem::initialize() InterruptDisabler disabler; auto tasks = Task::allTasks(); char* buffer; - auto stringImpl = StringImpl::createUninitialized(tasks.size() * 128, buffer); + auto stringImpl = StringImpl::createUninitialized(tasks.size() * 256, buffer); memset(buffer, 0, stringImpl->length()); char* ptr = buffer; - ptr += ksprintf(ptr, "PID OWNER STATE NSCHED NAME\n"); + ptr += ksprintf(ptr, "PID OWNER STATE NSCHED FDS NAME\n"); for (auto* task : tasks) { - ptr += ksprintf(ptr, "%w %w:%w %b %w %s\n", + ptr += ksprintf(ptr, "%w %w:%w %b %w %w %s\n", task->pid(), task->uid(), task->gid(), task->state(), task->timesScheduled(), + task->fileHandleCount(), task->name().characters()); } ptr += ksprintf(ptr, "kmalloc: alloc: %u / free: %u\n", sum_alloc, sum_free); diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index 1e70f9a5101..4be04cbfac1 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -66,6 +66,8 @@ DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3) break; case Syscall::Spawn: return current->sys$spawn((const char*)arg1); + case Syscall::GetDirEntries: + return current->sys$get_dir_entries((int)arg1, (void*)arg2, (size_t)arg3); case Syscall::PosixOpen: //kprintf("syscall: open('%s', %u)\n", arg1, arg2); return current->sys$open((const char*)arg1, (size_t)arg2); diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index 22f6fb3812a..70b3f12983d 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -26,6 +26,7 @@ enum Function { PosixWaitpid = 0x1994, PosixMmap = 0x1995, PosixMunmap = 0x1996, + GetDirEntries = 0x1997, }; void initialize(); diff --git a/Kernel/Task.cpp b/Kernel/Task.cpp index 331be38ffbb..fe185cc154f 100644 --- a/Kernel/Task.cpp +++ b/Kernel/Task.cpp @@ -230,6 +230,10 @@ Task::Task(String&& name, uid_t uid, gid_t gid) , m_state(Runnable) , m_ring(Ring3) { + m_fileHandles.append(nullptr); + m_fileHandles.append(nullptr); + m_fileHandles.append(nullptr); + m_nextRegion = LinearAddress(0x600000); memset(&m_tss, 0, sizeof(m_tss)); @@ -280,6 +284,10 @@ Task::Task(void (*e)(), const char* n, IPC::Handle h, RingLevel ring) , m_state(Runnable) , m_ring(ring) { + m_fileHandles.append(nullptr); + m_fileHandles.append(nullptr); + m_fileHandles.append(nullptr); + m_nextRegion = LinearAddress(0x600000); Region* codeRegion = nullptr; @@ -643,6 +651,14 @@ FileHandle* Task::fileHandleIfExists(int fd) return nullptr; } +ssize_t Task::sys$get_dir_entries(int fd, void* buffer, size_t size) +{ + auto* handle = fileHandleIfExists(fd); + if (!handle) + return -1; + return handle->get_dir_entries((byte*)buffer, size); +} + int Task::sys$seek(int fd, int offset) { auto* handle = fileHandleIfExists(fd); diff --git a/Kernel/Task.h b/Kernel/Task.h index f79ccc267d4..8ff28a00eda 100644 --- a/Kernel/Task.h +++ b/Kernel/Task.h @@ -101,6 +101,7 @@ public: pid_t sys$waitpid(pid_t); void* sys$mmap(void*, size_t size); int sys$munmap(void*, size_t size); + int sys$get_dir_entries(int fd, void*, size_t); struct { @@ -122,6 +123,8 @@ public: pid_t waitee() const { return m_waitee; } + size_t fileHandleCount() const { return m_fileHandles.size(); } + private: friend class MemoryManager; diff --git a/Kernel/_fs_contents b/Kernel/_fs_contents index 315825570efed2d33dad720c6d561cae18cbe31b..25f45186bf0759cb69e983cecd678b2f6563db67 100644 GIT binary patch delta 5019 zcmeI0YfN0n6~||mUHdMteehaL;$4h^#n^Q_fCg9YuA+TUWRMI-wtOFIVz}gM9 zE3nqyutr3{m3;fbwn*aIsnklLP(xF-T?^Nio3_DKK18YOI;tZ-)uwIK(u!pJpV`^< z&DDlReW{f?(qZPDGv~}>XXgIwq2Sh`;MUg@^>j>5(%X%BwF@mw%BIWoRaBR&pQ3)< zgp^3frjw+P}FuEAr443WDO(- zvQ~B#=gVy+uWisq#;YQCqP+`J1F3~PHBJks+cr9N%SPoQe;y zHbUNA6J8-37b#IFNe(yoZ0pdjhqxgPkVeRE$e!tooA#cbbv!HGOu4WiIc%>w9;6C& zNphr?oU))7N-6*ABy z9d0=u^rkg5_<{-b?P-x-zDwr&H(kL|&tl8oFV2otOY2q)Hu@e&JixaY@)iZ==k$@@ z0o#=!Guv^LD?_Q#mQA$o>s&$KC8-5Nn~t4BC*S6f>DXyBni}1K%f2}td~p37F-K;3 zG2my$k@PtwlaTMjF-U$k6!5d;ftOg~5kLQXl3C(Tvd-lThxD%C{p};>K$HGNy?(eU z`N|U#o7BkDhS5gjfk0ED>lY(C4CU7jC7h@+8;5JsO^@II?d9rZ6B(&Dj8>bC0iJdA z3H=vZzBKO&&TnB;I<)e#A!+r(${=}zsjlE%wv*Vmc&>Bp&CQ2lm{LwG>DBE{Q zYtnmqJ>6{`eU1aI9i5&wM};$<%uF1x$AmQo-sCgghzi?3ZQs9ZW}%0lyH%E)|Qq zS=8;Kz94Eh>z_f0P3SxKh{hpN9~1RuQ5)DmWnyCM31J6Nhni2ch!D1MI?PgHwTocO zQI}4?@#pKbvCq?4&kl-G@pJ$$=)sH8$W=vm^JP+#z2aW`{ z!ow!5hp^e z7X4V}d`JQ$GSWEO>XD|9VHM9X3XeKNyD9?~6V337Cc~S^U}71{*~L+3=v8IFmo}PV zN|WJT<-O;njPh@5!e3B@TU6mc)Pyg}t+z9jB@4xCt+>5XhUFbi4~d)8?rO|tY)}?o z`}^>yXFjAFnjN~x?tQ4qP>2jRmcbIzc&cRgoeWC?wpzX0wcMJiu{O&u-^obJ(^x&o zZDzUCTpG{8sAsG2;PUcv9G*<2)k;&WO~QpM#ml55|NNu$iUyd~D;>s4*?Yy#i5(JI zX@@3!iHDbaG~wIuyGFvZRpA4g@TXv*m`V z?F_@55za(mL;<1wy9j6#1FKjF^e-YH+48G5bHo$xc&^9m$UW%TH{kX3J9-W{*f({* zx2JC)JARx#s?C@n8qXwP|1UwaK z;0g8}*vNkho;(7QmW8KH0+u!ictX9M4UB*F>_pAriNn-m0;bjpn8JqypL4+1e+Z_Y zQ9e$l3Guj|Mg87BSCLD(wpsE;2uqKT6C*5VEW-L6oQ$QMikh%GBUX6WN+RF0F0}Ff zdcF8|w#Ij4-t5~GITQo( zwYw>D>Alpn2t`GpZ^($(heMy`430QEZF8KZv&jRgNp NqJJjo+)VO=zX3^su4e!M delta 3179 zcmb_eeQZ-z6u+lyXS=U{ZR;kmzOq6aHO`tT=1HRI>aoP7&0jYG#cke)I?(>*&k>yZaQRy#SAqD#zy_!*LFVYBqVy1^Ul5J zoZor(-FJTHz0Sdk&cTX-G(ClQy54E}e*U)`q!fq!`g=%sFzH?D)*UdWQ7D{lyk^!# zc7|w~KGGF2Lx*?d?9cVZAxs^_(xMYa(0<5L$lZ`-kWxrlh&;Su@v%jTz!W&;kig}T za>xou1!QH23c?Lbyt-SWa&(O4Lhgjjfz0K;;sQSE?<;*Jld<^yq((}Nn>T9(!UnNJ zG9g)zY-I3+N0*krc2pTFv=^GAz!Ft?nTsjmB}3E6^LjpAu{W2oc3anYT2MO2rXrDu zIkoFEOV2q`+(J9J^~zV79l=1G(iUt~f{o41E0v}GCH|BUDPn&sy(!kbZ9E{3-A5Ka z{KIxpzLoAvwXw&eH)MX%yOsQ86>ICsi4gOTRbrr?Dl2jjKpBk9gVrr%tT49r$#ouM z4@y0kv4GU`8QT)`Z&Upudn0YiUBK`pNMmCR8B~~2>ipC1r;<&Vw6(EWjIXA7qH-HO zCC+a#rruHXOxsppkx!gmW?aPwuayg>gWRTfQW>iRGLMITZZVBxRV-JcX1&qLy`x^! zTvSKYbVQoAkM`xRhDqKHdsS;k4=vY6x$lCV{NmjVvX{OAg9%azkz+kT7HA2=!?QT( zIOei`k|A=`@X!T^^?l5=)(wIlHabLcyU{{TeB^?o^b162^EYTVg;SZye=e43F|-_e zx$hT;bpkV)9|fb1uSKAd9A)EJXp=T0=^5DMrn4aNO(y}Xg?o+S8!Kg(MiTJu^uO^A z4c?xB-z`FQMn{$_W{&UmAWk()1Zv4{^~YRE$Rfwv+;!1mT@I@}`J1hku~;=wjoot5 zV|oXHop@d+KXTD&D8!rY6j#{v@;T)s1#J5%3u8^a8(vtiw}!zZT$*Zw0~GaR9V2)_CImtDjd*JF@Z zqg_q*FS*Hh8-9|9rX8hs!=$~P{D#Xall!|967Rxm63`z=^oj=)(4!i(>>+VF6eux!bflTHjNnRK4J#&(mF_m7pQ{RBkURo(NJ>gtF2 zuVcm3&z+abcGmSC8oLpR)b#EWfY0~H)X^Z{;H77gwYTw)4fPwJ=-qU6 uMUQY- +#include "stdio.h" + +extern "C" { + +DIR* opendir(const char* name) +{ + // FIXME: Should fail if it's not a directory! + int fd = open(name); + if (fd == -1) + return nullptr; + DIR* dirp = (DIR*)malloc(sizeof(dirp)); + dirp->fd = fd; + dirp->buffer = nullptr; + dirp->buffer_size = 0; + dirp->nextptr = nullptr; + return dirp; +} + +struct sys_dirent { + ino_t ino; + byte file_type; + size_t namelen; + char name[]; + size_t total_size() + { + return sizeof(ino_t) + sizeof(byte) + sizeof(size_t) + sizeof(char) * namelen; + } +} __attribute__ ((packed)); + +dirent* readdir(DIR* dirp) +{ + if (!dirp) + return nullptr; + if (dirp->fd == -1) + return nullptr; + + if (!dirp->buffer) { + // FIXME: Figure out how much to actually allocate. + dirp->buffer = (char*)malloc(4096); + ssize_t nread = Syscall::invoke(Syscall::GetDirEntries, (dword)dirp->fd, (dword)dirp->buffer, 4096); + dirp->buffer_size = nread; + dirp->nextptr = dirp->buffer; + } + + if (dirp->nextptr > (dirp->buffer + dirp->buffer_size)) + return nullptr; + + auto* sys_ent = (sys_dirent*)dirp->nextptr; + dirp->cur_ent.d_ino = sys_ent->ino; + dirp->cur_ent.d_type = sys_ent->file_type; + dirp->cur_ent.d_off = 0; + dirp->cur_ent.d_reclen = sys_ent->total_size(); + for (size_t i = 0; i < sys_ent->namelen; ++i) + dirp->cur_ent.d_name[i] = sys_ent->name[i]; + // FIXME: I think this null termination behavior is not supposed to be here. + dirp->cur_ent.d_name[sys_ent->namelen] = '\0'; + + dirp->nextptr += sys_ent->total_size(); + return &dirp->cur_ent; +} + +} + diff --git a/LibC/dirent.h b/LibC/dirent.h new file mode 100644 index 00000000000..be069d81335 --- /dev/null +++ b/LibC/dirent.h @@ -0,0 +1,27 @@ +#pragma once + +#include "types.h" + +extern "C" { + +struct dirent { + ino_t d_ino; + off_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[256]; +}; + +struct DIR { + int fd; + dirent cur_ent; + char* buffer; + size_t buffer_size; + char* nextptr; +}; + +DIR* opendir(const char* name); +dirent* readdir(DIR* dirp); + +} + diff --git a/LibC/stdlib.cpp b/LibC/stdlib.cpp new file mode 100644 index 00000000000..7d0f1b5e8fc --- /dev/null +++ b/LibC/stdlib.cpp @@ -0,0 +1,24 @@ +#include "stdlib.h" +#include "mman.h" + +extern "C" { + +void* malloc(size_t size) +{ + if (size > 4096) { + volatile char* crashme = (char*)0xc007d00d; + *crashme = 0; + } + void* ptr = mmap(nullptr, 4096); + return ptr; +} + +void free(void* ptr) +{ + if (!ptr) + return; + munmap(ptr, 4096); +} + +} + diff --git a/LibC/stdlib.h b/LibC/stdlib.h new file mode 100644 index 00000000000..55cd47c9f75 --- /dev/null +++ b/LibC/stdlib.h @@ -0,0 +1,11 @@ +#pragma once + +#include "types.h" + +extern "C" { + +void* malloc(size_t); +void free(void*); + +} + diff --git a/LibC/types.h b/LibC/types.h index fc990e79f74..cedc52280cf 100644 --- a/LibC/types.h +++ b/LibC/types.h @@ -17,5 +17,8 @@ typedef dword pid_t; typedef dword size_t; typedef signed_dword ssize_t; +typedef dword ino_t; +typedef signed_dword off_t; + } diff --git a/Userland/ls.cpp b/Userland/ls.cpp index f6a90568b9f..dfaa0d4eb22 100644 --- a/Userland/ls.cpp +++ b/Userland/ls.cpp @@ -1,21 +1,17 @@ #include #include -#include +#include int main(int c, char** v) { - int fd = open("/"); - if (fd == -1) { - printf("failed to open / :(\n"); + DIR* dirp = opendir("/"); + if (!dirp) { + printf("opendir failed :(\n"); return 1; } + while (auto* de = readdir(dirp)) { + printf("%s\n", de->d_name); - byte* memory = (byte*)mmap(nullptr, 16384); - printf("%p\n", memory); - memory[0] = 'H'; - memory[1] = 'i'; - memory[2] = '!'; - memory[3] = '\0'; - printf("%p : %s\n", memory, memory); + } return 0; } diff --git a/VirtualFileSystem/Ext2FileSystem.cpp b/VirtualFileSystem/Ext2FileSystem.cpp index 8e0dc9b87bf..53fa6a3b663 100644 --- a/VirtualFileSystem/Ext2FileSystem.cpp +++ b/VirtualFileSystem/Ext2FileSystem.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "sys-errno.h" //#define EXT2_DEBUG @@ -431,49 +432,6 @@ bool Ext2FileSystem::addInodeToDirectory(unsigned directoryInode, unsigned inode return writeDirectoryInode(directoryInode, move(entries)); } -class BufferStream { -public: - explicit BufferStream(ByteBuffer& buffer) - : m_buffer(buffer) - { - } - - void operator<<(byte value) - { - m_buffer[m_offset++] = value & 0xffu; - } - - void operator<<(word value) - { - m_buffer[m_offset++] = value & 0xffu; - m_buffer[m_offset++] = (byte)(value >> 8) & 0xffu; - } - - void operator<<(dword value) - { - m_buffer[m_offset++] = value & 0xffu; - m_buffer[m_offset++] = (byte)(value >> 8) & 0xffu; - m_buffer[m_offset++] = (byte)(value >> 16) & 0xffu; - m_buffer[m_offset++] = (byte)(value >> 24) & 0xffu; - } - - void operator<<(const String& value) - { - for (unsigned i = 0; i < value.length(); ++i) - m_buffer[m_offset++] = value[i]; - } - - void fillToEnd(byte ch) - { - while (m_offset < m_buffer.size()) - m_buffer[m_offset++] = ch; - } - -private: - ByteBuffer& m_buffer; - Unix::size_t m_offset { 0 }; -}; - bool Ext2FileSystem::writeDirectoryInode(unsigned directoryInode, Vector&& entries) { kprintf("[ext2fs] New directory inode %u contents to write:\n", directoryInode); diff --git a/VirtualFileSystem/FileHandle.cpp b/VirtualFileSystem/FileHandle.cpp index 113a9a56c11..90c0beade2d 100644 --- a/VirtualFileSystem/FileHandle.cpp +++ b/VirtualFileSystem/FileHandle.cpp @@ -3,6 +3,7 @@ #include "CharacterDevice.h" #include "sys-errno.h" #include "UnixTypes.h" +#include FileHandle::FileHandle(RetainPtr&& vnode) : m_vnode(move(vnode)) @@ -29,7 +30,7 @@ int FileHandle::stat(Unix::stat* buffer) if (!m_vnode) return -EBADF; - auto metadata = m_vnode->inode.metadata(); + auto metadata = m_vnode->metadata(); if (!metadata.isValid()) return -EIO; @@ -58,7 +59,7 @@ Unix::off_t FileHandle::seek(Unix::off_t offset, int whence) // FIXME: The file type should be cached on the vnode. // It's silly that we have to do a full metadata lookup here. - auto metadata = m_vnode->inode.metadata(); + auto metadata = m_vnode->metadata(); if (!metadata.isValid()) return -EIO; @@ -120,3 +121,27 @@ ByteBuffer FileHandle::readEntireFile() return m_vnode->fileSystem()->readEntireInode(m_vnode->inode); } +ssize_t FileHandle::get_dir_entries(byte* buffer, size_t size) +{ + Locker locker(VirtualFileSystem::lock()); + + auto metadata = m_vnode->metadata(); + if (!metadata.isValid()) + return -EIO; + if (!metadata.isDirectory()) + return -ENOTDIR; + + // FIXME: Compute the actual size needed. + auto tempBuffer = ByteBuffer::createUninitialized(2048); + BufferStream stream(tempBuffer); + m_vnode->vfs()->enumerateDirectoryInode(m_vnode->inode, [&stream] (const FileSystem::DirectoryEntry& entry) { + stream << (dword)entry.inode.index(); + stream << (byte)entry.fileType; + stream << (dword)entry.name.length(); + stream << entry.name; + return true; + }); + + memcpy(buffer, tempBuffer.pointer(), stream.offset()); + return stream.offset(); +} diff --git a/VirtualFileSystem/FileHandle.h b/VirtualFileSystem/FileHandle.h index 16956eb87ca..f75d88895ce 100644 --- a/VirtualFileSystem/FileHandle.h +++ b/VirtualFileSystem/FileHandle.h @@ -12,6 +12,8 @@ public: Unix::ssize_t read(byte* buffer, Unix::size_t count); int stat(Unix::stat*); + ssize_t get_dir_entries(byte* buffer, Unix::size_t); + ByteBuffer readEntireFile(); #ifdef SERENITY diff --git a/VirtualFileSystem/VirtualFileSystem.cpp b/VirtualFileSystem/VirtualFileSystem.cpp index c4c831b9c12..d7880a1b02f 100644 --- a/VirtualFileSystem/VirtualFileSystem.cpp +++ b/VirtualFileSystem/VirtualFileSystem.cpp @@ -78,6 +78,7 @@ auto VirtualFileSystem::makeNode(InodeIdentifier inode) -> RetainPtr fileSystem->retain(); vnode->inode = inode; + vnode->m_cachedMetadata = { }; #ifdef VFS_DEBUG kprintf("makeNode: inode=%u, size=%u, mode=%o, uid=%u, gid=%u\n", inode.index(), metadata.size, metadata.mode, metadata.uid, metadata.gid); @@ -85,6 +86,7 @@ auto VirtualFileSystem::makeNode(InodeIdentifier inode) -> RetainPtr m_inode2vnode.set(inode, vnode.ptr()); vnode->m_characterDevice = characterDevice; + return vnode; } @@ -151,7 +153,7 @@ auto VirtualFileSystem::allocateNode() -> RetainPtr auto* node = m_nodeFreeList.takeLast(); ASSERT(node->retainCount == 0); node->retainCount = 1; - node->vfs = this; + node->m_vfs = this; return adopt(*node); } @@ -198,8 +200,7 @@ bool VirtualFileSystem::isRoot(InodeIdentifier inode) const return inode == m_rootNode->inode; } -template -void VirtualFileSystem::enumerateDirectoryInode(InodeIdentifier directoryInode, F func) +void VirtualFileSystem::enumerateDirectoryInode(InodeIdentifier directoryInode, Function callback) { if (!directoryInode.isValid()) return; @@ -216,7 +217,7 @@ void VirtualFileSystem::enumerateDirectoryInode(InodeIdentifier directoryInode, ASSERT(mount); resolvedInode = mount->host(); } - func({ entry.name, resolvedInode }); + callback({ entry.name, resolvedInode }); return true; }); } @@ -340,6 +341,7 @@ void VirtualFileSystem::listDirectoryRecursively(const String& path) } else { kprintf("%s/%s\n", path.characters(), entry.name.characters()); } + return true; }); } @@ -467,10 +469,17 @@ void VirtualFileSystem::Node::release() { ASSERT(retainCount); if (--retainCount == 0) { - vfs->freeNode(this); + m_vfs->freeNode(this); } } +const InodeMetadata& VirtualFileSystem::Node::metadata() const +{ + if (!m_cachedMetadata.isValid()) + m_cachedMetadata = inode.metadata(); + return m_cachedMetadata; +} + VirtualFileSystem::Mount::Mount(InodeIdentifier host, RetainPtr&& guestFileSystem) : m_host(host) , m_guest(guestFileSystem->rootInode()) diff --git a/VirtualFileSystem/VirtualFileSystem.h b/VirtualFileSystem/VirtualFileSystem.h index 2fa31b51b90..bafb791d9f7 100644 --- a/VirtualFileSystem/VirtualFileSystem.h +++ b/VirtualFileSystem/VirtualFileSystem.h @@ -6,12 +6,14 @@ #include #include #include +#include #include "InodeIdentifier.h" +#include "InodeMetadata.h" #include "Limits.h" +#include "FileSystem.h" class CharacterDevice; class FileHandle; -class FileSystem; class VirtualFileSystem { public: @@ -20,6 +22,7 @@ public: struct Node { InodeIdentifier inode; + const InodeMetadata& metadata() const; bool inUse() const { return inode.isValid(); } @@ -32,11 +35,15 @@ public: FileSystem* fileSystem() { return inode.fileSystem(); } const FileSystem* fileSystem() const { return inode.fileSystem(); } + VirtualFileSystem* vfs() { return m_vfs; } + const VirtualFileSystem* vfs() const { return m_vfs; } + private: friend class VirtualFileSystem; - VirtualFileSystem* vfs { nullptr }; + VirtualFileSystem* m_vfs { nullptr }; unsigned retainCount { 0 }; CharacterDevice* m_characterDevice { nullptr }; + mutable InodeMetadata m_cachedMetadata; }; static VirtualFileSystem& the(); @@ -68,7 +75,9 @@ public: void registerCharacterDevice(unsigned major, unsigned minor, CharacterDevice&); private: - template void enumerateDirectoryInode(InodeIdentifier, F func); + friend class FileHandle; + + void enumerateDirectoryInode(InodeIdentifier, Function); InodeIdentifier resolvePath(const String& path); InodeIdentifier resolveSymbolicLink(const String& basePath, InodeIdentifier symlinkInode);