mirror of
https://github.com/Fennix-Project/Kernel.git
synced 2025-07-26 22:51:44 +00:00
.github
.vscode
Architecture
Core
Execute
FileSystem
FS
Filesystem.cpp
Library
Profiling
Recovery
SystemCalls
Tasking
include
.gitignore
DAPI.hpp
Doxyfile
Fex.hpp
KConfig.cpp
KThread.cpp
Kernel.cpp
LICENSE
Makefile
README.md
dump.sh
kernel.h
syscalls.h
489 lines
15 KiB
C++
489 lines
15 KiB
C++
#include <filesystem.hpp>
|
|
|
|
#include <smartptr.hpp>
|
|
#include <convert.h>
|
|
#include <printf.h>
|
|
#include <lock.hpp>
|
|
#include <cwalk.h>
|
|
#include <sys.h>
|
|
|
|
#include "../kernel.h"
|
|
|
|
NewLock(VFSLock);
|
|
|
|
namespace FileSystem
|
|
{
|
|
char *Virtual::GetPathFromNode(FileSystemNode *Node)
|
|
{
|
|
vfsdbg("GetPathFromNode( Node: \"%s\" )", Node->Name);
|
|
FileSystemNode *Parent = Node;
|
|
Vector<char *> Path;
|
|
size_t Size = 1;
|
|
|
|
while (Parent != FileSystemRoot && Parent != nullptr)
|
|
{
|
|
foreach (auto var in FileSystemRoot->Children)
|
|
if (var == Parent)
|
|
goto PathFromNodeContinue;
|
|
Path.push_back(Parent->Name);
|
|
Path.push_back((char *)"/");
|
|
Parent = Parent->Parent;
|
|
}
|
|
|
|
PathFromNodeContinue:
|
|
Path.reverse();
|
|
|
|
foreach (auto var in Path)
|
|
Size += strlen(var);
|
|
|
|
char *FinalPath = new char[Size];
|
|
|
|
foreach (auto var in Path)
|
|
strcat(FinalPath, var);
|
|
|
|
// for (size_t i = 0; i < Path.size(); i++)
|
|
// strcat(FinalPath, Path[i]);
|
|
|
|
// for (size_t i = 0; i < Path.size(); i++)
|
|
// Size += strlen(Path[i]);
|
|
vfsdbg("GetPathFromNode()->\"%s\"", FinalPath);
|
|
return FinalPath;
|
|
}
|
|
|
|
FileSystemNode *Virtual::GetNodeFromPath(FileSystemNode *Parent, const char *Path)
|
|
{
|
|
vfsdbg("GetNodeFromPath( Parent: \"%s\" Path: \"%s\" )", Parent->Name, Path);
|
|
|
|
if (Parent == nullptr)
|
|
Parent = FileSystemRoot;
|
|
|
|
if (strcmp(Parent->Name, Path))
|
|
{
|
|
cwk_segment segment;
|
|
if (unlikely(!cwk_path_get_first_segment(Path, &segment)))
|
|
{
|
|
error("Path doesn't have any segments.");
|
|
return nullptr;
|
|
}
|
|
|
|
do
|
|
{
|
|
char *SegmentName = new char[segment.end - segment.begin + 1];
|
|
memcpy(SegmentName, segment.begin, segment.end - segment.begin);
|
|
GetNodeFromPathNextParent:
|
|
foreach (auto var in Parent->Children)
|
|
{
|
|
if (!strcmp(var->Name, SegmentName))
|
|
{
|
|
Parent = var;
|
|
goto GetNodeFromPathNextParent;
|
|
}
|
|
}
|
|
delete[] SegmentName;
|
|
} while (cwk_path_get_next_segment(&segment));
|
|
const char *basename;
|
|
cwk_path_get_basename(Path, &basename, nullptr);
|
|
if (!strcmp(basename, Parent->Name))
|
|
{
|
|
vfsdbg("GetNodeFromPath()->\"%s\"", Parent->Name);
|
|
return Parent;
|
|
}
|
|
|
|
vfsdbg("GetNodeFromPath()->\"%s\"", nullptr);
|
|
return nullptr;
|
|
}
|
|
else
|
|
{
|
|
vfsdbg("GetNodeFromPath()->\"%s\"", Parent->Name);
|
|
return Parent;
|
|
}
|
|
}
|
|
|
|
FileSystemNode *AddNewChild(FileSystemNode *Parent, const char *Name)
|
|
{
|
|
vfsdbg("AddNewChild( Parent: \"%s\" Name: \"%s\" )", Parent->Name, Name);
|
|
FileSystemNode *newNode = new FileSystemNode;
|
|
newNode->Parent = Parent;
|
|
strncpy(newNode->Name, Name, FILENAME_LENGTH);
|
|
if (likely(Parent))
|
|
newNode->Operator = Parent->Operator;
|
|
else
|
|
newNode->Operator = nullptr;
|
|
|
|
if (likely(Parent))
|
|
Parent->Children.push_back(newNode);
|
|
vfsdbg("AddNewChild()->\"%s\"", newNode->Name);
|
|
return newNode;
|
|
}
|
|
|
|
FileSystemNode *GetChild(FileSystemNode *Parent, const char *Name)
|
|
{
|
|
vfsdbg("GetChild( Parent: \"%s\" Name: \"%s\" )", Parent->Name, Name);
|
|
if (likely(Parent))
|
|
foreach (auto var in Parent->Children)
|
|
if (strcmp(var->Name, Name) == 0)
|
|
{
|
|
vfsdbg("GetChild()->\"%s\"", var->Name);
|
|
return var;
|
|
}
|
|
vfsdbg("GetChild()->nullptr");
|
|
return nullptr;
|
|
}
|
|
|
|
FileStatus RemoveChild(FileSystemNode *Parent, const char *Name)
|
|
{
|
|
vfsdbg("RemoveChild( Parent: \"%s\" Name: \"%s\" )", Parent->Name, Name);
|
|
for (uint64_t i = 0; i < Parent->Children.size(); i++)
|
|
if (strcmp(Parent->Children[i]->Name, Name) == 0)
|
|
{
|
|
Parent->Children.remove(i);
|
|
vfsdbg("RemoveChild()->OK");
|
|
return FileStatus::OK;
|
|
}
|
|
vfsdbg("RemoveChild()->NOT_FOUND");
|
|
return FileStatus::NOT_FOUND;
|
|
}
|
|
|
|
char *Virtual::NormalizePath(FileSystemNode *Parent, const char *Path)
|
|
{
|
|
vfsdbg("NormalizePath( Parent: \"%s\" Path: \"%s\" )", Parent->Name, Path);
|
|
char *NormalizedPath = new char[strlen((char *)Path) + 1];
|
|
char *RelativePath = nullptr;
|
|
|
|
cwk_path_normalize(Path, NormalizedPath, strlen((char *)Path) + 1);
|
|
|
|
if (cwk_path_is_relative(NormalizedPath))
|
|
{
|
|
char *ParentPath = GetPathFromNode(Parent);
|
|
size_t PathSize = cwk_path_get_absolute(ParentPath, NormalizedPath, nullptr, 0);
|
|
RelativePath = new char[PathSize + 1];
|
|
cwk_path_get_absolute(ParentPath, NormalizedPath, RelativePath, PathSize + 1);
|
|
delete[] ParentPath;
|
|
}
|
|
else
|
|
{
|
|
RelativePath = new char[strlen(NormalizedPath) + 1];
|
|
strcpy(RelativePath, NormalizedPath);
|
|
}
|
|
delete[] NormalizedPath;
|
|
vfsdbg("NormalizePath()->\"%s\"", RelativePath);
|
|
return RelativePath;
|
|
}
|
|
|
|
FileStatus Virtual::FileExists(FileSystemNode *Parent, const char *Path)
|
|
{
|
|
vfsdbg("FileExists( Parent: \"%s\" Path: \"%s\" )", Parent->Name, Path);
|
|
if (isempty((char *)Path))
|
|
return FileStatus::INVALID_PATH;
|
|
if (Parent == nullptr)
|
|
Parent = FileSystemRoot;
|
|
|
|
char *NormalizedPath = NormalizePath(Parent, Path);
|
|
FileSystemNode *Node = GetNodeFromPath(Parent, NormalizedPath);
|
|
|
|
if (!Node)
|
|
{
|
|
vfsdbg("FileExists()->NOT_FOUND");
|
|
return FileStatus::NOT_FOUND;
|
|
}
|
|
else
|
|
{
|
|
vfsdbg("FileExists()->OK");
|
|
return FileStatus::OK;
|
|
}
|
|
}
|
|
|
|
FileSystemNode *Virtual::Create(FileSystemNode *Parent, const char *Path)
|
|
{
|
|
SmartLock(VFSLock);
|
|
|
|
if (isempty((char *)Path))
|
|
return nullptr;
|
|
|
|
vfsdbg("Virtual::Create( Parent: \"%s\" Path: \"%s\" )", Parent->Name, Path);
|
|
|
|
FileSystemNode *CurrentParent = nullptr;
|
|
|
|
if (!Parent)
|
|
{
|
|
if (FileSystemRoot->Children.size() >= 1)
|
|
{
|
|
if (FileSystemRoot->Children[0] == nullptr)
|
|
panic("Root node is null!");
|
|
|
|
CurrentParent = FileSystemRoot->Children[0]; // 0 - filesystem root
|
|
}
|
|
else
|
|
{
|
|
// TODO: check if here is a bug or something...
|
|
const char *PathCopy;
|
|
size_t length;
|
|
PathCopy = (char *)Path;
|
|
cwk_path_get_root(PathCopy, &length); // not working?
|
|
foreach (auto var in FileSystemRoot->Children)
|
|
if (!strcmp(var->Name, PathCopy))
|
|
{
|
|
CurrentParent = var;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
CurrentParent = Parent;
|
|
|
|
char *CleanPath = NormalizePath(CurrentParent, Path);
|
|
|
|
if (FileExists(CurrentParent, CleanPath) != FileStatus::NOT_FOUND)
|
|
{
|
|
error("File %s already exists.", CleanPath);
|
|
goto CreatePathError;
|
|
}
|
|
|
|
cwk_segment segment;
|
|
if (!cwk_path_get_first_segment(CleanPath, &segment))
|
|
{
|
|
error("Path doesn't have any segments.");
|
|
goto CreatePathError;
|
|
}
|
|
|
|
warn("Virtual::Create( ) is not working properly.");
|
|
do
|
|
{
|
|
char *SegmentName = new char[segment.end - segment.begin + 1];
|
|
memcpy(SegmentName, segment.begin, segment.end - segment.begin);
|
|
|
|
if (GetChild(CurrentParent, SegmentName) == nullptr)
|
|
CurrentParent = AddNewChild(CurrentParent, SegmentName);
|
|
else
|
|
CurrentParent = GetChild(CurrentParent, SegmentName);
|
|
|
|
delete[] SegmentName;
|
|
} while (cwk_path_get_next_segment(&segment));
|
|
|
|
delete CleanPath;
|
|
vfsdbg("Virtual::Create()->\"%s\"", CurrentParent->Name);
|
|
return CurrentParent;
|
|
|
|
CreatePathError:
|
|
vfsdbg("Virtual::Create()->nullptr");
|
|
delete CleanPath;
|
|
return nullptr;
|
|
}
|
|
|
|
FileSystemNode *Virtual::CreateRoot(FileSystemOperations *Operator, const char *RootName)
|
|
{
|
|
if (Operator == nullptr)
|
|
return nullptr;
|
|
vfsdbg("Setting root to %s", RootName);
|
|
FileSystemNode *newNode = new FileSystemNode;
|
|
strncpy(newNode->Name, RootName, FILENAME_LENGTH);
|
|
newNode->Flags = NodeFlags::FS_DIRECTORY;
|
|
newNode->Operator = Operator;
|
|
FileSystemRoot->Children.push_back(newNode);
|
|
return newNode;
|
|
}
|
|
|
|
FILE *Virtual::Mount(FileSystemOperations *Operator, const char *Path)
|
|
{
|
|
SmartLock(VFSLock);
|
|
|
|
if (unlikely(!Operator))
|
|
return nullptr;
|
|
|
|
if (unlikely(isempty((char *)Path)))
|
|
return nullptr;
|
|
|
|
vfsdbg("Mounting %s", Path);
|
|
FILE *file = new FILE;
|
|
cwk_path_get_basename(Path, &file->Name, 0);
|
|
file->Status = FileStatus::OK;
|
|
file->Node = Create(nullptr, Path);
|
|
file->Node->Operator = Operator;
|
|
file->Node->Flags = NodeFlags::FS_MOUNTPOINT;
|
|
return file;
|
|
}
|
|
|
|
FileStatus Virtual::Unmount(FILE *File)
|
|
{
|
|
SmartLock(VFSLock);
|
|
if (unlikely(File))
|
|
return FileStatus::INVALID_PARAMETER;
|
|
vfsdbg("Unmounting %s", File->Name);
|
|
return FileStatus::OK;
|
|
}
|
|
|
|
FILE *Virtual::Open(const char *Path, FileSystemNode *Parent)
|
|
{
|
|
SmartLock(VFSLock);
|
|
vfsdbg("Opening %s with parent %s", Path, Parent->Name);
|
|
|
|
if (strcmp(Path, ".") == 0)
|
|
{
|
|
FILE *file = new FILE;
|
|
FileStatus filestatus = FileStatus::OK;
|
|
file->Node = Parent;
|
|
if (unlikely(!file->Node))
|
|
file->Status = FileStatus::NOT_FOUND;
|
|
const char *basename;
|
|
cwk_path_get_basename(GetPathFromNode(Parent), &basename, nullptr);
|
|
file->Name = basename;
|
|
return file;
|
|
}
|
|
|
|
if (strcmp(Path, "..") == 0)
|
|
{
|
|
if (Parent->Parent != nullptr)
|
|
Parent = Parent->Parent;
|
|
|
|
FILE *file = new FILE;
|
|
FileStatus filestatus = FileStatus::OK;
|
|
file->Node = Parent;
|
|
if (!file->Node)
|
|
file->Status = FileStatus::NOT_FOUND;
|
|
const char *basename;
|
|
cwk_path_get_basename(GetPathFromNode(Parent), &basename, nullptr);
|
|
file->Name = basename;
|
|
return file;
|
|
}
|
|
|
|
if (Parent == nullptr)
|
|
{
|
|
if (FileSystemRoot->Children.size() >= 1)
|
|
Parent = FileSystemRoot->Children[0]; // 0 - filesystem root
|
|
else
|
|
{
|
|
// TODO: check if here is a bug or something...
|
|
const char *PathCopy;
|
|
size_t length;
|
|
PathCopy = (char *)Path;
|
|
cwk_path_get_root(PathCopy, &length); // not working?
|
|
foreach (auto var in FileSystemRoot->Children)
|
|
if (!strcmp(var->Name, PathCopy))
|
|
{
|
|
Parent = var;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
char *CleanPath = NormalizePath(Parent, Path);
|
|
|
|
FILE *file = new FILE;
|
|
FileStatus filestatus = FileStatus::OK;
|
|
filestatus = FileExists(Parent, CleanPath);
|
|
/* TODO: Check for other errors */
|
|
|
|
if (filestatus != FileStatus::OK)
|
|
{
|
|
foreach (auto var in FileSystemRoot->Children)
|
|
if (!strcmp(var->Name, CleanPath))
|
|
{
|
|
file->Node = var;
|
|
if (file->Node == nullptr)
|
|
goto OpenNodeFail;
|
|
const char *basename;
|
|
cwk_path_get_basename(GetPathFromNode(var), &basename, nullptr);
|
|
file->Name = basename;
|
|
goto OpenNodeExit;
|
|
}
|
|
|
|
file->Node = GetNodeFromPath(FileSystemRoot->Children[0], CleanPath);
|
|
if (file->Node)
|
|
{
|
|
const char *basename;
|
|
cwk_path_get_basename(GetPathFromNode(file->Node), &basename, nullptr);
|
|
file->Name = basename;
|
|
goto OpenNodeExit;
|
|
}
|
|
|
|
OpenNodeFail:
|
|
file->Status = filestatus;
|
|
file->Node = nullptr;
|
|
}
|
|
else
|
|
{
|
|
file->Node = GetNodeFromPath(Parent, CleanPath);
|
|
if (unlikely(!file->Node))
|
|
file->Status = FileStatus::NOT_FOUND;
|
|
const char *basename;
|
|
cwk_path_get_basename(CleanPath, &basename, nullptr);
|
|
file->Name = basename;
|
|
return file;
|
|
}
|
|
OpenNodeExit:
|
|
return file;
|
|
}
|
|
|
|
uint64_t Virtual::Read(FILE *File, uint64_t Offset, uint8_t *Buffer, uint64_t Size)
|
|
{
|
|
SmartLock(VFSLock);
|
|
if (unlikely(!File))
|
|
return 0;
|
|
|
|
File->Status = FileStatus::OK;
|
|
|
|
if (unlikely(!File->Node))
|
|
{
|
|
File->Status = FileStatus::INVALID_PARAMETER;
|
|
return 0;
|
|
}
|
|
|
|
if (unlikely(!File->Node->Operator))
|
|
{
|
|
File->Status = FileStatus::INVALID_PARAMETER;
|
|
return 0;
|
|
}
|
|
vfsdbg("Reading %s out->%016x", File->Name, Buffer);
|
|
return File->Node->Operator->Read(File->Node, Offset, Size, Buffer);
|
|
}
|
|
|
|
uint64_t Virtual::Write(FILE *File, uint64_t Offset, uint8_t *Buffer, uint64_t Size)
|
|
{
|
|
SmartLock(VFSLock);
|
|
if (unlikely(!File))
|
|
return 0;
|
|
|
|
File->Status = FileStatus::OK;
|
|
|
|
if (unlikely(!File->Node))
|
|
{
|
|
File->Status = FileStatus::INVALID_PARAMETER;
|
|
return 0;
|
|
}
|
|
|
|
if (unlikely(!File->Node->Operator))
|
|
{
|
|
File->Status = FileStatus::INVALID_PARAMETER;
|
|
return 0;
|
|
}
|
|
vfsdbg("Writing %s out->%016x", File->Name, Buffer);
|
|
return File->Node->Operator->Write(File->Node, Offset, Size, Buffer);
|
|
}
|
|
|
|
FileStatus Virtual::Close(FILE *File)
|
|
{
|
|
SmartLock(VFSLock);
|
|
if (unlikely(!File))
|
|
return FileStatus::INVALID_HANDLE;
|
|
vfsdbg("Closing %s", File->Name);
|
|
delete File;
|
|
return FileStatus::OK;
|
|
}
|
|
|
|
Virtual::Virtual()
|
|
{
|
|
trace("Initializing virtual file system...");
|
|
FileSystemRoot = new FileSystemNode;
|
|
FileSystemRoot->Flags = NodeFlags::FS_MOUNTPOINT;
|
|
FileSystemRoot->Operator = nullptr;
|
|
FileSystemRoot->Parent = nullptr;
|
|
strncpy(FileSystemRoot->Name, "root", 4);
|
|
cwk_path_set_style(CWK_STYLE_UNIX);
|
|
}
|
|
|
|
Virtual::~Virtual()
|
|
{
|
|
warn("Tried to deinitialize Virtual File System!");
|
|
}
|
|
}
|