diff --git a/Kernel/Makefile b/Kernel/Makefile index c7dfcd6ce2..b391a3f2a9 100644 --- a/Kernel/Makefile +++ b/Kernel/Makefile @@ -43,7 +43,8 @@ ELFLOADER_OBJS = \ AK_OBJS = \ ../AK/String.o \ - ../AK/StringImpl.o + ../AK/StringImpl.o \ + ../AK/StringBuilder.o OBJS = $(KERNEL_OBJS) $(VFS_OBJS) $(AK_OBJS) $(ELFLOADER_OBJS) diff --git a/Kernel/Task.cpp b/Kernel/Task.cpp index c08219a957..f5bc6160fc 100644 --- a/Kernel/Task.cpp +++ b/Kernel/Task.cpp @@ -234,7 +234,7 @@ Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t paren cwd = parentTask->m_cwd.copyRef(); } - auto handle = VirtualFileSystem::the().open(path, cwd.ptr()); + auto handle = VirtualFileSystem::the().open(path, cwd ? cwd->inode : InodeIdentifier()); if (!handle) { error = -ENOENT; // FIXME: Get a more detailed error from VFS. return nullptr; @@ -785,7 +785,7 @@ int Task::sys$close(int fd) int Task::sys$lstat(const char* path, Unix::stat* statbuf) { VALIDATE_USER_BUFFER(statbuf, sizeof(Unix::stat)); - auto handle = VirtualFileSystem::the().open(move(path), m_cwd.ptr()); + auto handle = VirtualFileSystem::the().open(move(path), cwdInode()); if (!handle) return -1; handle->stat(statbuf); @@ -795,7 +795,7 @@ int Task::sys$lstat(const char* path, Unix::stat* statbuf) int Task::sys$chdir(const char* path) { VALIDATE_USER_BUFFER(path, strlen(path)); - auto handle = VirtualFileSystem::the().open(path, m_cwd.ptr()); + auto handle = VirtualFileSystem::the().open(path, cwdInode()); if (!handle) return -ENOENT; // FIXME: More detailed error. if (!handle->isDirectory()) @@ -819,7 +819,7 @@ int Task::sys$open(const char* path, size_t pathLength) VALIDATE_USER_BUFFER(path, pathLength); if (m_fileHandles.size() >= m_maxFileHandles) return -EMFILE; - auto handle = VirtualFileSystem::the().open(String(path, pathLength), m_cwd.ptr()); + auto handle = VirtualFileSystem::the().open(String(path, pathLength), cwdInode()); if (!handle) return -ENOENT; // FIXME: Detailed error. int fd = m_fileHandles.size(); diff --git a/Kernel/Task.h b/Kernel/Task.h index 88d3f348a9..10ea3a2dd3 100644 --- a/Kernel/Task.h +++ b/Kernel/Task.h @@ -133,6 +133,8 @@ public: bool isValidAddressForKernel(LinearAddress) const; bool isValidAddressForUser(LinearAddress) const; + InodeIdentifier cwdInode() const { return m_cwd ? m_cwd->inode : InodeIdentifier(); } + private: friend class MemoryManager; friend bool scheduleNewTask(); diff --git a/VirtualFileSystem/Ext2FileSystem.cpp b/VirtualFileSystem/Ext2FileSystem.cpp index 9314722a5f..4c583162b3 100644 --- a/VirtualFileSystem/Ext2FileSystem.cpp +++ b/VirtualFileSystem/Ext2FileSystem.cpp @@ -943,3 +943,35 @@ InodeIdentifier Ext2FileSystem::createInode(InodeIdentifier parentInode, const S return { id(), inode }; } +InodeIdentifier Ext2FileSystem::findParentOfInode(InodeIdentifier inode) const +{ + ASSERT(inode.fileSystemID() == id()); + unsigned groupIndex = groupIndexFromInode(inode.index()); + unsigned firstInodeInGroup = inodesPerGroup() * (groupIndex - 1); + + Vector directoriesInGroup; + + for (unsigned i = 0; i < inodesPerGroup(); ++i) { + auto e2inode = lookupExt2Inode(firstInodeInGroup + i); + if (!e2inode) + continue; + if (isDirectory(e2inode->i_mode)) { + directoriesInGroup.append({ id(), firstInodeInGroup + i }); + } + } + + InodeIdentifier foundParent; + for (auto& directory : directoriesInGroup) { + enumerateDirectoryInode(directory, [inode, directory, &foundParent] (auto& entry) { + if (entry.inode == inode) { + foundParent = directory; + return false; + } + return true; + }); + if (foundParent.isValid()) + break; + } + + return foundParent; +} diff --git a/VirtualFileSystem/Ext2FileSystem.h b/VirtualFileSystem/Ext2FileSystem.h index a0f8a74d3e..8d67959251 100644 --- a/VirtualFileSystem/Ext2FileSystem.h +++ b/VirtualFileSystem/Ext2FileSystem.h @@ -46,6 +46,7 @@ private: 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, FileHandle*) const override; virtual InodeIdentifier makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t) override; + virtual InodeIdentifier findParentOfInode(InodeIdentifier) const override; bool isDirectoryInode(unsigned) const; unsigned allocateInode(unsigned preferredGroup, unsigned expectedSize); diff --git a/VirtualFileSystem/FileSystem.cpp b/VirtualFileSystem/FileSystem.cpp index e5529b5168..b718fe5c35 100644 --- a/VirtualFileSystem/FileSystem.cpp +++ b/VirtualFileSystem/FileSystem.cpp @@ -50,6 +50,20 @@ InodeIdentifier FileSystem::childOfDirectoryInodeWithName(InodeIdentifier inode, return foundInode; } +String FileSystem::nameOfChildInDirectory(InodeIdentifier parent, InodeIdentifier child) const +{ + String name; + bool success = enumerateDirectoryInode(parent, [&] (auto& entry) { + if (entry.inode == child) { + name = entry.name; + return false; + } + return true; + }); + ASSERT(success); + return name; +} + ByteBuffer FileSystem::readEntireInode(InodeIdentifier inode, FileHandle* handle) const { ASSERT(inode.fileSystemID() == id()); diff --git a/VirtualFileSystem/FileSystem.h b/VirtualFileSystem/FileSystem.h index c6e345d4aa..643a3ba51a 100644 --- a/VirtualFileSystem/FileSystem.h +++ b/VirtualFileSystem/FileSystem.h @@ -45,8 +45,11 @@ public: 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; + virtual InodeIdentifier findParentOfInode(InodeIdentifier) const = 0; + InodeIdentifier childOfDirectoryInodeWithName(InodeIdentifier, const String& name) const; ByteBuffer readEntireInode(InodeIdentifier, FileHandle* = nullptr) const; + String nameOfChildInDirectory(InodeIdentifier parent, InodeIdentifier child) const; protected: FileSystem(); diff --git a/VirtualFileSystem/SyntheticFileSystem.cpp b/VirtualFileSystem/SyntheticFileSystem.cpp index 51f48c8c9c..314e43c52d 100644 --- a/VirtualFileSystem/SyntheticFileSystem.cpp +++ b/VirtualFileSystem/SyntheticFileSystem.cpp @@ -199,7 +199,7 @@ Unix::ssize_t SyntheticFileSystem::readInodeBytes(InodeIdentifier inode, Unix::o #endif ASSERT(offset >= 0); ASSERT(buffer); -\ + auto it = m_inodes.find(inode.index()); if (it == m_inodes.end()) return false; @@ -235,3 +235,11 @@ auto SyntheticFileSystem::generateInodeIndex() -> InodeIndex { return m_nextInodeIndex++; } + +InodeIdentifier SyntheticFileSystem::findParentOfInode(InodeIdentifier inode) const +{ + auto it = m_inodes.find(inode.index()); + if (it == m_inodes.end()) + return { }; + return (*it).value->parent; +} diff --git a/VirtualFileSystem/SyntheticFileSystem.h b/VirtualFileSystem/SyntheticFileSystem.h index 2831d6d239..d9d84c962a 100644 --- a/VirtualFileSystem/SyntheticFileSystem.h +++ b/VirtualFileSystem/SyntheticFileSystem.h @@ -19,6 +19,7 @@ public: 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, FileHandle*) const override; virtual InodeIdentifier makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t) override; + virtual InodeIdentifier findParentOfInode(InodeIdentifier) const override; protected: typedef unsigned InodeIndex; diff --git a/VirtualFileSystem/VirtualFileSystem.cpp b/VirtualFileSystem/VirtualFileSystem.cpp index f7c91d38d7..f8ead5960a 100644 --- a/VirtualFileSystem/VirtualFileSystem.cpp +++ b/VirtualFileSystem/VirtualFileSystem.cpp @@ -1,6 +1,7 @@ #include "VirtualFileSystem.h" #include "FileHandle.h" #include "FileSystem.h" +#include #include #include #include @@ -169,7 +170,7 @@ void VirtualFileSystem::freeNode(Node* node) m_nodeFreeList.append(move(node)); } -bool VirtualFileSystem::isDirectory(const String& path, Node* base) +bool VirtualFileSystem::isDirectory(const String& path, InodeIdentifier base) { auto inode = resolvePath(path, base); if (!inode.isValid()) @@ -356,7 +357,7 @@ bool VirtualFileSystem::touch(const String& path) return inode.fileSystem()->setModificationTime(inode, ktime(nullptr)); } -OwnPtr VirtualFileSystem::open(const String& path, Node* base) +OwnPtr VirtualFileSystem::open(const String& path, InodeIdentifier base) { Locker locker(VirtualFileSystem::lock()); @@ -369,7 +370,7 @@ OwnPtr VirtualFileSystem::open(const String& path, Node* base) return make(move(vnode)); } -OwnPtr VirtualFileSystem::create(const String& path, Node* base) +OwnPtr VirtualFileSystem::create(const String& path, InodeIdentifier base) { Locker locker(VirtualFileSystem::lock()); @@ -379,7 +380,7 @@ OwnPtr VirtualFileSystem::create(const String& path, Node* base) return nullptr; } -OwnPtr VirtualFileSystem::mkdir(const String& path, Node* base) +OwnPtr VirtualFileSystem::mkdir(const String& path, InodeIdentifier base) { Locker locker(VirtualFileSystem::lock()); @@ -399,7 +400,41 @@ InodeIdentifier VirtualFileSystem::resolveSymbolicLink(const String& basePath, I return resolvePath(buf); } -InodeIdentifier VirtualFileSystem::resolvePath(const String& path, Node* base) +String VirtualFileSystem::absolutePath(InodeIdentifier inode) +{ + Locker locker(VirtualFileSystem::lock()); + + if (!inode.isValid()) + return String(); + + Vector lineage; + while (inode != m_rootNode->inode) { + if (auto* mount = findMountForGuest(inode)) + lineage.append(mount->host()); + else + lineage.append(inode); + if (inode.metadata().isDirectory()) { + inode = resolvePath("..", inode); + } else + inode = inode.fileSystem()->findParentOfInode(inode); + ASSERT(inode.isValid()); + } + if (lineage.isEmpty()) + return "/"; + lineage.append(m_rootNode->inode); + StringBuilder builder; + for (size_t i = lineage.size() - 1; i >= 1; --i) { + auto& child = lineage[i - 1]; + auto parent = lineage[i]; + if (auto* mount = findMountForHost(parent)) + parent = mount->guest(); + builder.append('/'); + builder.append(parent.fileSystem()->nameOfChildInDirectory(parent, child)); + } + return builder.build(); +} + +InodeIdentifier VirtualFileSystem::resolvePath(const String& path, InodeIdentifier base) { if (path.isEmpty()) return { }; @@ -410,7 +445,7 @@ InodeIdentifier VirtualFileSystem::resolvePath(const String& path, Node* base) if (path[0] == '/') inode = m_rootNode->inode; else - inode = base ? base->inode : m_rootNode->inode; + inode = base.isValid() ? base : m_rootNode->inode; for (unsigned i = 0; i < parts.size(); ++i) { bool wasRootInodeAtHeadOfLoop = inode.isRootInode(); diff --git a/VirtualFileSystem/VirtualFileSystem.h b/VirtualFileSystem/VirtualFileSystem.h index f23da02f6a..099cf2c853 100644 --- a/VirtualFileSystem/VirtualFileSystem.h +++ b/VirtualFileSystem/VirtualFileSystem.h @@ -66,7 +66,7 @@ public: VirtualFileSystem(); ~VirtualFileSystem(); - bool isDirectory(const String& path, Node* base = nullptr); + bool isDirectory(const String& path, InodeIdentifier base = InodeIdentifier()); void listDirectory(const String& path); void listDirectoryRecursively(const String& path); @@ -79,9 +79,9 @@ public: bool mountRoot(RetainPtr&&); bool mount(RetainPtr&&, const String& path); - OwnPtr open(const String& path, Node* base = nullptr); - OwnPtr create(const String& path, Node* base = nullptr); - OwnPtr mkdir(const String& path, Node* base = nullptr); + OwnPtr open(const String& path, InodeIdentifier base = InodeIdentifier()); + OwnPtr create(const String& path, InodeIdentifier base = InodeIdentifier()); + OwnPtr mkdir(const String& path, InodeIdentifier base = InodeIdentifier()); bool isRoot(InodeIdentifier) const; @@ -92,12 +92,13 @@ public: size_t mountCount() const { return m_mounts.size(); } void forEachMount(Function) const; + String absolutePath(InodeIdentifier); + private: friend class FileHandle; void enumerateDirectoryInode(InodeIdentifier, Function); - String absolutePath(InodeIdentifier); - InodeIdentifier resolvePath(const String& path, Node* base = nullptr); + InodeIdentifier resolvePath(const String& path, InodeIdentifier base = InodeIdentifier()); InodeIdentifier resolveSymbolicLink(const String& basePath, InodeIdentifier symlinkInode); RetainPtr allocateNode();