/* This file is part of Fennix Kernel. Fennix Kernel is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Fennix Kernel is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Fennix Kernel. If not, see . */ #ifndef __FENNIX_KERNEL_FILESYSTEM_H__ #define __FENNIX_KERNEL_FILESYSTEM_H__ #include #include #include #include #include #include #include #include static_assert(DTTOIF(DT_FIFO) == S_IFIFO); static_assert(IFTODT(S_IFCHR) == DT_CHR); #define __check_op(op, ...) \ if (fsi->Ops.op == nullptr) \ return -ENOTSUP; \ else \ return fsi->Ops.op(this->Node, ##__VA_ARGS__) class FileNode { public: std::string Name, Path; FileNode *Parent; std::vector Children; Inode *Node; FileSystemInfo *fsi; bool IsDirectory() { return S_ISDIR(Node->Mode); } bool IsCharacterDevice() { return S_ISCHR(Node->Mode); } bool IsBlockDevice() { return S_ISBLK(Node->Mode); } bool IsRegularFile() { return S_ISREG(Node->Mode); } bool IsFIFO() { return S_ISFIFO(Node->Mode); } bool IsSymbolicLink() { return S_ISLNK(Node->Mode); } bool IsSocket() { return S_ISSOCK(Node->Mode); } int Lookup(const char *Name, Inode **Node) { __check_op(Lookup, Name, Node); } int Create(const char *Name, mode_t Mode, Inode **Node) { __check_op(Create, Name, Mode, Node); } int Remove(const char *Name) { __check_op(Remove, Name); } int Rename(const char *OldName, const char *NewName) { __check_op(Rename, OldName, NewName); } ssize_t Read(auto Buffer, size_t Size, off_t Offset) { __check_op(Read, (void *)Buffer, Size, Offset); } ssize_t Write(const auto Buffer, size_t Size, off_t Offset) { __check_op(Write, (const void *)Buffer, Size, Offset); } int Truncate(off_t Size) { __check_op(Truncate, Size); } int Open(int Flags, mode_t Mode) { __check_op(Open, Flags, Mode); } int Close() { __check_op(Close); } int Ioctl(unsigned long Request, void *Argp) { __check_op(Ioctl, Request, Argp); } ssize_t ReadDir(struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) { __check_op(ReadDir, Buffer, Size, Offset, Entries); } int MkDir(const char *Name, mode_t Mode, struct Inode **Result) { __check_op(MkDir, Name, Mode, Result); } int RmDir(const char *Name) { __check_op(RmDir, Name); } int SymLink(const char *Name, const char *Target, struct Inode **Result) { __check_op(SymLink, Name, Target, Result); } ssize_t ReadLink(auto Buffer, size_t Size) { __check_op(ReadLink, (char *)Buffer, Size); } off_t Seek(off_t Offset) { __check_op(Seek, Offset); } int Stat(struct kstat *Stat) { __check_op(Stat, Stat); } ~FileNode() = delete; }; #undef __check_op namespace vfs { struct vfsInode { Inode Node; std::string Name; std::vector Children; }; class Virtual { private: NewLock(VirtualLock); struct FSMountInfo { FileSystemInfo *fsi; Inode *Root; }; struct CacheNode { FileNode *fn; std::atomic_int References; }; std::unordered_map DeviceMap; std::atomic_bool RegisterLock = false; FileNode *__CacheRecursiveSearch(FileNode *, const char *, bool); FileNode *CacheLookup(const char *Path); FileNode *CreateCacheNode(FileNode *Parent, Inode *Node, const char *Name, mode_t Mode); int RemoveCacheNode(FileNode *Node); public: vfsInode *FileSystemRoots = nullptr; bool PathIsRelative(const char *Path); bool PathIsAbsolute(const char *Path) { return !PathIsRelative(Path); } /** * Reserve a device number for a filesystem * * @note After this function is called, the filesystem must * call LateRegisterFileSystem to release the lock */ dev_t EarlyReserveDevice(); /** * Register a filesystem after the device number has been reserved */ int LateRegisterFileSystem(dev_t Device, FileSystemInfo *fsi, Inode *Root); dev_t RegisterFileSystem(FileSystemInfo *fsi, Inode *Root); int UnregisterFileSystem(dev_t Device); void AddRoot(Inode *Root); FileNode *GetRoot(size_t Index); FileNode *Create(FileNode *Parent, const char *Name, mode_t Mode); FileNode *ForceCreate(FileNode *Parent, const char *Name, mode_t Mode); FileNode *GetByPath(const char *Path, FileNode *Parent); FileNode *CreateLink(const char *Path, FileNode *Parent, const char *Target); FileNode *CreateLink(const char *Path, FileNode *Parent, FileNode *Target); bool PathExists(const char *Path, FileNode *Parent); int Remove(FileNode *Node); void Initialize(); Virtual(); ~Virtual(); }; class FileDescriptorTable { public: struct Fildes { enum FildesType { FD_INODE, FD_PIPE, FD_SOCKET, } Type; mode_t Mode = 0; int Flags = 0; FileNode *Node = nullptr; int References = 0; off_t Offset = 0; int operator==(const Fildes &other) { return Type == other.Type && Mode == other.Mode && Flags == other.Flags && Node == other.Node && References == other.References && Offset == other.Offset; } }; private: FileNode *fdDir = nullptr; void *Owner; int AddFileDescriptor(const char *AbsolutePath, mode_t Mode, int Flags); int RemoveFileDescriptor(int FileDescriptor); int GetFreeFileDescriptor(); public: std::unordered_map FileMap; int GetFlags(int FileDescriptor); int SetFlags(int FileDescriptor, int Flags); void Fork(FileDescriptorTable *Parent); int usr_open(const char *pathname, int flags, mode_t mode); int usr_creat(const char *pathname, mode_t mode); ssize_t usr_read(int fd, void *buf, size_t count); ssize_t usr_write(int fd, const void *buf, size_t count); int usr_close(int fd); off_t usr_lseek(int fd, off_t offset, int whence); int usr_stat(const char *pathname, struct kstat *statbuf); int usr_fstat(int fd, struct kstat *statbuf); int usr_lstat(const char *pathname, struct kstat *statbuf); int usr_dup(int oldfd); int usr_dup2(int oldfd, int newfd); int usr_ioctl(int fd, unsigned long request, void *argp); FileDescriptorTable(void *Owner); ~FileDescriptorTable() = default; }; } #endif // !__FENNIX_KERNEL_FILESYSTEM_H__