fix(kernel/vfs): 🎉 a complete rewrite of the vfs

This is the fourth time re-writing the VFS, hope this will be the last. Tried to make it as modular as possible so this won't be necessary in the future. 🙏

This change required the entire kernel code to be modified.
This commit is contained in:
EnderIce2 2025-05-13 15:59:12 +00:00
parent 83a7f83f81
commit 557c7e6235
Signed by: enderice2
GPG Key ID: FEB6B8A8507BA62E
83 changed files with 3252 additions and 2487 deletions

110
Drivers/include/block.h Normal file
View File

@ -0,0 +1,110 @@
/*
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/>.
*/
#ifndef __FENNIX_API_BLOCK_H__
#define __FENNIX_API_BLOCK_H__
#include <types.h>
#if __has_include(<interface/fs.h>)
#include <interface/fs.h>
#else
#include <fs.h>
#endif
struct BlockDevice
{
/**
* @brief Base name of the device.
*
* This name is used to identify the device in the system. It should be unique
* across all block devices. The kernel may append a number to this name to
* create a unique device name (e.g., "ahci0", "ahci1").
*/
const char *Name;
/**
* @brief Total size of the device in bytes.
*
* This value represents the total addressable storage capacity of the device.
* It is used for bounds checking and partitioning.
*/
size_t Size;
/**
* @brief Size of a single block in bytes.
*
* All read and write operations are performed in multiples of this block size.
* Typical values are 512 or 4096 bytes.
*/
uint32_t BlockSize;
/**
* @brief Number of blocks in the device.
*
* This value is calculated as Size / BlockSize. It represents the total number
* of addressable blocks on the device.
*/
size_t BlockCount;
/**
* @brief Pointer to the block device operations structure.
*
* This structure contains function pointers for various operations that can
* be performed on the block device, such as read, write, and ioctl.
*
* Yea, inode operations are used for block devices too.
*/
const InodeOperations *Ops;
/**
* @brief Opaque pointer to driver-specific or hardware-specific data.
*
* This field allows the driver to associate private context or state with the
* device, such as controller registers or internal buffers.
*/
void *PrivateData;
};
#ifndef __kernel__
/**
* @brief Registers a block device with the kernel block subsystem.
*
* This function should be called by block device drivers after initializing
* a device. The kernel will take ownership of the device structure and assign
* it a unique device ID. The device will then be accessible for filesystem
* mounting and I/O operations.
*
* @param Device Pointer to a fully initialized BlockDevice structure. All required fields must be set and valid for the lifetime of the device.
* @return Device ID (dev_t) assigned by the kernel on success, or an error code on failure.
*/
dev_t RegisterBlockDevice(struct BlockDevice *Device);
/**
* @brief Unregisters a block device from the kernel block subsystem.
*
* This function should be called by drivers when a device is being removed
* or is no longer available. The kernel will release any resources associated
* with the device and invalidate its device ID.
*
* @param DeviceID The device ID (dev_t) previously returned by RegisterBlockDevice().
* @return 0 on success, or an error code.
*/
int UnregisterBlockDevice(dev_t DeviceID);
#endif // __kernel__
#endif // __FENNIX_API_BLOCK_H__

View File

@ -322,10 +322,6 @@ struct InodeOperations
int (*Stat)(struct Inode *Node, struct kstat *Stat);
} __attribute__((packed));
#define I_FLAG_ROOT 0x1
#define I_FLAG_MOUNTPOINT 0x2
#define I_FLAG_CACHE_KEEP 0x4
struct FileSystemInfo;
struct SuperBlockOperations
{
@ -337,8 +333,8 @@ struct SuperBlockOperations
*
* Write all pending changes to the disk.
*
* @param Info Inode to synchronize. If NULL, synchronize all inodes.
* @param Node Inode to synchronize.
* @param Info Inode to synchronize.
* @param Node Inode to synchronize. If NULL, synchronize all inodes.
*
* @return Zero on success, otherwise an error code.
*/
@ -354,13 +350,50 @@ struct SuperBlockOperations
* @return Zero on success, otherwise an error code.
*/
int (*Destroy)(struct FileSystemInfo *Info);
/**
* Probe the filesystem.
*
* Check if the filesystem is supported by the driver.
*
* @param Device Device to probe.
*
* @return Zero on success, otherwise an error code.
*/
int (*Probe)(void *Device);
/**
* Mount the filesystem.
*
* Mount the filesystem on the given device.
*
* @param FS Filesystem to mount.
* @param Root Pointer to the root inode.
* @param Device Device to mount.
*
* @return Zero on success, otherwise an error code.
*/
int (*Mount)(struct FileSystemInfo *FS, struct Inode **Root, void *Device);
/**
* Unmount the filesystem.
*
* Unmount the filesystem from the given device.
*
* @param FS Filesystem to unmount.
*
* @return Zero on success, otherwise an error code.
*/
int (*Unmount)(struct FileSystemInfo *FS);
} __attribute__((packed));
struct FileSystemInfo
{
const char *Name;
const char *RootName;
int Flags;
int Capabilities;
struct SuperBlockOperations SuperOps;
struct InodeOperations Ops;
@ -368,6 +401,9 @@ struct FileSystemInfo
} __attribute__((packed));
#ifndef __kernel__
dev_t RegisterMountPoint(FileSystemInfo *fsi, Inode *Root);
int UnregisterMountPoint(dev_t Device);
dev_t RegisterFileSystem(struct FileSystemInfo *Info, struct Inode *Root);
int UnregisterFileSystem(dev_t Device);
#endif // !__kernel__

View File

@ -9,7 +9,7 @@
- [ ] ~~Do not map the entire memory. Map only the needed memory address at allocation time.~~ (we just copy the pages for userland, see `Fork()` inside [core/memory/page_table.cpp](core/memory/page_table.cpp))
- [ ] Implementation of logging (beside serial) with log rotation.
- [x] Implement a better task manager. (replace struct P/TCB with classes)
- [ ] Rewrite virtual file system.
- [x] Rewrite virtual file system.
- [ ] Colors in crash screen are not following the kernel color scheme.
- [x] ~~Find a way to add intrinsics.~~ (not feasible, use inline assembly)
- [ ] Rework PSF1 font loader.

View File

@ -156,15 +156,15 @@ namespace KernelConsole
bool SetTheme(std::string Theme)
{
FileNode *rn = fs->GetByPath("/sys/cfg/term", thisProcess->Info.RootNode);
Node rn = fs->Lookup(thisProcess->Info.RootNode, "/sys/cfg/term");
if (rn == nullptr)
return false;
kstat st{};
rn->Stat(&st);
kstat st;
fs->Stat(rn, &st);
char *sh = new char[st.Size];
rn->Read(sh, st.Size, 0);
fs->Read(rn, sh, st.Size, 0);
ini_t *ini = ini_load(sh, NULL);
int themeSection, c0, c1, c2, c3, c4, c5, c6, c7, colorsIdx;
@ -370,16 +370,16 @@ namespace KernelConsole
void LateInit()
{
FileNode *rn = fs->GetByPath("/sys/cfg/term", thisProcess->Info.RootNode);
Node rn = fs->Lookup(thisProcess->Info.RootNode, "/sys/cfg/term");
if (rn == nullptr)
return;
{
kstat st;
rn->Stat(&st);
fs->Stat(rn, &st);
std::string cfg;
cfg.reserve(st.Size);
rn->Read(cfg.data(), st.Size, 0);
cfg.resize(st.Size);
fs->Read(rn, cfg.data(), st.Size, 0);
LoadConsoleConfig(cfg);
}

View File

@ -191,11 +191,11 @@ namespace v0
/* --------- */
dev_t RegisterFileSystem(dev_t DriverID, FileSystemInfo *Info, struct Inode *Root)
dev_t RegisterFileSystem(dev_t DriverID, FileSystemInfo *Info)
{
dbg_api("%d, %#lx, %#lx", DriverID, Info, Root);
dbg_api("%d, %#lx", DriverID, Info);
return fs->RegisterFileSystem(Info, Root);
return fs->RegisterFileSystem(Info);
}
int UnregisterFileSystem(dev_t DriverID, dev_t Device)
@ -710,6 +710,20 @@ namespace v0
return DriverManager->ReportInputEvent(DriverID, Report);
}
dev_t RegisterBlockDevice(dev_t DriverID, struct BlockDevice *Device)
{
dbg_api("%d, %#lx", DriverID, Device);
return DriverManager->RegisterBlockDevice(DriverID, Device);
}
int UnregisterBlockDevice(dev_t DriverID, dev_t DeviceID)
{
dbg_api("%d, %d", DriverID, DeviceID);
return DriverManager->UnregisterBlockDevice(DriverID, DeviceID);
}
}
struct APISymbols
@ -777,6 +791,8 @@ static struct APISymbols APISymbols_v0[] = {
{"__RegisterDevice", (void *)v0::RegisterDevice},
{"__UnregisterDevice", (void *)v0::UnregisterDevice},
{"__ReportInputEvent", (void *)v0::ReportInputEvent},
{"__RegisterBlockDevice", (void *)v0::RegisterBlockDevice},
{"__UnregisterBlockDevice", (void *)v0::UnregisterBlockDevice},
};
long __KernelUndefinedFunction(long arg0, long arg1, long arg2, long arg3,

View File

@ -1,726 +0,0 @@
/*
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 <driver.hpp>
#include <interface/driver.h>
#include <interface/input.h>
#include <memory.hpp>
#include <stropts.h>
#include <ints.hpp>
#include <task.hpp>
#include <printf.h>
#include <exec.hpp>
#include <rand.hpp>
#include <cwalk.h>
#include <md5.h>
#include "../../kernel.h"
using namespace vfs;
namespace Driver
{
/**
* maj = 0
* min:
* 0 - <ROOT>
* 1 - /proc/self
*
* maj = 1
* min:
* 0 - /dev/input/keyboard
* 1 - /dev/input/mouse
* ..- /dev/input/eventN
*/
int __fs_Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result)
{
func("%#lx %s %#lx", _Parent, Name, Result);
assert(_Parent != nullptr);
const char *basename;
size_t length;
cwk_path_get_basename(Name, &basename, &length);
if (basename == NULL)
{
error("Invalid name %s", Name);
return -EINVAL;
}
auto Parent = (Manager::DeviceInode *)_Parent;
for (const auto &child : Parent->Children)
{
debug("Comparing %s with %s", basename, child->Name.c_str());
if (strcmp(child->Name.c_str(), basename) != 0)
continue;
*Result = &child->Node;
return 0;
}
debug("Not found %s", Name);
return -ENOENT;
}
int __fs_Create(struct Inode *_Parent, const char *Name, mode_t Mode, struct Inode **Result)
{
func("%#lx %s %d", _Parent, Name, Mode);
assert(_Parent != nullptr);
/* We expect to be /dev or children of it */
auto Parent = (Manager::DeviceInode *)_Parent;
auto _dev = new Manager::DeviceInode;
_dev->Parent = nullptr;
_dev->ParentInode = _Parent;
_dev->Name = Name;
_dev->Node.Device = Parent->Node.Device;
_dev->Node.Mode = Mode;
_dev->Node.Index = Parent->Node.Index + Parent->Children.size();
_dev->Node.Offset = Parent->Children.size();
Parent->Children.push_back(_dev);
*Result = &_dev->Node;
return 0;
}
ssize_t __fs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
{
func("%#lx %d %d", Node, Size, Offset);
switch (Node->GetMajor())
{
case 1:
{
switch (Node->GetMinor())
{
case 0: /* /dev/input/keyboard */
{
if (Size < sizeof(KeyboardReport))
return -EINVAL;
size_t nReads = Size / sizeof(KeyboardReport);
KeyboardReport *report = (KeyboardReport *)Buffer;
while (DriverManager->GlobalKeyboardInputReports.Count() == 0)
TaskManager->Yield();
DriverManager->GlobalKeyboardInputReports.Read(report, nReads);
return sizeof(KeyboardReport) * nReads;
}
case 1: /* /dev/input/mouse */
{
if (Size < sizeof(MouseReport))
return -EINVAL;
size_t nReads = Size / sizeof(MouseReport);
MouseReport *report = (MouseReport *)Buffer;
while (DriverManager->GlobalMouseInputReports.Count() == 0)
TaskManager->Yield();
DriverManager->GlobalMouseInputReports.Read(report, nReads);
return sizeof(MouseReport) * nReads;
}
default:
return -ENOENT;
};
}
default:
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(Node->GetMajor());
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Node->GetMinor());
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
AssertReturnError(dOps->second.Ops, -ENOTSUP);
AssertReturnError(dOps->second.Ops->Read, -ENOTSUP);
return dOps->second.Ops->Read(Node, Buffer, Size, Offset);
}
}
}
ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
{
func("%#lx %p %d %d", Node, Buffer, Size, Offset);
switch (Node->GetMajor())
{
case 1:
{
switch (Node->GetMinor())
{
case 0: /* /dev/input/keyboard */
{
return -ENOTSUP;
}
case 1: /* /dev/input/mouse */
{
return -ENOTSUP;
}
default:
return -ENOENT;
};
}
default:
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(Node->GetMajor());
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Node->GetMinor());
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
AssertReturnError(dOps->second.Ops, -ENOTSUP);
AssertReturnError(dOps->second.Ops->Write, -ENOTSUP);
return dOps->second.Ops->Write(Node, Buffer, Size, Offset);
}
}
}
int __fs_Open(struct Inode *Node, int Flags, mode_t Mode)
{
func("%#lx %d %d", Node, Flags, Mode);
switch (Node->GetMajor())
{
case 1:
{
switch (Node->GetMinor())
{
case 0: /* /dev/input/keyboard */
case 1: /* /dev/input/mouse */
return -ENOTSUP;
default:
return -ENOENT;
};
}
default:
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(Node->GetMajor());
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Node->GetMinor());
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
AssertReturnError(dOps->second.Ops, -ENOTSUP);
AssertReturnError(dOps->second.Ops->Open, -ENOTSUP);
return dOps->second.Ops->Open(Node, Flags, Mode);
}
}
}
int __fs_Close(struct Inode *Node)
{
func("%#lx", Node);
switch (Node->GetMajor())
{
case 1:
{
switch (Node->GetMinor())
{
case 0: /* /dev/input/keyboard */
case 1: /* /dev/input/mouse */
return -ENOTSUP;
default:
return -ENOENT;
};
}
default:
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(Node->GetMajor());
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Node->GetMinor());
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
AssertReturnError(dOps->second.Ops, -ENOTSUP);
AssertReturnError(dOps->second.Ops->Close, -ENOTSUP);
return dOps->second.Ops->Close(Node);
}
}
}
int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
{
func("%#lx %lu %#lx", Node, Request, Argp);
switch (Node->GetMajor())
{
case 1:
{
switch (Node->GetMinor())
{
case 0: /* /dev/input/keyboard */
case 1: /* /dev/input/mouse */
return -ENOSYS;
default:
return -ENOENT;
};
}
default:
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(Node->GetMajor());
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Node->GetMinor());
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
AssertReturnError(dOps->second.Ops, -ENOTSUP);
AssertReturnError(dOps->second.Ops->Ioctl, -ENOTSUP);
return dOps->second.Ops->Ioctl(Node, Request, Argp);
}
}
}
__no_sanitize("alignment")
ssize_t __fs_Readdir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
{
func("%#lx %#lx %d %d %d", _Node, Buffer, Size, Offset, Entries);
auto Node = (Manager::DeviceInode *)_Node;
off_t realOffset = Offset;
size_t totalSize = 0;
uint16_t reclen = 0;
struct kdirent *ent = nullptr;
if (Offset == 0)
{
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(".") + 1);
if (totalSize + reclen >= Size)
return -EINVAL;
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
ent->d_ino = Node->Node.Index;
ent->d_off = Offset++;
ent->d_reclen = reclen;
ent->d_type = DT_DIR;
strcpy(ent->d_name, ".");
totalSize += reclen;
}
if (Offset <= 1)
{
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen("..") + 1);
if (totalSize + reclen >= Size)
{
if (realOffset == 1)
return -EINVAL;
return totalSize;
}
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
if (Node->Parent)
ent->d_ino = Node->Parent->Node->Index;
else if (Node->ParentInode)
ent->d_ino = Node->ParentInode->Index;
else
{
warn("Parent is null for %s", Node->Name.c_str());
ent->d_ino = Node->Node.Index;
}
ent->d_off = Offset++;
ent->d_reclen = reclen;
ent->d_type = DT_DIR;
strcpy(ent->d_name, "..");
totalSize += reclen;
}
if (!S_ISDIR(Node->Node.Mode))
return -ENOTDIR;
if ((Offset >= 2 ? (Offset - 2) : Offset) > (off_t)Node->Children.size())
return -EINVAL;
off_t entries = 0;
for (const auto &var : Node->Children)
{
debug("iterating \"%s\" inside \"%s\"", var->Name.c_str(), Node->Name.c_str());
if (var->Node.Offset < realOffset)
{
debug("skipping \"%s\" (%d < %d)", var->Name.c_str(), var->Node.Offset, Offset);
continue;
}
if (entries >= Entries)
break;
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(var->Name.c_str()) + 1);
if (totalSize + reclen >= Size)
break;
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
ent->d_ino = var->Node.Index;
ent->d_off = var->Node.Offset;
ent->d_reclen = reclen;
ent->d_type = IFTODT(var->Node.Mode);
strncpy(ent->d_name, var->Name.c_str(), strlen(var->Name.c_str()));
totalSize += reclen;
entries++;
}
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;
}
void ManagerDaemonWrapper() { DriverManager->Daemon(); }
void Manager::Daemon()
{
while (true)
{
TaskManager->Sleep(1000);
}
}
dev_t Manager::RegisterInputDevice(std::unordered_map<dev_t, DriverHandlers> *dop,
dev_t DriverID, size_t i, const InodeOperations *Operations)
{
std::string prefix = "event";
for (size_t j = 0; j < 128; j++)
{
std::string deviceName = prefix + std::to_string(j);
FileNode *node = fs->GetByPath(deviceName.c_str(), devInputNode);
if (node)
continue;
/* c rwx r-- r-- */
mode_t mode = S_IRWXU |
S_IRGRP |
S_IROTH |
S_IFCHR;
node = fs->ForceCreate(devInputNode, deviceName.c_str(), mode);
node->Node->SetDevice(DriverID, i);
DriverHandlers dh{};
dh.Ops = Operations;
dh.Node = node->Node;
dh.InputReports = new RingBuffer<InputReport>(16);
dop->insert({i, std::move(dh)});
return i;
}
ReturnLogError(-1, "No available slots for device %d", DriverID);
return -1; /* -Werror=return-type */
}
dev_t Manager::RegisterBlockDevice(std::unordered_map<dev_t, DriverHandlers> *dop,
dev_t DriverID, size_t i, const InodeOperations *Operations)
{
std::string prefix = "event";
for (size_t j = 0; j < 128; j++)
{
std::string deviceName = prefix + std::to_string(j);
FileNode *node = fs->GetByPath(deviceName.c_str(), devInputNode);
if (node)
continue;
/* c rwx r-- r-- */
mode_t mode = S_IRWXU |
S_IRGRP |
S_IROTH |
S_IFBLK;
node = fs->ForceCreate(devInputNode, deviceName.c_str(), mode);
node->Node->SetDevice(DriverID, i);
DriverHandlers dh{};
dh.Ops = Operations;
dh.Node = node->Node;
dh.InputReports = new RingBuffer<InputReport>(16);
dop->insert({i, std::move(dh)});
return i;
}
ReturnLogError(-1, "No available slots for device %d", DriverID);
return -1; /* -Werror=return-type */
}
dev_t Manager::RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations)
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
const auto it = drivers.find(DriverID);
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
for (size_t i = 0; i < 128; i++)
{
const auto dOps = dop->find(i);
const auto dOpsEnd = dop->end();
if (dOps != dOpsEnd)
continue;
DeviceType devType = (DeviceType)(Type & DEVICE_TYPE_MASK);
switch (devType)
{
case DEVICE_TYPE_INPUT:
return RegisterInputDevice(dop, DriverID, i, Operations);
case DEVICE_TYPE_BLOCK:
return RegisterBlockDevice(dop, DriverID, i, Operations);
default:
ReturnLogError(-1, "Invalid device type %d", Type);
}
}
ReturnLogError(-1, "No available slots for device %d", DriverID);
}
dev_t Manager::CreateDeviceFile(dev_t DriverID, const char *name, mode_t mode, const InodeOperations *Operations)
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
const auto it = drivers.find(DriverID);
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
for (size_t i = 0; i < 128; i++)
{
const auto dOps = dop->find(i);
if (dOps != dop->end())
continue;
FileNode *node = fs->GetByPath(name, devNode);
if (node)
ReturnLogError(-EEXIST, "Device file %s already exists", name);
node = fs->Create(devNode, name, mode);
if (node == nullptr)
ReturnLogError(-ENOMEM, "Failed to create device file %s", name);
node->Node->SetDevice(DriverID, i);
DriverHandlers dh{};
dh.Ops = Operations;
dh.Node = node->Node;
dh.InputReports = new RingBuffer<InputReport>(16);
dop->insert({i, std::move(dh)});
return i;
}
ReturnLogError(-1, "No available slots for device %d", DriverID);
return -1; /* -Werror=return-type */
}
int Manager::UnregisterDevice(dev_t DriverID, dev_t Device)
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
const auto it = drivers.find(DriverID);
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
const auto dOps = dop->find(Device);
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Device);
dop->erase(dOps);
fixme("remove eventX from /dev/input");
fixme("delete InputReports");
return 0;
}
void *Manager::AllocateMemory(dev_t DriverID, size_t Pages)
{
auto itr = Drivers.find(DriverID);
assert(itr != Drivers.end());
void *ptr = itr->second.vma->RequestPages(Pages);
memset(ptr, 0, FROM_PAGES(Pages));
return ptr;
}
void Manager::FreeMemory(dev_t DriverID, void *Pointer, size_t Pages)
{
auto itr = Drivers.find(DriverID);
assert(itr != Drivers.end());
itr->second.vma->FreePages(Pointer, Pages);
}
int Manager::ReportInputEvent(dev_t DriverID, InputReport *Report)
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(DriverID);
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Report->Device);
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Report->Device);
dOps->second.InputReports->Write(Report, 1);
switch (Report->Type)
{
case INPUT_TYPE_KEYBOARD:
{
KeyboardReport *kReport = &Report->Keyboard;
GlobalKeyboardInputReports.Write(kReport, 1);
break;
}
case INPUT_TYPE_MOUSE:
{
MouseReport *mReport = &Report->Mouse;
GlobalMouseInputReports.Write(mReport, 1);
break;
}
default:
assert(!"Invalid input type");
}
return 0;
}
void Manager::InitializeDaemonFS()
{
dev_t MinorID = 0;
DeviceInode *_dev = new DeviceInode;
_dev->Name = "dev";
/* d rwx r-- r-- */
mode_t mode = S_IRWXU |
S_IRGRP |
S_IROTH |
S_IFDIR;
Inode *dev = (Inode *)_dev;
dev->Mode = mode;
dev->Flags = I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
FileSystemInfo *fsi = new FileSystemInfo;
fsi->Name = "Device Virtual File System";
fsi->RootName = "dev";
fsi->Flags = I_FLAG_ROOT | I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
fsi->SuperOps = {};
fsi->Ops.Lookup = __fs_Lookup;
fsi->Ops.Create = __fs_Create;
fsi->Ops.Remove = nullptr;
fsi->Ops.Rename = nullptr;
fsi->Ops.Read = __fs_Read;
fsi->Ops.Write = __fs_Write;
fsi->Ops.Truncate = nullptr;
fsi->Ops.Open = __fs_Open;
fsi->Ops.Close = __fs_Close;
fsi->Ops.Ioctl = __fs_Ioctl;
fsi->Ops.ReadDir = __fs_Readdir;
fsi->Ops.MkDir = nullptr;
fsi->Ops.RmDir = nullptr;
fsi->Ops.SymLink = nullptr;
fsi->Ops.ReadLink = nullptr;
fsi->Ops.Seek = nullptr;
fsi->Ops.Stat = nullptr;
dev->Device = fs->RegisterFileSystem(fsi, dev);
dev->SetDevice(0, MinorID++);
MinorID++; /* 1 = /proc/self */
devNode = fs->Mount(fs->GetRoot(0), dev, "/dev");
_dev->Parent = devNode->Parent;
_dev->ParentInode = devNode->Parent->Node;
/* d rwx r-- r-- */
mode = S_IRWXU |
S_IRGRP |
S_IROTH |
S_IFDIR;
DeviceInode *input = new DeviceInode;
input->Parent = devNode;
input->ParentInode = devNode->Node;
input->Name = "input";
input->Node.Device = dev->Device;
input->Node.Mode = mode;
input->Node.Flags = I_FLAG_CACHE_KEEP;
input->Node.Offset = _dev->Children.size();
_dev->Children.push_back(input);
devInputNode = fs->GetByPath("input", devNode);
auto createDevice = [](DeviceInode *p1, FileNode *p2, const std::string &name, dev_t maj, dev_t min, mode_t mode)
{
DeviceInode *device = new DeviceInode;
device->Parent = p2;
device->ParentInode = p2->Node;
device->Name = name;
device->Node.Device = p2->Node->Device;
device->Node.Mode = mode;
device->Node.SetDevice(maj, min);
device->Node.Flags = I_FLAG_CACHE_KEEP;
device->Node.Offset = p1->Children.size();
p1->Children.push_back(device);
};
MinorID = 0;
/* c rw- r-- --- */
mode = S_IRUSR | S_IWUSR |
S_IRGRP |
S_IFCHR;
createDevice(input, devInputNode, "keyboard", 1, MinorID++, mode);
/* c rw- r-- --- */
mode = S_IRUSR | S_IWUSR |
S_IRGRP |
S_IFCHR;
createDevice(input, devInputNode, "mouse", 1, MinorID++, mode);
}
}

483
Kernel/core/driver/dev.cpp Normal file
View File

