mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-05-25 22:14:37 +00:00
229 lines
7.0 KiB
C++
229 lines
7.0 KiB
C++
/*
|
|
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 <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef __FENNIX_KERNEL_FILESYSTEM_H__
|
|
#define __FENNIX_KERNEL_FILESYSTEM_H__
|
|
|
|
#include <types.h>
|
|
|
|
#include <interface/fs.h>
|
|
#include <unordered_map>
|
|
#include <lock.hpp>
|
|
#include <errno.h>
|
|
#include <atomic>
|
|
#include <string>
|
|
#include <list>
|
|
|
|
static_assert(DTTOIF(DT_FIFO) == S_IFIFO);
|
|
static_assert(IFTODT(S_IFCHR) == DT_CHR);
|
|
|
|
#define __check_op(op, err, ...) \
|
|
if (fsi->Ops.op == nullptr) \
|
|
return -err; \
|
|
else \
|
|
return fsi->Ops.op(this->Node, ##__VA_ARGS__)
|
|
|
|
#define FSROOT(num) "\x06root-" #num "\x06"
|
|
|
|
class FileNode
|
|
{
|
|
public:
|
|
std::string Name, Path;
|
|
FileNode *Parent;
|
|
std::vector<FileNode *> Children;
|
|
Inode *Node;
|
|
FileSystemInfo *fsi;
|
|
|
|
std::string GetName();
|
|
std::string GetPath();
|
|
|
|
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, ENOTSUP, Name, Node); }
|
|
int Create(const char *Name, mode_t Mode, Inode **Node) { __check_op(Create, EROFS, Name, Mode, Node); }
|
|
int Remove(const char *Name) { __check_op(Remove, EROFS, Name); }
|
|
int Rename(const char *OldName, const char *NewName) { __check_op(Rename, EROFS, OldName, NewName); }
|
|
ssize_t Read(auto Buffer, size_t Size, off_t Offset) { __check_op(Read, ENOTSUP, (void *)Buffer, Size, Offset); }
|
|
ssize_t Write(const auto Buffer, size_t Size, off_t Offset) { __check_op(Write, EROFS, (const void *)Buffer, Size, Offset); }
|
|
int Truncate(off_t Size) { __check_op(Truncate, EROFS, Size); }
|
|
int Open(int Flags, mode_t Mode) { __check_op(Open, ENOTSUP, Flags, Mode); }
|
|
int Close() { __check_op(Close, ENOTSUP); }
|
|
int Ioctl(unsigned long Request, void *Argp) { __check_op(Ioctl, ENOTSUP, Request, Argp); }
|
|
ssize_t ReadDir(struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) { __check_op(ReadDir, ENOTSUP, Buffer, Size, Offset, Entries); }
|
|
int MkDir(const char *Name, mode_t Mode, struct Inode **Result) { __check_op(MkDir, EROFS, Name, Mode, Result); }
|
|
int RmDir(const char *Name) { __check_op(RmDir, EROFS, Name); }
|
|
int SymLink(const char *Name, const char *Target, struct Inode **Result) { __check_op(SymLink, EROFS, Name, Target, Result); }
|
|
ssize_t ReadLink(auto Buffer, size_t Size) { __check_op(ReadLink, ENOTSUP, (char *)Buffer, Size); }
|
|
off_t Seek(off_t Offset) { __check_op(Seek, ENOTSUP, Offset); }
|
|
int Stat(struct kstat *Stat) { __check_op(Stat, ENOTSUP, Stat); }
|
|
|
|
~FileNode() = delete;
|
|
};
|
|
|
|
#undef __check_op
|
|
|
|
namespace vfs
|
|
{
|
|
struct vfsInode
|
|
{
|
|
Inode Node;
|
|
std::string Name;
|
|
std::string FriendlyName;
|
|
std::vector<Inode *> Children;
|
|
};
|
|
|
|
class Virtual
|
|
{
|
|
private:
|
|
NewLock(VirtualLock);
|
|
|
|
struct FSMountInfo
|
|
{
|
|
FileSystemInfo *fsi;
|
|
Inode *Root;
|
|
};
|
|
|
|
struct CacheNode
|
|
{
|
|
FileNode *fn;
|
|
std::atomic_int References;
|
|
};
|
|
|
|
std::unordered_map<dev_t, FSMountInfo> DeviceMap;
|
|
std::atomic_bool RegisterLock = false;
|
|
|
|
FileNode *CacheSearchReturnLast(FileNode *Parent, const char **Path);
|
|
FileNode *CacheRecursiveSearch(FileNode *Root, const char *NameOrPath, bool IsName);
|
|
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;
|
|
std::unordered_map<ino_t, FileNode *> FileRoots;
|
|
|
|
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 *Mount(FileNode *Parent, Inode *Node, const char *Path);
|
|
int Unmount(const char *Path);
|
|
|
|
FileNode *GetByPath(const char *Path, FileNode *Parent);
|
|
std::string GetByNode(FileNode *Node);
|
|
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<int, Fildes> 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__
|