mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-07-11 15:29:15 +00:00
Merge remote-tracking branch 'Kernel/master'
This commit is contained in:
257
Kernel/storage/virtual.cpp
Normal file
257
Kernel/storage/virtual.cpp
Normal file
@ -0,0 +1,257 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <filesystem.hpp>
|
||||
|
||||
#include <convert.h>
|
||||
#include <printf.h>
|
||||
#include <cwalk.h>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
/* maj = 0
|
||||
min:
|
||||
0 - <ROOT>
|
||||
1 - /proc/self
|
||||
...
|
||||
*/
|
||||
|
||||
int __vfs_Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result)
|
||||
{
|
||||
vfsInode *Parent = (vfsInode *)_Parent;
|
||||
|
||||
if (!S_ISDIR(Parent->Node.Mode))
|
||||
return -ENOTDIR;
|
||||
|
||||
assert(Parent->Node.Flags & I_FLAG_MOUNTPOINT);
|
||||
|
||||
if (Parent->Children.empty())
|
||||
return -ENOENT;
|
||||
|
||||
off_t offset = 0;
|
||||
for (const auto &Root : Parent->Children)
|
||||
{
|
||||
char rootName[128]{};
|
||||
snprintf(rootName, sizeof(rootName), "\x06root-%ld\x06", offset);
|
||||
|
||||
if (strcmp(rootName, Name) == 0)
|
||||
{
|
||||
*Result = Root;
|
||||
return 0;
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int __vfs_Create(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result)
|
||||
{
|
||||
assert(Parent != nullptr);
|
||||
assert(!"Not implemented");
|
||||
}
|
||||
|
||||
/* This implementation is used internally by the kernel, so no "." & ".." */
|
||||
__no_sanitize("alignment")
|
||||
ssize_t __vfs_Readdir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
|
||||
{
|
||||
if (_Node->GetMinor() != 0)
|
||||
{
|
||||
debug("_Node->GetMinor() != 0");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
assert(_Node->Flags & I_FLAG_MOUNTPOINT);
|
||||
|
||||
fixme("maybe wrong implementation of readdir");
|
||||
|
||||
size_t totalSize = 0;
|
||||
off_t entriesSkipped = 0;
|
||||
struct kdirent *ent = nullptr;
|
||||
vfsInode *Node = (vfsInode *)_Node;
|
||||
off_t entries = 0;
|
||||
foreach (const auto &Root in Node->Children)
|
||||
{
|
||||
if (entries >= Entries)
|
||||
break;
|
||||
|
||||
uint16_t reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen("root") + 1);
|
||||
|
||||
if (Offset > entriesSkipped)
|
||||
{
|
||||
entriesSkipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (totalSize + reclen >= Size)
|
||||
break;
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = Root->Index;
|
||||
ent->d_off = Root->Offset;
|
||||
ent->d_reclen = reclen;
|
||||
ent->d_type = IFTODT(Root->Mode);
|
||||
strncpy(ent->d_name, "root", strlen("root"));
|
||||
|
||||
totalSize += reclen;
|
||||
entries++;
|
||||
}
|
||||
|
||||
if (ent)
|
||||
ent->d_off = INT32_MAX;
|
||||
|
||||
if (totalSize + sizeof(struct kdirent) >= Size)
|
||||
return totalSize;
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = 0;
|
||||
ent->d_off = 0;
|
||||
ent->d_reclen = 0;
|
||||
ent->d_type = DT_UNKNOWN;
|
||||
ent->d_name[0] = '\0';
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
ssize_t __vfs_ReadLink(struct Inode *Node, char *Buffer, size_t Size)
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
/* FIXME: https://github.com/torvalds/linux/blob/c942a0cd3603e34dd2d7237e064d9318cb7f9654/fs/proc/self.c#L11
|
||||
https://lxr.linux.no/#linux+v3.2.9/fs/proc/base.c#L2482 */
|
||||
|
||||
int ret = snprintf(Buffer, Size, "/proc/%d", thisProcess->ID);
|
||||
debug("ReadLink: %s (%d bytes)", Buffer, ret);
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
void Virtual::Initialize()
|
||||
{
|
||||
SmartLock(VirtualLock);
|
||||
|
||||
trace("Initializing virtual file system...");
|
||||
uint32_t iFlags = I_FLAG_CACHE_KEEP;
|
||||
|
||||
/* d rwx rwx rwx */
|
||||
mode_t mode = S_IRWXU |
|
||||
S_IRWXG |
|
||||
S_IRWXO |
|
||||
S_IFDIR;
|
||||
FileNode *proc = this->ForceCreate(this->GetRoot(0), "proc", mode);
|
||||
FileNode *var = this->ForceCreate(this->GetRoot(0), "var", mode);
|
||||
FileNode *log = this->ForceCreate(var, "log", mode);
|
||||
proc->Node->Flags = iFlags;
|
||||
log->Node->Flags = iFlags;
|
||||
|
||||
/* l rwx rwx rwx */
|
||||
mode = S_IRWXU |
|
||||
S_IRWXG |
|
||||
S_IRWXO |
|
||||
S_IFLNK;
|
||||
FileNode *self = this->ForceCreate(proc, "self", mode);
|
||||
self->Node->Device = FileSystemRoots->Node.Device;
|
||||
self->Node->SetDevice(0, 1);
|
||||
self->Node->Flags = iFlags;
|
||||
}
|
||||
|
||||
dev_t Virtual::EarlyReserveDevice()
|
||||
{
|
||||
RegisterLock.store(true);
|
||||
size_t len = DeviceMap.size();
|
||||
return len;
|
||||
}
|
||||
|
||||
int Virtual::LateRegisterFileSystem(dev_t Device, FileSystemInfo *fsi, Inode *Root)
|
||||
{
|
||||
auto it = DeviceMap.find(Device);
|
||||
if (it != DeviceMap.end())
|
||||
ReturnLogError(-EEXIST, "Device %d already registered", Device);
|
||||
|
||||
Root->Flags |= I_FLAG_ROOT;
|
||||
FSMountInfo fsmi{.fsi = fsi, .Root = Root};
|
||||
DeviceMap.insert({Device, fsmi});
|
||||
RegisterLock.store(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_t Virtual::RegisterFileSystem(FileSystemInfo *fsi, Inode *Root)
|
||||
{
|
||||
RegisterLock.store(true);
|
||||
size_t len = DeviceMap.size();
|
||||
Root->Flags |= I_FLAG_ROOT;
|
||||
FSMountInfo fsmi{.fsi = fsi, .Root = Root};
|
||||
DeviceMap.insert({len, fsmi});
|
||||
RegisterLock.store(false);
|
||||
return len;
|
||||
}
|
||||
|
||||
int Virtual::UnregisterFileSystem(dev_t Device)
|
||||
{
|
||||
auto it = DeviceMap.find(Device);
|
||||
if (it == DeviceMap.end())
|
||||
ReturnLogError(-ENOENT, "Device %d not found", Device);
|
||||
|
||||
if (it->second.fsi->SuperOps.Synchronize)
|
||||
it->second.fsi->SuperOps.Synchronize(it->second.fsi, NULL);
|
||||
if (it->second.fsi->SuperOps.Destroy)
|
||||
it->second.fsi->SuperOps.Destroy(it->second.fsi);
|
||||
DeviceMap.erase(it);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Virtual::Virtual()
|
||||
{
|
||||
SmartLock(VirtualLock);
|
||||
|
||||
FileSystemRoots = new vfsInode;
|
||||
FileSystemRoots->Node.Index = -1;
|
||||
|
||||
FileSystemRoots->Node.Mode = S_IRWXU |
|
||||
S_IRWXG |
|
||||
S_IROTH | S_IXOTH |
|
||||
S_IFDIR;
|
||||
|
||||
FileSystemRoots->Node.Flags = I_FLAG_ROOT | I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
|
||||
|
||||
FileSystemRoots->Node.Offset = INT32_MAX;
|
||||
FileSystemRoots->Name = "<ROOT>";
|
||||
|
||||
FileSystemInfo *fsi = new FileSystemInfo;
|
||||
fsi->Name = "Virtual Roots";
|
||||
fsi->RootName = "ROOT";
|
||||
fsi->Flags = I_FLAG_ROOT | I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
|
||||
fsi->SuperOps = {};
|
||||
fsi->Ops.Lookup = __vfs_Lookup;
|
||||
fsi->Ops.Create = __vfs_Create;
|
||||
fsi->Ops.ReadDir = __vfs_Readdir;
|
||||
fsi->Ops.ReadLink = __vfs_ReadLink;
|
||||
|
||||
FileSystemRoots->Node.Device = this->RegisterFileSystem(fsi, &FileSystemRoots->Node);
|
||||
FileSystemRoots->Node.SetDevice(0, 0);
|
||||
}
|
||||
|
||||
Virtual::~Virtual()
|
||||
{
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user