@ -0,0 +1,483 @@
/*
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 <driver.hpp>
#include "../../kernel.h"
namespace Driver
{
dev_t DeviceDirID;
int __fs_Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result)
{
func("%#lx %s %#lx", _Parent, Name, Result);
assert(_Parent != nullptr);
const char *basename;
size_t length;
cwk_path_get_basename(Name, &basename, &length);
if (basename == NULL)
{
error("Invalid name %s", Name);
return -EINVAL;
}
auto Parent = (Manager::DeviceInode *)_Parent;
for (const auto &child : Parent->Children)
{
debug("Comparing %s with %s", basename, child->Name.c_str());
if (strcmp(child->Name.c_str(), basename) != 0)
continue;
*Result = &child->inode;
return 0;
}
debug("Not found %s", Name);
return -ENOENT;
}
int __fs_Create(struct Inode *_Parent, const char *Name, mode_t Mode, struct Inode **Result)
{
func("%#lx %s %d", _Parent, Name, Mode);
assert(_Parent != nullptr);
/* We expect to be /dev or children of it */
auto Parent = (Manager::DeviceInode *)_Parent;
auto _dev = new Manager::DeviceInode;
_dev->Parent = nullptr;
_dev->ParentInode = _Parent;
_dev->Name = Name;
_dev->inode.Device = Parent->inode.Device;
_dev->inode.Mode = Mode;
_dev->inode.Index = Parent->inode.Index + Parent->Children.size();
_dev->inode.Offset = Parent->Children.size();
Parent->Children.push_back(_dev);
*Result = &_dev->inode;
return 0;
}
ssize_t __fs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
{
func("%#lx %d %d", Node, Size, Offset);
if ((dev_t)Node->GetMajor() == DeviceDirID)
{
switch (Node->GetMinor())
{
case 0: /* /dev/input/keyboard */
{
if (Size < sizeof(KeyboardReport))
return -EINVAL;
size_t nReads = Size / sizeof(KeyboardReport);
KeyboardReport *report = (KeyboardReport *)Buffer;
while (DriverManager->GlobalKeyboardInputReports.Count() == 0)
TaskManager->Yield();
DriverManager->GlobalKeyboardInputReports.Read(report, nReads);
return sizeof(KeyboardReport) * nReads;
}
case 1: /* /dev/input/mouse */
{
if (Size < sizeof(MouseReport))
return -EINVAL;
size_t nReads = Size / sizeof(MouseReport);
MouseReport *report = (MouseReport *)Buffer;
while (DriverManager->GlobalMouseInputReports.Count() == 0)
TaskManager->Yield();
DriverManager->GlobalMouseInputReports.Read(report, nReads);
return sizeof(MouseReport) * nReads;
}
default:
return -ENOENT;
};
}
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(Node->GetMajor());
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Node->GetMinor());
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
AssertReturnError(dOps->second.Ops, -ENOTSUP);
AssertReturnError(dOps->second.Ops->Read, -ENOTSUP);
return dOps->second.Ops->Read(Node, Buffer, Size, Offset);
}
ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
{
func("%#lx %p %d %d", Node, Buffer, Size, Offset);
if ((dev_t)Node->GetMajor() == DeviceDirID)
{
switch (Node->GetMinor())
{
case 0: /* /dev/input/keyboard */
{
return -ENOTSUP;
}
case 1: /* /dev/input/mouse */
{
return -ENOTSUP;
}
default:
return -ENOENT;
};
}
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(Node->GetMajor());
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Node->GetMinor());
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
AssertReturnError(dOps->second.Ops, -ENOTSUP);
AssertReturnError(dOps->second.Ops->Write, -ENOTSUP);
return dOps->second.Ops->Write(Node, Buffer, Size, Offset);
}
int __fs_Open(struct Inode *Node, int Flags, mode_t Mode)
{
func("%#lx %d %d", Node, Flags, Mode);
if ((dev_t)Node->GetMajor() == DeviceDirID)
{
switch (Node->GetMinor())
{
case 0: /* /dev/input/keyboard */
case 1: /* /dev/input/mouse */
return -ENOTSUP;
default:
return -ENOENT;
};
}
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(Node->GetMajor());
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Node->GetMinor());
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
AssertReturnError(dOps->second.Ops, -ENOTSUP);
AssertReturnError(dOps->second.Ops->Open, -ENOTSUP);
return dOps->second.Ops->Open(Node, Flags, Mode);
}
int __fs_Close(struct Inode *Node)
{
func("%#lx", Node);
if ((dev_t)Node->GetMajor() == DeviceDirID)
{
switch (Node->GetMinor())
{
case 0: /* /dev/input/keyboard */
case 1: /* /dev/input/mouse */
return -ENOTSUP;
default:
return -ENOENT;
};
}
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(Node->GetMajor());
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Node->GetMinor());
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
AssertReturnError(dOps->second.Ops, -ENOTSUP);
AssertReturnError(dOps->second.Ops->Close, -ENOTSUP);
return dOps->second.Ops->Close(Node);
}
int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
{
func("%#lx %lu %#lx", Node, Request, Argp);
if ((dev_t)Node->GetMajor() == DeviceDirID)
{
switch (Node->GetMinor())
{
case 0: /* /dev/input/keyboard */
case 1: /* /dev/input/mouse */
return -ENOSYS;
default:
return -ENOENT;
};
}
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(Node->GetMajor());
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Node->GetMinor());
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
AssertReturnError(dOps->second.Ops, -ENOTSUP);
AssertReturnError(dOps->second.Ops->Ioctl, -ENOTSUP);
return dOps->second.Ops->Ioctl(Node, Request, Argp);
}
__no_sanitize("alignment") ssize_t __fs_Readdir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
{
func("%#lx %#lx %d %d %d", _Node, Buffer, Size, Offset, Entries);
auto node = (Manager::DeviceInode *)_Node;
off_t realOffset = Offset;
size_t totalSize = 0;
uint16_t reclen = 0;
struct kdirent *ent = nullptr;
if (!S_ISDIR(node->inode.Mode))
return -ENOTDIR;
if (Offset == 0)
{
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(".") + 1);
if (totalSize + reclen > Size)
return -EINVAL;
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
ent->d_ino = node->inode.Index;
ent->d_off = 0;
ent->d_reclen = reclen;
ent->d_type = DT_DIR;
strcpy(ent->d_name, ".");
totalSize += reclen;
Offset++;
}
if (Offset == 1)
{
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen("..") + 1);
if (totalSize + reclen > Size)
return totalSize;
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
if (node->Parent)
ent->d_ino = node->Parent->inode->Index;
else if (node->ParentInode)
ent->d_ino = node->ParentInode->Index;
else
ent->d_ino = node->inode.Index;
ent->d_off = 1;
ent->d_reclen = reclen;
ent->d_type = DT_DIR;
strcpy(ent->d_name, "..");
totalSize += reclen;
Offset++;
}
off_t entryIndex = 0;
for (const auto &var : node->Children)
{
if (entryIndex + 2 < realOffset)
{
entryIndex++;
continue;
}
if (Entries && entryIndex >= Entries)
break;
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(var->Name.c_str()) + 1);
if (totalSize + reclen > Size)
break;
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
ent->d_ino = var->inode.Index;
ent->d_off = entryIndex + 2;
ent->d_reclen = reclen;
ent->d_type = IFTODT(var->inode.Mode);
strcpy(ent->d_name, var->Name.c_str());
totalSize += reclen;
entryIndex++;
}
if (totalSize + offsetof(struct kdirent, d_name) + 1 > 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;
}
int __fs_Stat(struct Inode *_Node, struct kstat *Stat)
{
func("%#lx %#lx", _Node, Stat);
auto node = (Manager::DeviceInode *)_Node;
assert(node != nullptr);
assert(Stat != nullptr);
Stat->Device = node->inode.Device;
Stat->Index = node->inode.Index;
Stat->HardLinks = 1;
Stat->UserID = 0;
Stat->GroupID = 0;
Stat->RawDevice = node->inode.RawDevice;
Stat->Size = node->Size;
Stat->AccessTime = node->AccessTime;
Stat->ModifyTime = node->ModifyTime;
Stat->ChangeTime = node->ChangeTime;
Stat->BlockSize = node->BlockSize;
Stat->Blocks = node->Blocks;
Stat->Attribute = 0;
return 0;
}
void Manager::InitializeDeviceDirectory()
{
dev_t MinorID = 0;
DeviceInode *_dev = new DeviceInode;
_dev->Name = "dev";
/* d rwx r-- r-- */
mode_t mode = S_IRWXU |
S_IRGRP |
S_IROTH |
S_IFDIR;
Inode *dev = (Inode *)_dev;
dev->Mode = mode;
FileSystemInfo *fsi = new FileSystemInfo;
fsi->Name = "Device Virtual File System";
fsi->SuperOps = {};
fsi->Ops.Lookup = __fs_Lookup;
fsi->Ops.Create = __fs_Create;
fsi->Ops.Remove = nullptr;
fsi->Ops.Rename = nullptr;
fsi->Ops.Read = __fs_Read;
fsi->Ops.Write = __fs_Write;
fsi->Ops.Truncate = nullptr;
fsi->Ops.Open = __fs_Open;
fsi->Ops.Close = __fs_Close;
fsi->Ops.Ioctl = __fs_Ioctl;
fsi->Ops.ReadDir = __fs_Readdir;
fsi->Ops.MkDir = nullptr;
fsi->Ops.RmDir = nullptr;
fsi->Ops.SymLink = nullptr;
fsi->Ops.ReadLink = nullptr;
fsi->Ops.Seek = nullptr;
fsi->Ops.Stat = __fs_Stat;
DeviceDirID = dev->Device = fs->RegisterFileSystem(fsi);
dev->SetDevice(0, MinorID++);
Node root = fs->GetRoot(0);
devNode = fs->Mount(root, dev, "dev", fsi);
assert(devNode->Parent != nullptr);
_dev->Parent = devNode->Parent;
_dev->ParentInode = devNode->Parent->inode;
/* d rwx r-- r-- */
mode = S_IRWXU |
S_IRGRP |
S_IROTH |
S_IFDIR;
DeviceInode *blk = new DeviceInode;
blk->Parent = devNode;
blk->ParentInode = devNode->inode;
blk->Name = "block";
blk->inode.Device = dev->Device;
blk->inode.Mode = mode;
blk->inode.Offset = _dev->Children.size();
_dev->Children.push_back(blk);
devBlockNode = fs->Lookup(devNode, "block");
/* d rwx r-- r-- */
mode = S_IRWXU |
S_IRGRP |
S_IROTH |
S_IFDIR;
DeviceInode *input = new DeviceInode;
input->Parent = devNode;
input->ParentInode = devNode->inode;
input->Name = "input";
input->inode.Device = dev->Device;
input->inode.Mode = mode;
input->inode.Offset = _dev->Children.size();
_dev->Children.push_back(input);
devInputNode = fs->Lookup(devNode, "input");
auto createDevice = [](DeviceInode *p1, Node p2, const std::string &name, dev_t maj, dev_t min, mode_t mode)
{
DeviceInode *device = new DeviceInode;
device->Parent = p2;
device->ParentInode = p2->inode;
device->Name = name;
device->inode.Device = p2->inode->Device;
device->inode.Mode = mode;
device->inode.SetDevice(maj, min);
device->inode.Offset = p1->Children.size();
p1->Children.push_back(device);
};
MinorID = 0;
/* c rw- r-- --- */
mode = S_IRUSR | S_IWUSR |
S_IRGRP |
S_IFCHR;
createDevice(input, devInputNode, "keyboard", DeviceDirID, MinorID++, mode);
/* c rw- r-- --- */
mode = S_IRUSR | S_IWUSR |
S_IRGRP |
S_IFCHR;
createDevice(input, devInputNode, "mouse", DeviceDirID, MinorID++, mode);
}
}

View File

@ -38,12 +38,12 @@ extern const __SIZE_TYPE__ trusted_drivers_count;
namespace Driver
{
bool Manager::IsDriverTrusted(FileNode *File)
bool Manager::IsDriverTrusted(Node File)
{
kstat st;
File->Stat(&st);
fs->Stat(File, &st);
std::unique_ptr<uint8_t[]> ptr(new uint8_t[st.Size]);
File->Read(ptr.get(), st.Size, 0);
fs->Read(File, ptr.get(), st.Size, 0);
uint8_t *sha = sha512_sum(ptr.get(), st.Size);
char hash_str[129];
for (int j = 0; j < 64; j++)
@ -102,7 +102,8 @@ namespace Driver
}
const char *DriverDirectory = Config.DriverDirectory;
FileNode *drvDirNode = fs->GetByPath(DriverDirectory, nullptr);
Node root = fs->GetRoot(0);
Node drvDirNode = fs->Lookup(root, DriverDirectory);
if (!drvDirNode)
{
error("Failed to open driver directory %s", DriverDirectory);
@ -110,7 +111,7 @@ namespace Driver
return;
}
for (const auto &drvNode : drvDirNode->Children)
for (const auto &drvNode : fs->ReadDirectory(drvDirNode))
{
debug("Checking driver %s", drvNode->Path.c_str());
if (!drvNode->IsRegularFile())
@ -273,12 +274,12 @@ namespace Driver
}
}
int Manager::LoadDriverFile(DriverObject &Drv, FileNode *File)
int Manager::LoadDriverFile(DriverObject &Drv, Node File)
{
trace("Loading driver %s in memory", File->Name.c_str());
Elf_Ehdr ELFHeader{};
File->Read(&ELFHeader, sizeof(Elf_Ehdr), 0);
fs->Read(File, &ELFHeader, sizeof(Elf_Ehdr), 0);
AssertReturnError(ELFHeader.e_ident[EI_CLASS] == ELFCLASS64, -ENOEXEC);
AssertReturnError(ELFHeader.e_ident[EI_DATA] == ELFDATA2LSB, -ENOEXEC);
@ -295,7 +296,7 @@ namespace Driver
Elf_Phdr phdr{};
for (Elf_Half i = 0; i < ELFHeader.e_phnum; i++)
{
File->Read(&phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr)));
fs->Read(File, &phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr)));
if (phdr.p_type == PT_LOAD || phdr.p_type == PT_DYNAMIC)
{
if (segSize < phdr.p_vaddr + phdr.p_memsz)
@ -306,7 +307,7 @@ namespace Driver
if (phdr.p_type == PT_INTERP)
{
char interp[17];
File->Read(interp, sizeof(interp), phdr.p_offset);
fs->Read(File, interp, sizeof(interp), phdr.p_offset);
if (strncmp(interp, "/boot/fennix.elf", sizeof(interp)) != 0)
{
error("Interpreter is not /boot/fennix.elf");
@ -326,13 +327,13 @@ namespace Driver
Elf_Shdr shstrtab{};
Elf_Shdr shdr{};
__DriverInfo driverInfo{};
File->Read(&shstrtab, sizeof(Elf_Shdr), ELFHeader.e_shoff + (ELFHeader.e_shstrndx * ELFHeader.e_shentsize));
fs->Read(File, &shstrtab, sizeof(Elf_Shdr), ELFHeader.e_shoff + (ELFHeader.e_shstrndx * ELFHeader.e_shentsize));
for (Elf_Half i = 0; i < ELFHeader.e_shnum; i++)
{
if (i == ELFHeader.e_shstrndx)
continue;
File->Read(&shdr, ELFHeader.e_shentsize, ELFHeader.e_shoff + (i * ELFHeader.e_shentsize));
fs->Read(File, &shdr, ELFHeader.e_shentsize, ELFHeader.e_shoff + (i * ELFHeader.e_shentsize));
switch (shdr.sh_type)
{
@ -350,11 +351,11 @@ namespace Driver
}
char symName[16];
File->Read(symName, sizeof(symName), shstrtab.sh_offset + shdr.sh_name);
fs->Read(File, symName, sizeof(symName), shstrtab.sh_offset + shdr.sh_name);
if (strcmp(symName, ".driver.info") != 0)
continue;
File->Read(&driverInfo, sizeof(__DriverInfo), shdr.sh_offset);
fs->Read(File, &driverInfo, sizeof(__DriverInfo), shdr.sh_offset);
/* Perform relocations */
driverInfo.Name = (const char *)(Drv.BaseAddress + (uintptr_t)driverInfo.Name);
@ -367,13 +368,13 @@ namespace Driver
{
Elf_Sym symEntry{};
uintptr_t symOffset = sht_symtab.sh_offset + (h * sizeof(Elf_Sym));
File->Read(&symEntry, sizeof(Elf_Sym), symOffset);
fs->Read(File, &symEntry, sizeof(Elf_Sym), symOffset);
if (symEntry.st_name == 0)
continue;
char symName[16];
File->Read(symName, sizeof(symName), sht_strtab.sh_offset + symEntry.st_name);
fs->Read(File, symName, sizeof(symName), sht_strtab.sh_offset + symEntry.st_name);
switch (symEntry.st_shndx)
{
@ -405,7 +406,7 @@ namespace Driver
for (Elf_Half i = 0; i < ELFHeader.e_phnum; i++)
{
File->Read(&phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr)));
fs->Read(File, &phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr)));
switch (phdr.p_type)
{
@ -421,7 +422,7 @@ namespace Driver
phdr.p_filesz, phdr.p_memsz);
if (phdr.p_filesz > 0)
File->Read(dest, phdr.p_filesz, phdr.p_offset);
fs->Read(File, (void *)dest, phdr.p_filesz, phdr.p_offset);
if (phdr.p_memsz - phdr.p_filesz > 0)
{
@ -620,7 +621,8 @@ namespace Driver
delete Drv.DeviceOperations;
/* Reload the driver */
FileNode *drvNode = fs->GetByPath(Drv.Path.c_str(), nullptr);
Node root = fs->GetRoot(0);
Node drvNode = fs->Lookup(root, Drv.Path);
if (!drvNode)
{
error("Failed to open driver file %s", Drv.Path.c_str());
@ -684,7 +686,7 @@ namespace Driver
newDrvObj.Initialized = true;
}
Manager::Manager() { this->InitializeDaemonFS(); }
Manager::Manager() { this->InitializeDeviceDirectory(); }
Manager::~Manager()
{

View File

@ -0,0 +1,256 @@
/*
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 <driver.hpp>
#include <interface/driver.h>
#include <interface/input.h>
#include <memory.hpp>
#include <stropts.h>
#include <ints.hpp>
#include <task.hpp>
#include <printf.h>
#include <exec.hpp>
#include <rand.hpp>
#include <cwalk.h>
#include <md5.h>
#include "../../kernel.h"
using namespace vfs;
namespace Driver
{
dev_t Manager::RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations)
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
const auto it = drivers.find(DriverID);
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
for (size_t i = 0; i < 128; i++)
{
const auto dOps = dop->find(i);
const auto dOpsEnd = dop->end();
if (dOps != dOpsEnd)
continue;
DeviceType devType = (DeviceType)(Type & DEVICE_TYPE_MASK);
switch (devType)
{
case DEVICE_TYPE_INPUT:
{
std::string prefix = "event";
for (size_t j = 0; j < 128; j++)
{
std::string deviceName = prefix + std::to_string(j);
Node node = fs->Lookup(devInputNode, deviceName);
if (node)
continue;
/* c rwx r-- r-- */
mode_t mode = S_IRWXU |
S_IRGRP |
S_IROTH |
S_IFCHR;
node = fs->Create(devInputNode, deviceName, mode);
node->inode->SetDevice(DriverID, i);
DriverHandlers dh{};
dh.Ops = Operations;
dh.Node = node->inode;
dh.InputReports = new RingBuffer<InputReport>(16);
dop->insert({i, std::move(dh)});
return i;
}
ReturnLogError(-EOVERFLOW, "No available slots for device %d", DriverID);
}
default:
ReturnLogError(-EINVAL, "Invalid device type %d", Type);
}
}
ReturnLogError(-EOVERFLOW, "No available slots for device %d", DriverID);
}
dev_t Manager::CreateDeviceFile(dev_t DriverID, const char *name, mode_t mode, const InodeOperations *Operations)
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
const auto it = drivers.find(DriverID);
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
for (size_t i = 0; i < 128; i++)
{
const auto dOps = dop->find(i);
if (dOps != dop->end())
continue;
eNode node = fs->Lookup(devNode, name);
if (node == true)
ReturnLogError(-EEXIST, "Device file %s already exists", name);
node = fs->Create(devNode, name, mode);
if (node == false)
ReturnLogError(-node.Error, "Failed to create device file %s; %s", name, node.what());
node.Value->inode->SetDevice(DriverID, i);
DriverHandlers dh{};
dh.Ops = Operations;
dh.Node = node.Value->inode;
dh.InputReports = new RingBuffer<InputReport>(16);
dop->insert({i, std::move(dh)});
return i;
}
ReturnLogError(-EOVERFLOW, "No available slots for device %d", DriverID);
}
int Manager::UnregisterDevice(dev_t DriverID, dev_t Device)
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
const auto it = drivers.find(DriverID);
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
const auto dOps = dop->find(Device);
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Device);
dop->erase(dOps);
fixme("remove eventX from /dev/input");
fixme("delete InputReports");
return 0;
}
dev_t Manager::RegisterBlockDevice(dev_t DriverID, struct BlockDevice *Device)
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
const auto it = drivers.find(DriverID);
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
std::string prefix = Device->Name;
for (size_t j = 0; j < 128; j++)
{
std::string deviceName = prefix + std::to_string(j);
Node node = fs->Lookup(devBlockNode, deviceName);
if (node)
continue;
debug("Creating \"%s\"", deviceName.c_str());
/* b rwx --- --- */
mode_t mode = S_IRWXU |
S_IFBLK;
node = fs->Create(devBlockNode, deviceName, mode);
node->inode->SetDevice(DriverID, j);
auto devNode = (Manager::DeviceInode *)node->inode;
devNode->Size = Device->Size;
devNode->BlockSize = Device->BlockSize;
devNode->Blocks = Device->BlockCount;
devNode->inode.PrivateData = Device->PrivateData;
DriverHandlers dh{};
dh.Ops = Device->Ops;
dh.Node = node->inode;
dop->insert({j, std::move(dh)});
debug("dh ops:%#lx node:%#lx %d", dh.Ops, dh.Node, j);
return j;
}
ReturnLogError(-EOVERFLOW, "No available slots for device %d", DriverID);
}
int Manager::UnregisterBlockDevice(dev_t DriverID, dev_t DeviceID)
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
const auto it = drivers.find(DriverID);
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
const auto dOps = dop->find(DeviceID);
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", DeviceID);
dop->erase(dOps);
return 0;
}
void *Manager::AllocateMemory(dev_t DriverID, size_t Pages)
{
auto itr = Drivers.find(DriverID);
assert(itr != Drivers.end());
void *ptr = itr->second.vma->RequestPages(Pages);
memset(ptr, 0, FROM_PAGES(Pages));
return ptr;
}
void Manager::FreeMemory(dev_t DriverID, void *Pointer, size_t Pages)
{
auto itr = Drivers.find(DriverID);
assert(itr != Drivers.end());
itr->second.vma->FreePages(Pointer, Pages);
}
int Manager::ReportInputEvent(dev_t DriverID, InputReport *Report)
{
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
DriverManager->GetDrivers();
const auto it = drivers.find(DriverID);
if (it == drivers.end())
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
const Driver::DriverObject *drv = &it->second;
auto dop = drv->DeviceOperations;
auto dOps = dop->find(Report->Device);
if (dOps == dop->end())
ReturnLogError(-EINVAL, "Device %d not found", Report->Device);
dOps->second.InputReports->Write(Report, 1);
switch (Report->Type)
{
case INPUT_TYPE_KEYBOARD:
{
KeyboardReport *kReport = &Report->Keyboard;
GlobalKeyboardInputReports.Write(kReport, 1);
break;
}
case INPUT_TYPE_MOUSE:
{
MouseReport *mReport = &Report->Mouse;
GlobalMouseInputReports.Write(mReport, 1);
break;
}
default:
assert(!"Invalid input type");
}
return 0;
}
}

View File

@ -1,6 +1,6 @@
#include <memory.hpp>
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include <signal.hpp>
#include <utsname.h>
#include <time.h>

View File

