mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-07-11 07:19:20 +00:00
Refactor filesystem & stl code
This commit is contained in:
@ -20,309 +20,136 @@
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <smart_ptr.hpp>
|
||||
#include <interface/fs.h>
|
||||
#include <unordered_map>
|
||||
#include <lock.hpp>
|
||||
#include <errno.h>
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#define SEEK_SET 0
|
||||
#define SEEK_CUR 1
|
||||
#define SEEK_END 2
|
||||
static_assert(DTTOIF(DT_FIFO) == S_IFIFO);
|
||||
static_assert(IFTODT(S_IFCHR) == DT_CHR);
|
||||
|
||||
/** Other users have execute permission. */
|
||||
#define S_IXOTH 0001
|
||||
/** Other users have write permission. */
|
||||
#define S_IWOTH 0002
|
||||
/** Other users have read permission. */
|
||||
#define S_IROTH 0004
|
||||
/** Other users have read, write, and execute permissions. */
|
||||
#define S_IRWXO 0007
|
||||
/** Group members have execute permission. */
|
||||
#define S_IXGRP 0010
|
||||
/** Group members have write permission. */
|
||||
#define S_IWGRP 0020
|
||||
/** Group members have read permission. */
|
||||
#define S_IRGRP 0040
|
||||
/** Group members have read, write, and execute permissions. */
|
||||
#define S_IRWXG 0070
|
||||
/** The file owner has execute permission. */
|
||||
#define S_IXUSR 0100
|
||||
/** The file owner has write permission. */
|
||||
#define S_IWUSR 0200
|
||||
/** The file owner has read permission. */
|
||||
#define S_IRUSR 0400
|
||||
/** The file owner has read, write,
|
||||
* and execute permissions. */
|
||||
#define S_IRWXU 0700
|
||||
#define __check_op(op, ...) \
|
||||
if (fsi->Ops.op == nullptr) \
|
||||
return -ENOTSUP; \
|
||||
else \
|
||||
return fsi->Ops.op(this->Node, ##__VA_ARGS__)
|
||||
|
||||
#define O_RDONLY 00
|
||||
#define O_WRONLY 01
|
||||
#define O_RDWR 02
|
||||
#define O_CREAT 0100
|
||||
#define O_EXCL 0200
|
||||
#define O_TRUNC 01000
|
||||
#define O_APPEND 02000
|
||||
#define O_CLOEXEC 02000000
|
||||
|
||||
#define S_IFIFO 0010000
|
||||
#define S_IFCHR 0020000
|
||||
#define S_IFDIR 0040000
|
||||
#define S_IFBLK 0060000
|
||||
#define S_IFREG 0100000
|
||||
#define S_IFLNK 0120000
|
||||
#define S_IFSOCK 0140000
|
||||
|
||||
#define S_IFMT 0170000
|
||||
|
||||
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
|
||||
#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
|
||||
#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
|
||||
#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
|
||||
#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
|
||||
#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
|
||||
#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
|
||||
|
||||
struct kstat
|
||||
class FileNode
|
||||
{
|
||||
/** Device ID of the file. */
|
||||
dev_t st_dev;
|
||||
/** Inode number. */
|
||||
ino_t st_ino;
|
||||
/** File type and mode. */
|
||||
mode_t st_mode;
|
||||
/** Number of hard links. */
|
||||
nlink_t st_nlink;
|
||||
/** User ID of the file's owner. */
|
||||
uid_t st_uid;
|
||||
/** Group ID of the file's owner. */
|
||||
gid_t st_gid;
|
||||
/** Device ID for special files. */
|
||||
dev_t st_rdev;
|
||||
/** Size of the file in bytes. */
|
||||
off_t st_size;
|
||||
/** Time of last access. */
|
||||
time_t st_atime;
|
||||
/** Time of last modification. */
|
||||
time_t st_mtime;
|
||||
/** Time of last status change. */
|
||||
time_t st_ctime;
|
||||
/** Optimal I/O block size. */
|
||||
blksize_t st_blksize;
|
||||
/** Number of blocks allocated. */
|
||||
blkcnt_t st_blocks;
|
||||
/** Additional file attributes. */
|
||||
mode_t st_attr;
|
||||
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;
|
||||
};
|
||||
|
||||
static inline int ConvertFileFlags(const char *Mode)
|
||||
{
|
||||
int Flags = 0;
|
||||
|
||||
if (strchr(Mode, '+'))
|
||||
Flags |= O_RDWR;
|
||||
else if (*Mode == 'r')
|
||||
Flags |= O_RDONLY;
|
||||
else
|
||||
Flags |= O_WRONLY;
|
||||
|
||||
if (strchr(Mode, 'x'))
|
||||
Flags |= O_EXCL;
|
||||
|
||||
if (strchr(Mode, 'e'))
|
||||
Flags |= O_CLOEXEC;
|
||||
|
||||
if (*Mode != 'r')
|
||||
Flags |= O_CREAT;
|
||||
|
||||
if (*Mode == 'w')
|
||||
Flags |= O_TRUNC;
|
||||
|
||||
if (*Mode == 'a')
|
||||
Flags |= O_APPEND;
|
||||
|
||||
return Flags;
|
||||
}
|
||||
#undef __check_op
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
enum NodeType : mode_t
|
||||
struct vfsInode
|
||||
{
|
||||
NODE_TYPE_NONE = 0x0,
|
||||
FILE = S_IFREG,
|
||||
DIRECTORY = S_IFDIR,
|
||||
CHARDEVICE = S_IFCHR,
|
||||
BLOCKDEVICE = S_IFBLK,
|
||||
PIPE = S_IFIFO,
|
||||
SYMLINK = S_IFLNK,
|
||||
MOUNTPOINT = S_IFDIR
|
||||
};
|
||||
|
||||
class RefNode;
|
||||
|
||||
/**
|
||||
* Virtual filesystem node
|
||||
*
|
||||
* @note https://isocpp.org/wiki/faq/freestore-mgmt#delete-this
|
||||
*/
|
||||
class Node
|
||||
{
|
||||
private:
|
||||
NewLock(NodeLock);
|
||||
|
||||
public:
|
||||
virtual int open(int Flags, mode_t Mode);
|
||||
virtual int close();
|
||||
virtual size_t read(uint8_t *Buffer, size_t Size, off_t Offset);
|
||||
virtual size_t write(uint8_t *Buffer, size_t Size, off_t Offset);
|
||||
virtual int ioctl(unsigned long Request, void *Argp);
|
||||
// virtual int stat(struct kstat *Stat);
|
||||
// virtual int lstat(struct kstat *Stat);
|
||||
// virtual int fstat(struct kstat *Stat);
|
||||
// virtual int unlink();
|
||||
// virtual int mkdir(mode_t Mode);
|
||||
// virtual int rmdir();
|
||||
// virtual int rename(const char *NewName);
|
||||
// virtual int chmod(mode_t Mode);
|
||||
// virtual int chown(uid_t User, gid_t Group);
|
||||
// virtual int truncate(off_t Size);
|
||||
// virtual int symlink(const char *Target);
|
||||
// virtual int readlink(char *Buffer, size_t Size);
|
||||
// virtual int mount(Node *Target);
|
||||
// virtual int umount();
|
||||
|
||||
typedef int (*open_t)(int, mode_t);
|
||||
typedef int (*close_t)();
|
||||
typedef size_t (*read_t)(uint8_t *, size_t, off_t);
|
||||
typedef size_t (*write_t)(uint8_t *, size_t, off_t);
|
||||
typedef int (*ioctl_t)(unsigned long, void *);
|
||||
|
||||
open_t open_ptr = nullptr;
|
||||
close_t close_ptr = nullptr;
|
||||
read_t read_ptr = nullptr;
|
||||
write_t write_ptr = nullptr;
|
||||
ioctl_t ioctl_ptr = nullptr;
|
||||
|
||||
class Virtual *vFS = nullptr;
|
||||
Node *Parent = nullptr;
|
||||
const char *Name;
|
||||
const char *FullPath;
|
||||
NodeType Type;
|
||||
ino_t IndexNode;
|
||||
|
||||
const char *Symlink;
|
||||
Node *SymlinkTarget;
|
||||
|
||||
mode_t Mode;
|
||||
uid_t UserIdentifier;
|
||||
gid_t GroupIdentifier;
|
||||
|
||||
dev_t DeviceMajor;
|
||||
dev_t DeviceMinor;
|
||||
|
||||
time_t AccessTime;
|
||||
time_t ModifyTime;
|
||||
time_t ChangeTime;
|
||||
|
||||
off_t Size;
|
||||
std::vector<Node *> Children;
|
||||
|
||||
std::vector<RefNode *> References;
|
||||
RefNode *CreateReference();
|
||||
void RemoveReference(RefNode *Reference);
|
||||
|
||||
/**
|
||||
* Create a new node
|
||||
*
|
||||
* @param Parent The parent node
|
||||
* @param Name The name of the node
|
||||
* @param Type The type of the node
|
||||
* @param NoParent If true, the Parent will
|
||||
* be used as a hint for the parent node, but it
|
||||
* won't be set as the parent node.
|
||||
* @param fs The virtual filesystem (only if
|
||||
* NoParent is set)
|
||||
* @param Err If not nullptr, the function will
|
||||
* write the error code to the given address.
|
||||
*/
|
||||
Node(Node *Parent,
|
||||
const char *Name,
|
||||
NodeType Type,
|
||||
bool NoParent = false,
|
||||
Virtual *fs = nullptr,
|
||||
int *Err = nullptr);
|
||||
|
||||
virtual ~Node();
|
||||
};
|
||||
|
||||
class RefNode
|
||||
{
|
||||
private:
|
||||
std::atomic_int64_t FileOffset = 0;
|
||||
off_t FileSize = 0;
|
||||
Node *n;
|
||||
RefNode *SymlinkTo;
|
||||
|
||||
public:
|
||||
void *SpecialData;
|
||||
|
||||
decltype(FileSize) &Size = FileSize;
|
||||
decltype(n) &node = n;
|
||||
|
||||
size_t read(uint8_t *Buffer, size_t Size);
|
||||
size_t write(uint8_t *Buffer, size_t Size);
|
||||
off_t seek(off_t Offset, int Whence);
|
||||
int ioctl(unsigned long Request, void *Argp);
|
||||
|
||||
RefNode(Node *node);
|
||||
~RefNode();
|
||||
|
||||
friend class Virtual;
|
||||
friend class FileDescriptorTable;
|
||||
Inode Node;
|
||||
std::string Name;
|
||||
std::vector<Inode *> Children;
|
||||
};
|
||||
|
||||
class Virtual
|
||||
{
|
||||
private:
|
||||
Node *FileSystemRoot = nullptr;
|
||||
NewLock(VirtualLock);
|
||||
|
||||
Node *GetParent(const char *Path, Node *Parent);
|
||||
/** @note This function is NOT thread safe */
|
||||
Node *GetNodeFromPath_Unsafe(const char *Path, Node *Parent = nullptr);
|
||||
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:
|
||||
Node *nRoot = nullptr;
|
||||
Node *GetNodeFromPath(const char *Path, Node *Parent = nullptr);
|
||||
vfsInode *FileSystemRoots = nullptr;
|
||||
|
||||
bool PathIsRelative(const char *Path);
|
||||
|
||||
Node *GetRootNode() { return FileSystemRoot; }
|
||||
|
||||
const char *NormalizePath(const char *Path, Node *Parent = nullptr);
|
||||
bool PathExists(const char *Path, Node *Parent = nullptr);
|
||||
|
||||
Node *Create(const char *Path, NodeType Type, Node *Parent = nullptr);
|
||||
Node *CreateLink(const char *Path, const char *Target, Node *Parent);
|
||||
|
||||
int Delete(const char *Path, bool Recursive = false, Node *Parent = nullptr);
|
||||
int Delete(Node *Path, bool Recursive = false, Node *Parent = nullptr);
|
||||
bool PathIsAbsolute(const char *Path) { return !PathIsRelative(Path); }
|
||||
|
||||
/**
|
||||
* Open a file
|
||||
* @param Path The path to the file, relative or absolute. The buffer shouldn't be modified while the function is running.
|
||||
* @param Parent Pointer to the parent node, if nullptr, the root node will be used.
|
||||
* @return A pointer to the vfs::ReferenceNode, or nullptr if the file doesn't exist.
|
||||
* Reserve a device number for a filesystem
|
||||
*
|
||||
* @note After this function is called, the filesystem must
|
||||
* call LateRegisterFileSystem to release the lock
|
||||
*/
|
||||
RefNode *Open(const char *Path, Node *Parent = nullptr);
|
||||
dev_t EarlyReserveDevice();
|
||||
|
||||
Node *CreateIfNotExists(const char *Path, NodeType Type, Node *Parent = nullptr);
|
||||
/**
|
||||
* 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();
|
||||
|
||||
friend class Node;
|
||||
};
|
||||
|
||||
class FileDescriptorTable
|
||||
@ -330,63 +157,59 @@ namespace vfs
|
||||
public:
|
||||
struct Fildes
|
||||
{
|
||||
RefNode *Handle = nullptr;
|
||||
enum FildesType
|
||||
{
|
||||
FD_INODE,
|
||||
FD_PIPE,
|
||||
FD_SOCKET,
|
||||
} Type;
|
||||
mode_t Mode = 0;
|
||||
int Flags = 0;
|
||||
int Descriptor = -1;
|
||||
FileNode *Node = nullptr;
|
||||
int References = 0;
|
||||
off_t Offset = 0;
|
||||
|
||||
int operator==(const Fildes &other)
|
||||
{
|
||||
return this->Handle == other.Handle &&
|
||||
this->Mode == other.Mode &&
|
||||
this->Flags == other.Flags &&
|
||||
this->Descriptor == other.Descriptor;
|
||||
return Type == other.Type &&
|
||||
Mode == other.Mode &&
|
||||
Flags == other.Flags &&
|
||||
Node == other.Node &&
|
||||
References == other.References &&
|
||||
Offset == other.Offset;
|
||||
}
|
||||
|
||||
int operator!=(const Fildes &other)
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
} __attribute__((packed)) nullfd;
|
||||
};
|
||||
|
||||
private:
|
||||
std::vector<Fildes> FileDescriptors;
|
||||
std::vector<Fildes> FildesDuplicates;
|
||||
vfs::Node *fdDir = nullptr;
|
||||
FileNode *fdDir = nullptr;
|
||||
void *Owner;
|
||||
|
||||
Fildes &GetFileDescriptor(int FileDescriptor);
|
||||
FileDescriptorTable::Fildes &GetDupFildes(int FileDescriptor);
|
||||
|
||||
int ProbeMode(mode_t Mode, int Flags);
|
||||
int AddFileDescriptor(const char *AbsolutePath, mode_t Mode, int Flags);
|
||||
int RemoveFileDescriptor(int FileDescriptor);
|
||||
int GetFreeFileDescriptor();
|
||||
|
||||
public:
|
||||
Fildes &GetDescriptor(int FileDescriptor);
|
||||
const char *GetAbsolutePath(int FileDescriptor);
|
||||
std::vector<Fildes> &GetFileDescriptors() { return FileDescriptors; }
|
||||
std::vector<Fildes> &GetFileDescriptorsDuplicates() { return FildesDuplicates; }
|
||||
RefNode *GetRefNode(int FileDescriptor);
|
||||
std::unordered_map<int, Fildes> FileMap;
|
||||
|
||||
int GetFlags(int FileDescriptor);
|
||||
int SetFlags(int FileDescriptor, int Flags);
|
||||
void Fork(FileDescriptorTable *Parent);
|
||||
|
||||
int _open(const char *pathname, int flags, mode_t mode);
|
||||
int _creat(const char *pathname, mode_t mode);
|
||||
ssize_t _read(int fd, void *buf, size_t count);
|
||||
ssize_t _write(int fd, const void *buf, size_t count);
|
||||
int _close(int fd);
|
||||
off_t _lseek(int fd, off_t offset, int whence);
|
||||
int _stat(const char *pathname, struct kstat *statbuf);
|
||||
int _fstat(int fd, struct kstat *statbuf);
|
||||
int _lstat(const char *pathname, struct kstat *statbuf);
|
||||
int _dup(int oldfd);
|
||||
int _dup2(int oldfd, int newfd);
|
||||
int _ioctl(int fd, unsigned long request, void *argp);
|
||||
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();
|
||||
~FileDescriptorTable() = default;
|
||||
};
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user