#pragma once #include #include #include #include #include #include #include #include "InodeIdentifier.h" #include "InodeMetadata.h" #include "Limits.h" #include "FileSystem.h" #define O_RDONLY 0 #define O_WRONLY 1 #define O_RDWR 2 #define O_DIRECTORY 00200000 #define O_NOFOLLOW 00400000 #define O_NOFOLLOW_NOERROR 0x4000000 class CharacterDevice; class FileHandle; class VirtualFileSystem { public: static void initializeGlobals(); static SpinLock& lock(); class Mount { public: Mount(InodeIdentifier host, RetainPtr&&); InodeIdentifier host() const { return m_host; } InodeIdentifier guest() const { return m_guest; } const FileSystem& fileSystem() const { return *m_fileSystem; } private: InodeIdentifier m_host; InodeIdentifier m_guest; RetainPtr m_fileSystem; }; struct Node { InodeIdentifier inode; const InodeMetadata& metadata() const; bool inUse() const { return inode.isValid(); } bool isCharacterDevice() const { return m_characterDevice; } CharacterDevice* characterDevice() { return m_characterDevice; } void retain(); void release(); 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* m_vfs { nullptr }; unsigned retainCount { 0 }; CharacterDevice* m_characterDevice { nullptr }; mutable InodeMetadata m_cachedMetadata; }; static VirtualFileSystem& the() PURE; VirtualFileSystem(); ~VirtualFileSystem(); bool isDirectory(const String& path, InodeIdentifier base = InodeIdentifier()); void listDirectory(const String& path); void listDirectoryRecursively(const String& path); unsigned maxNodeCount() const { return m_maxNodeCount; } unsigned allocatedNodeCount() const { return m_maxNodeCount - m_nodeFreeList.size(); } Node* root() { return m_rootNode.ptr(); } const Node* root() const { return m_rootNode.ptr(); } bool mountRoot(RetainPtr&&); bool mount(RetainPtr&&, const String& path); OwnPtr open(const String& path, int& error, int options = 0, InodeIdentifier base = InodeIdentifier()); OwnPtr create(const String& path, InodeIdentifier base = InodeIdentifier()); OwnPtr mkdir(const String& path, InodeIdentifier base = InodeIdentifier()); bool isRoot(InodeIdentifier) const; bool touch(const String&path); void registerCharacterDevice(unsigned major, unsigned minor, CharacterDevice&); size_t mountCount() const { return m_mounts.size(); } void forEachMount(Function) const; String absolutePath(InodeIdentifier); private: friend class FileHandle; String absolutePathInternal(InodeIdentifier, Locker&); void enumerateDirectoryInode(InodeIdentifier, Function); InodeIdentifier resolvePath(const String& path, int& error, Locker&, InodeIdentifier base = InodeIdentifier(), int options = 0); InodeIdentifier resolveSymbolicLink(InodeIdentifier base, InodeIdentifier symlinkInode, int& error, Locker&); RetainPtr allocateNode(); void freeNode(Node*); RetainPtr makeNode(InodeIdentifier); RetainPtr getOrCreateNode(InodeIdentifier); Mount* findMountForHost(InodeIdentifier); Mount* findMountForGuest(InodeIdentifier); HashMap m_inode2vnode; HashMap m_device2vnode; Vector> m_mounts; unsigned m_maxNodeCount { 0 }; Node* m_nodes { nullptr }; Vector m_nodeFreeList; RetainPtr m_rootNode; HashMap m_characterDevices; };