@ -64,7 +64,7 @@ struct DiagnosticFile
} Data;
};
nsa bool WriteDiagDataToNode(FileNode *node)
nsa bool WriteDiagDataToNode(Node node)
{
uintptr_t KStart = (uintptr_t)&_kernel_start;
uintptr_t kEnd = (uintptr_t)&_kernel_end;
@ -89,7 +89,7 @@ nsa bool WriteDiagDataToNode(FileNode *node)
memcpy(file->Data.KernelMemory, (void *)KStart, kSize);
ExPrint("Writing to %s\n", node->Path.c_str());
size_t w = node->Write(buf, fileSize, 0);
size_t w = fs->Write(node, buf, fileSize, 0);
if (w != fileSize)
{
debug("%d out of %d bytes written", w, fileSize);
@ -115,7 +115,8 @@ nsa void DiagnosticDataCollection()
S_IROTH |
S_IFDIR;
FileNode *panicDir = fs->ForceCreate(nullptr, "/sys/log/panic", mode);
Node root = fs->GetRoot(0);
Node panicDir = fs->Create(root, "/sys/log/panic", mode);
if (!panicDir)
{
ExPrint("\x1b[0;30;41mFailed to create /sys/log/panic\x1b[0m\n");
@ -123,14 +124,14 @@ nsa void DiagnosticDataCollection()
return;
}
FileNode *dumpFile;
Node dumpFile;
Time::Clock clock = Time::ReadClock();
char filename[64];
for (int i = 0; i < INT32_MAX; i++)
{
sprintf(filename, "dump-%d-%d-%d-%d.dmp",
clock.Year, clock.Month, clock.Day, i);
if (fs->PathExists(filename, panicDir))
if (fs->Lookup(panicDir, filename))
continue;
mode = S_IRWXU |

View File

@ -408,8 +408,7 @@ nsa __noreturn void HandleBufferOverflow()
CPU::Stop();
}
EXTERNC nsa __noreturn void HandleAssertionFailed(const char *File, int Line,
const char *Expression)
EXTERNC nsa __noreturn void HandleAssertionFailed(const char *File, int Line, const char *Expression)
{
DisplayAssertionFailed(File, Line, Expression);
CPU::Stop();

View File

@ -20,9 +20,9 @@
#include <types.h>
#include <filesystem.hpp>
#include <fs/vfs.hpp>
namespace vfs
namespace Driver::ExtendedFilesystem
{
class EXT2
{

View File

@ -0,0 +1,200 @@
/*
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 <driver.hpp>
#include <fs/ustar.hpp>
#include <interface/fs.h>
#include <memory.hpp>
#include <debug.h>
using namespace vfs;
namespace Driver::UnixStandardTAR
{
dev_t DriverID;
int USTAR_AllocateInode(FileSystemInfo *Info, Inode **Result)
{
assert(!"NOT IMPLEMENTED");
}
int USTAR_DeleteInode(FileSystemInfo *Info, Inode *Node)
{
assert(!"NOT IMPLEMENTED");
}
int USTAR_Synchronize(FileSystemInfo *Info, Inode *Node)
{
assert(!"NOT IMPLEMENTED");
}
int USTAR_Destroy(FileSystemInfo *Info)
{
assert(!"NOT IMPLEMENTED");
}
int USTAR_Probe(void *Device)
{
assert(!"NOT IMPLEMENTED");
}
int USTAR_Mount(FileSystemInfo *FS, Inode **Root, void *Device)
{
assert(!"NOT IMPLEMENTED");
}
int USTAR_Unmount(FileSystemInfo *FS)
{
assert(!"NOT IMPLEMENTED");
}
int USTAR_Lookup(Inode *Parent, const char *Name, Inode **Result)
{
assert(!"NOT IMPLEMENTED");
}
int USTAR_Create(Inode *Parent, const char *Name, mode_t Mode, Inode **Result)
{
assert(!"NOT IMPLEMENTED");
}
int USTAR_Remove(Inode *Parent, const char *Name)
{
assert(!"NOT IMPLEMENTED");
}
int USTAR_Rename(Inode *Parent, const char *OldName, const char *NewName)
{
assert(!"NOT IMPLEMENTED");
}
ssize_t USTAR_Read(Inode *Node, void *Buffer, size_t Size, off_t Offset)
{
assert(!"NOT IMPLEMENTED");
}
ssize_t USTAR_Write(Inode *Node, const void *Buffer, size_t Size, off_t Offset)
{
assert(!"NOT IMPLEMENTED");
}
int USTAR_Truncate(Inode *Node, off_t Size)
{
assert(!"NOT IMPLEMENTED");
}
int USTAR_Open(Inode *Node, int Flags, mode_t Mode)
{
assert(!"NOT IMPLEMENTED");
}
int USTAR_Close(Inode *Node)
{
assert(!"NOT IMPLEMENTED");
}
int USTAR_Ioctl(Inode *Node, unsigned long Request, void *Argp)
{
assert(!"NOT IMPLEMENTED");
}
ssize_t USTAR_ReadDir(Inode *Node, kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
{
assert(!"NOT IMPLEMENTED");
}
int USTAR_MkDir(Inode *Parent, const char *Name, mode_t Mode, Inode **Result)
{
assert(!"NOT IMPLEMENTED");
}
int USTAR_RmDir(Inode *Parent, const char *Name)
{
assert(!"NOT IMPLEMENTED");
}
int USTAR_SymLink(Inode *Parent, const char *Name, const char *Target, Inode **Result)
{
assert(!"NOT IMPLEMENTED");
}
ssize_t USTAR_ReadLink(Inode *Node, char *Buffer, size_t Size)
{
assert(!"NOT IMPLEMENTED");
}
off_t USTAR_Seek(Inode *Node, off_t Offset)
{
assert(!"NOT IMPLEMENTED");
}
int USTAR_Stat(Inode *Node, kstat *Stat)
{
assert(!"NOT IMPLEMENTED");
}
static SuperBlockOperations ustarSuperOps = {
.AllocateInode = USTAR_AllocateInode,
.DeleteInode = USTAR_DeleteInode,
.Synchronize = USTAR_Synchronize,
.Destroy = USTAR_Destroy,
.Probe = USTAR_Probe,
.Mount = USTAR_Mount,
.Unmount = USTAR_Unmount};
static InodeOperations ustarInodeOps = {
.Lookup = USTAR_Lookup,
.Create = USTAR_Create,
.Remove = USTAR_Remove,
.Rename = USTAR_Rename,
.Read = USTAR_Read,
.Write = USTAR_Write,
.Truncate = USTAR_Truncate,
.Open = USTAR_Open,
.Close = USTAR_Close,
.Ioctl = USTAR_Ioctl,
.ReadDir = USTAR_ReadDir,
.MkDir = USTAR_MkDir,
.RmDir = USTAR_RmDir,
.SymLink = USTAR_SymLink,
.ReadLink = USTAR_ReadLink,
.Seek = USTAR_Seek,
.Stat = USTAR_Stat};
int Entry()
{
FileSystemInfo *fsi = new FileSystemInfo;
fsi->Name = "Unix Standard TAR";
fsi->SuperOps = ustarSuperOps;
fsi->Ops = ustarInodeOps;
v0::RegisterFileSystem(DriverID, fsi);
return 0;
}
int Final() { return 0; }
int Panic() { return 0; }
int Probe() { return 0; }
REGISTER_BUILTIN_DRIVER(ustar,
"Unix Standard TAR Driver",
"enderice2",
1, 0, 0,
Entry,
Final,
Panic,
Probe);
}

View File

@ -16,6 +16,7 @@
*/
#include <driver.hpp>
#include <interface/block.h>
#include <cpu.hpp>
#include <pci.hpp>
@ -572,6 +573,9 @@ namespace Driver::AHCI
HBAPort *HBAPortPtr;
uint8_t *Buffer;
uint8_t PortNumber;
uint32_t BlockSize;
uint32_t BlockCount;
size_t Size;
ATA_IDENTIFY *IdentifyData;
Port(PortType Type, HBAPort *PortPtr, uint8_t PortNumber)
@ -614,6 +618,7 @@ namespace Driver::AHCI
void Configure()
{
debug("Configuring port %d", PortNumber);
this->StopCMD();
void *CmdBase = v0::AllocateMemory(DriverID, 1);
HBAPortPtr->CommandListBase = (uint32_t)(uint64_t)CmdBase;
@ -639,19 +644,35 @@ namespace Driver::AHCI
Identify();
if (IdentifyData->CommandSetSupport.BigLba)
{
if ((IdentifyData->CommandSetActive.Words119_120Valid & 0x1) != 0)
{
uint32_t wordsPerLogicalSector = (IdentifyData->WordsPerLogicalSector[1] << 16) | IdentifyData->WordsPerLogicalSector[0];
if (wordsPerLogicalSector != 0)
this->BlockSize = wordsPerLogicalSector * 2;
}
}
this->BlockSize = 512;
this->BlockCount = this->IdentifyData->UserAddressableSectors;
this->Size = this->BlockCount * this->BlockSize;
trace("Port %d \"%x %x %x %x\" configured", PortNumber,
HBAPortPtr->Vendor[0], HBAPortPtr->Vendor[1],
HBAPortPtr->Vendor[2], HBAPortPtr->Vendor[3]);
}
bool ReadWrite(uint64_t Sector, uint32_t SectorCount, void *Buffer, bool Write)
int ReadWrite(uint64_t Sector, uint32_t SectorCount, void *Buffer, bool Write)
{
if (this->AHCIPortType == PortType::SATAPI && Write == true)
{
trace("SATAPI port does not support write.");
return false;
return ENOTSUP;
}
debug("%s op on port %d, sector %d, count %d", Write ? "Write" : "Read", this->PortNumber, Sector, SectorCount);
uint32_t SectorL = (uint32_t)Sector;
uint32_t SectorH = (uint32_t)(Sector >> 32);
@ -706,7 +727,7 @@ namespace Driver::AHCI
if (spinLock == 1000000)
{
trace("Port not responding.");
return false;
return ETIMEDOUT;
}
HBAPortPtr->CommandIssue = 1;
@ -723,7 +744,7 @@ namespace Driver::AHCI
spinLock = 0;
retries++;
if (retries > 10)
return false;
return ETIMEDOUT;
}
if (HBAPortPtr->CommandIssue == 0)
@ -733,11 +754,11 @@ namespace Driver::AHCI
if (HBAPortPtr->InterruptStatus & HBA_PxIS_TFES)
{
trace("Error reading/writing (%d).", Write);
return false;
return EIO;
}
}
return true;
return 0;
}
void Identify()
@ -840,34 +861,61 @@ namespace Driver::AHCI
}
}
int Open(struct Inode *, int, mode_t)
{
return 0;
}
int Close(struct Inode *)
{
return 0;
}
ssize_t Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
{
uint64_t sector = Offset / 512;
uint32_t sectorCount = uint32_t(Size / 512);
int num = Node->GetMinor();
bool ok = PortDevices[num]->ReadWrite(sector, sectorCount, Buffer, false);
return ok ? Size : 0;
Port *port = static_cast<Port *>(Node->PrivateData);
if ((Offset % port->BlockSize) != 0 || (Size % port->BlockSize) != 0)
{
trace("Read offset or size not aligned to block size (BlockSize=%u)", port->BlockSize);
return -EINVAL;
}
uint64_t sector = Offset / port->BlockSize;
uint32_t sectorCount = uint32_t(Size / port->BlockSize);
if (sectorCount == 0)
{
trace("Attempt to read 0 sectors");
return 0;
}
bool status = port->ReadWrite(sector, sectorCount, Buffer, false);
if (status != 0)
{
trace("Error '%s' reading from port %d", strerror(status), port->PortNumber);
return status;
}
return Size;
}
ssize_t Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
{
uint64_t sector = Offset / 512;
uint32_t sectorCount = uint32_t(Size / 512);
int num = Node->GetMinor();
bool ok = PortDevices[num]->ReadWrite(sector, sectorCount, (void *)Buffer, true);
return ok ? Size : 0;
Port *port = static_cast<Port *>(Node->PrivateData);
if ((Offset % port->BlockSize) != 0 || (Size % port->BlockSize) != 0)
{
trace("Read offset or size not aligned to block size (BlockSize=%u)", port->BlockSize);
return -EINVAL;
}
uint64_t sector = Offset / port->BlockSize;
uint32_t sectorCount = uint32_t(Size / port->BlockSize);
if (sectorCount == 0)
{
trace("Attempt to write 0 sectors");
return 0;
}
bool status = port->ReadWrite(sector, sectorCount, (void *)Buffer, true);
if (status != 0)
{
trace("Error '%s' writing to port %d", strerror(status), port->PortNumber);
return status;
}
return Size;
}
int Open(struct Inode *, int, mode_t) { return 0; }
int Close(struct Inode *) { return 0; }
const struct InodeOperations ops = {
.Lookup = nullptr,
.Create = nullptr,
@ -915,8 +963,18 @@ namespace Driver::AHCI
{
KPrint("%s drive found at port %d", PortTypeName[portType], i);
Port *port = new Port(portType, &hba->Ports[i], i);
dev_t ret = v0::RegisterDevice(DriverID, BLOCK_TYPE_HDD, &ops);
port->Configure();
BlockDevice *dev = new BlockDevice;
dev->Name = "ahci";
dev->BlockSize = port->BlockSize;
dev->BlockCount = port->BlockCount;
dev->Size = port->Size;
dev->Ops = &ops;
dev->PrivateData = port;
dev_t ret = v0::RegisterBlockDevice(DriverID, dev);
PortDevices[ret] = port;
debug("Port %d \"%s\" registered as %d", i, port->IdentifyData->ModelNumber, ret);
break;
}
case PortType::SEMB:
@ -942,10 +1000,6 @@ namespace Driver::AHCI
return -ENODEV;
}
trace("Initializing AHCI ports");
for (auto &&p : PortDevices)
p.second->Configure();
/* We don't use the interrupt handler now... maybe we will in the future */
// RegisterInterruptHandler(iLine(ctx->Device), (void *)OnInterruptReceived);
@ -957,7 +1011,7 @@ namespace Driver::AHCI
for (auto &&p : PortDevices)
{
p.second->StopCMD();
v0::UnregisterDevice(DriverID, p.first);
v0::UnregisterBlockDevice(DriverID, p.first);
delete p.second;
}

View File

@ -25,7 +25,7 @@
namespace Execute
{
BinaryType GetBinaryType(FileNode *Node)
BinaryType GetBinaryType(Node &Node)
{
debug("Checking binary type of %s", Node->Path.c_str());
BinaryType type;
@ -34,13 +34,13 @@ namespace Execute
ReturnLogError((BinaryType)-ENOENT, "Node is null");
Elf_Ehdr ehdr;
Node->Read(&ehdr, sizeof(Elf_Ehdr), 0);
fs->Read(Node, &ehdr, sizeof(Elf_Ehdr), 0);
mach_header mach;
Node->Read(&mach, sizeof(mach_header), 0);
fs->Read(Node, &mach, sizeof(mach_header), 0);
IMAGE_DOS_HEADER mz;
Node->Read(&mz, sizeof(IMAGE_DOS_HEADER), 0);
fs->Read(Node, &mz, sizeof(IMAGE_DOS_HEADER), 0);
/* Check ELF header. */
if (ehdr.e_ident[EI_MAG0] == ELFMAG0 &&
@ -64,10 +64,10 @@ namespace Execute
else if (mz.e_magic == IMAGE_DOS_SIGNATURE)
{
IMAGE_NT_HEADERS pe;
Node->Read(&pe, sizeof(IMAGE_NT_HEADERS), mz.e_lfanew);
fs->Read(Node, &pe, sizeof(IMAGE_NT_HEADERS), mz.e_lfanew);
IMAGE_OS2_HEADER ne;
Node->Read(&ne, sizeof(IMAGE_OS2_HEADER), mz.e_lfanew);
fs->Read(Node, &ne, sizeof(IMAGE_OS2_HEADER), mz.e_lfanew);
/* TODO: LE, EDOS */
if (pe.Signature == IMAGE_NT_SIGNATURE)
@ -99,14 +99,14 @@ namespace Execute
BinaryType GetBinaryType(std::string Path)
{
FileNode *node = fs->GetByPath(Path.c_str(), nullptr);
Node node = fs->Lookup(thisProcess->Info.RootNode, Path);
if (node->IsSymbolicLink())
{
char buffer[512];
node->ReadLink(buffer, sizeof(buffer));
node = fs->GetByPath(buffer, node->Parent);
fs->ReadLink(node, buffer, sizeof(buffer));
node = fs->Lookup(node->Parent, buffer);
}
debug("Checking binary type of %s (returning %p)", Path.c_str(), node);
debug("Checking binary type of %s (returning %p)", Path.c_str(), node.get());
assert(node != nullptr);
return GetBinaryType(node);
}

View File

@ -32,7 +32,7 @@ using namespace vfs;
namespace Execute
{
void ELFObject::GenerateAuxiliaryVector(Memory::VirtualMemoryArea *vma, FileNode *fd, Elf_Ehdr ELFHeader, uintptr_t EntryPoint, uintptr_t BaseAddress)
void ELFObject::GenerateAuxiliaryVector(Memory::VirtualMemoryArea *vma, Node &fd, Elf_Ehdr ELFHeader, uintptr_t EntryPoint, uintptr_t BaseAddress)
{
char *aux_platform = (char *)vma->RequestPages(1, true); /* TODO: 4KiB is too much for this */
strcpy(aux_platform, "x86_64");
@ -79,7 +79,7 @@ namespace Execute
#endif
}
void ELFObject::LoadSegments(FileNode *fd, PCB *TargetProcess, Elf_Ehdr &ELFHeader, uintptr_t &BaseAddress)
void ELFObject::LoadSegments(Node &fd, PCB *TargetProcess, Elf_Ehdr &ELFHeader, uintptr_t &BaseAddress)
{
Memory::Virtual vmm(TargetProcess->PageTable);
Memory::VirtualMemoryArea *vma = TargetProcess->vma;
@ -91,7 +91,7 @@ namespace Execute
size_t SegmentsSize = 0;
for (Elf_Half i = 0; i < ELFHeader.e_phnum; i++)
{
fd->Read(&ProgramHeader, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr)));
fs->Read(fd, &ProgramHeader, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr)));
if (ProgramHeader.p_type == PT_LOAD || ProgramHeader.p_type == PT_DYNAMIC)
{
@ -113,7 +113,7 @@ namespace Execute
for (Elf_Half i = 0; i < ELFHeader.e_phnum; i++)
{
fd->Read(&ProgramHeader, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr)));
fs->Read(fd, &ProgramHeader, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr)));
switch (ProgramHeader.p_type)
{
@ -132,7 +132,7 @@ namespace Execute
if (ProgramHeader.p_filesz > 0)
{
fd->Read(SegmentDestination, ProgramHeader.p_filesz, ProgramHeader.p_offset);
fs->Read(fd, (void *)SegmentDestination, ProgramHeader.p_filesz, ProgramHeader.p_offset);
}
if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0)
@ -158,7 +158,7 @@ namespace Execute
if (ProgramHeader.p_filesz > 0)
{
fd->Read(DynamicSegmentDestination, ProgramHeader.p_filesz, ProgramHeader.p_offset);
fs->Read(fd, (void *)DynamicSegmentDestination, ProgramHeader.p_filesz, ProgramHeader.p_offset);
}
if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0)
@ -212,7 +212,7 @@ namespace Execute
{
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
{
fd->Read(&ProgramHeader, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr)));
fs->Read(fd, &ProgramHeader, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr)));
switch (ProgramHeader.p_type)
{
case PT_LOAD:
@ -245,7 +245,7 @@ namespace Execute
if (ProgramHeader.p_filesz > 0)
{
debug("%d %#lx %d", ProgramHeader.p_offset, (uint8_t *)pAddr + destOffset, ProgramHeader.p_filesz);
fd->Read((uint8_t *)pAddr + destOffset, ProgramHeader.p_filesz, ProgramHeader.p_offset);
fs->Read(fd, (uint8_t *)pAddr + destOffset, ProgramHeader.p_filesz, ProgramHeader.p_offset);
}
if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0)
@ -265,35 +265,35 @@ namespace Execute
case PT_NOTE:
{
Elf_Nhdr NoteHeader;
fd->Read(&NoteHeader, sizeof(Elf_Nhdr), ProgramHeader.p_offset);
fs->Read(fd, &NoteHeader, sizeof(Elf_Nhdr), ProgramHeader.p_offset);
switch (NoteHeader.n_type)
{
case NT_PRSTATUS:
{
Elf_Prstatus prstatus;
fd->Read(&prstatus, sizeof(Elf_Prstatus), ProgramHeader.p_offset + sizeof(Elf_Nhdr));
fs->Read(fd, &prstatus, sizeof(Elf_Prstatus), ProgramHeader.p_offset + sizeof(Elf_Nhdr));
debug("PRSTATUS: %#lx", prstatus.pr_reg[0]);
break;
}
case NT_PRPSINFO:
{
Elf_Prpsinfo prpsinfo;
fd->Read(&prpsinfo, sizeof(Elf_Prpsinfo), ProgramHeader.p_offset + sizeof(Elf_Nhdr));
fs->Read(fd, &prpsinfo, sizeof(Elf_Prpsinfo), ProgramHeader.p_offset + sizeof(Elf_Nhdr));
debug("PRPSINFO: %s", prpsinfo.pr_fname);
break;
}
case NT_PLATFORM:
{
char platform[256];
fd->Read(&platform, sizeof(platform), ProgramHeader.p_offset + sizeof(Elf_Nhdr));
fs->Read(fd, &platform, sizeof(platform), ProgramHeader.p_offset + sizeof(Elf_Nhdr));
debug("PLATFORM: %s", platform);
break;
}
case NT_AUXV:
{
Elf_auxv_t auxv;
fd->Read(&auxv, sizeof(Elf_auxv_t), ProgramHeader.p_offset + sizeof(Elf_Nhdr));
fs->Read(fd, &auxv, sizeof(Elf_auxv_t), ProgramHeader.p_offset + sizeof(Elf_Nhdr));
debug("AUXV: %#lx", auxv.a_un.a_val);
break;
}
@ -311,7 +311,7 @@ namespace Execute
debug("TLS Size: %ld (%ld pages)",
tlsSize, TO_PAGES(tlsSize));
void *tlsMemory = vma->RequestPages(TO_PAGES(tlsSize));
fd->Read(tlsMemory, tlsSize, ProgramHeader.p_offset);
fs->Read(fd, tlsMemory, tlsSize, ProgramHeader.p_offset);
TargetProcess->TLS = {
.pBase = uintptr_t(tlsMemory),
.vBase = ProgramHeader.p_vaddr,
@ -346,12 +346,12 @@ namespace Execute
case PT_GNU_PROPERTY:
{
Elf_Nhdr NoteHeader;
fd->Read(&NoteHeader, sizeof(Elf_Nhdr), ProgramHeader.p_offset);
fs->Read(fd, &NoteHeader, sizeof(Elf_Nhdr), ProgramHeader.p_offset);
if (NoteHeader.n_type == NT_GNU_PROPERTY_TYPE_0)
{
char noteName[0x400];
fd->Read(noteName, NoteHeader.n_namesz, ProgramHeader.p_offset + sizeof(Elf_Nhdr));
fs->Read(fd, noteName, NoteHeader.n_namesz, ProgramHeader.p_offset + sizeof(Elf_Nhdr));
noteName[NoteHeader.n_namesz - 1] = '\0';
if (strcmp(noteName, "GNU") == 0)
@ -394,10 +394,10 @@ namespace Execute
TargetProcess->ProgramBreak->InitBrk(ProgramBreak);
}
void ELFObject::LoadExec(FileNode *fd, PCB *TargetProcess)
void ELFObject::LoadExec(Node &fd, PCB *TargetProcess)
{
Elf_Ehdr ehdr{};
fd->Read(&ehdr, sizeof(Elf_Ehdr), 0);
fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0);
uintptr_t entry = ehdr.e_entry;
debug("Entry point is %#lx", entry);
@ -424,10 +424,10 @@ namespace Execute
#endif
}
void ELFObject::LoadDyn(FileNode *fd, PCB *TargetProcess)
void ELFObject::LoadDyn(Node &fd, PCB *TargetProcess)
{
Elf_Ehdr ehdr{};
fd->Read(&ehdr, sizeof(Elf_Ehdr), 0);
fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0);
uintptr_t entry = ehdr.e_entry;
debug("Entry point is %#lx", entry);
@ -465,24 +465,25 @@ namespace Execute
Elf_Phdr interp = interpVec.front();
std::string interpreterPath;
interpreterPath.resize(256);
fd->Read(interpreterPath.data(), 256, interp.p_offset);
fs->Read(fd, interpreterPath.data(), 256, interp.p_offset);
debug("Interpreter: %s", interpreterPath.c_str());
FileNode *ifd = fs->GetByPath(interpreterPath.c_str(), TargetProcess->Info.RootNode);
if (ifd == nullptr)
eNode ret = fs->Lookup(TargetProcess->Info.RootNode, interpreterPath);
if (ret == false)
{
warn("Failed to open interpreter file: %s", interpreterPath.c_str());
warn("Failed to open interpreter file: %s", ret.what());
return;
}
Node ifd = ret;
if (ifd->IsSymbolicLink())
{
char buffer[512];
ifd->ReadLink(buffer, sizeof(buffer));
ifd = fs->GetByPath(buffer, ifd->Parent);
fs->ReadLink(ifd, buffer, sizeof(buffer));
ifd = fs->Lookup(ifd->Parent, buffer);
}
debug("ifd: %p, interpreter: %s", ifd, interpreterPath.c_str());
debug("ifd: %p, interpreter: %s", ifd.get(), interpreterPath.c_str());
if (GetBinaryType(interpreterPath) != BinTypeELF)
{
warn("Interpreter %s is not an ELF file", interpreterPath.c_str());
@ -492,10 +493,10 @@ namespace Execute
LoadInterpreter(ifd, TargetProcess);
}
bool ELFObject::LoadInterpreter(FileNode *fd, PCB *TargetProcess)
bool ELFObject::LoadInterpreter(Node &fd, PCB *TargetProcess)
{
Elf_Ehdr ehdr;
fd->Read(&ehdr, sizeof(Elf_Ehdr), 0);
fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0);
switch (ehdr.e_type)
{
@ -550,18 +551,19 @@ namespace Execute
return;
}
FileNode *fd = fs->GetByPath(AbsolutePath.c_str(), TargetProcess->Info.RootNode);
if (fd == nullptr)
eNode ret = fs->Lookup(TargetProcess->Info.RootNode, AbsolutePath);
if (ret == false)
{
error("Failed to open %s, errno: %d", AbsolutePath.c_str(), fd);
error("Failed to open %s, errno: %s", AbsolutePath.c_str(), ret.what());
return;
}
Node fd = ret;
if (fd->IsSymbolicLink())
{
char buffer[512];
fd->ReadLink(buffer, sizeof(buffer));
fd = fs->GetByPath(buffer, fd->Parent);
fs->ReadLink(fd, buffer, sizeof(buffer));
fd = fs->Lookup(fd->Parent, buffer);
}
debug("Opened %s", AbsolutePath.c_str());
@ -575,7 +577,7 @@ namespace Execute
envc++;
Elf_Ehdr ehdr{};
fd->Read(&ehdr, sizeof(Elf_Ehdr), 0);
fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0);
// ELFargv = new const char *[argc + 2];
size_t argv_size = argc + 2 * sizeof(char *);

View File

@ -92,10 +92,10 @@ namespace Execute
return nullptr;
}
Elf_Sym ELFLookupSymbol(FileNode *fd, std::string Name)
Elf_Sym ELFLookupSymbol(Node fd, std::string Name)
{
Elf_Ehdr ehdr{};
fd->Read(&ehdr, sizeof(Elf_Ehdr), 0);
fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0);
Elf_Shdr symTable{};
Elf_Shdr stringTable{};
@ -103,13 +103,13 @@ namespace Execute
for (Elf64_Half i = 0; i < ehdr.e_shnum; i++)
{
Elf_Shdr shdr;
fd->Read(&shdr, sizeof(Elf_Shdr), ehdr.e_shoff + (i * sizeof(Elf_Shdr)));
fs->Read(fd, &shdr, sizeof(Elf_Shdr), ehdr.e_shoff + (i * sizeof(Elf_Shdr)));
switch (shdr.sh_type)
{
case SHT_SYMTAB:
symTable = shdr;
fd->Read(&stringTable, sizeof(Elf_Shdr), ehdr.e_shoff + (shdr.sh_link * sizeof(Elf_Shdr)));
fs->Read(fd, &stringTable, sizeof(Elf_Shdr), ehdr.e_shoff + (shdr.sh_link * sizeof(Elf_Shdr)));
break;
default:
break;
@ -126,11 +126,11 @@ namespace Execute
{
// Elf_Sym *sym = (Elf_Sym *)((uintptr_t)Header + symTable->sh_offset + (i * sizeof(Elf_Sym)));
Elf_Sym sym;
fd->Read(&sym, sizeof(Elf_Sym), symTable.sh_offset + (i * sizeof(Elf_Sym)));
fs->Read(fd, &sym, sizeof(Elf_Sym), symTable.sh_offset + (i * sizeof(Elf_Sym)));
// char *str = (char *)((uintptr_t)Header + stringTable->sh_offset + sym->st_name);
char str[256];
fd->Read(&str, sizeof(str), stringTable.sh_offset + sym.st_name);
fs->Read(fd, &str, sizeof(str), stringTable.sh_offset + sym.st_name);
if (strcmp(str, Name.c_str()) == 0)
return sym;

View File

@ -21,7 +21,7 @@
namespace Execute
{
std::vector<Elf_Dyn> ELFGetDynamicTag(FileNode *fd, DynamicArrayTags Tag)
std::vector<Elf_Dyn> ELFGetDynamicTag(Node &fd, DynamicArrayTags Tag)
{
std::vector<Elf_Dyn> ret;
std::vector<Elf_Phdr> phdrs = ELFGetSymbolType(fd, PT_DYNAMIC);
@ -37,7 +37,7 @@ namespace Execute
Elf_Dyn dyn;
for (size_t i = 0; i < phdr.p_filesz / sizeof(Elf_Dyn); i++)
{
fd->Read(&dyn, sizeof(Elf_Dyn), phdr.p_offset + (i * sizeof(Elf_Dyn)));
fs->Read(fd, &dyn, sizeof(Elf_Dyn), phdr.p_offset + (i * sizeof(Elf_Dyn)));
if (dyn.d_tag != Tag)
continue;

View File

@ -21,18 +21,18 @@
namespace Execute
{
std::vector<Elf_Shdr> ELFGetSections(FileNode *fd, const char *SectionName)
std::vector<Elf_Shdr> ELFGetSections(Node fd, const char *SectionName)
{
std::vector<Elf_Shdr> ret;
Elf_Ehdr ehdr;
fd->Read(&ehdr, sizeof(Elf_Ehdr), 0);
fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0);
std::unique_ptr<Elf_Shdr[]> sections(new Elf_Shdr[ehdr.e_shnum]);
fd->Read(sections.get(), sizeof(Elf_Shdr) * ehdr.e_shnum, ehdr.e_shoff);
fs->Read(fd, sections.get(), sizeof(Elf_Shdr) * ehdr.e_shnum, ehdr.e_shoff);
std::string sectionNames(sections[ehdr.e_shstrndx].sh_size, '\0');
fd->Read(sectionNames.data(), sections[ehdr.e_shstrndx].sh_size, sections[ehdr.e_shstrndx].sh_offset);
fs->Read(fd, sectionNames.data(), sections[ehdr.e_shstrndx].sh_size, sections[ehdr.e_shstrndx].sh_offset);
for (Elf_Half i = 0; i < ehdr.e_shnum; ++i)
{

View File

@ -21,15 +21,15 @@
namespace Execute
{
std::vector<Elf_Phdr> ELFGetSymbolType(FileNode *fd, SegmentTypes Tag)
std::vector<Elf_Phdr> ELFGetSymbolType(Node &fd, SegmentTypes Tag)
{
std::vector<Elf_Phdr> ret;
Elf_Ehdr ehdr;
fd->Read(&ehdr, sizeof(Elf_Ehdr), 0);
fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0);
Elf_Phdr phdr;
fd->Read(&phdr, sizeof(Elf_Phdr), ehdr.e_phoff);
fs->Read(fd, &phdr, sizeof(Elf_Phdr), ehdr.e_phoff);
off_t off = ehdr.e_phoff;
for (Elf_Half i = 0; i < ehdr.e_phnum; i++)
@ -38,7 +38,7 @@ namespace Execute
ret.push_back(phdr);
off += sizeof(Elf_Phdr);
fd->Read(&phdr, sizeof(Elf_Phdr), off);
fs->Read(fd, &phdr, sizeof(Elf_Phdr), off);
}
return ret;

View File

@ -35,7 +35,13 @@ namespace Execute
Tasking::TaskCompatibility Compatibility,
bool Critical)
{
FileNode *fd = fs->GetByPath(Path, nullptr);
if (Parent == nullptr)
{
debug("no parent specified, using current process");
Parent = thisProcess;
}
Node fd = fs->Lookup(Parent->Info.RootNode, Path);
if (fd == nullptr)
return -ENOENT;
@ -44,8 +50,8 @@ namespace Execute
if (fd->IsSymbolicLink())
{
char buffer[512];
fd->ReadLink(buffer, sizeof(buffer));
fd = fs->GetByPath(buffer, fd->Parent);
fs->ReadLink(fd, buffer, sizeof(buffer));
fd = fs->Lookup(fd->Parent, buffer);
if (fd == nullptr)
return -ENOENT;
}
@ -61,7 +67,7 @@ namespace Execute
const char *BaseName;
cwk_path_get_basename(Path, &BaseName, nullptr);
Elf32_Ehdr ELFHeader;
fd->Read(&ELFHeader, sizeof(Elf32_Ehdr), 0);
fs->Read(fd, &ELFHeader, sizeof(Elf32_Ehdr), 0);
switch (ELFHeader.e_machine)
{
@ -108,7 +114,6 @@ namespace Execute
PCB *Process;
if (Fork)
{
assert(Parent != nullptr);
CriticalSection cs;
Process = Parent;
@ -124,17 +129,13 @@ namespace Execute
}
else
{
if (Parent == nullptr)
Parent = thisProcess;
Process = TaskManager->CreateProcess(Parent, BaseName,
TaskExecutionMode::User,
false, 0, 0);
Process = TaskManager->CreateProcess(Parent, BaseName, User, false, 0, 0);
Process->Info.Compatibility = Compatibility;
Process->Info.Architecture = Arch;
}
Process->SetWorkingDirectory(fs->GetByPath(Path, nullptr)->Parent);
Node cwdNode = fs->Lookup(Parent->Info.RootNode, Path);
Process->SetWorkingDirectory(fs->Convert(cwdNode->Parent));
Process->SetExe(Path);
ELFObject *obj = new ELFObject(Path, Process, argv, envp);
@ -148,9 +149,9 @@ namespace Execute
vfs::FileDescriptorTable *pfdt = Parent->FileDescriptors;
vfs::FileDescriptorTable *fdt = Process->FileDescriptors;
auto ForkStdio = [pfdt, fdt](FileNode *SearchNode)
auto ForkStdio = [pfdt, fdt](Node SearchNode)
{
if (unlikely(SearchNode == nullptr))
if (unlikely(SearchNode.get() == nullptr))
return false;
for (const auto &ffd : pfdt->FileMap)
@ -158,12 +159,11 @@ namespace Execute
if (ffd.second.Flags & O_CLOEXEC)
continue;
if (ffd.second.Node == SearchNode)
{
fdt->usr_open(ffd.second.Node->Path.c_str(),
ffd.second.Flags, ffd.second.Mode);
return true;
}
if (ffd.second.node.get() != SearchNode.get())
continue;
fdt->usr_open(ffd.second.node->Path.c_str(), ffd.second.Flags, ffd.second.Mode);
return true;
}
return false;
};

View File

@ -15,7 +15,7 @@
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include <convert.h>
#include <stropts.h>
@ -47,8 +47,7 @@ namespace vfs
return 0;
}
int FileDescriptorTable::AddFileDescriptor(const char *AbsolutePath,
mode_t Mode, int Flags)
int FileDescriptorTable::AddFileDescriptor(const char *AbsolutePath, mode_t Mode, int Flags)
{
Tasking::PCB *pcb = thisProcess;
@ -77,8 +76,7 @@ namespace vfs
if (Flags & O_RDWR)
{
if (!(Mode & S_IRUSR) ||
!(Mode & S_IWUSR))
if (!(Mode & S_IRUSR) || !(Mode & S_IWUSR))
{
debug("No read/write permission (%d)", Mode);
return -EACCES;
@ -95,12 +93,11 @@ namespace vfs
if (Flags & O_CREAT)
{
FileNode *ret = fs->Create(pcb->CWD, AbsolutePath, Mode);
if (Flags & O_EXCL && ret == nullptr)
eNode ret = fs->Create(pcb->CWD, AbsolutePath, Mode);
if (Flags & O_EXCL && ret == false)
{
debug("%s: File already exists?, returning EEXIST",
AbsolutePath);
return -EEXIST;
debug("%s: File already exists?, returning %s", AbsolutePath, ret.what());
return -ret.Error;
}
}
@ -109,18 +106,18 @@ namespace vfs
fixme("O_CLOEXEC");
}
FileNode *File = fs->GetByPath(AbsolutePath, pcb->CWD);
if (!File)
eNode ret = fs->Lookup(pcb->CWD, AbsolutePath);
if (ret == false)
{
error("Failed to open file %s", AbsolutePath);
return -ENOENT;
error("Failed to open file %s, %s", AbsolutePath, ret.what());
return -ret.Error;
}
Node node = ret;
if (Flags & O_TRUNC)
{
debug("Truncating file %s", AbsolutePath);
File->Truncate(0);
fs->Truncate(node, 0);
}
Fildes fd{};
@ -129,13 +126,13 @@ namespace vfs
{
debug("Appending to file %s", AbsolutePath);
struct kstat stat;
File->Stat(&stat);
fd.Offset = File->Seek(stat.Size);
fs->Stat(node, &stat);
fd.Offset = fs->Seek(node, stat.Size);
}
fd.Mode = Mode;
fd.Flags = Flags;
fd.Node = File;
fd.node = node;
int fdn = this->GetFreeFileDescriptor();
if (fdn < 0)
@ -145,9 +142,8 @@ namespace vfs
char linkName[64];
snprintf(linkName, 64, "%d", fdn);
assert(fs->CreateLink(linkName, this->fdDir, AbsolutePath) != nullptr);
File->Open(Flags, Mode);
assert(fs->CreateLink(this->fdDir, linkName, AbsolutePath) == true);
fs->Open(node, Flags, Mode);
return fdn;
}
@ -157,7 +153,7 @@ namespace vfs
if (it == this->FileMap.end())
ReturnLogError(-EBADF, "Invalid fd %d", FileDescriptor);
fs->Remove(it->second.Node);
fs->Remove(it->second.node);
this->FileMap.erase(it);
return 0;
}
@ -209,7 +205,7 @@ namespace vfs
if (it == this->FileMap.end())
ReturnLogError(-EBADF, "Invalid fd %d", fd);
return it->second.Node->Read(buf, count, it->second.Offset);
return fs->Read(it->second.node, buf, count, it->second.Offset);
}
ssize_t FileDescriptorTable::usr_pread(int fd, void *buf, size_t count, off_t offset)
@ -218,7 +214,7 @@ namespace vfs
if (it == this->FileMap.end())
ReturnLogError(-EBADF, "Invalid fd %d", fd);
return it->second.Node->Read(buf, count, offset);
return fs->Read(it->second.node, buf, count, offset);
}
ssize_t FileDescriptorTable::usr_write(int fd, const void *buf, size_t count)
@ -227,7 +223,7 @@ namespace vfs
if (it == this->FileMap.end())
ReturnLogError(-EBADF, "Invalid fd %d", fd);
return it->second.Node->Write(buf, count, it->second.Offset);
return fs->Write(it->second.node, buf, count, it->second.Offset);
}
ssize_t FileDescriptorTable::usr_pwrite(int fd, const void *buf, size_t count, off_t offset)
@ -236,7 +232,7 @@ namespace vfs
if (it == this->FileMap.end())
ReturnLogError(-EBADF, "Invalid fd %d", fd);
return it->second.Node->Write(buf, count, offset);
return fs->Write(it->second.node, buf, count, offset);
}
int FileDescriptorTable::usr_close(int fd)
@ -260,21 +256,19 @@ namespace vfs
{
case SEEK_SET:
{
newOffset = it->second.Node->Seek(offset);
newOffset = fs->Seek(it->second.node, offset);
break;
}
case SEEK_CUR:
{
newOffset = it->second.Node->Seek(newOffset + offset);
newOffset = fs->Seek(it->second.node, newOffset + offset);
break;
}
case SEEK_END:
{
struct kstat stat
{
};
it->second.Node->Stat(&stat);
newOffset = it->second.Node->Seek(stat.Size + offset);
struct kstat stat{};
fs->Stat(it->second.node, &stat);
newOffset = fs->Seek(it->second.node, stat.Size + offset);
break;
}
default:
@ -284,48 +278,48 @@ namespace vfs
return newOffset;
}
int FileDescriptorTable::usr_stat(const char *pathname,
struct kstat *statbuf)
int FileDescriptorTable::usr_stat(const char *pathname, kstat *statbuf)
{
FileNode *node = fs->GetByPath(pathname, nullptr);
if (node == nullptr)
ReturnLogError(-ENOENT, "Failed to find %s", pathname);
Node root = thisProcess->Info.RootNode;
eNode ret = fs->Lookup(root, pathname);
if (ret == false)
ReturnLogError(-ret.Error, "Error on %s, %s", pathname, ret.what());
Node node = ret;
if (node->IsSymbolicLink())
{
std::unique_ptr<char[]> buffer(new char[1024]);
ssize_t ret = node->ReadLink(buffer.get(), 1024);
if (ret < 0)
return ret;
ssize_t len = fs->ReadLink(node, buffer.get(), 1024);
if (len < 0)
return len;
FileNode *target = fs->GetByPath(buffer.get(), nullptr);
if (target == nullptr)
return -ENOENT;
return target->Stat(statbuf);
ret = fs->Lookup(root, buffer.get());
if (ret == false)
return -ret.Error;
return fs->Stat(ret.Value, statbuf);
}
return node->Stat(statbuf);
return fs->Stat(node, statbuf);
}
int FileDescriptorTable::usr_fstat(int fd, struct kstat *statbuf)
int FileDescriptorTable::usr_fstat(int fd, kstat *statbuf)
{
auto it = this->FileMap.find(fd);
if (it == this->FileMap.end())
ReturnLogError(-EBADF, "Invalid fd %d", fd);
vfs::FileDescriptorTable::Fildes &fildes = it->second;
return fildes.Node->Stat(statbuf);
return fs->Stat(fildes.node, statbuf);
}
int FileDescriptorTable::usr_lstat(const char *pathname,
struct kstat *statbuf)
int FileDescriptorTable::usr_lstat(const char *pathname, kstat *statbuf)
{
FileNode *node = fs->GetByPath(pathname, nullptr);
if (node == nullptr)
ReturnLogError(-ENOENT, "Failed to find %s", pathname);
return node->Stat(statbuf);
Node root = thisProcess->Info.RootNode;
eNode ret = fs->Lookup(root, pathname);
if (ret == false)
ReturnLogError(-ret.Error, "Error on %s, %s", pathname, ret.what());
return fs->Stat(ret.Value, statbuf);
}
int FileDescriptorTable::usr_dup(int oldfd)
@ -339,7 +333,7 @@ namespace vfs
return -EMFILE;
Fildes new_dfd{};
new_dfd.Node = it->second.Node;
new_dfd.node = it->second.node;
new_dfd.Mode = it->second.Mode;
this->FileMap.insert({newfd, new_dfd});
@ -364,7 +358,7 @@ namespace vfs
this->usr_close(newfd);
Fildes new_dfd{};
new_dfd.Node = it->second.Node;
new_dfd.node = it->second.node;
new_dfd.Mode = it->second.Mode;
this->FileMap.insert({newfd, new_dfd});
@ -378,7 +372,7 @@ namespace vfs
if (it == this->FileMap.end())
ReturnLogError(-EBADF, "Invalid fd %d", fd);
return it->second.Node->Ioctl(request, argp);
return fs->Ioctl(it->second.node, request, argp);
}
FileDescriptorTable::FileDescriptorTable(void *_Owner)
@ -386,11 +380,12 @@ namespace vfs
{
debug("+ %#lx", this);
mode_t Mode = S_IXOTH | S_IROTH |
S_IXGRP | S_IRGRP |
S_IXUSR | S_IRUSR |
/* d r-x r-x r-x */
mode_t Mode = S_IROTH | S_IXOTH |
S_IRGRP | S_IXGRP |
S_IRUSR | S_IXUSR |
S_IFDIR;
this->fdDir = fs->Create(((Tasking::PCB *)_Owner)->ProcDirectory, "fd", Mode);
Tasking::PCB *pcb = (Tasking::PCB *)_Owner;
this->fdDir = fs->Create(pcb->ProcDirectory, "fd", Mode);
}
}

View File

@ -15,12 +15,12 @@
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <filesystem/ramfs.hpp>
#include <fs/ramfs.hpp>
#include <memory.hpp>
#include <functional>
#include <debug.h>
#include "../../kernel.h"
#include "../kernel.h"
namespace vfs
{
@ -81,7 +81,6 @@ namespace vfs
inode.Index = NextInode;
inode.Offset = 0;
inode.PrivateData = this;
inode.Flags = I_FLAG_CACHE_KEEP;
const char *basename;
size_t length;
@ -329,54 +328,54 @@ namespace vfs
}
}
O2 int __ramfs_Lookup(struct Inode *Parent, const char *Name, struct Inode **Result)
int __ramfs_Lookup(struct Inode *Parent, const char *Name, struct Inode **Result)
{
return ((vfs::RAMFS *)Parent->PrivateData)->Lookup(Parent, Name, Result);
}
O2 int __ramfs_Create(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result)
int __ramfs_Create(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result)
{
return ((vfs::RAMFS *)Parent->PrivateData)->Create(Parent, Name, Mode, Result);
}
O2 ssize_t __ramfs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
ssize_t __ramfs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
{
return ((vfs::RAMFS *)Node->PrivateData)->Read(Node, Buffer, Size, Offset);
}
O2 ssize_t __ramfs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
ssize_t __ramfs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
{
return ((vfs::RAMFS *)Node->PrivateData)->Write(Node, Buffer, Size, Offset);
}
O2 ssize_t __ramfs_Readdir(struct Inode *Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
ssize_t __ramfs_Readdir(struct Inode *Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
{
return ((vfs::RAMFS *)Node->PrivateData)->ReadDir(Node, Buffer, Size, Offset, Entries);
}
O2 int __ramfs_SymLink(Inode *Parent, const char *Name, const char *Target, Inode **Result)
int __ramfs_SymLink(Inode *Parent, const char *Name, const char *Target, Inode **Result)
{
return ((vfs::RAMFS *)Parent->PrivateData)->SymLink(Parent, Name, Target, Result);
}
O2 ssize_t __ramfs_ReadLink(Inode *Node, char *Buffer, size_t Size)
ssize_t __ramfs_ReadLink(Inode *Node, char *Buffer, size_t Size)
{
return ((vfs::RAMFS *)Node->PrivateData)->ReadLink(Node, Buffer, Size);
}
O2 int __ramfs_Stat(struct Inode *Node, kstat *Stat)
int __ramfs_Stat(struct Inode *Node, kstat *Stat)
{
return ((vfs::RAMFS *)Node->PrivateData)->Stat(Node, Stat);
}
O2 int __ramfs_DestroyInode(FileSystemInfo *Info, Inode *Node)
int __ramfs_DestroyInode(FileSystemInfo *Info, Inode *Node)
{
vfs::RAMFS::RAMFSInode *inode = (vfs::RAMFS::RAMFSInode *)Node;
delete inode;
return 0;
}
O2 int __ramfs_Destroy(FileSystemInfo *fsi)
int __ramfs_Destroy(FileSystemInfo *fsi)
{
assert(fsi->PrivateData);
delete (vfs::RAMFS *)fsi->PrivateData;
@ -384,16 +383,13 @@ O2 int __ramfs_Destroy(FileSystemInfo *fsi)
return 0;
}
bool MountRAMFS(FileNode *Parent, const char *Name, size_t Index)
bool MountAndRootRAMFS(Node Parent, const char *Name, size_t Index)
{
vfs::RAMFS *ramfs = new vfs::RAMFS;
ramfs->DeviceID = fs->EarlyReserveDevice();
ramfs->RootName.assign(Name);
FileSystemInfo *fsi = new FileSystemInfo;
fsi->Name = "ramfs";
fsi->RootName = Name;
fsi->Flags = I_FLAG_ROOT | I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
fsi->SuperOps.DeleteInode = __ramfs_DestroyInode;
fsi->SuperOps.Destroy = __ramfs_Destroy;
fsi->Ops.Lookup = __ramfs_Lookup;
@ -405,13 +401,12 @@ bool MountRAMFS(FileNode *Parent, const char *Name, size_t Index)
fsi->Ops.ReadLink = __ramfs_ReadLink;
fsi->Ops.Stat = __ramfs_Stat;
fsi->PrivateData = ramfs;
ramfs->DeviceID = fs->RegisterFileSystem(fsi);
Inode *root = nullptr;
ramfs->Create(nullptr, Name, S_IFDIR | 0755, &root);
fs->LateRegisterFileSystem(ramfs->DeviceID, fsi, root);
fs->AddRootAt(root, Index);
fs->Mount(Parent, root, Name);
fs->Mount(Parent, root, Name, fsi);
fs->AddRoot(Index, fs->Convert(root));
return true;
}

View File

@ -15,12 +15,12 @@
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <filesystem/ustar.hpp>
#include <fs/ustar.hpp>
#include <memory.hpp>
#include <functional>
#include <debug.h>
#include "../../kernel.h"
#include "../kernel.h"
#define TMAGIC "ustar"
#define TMAGLEN 6
@ -32,7 +32,7 @@ namespace vfs
int USTAR::Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result)
{
auto Parent = (USTARInode *)_Parent;
debug("looking up for %s", Name);
const char *basename;
size_t length;
cwk_path_get_basename(Name, &basename, &length);
@ -91,7 +91,6 @@ namespace vfs
inode.Index = NextInode;
inode.Offset = 0;
inode.PrivateData = this;
inode.Flags = I_FLAG_CACHE_KEEP;
const char *basename;
size_t length;
@ -217,6 +216,7 @@ namespace vfs
{
/* FIXME: FIX ALIGNMENT FOR DIRENT! */
auto Node = (USTARInode *)_Node;
debug("reading directory %s", Node->Path.c_str());
off_t realOffset = Offset;
@ -237,6 +237,7 @@ namespace vfs
ent->d_type = DT_DIR;
strcpy(ent->d_name, ".");
totalSize += reclen;
debug(".");
}
if (Offset <= 1)
@ -263,6 +264,7 @@ namespace vfs
ent->d_type = DT_DIR;
strcpy(ent->d_name, "..");
totalSize += reclen;
debug("..");
}
// off_t entriesSkipped = 0;
@ -309,10 +311,13 @@ namespace vfs
if (var->Deleted)
continue;
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(var->Name.c_str()) + 1);
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + var->Name.size() + 1);
if (totalSize + reclen >= Size)
if (totalSize + reclen > Size)
{
debug("not enough space for %s (%zu + %zu = %zu > %zu)", var->Name.c_str(), totalSize, reclen, totalSize + reclen, Size);
break;
}
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
ent->d_ino = var->Node.Index;
@ -349,7 +354,7 @@ namespace vfs
break;
}
strncpy(ent->d_name, var->Name.c_str(), strlen(var->Name.c_str()));
debug("%s", var->Name.c_str());
totalSize += reclen;
entries++;
}
@ -601,7 +606,6 @@ namespace vfs
uNode.RawDevice = 0;
uNode.Index = NextInode;
SetMode(uNode, header);
uNode.Flags = I_FLAG_CACHE_KEEP;
uNode.Offset = 0;
uNode.PrivateData = this;
@ -847,17 +851,8 @@ bool TestAndInitializeUSTAR(uintptr_t Address, size_t Size, size_t Index)
return false;
}
ustar->DeviceID = fs->EarlyReserveDevice();
ustar->ReadArchive(Address, Size);
Inode *rootfs = nullptr;
ustar->Lookup(nullptr, "/", &rootfs);
assert(rootfs != nullptr);
FileSystemInfo *fsi = new FileSystemInfo;
fsi->Name = "ustar";
fsi->RootName = "/";
fsi->Flags = I_FLAG_ROOT | I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
fsi->SuperOps.DeleteInode = __ustar_DestroyInode;
fsi->SuperOps.Destroy = __ustar_Destroy;
fsi->Ops.Lookup = __ustar_Lookup;
@ -868,8 +863,23 @@ bool TestAndInitializeUSTAR(uintptr_t Address, size_t Size, size_t Index)
fsi->Ops.ReadLink = __ustar_ReadLink;
fsi->Ops.Stat = __ustar_Stat;
fsi->PrivateData = ustar;
fs->LateRegisterFileSystem(ustar->DeviceID, fsi, rootfs);
fs->AddRootAt(rootfs, Index);
ustar->DeviceID = fs->RegisterFileSystem(fsi);
ustar->ReadArchive(Address, Size);
Inode *rootfs = nullptr;
ustar->Lookup(nullptr, "/", &rootfs);
assert(rootfs != nullptr);
eNode _node = fs->Convert(rootfs);
assert(_node.Error == 0);
Node node = _node;
node->fsi = fsi;
node->Flags.MountPoint = true;
node->Name = "/";
node->Path = "/";
fs->AddRoot(Index, node);
return true;
}

