/* 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 #include "../kernel.h" namespace vfs { /* maj = 0 min: 0 - 1 - /proc/self 2 - /dev/null 3 - /dev/zero 4 - /dev/random 5 - /dev/mem */ 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; foreach (const auto &Root in Parent->Children) { char rootName[128]{}; snprintf(rootName, sizeof(rootName), "root-%ld", 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"); } ssize_t __vfs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset) { switch (Node->GetMinor()) { case 2: /* /dev/null */ { return 0; } case 3: /* /dev/zero */ { if (Size <= 0) return 0; memset(Buffer, 0, Size); return Size; } case 4: /* /dev/random */ { if (Size <= 0) return 0; if (Size < sizeof(uint64_t)) { uint8_t *buf = (uint8_t *)Buffer; for (size_t i = 0; i < Size; i++) buf[i] = (uint8_t)(Random::rand16() & 0xFF); return Size; } uint64_t *buf = (uint64_t *)Buffer; for (size_t i = 0; i < Size / sizeof(uint64_t); i++) buf[i] = Random::rand64(); return Size; } case 5: /* /dev/mem */ { stub; return 0; } default: return -ENOENT; }; } ssize_t __vfs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset) { switch (Node->GetMinor()) { case 2: /* /dev/null */ { return Size; } case 3: /* /dev/zero */ { return Size; } case 4: /* /dev/random */ { return Size; } case 5: /* /dev/mem */ { stub; return 0; } default: return -ENOENT; }; } /* This implementation is used internally by the kernel, so no "." & ".." */ 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; 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 *dev = this->ForceCreate(this->GetRoot(0), "dev", mode); FileNode *mnt = this->ForceCreate(this->GetRoot(0), "mnt", mode); FileNode *proc = this->ForceCreate(this->GetRoot(0), "proc", mode); FileNode *log = this->ForceCreate(this->GetRoot(0), "var", mode); log = this->ForceCreate(log, "log", mode); dev->Node->Flags = iFlags; mnt->Node->Flags = iFlags; 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; /* c rw- rw- rw- */ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH | S_IFCHR; FileNode *null = this->ForceCreate(dev, "null", mode); null->Node->Device = FileSystemRoots->Node.Device; null->Node->SetDevice(0, 2); null->Node->Flags = iFlags; /* c rw- rw- rw- */ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH | S_IFCHR; FileNode *zero = this->ForceCreate(dev, "zero", mode); zero->Node->Device = FileSystemRoots->Node.Device; zero->Node->SetDevice(0, 3); zero->Node->Flags = iFlags; /* c rw- rw- rw- */ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH | S_IFCHR; FileNode *random = this->ForceCreate(dev, "random", mode); random->Node->Device = FileSystemRoots->Node.Device; random->Node->SetDevice(0, 4); random->Node->Flags = iFlags; /* c rw- r-- --- */ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR; FileNode *mem = this->ForceCreate(dev, "mem", mode); mem->Node->Device = FileSystemRoots->Node.Device; mem->Node->SetDevice(0, 5); mem->Node->Flags = iFlags; new vfs::PTMXDevice(); } 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_MOUNTPOINT | I_FLAG_CACHE_KEEP; FileSystemRoots->Node.Offset = INT32_MAX; FileSystemRoots->Name = ""; FileSystemInfo *fsi = new FileSystemInfo; fsi->Name = "Virtual Roots"; fsi->Flags = I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP; fsi->SuperOps = {}; fsi->Ops.Lookup = __vfs_Lookup; fsi->Ops.Create = __vfs_Create; fsi->Ops.Read = __vfs_Read; fsi->Ops.Write = __vfs_Write; 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() { } }