diff --git a/Drivers/include/block.h b/Drivers/include/block.h
new file mode 100644
index 00000000..45c6ce29
--- /dev/null
+++ b/Drivers/include/block.h
@@ -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 .
+*/
+
+#ifndef __FENNIX_API_BLOCK_H__
+#define __FENNIX_API_BLOCK_H__
+
+#include
+
+#if __has_include()
+#include
+#else
+#include
+#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__
diff --git a/Drivers/include/fs.h b/Drivers/include/fs.h
index 3abe9a75..c55969d5 100644
--- a/Drivers/include/fs.h
+++ b/Drivers/include/fs.h
@@ -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__
diff --git a/Kernel/TODO.md b/Kernel/TODO.md
index 9d9a64bd..cd5a33fd 100644
--- a/Kernel/TODO.md
+++ b/Kernel/TODO.md
@@ -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.
diff --git a/Kernel/core/console.cpp b/Kernel/core/console.cpp
index a89f014e..f36bba05 100644
--- a/Kernel/core/console.cpp
+++ b/Kernel/core/console.cpp
@@ -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);
}
diff --git a/Kernel/core/driver/api.cpp b/Kernel/core/driver/api.cpp
index bc424a4c..a44e8741 100644
--- a/Kernel/core/driver/api.cpp
+++ b/Kernel/core/driver/api.cpp
@@ -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,
diff --git a/Kernel/core/driver/daemon.cpp b/Kernel/core/driver/daemon.cpp
deleted file mode 100644
index e97d5297..00000000
--- a/Kernel/core/driver/daemon.cpp
+++ /dev/null
@@ -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 .
-*/
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "../../kernel.h"
-
-using namespace vfs;
-
-namespace Driver
-{
- /**
- * maj = 0
- * min:
- * 0 -
- * 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 &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 &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 &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 &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 &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 *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(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 *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(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 &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 &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(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 &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 &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);
- }
-}
diff --git a/Kernel/core/driver/dev.cpp b/Kernel/core/driver/dev.cpp
new file mode 100644
index 00000000..d21004c7
--- /dev/null
+++ b/Kernel/core/driver/dev.cpp
@@ -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 .
+*/
+
+#include
+
+#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 &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 &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 &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 &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 &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);
+ }
+}
diff --git a/Kernel/core/driver/driver.cpp b/Kernel/core/driver/driver.cpp
index 413f94dc..e1a99cab 100644
--- a/Kernel/core/driver/driver.cpp
+++ b/Kernel/core/driver/driver.cpp
@@ -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 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()
{
diff --git a/Kernel/core/driver/manager.cpp b/Kernel/core/driver/manager.cpp
new file mode 100644
index 00000000..1b59d3e7
--- /dev/null
+++ b/Kernel/core/driver/manager.cpp
@@ -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 .
+*/
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "../../kernel.h"
+
+using namespace vfs;
+
+namespace Driver
+{
+ dev_t Manager::RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations)
+ {
+ std::unordered_map &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(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 &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(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 &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 &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 &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 &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;
+ }
+}
diff --git a/Kernel/core/memory/page_table.cpp b/Kernel/core/memory/page_table.cpp
index d4ab3d7f..9473e97b 100644
--- a/Kernel/core/memory/page_table.cpp
+++ b/Kernel/core/memory/page_table.cpp
@@ -1,6 +1,6 @@
#include
-#include
+#include
#include
#include
#include
diff --git a/Kernel/core/panic/diag.cpp b/Kernel/core/panic/diag.cpp
index 6c237dcb..bfe55506 100644
--- a/Kernel/core/panic/diag.cpp
+++ b/Kernel/core/panic/diag.cpp
@@ -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 |
diff --git a/Kernel/core/panic/handler.cpp b/Kernel/core/panic/handler.cpp
index 8f19590d..385e773b 100644
--- a/Kernel/core/panic/handler.cpp
+++ b/Kernel/core/panic/handler.cpp
@@ -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();
diff --git a/Kernel/include/filesystem/ext2.hpp b/Kernel/drivers/fs/ext2/ext2.hpp
similarity index 97%
rename from Kernel/include/filesystem/ext2.hpp
rename to Kernel/drivers/fs/ext2/ext2.hpp
index 830abe6e..6c21f17e 100644
--- a/Kernel/include/filesystem/ext2.hpp
+++ b/Kernel/drivers/fs/ext2/ext2.hpp
@@ -20,9 +20,9 @@
#include
-#include
+#include
-namespace vfs
+namespace Driver::ExtendedFilesystem
{
class EXT2
{
diff --git a/Kernel/drivers/fs/ustar/ustar.cpp b/Kernel/drivers/fs/ustar/ustar.cpp
new file mode 100644
index 00000000..b71120a2
--- /dev/null
+++ b/Kernel/drivers/fs/ustar/ustar.cpp
@@ -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 .
+*/
+
+#include
+#include
+#include
+#include
+#include
+
+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);
+}
diff --git a/Kernel/drivers/storage/ahci/ahci.cpp b/Kernel/drivers/storage/ahci/ahci.cpp
index cb887914..6c7132a8 100644
--- a/Kernel/drivers/storage/ahci/ahci.cpp
+++ b/Kernel/drivers/storage/ahci/ahci.cpp
@@ -16,6 +16,7 @@
*/
#include
+#include
#include
#include
@@ -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(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(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;
}
diff --git a/Kernel/exec/binary_parse.cpp b/Kernel/exec/binary_parse.cpp
index a0c6c295..9af1cdda 100644
--- a/Kernel/exec/binary_parse.cpp
+++ b/Kernel/exec/binary_parse.cpp
@@ -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);
}
diff --git a/Kernel/exec/elf/elf_loader.cpp b/Kernel/exec/elf/elf_loader.cpp
index d042dcc9..f55930d6 100644
--- a/Kernel/exec/elf/elf_loader.cpp
+++ b/Kernel/exec/elf/elf_loader.cpp
@@ -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 *);
diff --git a/Kernel/exec/elf/elf_parse.cpp b/Kernel/exec/elf/elf_parse.cpp
index 14215129..4e644877 100644
--- a/Kernel/exec/elf/elf_parse.cpp
+++ b/Kernel/exec/elf/elf_parse.cpp
@@ -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;
diff --git a/Kernel/exec/elf/parse/elf_get_dynamic_tag.cpp b/Kernel/exec/elf/parse/elf_get_dynamic_tag.cpp
index dd07f398..c7474c2b 100644
--- a/Kernel/exec/elf/parse/elf_get_dynamic_tag.cpp
+++ b/Kernel/exec/elf/parse/elf_get_dynamic_tag.cpp
@@ -21,7 +21,7 @@
namespace Execute
{
- std::vector ELFGetDynamicTag(FileNode *fd, DynamicArrayTags Tag)
+ std::vector ELFGetDynamicTag(Node &fd, DynamicArrayTags Tag)
{
std::vector ret;
std::vector 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;
diff --git a/Kernel/exec/elf/parse/elf_get_sections.cpp b/Kernel/exec/elf/parse/elf_get_sections.cpp
index 363028c2..e1367cf0 100644
--- a/Kernel/exec/elf/parse/elf_get_sections.cpp
+++ b/Kernel/exec/elf/parse/elf_get_sections.cpp
@@ -21,18 +21,18 @@
namespace Execute
{
- std::vector ELFGetSections(FileNode *fd, const char *SectionName)
+ std::vector ELFGetSections(Node fd, const char *SectionName)
{
std::vector ret;
Elf_Ehdr ehdr;
- fd->Read(&ehdr, sizeof(Elf_Ehdr), 0);
+ fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0);
std::unique_ptr 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)
{
diff --git a/Kernel/exec/elf/parse/elf_get_symbol_type.cpp b/Kernel/exec/elf/parse/elf_get_symbol_type.cpp
index 5e22d84a..a495e41f 100644
--- a/Kernel/exec/elf/parse/elf_get_symbol_type.cpp
+++ b/Kernel/exec/elf/parse/elf_get_symbol_type.cpp
@@ -21,15 +21,15 @@
namespace Execute
{
- std::vector ELFGetSymbolType(FileNode *fd, SegmentTypes Tag)
+ std::vector ELFGetSymbolType(Node &fd, SegmentTypes Tag)
{
std::vector 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;
diff --git a/Kernel/exec/spawn.cpp b/Kernel/exec/spawn.cpp
index 9ffb3a43..60a89a81 100644
--- a/Kernel/exec/spawn.cpp
+++ b/Kernel/exec/spawn.cpp
@@ -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;
};
diff --git a/Kernel/storage/descriptor.cpp b/Kernel/fs/descriptor.cpp
similarity index 73%
rename from Kernel/storage/descriptor.cpp
rename to Kernel/fs/descriptor.cpp
index a0e7b0d5..5ca4990c 100644
--- a/Kernel/storage/descriptor.cpp
+++ b/Kernel/fs/descriptor.cpp
@@ -15,7 +15,7 @@
along with Fennix Kernel. If not, see .
*/
-#include
+#include
#include
#include
@@ -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 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);
}
}
diff --git a/Kernel/storage/fs/ramfs.cpp b/Kernel/fs/ramfs.cpp
similarity index 88%
rename from Kernel/storage/fs/ramfs.cpp
rename to Kernel/fs/ramfs.cpp
index 56a9ff8d..f0f34e24 100644
--- a/Kernel/storage/fs/ramfs.cpp
+++ b/Kernel/fs/ramfs.cpp
@@ -15,12 +15,12 @@
along with Fennix Kernel. If not, see .
*/
-#include
+#include
#include
#include
#include
-#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;
}
diff --git a/Kernel/storage/fs/ustar.cpp b/Kernel/fs/ustar.cpp
similarity index 96%
rename from Kernel/storage/fs/ustar.cpp
rename to Kernel/fs/ustar.cpp
index 1c929dc8..762d7267 100644
--- a/Kernel/storage/fs/ustar.cpp
+++ b/Kernel/fs/ustar.cpp
@@ -15,12 +15,12 @@
along with Fennix Kernel. If not, see .
*/
-#include
+#include
#include
#include
#include
-#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;
}
diff --git a/Kernel/fs/vfs.cpp b/Kernel/fs/vfs.cpp
new file mode 100644
index 00000000..28f7db06
--- /dev/null
+++ b/Kernel/fs/vfs.cpp
@@ -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 .
+*/
+
+#include
+
+#include "../kernel.h"
+
+namespace vfs
+{
+ eNode Virtual::Convert(Inode *inode)
+ {
+ Node cache = std::make_shared();
+ cache->inode = inode;
+ return {cache, 0};
+ }
+
+ eNode Virtual::Convert(Node &Parent, Inode *inode)
+ {
+ Node cache = std::make_shared();
+ 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() : "");
+ }
+ }
+
+ 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 seen;
+
+ uint8_t *bufPtr = reinterpret_cast(Buffer);
+
+ if (Target->fsi && Target->fsi->Ops.ReadDir)
+ {
+ const size_t tempBufSize = 4096;
+ std::unique_ptr 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 Virtual::ReadDirectory(Node &Target)
+ {
+ if (!Target->IsDirectory() && !Target->IsMountPoint())
+ return {};
+ std::list ret;
+ std::list seen;
+
+ if (Target->fsi && Target->fsi->Ops.ReadDir)
+ {
+ const size_t bufSize = 4096;
+ std::unique_ptr 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 &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() {}
+}
diff --git a/Kernel/include/driver.hpp b/Kernel/include/driver.hpp
index a7e3a0c6..1202dc54 100644
--- a/Kernel/include/driver.hpp
+++ b/Kernel/include/driver.hpp
@@ -22,7 +22,8 @@
#include
#include
-#include
+#include
+#include
#include
#include
#include
@@ -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, size_t, const InodeOperations *);
- dev_t RegisterBlockDevice(std::unordered_map *, dev_t, size_t, const InodeOperations *);
+ void InitializeDeviceDirectory();
public:
RingBuffer 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 Children;
+
+ size_t Size;
+ time_t AccessTime, ModifyTime, ChangeTime;
+ uint32_t BlockSize;
+ uint32_t Blocks;
};
std::unordered_map &
@@ -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);
diff --git a/Kernel/include/exec.hpp b/Kernel/include/exec.hpp
index be31797b..79fc3330 100644
--- a/Kernel/include/exec.hpp
+++ b/Kernel/include/exec.hpp
@@ -20,7 +20,7 @@
#include
-#include
+#include
#include
#include
#include
@@ -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 ELFGetSymbolType(FileNode *fd, SegmentTypes Tag);
- std::vector ELFGetSections(FileNode *fd, std::string SectionName);
- std::vector ELFGetDynamicTag(FileNode *fd, DynamicArrayTags Tag);
+ std::vector ELFGetSymbolType(Node &fd, SegmentTypes Tag);
+ std::vector ELFGetSections(Node &fd, std::string SectionName);
+ std::vector ELFGetDynamicTag(Node &fd, DynamicArrayTags Tag);
}
#endif // !__FENNIX_KERNEL_FILE_EXECUTE_H__
diff --git a/Kernel/include/filesystem.hpp b/Kernel/include/filesystem.hpp
deleted file mode 100644
index bda0be7d..00000000
--- a/Kernel/include/filesystem.hpp
+++ /dev/null
@@ -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 .
-*/
-
-#ifndef __FENNIX_KERNEL_FILESYSTEM_H__
-#define __FENNIX_KERNEL_FILESYSTEM_H__
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-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 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 Children;
- };
-
- class Virtual
- {
- private:
- NewLock(VirtualLock);
-
- struct FSMountInfo
- {
- FileSystemInfo *fsi;
- Inode *Root;
- };
-
- struct CacheNode
- {
- FileNode *fn;
- std::atomic_int References;
- };
-
- std::unordered_map 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 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 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__
diff --git a/Kernel/include/filesystem/initrd.hpp b/Kernel/include/filesystem/initrd.hpp
deleted file mode 100644
index 833eac78..00000000
--- a/Kernel/include/filesystem/initrd.hpp
+++ /dev/null
@@ -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 .
-*/
-
-#ifndef __FENNIX_KERNEL_FILESYSTEM_INITRD_H__
-#define __FENNIX_KERNEL_FILESYSTEM_INITRD_H__
-
-#include
-
-#include
-
-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__
diff --git a/Kernel/include/fs/fdt.hpp b/Kernel/include/fs/fdt.hpp
new file mode 100644
index 00000000..13553554
--- /dev/null
+++ b/Kernel/include/fs/fdt.hpp
@@ -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 .
+*/
+
+#pragma once
+
+#include
+#include
+
+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 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;
+ };
+}
diff --git a/Kernel/include/filesystem/ioctl.hpp b/Kernel/include/fs/ioctl.hpp
similarity index 100%
rename from Kernel/include/filesystem/ioctl.hpp
rename to Kernel/include/fs/ioctl.hpp
diff --git a/Kernel/include/fs/node.hpp b/Kernel/include/fs/node.hpp
new file mode 100644
index 00000000..3dc97aae
--- /dev/null
+++ b/Kernel/include/fs/node.hpp
@@ -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 .
+*/
+
+#pragma once
+
+#include
+#include
+#include
+#include
+
+/**
+ * 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 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 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
diff --git a/Kernel/include/filesystem/ramfs.hpp b/Kernel/include/fs/ramfs.hpp
similarity index 97%
rename from Kernel/include/filesystem/ramfs.hpp
rename to Kernel/include/fs/ramfs.hpp
index bd39df3a..fc846dd6 100644
--- a/Kernel/include/filesystem/ramfs.hpp
+++ b/Kernel/include/fs/ramfs.hpp
@@ -17,7 +17,7 @@
#pragma once
-#include
+#include
#include
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);
diff --git a/Kernel/include/filesystem/ustar.hpp b/Kernel/include/fs/ustar.hpp
similarity index 99%
rename from Kernel/include/filesystem/ustar.hpp
rename to Kernel/include/fs/ustar.hpp
index b714b5d4..83286255 100644
--- a/Kernel/include/filesystem/ustar.hpp
+++ b/Kernel/include/fs/ustar.hpp
@@ -18,7 +18,7 @@
#ifndef __FENNIX_KERNEL_FILESYSTEM_USTAR_H__
#define __FENNIX_KERNEL_FILESYSTEM_USTAR_H__
-#include
+#include
namespace vfs
{
diff --git a/Kernel/include/fs/vfs.hpp b/Kernel/include/fs/vfs.hpp
new file mode 100644
index 00000000..0cabf605
--- /dev/null
+++ b/Kernel/include/fs/vfs.hpp
@@ -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 .
+*/
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* sanity checks */
+static_assert(DTTOIF(DT_FIFO) == S_IFIFO);
+static_assert(IFTODT(S_IFCHR) == DT_CHR);
+
+namespace vfs
+{
+ class Virtual
+ {
+ private:
+ std::unordered_map Roots;
+ std::unordered_map 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 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();
+ };
+}
diff --git a/Kernel/include/interface/block.h b/Kernel/include/interface/block.h
new file mode 100644
index 00000000..45c6ce29
--- /dev/null
+++ b/Kernel/include/interface/block.h
@@ -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 .
+*/
+
+#ifndef __FENNIX_API_BLOCK_H__
+#define __FENNIX_API_BLOCK_H__
+
+#include
+
+#if __has_include()
+#include
+#else
+#include
+#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__
diff --git a/Kernel/include/interface/fs.h b/Kernel/include/interface/fs.h
index 3abe9a75..c55969d5 100644
--- a/Kernel/include/interface/fs.h
+++ b/Kernel/include/interface/fs.h
@@ -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__
diff --git a/Kernel/include/memory.hpp b/Kernel/include/memory.hpp
index 61d4a972..a26dcc3f 100644
--- a/Kernel/include/memory.hpp
+++ b/Kernel/include/memory.hpp
@@ -19,7 +19,7 @@
#define __FENNIX_KERNEL_INTERNAL_MEMORY_H__
#ifdef __cplusplus
-#include
+#include
#include
#include
#include
diff --git a/Kernel/include/memory/vma.hpp b/Kernel/include/memory/vma.hpp
index 1dfe8358..2abe448c 100644
--- a/Kernel/include/memory/vma.hpp
+++ b/Kernel/include/memory/vma.hpp
@@ -19,7 +19,7 @@
#define __FENNIX_KERNEL_MEMORY_VMA_H__
#include
-#include
+#include
#include
#include
#include
diff --git a/Kernel/include/task.hpp b/Kernel/include/task.hpp
index 105b0a1e..02dda6b1 100644
--- a/Kernel/include/task.hpp
+++ b/Kernel/include/task.hpp
@@ -20,7 +20,7 @@
#include
-#include
+#include
#include
#include
#include
@@ -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);
diff --git a/Kernel/include/types.h b/Kernel/include/types.h
index 817b21d4..232727fd 100644
--- a/Kernel/include/types.h
+++ b/Kernel/include/types.h
@@ -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
diff --git a/Kernel/kernel.cpp b/Kernel/kernel.cpp
index 41fbe7ed..b74689da 100644
--- a/Kernel/kernel.cpp
+++ b/Kernel/kernel.cpp
@@ -17,7 +17,7 @@
#include "kernel.h"
-#include
+#include
#include
#include
#include
diff --git a/Kernel/kernel.h b/Kernel/kernel.h
index 3b4718c1..2e8d54e7 100644
--- a/Kernel/kernel.h
+++ b/Kernel/kernel.h
@@ -22,7 +22,7 @@
#include
#ifdef __cplusplus
-#include
+#include
#include
#include
#include
diff --git a/Kernel/kernel_thread.cpp b/Kernel/kernel_thread.cpp
index 755a440d..668d6854 100644
--- a/Kernel/kernel_thread.cpp
+++ b/Kernel/kernel_thread.cpp
@@ -20,7 +20,7 @@
#include "tests/t.h"
#endif
-#include
+#include
#include
#include
#include
@@ -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();
diff --git a/Kernel/kernel_vfs.cpp b/Kernel/kernel_vfs.cpp
index 64f90c1c..8ae960fc 100644
--- a/Kernel/kernel_vfs.cpp
+++ b/Kernel/kernel_vfs.cpp
@@ -17,7 +17,7 @@
#include "kernel.h"
-#include
+#include
#include
vfs::Virtual *fs = nullptr;
diff --git a/Kernel/kshell/commands/cat.cpp b/Kernel/kshell/commands/cat.cpp
index 9f18556c..253f42d8 100644
--- a/Kernel/kshell/commands/cat.cpp
+++ b/Kernel/kshell/commands/cat.cpp
@@ -17,7 +17,7 @@
#include "../cmds.hpp"
-#include
+#include
#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
diff --git a/Kernel/kshell/commands/cd.cpp b/Kernel/kshell/commands/cd.cpp
index 64f2a508..2ad61013 100644
--- a/Kernel/kshell/commands/cd.cpp
+++ b/Kernel/kshell/commands/cd.cpp
@@ -17,7 +17,7 @@
#include "../cmds.hpp"
-#include
+#include
#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());
}
diff --git a/Kernel/kshell/commands/dump.cpp b/Kernel/kshell/commands/dump.cpp
index 3218e9a1..df7691d8 100644
--- a/Kernel/kshell/commands/dump.cpp
+++ b/Kernel/kshell/commands/dump.cpp
@@ -17,7 +17,7 @@
#include "../cmds.hpp"
-#include
+#include
#include
#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');
}
-}
\ No newline at end of file
+}
diff --git a/Kernel/kshell/commands/exit.cpp b/Kernel/kshell/commands/exit.cpp
index 20dcb9d9..07339e32 100644
--- a/Kernel/kshell/commands/exit.cpp
+++ b/Kernel/kshell/commands/exit.cpp
@@ -17,7 +17,7 @@
#include "../cmds.hpp"
-#include
+#include
#include
#include "../../kernel.h"
diff --git a/Kernel/kshell/commands/kill.cpp b/Kernel/kshell/commands/kill.cpp
index 76879a76..b124bb0c 100644
--- a/Kernel/kshell/commands/kill.cpp
+++ b/Kernel/kshell/commands/kill.cpp
@@ -17,7 +17,7 @@
#include "../cmds.hpp"
-#include
+#include
#include
#include "../../kernel.h"
diff --git a/Kernel/kshell/commands/killall.cpp b/Kernel/kshell/commands/killall.cpp
index 80f30b99..28bac761 100644
--- a/Kernel/kshell/commands/killall.cpp
+++ b/Kernel/kshell/commands/killall.cpp
@@ -17,7 +17,7 @@
#include "../cmds.hpp"
-#include
+#include
#include
#include "../../kernel.h"
diff --git a/Kernel/kshell/commands/ls.cpp b/Kernel/kshell/commands/ls.cpp
index e7c7c98c..52ca6d46 100644
--- a/Kernel/kshell/commands/ls.cpp
+++ b/Kernel/kshell/commands/ls.cpp
@@ -17,98 +17,60 @@
#include "../cmds.hpp"
-#include
+#include
#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 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)
{
diff --git a/Kernel/kshell/commands/lsacpi.cpp b/Kernel/kshell/commands/lsacpi.cpp
index 586bad7b..94fb622f 100644
--- a/Kernel/kshell/commands/lsacpi.cpp
+++ b/Kernel/kshell/commands/lsacpi.cpp
@@ -17,7 +17,7 @@
#include "../cmds.hpp"
-#include
+#include
#include
#include "../../kernel.h"
diff --git a/Kernel/kshell/commands/lspci.cpp b/Kernel/kshell/commands/lspci.cpp
index 246ed1d7..457d10a7 100644
--- a/Kernel/kshell/commands/lspci.cpp
+++ b/Kernel/kshell/commands/lspci.cpp
@@ -17,7 +17,7 @@
#include "../cmds.hpp"
-#include
+#include
#include "../../kernel.h"
diff --git a/Kernel/kshell/commands/mem.cpp b/Kernel/kshell/commands/mem.cpp
index 1b2e51a1..2a096437 100644
--- a/Kernel/kshell/commands/mem.cpp
+++ b/Kernel/kshell/commands/mem.cpp
@@ -17,7 +17,7 @@
#include "../cmds.hpp"
-#include
+#include
#include
#include "../../kernel.h"
diff --git a/Kernel/kshell/commands/panic.cpp b/Kernel/kshell/commands/panic.cpp
index 19dc8fce..8fc63273 100644
--- a/Kernel/kshell/commands/panic.cpp
+++ b/Kernel/kshell/commands/panic.cpp
@@ -17,7 +17,7 @@
#include "../cmds.hpp"
-#include
+#include
#include "../../kernel.h"
diff --git a/Kernel/kshell/commands/ps.cpp b/Kernel/kshell/commands/ps.cpp
index d160b8a2..6fc28fbc 100644
--- a/Kernel/kshell/commands/ps.cpp
+++ b/Kernel/kshell/commands/ps.cpp
@@ -17,7 +17,7 @@
#include "../cmds.hpp"
-#include
+#include
#include
#include "../../kernel.h"
diff --git a/Kernel/kshell/commands/reboot.cpp b/Kernel/kshell/commands/reboot.cpp
index a9da5456..47d002a2 100644
--- a/Kernel/kshell/commands/reboot.cpp
+++ b/Kernel/kshell/commands/reboot.cpp
@@ -17,7 +17,7 @@
#include "../cmds.hpp"
-#include
+#include
#include
#include "../../kernel.h"
diff --git a/Kernel/kshell/commands/shutdown.cpp b/Kernel/kshell/commands/shutdown.cpp
index 0d3acea6..790c8083 100644
--- a/Kernel/kshell/commands/shutdown.cpp
+++ b/Kernel/kshell/commands/shutdown.cpp
@@ -17,7 +17,7 @@
#include "../cmds.hpp"
-#include