586
Kernel/fs/vfs.cpp Normal file
View File

@ -0,0 +1,586 @@
/*
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 <fs/vfs.hpp>
#include "../kernel.h"
namespace vfs
{
eNode Virtual::Convert(Inode *inode)
{
Node cache = std::make_shared<NodeCache>();
cache->inode = inode;
return {cache, 0};
}
eNode Virtual::Convert(Node &Parent, Inode *inode)
{
Node cache = std::make_shared<NodeCache>();
cache->inode = inode;
cache->fsi = Parent->fsi;
cache->Parent = Parent;
Parent->Children.push_back(cache);
return {cache, 0};
}
std::string Virtual::NormalizePath(Node &Parent, std::string Path, bool Join)
{
std::string result;
if (Join)
{
size_t len = Path.size() + Parent->Path.size() + 2;
result.reserve(len);
len = cwk_path_join(Parent->Path.c_str(), Path.c_str(), result.data(), result.capacity());
result.resize(len);
return result;
}
size_t len = Path.size() + 2;
result.reserve(len);
len = cwk_path_normalize(Path.c_str(), result.data(), result.capacity());
result.resize(len);
return result;
}
bool Virtual::RootExists(dev_t Index)
{
if (Roots.find(Index) == Roots.end())
return false;
return true;
}
eNode Virtual::GetRoot(dev_t Index)
{
auto it = Roots.find(Index);
if (it == Roots.end())
return {nullptr, ENOENT};
return {it->second, 0};
}
ssize_t Virtual::GetRoot(Node Index)
{
for (auto it = Roots.begin(); it != Roots.end(); ++it)
{
if (it->second == Index)
return it->first;
}
return -ENOENT;
}
int Virtual::AddRoot(dev_t Index, Node Root, bool Replace)
{
assert(Root != nullptr);
auto it = Roots.find(Index);
if (it == Roots.end())
{
Roots[Index] = Root;
return 0;
}
if (Replace)
{
Roots[Index] = Root;
return 0;
}
else
{
debug("Root %ld already exists", Index);
return EEXIST;
}
}
dev_t Virtual::RegisterFileSystem(FileSystemInfo *fsi)
{
assert(fsi != nullptr);
FileSystems.insert({FileSystems.size(), fsi});
return FileSystems.size() - 1;
}
int Virtual::UnregisterFileSystem(dev_t Device)
{
auto it = FileSystems.find(Device);
if (it == FileSystems.end())
return -ENOENT;
FileSystemInfo *fsi = it->second;
/* TODO: unmount */
fixme("Unmounting %d", Device);
if (fsi->SuperOps.Synchronize)
fsi->SuperOps.Synchronize(fsi, nullptr);
if (fsi->SuperOps.Destroy)
fsi->SuperOps.Destroy(fsi);
FileSystems.erase(it);
return 0;
}
eNode Virtual::Lookup(Node &Parent, std::string Path)
{
assert(Parent != nullptr);
debug("looking up \"%s\" in \"%s\"", Path.c_str(), Parent->Path.c_str());
if (Path == ".")
return {Parent, 0};
else if (Path == "..")
return {Parent->Parent ? Parent->Parent : Parent, 0};
Node base = Parent;
bool absolute = PathIsAbsolute(Path);
if (absolute == true)
{
while (base->Parent)
base = base->Parent;
}
debug("base is \"%s\" and path is \"%s\" %d", base->Path.c_str(), Path.c_str(), absolute);
Path = this->NormalizePath(base, Path, !absolute);
debug("after normalizing, path is \"%s\" %d", Path.c_str(), absolute);
struct cwk_segment segment;
if (!cwk_path_get_first_segment(Path.c_str(), &segment))
{
debug("%s no segments; %d", Path.c_str(), absolute);
if (Path == "/")
return {base, 0};
assert(!"Path doesn't have any segments.");
}
Node node = base;
/* We need to go to the root after NormalizePath even if Path is relative */
if (absolute == false)
{
while (node->Parent)
{
debug("current parent \"%s\"", node->Parent->Path.c_str());
node = node->Parent;
debug("new parent \"%s\"", node->Parent ? node->Parent->Path.c_str() : "<null>");
}
}
std::string currentPath = node->Path;
if (currentPath.empty())
currentPath = "/";
do
{
std::string segmentStr(segment.begin, segment.size);
debug("Current segment is \"%s\"", segmentStr.c_str());
eNode ret = node->CachedSearch(segmentStr);
if (ret == false)
{
debug("cache miss for \"%s\"", segmentStr.c_str());
if (node->fsi->Ops.Lookup == nullptr)
return {nullptr, ENOTSUP};
Inode *inode;
int ret = node->fsi->Ops.Lookup(node->inode, segmentStr.c_str(), &inode);
if (ret != 0)
return {nullptr, ret};
if (currentPath == "/")
currentPath += segmentStr;
else
currentPath += "/" + segmentStr;
node = Convert(node, inode);
node->Name = segmentStr;
node->Path = currentPath;
}
else
{
debug("cache hit for \"%s\"", segmentStr.c_str());
node = ret;
if (currentPath == "/")
currentPath += segmentStr;
else
currentPath += "/" + segmentStr;
}
} while (cwk_path_get_next_segment(&segment));
return {node, 0};
}
eNode Virtual::Create(Node &Parent, std::string Name, mode_t Mode, bool ErrorIfExists)
{
eNode exists = this->Lookup(Parent, Name);
if (exists)
{
if (ErrorIfExists)
return {nullptr, EEXIST};
/* I should handle this in a better way */
assert((exists.Value->inode->Mode & S_IFMT) == (Mode & S_IFMT));
debug("File \"%s\" already exists in cache", Name.c_str());
return exists;
}
if (!Parent)
return {nullptr, EINVAL};
if (Parent->fsi->Ops.Create == nullptr)
return {nullptr, ENOTSUP};
Inode *inode;
int ret = Parent->fsi->Ops.Create(Parent->inode, Name.c_str(), Mode, &inode);
if (ret != 0)
return {nullptr, ret};
Node node = Convert(Parent, inode);
node->Name = Name;
std::string unormalized = Parent->Path == "/" ? "/" + Name : Parent->Path + "/" + Name;
node->Path = fs->NormalizePath(Parent, unormalized);
return {node, 0};
}
int Virtual::Remove(Node &Parent, std::string Name)
{
if (!Parent)
return -EINVAL;
if (Parent->fsi->Ops.Remove == nullptr)
return -ENOTSUP;
int ret = Parent->fsi->Ops.Remove(Parent->inode, Name.c_str());
if (ret == 0)
{
for (auto it = Parent->Children.begin(); it != Parent->Children.end(); ++it)
{
if (it->get()->Name != Name)
continue;
Parent->Children.erase(it);
break;
}
}
return ret;
}
int Virtual::Remove(Node &node)
{
if (!node->Parent)
return -EINVAL;
if (node->Parent->fsi->Ops.Remove == nullptr)
return -ENOTSUP;
int ret = node->Parent->fsi->Ops.Remove(node->inode, node->Name.c_str());
if (ret == 0)
{
Node &p = node->Parent;
for (auto it = p->Children.begin(); it != p->Children.end(); ++it)
{
if (it->get() != node.get())
continue;
p->Children.erase(it);
break;
}
}
return ret;
}
int Virtual::Rename(Node &node, std::string NewName)
{
if (node->fsi->Ops.Rename == nullptr)
return -ENOTSUP;
int ret = node->fsi->Ops.Rename(node->inode, node->Name.c_str(), NewName.c_str());
if (ret == 0)
node->Name = NewName;
return ret;
}
ssize_t Virtual::Read(Node &Target, void *Buffer, size_t Size, off_t Offset)
{
if (Target->IsDirectory() || Target->IsMountPoint())
return -EISDIR;
if (Target->IsSymbolicLink())
return -EINVAL;
/* TODO: cache buffer */
return Target->__Read(Buffer, Size, Offset);
}
ssize_t Virtual::Write(Node &Target, const void *Buffer, size_t Size, off_t Offset)
{
if (Target->IsDirectory() || Target->IsMountPoint())
return -EISDIR;
if (Target->IsSymbolicLink())
return -EINVAL;
/* TODO: cache buffer */
return Target->__Write(Buffer, Size, Offset);
}
int Virtual::Truncate(Node &Target, off_t Size)
{
if (Target->IsDirectory() || Target->IsMountPoint())
return -EISDIR;
if (!Target->IsRegularFile())
return -EINVAL;
/* TODO: cache buffer */
return Target->__Truncate(Size);
}
__no_sanitize("alignment") ssize_t Virtual::ReadDirectory(Node &Target, kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
{
if (!Target->IsDirectory() && !Target->IsMountPoint())
return -ENOTDIR;
ssize_t total = 0;
off_t entryIndex = 0;
std::list<std::string> seen;
uint8_t *bufPtr = reinterpret_cast<uint8_t *>(Buffer);
if (Target->fsi && Target->fsi->Ops.ReadDir)
{
const size_t tempBufSize = 4096;
std::unique_ptr<uint8_t[]> tempBuf(new uint8_t[tempBufSize]);
off_t fsOffset = Offset;
ssize_t read = Target->fsi->Ops.ReadDir(Target->inode, (kdirent *)tempBuf.get(), tempBufSize, fsOffset, Entries);
if (read > 0)
{
ssize_t pos = 0;
while (pos < read)
{
kdirent *ent = (kdirent *)(tempBuf.get() + pos);
if (ent->d_reclen == 0)
break;
size_t reclen = ent->d_reclen;
if (total + reclen > Size)
break;
memcpy(bufPtr, ent, reclen);
seen.push_back(ent->d_name);
bufPtr += reclen;
total += reclen;
pos += reclen;
entryIndex++;
}
}
}
for (const auto &child : Target->Children)
{
if (std::find(seen.begin(), seen.end(), child->Name) != seen.end())
continue;
if (entryIndex < Offset)
{
entryIndex++;
continue;
}
uint16_t reclen = (uint16_t)(offsetof(struct kdirent, d_name) + child->Name.size() + 1);
if (total + reclen > (ssize_t)Size)
break;
kdirent *ent = (kdirent *)bufPtr;
ent->d_ino = child->inode ? child->inode->Index : 0;
ent->d_off = entryIndex++;
ent->d_reclen = reclen;
ent->d_type = child->inode ? IFTODT(child->inode->Mode) : DT_UNKNOWN;
strcpy(ent->d_name, child->Name.c_str());
bufPtr += reclen;
total += reclen;
seen.push_back(child->Name);
}
return total;
}
__no_sanitize("alignment") std::list<Node> Virtual::ReadDirectory(Node &Target)
{
if (!Target->IsDirectory() && !Target->IsMountPoint())
return {};
std::list<Node> ret;
std::list<std::string> seen;
if (Target->fsi && Target->fsi->Ops.ReadDir)
{
const size_t bufSize = 4096;
std::unique_ptr<uint8_t[]> buf(new uint8_t[bufSize]);
off_t offset = 0;
while (true)
{
ssize_t read = Target->fsi->Ops.ReadDir(Target->inode, (kdirent *)buf.get(), bufSize, offset, LONG_MAX);
if (read <= 0)
break;
ssize_t pos = 0;
while (pos < read)
{
kdirent *ent = (kdirent *)(buf.get() + pos);
if (ent->d_reclen == 0)
break;
debug("%s", ent->d_name);
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
{
pos += ent->d_reclen;
continue;
}
seen.push_back(ent->d_name);
auto it = std::find_if(Target->Children.begin(), Target->Children.end(),
[&](const Node &n)
{ return n->Name == ent->d_name; });
if (it != Target->Children.end())
ret.push_back(*it);
else
{
eNode result = Lookup(Target, ent->d_name);
if (result.Error == 0 && result.Value)
{
Target->Children.push_back(result.Value);
result.Value->Parent = Target;
ret.push_back(result.Value);
}
}
pos += ent->d_reclen;
}
offset += read;
}
}
for (const auto &child : Target->Children)
{
if (std::find(seen.begin(), seen.end(), child->Name) != seen.end())
continue;
if (child->Name == "." || child->Name == "..")
continue;
ret.push_back(child);
seen.push_back(child->Name.c_str());
}
return ret;
}
eNode Virtual::CreateLink(Node &Parent, std::string Name, std::string Target)
{
mode_t mode = S_IRWXU |
S_IRWXG |
S_IRWXO |
S_IFLNK;
eNode enode = this->Create(Parent, Name, mode);
if (!enode)
return enode;
Node node = enode;
node->Link = Target;
return {node, 0};
}
int Virtual::Stat(Node &Target, struct kstat *Stat)
{
/* TODO: cache */
return Target->__Stat(Stat);
}
off_t Virtual::Seek(Node &Target, off_t Offset)
{
/* TODO: cache */
return Target->__Seek(Offset);
}
int Virtual::Open(Node &Target, int Flags, mode_t Mode)
{
/* TODO: cache */
return Target->__Open(Flags, Mode);
}
int Virtual::Close(Node &Target)
{
/* TODO: cache */
return Target->__Close();
}
eNode Virtual::Mount(Node &Parent, Inode *inode, std::string Name, FileSystemInfo *fsi)
{
assert(Parent);
assert(inode);
Node ret = this->Convert(inode);
ret->fsi = fsi;
ret->Name = Name;
std::string unormalized = Parent->Path == "/" ? "/" + Name : Parent->Path + "/" + Name;
ret->Path = fs->NormalizePath(Parent, unormalized);
// ret->Link =
ret->Parent = Parent;
Parent->Children.push_back(ret);
return {ret, 0};
}
int Virtual::Umount(Node &node)
{
if (!node->Flags.MountPoint)
{
debug("node %s is not a mountpoint", node->Path.c_str());
return -EINVAL;
}
fixme("untested code");
std::shared_ptr<NodeCache> &ptr = node;
ptr.reset();
return 0;
}
int Virtual::Umount(Node &Parent, std::string Name)
{
eNode node = Parent->CachedSearch(Name);
if (!node)
{
debug("mountpoint %s not found: %s", Name.c_str(), node.what());
return -node.Error;
}
return this->Umount(node.Value);
}
void Virtual::Initialize()
{
debug("Initializing virtual file system...");
Node root = this->GetRoot(0);
/* d rwx rwx rwx */
mode_t mode = S_IRWXU |
S_IRWXG |
S_IRWXO |
S_IFDIR;
Node var = this->Create(root, "var", mode, false);
Node log = this->Create(var, "log", mode, false);
}
Virtual::Virtual() {}
Virtual::~Virtual() {}
}

