Kernel/include/filesystem.hpp
2024-05-18 07:42:01 +03:00

217 lines
6.5 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, ...) \
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<FileNode *> 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<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 *__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<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__