/* 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 . */ #include #include #include #include #include "../kernel.h" namespace vfs { /* maj = 0 min: 0 - 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 = ""; 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() { } }