View File

@ -22,7 +22,8 @@
#include <interface/driver.h>
#include <interface/input.h>
#include <filesystem.hpp>
#include <interface/block.h>
#include <fs/vfs.hpp>
#include <unordered_map>
#include <memory.hpp>
#include <ints.hpp>
@ -120,17 +121,15 @@ namespace Driver
* 1 - input/... devices
*/
dev_t DriverIDCounter = 2;
FileNode *devNode = nullptr;
FileNode *devInputNode = nullptr;
Node devNode = nullptr;
Node devInputNode = nullptr;
Node devBlockNode = nullptr;
bool IsDriverTrusted(FileNode *File);
int LoadDriverFile(DriverObject &Drv, FileNode *File);
bool IsDriverTrusted(Node File);
int LoadDriverFile(DriverObject &Drv, Node File);
void ReloadDriver(dev_t driverID);
void InitializeDaemonFS();
dev_t RegisterInputDevice(std::unordered_map<dev_t, DriverHandlers> *, dev_t, size_t, const InodeOperations *);
dev_t RegisterBlockDevice(std::unordered_map<dev_t, DriverHandlers> *, dev_t, size_t, const InodeOperations *);
void InitializeDeviceDirectory();
public:
RingBuffer<KeyboardReport> GlobalKeyboardInputReports;
@ -138,11 +137,16 @@ namespace Driver
struct DeviceInode
{
struct Inode Node;
FileNode *Parent;
struct Inode inode;
Node Parent;
Inode *ParentInode;
std::string Name;
std::vector<DeviceInode *> Children;
size_t Size;
time_t AccessTime, ModifyTime, ChangeTime;
uint32_t BlockSize;
uint32_t Blocks;
};
std::unordered_map<dev_t, DriverObject> &
@ -185,6 +189,9 @@ namespace Driver
int ReportInputEvent(dev_t DriverID, InputReport *Report);
int UnregisterDevice(dev_t DriverID, dev_t Device);
dev_t RegisterBlockDevice(dev_t DriverID, struct BlockDevice *Device);
int UnregisterBlockDevice(dev_t DriverID, dev_t DeviceID);
void *AllocateMemory(dev_t DriverID, size_t Pages);
void FreeMemory(dev_t DriverID, void *Pointer, size_t Pages);
@ -193,8 +200,6 @@ namespace Driver
private:
~Manager();
};
void ManagerDaemonWrapper();
}
void *GetSymbolByName(const char *Name, int Version);
@ -215,9 +220,12 @@ namespace v0
int UnregisterInterruptHandler(dev_t DriverID, uint8_t IRQ, void *Handler);
int UnregisterAllInterruptHandlers(dev_t DriverID, void *Handler);
dev_t RegisterFileSystem(dev_t DriverID, FileSystemInfo *Info, struct Inode *Root);
dev_t RegisterFileSystem(dev_t DriverID, FileSystemInfo *Info);
int UnregisterFileSystem(dev_t DriverID, dev_t Device);
dev_t RegisterBlockDevice(dev_t DriverID, struct BlockDevice *Device);
int UnregisterBlockDevice(dev_t DriverID, dev_t DeviceID);
pid_t CreateKernelProcess(dev_t DriverID, const char *Name);
pid_t CreateKernelThread(dev_t DriverID, pid_t pId, const char *Name, void *EntryPoint, void *Argument);
pid_t GetCurrentProcess(dev_t DriverID);

View File

@ -20,7 +20,7 @@
#include <types.h>
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include <task.hpp>
#include <errno.h>
#include <vector>
@ -50,15 +50,15 @@ namespace Execute
void *ELFProgramHeaders;
void GenerateAuxiliaryVector(Memory::VirtualMemoryArea *vma,
FileNode *fd, Elf_Ehdr ELFHeader,
Node &fd, Elf_Ehdr ELFHeader,
uintptr_t EntryPoint,
uintptr_t BaseAddress);
void LoadSegments(FileNode *fd, Tasking::PCB *TargetProcess, Elf_Ehdr &ELFHeader, uintptr_t &BaseAddress);
void LoadSegments(Node &fd, Tasking::PCB *TargetProcess, Elf_Ehdr &ELFHeader, uintptr_t &BaseAddress);
void LoadExec(FileNode *fd, Tasking::PCB *TargetProcess);
void LoadDyn(FileNode *fd, Tasking::PCB *TargetProcess);
bool LoadInterpreter(FileNode *fd, Tasking::PCB *TargetProcess);
void LoadExec(Node &fd, Tasking::PCB *TargetProcess);
void LoadDyn(Node &fd, Tasking::PCB *TargetProcess);
bool LoadInterpreter(Node &fd, Tasking::PCB *TargetProcess);
public:
decltype(IsElfValid) &IsValid = IsElfValid;
@ -74,7 +74,7 @@ namespace Execute
~ELFObject();
};
BinaryType GetBinaryType(FileNode *Path);
BinaryType GetBinaryType(Node &Path);
BinaryType GetBinaryType(std::string Path);
int Spawn(const char *Path, const char **argv, const char **envp,
@ -88,12 +88,12 @@ namespace Execute
char *GetELFStringTable(Elf_Ehdr *Header);
char *ELFLookupString(Elf_Ehdr *Header, uintptr_t Offset);
Elf_Sym *ELFLookupSymbol(Elf_Ehdr *Header, std::string Name);
Elf_Sym ELFLookupSymbol(FileNode *fd, std::string Name);
Elf_Sym ELFLookupSymbol(Node &fd, std::string Name);
uintptr_t ELFGetSymbolValue(Elf_Ehdr *Header, uintptr_t Table, uintptr_t Index);
std::vector<Elf_Phdr> ELFGetSymbolType(FileNode *fd, SegmentTypes Tag);
std::vector<Elf_Shdr> ELFGetSections(FileNode *fd, std::string SectionName);
std::vector<Elf_Dyn> ELFGetDynamicTag(FileNode *fd, DynamicArrayTags Tag);
std::vector<Elf_Phdr> ELFGetSymbolType(Node &fd, SegmentTypes Tag);
std::vector<Elf_Shdr> ELFGetSections(Node &fd, std::string SectionName);
std::vector<Elf_Dyn> ELFGetDynamicTag(Node &fd, DynamicArrayTags Tag);
}
#endif // !__FENNIX_KERNEL_FILE_EXECUTE_H__

View File

@ -1,260 +0,0 @@
/*
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/>.
*/
#ifndef __FENNIX_KERNEL_FILESYSTEM_H__
#define __FENNIX_KERNEL_FILESYSTEM_H__
#include <types.h>
#include <interface/fs.h>
#include <unordered_map>
#include <lock.hpp>
#include <errno.h>
#include <atomic>
#include <string>
#include <list>
static_assert(DTTOIF(DT_FIFO) == S_IFIFO);
static_assert(IFTODT(S_IFCHR) == DT_CHR);
/**
* This macro is used to check if a filesystem operation is available.
*
* TL;DR
*
* @code
* if FileSystemInfo.Ops.op == nullptr
* return -err
* else
* return FileSystemInfo.Ops.op(this->Node, ...);
* @endcode
*
* @param op The operation to check.
* @param err The error to return if the operation is not available.
* @param ... The arguments to pass to the operation.
*
* @return The result of the operation.
*/
#define __check_op(op, err, ...) \
if (fsi->Ops.op == nullptr) \
return -err; \
else \
return fsi->Ops.op(this->Node, ##__VA_ARGS__)
#define FSROOT(num) "\x06root-" #num "\x06"
class FileNode
{
public:
std::string Name, Path;
FileNode *Parent;
std::vector<FileNode *> Children;
Inode *Node;
FileSystemInfo *fsi;
std::string GetName();
std::string GetPath();
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, ENOTSUP, Name, Node); }
int Create(const char *Name, mode_t Mode, Inode **Node) { __check_op(Create, EROFS, Name, Mode, Node); }
int Remove(const char *Name) { __check_op(Remove, EROFS, Name); }
int Rename(const char *OldName, const char *NewName) { __check_op(Rename, EROFS, OldName, NewName); }
ssize_t Read(auto Buffer, size_t Size, off_t Offset) { __check_op(Read, ENOTSUP, (void *)Buffer, Size, Offset); }
ssize_t Write(const auto Buffer, size_t Size, off_t Offset) { __check_op(Write, EROFS, (const void *)Buffer, Size, Offset); }
int Truncate(off_t Size) { __check_op(Truncate, EROFS, Size); }
int Open(int Flags, mode_t Mode) { __check_op(Open, ENOTSUP, Flags, Mode); }
int Close() { __check_op(Close, ENOTSUP); }
int Ioctl(unsigned long Request, void *Argp) { __check_op(Ioctl, ENOTSUP, Request, Argp); }
ssize_t ReadDir(struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) { __check_op(ReadDir, ENOTSUP, Buffer, Size, Offset, Entries); }
int MkDir(const char *Name, mode_t Mode, struct Inode **Result) { __check_op(MkDir, EROFS, Name, Mode, Result); }
int RmDir(const char *Name) { __check_op(RmDir, EROFS, Name); }
int SymLink(const char *Name, const char *Target, struct Inode **Result) { __check_op(SymLink, EROFS, Name, Target, Result); }
ssize_t ReadLink(auto Buffer, size_t Size) { __check_op(ReadLink, ENOTSUP, (char *)Buffer, Size); }
off_t Seek(off_t Offset) { __check_op(Seek, ENOTSUP, Offset); }
int Stat(struct kstat *Stat) { __check_op(Stat, ENOTSUP, Stat); }
~FileNode() = delete;
};
#undef __check_op
namespace vfs
{
struct vfsInode
{
Inode Node;
std::string Name;
std::string FriendlyName;
std::vector<Inode *> Children;
};
class Virtual
{
private:
NewLock(VirtualLock);
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 *CacheSearchReturnLast(FileNode *Parent, const char **Path);
FileNode *CacheRecursiveSearch(FileNode *Root, const char *NameOrPath, bool IsName);
FileNode *CacheLookup(FileNode *Parent, const char *Path);
FileNode *CreateCacheNode(FileNode *Parent, Inode *Node, const char *Name, mode_t Mode);
int RemoveCacheNode(FileNode *Node);
public:
vfsInode *FileSystemRoots = nullptr;
/**
* Default reserved roots:
*
* 0 - Native
* 1 - Linux
* 2 - Windows
*/
std::unordered_map<ino_t, FileNode *> FileRoots;
bool PathIsRelative(const char *Path);
bool PathIsAbsolute(const char *Path) { return !PathIsRelative(Path); }
/**
* Reserve a device number for a filesystem
*
* @note After this function is called, the filesystem must
* call LateRegisterFileSystem to release the lock
*/
dev_t EarlyReserveDevice();
/**
* 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);
void AddRootAt(Inode *Root, size_t Index);
bool SetRootAt(Inode *Root, size_t Index);
void RemoveRoot(Inode *Root);
FileNode *GetRoot(size_t Index);
bool RootExists(size_t Index);
FileNode *Create(FileNode *Parent, const char *Name, mode_t Mode);
FileNode *ForceCreate(FileNode *Parent, const char *Name, mode_t Mode);
FileNode *Mount(FileNode *Parent, Inode *Node, const char *Path);
int Unmount(const char *Path);
FileNode *GetByPath(const char *Path, FileNode *Parent);
std::string GetByNode(FileNode *Node);
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();
};
class FileDescriptorTable
{
public:
struct Fildes
{
enum FildesType
{
FD_INODE,
FD_PIPE,
FD_SOCKET,
} Type;
mode_t Mode = 0;
int Flags = 0;
FileNode *Node = nullptr;
int References = 0;
off_t Offset = 0;
int operator==(const Fildes &other)
{
return Type == other.Type &&
Mode == other.Mode &&
Flags == other.Flags &&
Node == other.Node &&
References == other.References &&
Offset == other.Offset;
}
};
private:
FileNode *fdDir = nullptr;
void *Owner;
int AddFileDescriptor(const char *AbsolutePath, mode_t Mode, int Flags);
int RemoveFileDescriptor(int FileDescriptor);
int GetFreeFileDescriptor();
public:
std::unordered_map<int, Fildes> FileMap;
int GetFlags(int FileDescriptor);
int SetFlags(int FileDescriptor, int Flags);
void Fork(FileDescriptorTable *Parent);
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);
ssize_t usr_pread(int fd, void *buf, size_t count, off_t offset);
ssize_t usr_pwrite(int fd, const void *buf, size_t count, off_t offset);
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() = default;
};
}
#endif // !__FENNIX_KERNEL_FILESYSTEM_H__

View File

@ -1,48 +0,0 @@
/*
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/>.
*/
#ifndef __FENNIX_KERNEL_FILESYSTEM_INITRD_H__
#define __FENNIX_KERNEL_FILESYSTEM_INITRD_H__
#include <types.h>
#include <filesystem.hpp>
namespace vfs
{
class Initrd
{
public:
struct InitrdHeader
{
uint32_t nfiles;
};
struct InitrdFileHeader
{
uint8_t magic;
char name[64];
uint32_t offset;
uint32_t length;
};
Initrd(uintptr_t Address);
~Initrd();
};
}
#endif // !__FENNIX_KERNEL_FILESYSTEM_INITRD_H__

86
Kernel/include/fs/fdt.hpp Normal file
View File

@ -0,0 +1,86 @@
/*
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/>.
*/
#pragma once
#include <fs/node.hpp>
#include <unordered_map>
namespace vfs
{
class FileDescriptorTable
{
public:
struct Fildes
{
enum FildesType
{
FD_INODE,
FD_PIPE,
FD_SOCKET,
} Type;
mode_t Mode = 0;
int Flags = 0;
Node node = nullptr;
int References = 0;
off_t Offset = 0;
int operator==(const Fildes &other)
{
return Type == other.Type &&
Mode == other.Mode &&
Flags == other.Flags &&
node.get() == other.node.get() &&
References == other.References &&
Offset == other.Offset;
}
};
private:
Node fdDir = nullptr;
void *Owner;
int AddFileDescriptor(const char *AbsolutePath, mode_t Mode, int Flags);
int RemoveFileDescriptor(int FileDescriptor);
int GetFreeFileDescriptor();
public:
std::unordered_map<int, Fildes> FileMap;
int GetFlags(int FileDescriptor);
int SetFlags(int FileDescriptor, int Flags);
void Fork(FileDescriptorTable *Parent);
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);
ssize_t usr_pread(int fd, void *buf, size_t count, off_t offset);
ssize_t usr_pwrite(int fd, const void *buf, size_t count, off_t offset);
int usr_close(int fd);
off_t usr_lseek(int fd, off_t offset, int whence);
int usr_stat(const char *pathname, kstat *statbuf);
int usr_fstat(int fd, kstat *statbuf);
int usr_lstat(const char *pathname, 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() = default;
};
}

207
Kernel/include/fs/node.hpp Normal file
View File

@ -0,0 +1,207 @@
/*
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/>.
*/
#pragma once
#include <interface/fs.h>
#include <errno.h>
#include <string>
#include <vector>
/**
* This macro is used to check if a filesystem operation is available.
*
* TL;DR
*
* @code
* if FileSystemInfo.Ops.op == nullptr
* return -err
* else
* return FileSystemInfo.Ops.op(this->Node, ...);
* @endcode
*
* @param op The operation to check.
* @param err The error to return if the operation is not available.
* @param ... The arguments to pass to the operation.
*
* @return The result of the operation.
*/
#define __check_op(op, err, ...) \
if (unlikely(fsi->Ops.op == nullptr)) \
return -err; \
else \
return fsi->Ops.op(this->inode, ##__VA_ARGS__)
namespace vfs
{
class NodeObject
{
public:
Inode *inode;
FileSystemInfo *fsi;
union
{
struct
{
uint8_t MountPoint : 1;
uint8_t __reserved : 7;
};
uint8_t raw;
} Flags;
int __Lookup(const char *Name, Inode **Node) { __check_op(Lookup, ENOTSUP, Name, Node); }
int __Create(const char *Name, mode_t Mode, Inode **Node) { __check_op(Create, ENOTSUP, Name, Mode, Node); }
int __Remove(const char *Name) { __check_op(Remove, ENOTSUP, Name); }
int __Rename(const char *OldName, const char *NewName) { __check_op(Rename, ENOTSUP, OldName, NewName); }
ssize_t __Read(auto Buffer, size_t Size, off_t Offset) { __check_op(Read, ENOTSUP, (void *)Buffer, Size, Offset); }
ssize_t __Write(const auto Buffer, size_t Size, off_t Offset) { __check_op(Write, ENOTSUP, (const void *)Buffer, Size, Offset); }
int __Truncate(off_t Size) { __check_op(Truncate, ENOTSUP, Size); }
int __Open(int Flags, mode_t Mode) { __check_op(Open, ENOTSUP, Flags, Mode); }
int __Close() { __check_op(Close, ENOTSUP); }
int __Ioctl(unsigned long Request, void *Argp) { __check_op(Ioctl, ENOTSUP, Request, Argp); }
ssize_t __ReadDir(struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) { __check_op(ReadDir, ENOTSUP, Buffer, Size, Offset, Entries); }
int __MkDir(const char *Name, mode_t Mode, struct Inode **Result) { __check_op(MkDir, ENOTSUP, Name, Mode, Result); }
int __RmDir(const char *Name) { __check_op(RmDir, ENOTSUP, Name); }
int __SymLink(const char *Name, const char *Target, struct Inode **Result) { __check_op(SymLink, ENOTSUP, Name, Target, Result); }
ssize_t __ReadLink(auto Buffer, size_t Size) { __check_op(ReadLink, ENOTSUP, (char *)Buffer, Size); }
off_t __Seek(off_t Offset) { __check_op(Seek, ENOTSUP, Offset); }
int __Stat(struct kstat *Stat) { __check_op(Stat, ENOTSUP, Stat); }
~NodeObject()
{
debug("%#lx destructor called", this);
}
};
}
class NodeCache;
/**
* @brief Node is a type that represents a filesystem node.
* It is a shared pointer to a NodeCache object.
*
* If the refcount of the NodeCache object goes to zero, the data is synced to disk.
*/
typedef std::shared_ptr<NodeCache> Node;
/**
* @brief NodeResult is a type that represents the result of a filesystem operation.
* It contains a Node object and an error code.
*/
typedef struct NodeResult
{
/* Value must be the first member of the struct to allow for implicit conversion */
Node Value;
int Error;
operator bool() const { return Error == 0 && Value.get() != nullptr; }
operator Node() const { return Value; }
const char *what() const { return strerror(Error); }
} eNode;
class NodeCache : public vfs::NodeObject
{
public:
std::string Name, Path, Link;
/**
* @brief Parent of this node
*
* Maximum depth is 1, otherwise undefined behavior.
*/
Node Parent;
/**
* @brief Childrens of this node
*
* On access, children are loaded, but not children of children!
* Accessing children of children is undefined behavior.
*/
std::vector<Node> Children;
std::string GetName() { return Name; }
std::string GetPath() { return Path; }
std::string GetLink() { return Link; }
bool IsDirectory() { return S_ISDIR(inode->Mode); }
bool IsCharacterDevice() { return S_ISCHR(inode->Mode); }
bool IsBlockDevice() { return S_ISBLK(inode->Mode); }
bool IsRegularFile() { return S_ISREG(inode->Mode); }
bool IsFIFO() { return S_ISFIFO(inode->Mode); }
bool IsSymbolicLink() { return S_ISLNK(inode->Mode); }
bool IsSocket() { return S_ISSOCK(inode->Mode); }
bool IsMountPoint() { return Flags.MountPoint; }
/**
* @brief Search through the cached children of this node
*
* Searches through the cached children of this node.
*
* @param Name The name to search for
* @return 0 and a Node on success, ENOENT on failure
*/
eNode CachedSearch(std::string Name)
{
for (auto it = Children.begin(); it != Children.end(); ++it)
{
if ((*it).get() == nullptr)
{
Children.erase(it);
continue;
}
debug("comparing \"%s\" with \"%s\"", (*it)->Name.c_str(), Name.c_str());
if ((*it)->Name == Name)
{
debug("\"%s\" found", Name.c_str());
return {*it, 0};
}
}
return {nullptr, ENOENT};
}
/**
* @brief Get the allocation size of this object
*
* @return The allocated size
*/
size_t GetAllocationSize()
{
size_t size = sizeof(NodeCache);
size += Name.capacity();
size += Path.capacity();
size += Link.capacity();
size += Children.capacity();
return size;
}
~NodeCache()
{
debug("%#lx\"%s\" destructor called", this, Name.c_str());
if (this->Parent)
this->Parent->Children.erase(std::remove(this->Parent->Children.begin(), this->Parent->Children.end(), Node(this)), this->Parent->Children.end());
if (fsi->SuperOps.Synchronize)
fsi->SuperOps.Synchronize(this->fsi, this->inode);
// FIXME: recursive deletion of nodes children
}
};
#undef __check_op

View File

@ -17,7 +17,7 @@
#pragma once
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include <memory.hpp>
namespace vfs
@ -147,4 +147,4 @@ namespace vfs
};
}
bool MountRAMFS(FileNode *Parent, const char *Name, size_t Index);
bool MountAndRootRAMFS(Node Parent, const char *Name, size_t Index);

View File

@ -18,7 +18,7 @@
#ifndef __FENNIX_KERNEL_FILESYSTEM_USTAR_H__
#define __FENNIX_KERNEL_FILESYSTEM_USTAR_H__
#include <filesystem.hpp>
#include <fs/vfs.hpp>
namespace vfs
{

179
Kernel/include/fs/vfs.hpp Normal file
View File

@ -0,0 +1,179 @@
/*
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/>.
*/
#pragma once
#include <fs/fdt.hpp>
#include <errno.h>
#include <cwalk.h>
#include <atomic>
#include <string>
#include <list>
/* sanity checks */
static_assert(DTTOIF(DT_FIFO) == S_IFIFO);
static_assert(IFTODT(S_IFCHR) == DT_CHR);
namespace vfs
{
class Virtual
{
private:
std::unordered_map<dev_t, Node> Roots;
std::unordered_map<dev_t, FileSystemInfo *> FileSystems;
public:
#pragma region Utilities
inline bool PathIsRelative(const char *Path) { return cwk_path_is_relative(Path); }
inline bool PathIsAbsolute(const char *Path) { return !PathIsRelative(Path); }
inline bool PathIsRelative(std::string &Path) { return cwk_path_is_relative(Path.c_str()); }
inline bool PathIsAbsolute(std::string &Path) { return !PathIsRelative(Path.c_str()); }
eNode Convert(Node node) { return {node, 0}; }
/**
* @brief Converts an Inode to a Node
*
* Result of this function will be empty.
* You are responsible to populate the Node.
*
* @param inode Inode to convert
* @return eNode{Node, errno}
*/
eNode Convert(Inode *inode);
/**
* @brief Converts an Inode to a Node
*
* Result of this function will be populated using the Parent Node.
* This function will automatically assign the FSI, parents and children.
*
* @note Name and Path won't be set.
*
* @param Parent Parent Node
* @param inode Inode to convert
* @return eNode{Node, errno}
*/
eNode Convert(Node &Parent, Inode *inode);
/**
* @brief Normalizes a path
*
* If the path is relative, it will be normalized using the Parent Node.
* Example if Join is true:
* Parent = /home/user/Desktop
* Path = ../Documents
* Result = /home/user/Documents
*
* If Join is false:
* Path = /var/foo/bar/../../
* Result = /var
*
* @param Parent Parent Node
* @param Path Path to normalize
* @param Join If true, the path will be joined with the Parent Node
* @return Normalized Path
*/
std::string NormalizePath(Node &Parent, std::string Path, bool Join = false);
#pragma endregion Utilities
#pragma region Roots
bool RootExists(dev_t Index);
eNode GetRoot(dev_t Index);
ssize_t GetRoot(Node Index);
int AddRoot(dev_t Index, Node Root, bool Replace = false);
int AddRoot(dev_t Index, eNode Root, bool Replace = false) { return AddRoot(Index, Root.Value, Replace); }
#pragma endregion Roots
#pragma region Registrations
dev_t RegisterFileSystem(FileSystemInfo *fsi);
int UnregisterFileSystem(dev_t Device);
#pragma endregion Registrations
#pragma region Node Operations
eNode Lookup(Node &Parent, std::string Path);
eNode Create(Node &Parent, std::string Name, mode_t Mode, bool ErrorIfExists = true);
int Remove(Node &Parent, std::string Name);
int Remove(Node &node);
int Rename(Node &node, std::string NewName);
ssize_t Read(Node &Target, void *Buffer, size_t Size, off_t Offset);
ssize_t Write(Node &Target, const void *Buffer, size_t Size, off_t Offset);
int Truncate(Node &Target, off_t Size);
/**
* @brief Read directory entries
*
* @note This function includes "." and ".."
*
* @param Target
* @param Buffer
* @param Size
* @param Offset
* @param Entries
* @return
*/
ssize_t ReadDirectory(Node &Target, kdirent *Buffer, size_t Size, off_t Offset, off_t Entries);
/**
* @brief Read directory entries
*
* @note This function does NOT include "." and ".."
*
* @param Target
* @return
*/
std::list<Node> ReadDirectory(Node &Target);
eNode CreateLink(Node &Parent, std::string Name, std::string Target);
eNode CreateLink(Node &Parent, std::string Name, Node &Target) { return this->CreateLink(Parent, Name, Target->Path); }
int Stat(Node &Target, kstat *Stat);
int ReadLink(Node &Target, char *Buffer, size_t Size) { return Target->__ReadLink(Buffer, Size); }
off_t Seek(Node &Target, off_t Offset);
int Open(Node &Target, int Flags, mode_t Mode);
int Close(Node &Target);
int Ioctl(Node &Target, unsigned long Request, void *Argp) { return Target->__Ioctl(Request, Argp); }
#pragma endregion Node Operations
#pragma region Mounting
eNode Mount(Node &Parent, Inode *inode, std::string Name, FileSystemInfo *fsi);
int Umount(Node &node);
int Umount(Node &Parent, std::string Name);
#pragma endregion Mounting
void Initialize();
Virtual();
~Virtual();
};
}

View File

@ -0,0 +1,110 @@
/*
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/>.
*/
#ifndef __FENNIX_API_BLOCK_H__
#define __FENNIX_API_BLOCK_H__
#include <types.h>
#if __has_include(<interface/fs.h>)
#include <interface/fs.h>
#else
#include <fs.h>
#endif
struct BlockDevice
{
/**
* @brief Base name of the device.
*
* This name is used to identify the device in the system. It should be unique
* across all block devices. The kernel may append a number to this name to
* create a unique device name (e.g., "ahci0", "ahci1").
*/
const char *Name;
/**
* @brief Total size of the device in bytes.
*
* This value represents the total addressable storage capacity of the device.
* It is used for bounds checking and partitioning.
*/
size_t Size;
/**
* @brief Size of a single block in bytes.
*
* All read and write operations are performed in multiples of this block size.
* Typical values are 512 or 4096 bytes.
*/
uint32_t BlockSize;
/**
* @brief Number of blocks in the device.
*
* This value is calculated as Size / BlockSize. It represents the total number
* of addressable blocks on the device.
*/
size_t BlockCount;
/**
* @brief Pointer to the block device operations structure.
*
* This structure contains function pointers for various operations that can
* be performed on the block device, such as read, write, and ioctl.
*
* Yea, inode operations are used for block devices too.
*/
const InodeOperations *Ops;
/**
* @brief Opaque pointer to driver-specific or hardware-specific data.
*
* This field allows the driver to associate private context or state with the
* device, such as controller registers or internal buffers.
*/
void *PrivateData;
};
#ifndef __kernel__
/**
* @brief Registers a block device with the kernel block subsystem.
*
* This function should be called by block device drivers after initializing
* a device. The kernel will take ownership of the device structure and assign
* it a unique device ID. The device will then be accessible for filesystem
* mounting and I/O operations.
*
* @param Device Pointer to a fully initialized BlockDevice structure. All required fields must be set and valid for the lifetime of the device.
* @return Device ID (dev_t) assigned by the kernel on success, or an error code on failure.
*/
dev_t RegisterBlockDevice(struct BlockDevice *Device);
/**
* @brief Unregisters a block device from the kernel block subsystem.
*
* This function should be called by drivers when a device is being removed
* or is no longer available. The kernel will release any resources associated
* with the device and invalidate its device ID.
*
* @param DeviceID The device ID (dev_t) previously returned by RegisterBlockDevice().
* @return 0 on success, or an error code.
*/
int UnregisterBlockDevice(dev_t DeviceID);
#endif // __kernel__
#endif // __FENNIX_API_BLOCK_H__

View File

@ -322,10 +322,6 @@ struct InodeOperations
int (*Stat)(struct Inode *Node, struct kstat *Stat);
} __attribute__((packed));
#define I_FLAG_ROOT 0x1
#define I_FLAG_MOUNTPOINT 0x2
#define I_FLAG_CACHE_KEEP 0x4
struct FileSystemInfo;
struct SuperBlockOperations
{
@ -337,8 +333,8 @@ struct SuperBlockOperations
*
* Write all pending changes to the disk.
*
* @param Info Inode to synchronize. If NULL, synchronize all inodes.
* @param Node Inode to synchronize.
* @param Info Inode to synchronize.
* @param Node Inode to synchronize. If NULL, synchronize all inodes.
*
* @return Zero on success, otherwise an error code.
*/
@ -354,13 +350,50 @@ struct SuperBlockOperations
* @return Zero on success, otherwise an error code.
*/
int (*Destroy)(struct FileSystemInfo *Info);
/**
* Probe the filesystem.
*
* Check if the filesystem is supported by the driver.
*
* @param Device Device to probe.
*
* @return Zero on success, otherwise an error code.
*/
int (*Probe)(void *Device);
/**
* Mount the filesystem.
*
* Mount the filesystem on the given device.
*
* @param FS Filesystem to mount.
* @param Root Pointer to the root inode.
* @param Device Device to mount.
*
* @return Zero on success, otherwise an error code.
*/
int (*Mount)(struct FileSystemInfo *FS, struct Inode **Root, void *Device);
/**
* Unmount the filesystem.
*
* Unmount the filesystem from the given device.
*
* @param FS Filesystem to unmount.
*
* @return Zero on success, otherwise an error code.
*/
int (*Unmount)(struct FileSystemInfo *FS);
} __attribute__((packed));
struct FileSystemInfo
{
const char *Name;
const char *RootName;
int Flags;
int Capabilities;
struct SuperBlockOperations SuperOps;
struct InodeOperations Ops;
@ -368,6 +401,9 @@ struct FileSystemInfo
} __attribute__((packed));
#ifndef __kernel__
dev_t RegisterMountPoint(FileSystemInfo *fsi, Inode *Root);
int UnregisterMountPoint(dev_t Device);
dev_t RegisterFileSystem(struct FileSystemInfo *Info, struct Inode *Root);
int UnregisterFileSystem(dev_t Device);
#endif // !__kernel__

View File

@ -19,7 +19,7 @@
#define __FENNIX_KERNEL_INTERNAL_MEMORY_H__
#ifdef __cplusplus
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include <boot/binfo.h>
#include <bitmap.hpp>
#include <lock.hpp>

View File

@ -19,7 +19,7 @@
#define __FENNIX_KERNEL_MEMORY_VMA_H__
#include <types.h>
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include <bitmap.hpp>
#include <lock.hpp>
#include <list>

View File

@ -20,7 +20,7 @@
#include <types.h>
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include <memory/va.hpp>
#include <symbols.hpp>
#include <memory.hpp>
@ -219,7 +219,7 @@ namespace Tasking
TaskArchitecture Architecture = TaskArchitecture::UnknownArchitecture;
TaskCompatibility Compatibility = TaskCompatibility::UnknownPlatform;
cwk_path_style PathStyle = CWK_STYLE_UNIX;
FileNode *RootNode = nullptr;
Node RootNode = nullptr;
};
struct ThreadLocalStorage
@ -445,7 +445,7 @@ namespace Tasking
PID ID = -1;
const char *Name = nullptr;
PCB *Parent = nullptr;
FileNode *ProcDirectory = nullptr;
Node ProcDirectory = nullptr;
/* Statuses */
std::atomic_int ExitCode;
@ -489,14 +489,14 @@ namespace Tasking
} Linux{};
/* Filesystem */
FileNode *CWD;
FileNode *Executable;
Node CWD;
Node Executable;
FileDescriptorTable *FileDescriptors;
/* stdio */
FileNode *stdin;
FileNode *stdout;
FileNode *stderr;
Node stdin;
Node stdout;
Node stderr;
/*TTY::TeletypeDriver*/ void *tty;
/* Memory */
@ -521,7 +521,7 @@ namespace Tasking
void SetState(TaskState state);
void SetExitCode(int code);
void Rename(const char *name);
void SetWorkingDirectory(FileNode *node);
void SetWorkingDirectory(Node node);
void SetExe(const char *path);
size_t GetSize();
TCB *GetThread(TID ID);

View File

@ -458,6 +458,10 @@ typedef uint48_t uint_fast48_t;
#define hot __attribute__((hot))
#define cold __attribute__((cold))
#define OPTIONAL
#define IN
#define OUT
#define NoSecurityAnalysis __no_stack_protector __no_sanitize_address __no_sanitize_undefined __no_sanitize_thread
#define nsa NoSecurityAnalysis

View File

@ -17,7 +17,7 @@
#include "kernel.h"
#include <filesystem/ustar.hpp>
#include <fs/ustar.hpp>
#include <memory.hpp>
#include <convert.h>
#include <ints.hpp>

View File

@ -22,7 +22,7 @@
#include <boot/binfo.h>
#ifdef __cplusplus
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include <display.hpp>
#include <symbols.hpp>
#include <kconfig.hpp>

View File

@ -20,7 +20,7 @@
#include "tests/t.h"
#endif
#include <filesystem/ustar.hpp>
#include <fs/ustar.hpp>
#include <subsystems.hpp>
#include <kshell.hpp>
#include <power.hpp>
@ -70,11 +70,11 @@ int SpawnLinuxInit()
"/startup/init"};
const char *foundPath = nullptr;
FileNode *root = fs->GetRoot(1);
Node root = fs->GetRoot(1);
for (const std::string &path : fallbackPaths)
{
const char *str = path.c_str();
if (!fs->PathExists(str, root))
if (fs->Lookup(root, str) == false)
continue;
foundPath = str;
break;
@ -123,8 +123,6 @@ void KernelMainThread()
KPrint("Initializing Driver Manager");
DriverManager = new Driver::Manager;
TaskManager->CreateThread(thisProcess, Tasking::IP(Driver::ManagerDaemonWrapper))
->Rename("Device Service");
KPrint("Loading Drivers");
DriverManager->PreloadDrivers();

View File

@ -17,7 +17,7 @@
#include "kernel.h"
#include <filesystem/ustar.hpp>
#include <fs/ustar.hpp>
#include <memory.hpp>
vfs::Virtual *fs = nullptr;

View File

@ -17,7 +17,7 @@
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include "../../kernel.h"
@ -28,7 +28,7 @@ void cmd_cat(const char *args)
if (args[0] == '\0')
return;
FileNode *node = fs->GetByPath(args, nullptr);
Node node = fs->Lookup(thisProcess->CWD, args);
if (node == nullptr)
{
@ -48,11 +48,11 @@ void cmd_cat(const char *args)
return;
}
kstat stat = {};
node->Stat(&stat);
kstat stat;
fs->Stat(node, &stat);
uint8_t *buffer = new uint8_t[stat.Size + 1];
ssize_t rBytes = node->Read(buffer, stat.Size, 0);
ssize_t rBytes = fs->Read(node, buffer, stat.Size, 0);
if (rBytes > 0)
printf("%s\n", buffer);
else

View File

@ -17,7 +17,7 @@
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include "../../kernel.h"
@ -28,8 +28,7 @@ void cmd_cd(const char *args)
if (args[0] == '\0')
return;
FileNode *node = fs->GetByPath(args, nullptr);
Node node = fs->Lookup(thisProcess->CWD, args);
if (node == nullptr)
{
printf("cd: %s: No such file or directory\n", args);
@ -43,4 +42,5 @@ void cmd_cd(const char *args)
}
thisProcess->CWD = node;
debug("changed cwd to %s", node->Path.c_str());
}

View File

@ -17,7 +17,7 @@
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include <acpi.hpp>
#include "../../kernel.h"
@ -38,9 +38,41 @@ void cmd_dump(const char *args)
*strLen = '\0';
strLen++;
void *Address = (void *)strtoul(strAddr, nullptr, 16);
void *Address;
unsigned long Length = strtoul(strLen, nullptr, 10);
Node root = fs->GetRoot(0);
Node fileNode = fs->Lookup(root, strAddr);
if (fileNode && !fileNode->IsDirectory() && !fileNode->IsFIFO() && !fileNode->IsSocket())
{
kstat stat;
int status = fs->Stat(fileNode, &stat);
if (status != 0)
{
printf("cannot get stat: %s\n", strerror(status));
return;
}
size_t size = stat.Size > (off_t)Length ? Length : stat.Size;
Address = new char[size]; /* FIXME: memory leak */
size_t read = fs->Read(fileNode, Address, size, 0);
if (read < Length)
{
debug("clamp %lu to %lu", Length, read);
Length = read;
}
}
else
{
if (fileNode)
{
printf("file %s cannot be dumped\n", strAddr);
return;
}
Address = (void *)strtoul(strAddr, nullptr, 16);
debug("address %s", strAddr);
}
{
unsigned char *AddressChar = (unsigned char *)Address;
unsigned char Buffer[17];
@ -74,4 +106,4 @@ void cmd_dump(const char *args)
}
putchar('\n');
}
}
}

View File

@ -17,7 +17,7 @@
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include <task.hpp>
#include "../../kernel.h"

View File

@ -17,7 +17,7 @@
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include <task.hpp>
#include "../../kernel.h"

View File

@ -17,7 +17,7 @@
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include <task.hpp>
#include "../../kernel.h"

View File

@ -17,98 +17,60 @@
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include "../../kernel.h"
using namespace vfs;
const char *ColorNodeType(FileNode *node)
const char *ColorNodeType(Node node)
{
if (node->IsRegularFile())
return "\x1b[32m";
return "\x1b[0m";
else if (node->IsDirectory())
return "\x1b[34m";
return "\x1b[1;34m";
else if (node->IsBlockDevice())
return "\x1b[33m";
return "\x1b[1;33m";
else if (node->IsCharacterDevice())
return "\x1b[33m";
return "\x1b[1;33m";
else if (node->IsFIFO())
return "\x1b[33m";
return "\x1b[0;33m";
else if (node->IsSymbolicLink())
return "\x1b[35m";
return "\x1b[1;36m";
else
return "\x1b[0m";
}
__no_sanitize("alignment") size_t MaxNameLength(FileNode *nodes)
__no_sanitize("alignment") void PrintLS(Node node)
{
size_t maxLength = 0;
kdirent *dirBuffer = new kdirent[16];
ssize_t read = 0;
off_t offset = 0;
while ((read = nodes->ReadDir(dirBuffer, sizeof(kdirent) * 16, offset, LONG_MAX)) > 0)
{
if (read / sizeof(kdirent) == 0)
break;
off_t bufOffset = 0;
debug("There are %ld entries in this directory", read / sizeof(kdirent));
for (size_t i = 0; i < read / sizeof(kdirent); i++)
{
kdirent *dirent = (kdirent *)((uintptr_t)dirBuffer + bufOffset);
if (dirent->d_reclen == 0)
break;
bufOffset += dirent->d_reclen;
maxLength = std::max(maxLength, strlen(dirent->d_name));
debug("dirent->d_name: %s (max length: %ld)", dirent->d_name, maxLength);
}
offset += read / sizeof(kdirent);
}
delete[] dirBuffer;
return maxLength;
}
__no_sanitize("alignment") void PrintLS(FileNode *node)
{
size_t maxNameLength = MaxNameLength(node);
size_t maxNameLength = 0;
int count = 0;
bool first = true;
kdirent *dirBuffer = new kdirent[16];
ssize_t read = 0;
off_t offset = 0;
while ((read = node->ReadDir(dirBuffer, sizeof(kdirent) * 16, offset, LONG_MAX)) > 0)
{
if (read / sizeof(kdirent) == 0)
break;
std::list<Node> children = fs->ReadDirectory(node);
off_t bufOffset = 0;
for (size_t i = 0; i < read / sizeof(kdirent); i++)
{
if (count % 5 == 0 && !first)
printf("\n");
kdirent *dirent = (kdirent *)((uintptr_t)dirBuffer + bufOffset);
if (dirent->d_reclen == 0)
break;
bufOffset += dirent->d_reclen;
printf(" %s%-*s ", ColorNodeType(node), (int)maxNameLength, dirent->d_name);
count++;
first = false;
}
offset += read / sizeof(kdirent);
for (auto &&i : children)
std::max(maxNameLength, i->Name.length());
for (auto &&i : children)
{
if (count % 5 == 0 && !first)
printf("\n");
printf(" %s%-*s ", ColorNodeType(i), (int)maxNameLength, i->Name.c_str());
count++;
first = false;
}
printf("\x1b[0m\n");
delete[] dirBuffer;
}
void cmd_ls(const char *args)
{
if (args[0] == '\0')
{
FileNode *rootNode = thisProcess->CWD;
Node rootNode = thisProcess->CWD;
if (rootNode == nullptr)
rootNode = fs->GetRoot(0);
@ -117,7 +79,7 @@ void cmd_ls(const char *args)
return;
}
FileNode *thisNode = fs->GetByPath(args, nullptr);
Node thisNode = fs->Lookup(thisProcess->CWD, args);
if (thisNode == nullptr)
{

View File

@ -17,7 +17,7 @@
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include <acpi.hpp>
#include "../../kernel.h"

View File

@ -17,7 +17,7 @@
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include "../../kernel.h"

View File

@ -17,7 +17,7 @@
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include <task.hpp>
#include "../../kernel.h"

View File

@ -17,7 +17,7 @@
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include "../../kernel.h"

View File

@ -17,7 +17,7 @@
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include <task.hpp>
#include "../../kernel.h"

View File

@ -17,7 +17,7 @@
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include <task.hpp>
#include "../../kernel.h"

View File

@ -17,7 +17,7 @@
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include <task.hpp>
#include "../../kernel.h"

View File

@ -17,7 +17,7 @@
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include <task.hpp>
#include "../../kernel.h"

View File

@ -17,70 +17,38 @@
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include "../../kernel.h"
void tree_loop(FileNode *rootNode, int depth = 0)
// Enhancing the tree_loop function to display a fancier tree structure
__no_sanitize("alignment") void tree_loop(Node rootNode, int depth = 0, std::string prefix = "")
{
// for (auto Child : rootNode->GetChildren(true))
// {
// Display->UpdateBuffer();
// if (Child->Stat.IsType(DIRECTORY) || Child->Stat.IsType(MOUNTPOINT))
// {
// printf("%*s%*s%*s|- %s\n",
// depth, "",
// depth, "",
// depth, "",
// Child->FileName);
// tree_loop(Child, depth + 1);
// }
// else
// printf("%*s%*s%*s|- %s\n",
// depth, "",
// depth, "",
// depth, "",
// Child->FileName);
// }
std::list<Node> children = fs->ReadDirectory(rootNode);
size_t count = children.size();
size_t index = 0;
kdirent *dirBuffer = new kdirent[16];
ssize_t read = 0;
off_t offset = 0;
while ((read = rootNode->ReadDir(dirBuffer, sizeof(kdirent) * 16, offset, LONG_MAX)) > 0)
{
if (read / sizeof(kdirent) == 0)
break;
for (auto &&child : children)
{
if (child->Name == "." || child->Name == "..")
continue;
off_t bufOffset = 0;
for (size_t i = 0; i < read / sizeof(kdirent); i++)
{
kdirent *dirent = (kdirent *)((uintptr_t)dirBuffer + bufOffset);
if (dirent->d_reclen == 0)
break;
bufOffset += dirent->d_reclen;
bool isLast = (++index == count);
if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0)
continue;
printf("%s%s- %s\n", prefix.c_str(), isLast ? "\\" : "|-", child->Name.c_str());
FileNode *node = fs->GetByPath(dirent->d_name, rootNode);
if (node == nullptr)
continue;
for (int i = 0; i < depth; i++)
printf(" ");
printf("|- %s\n", dirent->d_name);
if (node->IsDirectory())
tree_loop(node, depth + 1);
}
offset += read;
}
delete[] dirBuffer;
if (child->IsDirectory())
{
std::string newPrefix = prefix + (isLast ? " " : "| ");
tree_loop(child, depth + 1, newPrefix);
}
}
}
void cmd_tree(const char *args)
{
FileNode *rootNode = thisProcess->CWD;
Node rootNode = thisProcess->CWD;
if (args[0] == '\0')
{
if (rootNode == nullptr)
@ -88,7 +56,7 @@ void cmd_tree(const char *args)
}
else
{
rootNode = fs->GetByPath(args, nullptr);
rootNode = fs->Lookup(thisProcess->CWD, args);
if (rootNode == nullptr)
{
printf("ls: %s: No such file or directory\n", args);

View File

@ -17,7 +17,7 @@
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include "../../kernel.h"

View File

@ -17,7 +17,7 @@
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include "../../kernel.h"

View File

@ -17,7 +17,7 @@
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include "../../kernel.h"

View File

@ -19,7 +19,7 @@
#include <interface/driver.h>
#include <interface/input.h>
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include <driver.hpp>
#include <lock.hpp>
#include <exec.hpp>
@ -88,6 +88,7 @@ void KShellThread()
KPrint("Starting kernel shell...");
thisThread->SetPriority(Tasking::TaskPriority::Normal);
thisProcess->CWD = fs->GetRoot(0);
std::string strBuf = "";
std::vector<std::string *> history;
@ -97,7 +98,8 @@ void KShellThread()
bool tabDblPress = false;
const char *keyDevPath = "/dev/input/keyboard";
FileNode *kfd = fs->GetByPath(keyDevPath, fs->GetRoot(0));
Node root = fs->GetRoot(0);
Node kfd = fs->Lookup(root, keyDevPath);
if (kfd == nullptr)
{
KPrint("Failed to open keyboard device!");
@ -125,21 +127,20 @@ void KShellThread()
debug("clearing strBuf(\"%s\")", strBuf.c_str());
strBuf.clear();
FileNode *cwd = thisProcess->CWD;
Node cwd = thisProcess->CWD;
if (!cwd)
cwd = fs->GetRoot(0);
std::string cwdStr = fs->GetByNode(cwd);
debug("cwd: %*s", (int)cwdStr.size(), cwdStr.c_str());
debug("cwd: %s", cwd->Path.c_str());
printf("\x1b[1;34m%s@%s:%s$ \x1b[0m",
"kernel", "fennix",
cwdStr.c_str());
cwd->Path.c_str());
KeyboardReport scBuf{};
ssize_t nBytes;
while (true)
{
nBytes = kfd->Read(&scBuf, sizeof(KeyboardReport), 0);
nBytes = fs->Read(kfd, &scBuf, sizeof(KeyboardReport), 0);
if (nBytes == 0)
{
debug("Empty read from keyboard device!");
@ -561,14 +562,14 @@ void KShellThread()
if (fs->PathIsRelative(cmd_only.c_str()))
{
path += cmd_only;
if (!fs->PathExists(path.c_str(), nullptr))
if (!fs->Lookup(root, path.c_str()))
path = "/usr/bin/" + cmd_only;
}
else
path = cmd_only;
debug("path: %s", path.c_str());
if (fs->PathExists(path.c_str(), nullptr))
if (fs->Lookup(root, path.c_str()))
{
const char *envp[5] = {
"PATH=/bin:/usr/bin",

View File

@ -158,11 +158,9 @@ void terminate_header_stub()
CPU::Stop(); /* FIXME: Panic */
}
void exception_cleanup_stub(_Unwind_Reason_Code Code,
_Unwind_Exception *Exception)
void exception_cleanup_stub(_Unwind_Reason_Code Code, _Unwind_Exception *Exception)
{
fixme("exception_cleanup( %d %p ) called.",
Code, Exception);
fixme("exception_cleanup( %d %p ) called.", Code, Exception);
}
extern "C" void *__cxa_allocate_exception(size_t thrown_size) throw()
@ -175,12 +173,10 @@ extern "C" void *__cxa_allocate_exception(size_t thrown_size) throw()
return Exception + 1;
}
extern "C" __noreturn void __cxa_throw(void *thrown_object,
std::type_info *tinfo,
void (*dest)(void *))
extern "C" __noreturn void __cxa_throw(void *thrown_object, void *tinfo, void (*dest)(void *))
{
trace("Throwing exception of type \"%s\". ( object: %p, destructor: %p )",
tinfo->name(), thrown_object, dest);
((std::type_info *)tinfo)->name(), thrown_object, dest);
__cxa_eh_globals *Globals = __cxa_get_globals();
Globals->uncaughtExceptions++;
@ -218,10 +214,9 @@ extern "C" void __cxa_throw_bad_array_new_length()
fixme("__cxa_throw_bad_array_new_length() called.");
}
extern "C" void __cxa_free_exception(void *thrown_exception)
extern "C" void __cxa_free_exception(void *thrown_exception) throw()
{
fixme("__cxa_free_exception( %p ) called.",
thrown_exception);
fixme("__cxa_free_exception( %p ) called.", thrown_exception);
}
__extension__ typedef int __guard __attribute__((mode(__DI__)));

View File

@ -1,227 +0,0 @@
/*
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 <rand.hpp>
#include <cwalk.h>
#include "../kernel.h"
namespace vfs
{
FileNode *Virtual::CacheSearchReturnLast(FileNode *Parent, const char **Path)
{
assert(Parent != nullptr);
struct cwk_segment segment;
if (!cwk_path_get_first_segment(*Path, &segment))
{
if (strcmp(*Path, Parent->fsi->RootName) == 0)
return Parent;
ReturnLogError(nullptr, "Failed to get first segment of path");
}
size_t segments = 0;
while (cwk_path_get_next_segment(&segment))
segments++;
if (segments == 0)
return Parent;
const char *tmpPath = *Path;
if (strncmp(tmpPath, "\x06root-", 6) == 0) /* FIXME: deduce the index */
{
tmpPath += 6;
while (*tmpPath != '\0' && *tmpPath != '\x06')
tmpPath++;
if (*tmpPath == '\x06')
tmpPath++;
}
else
tmpPath = *Path;
FileNode *__Parent = Parent;
if (this->PathIsAbsolute(tmpPath))
{
while (__Parent->Parent)
__Parent = __Parent->Parent;
}
cwk_path_get_first_segment(tmpPath, &segment);
do
{
std::string segmentName(segment.begin, segment.size);
bool found = false;
for (FileNode *fn : __Parent->Children)
{
if (fn->Name != segmentName)
continue;
cwk_segment __seg = segment;
assert(cwk_path_get_next_segment(&__seg)); /* There's something wrong */
__Parent = fn;
found = true;
break;
}
if (!found)
{
*Path = segment.begin;
break;
}
} while (cwk_path_get_next_segment(&segment));
return __Parent;
}
FileNode *Virtual::CacheRecursiveSearch(FileNode *Root, const char *NameOrPath, bool IsName)
{
if (Root == nullptr)
return nullptr;
debug("%s cache search for \"%s\" in \"%s\"",
IsName ? "Relative" : "Absolute",
NameOrPath,
Root->Path.c_str());
struct cwk_segment segment;
if (!cwk_path_get_first_segment(NameOrPath, &segment))
{
if (strcmp(NameOrPath, Root->fsi->RootName) == 0)
return Root;
ReturnLogError(nullptr, "Failed to get first segment of path");
}
size_t segments = 0;
while (cwk_path_get_next_segment(&segment))
segments++;
if (IsName && segments == 0)
{
for (FileNode *fn : Root->Children)
{
if (fn->Name == NameOrPath)
return fn;
}
ReturnLogError(nullptr, "Failed to find \"%s\" in \"%s\"", NameOrPath, Root->Path.c_str());
}
const char *path = NameOrPath;
if (strncmp(path, "\x06root-", 6) == 0) /* FIXME: deduce the index */
{
path += 6;
while (*path != '\0' && *path != '\x06')
path++;
if (*path == '\x06')
path++;
}
else
path = NameOrPath;
FileNode *__Parent = Root;
if (this->PathIsAbsolute(path))
{
/* Get the root if Root is not the root 【・_・?】 */
while (__Parent->Parent)
__Parent = __Parent->Parent;
}
cwk_path_get_first_segment(path, &segment);
do
{
std::string segmentName(segment.begin, segment.size);
bool found = false;
for (FileNode *fn : __Parent->Children)
{
if (fn->Name != segmentName)
continue;
cwk_segment __seg = segment;
if (!cwk_path_get_next_segment(&__seg))
return fn;
__Parent = fn;
found = true;
break;
}
if (!found)
break;
} while (cwk_path_get_next_segment(&segment));
debug("Failed to find \"%s\" in \"%s\"", NameOrPath, Root->Path.c_str());
return nullptr;
}
FileNode *Virtual::CacheLookup(FileNode *Parent, const char *Path)
{
debug("Cache lookup for \"%s\"", Path);
if (Parent == nullptr)
Parent = thisProcess ? thisProcess->Info.RootNode : this->GetRoot(0);
FileNode *ret = CacheRecursiveSearch(Parent, Path, false);
if (ret)
return ret;
debug("Path \"%s\" not found", Path);
return nullptr;
}
FileNode *Virtual::CreateCacheNode(FileNode *Parent, Inode *Node, const char *Name, mode_t Mode)
{
FileNode *fn = new FileNode;
fn->Name = Name;
if (Parent)
{
fn->Path = Parent->Path + "/" + Name;
Parent->Children.push_back(fn);
}
else
fn->Path = Name;
fn->Parent = Parent;
fn->Node = Node;
fn->fsi = DeviceMap[Node->Device].fsi;
if (fn->fsi == nullptr)
warn("Failed to find filesystem for device %d", Node->Device);
debug("Created cache node %s", fn->Path.c_str());
return fn;
}
int Virtual::RemoveCacheNode(FileNode *Node)
{
if (Node == nullptr)
return -EINVAL;
if (Node->Parent)
{
Node->Parent->Children.erase(std::find(Node->Parent->Children.begin(), Node->Parent->Children.end(), Node));
// delete Node;
fixme("Node deletion is disabled for now (for debugging purposes)");
}
return 0;
}
}

View File

@ -1,390 +0,0 @@
/*
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 <rand.hpp>
#include <cwalk.h>
#include "../kernel.h"
namespace vfs
{
bool Virtual::PathIsRelative(const char *Path)
{
return cwk_path_is_relative(Path);
}
void Virtual::AddRoot(Inode *Root)
{
SmartLock(VirtualLock);
FileSystemRoots->Children.push_back(Root);
}
void Virtual::AddRootAt(Inode *Root, size_t Index)
{
SmartLock(VirtualLock);
if (Index >= FileSystemRoots->Children.size())
FileSystemRoots->Children.resize(Index + 1);
if (FileSystemRoots->Children[Index] == nullptr)
FileSystemRoots->Children[Index] = Root;
else
{
debug("Root %ld already exists", Index);
}
}
bool Virtual::SetRootAt(Inode *Root, size_t Index)
{
SmartLock(VirtualLock);
assert(Index < FileSystemRoots->Children.size());
if (FileSystemRoots->Children[Index] != nullptr)
{
debug("Root %ld already exists", Index);
return false;
}
FileSystemRoots->Children[Index] = Root;
return true;
}
void Virtual::RemoveRoot(Inode *Root)
{
SmartLock(VirtualLock);
for (size_t i = 0; i < FileSystemRoots->Children.size(); i++)
{
if (FileSystemRoots->Children[i] != Root)
continue;
FileSystemRoots->Children[i] = nullptr;
break;
}
debug("removed root %p", Root);
}
FileNode *Virtual::GetRoot(size_t Index)
{
assert(Index < FileSystemRoots->Children.size());
auto it = FileRoots.find(Index);
if (it != FileRoots.end())
return it->second;
Inode *rootNode = FileSystemRoots->Children[Index];
assert(rootNode != nullptr);
char rootName[128]{};
snprintf(rootName, sizeof(rootName), "\x06root-%ld\x06", Index);
FileNode *ret = this->CreateCacheNode(nullptr, rootNode, rootName, 0);
FileRoots.insert({Index, ret});
return ret;
}
bool Virtual::RootExists(size_t Index)
{
if (Index >= FileSystemRoots->Children.size())
return false;
return FileSystemRoots->Children[Index] != nullptr;
}
FileNode *Virtual::Create(FileNode *Parent, const char *Name, mode_t Mode)
{
FileNode *existingNode = this->GetByPath(Name, Parent);
if (existingNode != nullptr)
ReturnLogError(existingNode, "File %s already exists", Name);
if (Parent == nullptr)
{
assert(thisProcess != nullptr);
Parent = thisProcess->Info.RootNode;
}
auto it = DeviceMap.find(Parent->Node->Device);
if (it == DeviceMap.end())
ReturnLogError(nullptr, "Device %d not found", Parent->Node->Device);
Inode *Node = NULL;
if (it->second.fsi->Ops.Create == NULL)
ReturnLogError(nullptr, "Create not supported for %d", it->first);
int ret = it->second.fsi->Ops.Create(Parent->Node, Name, Mode, &Node);
if (ret < 0)
ReturnLogError(nullptr, "Create for %d failed with %d", it->first, ret);
return this->CreateCacheNode(Parent, Node, Name, Mode);
}
FileNode *Virtual::ForceCreate(FileNode *Parent, const char *Name, mode_t Mode)
{
fixme("ForceCreate: %s", Name);
return this->Create(Parent, Name, Mode);
}
FileNode *Virtual::Mount(FileNode *Parent, Inode *Node, const char *Path)
{
char *path = strdup(Path);
char *lastSlash = strrchr(path, '/');
if (lastSlash)
{
if (lastSlash == path)
lastSlash++;
*lastSlash = '\0';
}
FileNode *parentNode = this->GetByPath(path, Parent);
if (parentNode == nullptr && Parent != nullptr)
parentNode = Parent;
free(path);
lastSlash = strrchr(Path, '/');
if (lastSlash)
lastSlash++;
else
lastSlash = (char *)Path;
return this->CreateCacheNode(parentNode, Node, lastSlash, Node->Mode);
}
int Virtual::Unmount(const char *Path)
{
FileNode *node = this->GetByPath(Path, nullptr);
if (node == nullptr)
ReturnLogError(-ENOENT, "Path %s not found", Path);
return this->RemoveCacheNode(node);
}
FileNode *Virtual::GetByPath(const char *Path, FileNode *Parent)
{
debug("GetByPath: %s", Path);
if (Parent == nullptr)
{
if (fs->PathIsRelative(Path))
Parent = thisProcess ? thisProcess->CWD : thisProcess->Info.RootNode;
else
Parent = thisProcess ? thisProcess->Info.RootNode : this->GetRoot(0);
}
if (strcmp(Path, ".") == 0)
return Parent;
if (strcmp(Path, "..") == 0)
return Parent->Parent ? Parent->Parent : Parent;
FileNode *fn = this->CacheRecursiveSearch(Parent, Path, this->PathIsRelative(Path));
if (fn)
return fn;
if (strncmp(Path, "\x06root-", 6) == 0) /* FIXME: deduce the index */
{
Path += 7;
while (*Path != '\0' && *Path != '\x06')
Path++;
if (*Path == '\x06')
Path++;
}
FileNode *__Parent = CacheSearchReturnLast(Parent, &Path);
struct cwk_segment segment;
if (!cwk_path_get_first_segment(Path, &segment))
{
auto it = DeviceMap.find(Parent->Node->Device);
if (unlikely(it == DeviceMap.end()))
ReturnLogError(nullptr, "Device %d not found", Parent->Node->Device);
if (it->second.fsi->Ops.Lookup == NULL)
ReturnLogError(nullptr, "Lookup not supported for %d", it->first);
Inode *Node = NULL;
int ret = it->second.fsi->Ops.Lookup(Parent->Node, Path, &Node);
if (ret < 0)
ReturnLogError(nullptr, "Lookup for \"%s\"(%d) failed with %d", Path, it->first, ret);
if (Parent->Node == Node) /* root / */
{
debug("Returning root (%#lx)", Node);
return Parent;
}
ReturnLogError(nullptr, "Path has no segments");
}
Inode *Node = NULL;
bool readSymlinks = true; /* FIXME: implement */
do
{
auto it = DeviceMap.find(__Parent->Node->Device);
if (unlikely(it == DeviceMap.end()))
ReturnLogError(nullptr, "Device %d not found", __Parent->Node->Device);
debug("found fs %s", it->second.fsi->Name);
if (it->second.fsi->Ops.Lookup == NULL)
ReturnLogError(nullptr, "Lookup not supported for %d", it->first);
if (readSymlinks && __Parent->IsSymbolicLink())
{
if (it->second.fsi->Ops.ReadLink == NULL)
ReturnLogError(nullptr, "Readlink not supported for %d", it->first);
char buffer[256];
int ret = it->second.fsi->Ops.ReadLink(__Parent->Node, buffer, sizeof(buffer));
if (ret < 0)
ReturnLogError(nullptr, "Readlink for \"%s\"(%d) failed with %d", __Parent->Path.c_str(), it->first, ret);
FileNode *target = this->GetByPath(buffer, __Parent->Parent ? __Parent->Parent : __Parent);
if (target == nullptr)
ReturnLogError(nullptr, "Failed to find target for \"%s\"", __Parent->Path.c_str());
__Parent = target;
}
std::string segmentName(segment.begin, segment.size);
int ret = it->second.fsi->Ops.Lookup(__Parent->Node, segmentName.c_str(), &Node);
if (ret < 0)
ReturnLogError(nullptr, "Lookup for \"%s\"(%d) failed with %d", segmentName.c_str(), it->first, ret);
__Parent = this->CreateCacheNode(__Parent, Node, segmentName.c_str(), 0);
} while (cwk_path_get_next_segment(&segment));
FileNode *ret = __Parent;
if (!ret->IsDirectory())
return ret;
auto it = DeviceMap.find(__Parent->Node->Device);
if (unlikely(it == DeviceMap.end()))
ReturnLogError(nullptr, "Device %d not found", __Parent->Node->Device);
size_t dirAllocLen = sizeof(struct kdirent) + strlen(Path);
struct kdirent *dirent = (struct kdirent *)malloc(dirAllocLen);
size_t offset = 2; /* Skip . and .. */
while (it->second.fsi->Ops.ReadDir(Node, dirent, dirAllocLen, offset++, 1) > 0)
{
Inode *ChildNode = NULL;
int luRet = it->second.fsi->Ops.Lookup(Node, dirent->d_name, &ChildNode);
if (luRet < 0)
{
debug("Lookup for %d failed with %d", it->first, luRet);
break;
}
this->CreateCacheNode(ret, ChildNode, dirent->d_name, 0);
}
free(dirent);
return ret;
}
std::string Virtual::GetByNode(FileNode *Node)
{
assert(Node != nullptr);
if (Node->Parent == nullptr)
{
if (Node->Node->Flags & I_FLAG_ROOT)
return Node->fsi->RootName;
assert(Node->Parent != nullptr);
}
std::string path;
auto appendPath = [&path](const char *name)
{
if (path.size() > 0)
path += "/";
path += name;
};
FileNode *current = Node;
while (current->Parent != nullptr)
{
appendPath(current->Name.c_str());
current = current->Parent;
}
return path;
}
FileNode *Virtual::CreateLink(const char *Path, FileNode *Parent, const char *Target)
{
auto it = DeviceMap.find(Parent->Node->Device);
if (it == DeviceMap.end())
ReturnLogError(nullptr, "Device %d not found", Parent->Node->Device);
Inode *Node = NULL;
if (it->second.fsi->Ops.SymLink == NULL)
ReturnLogError(nullptr, "SymLink not supported for %d", it->first);
int ret = it->second.fsi->Ops.SymLink(Parent->Node, Path, Target, &Node);
if (ret < 0)
ReturnLogError(nullptr, "SymLink for %d failed with %d", it->first, ret);
return this->CreateCacheNode(Parent, Node, Path, 0);
}
FileNode *Virtual::CreateLink(const char *Path, FileNode *Parent, FileNode *Target)
{
return this->CreateLink(Path, Parent, Target->Path.c_str());
}
bool Virtual::PathExists(const char *Path, FileNode *Parent)
{
FileNode *fn = this->CacheLookup(Parent, Path);
if (fn)
return true;
FileNode *Node = this->GetByPath(Path, Parent);
if (Node)
return true;
return false;
}
int Virtual::Remove(FileNode *Node)
{
auto it = DeviceMap.find(Node->Node->Device);
if (it == DeviceMap.end())
ReturnLogError(-ENODEV, "Device %d not found", Node->Node->Device);
if (it->second.fsi->Ops.Remove == NULL)
ReturnLogError(-ENOTSUP, "Remove not supported for %d", it->first);
int ret = it->second.fsi->Ops.Remove(Node->Parent->Node, Node->Name.c_str());
if (ret < 0)
ReturnLogError(ret, "Remove for %d failed with %d", it->first, ret);
this->RemoveCacheNode(Node);
return 0;
}
}
std::string FileNode::GetName()
{
return this->Name;
}
std::string FileNode::GetPath()
{
const char *path = this->Path.c_str();
if (strncmp(path, "\x06root-", 6) == 0) /* FIXME: deduce the index */
{
path += 6;
while (*path != '\0' && *path != '\x06')
path++;
if (*path == '\x06')
path++;
}
else
return this->Path;
if (path[0] == '\0')
return std::string(this->fsi->RootName);
return std::string(path);
}

View File

@ -1,257 +0,0 @@
/*
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;
for (const auto &Root : 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()
{
}
}

View File

@ -15,45 +15,88 @@
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <filesystem/ramfs.hpp>
#include <fs/ramfs.hpp>
#include "../../kernel.h"
#include <fs/ustar.hpp>
#include <ini.h>
namespace Subsystem::Linux
{
bool Initialized = false;
void __CreateStubRoot()
{
Node root = fs->GetRoot(0);
Node nmnt = fs->Lookup(root, "/mnt");
assert(MountAndRootRAMFS(nmnt, "linux", 1));
Node linux = fs->GetRoot(1);
Node bin = fs->Create(linux, "bin", 0755);
Node boot = fs->Create(linux, "boot", 0755);
Node dev = fs->Create(linux, "dev", 0755);
Node etc = fs->Create(linux, "etc", 0755);
Node home = fs->Create(linux, "home", 0755);
Node lib = fs->Create(linux, "lib", 0755);
Node lib64 = fs->Create(linux, "lib64", 0755);
Node media = fs->Create(linux, "media", 0755);
Node mnt = fs->Create(linux, "mnt", 0755);
Node opt = fs->Create(linux, "opt", 0755);
Node proc = fs->Create(linux, "proc", 0755);
UNUSED(bin);
UNUSED(boot);
UNUSED(dev);
UNUSED(etc);
UNUSED(home);
UNUSED(lib);
UNUSED(lib64);
UNUSED(media);
UNUSED(mnt);
UNUSED(opt);
UNUSED(proc);
}
void InitializeSubSystem()
{
if (fs->RootExists(1) == false)
{
FileNode *nmnt = fs->GetByPath("/mnt", fs->GetRoot(0));
assert(MountRAMFS(nmnt, "linux", 1));
FileNode *linux = fs->GetRoot(1);
Node root = fs->GetRoot(0);
Node cfg = fs->Lookup(root, "/sys/cfg/subsystem/linux");
if (cfg)
{
struct kstat st;
fs->Stat(cfg, &st);
FileNode *bin = fs->ForceCreate(linux, "bin", 0755);
FileNode *boot = fs->ForceCreate(linux, "boot", 0755);
FileNode *dev = fs->ForceCreate(linux, "dev", 0755);
FileNode *etc = fs->ForceCreate(linux, "etc", 0755);
FileNode *home = fs->ForceCreate(linux, "home", 0755);
FileNode *lib = fs->ForceCreate(linux, "lib", 0755);
FileNode *lib64 = fs->ForceCreate(linux, "lib64", 0755);
FileNode *media = fs->ForceCreate(linux, "media", 0755);
FileNode *mnt = fs->ForceCreate(linux, "mnt", 0755);
FileNode *opt = fs->ForceCreate(linux, "opt", 0755);
FileNode *proc = fs->ForceCreate(linux, "proc", 0755);
std::unique_ptr<char[]> buf(new char[st.Size]);
fs->Read(cfg, buf.get(), st.Size, 0);
UNUSED(bin);
UNUSED(boot);
UNUSED(dev);
UNUSED(etc);
UNUSED(home);
UNUSED(lib);
UNUSED(lib64);
UNUSED(media);
UNUSED(mnt);
UNUSED(opt);
UNUSED(proc);
ini_t *ini = ini_load(buf.get(), NULL);
int section = ini_find_section(ini, "rootfs", NULL);
int pathIdx = ini_find_property(ini, section, "path", NULL);
const char *uPath = ini_property_value(ini, section, pathIdx);
debug("path=%s", uPath);
ini_destroy(ini);
if (fs->Lookup(root, uPath) != false)
{
root = fs->Lookup(root, uPath);
// if (TestAndInitializeUSTAR(moduleAddress, moduleSize, 0))
// {
// }
}
else
{
warn("Couldn't find rootfs path %s", uPath);
__CreateStubRoot();
}
}
else
{
warn("Couldn't open /sys/cfg/subsystem/linux");
__CreateStubRoot();
}
}
}
}

View File

@ -816,7 +816,7 @@ static int linux_open(SysFrm *sf, const char *pathname, int flags, mode_t mode)
if (flags & 0200000 /* O_DIRECTORY */)
{
FileNode *node = fs->GetByPath(pPathname, pcb->CWD);
Node node = fs->Lookup(pcb->CWD, pPathname);
if (node == nullptr)
{
debug("Couldn't find %s", pPathname);
@ -1313,7 +1313,7 @@ static int linux_access(SysFrm *, const char *pathname, int mode)
debug("access(%s, %d)", (char *)pPathname, mode);
if (!fs->PathExists(pPathname, pcb->CWD))
if (!fs->Lookup(pcb->CWD, pPathname))
return -linux_ENOENT;
stub;
@ -1717,7 +1717,7 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn
safeEnvp[i + 1] = nullptr;
}
FileNode *file = fs->GetByPath(pPathname, pcb->CWD);
Node file = fs->Lookup(pcb->CWD, pPathname);
if (!file)
{
@ -1726,7 +1726,7 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn
}
char shebangMagic[2]{};
file->Read((uint8_t *)shebangMagic, 2, 0);
fs->Read(file, (uint8_t *)shebangMagic, 2, 0);
if (shebangMagic[0] == '#' && shebangMagic[1] == '!')
{
@ -1740,7 +1740,7 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn
while (true)
{
char c;
if (file->Read((uint8_t *)&c, 1, shebangOffset) == 0)
if (fs->Read(file, (uint8_t *)&c, 1, shebangOffset) == 0)
break;
if (c == '\n' || shebangLength == shebangLengthMax)
break;
@ -1870,7 +1870,7 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn
cwk_path_get_basename(pPathname, &baseName, nullptr);
pcb->Rename(baseName);
pcb->SetWorkingDirectory(file->Parent);
pcb->SetWorkingDirectory(fs->Convert(file->Parent));
pcb->SetExe(pPathname);
Tasking::Task *ctx = pcb->GetContext();
@ -2208,14 +2208,15 @@ static int linux_uname(SysFrm *, struct utsname *buf)
#endif
};
FileNode *rn = fs->GetByPath("/sys/cfg/cross/linux", pcb->Info.RootNode);
Node root = fs->GetRoot(0);
Node rn = fs->Lookup(root, "/sys/cfg/subsystem/linux");
if (rn)
{
struct kstat st{};
rn->Stat(&st);
struct kstat st;
fs->Stat(rn, &st);
char *sh = new char[st.Size];
rn->Read(sh, st.Size, 0);
fs->Read(rn, sh, st.Size, 0);
ini_t *ini = ini_load(sh, NULL);
int section = ini_find_section(ini, "uname", NULL);
@ -2250,7 +2251,7 @@ static int linux_uname(SysFrm *, struct utsname *buf)
delete[] sh;
}
else
warn("Couldn't open /sys/cfg/cross/linux");
warn("Couldn't open /sys/cfg/subsystem/linux");
memcpy(pBuf, &uname, sizeof(struct utsname));
return 0;
@ -2360,7 +2361,7 @@ static int linux_chdir(SysFrm *, const char *path)
if (!pPath)
return -linux_EFAULT;
FileNode *n = fs->GetByPath(pPath, pcb->CWD);
Node n = fs->Lookup(pcb->CWD, pPath);
if (!n)
return -linux_ENOENT;
@ -2378,8 +2379,8 @@ static int linux_fchdir(SysFrm *, int fd)
if (it == fdt->FileMap.end())
return -linux_EBADF;
pcb->SetWorkingDirectory(it->second.Node);
debug("Changed cwd to \"%s\"", it->second.Node->GetPath().c_str());
pcb->SetWorkingDirectory(it->second.node);
debug("Changed cwd to \"%s\"", it->second.node->GetPath().c_str());
return 0;
}
@ -2395,7 +2396,7 @@ static int linux_mkdir(SysFrm *, const char *pathname, mode_t mode)
mode &= ~pcb->FileCreationMask & 0777;
FileNode *n = fs->Create(pcb->CWD, pPathname, mode);
Node n = fs->Create(pcb->CWD, pPathname, mode);
if (!n)
return -linux_EEXIST;
return 0;
@ -2432,13 +2433,13 @@ static ssize_t linux_readlink(SysFrm *, const char *pathname,
ReturnLogError(-linux_EBADF, "Invalid fd %d", fd);
vfs::FileDescriptorTable::Fildes &fildes = it->second;
FileNode *node = fildes.Node;
Node node = fildes.node;
fdt->usr_close(fd);
if (!node->IsSymbolicLink())
return -linux_EINVAL;
return ConvertErrnoToLinux(node->ReadLink(pBuf, bufsiz));
return ConvertErrnoToLinux(fs->ReadLink(node, pBuf, bufsiz));
}
static int linux_fchmod(SysFrm *, int fd, mode_t mode)
@ -2480,7 +2481,7 @@ static int linux_chmod(SysFrm *sf, const char *pathname, mode_t mode)
if (pPathname == nullptr)
return -linux_EFAULT;
FileNode *node = fs->GetByPath(pPathname, pcb->CWD);
Node node = fs->Lookup(pcb->CWD, pPathname);
if (!node)
return -linux_ENOENT;
@ -3114,7 +3115,7 @@ __no_sanitize("undefined") static ssize_t linux_getdents64(SysFrm *,
}
vfs::FileDescriptorTable::Fildes &fildes = it->second;
if (!fildes.Node->IsDirectory())
if (!fildes.node->IsDirectory())
{
debug("Not a directory");
return -ENOTDIR;
@ -3138,8 +3139,7 @@ __no_sanitize("undefined") static ssize_t linux_getdents64(SysFrm *,
#endif
/* The structs are the same, no need for conversion. */
ssize_t ret = fildes.Node->ReadDir((struct kdirent *)pDirp, count, fildes.Offset,
count / sizeof(kdirent));
ssize_t ret = fs->ReadDirectory(fildes.node, (struct kdirent *)pDirp, count, fildes.Offset, count / sizeof(kdirent));
if (ret > 0)
fildes.Offset += ret;
@ -3324,7 +3324,7 @@ static int linux_openat(SysFrm *, int dirfd, const char *pathname, int flags, mo
if (dirfd == linux_AT_FDCWD)
{
FileNode *absoluteNode = fs->GetByPath(pPathname, pcb->CWD);
Node absoluteNode = fs->Lookup(pcb->CWD, pPathname);
if (!absoluteNode)
return -linux_ENOENT;
@ -3373,7 +3373,7 @@ static long linux_newfstatat(SysFrm *, int dirfd, const char *pathname,
case linux_AT_FDCWD:
{
debug("dirfd is AT_FDCWD for \"%s\"", pPathname);
FileNode *node = fs->GetByPath(pPathname, pcb->CWD);
Node node = fs->Lookup(pcb->CWD, pPathname);
if (!node)
return -linux_ENOENT;
@ -3390,7 +3390,7 @@ static long linux_newfstatat(SysFrm *, int dirfd, const char *pathname,
ReturnLogError(-linux_EBADF, "Invalid fd %d", dirfd);
vfs::FileDescriptorTable::Fildes &fildes = it->second;
FileNode *node = fs->GetByPath(pPathname, fildes.Node);
Node node = fs->Lookup(fildes.node, pPathname);
debug("node: %s", node->GetPath().c_str());
if (!node)
return -linux_ENOENT;

View File

@ -15,7 +15,7 @@
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <filesystem/ramfs.hpp>
#include <fs/ramfs.hpp>
#include "../../kernel.h"
@ -23,25 +23,30 @@ namespace Subsystem::Windows
{
bool Initialized = false;
void __CreateStubRoot()
{
Node root = fs->GetRoot(0);
Node nmnt = fs->Lookup(root, "/mnt");
assert(MountAndRootRAMFS(nmnt, "windows", 2));
Node win = fs->GetRoot(2);
Node windows = fs->Create(win, "Windows", 0755);
Node programFiles = fs->Create(windows, "Program Files", 0755);
Node programFilesX86 = fs->Create(windows, "Program Files (x86)", 0755);
Node programData = fs->Create(windows, "ProgramData", 0755);
Node users = fs->Create(windows, "Users", 0755);
UNUSED(windows);
UNUSED(programFiles);
UNUSED(programFilesX86);
UNUSED(programData);
UNUSED(users);
}
void InitializeSubSystem()
{
if (fs->RootExists(2) == false)
{
FileNode *nmnt = fs->GetByPath("/mnt", fs->GetRoot(0));
assert(MountRAMFS(nmnt, "windows", 2));
FileNode *win = fs->GetRoot(2);
FileNode *windows = fs->ForceCreate(win, "Windows", 0755);
FileNode *programFiles = fs->ForceCreate(windows, "Program Files", 0755);
FileNode *programFilesX86 = fs->ForceCreate(windows, "Program Files (x86)", 0755);
FileNode *programData = fs->ForceCreate(windows, "ProgramData", 0755);
FileNode *users = fs->ForceCreate(windows, "Users", 0755);
UNUSED(windows);
UNUSED(programFiles);
UNUSED(programFilesX86);
UNUSED(programData);
UNUSED(users);
}
}
}

View File

@ -109,7 +109,7 @@ static int sys_open(SysFrm *Frame, const char *pathname, int flags, mode_t mode)
if (flags & 0200000 /* O_DIRECTORY */)
{
FileNode *node = fs->GetByPath(pPathname, pcb->CWD);
Node node = fs->Lookup(pcb->CWD, pPathname);
if (node == nullptr)
{
debug("Couldn't find %s", pPathname);
@ -150,7 +150,7 @@ static int sys_access(SysFrm *Frame, const char *pathname, int mode)
debug("access(%s, %d)", (char *)pPathname, mode);
if (!fs->PathExists(pPathname, pcb->CWD))
if (!fs->Lookup(pcb->CWD, pPathname))
return -ENOENT;
stub;

View File

@ -95,34 +95,34 @@ namespace Tasking
strcpy((char *)this->Name, name);
}
void PCB::SetWorkingDirectory(FileNode *node)
void PCB::SetWorkingDirectory(Node node)
{
trace("Setting working directory of process %s to %#lx (%s)",
this->Name, node, node->Name.c_str());
CWD = node;
FileNode *cwd = fs->GetByPath("cwd", ProcDirectory);
trace("Setting working directory of process %s", node->Name.c_str());
this->CWD = node;
Node cwd = fs->Lookup(ProcDirectory, "cwd");
if (cwd)
fs->Remove(cwd);
cwd = fs->CreateLink("cwd", ProcDirectory, node);
cwd = fs->CreateLink(ProcDirectory, "cwd", node);
if (cwd == nullptr)
error("Failed to create cwd link");
}
void PCB::SetExe(const char *path)
{
trace("Setting exe %s to %s",
this->Name, path);
Executable = fs->GetByPath(path, ProcDirectory);
trace("Setting exe %s to %s", this->Name, path);
Executable = fs->Lookup(ProcDirectory, path);
if (Executable->IsSymbolicLink())
{
char buffer[512];
Executable->ReadLink(buffer, sizeof(buffer));
Executable = fs->GetByPath(buffer, Executable->Parent);
fs->ReadLink(Executable, buffer, sizeof(buffer));
Executable = fs->Lookup(Executable->Parent, buffer);
}
FileNode *exe = fs->GetByPath("exe", ProcDirectory);
Node exe = fs->Lookup(ProcDirectory, "exe");
if (exe)
fs->Remove(exe);
exe = fs->CreateLink("exe", ProcDirectory, path);
exe = fs->CreateLink(ProcDirectory, "exe", path);
if (exe == nullptr)
error("Failed to create exe link");
}
@ -155,7 +155,8 @@ namespace Tasking
assert(ExecutionMode >= _ExecuteModeMin);
assert(ExecutionMode <= _ExecuteModeMax);
FileNode *procDir = fs->GetByPath("/proc", nullptr);
Node root = fs->GetRoot(0);
Node procDir = fs->Lookup(root, "/proc");
assert(procDir != nullptr);
/* d r-x r-x r-x */

View File

@ -246,23 +246,222 @@ namespace Tasking
debug("Tasking Started");
}
struct TaskNode : public Inode
{
kstat Stat;
Inode *Parent;
std::string Name;
std::vector<TaskNode *> Children;
};
int __task_Lookup(struct Inode *Parent, const char *Name, struct Inode **Result)
{
return -ENOSYS;
}
int __task_Create(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result)
{
TaskNode *p = (TaskNode *)Parent;
if (!S_ISDIR(p->Mode))
return -ENOTDIR;
TaskNode *newNode = new TaskNode;
newNode->Parent = p;
newNode->Name = Name;
newNode->Mode = Mode;
p->Children.push_back(newNode);
*Result = newNode;
return 0;
}
ssize_t __task_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
{
return -ENOSYS;
}
ssize_t __task_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
{
return -ENOSYS;
}
__no_sanitize("alignment") ssize_t __task_Readdir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
{
auto node = (TaskNode *)_Node;
off_t realOffset = Offset;
size_t totalSize = 0;
uint16_t reclen = 0;
struct kdirent *ent = nullptr;
if (!S_ISDIR(node->Mode))
return -ENOTDIR;
if (Offset == 0)
{
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(".") + 1);
if (totalSize + reclen > Size)
return -EINVAL;
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
ent->d_ino = node->Index;
ent->d_off = 0;
ent->d_reclen = reclen;
ent->d_type = DT_DIR;
strcpy(ent->d_name, ".");
totalSize += reclen;
Offset++;
}
if (Offset == 1)
{
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen("..") + 1);
if (totalSize + reclen > Size)
return totalSize;
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
ent->d_ino = node->Parent ? node->Parent->Index : 0;
ent->d_off = 1;
ent->d_reclen = reclen;
ent->d_type = DT_DIR;
strcpy(ent->d_name, "..");
totalSize += reclen;
Offset++;
}
off_t entryIndex = 0;
for (const auto &var : node->Children)
{
if (entryIndex + 2 < realOffset)
{
entryIndex++;
continue;
}
if (Entries && entryIndex >= Entries)
break;
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(var->Name.c_str()) + 1);
if (totalSize + reclen > Size)
break;
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
ent->d_ino = var->Index;
ent->d_off = entryIndex + 2;
ent->d_reclen = reclen;
ent->d_type = IFTODT(var->Mode);
strcpy(ent->d_name, var->Name.c_str());
totalSize += reclen;
entryIndex++;
}
if (totalSize + offsetof(struct kdirent, d_name) + 1 > 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;
}
int __task_SymLink(Inode *Parent, const char *Name, const char *Target, Inode **Result)
{
return -ENOSYS;
}
ssize_t __task_ReadLink(Inode *Node, char *Buffer, size_t Size)
{
switch (Node->GetMajor())
{
case 0:
{
switch (Node->GetMinor())
{
case 0:
{
/* 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;
}
}
default:
return -ENOENT;
}
}
int __task_Stat(struct Inode *Node, kstat *Stat)
{
TaskNode *node = (TaskNode *)Node;
*Stat = node->Stat;
return 0;
}
int __task_AllocateInode(struct FileSystemInfo *, struct Inode **Result)
{
TaskNode *ret = new TaskNode;
*Result = (Inode *)ret;
return 0;
}
int __task_DeleteInode(struct FileSystemInfo *, struct Inode *Node)
{
delete Node;
return 0;
}
Task::Task(const IP EntryPoint)
{
Node root = fs->GetRoot(0);
FileSystemInfo *fsi = new FileSystemInfo;
fsi->Name = "procfs";
fsi->SuperOps.AllocateInode = __task_AllocateInode;
fsi->SuperOps.DeleteInode = __task_DeleteInode;
fsi->Ops.Lookup = __task_Lookup;
fsi->Ops.Create = __task_Create;
fsi->Ops.Read = __task_Read;
fsi->Ops.Write = __task_Write;
fsi->Ops.ReadDir = __task_Readdir;
fsi->Ops.SymLink = __task_SymLink;
fsi->Ops.ReadLink = __task_ReadLink;
fsi->Ops.Stat = __task_Stat;
/* d rwx rwx rwx */
mode_t mode = S_IRWXU |
S_IRWXG |
S_IRWXO |
S_IFDIR;
TaskNode *inode = new TaskNode;
inode->Device = fs->RegisterFileSystem(fsi);
inode->Mode = mode;
Node proc = fs->Mount(root, inode, "proc", fsi);
// proc->fsi = fsi;
// inode->Parent = root->inode;
// inode->Name = "proc";
/* l rwx rwx rwx */
mode = S_IRWXU |
S_IRWXG |
S_IRWXO |
S_IFLNK;
Node self = fs->Create(proc, "self", mode);
self->inode->Device = inode->Device;
self->inode->SetDevice(0, 0);
/* I don't know if this is the best way to do this. */
Scheduler::Custom *custom_sched = new Scheduler::Custom(this);
Scheduler::Base *sched = r_cst(Scheduler::Base *, custom_sched);
__sched_ctx = custom_sched;
Scheduler = sched;
KernelProcess = CreateProcess(nullptr, "Kernel",
TaskExecutionMode::Kernel, true);
KernelProcess->PageTable = KernelPageTable;
TCB *kthrd = CreateThread(KernelProcess, EntryPoint,
nullptr, nullptr,
std::vector<AuxiliaryVector>(), GetKArch());
KernelProcess = CreateProcess(nullptr, "Kernel", Kernel, true, 0, 0);
TCB *kthrd = CreateThread(KernelProcess, EntryPoint, nullptr, nullptr, {}, GetKArch());
kthrd->Rename("Main Thread");
debug("Created Kernel Process: %s and Thread: %s",
KernelProcess->Name, kthrd->Name);
debug("Created Kernel Process: %s and Thread: %s", KernelProcess->Name, kthrd->Name);
if (!CPU::Interrupts(CPU::Check))
{

View File

@ -17,7 +17,7 @@
#include <task.hpp>
#include <filesystem/ioctl.hpp>
#include <fs/ioctl.hpp>
#include <dumper.hpp>
#include <convert.h>
#include <lock.hpp>

View File

@ -18,11 +18,11 @@
#ifdef DEBUG
#include <types.h>
#include <filesystem/ioctl.hpp>
#include <fs/ioctl.hpp>
#include <interface/syscalls.h>
#include <memory/macro.hpp>
#include <memory/vma.hpp>
#include <filesystem.hpp>
#include <fs/vfs.hpp>
#include <assert.h>
#include <debug.h>

94
Kernel/tests/readdir.cpp Normal file
View File

@ -0,0 +1,94 @@
/*
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 <fs/vfs.hpp>
#include "../kernel.h"
#ifdef DEBUG
void TestReadDirectory(Node &Target)
{
const size_t bufLen = 4096;
std::unique_ptr<uint8_t[]> buf(new uint8_t[bufLen]);
off_t off = 0;
off_t max = LONG_MAX;
KPrint("Listing directory: \x1b[1;36m%s\x1b[0m", Target->Name.c_str());
while (true)
{
ssize_t bytes = fs->ReadDirectory(Target, (kdirent *)buf.get(), bufLen, off, max);
if (bytes < 0)
{
KPrint("ReadDirectory returned error: %d", bytes);
break;
}
if (bytes == 0)
break;
ssize_t Pos = 0;
while (Pos < bytes)
{
kdirent *Entry = (kdirent *)(buf.get() + Pos);
if (Entry->d_reclen == 0)
{
KPrint("Entry with zero length detected at offset %ld!", off + Pos);
break;
}
KPrint("name=\"%s\" inode=%lu type=%u reclen=%u", Entry->d_name, Entry->d_ino, Entry->d_type, Entry->d_reclen);
Pos += Entry->d_reclen;
}
off += bytes;
}
}
void readdir_sanity_tests()
{
Node root = fs->GetRoot(0);
Node t0 = fs->Lookup(root, "/");
Node t1 = fs->Lookup(root, "/dev");
Node t2 = fs->Lookup(root, "/home");
Node t3 = fs->Lookup(root, "/var");
Node t4 = fs->Lookup(root, "/tmp");
KPrint("TEST /");
TestReadDirectory(t0);
TaskManager->Sleep(2000);
KPrint("TEST /dev");
TestReadDirectory(t1);
TaskManager->Sleep(2000);
KPrint("TEST /home");
TestReadDirectory(t2);
TaskManager->Sleep(2000);
KPrint("TEST /var");
TestReadDirectory(t3);
TaskManager->Sleep(2000);
KPrint("TEST /tmp");
TestReadDirectory(t4);
TaskManager->Sleep(2000);
CPU::Stop();
}
#endif // DEBUG

View File

@ -20,14 +20,14 @@
#ifdef DEBUG
#include <types.h>
#include <filesystem.hpp>
#include <fs/vfs.hpp>
void Test_stl();
void TestMemoryAllocation();
void tasking_test_fb();
void tasking_test_mutex();
void TaskMgr();
void TreeFS(FileNode *node, int Depth);
void TreeFS(Node node, int Depth);
void TaskHeartbeat();
void StressKernel();
void coroutineTest();

View File

@ -21,7 +21,7 @@
#include "../kernel.h"
void TreeFS(FileNode *node, int Depth)
void TreeFS(Node node, int Depth)
{
return;
// for (auto Chld : node->GetChildren(true))

View File

@ -16,7 +16,7 @@
*/
#include <tty.hpp>
#include <filesystem/ioctl.hpp>
#include <fs/ioctl.hpp>
#include <smp.hpp>
#include <errno.h>

View File

@ -17,7 +17,7 @@
#include <kcon.hpp>
#include <filesystem/ioctl.hpp>
#include <fs/ioctl.hpp>
#include <memory.hpp>
#include <stropts.h>
#include <string.h>