mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-05-25 22:14:34 +00:00
fix(kernel/vfs): 🎉 a complete rewrite of the vfs
This is the fourth time re-writing the VFS, hope this will be the last. Tried to make it as modular as possible so this won't be necessary in the future. 🙏
This change required the entire kernel code to be modified.
This commit is contained in:
parent
83a7f83f81
commit
557c7e6235
110
Drivers/include/block.h
Normal file
110
Drivers/include/block.h
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __FENNIX_API_BLOCK_H__
|
||||
#define __FENNIX_API_BLOCK_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#if __has_include(<interface/fs.h>)
|
||||
#include <interface/fs.h>
|
||||
#else
|
||||
#include <fs.h>
|
||||
#endif
|
||||
|
||||
struct BlockDevice
|
||||
{
|
||||
/**
|
||||
* @brief Base name of the device.
|
||||
*
|
||||
* This name is used to identify the device in the system. It should be unique
|
||||
* across all block devices. The kernel may append a number to this name to
|
||||
* create a unique device name (e.g., "ahci0", "ahci1").
|
||||
*/
|
||||
const char *Name;
|
||||
|
||||
/**
|
||||
* @brief Total size of the device in bytes.
|
||||
*
|
||||
* This value represents the total addressable storage capacity of the device.
|
||||
* It is used for bounds checking and partitioning.
|
||||
*/
|
||||
size_t Size;
|
||||
|
||||
/**
|
||||
* @brief Size of a single block in bytes.
|
||||
*
|
||||
* All read and write operations are performed in multiples of this block size.
|
||||
* Typical values are 512 or 4096 bytes.
|
||||
*/
|
||||
uint32_t BlockSize;
|
||||
|
||||
/**
|
||||
* @brief Number of blocks in the device.
|
||||
*
|
||||
* This value is calculated as Size / BlockSize. It represents the total number
|
||||
* of addressable blocks on the device.
|
||||
*/
|
||||
size_t BlockCount;
|
||||
|
||||
/**
|
||||
* @brief Pointer to the block device operations structure.
|
||||
*
|
||||
* This structure contains function pointers for various operations that can
|
||||
* be performed on the block device, such as read, write, and ioctl.
|
||||
*
|
||||
* Yea, inode operations are used for block devices too.
|
||||
*/
|
||||
const InodeOperations *Ops;
|
||||
|
||||
/**
|
||||
* @brief Opaque pointer to driver-specific or hardware-specific data.
|
||||
*
|
||||
* This field allows the driver to associate private context or state with the
|
||||
* device, such as controller registers or internal buffers.
|
||||
*/
|
||||
void *PrivateData;
|
||||
};
|
||||
|
||||
#ifndef __kernel__
|
||||
/**
|
||||
* @brief Registers a block device with the kernel block subsystem.
|
||||
*
|
||||
* This function should be called by block device drivers after initializing
|
||||
* a device. The kernel will take ownership of the device structure and assign
|
||||
* it a unique device ID. The device will then be accessible for filesystem
|
||||
* mounting and I/O operations.
|
||||
*
|
||||
* @param Device Pointer to a fully initialized BlockDevice structure. All required fields must be set and valid for the lifetime of the device.
|
||||
* @return Device ID (dev_t) assigned by the kernel on success, or an error code on failure.
|
||||
*/
|
||||
dev_t RegisterBlockDevice(struct BlockDevice *Device);
|
||||
|
||||
/**
|
||||
* @brief Unregisters a block device from the kernel block subsystem.
|
||||
*
|
||||
* This function should be called by drivers when a device is being removed
|
||||
* or is no longer available. The kernel will release any resources associated
|
||||
* with the device and invalidate its device ID.
|
||||
*
|
||||
* @param DeviceID The device ID (dev_t) previously returned by RegisterBlockDevice().
|
||||
* @return 0 on success, or an error code.
|
||||
*/
|
||||
int UnregisterBlockDevice(dev_t DeviceID);
|
||||
#endif // __kernel__
|
||||
|
||||
#endif // __FENNIX_API_BLOCK_H__
|
@ -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__
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -1,726 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <driver.hpp>
|
||||
|
||||
#include <interface/driver.h>
|
||||
#include <interface/input.h>
|
||||
#include <memory.hpp>
|
||||
#include <stropts.h>
|
||||
#include <ints.hpp>
|
||||
#include <task.hpp>
|
||||
#include <printf.h>
|
||||
#include <exec.hpp>
|
||||
#include <rand.hpp>
|
||||
#include <cwalk.h>
|
||||
#include <md5.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
using namespace vfs;
|
||||
|
||||
namespace Driver
|
||||
{
|
||||
/**
|
||||
* maj = 0
|
||||
* min:
|
||||
* 0 - <ROOT>
|
||||
* 1 - /proc/self
|
||||
*
|
||||
* maj = 1
|
||||
* min:
|
||||
* 0 - /dev/input/keyboard
|
||||
* 1 - /dev/input/mouse
|
||||
* ..- /dev/input/eventN
|
||||
*/
|
||||
|
||||
int __fs_Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result)
|
||||
{
|
||||
func("%#lx %s %#lx", _Parent, Name, Result);
|
||||
|
||||
assert(_Parent != nullptr);
|
||||
|
||||
const char *basename;
|
||||
size_t length;
|
||||
cwk_path_get_basename(Name, &basename, &length);
|
||||
if (basename == NULL)
|
||||
{
|
||||
error("Invalid name %s", Name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
auto Parent = (Manager::DeviceInode *)_Parent;
|
||||
for (const auto &child : Parent->Children)
|
||||
{
|
||||
debug("Comparing %s with %s", basename, child->Name.c_str());
|
||||
if (strcmp(child->Name.c_str(), basename) != 0)
|
||||
continue;
|
||||
|
||||
*Result = &child->Node;
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug("Not found %s", Name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int __fs_Create(struct Inode *_Parent, const char *Name, mode_t Mode, struct Inode **Result)
|
||||
{
|
||||
func("%#lx %s %d", _Parent, Name, Mode);
|
||||
|
||||
assert(_Parent != nullptr);
|
||||
|
||||
/* We expect to be /dev or children of it */
|
||||
auto Parent = (Manager::DeviceInode *)_Parent;
|
||||
auto _dev = new Manager::DeviceInode;
|
||||
_dev->Parent = nullptr;
|
||||
_dev->ParentInode = _Parent;
|
||||
_dev->Name = Name;
|
||||
_dev->Node.Device = Parent->Node.Device;
|
||||
_dev->Node.Mode = Mode;
|
||||
_dev->Node.Index = Parent->Node.Index + Parent->Children.size();
|
||||
_dev->Node.Offset = Parent->Children.size();
|
||||
Parent->Children.push_back(_dev);
|
||||
|
||||
*Result = &_dev->Node;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t __fs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
func("%#lx %d %d", Node, Size, Offset);
|
||||
switch (Node->GetMajor())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 0: /* /dev/input/keyboard */
|
||||
{
|
||||
if (Size < sizeof(KeyboardReport))
|
||||
return -EINVAL;
|
||||
|
||||
size_t nReads = Size / sizeof(KeyboardReport);
|
||||
|
||||
KeyboardReport *report = (KeyboardReport *)Buffer;
|
||||
|
||||
while (DriverManager->GlobalKeyboardInputReports.Count() == 0)
|
||||
TaskManager->Yield();
|
||||
|
||||
DriverManager->GlobalKeyboardInputReports.Read(report, nReads);
|
||||
return sizeof(KeyboardReport) * nReads;
|
||||
}
|
||||
case 1: /* /dev/input/mouse */
|
||||
{
|
||||
if (Size < sizeof(MouseReport))
|
||||
return -EINVAL;
|
||||
|
||||
size_t nReads = Size / sizeof(MouseReport);
|
||||
|
||||
MouseReport *report = (MouseReport *)Buffer;
|
||||
|
||||
while (DriverManager->GlobalMouseInputReports.Count() == 0)
|
||||
TaskManager->Yield();
|
||||
|
||||
DriverManager->GlobalMouseInputReports.Read(report, nReads);
|
||||
return sizeof(MouseReport) * nReads;
|
||||
}
|
||||
default:
|
||||
return -ENOENT;
|
||||
};
|
||||
}
|
||||
default:
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(Node->GetMajor());
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Node->GetMinor());
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
|
||||
AssertReturnError(dOps->second.Ops, -ENOTSUP);
|
||||
AssertReturnError(dOps->second.Ops->Read, -ENOTSUP);
|
||||
return dOps->second.Ops->Read(Node, Buffer, Size, Offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
func("%#lx %p %d %d", Node, Buffer, Size, Offset);
|
||||
|
||||
switch (Node->GetMajor())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 0: /* /dev/input/keyboard */
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
case 1: /* /dev/input/mouse */
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
default:
|
||||
return -ENOENT;
|
||||
};
|
||||
}
|
||||
default:
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(Node->GetMajor());
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Node->GetMinor());
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
|
||||
AssertReturnError(dOps->second.Ops, -ENOTSUP);
|
||||
AssertReturnError(dOps->second.Ops->Write, -ENOTSUP);
|
||||
return dOps->second.Ops->Write(Node, Buffer, Size, Offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int __fs_Open(struct Inode *Node, int Flags, mode_t Mode)
|
||||
{
|
||||
func("%#lx %d %d", Node, Flags, Mode);
|
||||
|
||||
switch (Node->GetMajor())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 0: /* /dev/input/keyboard */
|
||||
case 1: /* /dev/input/mouse */
|
||||
return -ENOTSUP;
|
||||
default:
|
||||
return -ENOENT;
|
||||
};
|
||||
}
|
||||
default:
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(Node->GetMajor());
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Node->GetMinor());
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
|
||||
AssertReturnError(dOps->second.Ops, -ENOTSUP);
|
||||
AssertReturnError(dOps->second.Ops->Open, -ENOTSUP);
|
||||
return dOps->second.Ops->Open(Node, Flags, Mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int __fs_Close(struct Inode *Node)
|
||||
{
|
||||
func("%#lx", Node);
|
||||
|
||||
switch (Node->GetMajor())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 0: /* /dev/input/keyboard */
|
||||
case 1: /* /dev/input/mouse */
|
||||
return -ENOTSUP;
|
||||
default:
|
||||
return -ENOENT;
|
||||
};
|
||||
}
|
||||
default:
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(Node->GetMajor());
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Node->GetMinor());
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
|
||||
AssertReturnError(dOps->second.Ops, -ENOTSUP);
|
||||
AssertReturnError(dOps->second.Ops->Close, -ENOTSUP);
|
||||
return dOps->second.Ops->Close(Node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
|
||||
{
|
||||
func("%#lx %lu %#lx", Node, Request, Argp);
|
||||
|
||||
switch (Node->GetMajor())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 0: /* /dev/input/keyboard */
|
||||
case 1: /* /dev/input/mouse */
|
||||
return -ENOSYS;
|
||||
default:
|
||||
return -ENOENT;
|
||||
};
|
||||
}
|
||||
default:
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(Node->GetMajor());
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Node->GetMinor());
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
|
||||
AssertReturnError(dOps->second.Ops, -ENOTSUP);
|
||||
AssertReturnError(dOps->second.Ops->Ioctl, -ENOTSUP);
|
||||
return dOps->second.Ops->Ioctl(Node, Request, Argp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__no_sanitize("alignment")
|
||||
ssize_t __fs_Readdir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
|
||||
{
|
||||
func("%#lx %#lx %d %d %d", _Node, Buffer, Size, Offset, Entries);
|
||||
|
||||
auto Node = (Manager::DeviceInode *)_Node;
|
||||
|
||||
off_t realOffset = Offset;
|
||||
|
||||
size_t totalSize = 0;
|
||||
uint16_t reclen = 0;
|
||||
struct kdirent *ent = nullptr;
|
||||
|
||||
if (Offset == 0)
|
||||
{
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(".") + 1);
|
||||
if (totalSize + reclen >= Size)
|
||||
return -EINVAL;
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = Node->Node.Index;
|
||||
ent->d_off = Offset++;
|
||||
ent->d_reclen = reclen;
|
||||
ent->d_type = DT_DIR;
|
||||
strcpy(ent->d_name, ".");
|
||||
totalSize += reclen;
|
||||
}
|
||||
|
||||
if (Offset <= 1)
|
||||
{
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen("..") + 1);
|
||||
if (totalSize + reclen >= Size)
|
||||
{
|
||||
if (realOffset == 1)
|
||||
return -EINVAL;
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
|
||||
if (Node->Parent)
|
||||
ent->d_ino = Node->Parent->Node->Index;
|
||||
else if (Node->ParentInode)
|
||||
ent->d_ino = Node->ParentInode->Index;
|
||||
else
|
||||
{
|
||||
warn("Parent is null for %s", Node->Name.c_str());
|
||||
ent->d_ino = Node->Node.Index;
|
||||
}
|
||||
ent->d_off = Offset++;
|
||||
ent->d_reclen = reclen;
|
||||
ent->d_type = DT_DIR;
|
||||
strcpy(ent->d_name, "..");
|
||||
totalSize += reclen;
|
||||
}
|
||||
|
||||
if (!S_ISDIR(Node->Node.Mode))
|
||||
return -ENOTDIR;
|
||||
|
||||
if ((Offset >= 2 ? (Offset - 2) : Offset) > (off_t)Node->Children.size())
|
||||
return -EINVAL;
|
||||
|
||||
off_t entries = 0;
|
||||
for (const auto &var : Node->Children)
|
||||
{
|
||||
debug("iterating \"%s\" inside \"%s\"", var->Name.c_str(), Node->Name.c_str());
|
||||
if (var->Node.Offset < realOffset)
|
||||
{
|
||||
debug("skipping \"%s\" (%d < %d)", var->Name.c_str(), var->Node.Offset, Offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entries >= Entries)
|
||||
break;
|
||||
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(var->Name.c_str()) + 1);
|
||||
|
||||
if (totalSize + reclen >= Size)
|
||||
break;
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = var->Node.Index;
|
||||
ent->d_off = var->Node.Offset;
|
||||
ent->d_reclen = reclen;
|
||||
ent->d_type = IFTODT(var->Node.Mode);
|
||||
strncpy(ent->d_name, var->Name.c_str(), strlen(var->Name.c_str()));
|
||||
|
||||
totalSize += reclen;
|
||||
entries++;
|
||||
}
|
||||
|
||||
if (totalSize + sizeof(struct kdirent) >= Size)
|
||||
return totalSize;
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = 0;
|
||||
ent->d_off = 0;
|
||||
ent->d_reclen = 0;
|
||||
ent->d_type = DT_UNKNOWN;
|
||||
ent->d_name[0] = '\0';
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
void ManagerDaemonWrapper() { DriverManager->Daemon(); }
|
||||
|
||||
void Manager::Daemon()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
TaskManager->Sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
dev_t Manager::RegisterInputDevice(std::unordered_map<dev_t, DriverHandlers> *dop,
|
||||
dev_t DriverID, size_t i, const InodeOperations *Operations)
|
||||
{
|
||||
std::string prefix = "event";
|
||||
for (size_t j = 0; j < 128; j++)
|
||||
{
|
||||
std::string deviceName = prefix + std::to_string(j);
|
||||
FileNode *node = fs->GetByPath(deviceName.c_str(), devInputNode);
|
||||
if (node)
|
||||
continue;
|
||||
|
||||
/* c rwx r-- r-- */
|
||||
mode_t mode = S_IRWXU |
|
||||
S_IRGRP |
|
||||
S_IROTH |
|
||||
S_IFCHR;
|
||||
|
||||
node = fs->ForceCreate(devInputNode, deviceName.c_str(), mode);
|
||||
node->Node->SetDevice(DriverID, i);
|
||||
|
||||
DriverHandlers dh{};
|
||||
dh.Ops = Operations;
|
||||
dh.Node = node->Node;
|
||||
dh.InputReports = new RingBuffer<InputReport>(16);
|
||||
dop->insert({i, std::move(dh)});
|
||||
return i;
|
||||
}
|
||||
|
||||
ReturnLogError(-1, "No available slots for device %d", DriverID);
|
||||
return -1; /* -Werror=return-type */
|
||||
}
|
||||
|
||||
dev_t Manager::RegisterBlockDevice(std::unordered_map<dev_t, DriverHandlers> *dop,
|
||||
dev_t DriverID, size_t i, const InodeOperations *Operations)
|
||||
{
|
||||
std::string prefix = "event";
|
||||
for (size_t j = 0; j < 128; j++)
|
||||
{
|
||||
std::string deviceName = prefix + std::to_string(j);
|
||||
FileNode *node = fs->GetByPath(deviceName.c_str(), devInputNode);
|
||||
if (node)
|
||||
continue;
|
||||
|
||||
/* c rwx r-- r-- */
|
||||
mode_t mode = S_IRWXU |
|
||||
S_IRGRP |
|
||||
S_IROTH |
|
||||
S_IFBLK;
|
||||
|
||||
node = fs->ForceCreate(devInputNode, deviceName.c_str(), mode);
|
||||
node->Node->SetDevice(DriverID, i);
|
||||
|
||||
DriverHandlers dh{};
|
||||
dh.Ops = Operations;
|
||||
dh.Node = node->Node;
|
||||
dh.InputReports = new RingBuffer<InputReport>(16);
|
||||
dop->insert({i, std::move(dh)});
|
||||
return i;
|
||||
}
|
||||
|
||||
ReturnLogError(-1, "No available slots for device %d", DriverID);
|
||||
return -1; /* -Werror=return-type */
|
||||
}
|
||||
|
||||
dev_t Manager::RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations)
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(DriverID);
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
for (size_t i = 0; i < 128; i++)
|
||||
{
|
||||
const auto dOps = dop->find(i);
|
||||
const auto dOpsEnd = dop->end();
|
||||
if (dOps != dOpsEnd)
|
||||
continue;
|
||||
|
||||
DeviceType devType = (DeviceType)(Type & DEVICE_TYPE_MASK);
|
||||
switch (devType)
|
||||
{
|
||||
case DEVICE_TYPE_INPUT:
|
||||
return RegisterInputDevice(dop, DriverID, i, Operations);
|
||||
case DEVICE_TYPE_BLOCK:
|
||||
return RegisterBlockDevice(dop, DriverID, i, Operations);
|
||||
default:
|
||||
ReturnLogError(-1, "Invalid device type %d", Type);
|
||||
}
|
||||
}
|
||||
|
||||
ReturnLogError(-1, "No available slots for device %d", DriverID);
|
||||
}
|
||||
|
||||
dev_t Manager::CreateDeviceFile(dev_t DriverID, const char *name, mode_t mode, const InodeOperations *Operations)
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(DriverID);
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
for (size_t i = 0; i < 128; i++)
|
||||
{
|
||||
const auto dOps = dop->find(i);
|
||||
if (dOps != dop->end())
|
||||
continue;
|
||||
|
||||
FileNode *node = fs->GetByPath(name, devNode);
|
||||
if (node)
|
||||
ReturnLogError(-EEXIST, "Device file %s already exists", name);
|
||||
|
||||
node = fs->Create(devNode, name, mode);
|
||||
if (node == nullptr)
|
||||
ReturnLogError(-ENOMEM, "Failed to create device file %s", name);
|
||||
|
||||
node->Node->SetDevice(DriverID, i);
|
||||
|
||||
DriverHandlers dh{};
|
||||
dh.Ops = Operations;
|
||||
dh.Node = node->Node;
|
||||
dh.InputReports = new RingBuffer<InputReport>(16);
|
||||
dop->insert({i, std::move(dh)});
|
||||
return i;
|
||||
}
|
||||
|
||||
ReturnLogError(-1, "No available slots for device %d", DriverID);
|
||||
return -1; /* -Werror=return-type */
|
||||
}
|
||||
|
||||
int Manager::UnregisterDevice(dev_t DriverID, dev_t Device)
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(DriverID);
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
const auto dOps = dop->find(Device);
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Device);
|
||||
dop->erase(dOps);
|
||||
fixme("remove eventX from /dev/input");
|
||||
fixme("delete InputReports");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *Manager::AllocateMemory(dev_t DriverID, size_t Pages)
|
||||
{
|
||||
auto itr = Drivers.find(DriverID);
|
||||
assert(itr != Drivers.end());
|
||||
void *ptr = itr->second.vma->RequestPages(Pages);
|
||||
memset(ptr, 0, FROM_PAGES(Pages));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void Manager::FreeMemory(dev_t DriverID, void *Pointer, size_t Pages)
|
||||
{
|
||||
auto itr = Drivers.find(DriverID);
|
||||
assert(itr != Drivers.end());
|
||||
itr->second.vma->FreePages(Pointer, Pages);
|
||||
}
|
||||
|
||||
int Manager::ReportInputEvent(dev_t DriverID, InputReport *Report)
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(DriverID);
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Report->Device);
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Report->Device);
|
||||
|
||||
dOps->second.InputReports->Write(Report, 1);
|
||||
|
||||
switch (Report->Type)
|
||||
{
|
||||
case INPUT_TYPE_KEYBOARD:
|
||||
{
|
||||
KeyboardReport *kReport = &Report->Keyboard;
|
||||
GlobalKeyboardInputReports.Write(kReport, 1);
|
||||
break;
|
||||
}
|
||||
case INPUT_TYPE_MOUSE:
|
||||
{
|
||||
MouseReport *mReport = &Report->Mouse;
|
||||
GlobalMouseInputReports.Write(mReport, 1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(!"Invalid input type");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Manager::InitializeDaemonFS()
|
||||
{
|
||||
dev_t MinorID = 0;
|
||||
DeviceInode *_dev = new DeviceInode;
|
||||
_dev->Name = "dev";
|
||||
|
||||
/* d rwx r-- r-- */
|
||||
mode_t mode = S_IRWXU |
|
||||
S_IRGRP |
|
||||
S_IROTH |
|
||||
S_IFDIR;
|
||||
Inode *dev = (Inode *)_dev;
|
||||
dev->Mode = mode;
|
||||
dev->Flags = I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
|
||||
|
||||
FileSystemInfo *fsi = new FileSystemInfo;
|
||||
fsi->Name = "Device Virtual File System";
|
||||
fsi->RootName = "dev";
|
||||
fsi->Flags = I_FLAG_ROOT | I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
|
||||
fsi->SuperOps = {};
|
||||
fsi->Ops.Lookup = __fs_Lookup;
|
||||
fsi->Ops.Create = __fs_Create;
|
||||
fsi->Ops.Remove = nullptr;
|
||||
fsi->Ops.Rename = nullptr;
|
||||
fsi->Ops.Read = __fs_Read;
|
||||
fsi->Ops.Write = __fs_Write;
|
||||
fsi->Ops.Truncate = nullptr;
|
||||
fsi->Ops.Open = __fs_Open;
|
||||
fsi->Ops.Close = __fs_Close;
|
||||
fsi->Ops.Ioctl = __fs_Ioctl;
|
||||
fsi->Ops.ReadDir = __fs_Readdir;
|
||||
fsi->Ops.MkDir = nullptr;
|
||||
fsi->Ops.RmDir = nullptr;
|
||||
fsi->Ops.SymLink = nullptr;
|
||||
fsi->Ops.ReadLink = nullptr;
|
||||
fsi->Ops.Seek = nullptr;
|
||||
fsi->Ops.Stat = nullptr;
|
||||
|
||||
dev->Device = fs->RegisterFileSystem(fsi, dev);
|
||||
dev->SetDevice(0, MinorID++);
|
||||
MinorID++; /* 1 = /proc/self */
|
||||
|
||||
devNode = fs->Mount(fs->GetRoot(0), dev, "/dev");
|
||||
_dev->Parent = devNode->Parent;
|
||||
_dev->ParentInode = devNode->Parent->Node;
|
||||
|
||||
/* d rwx r-- r-- */
|
||||
mode = S_IRWXU |
|
||||
S_IRGRP |
|
||||
S_IROTH |
|
||||
S_IFDIR;
|
||||
DeviceInode *input = new DeviceInode;
|
||||
input->Parent = devNode;
|
||||
input->ParentInode = devNode->Node;
|
||||
input->Name = "input";
|
||||
input->Node.Device = dev->Device;
|
||||
input->Node.Mode = mode;
|
||||
input->Node.Flags = I_FLAG_CACHE_KEEP;
|
||||
input->Node.Offset = _dev->Children.size();
|
||||
_dev->Children.push_back(input);
|
||||
devInputNode = fs->GetByPath("input", devNode);
|
||||
|
||||
auto createDevice = [](DeviceInode *p1, FileNode *p2, const std::string &name, dev_t maj, dev_t min, mode_t mode)
|
||||
{
|
||||
DeviceInode *device = new DeviceInode;
|
||||
device->Parent = p2;
|
||||
device->ParentInode = p2->Node;
|
||||
device->Name = name;
|
||||
device->Node.Device = p2->Node->Device;
|
||||
device->Node.Mode = mode;
|
||||
device->Node.SetDevice(maj, min);
|
||||
device->Node.Flags = I_FLAG_CACHE_KEEP;
|
||||
device->Node.Offset = p1->Children.size();
|
||||
p1->Children.push_back(device);
|
||||
};
|
||||
|
||||
MinorID = 0;
|
||||
|
||||
/* c rw- r-- --- */
|
||||
mode = S_IRUSR | S_IWUSR |
|
||||
S_IRGRP |
|
||||
|
||||
S_IFCHR;
|
||||
createDevice(input, devInputNode, "keyboard", 1, MinorID++, mode);
|
||||
|
||||
/* c rw- r-- --- */
|
||||
mode = S_IRUSR | S_IWUSR |
|
||||
S_IRGRP |
|
||||
|
||||
S_IFCHR;
|
||||
createDevice(input, devInputNode, "mouse", 1, MinorID++, mode);
|
||||
}
|
||||
}
|
483
Kernel/core/driver/dev.cpp
Normal file
483
Kernel/core/driver/dev.cpp
Normal file
@ -0,0 +1,483 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <driver.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
namespace Driver
|
||||
{
|
||||
dev_t DeviceDirID;
|
||||
|
||||
int __fs_Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result)
|
||||
{
|
||||
func("%#lx %s %#lx", _Parent, Name, Result);
|
||||
|
||||
assert(_Parent != nullptr);
|
||||
|
||||
const char *basename;
|
||||
size_t length;
|
||||
cwk_path_get_basename(Name, &basename, &length);
|
||||
if (basename == NULL)
|
||||
{
|
||||
error("Invalid name %s", Name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
auto Parent = (Manager::DeviceInode *)_Parent;
|
||||
for (const auto &child : Parent->Children)
|
||||
{
|
||||
debug("Comparing %s with %s", basename, child->Name.c_str());
|
||||
if (strcmp(child->Name.c_str(), basename) != 0)
|
||||
continue;
|
||||
|
||||
*Result = &child->inode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug("Not found %s", Name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int __fs_Create(struct Inode *_Parent, const char *Name, mode_t Mode, struct Inode **Result)
|
||||
{
|
||||
func("%#lx %s %d", _Parent, Name, Mode);
|
||||
|
||||
assert(_Parent != nullptr);
|
||||
|
||||
/* We expect to be /dev or children of it */
|
||||
auto Parent = (Manager::DeviceInode *)_Parent;
|
||||
auto _dev = new Manager::DeviceInode;
|
||||
_dev->Parent = nullptr;
|
||||
_dev->ParentInode = _Parent;
|
||||
_dev->Name = Name;
|
||||
_dev->inode.Device = Parent->inode.Device;
|
||||
_dev->inode.Mode = Mode;
|
||||
_dev->inode.Index = Parent->inode.Index + Parent->Children.size();
|
||||
_dev->inode.Offset = Parent->Children.size();
|
||||
Parent->Children.push_back(_dev);
|
||||
|
||||
*Result = &_dev->inode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t __fs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
func("%#lx %d %d", Node, Size, Offset);
|
||||
|
||||
if ((dev_t)Node->GetMajor() == DeviceDirID)
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 0: /* /dev/input/keyboard */
|
||||
{
|
||||
if (Size < sizeof(KeyboardReport))
|
||||
return -EINVAL;
|
||||
|
||||
size_t nReads = Size / sizeof(KeyboardReport);
|
||||
|
||||
KeyboardReport *report = (KeyboardReport *)Buffer;
|
||||
|
||||
while (DriverManager->GlobalKeyboardInputReports.Count() == 0)
|
||||
TaskManager->Yield();
|
||||
|
||||
DriverManager->GlobalKeyboardInputReports.Read(report, nReads);
|
||||
return sizeof(KeyboardReport) * nReads;
|
||||
}
|
||||
case 1: /* /dev/input/mouse */
|
||||
{
|
||||
if (Size < sizeof(MouseReport))
|
||||
return -EINVAL;
|
||||
|
||||
size_t nReads = Size / sizeof(MouseReport);
|
||||
|
||||
MouseReport *report = (MouseReport *)Buffer;
|
||||
|
||||
while (DriverManager->GlobalMouseInputReports.Count() == 0)
|
||||
TaskManager->Yield();
|
||||
|
||||
DriverManager->GlobalMouseInputReports.Read(report, nReads);
|
||||
return sizeof(MouseReport) * nReads;
|
||||
}
|
||||
default:
|
||||
return -ENOENT;
|
||||
};
|
||||
}
|
||||
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(Node->GetMajor());
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Node->GetMinor());
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
|
||||
AssertReturnError(dOps->second.Ops, -ENOTSUP);
|
||||
AssertReturnError(dOps->second.Ops->Read, -ENOTSUP);
|
||||
return dOps->second.Ops->Read(Node, Buffer, Size, Offset);
|
||||
}
|
||||
|
||||
ssize_t __fs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
func("%#lx %p %d %d", Node, Buffer, Size, Offset);
|
||||
|
||||
if ((dev_t)Node->GetMajor() == DeviceDirID)
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 0: /* /dev/input/keyboard */
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
case 1: /* /dev/input/mouse */
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
default:
|
||||
return -ENOENT;
|
||||
};
|
||||
}
|
||||
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(Node->GetMajor());
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Node->GetMinor());
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
|
||||
AssertReturnError(dOps->second.Ops, -ENOTSUP);
|
||||
AssertReturnError(dOps->second.Ops->Write, -ENOTSUP);
|
||||
return dOps->second.Ops->Write(Node, Buffer, Size, Offset);
|
||||
}
|
||||
|
||||
int __fs_Open(struct Inode *Node, int Flags, mode_t Mode)
|
||||
{
|
||||
func("%#lx %d %d", Node, Flags, Mode);
|
||||
|
||||
if ((dev_t)Node->GetMajor() == DeviceDirID)
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 0: /* /dev/input/keyboard */
|
||||
case 1: /* /dev/input/mouse */
|
||||
return -ENOTSUP;
|
||||
default:
|
||||
return -ENOENT;
|
||||
};
|
||||
}
|
||||
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(Node->GetMajor());
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Node->GetMinor());
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
|
||||
AssertReturnError(dOps->second.Ops, -ENOTSUP);
|
||||
AssertReturnError(dOps->second.Ops->Open, -ENOTSUP);
|
||||
return dOps->second.Ops->Open(Node, Flags, Mode);
|
||||
}
|
||||
|
||||
int __fs_Close(struct Inode *Node)
|
||||
{
|
||||
func("%#lx", Node);
|
||||
|
||||
if ((dev_t)Node->GetMajor() == DeviceDirID)
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 0: /* /dev/input/keyboard */
|
||||
case 1: /* /dev/input/mouse */
|
||||
return -ENOTSUP;
|
||||
default:
|
||||
return -ENOENT;
|
||||
};
|
||||
}
|
||||
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(Node->GetMajor());
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Node->GetMinor());
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
|
||||
AssertReturnError(dOps->second.Ops, -ENOTSUP);
|
||||
AssertReturnError(dOps->second.Ops->Close, -ENOTSUP);
|
||||
return dOps->second.Ops->Close(Node);
|
||||
}
|
||||
|
||||
int __fs_Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
|
||||
{
|
||||
func("%#lx %lu %#lx", Node, Request, Argp);
|
||||
|
||||
if ((dev_t)Node->GetMajor() == DeviceDirID)
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 0: /* /dev/input/keyboard */
|
||||
case 1: /* /dev/input/mouse */
|
||||
return -ENOSYS;
|
||||
default:
|
||||
return -ENOENT;
|
||||
};
|
||||
}
|
||||
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(Node->GetMajor());
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", Node->GetMajor());
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Node->GetMinor());
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Node->GetMinor());
|
||||
AssertReturnError(dOps->second.Ops, -ENOTSUP);
|
||||
AssertReturnError(dOps->second.Ops->Ioctl, -ENOTSUP);
|
||||
return dOps->second.Ops->Ioctl(Node, Request, Argp);
|
||||
}
|
||||
|
||||
__no_sanitize("alignment") ssize_t __fs_Readdir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
|
||||
{
|
||||
func("%#lx %#lx %d %d %d", _Node, Buffer, Size, Offset, Entries);
|
||||
|
||||
auto node = (Manager::DeviceInode *)_Node;
|
||||
off_t realOffset = Offset;
|
||||
size_t totalSize = 0;
|
||||
uint16_t reclen = 0;
|
||||
struct kdirent *ent = nullptr;
|
||||
|
||||
if (!S_ISDIR(node->inode.Mode))
|
||||
return -ENOTDIR;
|
||||
|
||||
if (Offset == 0)
|
||||
{
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(".") + 1);
|
||||
if (totalSize + reclen > Size)
|
||||
return -EINVAL;
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = node->inode.Index;
|
||||
ent->d_off = 0;
|
||||
ent->d_reclen = reclen;
|
||||
ent->d_type = DT_DIR;
|
||||
strcpy(ent->d_name, ".");
|
||||
totalSize += reclen;
|
||||
Offset++;
|
||||
}
|
||||
|
||||
if (Offset == 1)
|
||||
{
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen("..") + 1);
|
||||
if (totalSize + reclen > Size)
|
||||
return totalSize;
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
if (node->Parent)
|
||||
ent->d_ino = node->Parent->inode->Index;
|
||||
else if (node->ParentInode)
|
||||
ent->d_ino = node->ParentInode->Index;
|
||||
else
|
||||
ent->d_ino = node->inode.Index;
|
||||
ent->d_off = 1;
|
||||
ent->d_reclen = reclen;
|
||||
ent->d_type = DT_DIR;
|
||||
strcpy(ent->d_name, "..");
|
||||
totalSize += reclen;
|
||||
Offset++;
|
||||
}
|
||||
|
||||
off_t entryIndex = 0;
|
||||
for (const auto &var : node->Children)
|
||||
{
|
||||
if (entryIndex + 2 < realOffset)
|
||||
{
|
||||
entryIndex++;
|
||||
continue;
|
||||
}
|
||||
if (Entries && entryIndex >= Entries)
|
||||
break;
|
||||
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(var->Name.c_str()) + 1);
|
||||
if (totalSize + reclen > Size)
|
||||
break;
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = var->inode.Index;
|
||||
ent->d_off = entryIndex + 2;
|
||||
ent->d_reclen = reclen;
|
||||
ent->d_type = IFTODT(var->inode.Mode);
|
||||
strcpy(ent->d_name, var->Name.c_str());
|
||||
totalSize += reclen;
|
||||
entryIndex++;
|
||||
}
|
||||
|
||||
if (totalSize + offsetof(struct kdirent, d_name) + 1 > Size)
|
||||
return totalSize;
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = 0;
|
||||
ent->d_off = 0;
|
||||
ent->d_reclen = 0;
|
||||
ent->d_type = DT_UNKNOWN;
|
||||
ent->d_name[0] = '\0';
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
int __fs_Stat(struct Inode *_Node, struct kstat *Stat)
|
||||
{
|
||||
func("%#lx %#lx", _Node, Stat);
|
||||
auto node = (Manager::DeviceInode *)_Node;
|
||||
|
||||
assert(node != nullptr);
|
||||
assert(Stat != nullptr);
|
||||
|
||||
Stat->Device = node->inode.Device;
|
||||
Stat->Index = node->inode.Index;
|
||||
Stat->HardLinks = 1;
|
||||
Stat->UserID = 0;
|
||||
Stat->GroupID = 0;
|
||||
Stat->RawDevice = node->inode.RawDevice;
|
||||
Stat->Size = node->Size;
|
||||
Stat->AccessTime = node->AccessTime;
|
||||
Stat->ModifyTime = node->ModifyTime;
|
||||
Stat->ChangeTime = node->ChangeTime;
|
||||
Stat->BlockSize = node->BlockSize;
|
||||
Stat->Blocks = node->Blocks;
|
||||
Stat->Attribute = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Manager::InitializeDeviceDirectory()
|
||||
{
|
||||
dev_t MinorID = 0;
|
||||
DeviceInode *_dev = new DeviceInode;
|
||||
_dev->Name = "dev";
|
||||
|
||||
/* d rwx r-- r-- */
|
||||
mode_t mode = S_IRWXU |
|
||||
S_IRGRP |
|
||||
S_IROTH |
|
||||
S_IFDIR;
|
||||
Inode *dev = (Inode *)_dev;
|
||||
dev->Mode = mode;
|
||||
|
||||
FileSystemInfo *fsi = new FileSystemInfo;
|
||||
fsi->Name = "Device Virtual File System";
|
||||
fsi->SuperOps = {};
|
||||
fsi->Ops.Lookup = __fs_Lookup;
|
||||
fsi->Ops.Create = __fs_Create;
|
||||
fsi->Ops.Remove = nullptr;
|
||||
fsi->Ops.Rename = nullptr;
|
||||
fsi->Ops.Read = __fs_Read;
|
||||
fsi->Ops.Write = __fs_Write;
|
||||
fsi->Ops.Truncate = nullptr;
|
||||
fsi->Ops.Open = __fs_Open;
|
||||
fsi->Ops.Close = __fs_Close;
|
||||
fsi->Ops.Ioctl = __fs_Ioctl;
|
||||
fsi->Ops.ReadDir = __fs_Readdir;
|
||||
fsi->Ops.MkDir = nullptr;
|
||||
fsi->Ops.RmDir = nullptr;
|
||||
fsi->Ops.SymLink = nullptr;
|
||||
fsi->Ops.ReadLink = nullptr;
|
||||
fsi->Ops.Seek = nullptr;
|
||||
fsi->Ops.Stat = __fs_Stat;
|
||||
|
||||
DeviceDirID = dev->Device = fs->RegisterFileSystem(fsi);
|
||||
dev->SetDevice(0, MinorID++);
|
||||
|
||||
Node root = fs->GetRoot(0);
|
||||
devNode = fs->Mount(root, dev, "dev", fsi);
|
||||
assert(devNode->Parent != nullptr);
|
||||
|
||||
_dev->Parent = devNode->Parent;
|
||||
_dev->ParentInode = devNode->Parent->inode;
|
||||
|
||||
/* d rwx r-- r-- */
|
||||
mode = S_IRWXU |
|
||||
S_IRGRP |
|
||||
S_IROTH |
|
||||
S_IFDIR;
|
||||
DeviceInode *blk = new DeviceInode;
|
||||
blk->Parent = devNode;
|
||||
blk->ParentInode = devNode->inode;
|
||||
blk->Name = "block";
|
||||
blk->inode.Device = dev->Device;
|
||||
blk->inode.Mode = mode;
|
||||
blk->inode.Offset = _dev->Children.size();
|
||||
_dev->Children.push_back(blk);
|
||||
devBlockNode = fs->Lookup(devNode, "block");
|
||||
|
||||
/* d rwx r-- r-- */
|
||||
mode = S_IRWXU |
|
||||
S_IRGRP |
|
||||
S_IROTH |
|
||||
S_IFDIR;
|
||||
DeviceInode *input = new DeviceInode;
|
||||
input->Parent = devNode;
|
||||
input->ParentInode = devNode->inode;
|
||||
input->Name = "input";
|
||||
input->inode.Device = dev->Device;
|
||||
input->inode.Mode = mode;
|
||||
input->inode.Offset = _dev->Children.size();
|
||||
_dev->Children.push_back(input);
|
||||
devInputNode = fs->Lookup(devNode, "input");
|
||||
|
||||
auto createDevice = [](DeviceInode *p1, Node p2, const std::string &name, dev_t maj, dev_t min, mode_t mode)
|
||||
{
|
||||
DeviceInode *device = new DeviceInode;
|
||||
device->Parent = p2;
|
||||
device->ParentInode = p2->inode;
|
||||
device->Name = name;
|
||||
device->inode.Device = p2->inode->Device;
|
||||
device->inode.Mode = mode;
|
||||
device->inode.SetDevice(maj, min);
|
||||
device->inode.Offset = p1->Children.size();
|
||||
p1->Children.push_back(device);
|
||||
};
|
||||
|
||||
MinorID = 0;
|
||||
|
||||
/* c rw- r-- --- */
|
||||
mode = S_IRUSR | S_IWUSR |
|
||||
S_IRGRP |
|
||||
|
||||
S_IFCHR;
|
||||
createDevice(input, devInputNode, "keyboard", DeviceDirID, MinorID++, mode);
|
||||
|
||||
/* c rw- r-- --- */
|
||||
mode = S_IRUSR | S_IWUSR |
|
||||
S_IRGRP |
|
||||
|
||||
S_IFCHR;
|
||||
createDevice(input, devInputNode, "mouse", DeviceDirID, MinorID++, mode);
|
||||
}
|
||||
}
|
@ -38,12 +38,12 @@ extern const __SIZE_TYPE__ trusted_drivers_count;
|
||||
|
||||
namespace Driver
|
||||
{
|
||||
bool Manager::IsDriverTrusted(FileNode *File)
|
||||
bool Manager::IsDriverTrusted(Node File)
|
||||
{
|
||||
kstat st;
|
||||
File->Stat(&st);
|
||||
fs->Stat(File, &st);
|
||||
std::unique_ptr<uint8_t[]> ptr(new uint8_t[st.Size]);
|
||||
File->Read(ptr.get(), st.Size, 0);
|
||||
fs->Read(File, ptr.get(), st.Size, 0);
|
||||
uint8_t *sha = sha512_sum(ptr.get(), st.Size);
|
||||
char hash_str[129];
|
||||
for (int j = 0; j < 64; j++)
|
||||
@ -102,7 +102,8 @@ namespace Driver
|
||||
}
|
||||
|
||||
const char *DriverDirectory = Config.DriverDirectory;
|
||||
FileNode *drvDirNode = fs->GetByPath(DriverDirectory, nullptr);
|
||||
Node root = fs->GetRoot(0);
|
||||
Node drvDirNode = fs->Lookup(root, DriverDirectory);
|
||||
if (!drvDirNode)
|
||||
{
|
||||
error("Failed to open driver directory %s", DriverDirectory);
|
||||
@ -110,7 +111,7 @@ namespace Driver
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &drvNode : drvDirNode->Children)
|
||||
for (const auto &drvNode : fs->ReadDirectory(drvDirNode))
|
||||
{
|
||||
debug("Checking driver %s", drvNode->Path.c_str());
|
||||
if (!drvNode->IsRegularFile())
|
||||
@ -273,12 +274,12 @@ namespace Driver
|
||||
}
|
||||
}
|
||||
|
||||
int Manager::LoadDriverFile(DriverObject &Drv, FileNode *File)
|
||||
int Manager::LoadDriverFile(DriverObject &Drv, Node File)
|
||||
{
|
||||
trace("Loading driver %s in memory", File->Name.c_str());
|
||||
|
||||
Elf_Ehdr ELFHeader{};
|
||||
File->Read(&ELFHeader, sizeof(Elf_Ehdr), 0);
|
||||
fs->Read(File, &ELFHeader, sizeof(Elf_Ehdr), 0);
|
||||
|
||||
AssertReturnError(ELFHeader.e_ident[EI_CLASS] == ELFCLASS64, -ENOEXEC);
|
||||
AssertReturnError(ELFHeader.e_ident[EI_DATA] == ELFDATA2LSB, -ENOEXEC);
|
||||
@ -295,7 +296,7 @@ namespace Driver
|
||||
Elf_Phdr phdr{};
|
||||
for (Elf_Half i = 0; i < ELFHeader.e_phnum; i++)
|
||||
{
|
||||
File->Read(&phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr)));
|
||||
fs->Read(File, &phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr)));
|
||||
if (phdr.p_type == PT_LOAD || phdr.p_type == PT_DYNAMIC)
|
||||
{
|
||||
if (segSize < phdr.p_vaddr + phdr.p_memsz)
|
||||
@ -306,7 +307,7 @@ namespace Driver
|
||||
if (phdr.p_type == PT_INTERP)
|
||||
{
|
||||
char interp[17];
|
||||
File->Read(interp, sizeof(interp), phdr.p_offset);
|
||||
fs->Read(File, interp, sizeof(interp), phdr.p_offset);
|
||||
if (strncmp(interp, "/boot/fennix.elf", sizeof(interp)) != 0)
|
||||
{
|
||||
error("Interpreter is not /boot/fennix.elf");
|
||||
@ -326,13 +327,13 @@ namespace Driver
|
||||
Elf_Shdr shstrtab{};
|
||||
Elf_Shdr shdr{};
|
||||
__DriverInfo driverInfo{};
|
||||
File->Read(&shstrtab, sizeof(Elf_Shdr), ELFHeader.e_shoff + (ELFHeader.e_shstrndx * ELFHeader.e_shentsize));
|
||||
fs->Read(File, &shstrtab, sizeof(Elf_Shdr), ELFHeader.e_shoff + (ELFHeader.e_shstrndx * ELFHeader.e_shentsize));
|
||||
for (Elf_Half i = 0; i < ELFHeader.e_shnum; i++)
|
||||
{
|
||||
if (i == ELFHeader.e_shstrndx)
|
||||
continue;
|
||||
|
||||
File->Read(&shdr, ELFHeader.e_shentsize, ELFHeader.e_shoff + (i * ELFHeader.e_shentsize));
|
||||
fs->Read(File, &shdr, ELFHeader.e_shentsize, ELFHeader.e_shoff + (i * ELFHeader.e_shentsize));
|
||||
|
||||
switch (shdr.sh_type)
|
||||
{
|
||||
@ -350,11 +351,11 @@ namespace Driver
|
||||
}
|
||||
|
||||
char symName[16];
|
||||
File->Read(symName, sizeof(symName), shstrtab.sh_offset + shdr.sh_name);
|
||||
fs->Read(File, symName, sizeof(symName), shstrtab.sh_offset + shdr.sh_name);
|
||||
if (strcmp(symName, ".driver.info") != 0)
|
||||
continue;
|
||||
|
||||
File->Read(&driverInfo, sizeof(__DriverInfo), shdr.sh_offset);
|
||||
fs->Read(File, &driverInfo, sizeof(__DriverInfo), shdr.sh_offset);
|
||||
|
||||
/* Perform relocations */
|
||||
driverInfo.Name = (const char *)(Drv.BaseAddress + (uintptr_t)driverInfo.Name);
|
||||
@ -367,13 +368,13 @@ namespace Driver
|
||||
{
|
||||
Elf_Sym symEntry{};
|
||||
uintptr_t symOffset = sht_symtab.sh_offset + (h * sizeof(Elf_Sym));
|
||||
File->Read(&symEntry, sizeof(Elf_Sym), symOffset);
|
||||
fs->Read(File, &symEntry, sizeof(Elf_Sym), symOffset);
|
||||
|
||||
if (symEntry.st_name == 0)
|
||||
continue;
|
||||
|
||||
char symName[16];
|
||||
File->Read(symName, sizeof(symName), sht_strtab.sh_offset + symEntry.st_name);
|
||||
fs->Read(File, symName, sizeof(symName), sht_strtab.sh_offset + symEntry.st_name);
|
||||
|
||||
switch (symEntry.st_shndx)
|
||||
{
|
||||
@ -405,7 +406,7 @@ namespace Driver
|
||||
|
||||
for (Elf_Half i = 0; i < ELFHeader.e_phnum; i++)
|
||||
{
|
||||
File->Read(&phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr)));
|
||||
fs->Read(File, &phdr, sizeof(Elf_Phdr), ELFHeader.e_phoff + (i * sizeof(Elf_Phdr)));
|
||||
|
||||
switch (phdr.p_type)
|
||||
{
|
||||
@ -421,7 +422,7 @@ namespace Driver
|
||||
phdr.p_filesz, phdr.p_memsz);
|
||||
|
||||
if (phdr.p_filesz > 0)
|
||||
File->Read(dest, phdr.p_filesz, phdr.p_offset);
|
||||
fs->Read(File, (void *)dest, phdr.p_filesz, phdr.p_offset);
|
||||
|
||||
if (phdr.p_memsz - phdr.p_filesz > 0)
|
||||
{
|
||||
@ -620,7 +621,8 @@ namespace Driver
|
||||
delete Drv.DeviceOperations;
|
||||
|
||||
/* Reload the driver */
|
||||
FileNode *drvNode = fs->GetByPath(Drv.Path.c_str(), nullptr);
|
||||
Node root = fs->GetRoot(0);
|
||||
Node drvNode = fs->Lookup(root, Drv.Path);
|
||||
if (!drvNode)
|
||||
{
|
||||
error("Failed to open driver file %s", Drv.Path.c_str());
|
||||
@ -684,7 +686,7 @@ namespace Driver
|
||||
newDrvObj.Initialized = true;
|
||||
}
|
||||
|
||||
Manager::Manager() { this->InitializeDaemonFS(); }
|
||||
Manager::Manager() { this->InitializeDeviceDirectory(); }
|
||||
|
||||
Manager::~Manager()
|
||||
{
|
||||
|
256
Kernel/core/driver/manager.cpp
Normal file
256
Kernel/core/driver/manager.cpp
Normal file
@ -0,0 +1,256 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <driver.hpp>
|
||||
|
||||
#include <interface/driver.h>
|
||||
#include <interface/input.h>
|
||||
#include <memory.hpp>
|
||||
#include <stropts.h>
|
||||
#include <ints.hpp>
|
||||
#include <task.hpp>
|
||||
#include <printf.h>
|
||||
#include <exec.hpp>
|
||||
#include <rand.hpp>
|
||||
#include <cwalk.h>
|
||||
#include <md5.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
using namespace vfs;
|
||||
|
||||
namespace Driver
|
||||
{
|
||||
dev_t Manager::RegisterDevice(dev_t DriverID, DeviceType Type, const InodeOperations *Operations)
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(DriverID);
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
for (size_t i = 0; i < 128; i++)
|
||||
{
|
||||
const auto dOps = dop->find(i);
|
||||
const auto dOpsEnd = dop->end();
|
||||
if (dOps != dOpsEnd)
|
||||
continue;
|
||||
|
||||
DeviceType devType = (DeviceType)(Type & DEVICE_TYPE_MASK);
|
||||
switch (devType)
|
||||
{
|
||||
case DEVICE_TYPE_INPUT:
|
||||
{
|
||||
std::string prefix = "event";
|
||||
for (size_t j = 0; j < 128; j++)
|
||||
{
|
||||
std::string deviceName = prefix + std::to_string(j);
|
||||
Node node = fs->Lookup(devInputNode, deviceName);
|
||||
if (node)
|
||||
continue;
|
||||
|
||||
/* c rwx r-- r-- */
|
||||
mode_t mode = S_IRWXU |
|
||||
S_IRGRP |
|
||||
S_IROTH |
|
||||
S_IFCHR;
|
||||
|
||||
node = fs->Create(devInputNode, deviceName, mode);
|
||||
node->inode->SetDevice(DriverID, i);
|
||||
|
||||
DriverHandlers dh{};
|
||||
dh.Ops = Operations;
|
||||
dh.Node = node->inode;
|
||||
dh.InputReports = new RingBuffer<InputReport>(16);
|
||||
dop->insert({i, std::move(dh)});
|
||||
return i;
|
||||
}
|
||||
|
||||
ReturnLogError(-EOVERFLOW, "No available slots for device %d", DriverID);
|
||||
}
|
||||
default:
|
||||
ReturnLogError(-EINVAL, "Invalid device type %d", Type);
|
||||
}
|
||||
}
|
||||
|
||||
ReturnLogError(-EOVERFLOW, "No available slots for device %d", DriverID);
|
||||
}
|
||||
|
||||
dev_t Manager::CreateDeviceFile(dev_t DriverID, const char *name, mode_t mode, const InodeOperations *Operations)
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(DriverID);
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
for (size_t i = 0; i < 128; i++)
|
||||
{
|
||||
const auto dOps = dop->find(i);
|
||||
if (dOps != dop->end())
|
||||
continue;
|
||||
|
||||
eNode node = fs->Lookup(devNode, name);
|
||||
if (node == true)
|
||||
ReturnLogError(-EEXIST, "Device file %s already exists", name);
|
||||
|
||||
node = fs->Create(devNode, name, mode);
|
||||
if (node == false)
|
||||
ReturnLogError(-node.Error, "Failed to create device file %s; %s", name, node.what());
|
||||
|
||||
node.Value->inode->SetDevice(DriverID, i);
|
||||
|
||||
DriverHandlers dh{};
|
||||
dh.Ops = Operations;
|
||||
dh.Node = node.Value->inode;
|
||||
dh.InputReports = new RingBuffer<InputReport>(16);
|
||||
dop->insert({i, std::move(dh)});
|
||||
return i;
|
||||
}
|
||||
|
||||
ReturnLogError(-EOVERFLOW, "No available slots for device %d", DriverID);
|
||||
}
|
||||
|
||||
int Manager::UnregisterDevice(dev_t DriverID, dev_t Device)
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(DriverID);
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
const auto dOps = dop->find(Device);
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Device);
|
||||
dop->erase(dOps);
|
||||
fixme("remove eventX from /dev/input");
|
||||
fixme("delete InputReports");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_t Manager::RegisterBlockDevice(dev_t DriverID, struct BlockDevice *Device)
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(DriverID);
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
std::string prefix = Device->Name;
|
||||
for (size_t j = 0; j < 128; j++)
|
||||
{
|
||||
std::string deviceName = prefix + std::to_string(j);
|
||||
Node node = fs->Lookup(devBlockNode, deviceName);
|
||||
if (node)
|
||||
continue;
|
||||
debug("Creating \"%s\"", deviceName.c_str());
|
||||
|
||||
/* b rwx --- --- */
|
||||
mode_t mode = S_IRWXU |
|
||||
S_IFBLK;
|
||||
|
||||
node = fs->Create(devBlockNode, deviceName, mode);
|
||||
node->inode->SetDevice(DriverID, j);
|
||||
auto devNode = (Manager::DeviceInode *)node->inode;
|
||||
devNode->Size = Device->Size;
|
||||
devNode->BlockSize = Device->BlockSize;
|
||||
devNode->Blocks = Device->BlockCount;
|
||||
devNode->inode.PrivateData = Device->PrivateData;
|
||||
|
||||
DriverHandlers dh{};
|
||||
dh.Ops = Device->Ops;
|
||||
dh.Node = node->inode;
|
||||
dop->insert({j, std::move(dh)});
|
||||
debug("dh ops:%#lx node:%#lx %d", dh.Ops, dh.Node, j);
|
||||
return j;
|
||||
}
|
||||
|
||||
ReturnLogError(-EOVERFLOW, "No available slots for device %d", DriverID);
|
||||
}
|
||||
|
||||
int Manager::UnregisterBlockDevice(dev_t DriverID, dev_t DeviceID)
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers = DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(DriverID);
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
const auto dOps = dop->find(DeviceID);
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", DeviceID);
|
||||
dop->erase(dOps);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *Manager::AllocateMemory(dev_t DriverID, size_t Pages)
|
||||
{
|
||||
auto itr = Drivers.find(DriverID);
|
||||
assert(itr != Drivers.end());
|
||||
void *ptr = itr->second.vma->RequestPages(Pages);
|
||||
memset(ptr, 0, FROM_PAGES(Pages));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void Manager::FreeMemory(dev_t DriverID, void *Pointer, size_t Pages)
|
||||
{
|
||||
auto itr = Drivers.find(DriverID);
|
||||
assert(itr != Drivers.end());
|
||||
itr->second.vma->FreePages(Pointer, Pages);
|
||||
}
|
||||
|
||||
int Manager::ReportInputEvent(dev_t DriverID, InputReport *Report)
|
||||
{
|
||||
std::unordered_map<dev_t, Driver::DriverObject> &drivers =
|
||||
DriverManager->GetDrivers();
|
||||
const auto it = drivers.find(DriverID);
|
||||
if (it == drivers.end())
|
||||
ReturnLogError(-EINVAL, "Driver %d not found", DriverID);
|
||||
const Driver::DriverObject *drv = &it->second;
|
||||
|
||||
auto dop = drv->DeviceOperations;
|
||||
auto dOps = dop->find(Report->Device);
|
||||
if (dOps == dop->end())
|
||||
ReturnLogError(-EINVAL, "Device %d not found", Report->Device);
|
||||
|
||||
dOps->second.InputReports->Write(Report, 1);
|
||||
|
||||
switch (Report->Type)
|
||||
{
|
||||
case INPUT_TYPE_KEYBOARD:
|
||||
{
|
||||
KeyboardReport *kReport = &Report->Keyboard;
|
||||
GlobalKeyboardInputReports.Write(kReport, 1);
|
||||
break;
|
||||
}
|
||||
case INPUT_TYPE_MOUSE:
|
||||
{
|
||||
MouseReport *mReport = &Report->Mouse;
|
||||
GlobalMouseInputReports.Write(mReport, 1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(!"Invalid input type");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
#include <memory.hpp>
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
#include <signal.hpp>
|
||||
#include <utsname.h>
|
||||
#include <time.h>
|
||||
|
@ -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 |
|
||||
|
@ -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();
|
||||
|
@ -20,9 +20,9 @@
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
|
||||
namespace vfs
|
||||
namespace Driver::ExtendedFilesystem
|
||||
{
|
||||
class EXT2
|
||||
{
|
200
Kernel/drivers/fs/ustar/ustar.cpp
Normal file
200
Kernel/drivers/fs/ustar/ustar.cpp
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <driver.hpp>
|
||||
#include <fs/ustar.hpp>
|
||||
#include <interface/fs.h>
|
||||
#include <memory.hpp>
|
||||
#include <debug.h>
|
||||
|
||||
using namespace vfs;
|
||||
|
||||
namespace Driver::UnixStandardTAR
|
||||
{
|
||||
dev_t DriverID;
|
||||
|
||||
int USTAR_AllocateInode(FileSystemInfo *Info, Inode **Result)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_DeleteInode(FileSystemInfo *Info, Inode *Node)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Synchronize(FileSystemInfo *Info, Inode *Node)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Destroy(FileSystemInfo *Info)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Probe(void *Device)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Mount(FileSystemInfo *FS, Inode **Root, void *Device)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Unmount(FileSystemInfo *FS)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Lookup(Inode *Parent, const char *Name, Inode **Result)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Create(Inode *Parent, const char *Name, mode_t Mode, Inode **Result)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Remove(Inode *Parent, const char *Name)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Rename(Inode *Parent, const char *OldName, const char *NewName)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
ssize_t USTAR_Read(Inode *Node, void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
ssize_t USTAR_Write(Inode *Node, const void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Truncate(Inode *Node, off_t Size)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Open(Inode *Node, int Flags, mode_t Mode)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Close(Inode *Node)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Ioctl(Inode *Node, unsigned long Request, void *Argp)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
ssize_t USTAR_ReadDir(Inode *Node, kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_MkDir(Inode *Parent, const char *Name, mode_t Mode, Inode **Result)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_RmDir(Inode *Parent, const char *Name)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_SymLink(Inode *Parent, const char *Name, const char *Target, Inode **Result)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
ssize_t USTAR_ReadLink(Inode *Node, char *Buffer, size_t Size)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
off_t USTAR_Seek(Inode *Node, off_t Offset)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
int USTAR_Stat(Inode *Node, kstat *Stat)
|
||||
{
|
||||
assert(!"NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
static SuperBlockOperations ustarSuperOps = {
|
||||
.AllocateInode = USTAR_AllocateInode,
|
||||
.DeleteInode = USTAR_DeleteInode,
|
||||
.Synchronize = USTAR_Synchronize,
|
||||
.Destroy = USTAR_Destroy,
|
||||
.Probe = USTAR_Probe,
|
||||
.Mount = USTAR_Mount,
|
||||
.Unmount = USTAR_Unmount};
|
||||
|
||||
static InodeOperations ustarInodeOps = {
|
||||
.Lookup = USTAR_Lookup,
|
||||
.Create = USTAR_Create,
|
||||
.Remove = USTAR_Remove,
|
||||
.Rename = USTAR_Rename,
|
||||
.Read = USTAR_Read,
|
||||
.Write = USTAR_Write,
|
||||
.Truncate = USTAR_Truncate,
|
||||
.Open = USTAR_Open,
|
||||
.Close = USTAR_Close,
|
||||
.Ioctl = USTAR_Ioctl,
|
||||
.ReadDir = USTAR_ReadDir,
|
||||
.MkDir = USTAR_MkDir,
|
||||
.RmDir = USTAR_RmDir,
|
||||
.SymLink = USTAR_SymLink,
|
||||
.ReadLink = USTAR_ReadLink,
|
||||
.Seek = USTAR_Seek,
|
||||
.Stat = USTAR_Stat};
|
||||
|
||||
int Entry()
|
||||
{
|
||||
FileSystemInfo *fsi = new FileSystemInfo;
|
||||
fsi->Name = "Unix Standard TAR";
|
||||
fsi->SuperOps = ustarSuperOps;
|
||||
fsi->Ops = ustarInodeOps;
|
||||
v0::RegisterFileSystem(DriverID, fsi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Final() { return 0; }
|
||||
int Panic() { return 0; }
|
||||
int Probe() { return 0; }
|
||||
|
||||
REGISTER_BUILTIN_DRIVER(ustar,
|
||||
"Unix Standard TAR Driver",
|
||||
"enderice2",
|
||||
1, 0, 0,
|
||||
Entry,
|
||||
Final,
|
||||
Panic,
|
||||
Probe);
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include <driver.hpp>
|
||||
#include <interface/block.h>
|
||||
#include <cpu.hpp>
|
||||
#include <pci.hpp>
|
||||
|
||||
@ -572,6 +573,9 @@ namespace Driver::AHCI
|
||||
HBAPort *HBAPortPtr;
|
||||
uint8_t *Buffer;
|
||||
uint8_t PortNumber;
|
||||
uint32_t BlockSize;
|
||||
uint32_t BlockCount;
|
||||
size_t Size;
|
||||
ATA_IDENTIFY *IdentifyData;
|
||||
|
||||
Port(PortType Type, HBAPort *PortPtr, uint8_t PortNumber)
|
||||
@ -614,6 +618,7 @@ namespace Driver::AHCI
|
||||
|
||||
void Configure()
|
||||
{
|
||||
debug("Configuring port %d", PortNumber);
|
||||
this->StopCMD();
|
||||
void *CmdBase = v0::AllocateMemory(DriverID, 1);
|
||||
HBAPortPtr->CommandListBase = (uint32_t)(uint64_t)CmdBase;
|
||||
@ -639,19 +644,35 @@ namespace Driver::AHCI
|
||||
|
||||
Identify();
|
||||
|
||||
if (IdentifyData->CommandSetSupport.BigLba)
|
||||
{
|
||||
if ((IdentifyData->CommandSetActive.Words119_120Valid & 0x1) != 0)
|
||||
{
|
||||
uint32_t wordsPerLogicalSector = (IdentifyData->WordsPerLogicalSector[1] << 16) | IdentifyData->WordsPerLogicalSector[0];
|
||||
if (wordsPerLogicalSector != 0)
|
||||
this->BlockSize = wordsPerLogicalSector * 2;
|
||||
}
|
||||
}
|
||||
this->BlockSize = 512;
|
||||
|
||||
this->BlockCount = this->IdentifyData->UserAddressableSectors;
|
||||
this->Size = this->BlockCount * this->BlockSize;
|
||||
|
||||
trace("Port %d \"%x %x %x %x\" configured", PortNumber,
|
||||
HBAPortPtr->Vendor[0], HBAPortPtr->Vendor[1],
|
||||
HBAPortPtr->Vendor[2], HBAPortPtr->Vendor[3]);
|
||||
}
|
||||
|
||||
bool ReadWrite(uint64_t Sector, uint32_t SectorCount, void *Buffer, bool Write)
|
||||
int ReadWrite(uint64_t Sector, uint32_t SectorCount, void *Buffer, bool Write)
|
||||
{
|
||||
if (this->AHCIPortType == PortType::SATAPI && Write == true)
|
||||
{
|
||||
trace("SATAPI port does not support write.");
|
||||
return false;
|
||||
return ENOTSUP;
|
||||
}
|
||||
|
||||
debug("%s op on port %d, sector %d, count %d", Write ? "Write" : "Read", this->PortNumber, Sector, SectorCount);
|
||||
|
||||
uint32_t SectorL = (uint32_t)Sector;
|
||||
uint32_t SectorH = (uint32_t)(Sector >> 32);
|
||||
|
||||
@ -706,7 +727,7 @@ namespace Driver::AHCI
|
||||
if (spinLock == 1000000)
|
||||
{
|
||||
trace("Port not responding.");
|
||||
return false;
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
|
||||
HBAPortPtr->CommandIssue = 1;
|
||||
@ -723,7 +744,7 @@ namespace Driver::AHCI
|
||||
spinLock = 0;
|
||||
retries++;
|
||||
if (retries > 10)
|
||||
return false;
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (HBAPortPtr->CommandIssue == 0)
|
||||
@ -733,11 +754,11 @@ namespace Driver::AHCI
|
||||
if (HBAPortPtr->InterruptStatus & HBA_PxIS_TFES)
|
||||
{
|
||||
trace("Error reading/writing (%d).", Write);
|
||||
return false;
|
||||
return EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Identify()
|
||||
@ -840,34 +861,61 @@ namespace Driver::AHCI
|
||||
}
|
||||
}
|
||||
|
||||
int Open(struct Inode *, int, mode_t)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Close(struct Inode *)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
uint64_t sector = Offset / 512;
|
||||
uint32_t sectorCount = uint32_t(Size / 512);
|
||||
int num = Node->GetMinor();
|
||||
bool ok = PortDevices[num]->ReadWrite(sector, sectorCount, Buffer, false);
|
||||
return ok ? Size : 0;
|
||||
Port *port = static_cast<Port *>(Node->PrivateData);
|
||||
if ((Offset % port->BlockSize) != 0 || (Size % port->BlockSize) != 0)
|
||||
{
|
||||
trace("Read offset or size not aligned to block size (BlockSize=%u)", port->BlockSize);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uint64_t sector = Offset / port->BlockSize;
|
||||
uint32_t sectorCount = uint32_t(Size / port->BlockSize);
|
||||
if (sectorCount == 0)
|
||||
{
|
||||
trace("Attempt to read 0 sectors");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool status = port->ReadWrite(sector, sectorCount, Buffer, false);
|
||||
if (status != 0)
|
||||
{
|
||||
trace("Error '%s' reading from port %d", strerror(status), port->PortNumber);
|
||||
return status;
|
||||
}
|
||||
return Size;
|
||||
}
|
||||
|
||||
ssize_t Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
uint64_t sector = Offset / 512;
|
||||
uint32_t sectorCount = uint32_t(Size / 512);
|
||||
int num = Node->GetMinor();
|
||||
bool ok = PortDevices[num]->ReadWrite(sector, sectorCount, (void *)Buffer, true);
|
||||
return ok ? Size : 0;
|
||||
Port *port = static_cast<Port *>(Node->PrivateData);
|
||||
if ((Offset % port->BlockSize) != 0 || (Size % port->BlockSize) != 0)
|
||||
{
|
||||
trace("Read offset or size not aligned to block size (BlockSize=%u)", port->BlockSize);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uint64_t sector = Offset / port->BlockSize;
|
||||
uint32_t sectorCount = uint32_t(Size / port->BlockSize);
|
||||
if (sectorCount == 0)
|
||||
{
|
||||
trace("Attempt to write 0 sectors");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool status = port->ReadWrite(sector, sectorCount, (void *)Buffer, true);
|
||||
if (status != 0)
|
||||
{
|
||||
trace("Error '%s' writing to port %d", strerror(status), port->PortNumber);
|
||||
return status;
|
||||
}
|
||||
return Size;
|
||||
}
|
||||
|
||||
int Open(struct Inode *, int, mode_t) { return 0; }
|
||||
int Close(struct Inode *) { return 0; }
|
||||
|
||||
const struct InodeOperations ops = {
|
||||
.Lookup = nullptr,
|
||||
.Create = nullptr,
|
||||
@ -915,8 +963,18 @@ namespace Driver::AHCI
|
||||
{
|
||||
KPrint("%s drive found at port %d", PortTypeName[portType], i);
|
||||
Port *port = new Port(portType, &hba->Ports[i], i);
|
||||
dev_t ret = v0::RegisterDevice(DriverID, BLOCK_TYPE_HDD, &ops);
|
||||
port->Configure();
|
||||
|
||||
BlockDevice *dev = new BlockDevice;
|
||||
dev->Name = "ahci";
|
||||
dev->BlockSize = port->BlockSize;
|
||||
dev->BlockCount = port->BlockCount;
|
||||
dev->Size = port->Size;
|
||||
dev->Ops = &ops;
|
||||
dev->PrivateData = port;
|
||||
dev_t ret = v0::RegisterBlockDevice(DriverID, dev);
|
||||
PortDevices[ret] = port;
|
||||
debug("Port %d \"%s\" registered as %d", i, port->IdentifyData->ModelNumber, ret);
|
||||
break;
|
||||
}
|
||||
case PortType::SEMB:
|
||||
@ -942,10 +1000,6 @@ namespace Driver::AHCI
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
trace("Initializing AHCI ports");
|
||||
for (auto &&p : PortDevices)
|
||||
p.second->Configure();
|
||||
|
||||
/* We don't use the interrupt handler now... maybe we will in the future */
|
||||
// RegisterInterruptHandler(iLine(ctx->Device), (void *)OnInterruptReceived);
|
||||
|
||||
@ -957,7 +1011,7 @@ namespace Driver::AHCI
|
||||
for (auto &&p : PortDevices)
|
||||
{
|
||||
p.second->StopCMD();
|
||||
v0::UnregisterDevice(DriverID, p.first);
|
||||
v0::UnregisterBlockDevice(DriverID, p.first);
|
||||
delete p.second;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 *);
|
||||
|
@ -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;
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
std::vector<Elf_Dyn> ELFGetDynamicTag(FileNode *fd, DynamicArrayTags Tag)
|
||||
std::vector<Elf_Dyn> ELFGetDynamicTag(Node &fd, DynamicArrayTags Tag)
|
||||
{
|
||||
std::vector<Elf_Dyn> ret;
|
||||
std::vector<Elf_Phdr> phdrs = ELFGetSymbolType(fd, PT_DYNAMIC);
|
||||
@ -37,7 +37,7 @@ namespace Execute
|
||||
Elf_Dyn dyn;
|
||||
for (size_t i = 0; i < phdr.p_filesz / sizeof(Elf_Dyn); i++)
|
||||
{
|
||||
fd->Read(&dyn, sizeof(Elf_Dyn), phdr.p_offset + (i * sizeof(Elf_Dyn)));
|
||||
fs->Read(fd, &dyn, sizeof(Elf_Dyn), phdr.p_offset + (i * sizeof(Elf_Dyn)));
|
||||
if (dyn.d_tag != Tag)
|
||||
continue;
|
||||
|
||||
|
@ -21,18 +21,18 @@
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
std::vector<Elf_Shdr> ELFGetSections(FileNode *fd, const char *SectionName)
|
||||
std::vector<Elf_Shdr> ELFGetSections(Node fd, const char *SectionName)
|
||||
{
|
||||
std::vector<Elf_Shdr> ret;
|
||||
|
||||
Elf_Ehdr ehdr;
|
||||
fd->Read(&ehdr, sizeof(Elf_Ehdr), 0);
|
||||
fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0);
|
||||
|
||||
std::unique_ptr<Elf_Shdr[]> sections(new Elf_Shdr[ehdr.e_shnum]);
|
||||
fd->Read(sections.get(), sizeof(Elf_Shdr) * ehdr.e_shnum, ehdr.e_shoff);
|
||||
fs->Read(fd, sections.get(), sizeof(Elf_Shdr) * ehdr.e_shnum, ehdr.e_shoff);
|
||||
|
||||
std::string sectionNames(sections[ehdr.e_shstrndx].sh_size, '\0');
|
||||
fd->Read(sectionNames.data(), sections[ehdr.e_shstrndx].sh_size, sections[ehdr.e_shstrndx].sh_offset);
|
||||
fs->Read(fd, sectionNames.data(), sections[ehdr.e_shstrndx].sh_size, sections[ehdr.e_shstrndx].sh_offset);
|
||||
|
||||
for (Elf_Half i = 0; i < ehdr.e_shnum; ++i)
|
||||
{
|
||||
|
@ -21,15 +21,15 @@
|
||||
|
||||
namespace Execute
|
||||
{
|
||||
std::vector<Elf_Phdr> ELFGetSymbolType(FileNode *fd, SegmentTypes Tag)
|
||||
std::vector<Elf_Phdr> ELFGetSymbolType(Node &fd, SegmentTypes Tag)
|
||||
{
|
||||
std::vector<Elf_Phdr> ret;
|
||||
|
||||
Elf_Ehdr ehdr;
|
||||
fd->Read(&ehdr, sizeof(Elf_Ehdr), 0);
|
||||
fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0);
|
||||
|
||||
Elf_Phdr phdr;
|
||||
fd->Read(&phdr, sizeof(Elf_Phdr), ehdr.e_phoff);
|
||||
fs->Read(fd, &phdr, sizeof(Elf_Phdr), ehdr.e_phoff);
|
||||
|
||||
off_t off = ehdr.e_phoff;
|
||||
for (Elf_Half i = 0; i < ehdr.e_phnum; i++)
|
||||
@ -38,7 +38,7 @@ namespace Execute
|
||||
ret.push_back(phdr);
|
||||
|
||||
off += sizeof(Elf_Phdr);
|
||||
fd->Read(&phdr, sizeof(Elf_Phdr), off);
|
||||
fs->Read(fd, &phdr, sizeof(Elf_Phdr), off);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -15,7 +15,7 @@
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
|
||||
#include <convert.h>
|
||||
#include <stropts.h>
|
||||
@ -47,8 +47,7 @@ namespace vfs
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FileDescriptorTable::AddFileDescriptor(const char *AbsolutePath,
|
||||
mode_t Mode, int Flags)
|
||||
int FileDescriptorTable::AddFileDescriptor(const char *AbsolutePath, mode_t Mode, int Flags)
|
||||
{
|
||||
Tasking::PCB *pcb = thisProcess;
|
||||
|
||||
@ -77,8 +76,7 @@ namespace vfs
|
||||
|
||||
if (Flags & O_RDWR)
|
||||
{
|
||||
if (!(Mode & S_IRUSR) ||
|
||||
!(Mode & S_IWUSR))
|
||||
if (!(Mode & S_IRUSR) || !(Mode & S_IWUSR))
|
||||
{
|
||||
debug("No read/write permission (%d)", Mode);
|
||||
return -EACCES;
|
||||
@ -95,12 +93,11 @@ namespace vfs
|
||||
|
||||
if (Flags & O_CREAT)
|
||||
{
|
||||
FileNode *ret = fs->Create(pcb->CWD, AbsolutePath, Mode);
|
||||
if (Flags & O_EXCL && ret == nullptr)
|
||||
eNode ret = fs->Create(pcb->CWD, AbsolutePath, Mode);
|
||||
if (Flags & O_EXCL && ret == false)
|
||||
{
|
||||
debug("%s: File already exists?, returning EEXIST",
|
||||
AbsolutePath);
|
||||
return -EEXIST;
|
||||
debug("%s: File already exists?, returning %s", AbsolutePath, ret.what());
|
||||
return -ret.Error;
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,18 +106,18 @@ namespace vfs
|
||||
fixme("O_CLOEXEC");
|
||||
}
|
||||
|
||||
FileNode *File = fs->GetByPath(AbsolutePath, pcb->CWD);
|
||||
|
||||
if (!File)
|
||||
eNode ret = fs->Lookup(pcb->CWD, AbsolutePath);
|
||||
if (ret == false)
|
||||
{
|
||||
error("Failed to open file %s", AbsolutePath);
|
||||
return -ENOENT;
|
||||
error("Failed to open file %s, %s", AbsolutePath, ret.what());
|
||||
return -ret.Error;
|
||||
}
|
||||
Node node = ret;
|
||||
|
||||
if (Flags & O_TRUNC)
|
||||
{
|
||||
debug("Truncating file %s", AbsolutePath);
|
||||
File->Truncate(0);
|
||||
fs->Truncate(node, 0);
|
||||
}
|
||||
|
||||
Fildes fd{};
|
||||
@ -129,13 +126,13 @@ namespace vfs
|
||||
{
|
||||
debug("Appending to file %s", AbsolutePath);
|
||||
struct kstat stat;
|
||||
File->Stat(&stat);
|
||||
fd.Offset = File->Seek(stat.Size);
|
||||
fs->Stat(node, &stat);
|
||||
fd.Offset = fs->Seek(node, stat.Size);
|
||||
}
|
||||
|
||||
fd.Mode = Mode;
|
||||
fd.Flags = Flags;
|
||||
fd.Node = File;
|
||||
fd.node = node;
|
||||
|
||||
int fdn = this->GetFreeFileDescriptor();
|
||||
if (fdn < 0)
|
||||
@ -145,9 +142,8 @@ namespace vfs
|
||||
|
||||
char linkName[64];
|
||||
snprintf(linkName, 64, "%d", fdn);
|
||||
assert(fs->CreateLink(linkName, this->fdDir, AbsolutePath) != nullptr);
|
||||
|
||||
File->Open(Flags, Mode);
|
||||
assert(fs->CreateLink(this->fdDir, linkName, AbsolutePath) == true);
|
||||
fs->Open(node, Flags, Mode);
|
||||
return fdn;
|
||||
}
|
||||
|
||||
@ -157,7 +153,7 @@ namespace vfs
|
||||
if (it == this->FileMap.end())
|
||||
ReturnLogError(-EBADF, "Invalid fd %d", FileDescriptor);
|
||||
|
||||
fs->Remove(it->second.Node);
|
||||
fs->Remove(it->second.node);
|
||||
this->FileMap.erase(it);
|
||||
return 0;
|
||||
}
|
||||
@ -209,7 +205,7 @@ namespace vfs
|
||||
if (it == this->FileMap.end())
|
||||
ReturnLogError(-EBADF, "Invalid fd %d", fd);
|
||||
|
||||
return it->second.Node->Read(buf, count, it->second.Offset);
|
||||
return fs->Read(it->second.node, buf, count, it->second.Offset);
|
||||
}
|
||||
|
||||
ssize_t FileDescriptorTable::usr_pread(int fd, void *buf, size_t count, off_t offset)
|
||||
@ -218,7 +214,7 @@ namespace vfs
|
||||
if (it == this->FileMap.end())
|
||||
ReturnLogError(-EBADF, "Invalid fd %d", fd);
|
||||
|
||||
return it->second.Node->Read(buf, count, offset);
|
||||
return fs->Read(it->second.node, buf, count, offset);
|
||||
}
|
||||
|
||||
ssize_t FileDescriptorTable::usr_write(int fd, const void *buf, size_t count)
|
||||
@ -227,7 +223,7 @@ namespace vfs
|
||||
if (it == this->FileMap.end())
|
||||
ReturnLogError(-EBADF, "Invalid fd %d", fd);
|
||||
|
||||
return it->second.Node->Write(buf, count, it->second.Offset);
|
||||
return fs->Write(it->second.node, buf, count, it->second.Offset);
|
||||
}
|
||||
|
||||
ssize_t FileDescriptorTable::usr_pwrite(int fd, const void *buf, size_t count, off_t offset)
|
||||
@ -236,7 +232,7 @@ namespace vfs
|
||||
if (it == this->FileMap.end())
|
||||
ReturnLogError(-EBADF, "Invalid fd %d", fd);
|
||||
|
||||
return it->second.Node->Write(buf, count, offset);
|
||||
return fs->Write(it->second.node, buf, count, offset);
|
||||
}
|
||||
|
||||
int FileDescriptorTable::usr_close(int fd)
|
||||
@ -260,21 +256,19 @@ namespace vfs
|
||||
{
|
||||
case SEEK_SET:
|
||||
{
|
||||
newOffset = it->second.Node->Seek(offset);
|
||||
newOffset = fs->Seek(it->second.node, offset);
|
||||
break;
|
||||
}
|
||||
case SEEK_CUR:
|
||||
{
|
||||
newOffset = it->second.Node->Seek(newOffset + offset);
|
||||
newOffset = fs->Seek(it->second.node, newOffset + offset);
|
||||
break;
|
||||
}
|
||||
case SEEK_END:
|
||||
{
|
||||
struct kstat stat
|
||||
{
|
||||
};
|
||||
it->second.Node->Stat(&stat);
|
||||
newOffset = it->second.Node->Seek(stat.Size + offset);
|
||||
struct kstat stat{};
|
||||
fs->Stat(it->second.node, &stat);
|
||||
newOffset = fs->Seek(it->second.node, stat.Size + offset);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -284,48 +278,48 @@ namespace vfs
|
||||
return newOffset;
|
||||
}
|
||||
|
||||
int FileDescriptorTable::usr_stat(const char *pathname,
|
||||
struct kstat *statbuf)
|
||||
int FileDescriptorTable::usr_stat(const char *pathname, kstat *statbuf)
|
||||
{
|
||||
FileNode *node = fs->GetByPath(pathname, nullptr);
|
||||
if (node == nullptr)
|
||||
ReturnLogError(-ENOENT, "Failed to find %s", pathname);
|
||||
Node root = thisProcess->Info.RootNode;
|
||||
eNode ret = fs->Lookup(root, pathname);
|
||||
if (ret == false)
|
||||
ReturnLogError(-ret.Error, "Error on %s, %s", pathname, ret.what());
|
||||
Node node = ret;
|
||||
|
||||
if (node->IsSymbolicLink())
|
||||
{
|
||||
std::unique_ptr<char[]> buffer(new char[1024]);
|
||||
ssize_t ret = node->ReadLink(buffer.get(), 1024);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ssize_t len = fs->ReadLink(node, buffer.get(), 1024);
|
||||
if (len < 0)
|
||||
return len;
|
||||
|
||||
FileNode *target = fs->GetByPath(buffer.get(), nullptr);
|
||||
if (target == nullptr)
|
||||
return -ENOENT;
|
||||
|
||||
return target->Stat(statbuf);
|
||||
ret = fs->Lookup(root, buffer.get());
|
||||
if (ret == false)
|
||||
return -ret.Error;
|
||||
return fs->Stat(ret.Value, statbuf);
|
||||
}
|
||||
|
||||
return node->Stat(statbuf);
|
||||
return fs->Stat(node, statbuf);
|
||||
}
|
||||
|
||||
int FileDescriptorTable::usr_fstat(int fd, struct kstat *statbuf)
|
||||
int FileDescriptorTable::usr_fstat(int fd, kstat *statbuf)
|
||||
{
|
||||
auto it = this->FileMap.find(fd);
|
||||
if (it == this->FileMap.end())
|
||||
ReturnLogError(-EBADF, "Invalid fd %d", fd);
|
||||
|
||||
vfs::FileDescriptorTable::Fildes &fildes = it->second;
|
||||
|
||||
return fildes.Node->Stat(statbuf);
|
||||
return fs->Stat(fildes.node, statbuf);
|
||||
}
|
||||
|
||||
int FileDescriptorTable::usr_lstat(const char *pathname,
|
||||
struct kstat *statbuf)
|
||||
int FileDescriptorTable::usr_lstat(const char *pathname, kstat *statbuf)
|
||||
{
|
||||
FileNode *node = fs->GetByPath(pathname, nullptr);
|
||||
if (node == nullptr)
|
||||
ReturnLogError(-ENOENT, "Failed to find %s", pathname);
|
||||
return node->Stat(statbuf);
|
||||
Node root = thisProcess->Info.RootNode;
|
||||
eNode ret = fs->Lookup(root, pathname);
|
||||
if (ret == false)
|
||||
ReturnLogError(-ret.Error, "Error on %s, %s", pathname, ret.what());
|
||||
|
||||
return fs->Stat(ret.Value, statbuf);
|
||||
}
|
||||
|
||||
int FileDescriptorTable::usr_dup(int oldfd)
|
||||
@ -339,7 +333,7 @@ namespace vfs
|
||||
return -EMFILE;
|
||||
|
||||
Fildes new_dfd{};
|
||||
new_dfd.Node = it->second.Node;
|
||||
new_dfd.node = it->second.node;
|
||||
new_dfd.Mode = it->second.Mode;
|
||||
|
||||
this->FileMap.insert({newfd, new_dfd});
|
||||
@ -364,7 +358,7 @@ namespace vfs
|
||||
this->usr_close(newfd);
|
||||
|
||||
Fildes new_dfd{};
|
||||
new_dfd.Node = it->second.Node;
|
||||
new_dfd.node = it->second.node;
|
||||
new_dfd.Mode = it->second.Mode;
|
||||
|
||||
this->FileMap.insert({newfd, new_dfd});
|
||||
@ -378,7 +372,7 @@ namespace vfs
|
||||
if (it == this->FileMap.end())
|
||||
ReturnLogError(-EBADF, "Invalid fd %d", fd);
|
||||
|
||||
return it->second.Node->Ioctl(request, argp);
|
||||
return fs->Ioctl(it->second.node, request, argp);
|
||||
}
|
||||
|
||||
FileDescriptorTable::FileDescriptorTable(void *_Owner)
|
||||
@ -386,11 +380,12 @@ namespace vfs
|
||||
{
|
||||
debug("+ %#lx", this);
|
||||
|
||||
mode_t Mode = S_IXOTH | S_IROTH |
|
||||
S_IXGRP | S_IRGRP |
|
||||
S_IXUSR | S_IRUSR |
|
||||
/* d r-x r-x r-x */
|
||||
mode_t Mode = S_IROTH | S_IXOTH |
|
||||
S_IRGRP | S_IXGRP |
|
||||
S_IRUSR | S_IXUSR |
|
||||
S_IFDIR;
|
||||
|
||||
this->fdDir = fs->Create(((Tasking::PCB *)_Owner)->ProcDirectory, "fd", Mode);
|
||||
Tasking::PCB *pcb = (Tasking::PCB *)_Owner;
|
||||
this->fdDir = fs->Create(pcb->ProcDirectory, "fd", Mode);
|
||||
}
|
||||
}
|
@ -15,12 +15,12 @@
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem/ramfs.hpp>
|
||||
#include <fs/ramfs.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <functional>
|
||||
#include <debug.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
#include "../kernel.h"
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
@ -81,7 +81,6 @@ namespace vfs
|
||||
inode.Index = NextInode;
|
||||
inode.Offset = 0;
|
||||
inode.PrivateData = this;
|
||||
inode.Flags = I_FLAG_CACHE_KEEP;
|
||||
|
||||
const char *basename;
|
||||
size_t length;
|
||||
@ -329,54 +328,54 @@ namespace vfs
|
||||
}
|
||||
}
|
||||
|
||||
O2 int __ramfs_Lookup(struct Inode *Parent, const char *Name, struct Inode **Result)
|
||||
int __ramfs_Lookup(struct Inode *Parent, const char *Name, struct Inode **Result)
|
||||
{
|
||||
return ((vfs::RAMFS *)Parent->PrivateData)->Lookup(Parent, Name, Result);
|
||||
}
|
||||
|
||||
O2 int __ramfs_Create(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result)
|
||||
int __ramfs_Create(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result)
|
||||
{
|
||||
return ((vfs::RAMFS *)Parent->PrivateData)->Create(Parent, Name, Mode, Result);
|
||||
}
|
||||
|
||||
O2 ssize_t __ramfs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
|
||||
ssize_t __ramfs_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
return ((vfs::RAMFS *)Node->PrivateData)->Read(Node, Buffer, Size, Offset);
|
||||
}
|
||||
|
||||
O2 ssize_t __ramfs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
|
||||
ssize_t __ramfs_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
return ((vfs::RAMFS *)Node->PrivateData)->Write(Node, Buffer, Size, Offset);
|
||||
}
|
||||
|
||||
O2 ssize_t __ramfs_Readdir(struct Inode *Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
|
||||
ssize_t __ramfs_Readdir(struct Inode *Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
|
||||
{
|
||||
return ((vfs::RAMFS *)Node->PrivateData)->ReadDir(Node, Buffer, Size, Offset, Entries);
|
||||
}
|
||||
|
||||
O2 int __ramfs_SymLink(Inode *Parent, const char *Name, const char *Target, Inode **Result)
|
||||
int __ramfs_SymLink(Inode *Parent, const char *Name, const char *Target, Inode **Result)
|
||||
{
|
||||
return ((vfs::RAMFS *)Parent->PrivateData)->SymLink(Parent, Name, Target, Result);
|
||||
}
|
||||
|
||||
O2 ssize_t __ramfs_ReadLink(Inode *Node, char *Buffer, size_t Size)
|
||||
ssize_t __ramfs_ReadLink(Inode *Node, char *Buffer, size_t Size)
|
||||
{
|
||||
return ((vfs::RAMFS *)Node->PrivateData)->ReadLink(Node, Buffer, Size);
|
||||
}
|
||||
|
||||
O2 int __ramfs_Stat(struct Inode *Node, kstat *Stat)
|
||||
int __ramfs_Stat(struct Inode *Node, kstat *Stat)
|
||||
{
|
||||
return ((vfs::RAMFS *)Node->PrivateData)->Stat(Node, Stat);
|
||||
}
|
||||
|
||||
O2 int __ramfs_DestroyInode(FileSystemInfo *Info, Inode *Node)
|
||||
int __ramfs_DestroyInode(FileSystemInfo *Info, Inode *Node)
|
||||
{
|
||||
vfs::RAMFS::RAMFSInode *inode = (vfs::RAMFS::RAMFSInode *)Node;
|
||||
delete inode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
O2 int __ramfs_Destroy(FileSystemInfo *fsi)
|
||||
int __ramfs_Destroy(FileSystemInfo *fsi)
|
||||
{
|
||||
assert(fsi->PrivateData);
|
||||
delete (vfs::RAMFS *)fsi->PrivateData;
|
||||
@ -384,16 +383,13 @@ O2 int __ramfs_Destroy(FileSystemInfo *fsi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool MountRAMFS(FileNode *Parent, const char *Name, size_t Index)
|
||||
bool MountAndRootRAMFS(Node Parent, const char *Name, size_t Index)
|
||||
{
|
||||
vfs::RAMFS *ramfs = new vfs::RAMFS;
|
||||
ramfs->DeviceID = fs->EarlyReserveDevice();
|
||||
ramfs->RootName.assign(Name);
|
||||
|
||||
FileSystemInfo *fsi = new FileSystemInfo;
|
||||
fsi->Name = "ramfs";
|
||||
fsi->RootName = Name;
|
||||
fsi->Flags = I_FLAG_ROOT | I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
|
||||
fsi->SuperOps.DeleteInode = __ramfs_DestroyInode;
|
||||
fsi->SuperOps.Destroy = __ramfs_Destroy;
|
||||
fsi->Ops.Lookup = __ramfs_Lookup;
|
||||
@ -405,13 +401,12 @@ bool MountRAMFS(FileNode *Parent, const char *Name, size_t Index)
|
||||
fsi->Ops.ReadLink = __ramfs_ReadLink;
|
||||
fsi->Ops.Stat = __ramfs_Stat;
|
||||
fsi->PrivateData = ramfs;
|
||||
ramfs->DeviceID = fs->RegisterFileSystem(fsi);
|
||||
|
||||
Inode *root = nullptr;
|
||||
ramfs->Create(nullptr, Name, S_IFDIR | 0755, &root);
|
||||
|
||||
fs->LateRegisterFileSystem(ramfs->DeviceID, fsi, root);
|
||||
fs->AddRootAt(root, Index);
|
||||
|
||||
fs->Mount(Parent, root, Name);
|
||||
fs->Mount(Parent, root, Name, fsi);
|
||||
fs->AddRoot(Index, fs->Convert(root));
|
||||
return true;
|
||||
}
|
@ -15,12 +15,12 @@
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem/ustar.hpp>
|
||||
#include <fs/ustar.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <functional>
|
||||
#include <debug.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
#include "../kernel.h"
|
||||
|
||||
#define TMAGIC "ustar"
|
||||
#define TMAGLEN 6
|
||||
@ -32,7 +32,7 @@ namespace vfs
|
||||
int USTAR::Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result)
|
||||
{
|
||||
auto Parent = (USTARInode *)_Parent;
|
||||
|
||||
debug("looking up for %s", Name);
|
||||
const char *basename;
|
||||
size_t length;
|
||||
cwk_path_get_basename(Name, &basename, &length);
|
||||
@ -91,7 +91,6 @@ namespace vfs
|
||||
inode.Index = NextInode;
|
||||
inode.Offset = 0;
|
||||
inode.PrivateData = this;
|
||||
inode.Flags = I_FLAG_CACHE_KEEP;
|
||||
|
||||
const char *basename;
|
||||
size_t length;
|
||||
@ -217,6 +216,7 @@ namespace vfs
|
||||
{
|
||||
/* FIXME: FIX ALIGNMENT FOR DIRENT! */
|
||||
auto Node = (USTARInode *)_Node;
|
||||
debug("reading directory %s", Node->Path.c_str());
|
||||
|
||||
off_t realOffset = Offset;
|
||||
|
||||
@ -237,6 +237,7 @@ namespace vfs
|
||||
ent->d_type = DT_DIR;
|
||||
strcpy(ent->d_name, ".");
|
||||
totalSize += reclen;
|
||||
debug(".");
|
||||
}
|
||||
|
||||
if (Offset <= 1)
|
||||
@ -263,6 +264,7 @@ namespace vfs
|
||||
ent->d_type = DT_DIR;
|
||||
strcpy(ent->d_name, "..");
|
||||
totalSize += reclen;
|
||||
debug("..");
|
||||
}
|
||||
|
||||
// off_t entriesSkipped = 0;
|
||||
@ -309,10 +311,13 @@ namespace vfs
|
||||
if (var->Deleted)
|
||||
continue;
|
||||
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(var->Name.c_str()) + 1);
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + var->Name.size() + 1);
|
||||
|
||||
if (totalSize + reclen >= Size)
|
||||
if (totalSize + reclen > Size)
|
||||
{
|
||||
debug("not enough space for %s (%zu + %zu = %zu > %zu)", var->Name.c_str(), totalSize, reclen, totalSize + reclen, Size);
|
||||
break;
|
||||
}
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = var->Node.Index;
|
||||
@ -349,7 +354,7 @@ namespace vfs
|
||||
break;
|
||||
}
|
||||
strncpy(ent->d_name, var->Name.c_str(), strlen(var->Name.c_str()));
|
||||
|
||||
debug("%s", var->Name.c_str());
|
||||
totalSize += reclen;
|
||||
entries++;
|
||||
}
|
||||
@ -601,7 +606,6 @@ namespace vfs
|
||||
uNode.RawDevice = 0;
|
||||
uNode.Index = NextInode;
|
||||
SetMode(uNode, header);
|
||||
uNode.Flags = I_FLAG_CACHE_KEEP;
|
||||
uNode.Offset = 0;
|
||||
uNode.PrivateData = this;
|
||||
|
||||
@ -847,17 +851,8 @@ bool TestAndInitializeUSTAR(uintptr_t Address, size_t Size, size_t Index)
|
||||
return false;
|
||||
}
|
||||
|
||||
ustar->DeviceID = fs->EarlyReserveDevice();
|
||||
ustar->ReadArchive(Address, Size);
|
||||
|
||||
Inode *rootfs = nullptr;
|
||||
ustar->Lookup(nullptr, "/", &rootfs);
|
||||
assert(rootfs != nullptr);
|
||||
|
||||
FileSystemInfo *fsi = new FileSystemInfo;
|
||||
fsi->Name = "ustar";
|
||||
fsi->RootName = "/";
|
||||
fsi->Flags = I_FLAG_ROOT | I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
|
||||
fsi->SuperOps.DeleteInode = __ustar_DestroyInode;
|
||||
fsi->SuperOps.Destroy = __ustar_Destroy;
|
||||
fsi->Ops.Lookup = __ustar_Lookup;
|
||||
@ -868,8 +863,23 @@ bool TestAndInitializeUSTAR(uintptr_t Address, size_t Size, size_t Index)
|
||||
fsi->Ops.ReadLink = __ustar_ReadLink;
|
||||
fsi->Ops.Stat = __ustar_Stat;
|
||||
fsi->PrivateData = ustar;
|
||||
fs->LateRegisterFileSystem(ustar->DeviceID, fsi, rootfs);
|
||||
|
||||
fs->AddRootAt(rootfs, Index);
|
||||
ustar->DeviceID = fs->RegisterFileSystem(fsi);
|
||||
ustar->ReadArchive(Address, Size);
|
||||
|
||||
Inode *rootfs = nullptr;
|
||||
ustar->Lookup(nullptr, "/", &rootfs);
|
||||
assert(rootfs != nullptr);
|
||||
|
||||
eNode _node = fs->Convert(rootfs);
|
||||
assert(_node.Error == 0);
|
||||
|
||||
Node node = _node;
|
||||
node->fsi = fsi;
|
||||
node->Flags.MountPoint = true;
|
||||
node->Name = "/";
|
||||
node->Path = "/";
|
||||
|
||||
fs->AddRoot(Index, node);
|
||||
return true;
|
||||
}
|
586
Kernel/fs/vfs.cpp
Normal file
586
Kernel/fs/vfs.cpp
Normal file
@ -0,0 +1,586 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <fs/vfs.hpp>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
eNode Virtual::Convert(Inode *inode)
|
||||
{
|
||||
Node cache = std::make_shared<NodeCache>();
|
||||
cache->inode = inode;
|
||||
return {cache, 0};
|
||||
}
|
||||
|
||||
eNode Virtual::Convert(Node &Parent, Inode *inode)
|
||||
{
|
||||
Node cache = std::make_shared<NodeCache>();
|
||||
cache->inode = inode;
|
||||
cache->fsi = Parent->fsi;
|
||||
cache->Parent = Parent;
|
||||
Parent->Children.push_back(cache);
|
||||
return {cache, 0};
|
||||
}
|
||||
|
||||
std::string Virtual::NormalizePath(Node &Parent, std::string Path, bool Join)
|
||||
{
|
||||
std::string result;
|
||||
if (Join)
|
||||
{
|
||||
size_t len = Path.size() + Parent->Path.size() + 2;
|
||||
result.reserve(len);
|
||||
len = cwk_path_join(Parent->Path.c_str(), Path.c_str(), result.data(), result.capacity());
|
||||
result.resize(len);
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t len = Path.size() + 2;
|
||||
result.reserve(len);
|
||||
len = cwk_path_normalize(Path.c_str(), result.data(), result.capacity());
|
||||
result.resize(len);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Virtual::RootExists(dev_t Index)
|
||||
{
|
||||
if (Roots.find(Index) == Roots.end())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
eNode Virtual::GetRoot(dev_t Index)
|
||||
{
|
||||
auto it = Roots.find(Index);
|
||||
if (it == Roots.end())
|
||||
return {nullptr, ENOENT};
|
||||
return {it->second, 0};
|
||||
}
|
||||
|
||||
ssize_t Virtual::GetRoot(Node Index)
|
||||
{
|
||||
for (auto it = Roots.begin(); it != Roots.end(); ++it)
|
||||
{
|
||||
if (it->second == Index)
|
||||
return it->first;
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int Virtual::AddRoot(dev_t Index, Node Root, bool Replace)
|
||||
{
|
||||
assert(Root != nullptr);
|
||||
|
||||
auto it = Roots.find(Index);
|
||||
if (it == Roots.end())
|
||||
{
|
||||
Roots[Index] = Root;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Replace)
|
||||
{
|
||||
Roots[Index] = Root;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("Root %ld already exists", Index);
|
||||
return EEXIST;
|
||||
}
|
||||
}
|
||||
|
||||
dev_t Virtual::RegisterFileSystem(FileSystemInfo *fsi)
|
||||
{
|
||||
assert(fsi != nullptr);
|
||||
FileSystems.insert({FileSystems.size(), fsi});
|
||||
return FileSystems.size() - 1;
|
||||
}
|
||||
|
||||
int Virtual::UnregisterFileSystem(dev_t Device)
|
||||
{
|
||||
auto it = FileSystems.find(Device);
|
||||
if (it == FileSystems.end())
|
||||
return -ENOENT;
|
||||
|
||||
FileSystemInfo *fsi = it->second;
|
||||
|
||||
/* TODO: unmount */
|
||||
fixme("Unmounting %d", Device);
|
||||
|
||||
if (fsi->SuperOps.Synchronize)
|
||||
fsi->SuperOps.Synchronize(fsi, nullptr);
|
||||
if (fsi->SuperOps.Destroy)
|
||||
fsi->SuperOps.Destroy(fsi);
|
||||
|
||||
FileSystems.erase(it);
|
||||
return 0;
|
||||
}
|
||||
|
||||
eNode Virtual::Lookup(Node &Parent, std::string Path)
|
||||
{
|
||||
assert(Parent != nullptr);
|
||||
|
||||
debug("looking up \"%s\" in \"%s\"", Path.c_str(), Parent->Path.c_str());
|
||||
|
||||
if (Path == ".")
|
||||
return {Parent, 0};
|
||||
else if (Path == "..")
|
||||
return {Parent->Parent ? Parent->Parent : Parent, 0};
|
||||
|
||||
Node base = Parent;
|
||||
bool absolute = PathIsAbsolute(Path);
|
||||
if (absolute == true)
|
||||
{
|
||||
while (base->Parent)
|
||||
base = base->Parent;
|
||||
}
|
||||
|
||||
debug("base is \"%s\" and path is \"%s\" %d", base->Path.c_str(), Path.c_str(), absolute);
|
||||
Path = this->NormalizePath(base, Path, !absolute);
|
||||
debug("after normalizing, path is \"%s\" %d", Path.c_str(), absolute);
|
||||
|
||||
struct cwk_segment segment;
|
||||
if (!cwk_path_get_first_segment(Path.c_str(), &segment))
|
||||
{
|
||||
debug("%s no segments; %d", Path.c_str(), absolute);
|
||||
if (Path == "/")
|
||||
return {base, 0};
|
||||
|
||||
assert(!"Path doesn't have any segments.");
|
||||
}
|
||||
|
||||
Node node = base;
|
||||
/* We need to go to the root after NormalizePath even if Path is relative */
|
||||
if (absolute == false)
|
||||
{
|
||||
while (node->Parent)
|
||||
{
|
||||
debug("current parent \"%s\"", node->Parent->Path.c_str());
|
||||
node = node->Parent;
|
||||
debug("new parent \"%s\"", node->Parent ? node->Parent->Path.c_str() : "<null>");
|
||||
}
|
||||
}
|
||||
|
||||
std::string currentPath = node->Path;
|
||||
if (currentPath.empty())
|
||||
currentPath = "/";
|
||||
|
||||
do
|
||||
{
|
||||
std::string segmentStr(segment.begin, segment.size);
|
||||
debug("Current segment is \"%s\"", segmentStr.c_str());
|
||||
|
||||
eNode ret = node->CachedSearch(segmentStr);
|
||||
if (ret == false)
|
||||
{
|
||||
debug("cache miss for \"%s\"", segmentStr.c_str());
|
||||
|
||||
if (node->fsi->Ops.Lookup == nullptr)
|
||||
return {nullptr, ENOTSUP};
|
||||
|
||||
Inode *inode;
|
||||
int ret = node->fsi->Ops.Lookup(node->inode, segmentStr.c_str(), &inode);
|
||||
if (ret != 0)
|
||||
return {nullptr, ret};
|
||||
|
||||
if (currentPath == "/")
|
||||
currentPath += segmentStr;
|
||||
else
|
||||
currentPath += "/" + segmentStr;
|
||||
|
||||
node = Convert(node, inode);
|
||||
node->Name = segmentStr;
|
||||
node->Path = currentPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("cache hit for \"%s\"", segmentStr.c_str());
|
||||
node = ret;
|
||||
if (currentPath == "/")
|
||||
currentPath += segmentStr;
|
||||
else
|
||||
currentPath += "/" + segmentStr;
|
||||
}
|
||||
} while (cwk_path_get_next_segment(&segment));
|
||||
|
||||
return {node, 0};
|
||||
}
|
||||
|
||||
eNode Virtual::Create(Node &Parent, std::string Name, mode_t Mode, bool ErrorIfExists)
|
||||
{
|
||||
eNode exists = this->Lookup(Parent, Name);
|
||||
if (exists)
|
||||
{
|
||||
if (ErrorIfExists)
|
||||
return {nullptr, EEXIST};
|
||||
|
||||
/* I should handle this in a better way */
|
||||
assert((exists.Value->inode->Mode & S_IFMT) == (Mode & S_IFMT));
|
||||
debug("File \"%s\" already exists in cache", Name.c_str());
|
||||
return exists;
|
||||
}
|
||||
|
||||
if (!Parent)
|
||||
return {nullptr, EINVAL};
|
||||
if (Parent->fsi->Ops.Create == nullptr)
|
||||
return {nullptr, ENOTSUP};
|
||||
|
||||
Inode *inode;
|
||||
int ret = Parent->fsi->Ops.Create(Parent->inode, Name.c_str(), Mode, &inode);
|
||||
if (ret != 0)
|
||||
return {nullptr, ret};
|
||||
|
||||
Node node = Convert(Parent, inode);
|
||||
node->Name = Name;
|
||||
std::string unormalized = Parent->Path == "/" ? "/" + Name : Parent->Path + "/" + Name;
|
||||
node->Path = fs->NormalizePath(Parent, unormalized);
|
||||
return {node, 0};
|
||||
}
|
||||
|
||||
int Virtual::Remove(Node &Parent, std::string Name)
|
||||
{
|
||||
if (!Parent)
|
||||
return -EINVAL;
|
||||
if (Parent->fsi->Ops.Remove == nullptr)
|
||||
return -ENOTSUP;
|
||||
int ret = Parent->fsi->Ops.Remove(Parent->inode, Name.c_str());
|
||||
if (ret == 0)
|
||||
{
|
||||
for (auto it = Parent->Children.begin(); it != Parent->Children.end(); ++it)
|
||||
{
|
||||
if (it->get()->Name != Name)
|
||||
continue;
|
||||
Parent->Children.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Virtual::Remove(Node &node)
|
||||
{
|
||||
if (!node->Parent)
|
||||
return -EINVAL;
|
||||
if (node->Parent->fsi->Ops.Remove == nullptr)
|
||||
return -ENOTSUP;
|
||||
int ret = node->Parent->fsi->Ops.Remove(node->inode, node->Name.c_str());
|
||||
if (ret == 0)
|
||||
{
|
||||
Node &p = node->Parent;
|
||||
for (auto it = p->Children.begin(); it != p->Children.end(); ++it)
|
||||
{
|
||||
if (it->get() != node.get())
|
||||
continue;
|
||||
p->Children.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Virtual::Rename(Node &node, std::string NewName)
|
||||
{
|
||||
if (node->fsi->Ops.Rename == nullptr)
|
||||
return -ENOTSUP;
|
||||
int ret = node->fsi->Ops.Rename(node->inode, node->Name.c_str(), NewName.c_str());
|
||||
if (ret == 0)
|
||||
node->Name = NewName;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t Virtual::Read(Node &Target, void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
if (Target->IsDirectory() || Target->IsMountPoint())
|
||||
return -EISDIR;
|
||||
|
||||
if (Target->IsSymbolicLink())
|
||||
return -EINVAL;
|
||||
|
||||
/* TODO: cache buffer */
|
||||
|
||||
return Target->__Read(Buffer, Size, Offset);
|
||||
}
|
||||
|
||||
ssize_t Virtual::Write(Node &Target, const void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
if (Target->IsDirectory() || Target->IsMountPoint())
|
||||
return -EISDIR;
|
||||
|
||||
if (Target->IsSymbolicLink())
|
||||
return -EINVAL;
|
||||
|
||||
/* TODO: cache buffer */
|
||||
|
||||
return Target->__Write(Buffer, Size, Offset);
|
||||
}
|
||||
|
||||
int Virtual::Truncate(Node &Target, off_t Size)
|
||||
{
|
||||
if (Target->IsDirectory() || Target->IsMountPoint())
|
||||
return -EISDIR;
|
||||
|
||||
if (!Target->IsRegularFile())
|
||||
return -EINVAL;
|
||||
|
||||
/* TODO: cache buffer */
|
||||
|
||||
return Target->__Truncate(Size);
|
||||
}
|
||||
|
||||
__no_sanitize("alignment") ssize_t Virtual::ReadDirectory(Node &Target, kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
|
||||
{
|
||||
if (!Target->IsDirectory() && !Target->IsMountPoint())
|
||||
return -ENOTDIR;
|
||||
|
||||
ssize_t total = 0;
|
||||
off_t entryIndex = 0;
|
||||
std::list<std::string> seen;
|
||||
|
||||
uint8_t *bufPtr = reinterpret_cast<uint8_t *>(Buffer);
|
||||
|
||||
if (Target->fsi && Target->fsi->Ops.ReadDir)
|
||||
{
|
||||
const size_t tempBufSize = 4096;
|
||||
std::unique_ptr<uint8_t[]> tempBuf(new uint8_t[tempBufSize]);
|
||||
|
||||
off_t fsOffset = Offset;
|
||||
ssize_t read = Target->fsi->Ops.ReadDir(Target->inode, (kdirent *)tempBuf.get(), tempBufSize, fsOffset, Entries);
|
||||
if (read > 0)
|
||||
{
|
||||
ssize_t pos = 0;
|
||||
while (pos < read)
|
||||
{
|
||||
kdirent *ent = (kdirent *)(tempBuf.get() + pos);
|
||||
if (ent->d_reclen == 0)
|
||||
break;
|
||||
|
||||
size_t reclen = ent->d_reclen;
|
||||
if (total + reclen > Size)
|
||||
break;
|
||||
|
||||
memcpy(bufPtr, ent, reclen);
|
||||
seen.push_back(ent->d_name);
|
||||
bufPtr += reclen;
|
||||
total += reclen;
|
||||
pos += reclen;
|
||||
entryIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &child : Target->Children)
|
||||
{
|
||||
if (std::find(seen.begin(), seen.end(), child->Name) != seen.end())
|
||||
continue;
|
||||
|
||||
if (entryIndex < Offset)
|
||||
{
|
||||
entryIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint16_t reclen = (uint16_t)(offsetof(struct kdirent, d_name) + child->Name.size() + 1);
|
||||
if (total + reclen > (ssize_t)Size)
|
||||
break;
|
||||
|
||||
kdirent *ent = (kdirent *)bufPtr;
|
||||
ent->d_ino = child->inode ? child->inode->Index : 0;
|
||||
ent->d_off = entryIndex++;
|
||||
ent->d_reclen = reclen;
|
||||
ent->d_type = child->inode ? IFTODT(child->inode->Mode) : DT_UNKNOWN;
|
||||
strcpy(ent->d_name, child->Name.c_str());
|
||||
|
||||
bufPtr += reclen;
|
||||
total += reclen;
|
||||
seen.push_back(child->Name);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
__no_sanitize("alignment") std::list<Node> Virtual::ReadDirectory(Node &Target)
|
||||
{
|
||||
if (!Target->IsDirectory() && !Target->IsMountPoint())
|
||||
return {};
|
||||
std::list<Node> ret;
|
||||
std::list<std::string> seen;
|
||||
|
||||
if (Target->fsi && Target->fsi->Ops.ReadDir)
|
||||
{
|
||||
const size_t bufSize = 4096;
|
||||
std::unique_ptr<uint8_t[]> buf(new uint8_t[bufSize]);
|
||||
off_t offset = 0;
|
||||
while (true)
|
||||
{
|
||||
ssize_t read = Target->fsi->Ops.ReadDir(Target->inode, (kdirent *)buf.get(), bufSize, offset, LONG_MAX);
|
||||
if (read <= 0)
|
||||
break;
|
||||
ssize_t pos = 0;
|
||||
while (pos < read)
|
||||
{
|
||||
kdirent *ent = (kdirent *)(buf.get() + pos);
|
||||
if (ent->d_reclen == 0)
|
||||
break;
|
||||
debug("%s", ent->d_name);
|
||||
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
|
||||
{
|
||||
pos += ent->d_reclen;
|
||||
continue;
|
||||
}
|
||||
|
||||
seen.push_back(ent->d_name);
|
||||
|
||||
auto it = std::find_if(Target->Children.begin(), Target->Children.end(),
|
||||
[&](const Node &n)
|
||||
{ return n->Name == ent->d_name; });
|
||||
|
||||
if (it != Target->Children.end())
|
||||
ret.push_back(*it);
|
||||
else
|
||||
{
|
||||
eNode result = Lookup(Target, ent->d_name);
|
||||
if (result.Error == 0 && result.Value)
|
||||
{
|
||||
Target->Children.push_back(result.Value);
|
||||
result.Value->Parent = Target;
|
||||
ret.push_back(result.Value);
|
||||
}
|
||||
}
|
||||
pos += ent->d_reclen;
|
||||
}
|
||||
offset += read;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &child : Target->Children)
|
||||
{
|
||||
if (std::find(seen.begin(), seen.end(), child->Name) != seen.end())
|
||||
continue;
|
||||
if (child->Name == "." || child->Name == "..")
|
||||
continue;
|
||||
ret.push_back(child);
|
||||
seen.push_back(child->Name.c_str());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
eNode Virtual::CreateLink(Node &Parent, std::string Name, std::string Target)
|
||||
{
|
||||
mode_t mode = S_IRWXU |
|
||||
S_IRWXG |
|
||||
S_IRWXO |
|
||||
S_IFLNK;
|
||||
|
||||
eNode enode = this->Create(Parent, Name, mode);
|
||||
if (!enode)
|
||||
return enode;
|
||||
Node node = enode;
|
||||
node->Link = Target;
|
||||
return {node, 0};
|
||||
}
|
||||
|
||||
int Virtual::Stat(Node &Target, struct kstat *Stat)
|
||||
{
|
||||
/* TODO: cache */
|
||||
|
||||
return Target->__Stat(Stat);
|
||||
}
|
||||
|
||||
off_t Virtual::Seek(Node &Target, off_t Offset)
|
||||
{
|
||||
/* TODO: cache */
|
||||
|
||||
return Target->__Seek(Offset);
|
||||
}
|
||||
|
||||
int Virtual::Open(Node &Target, int Flags, mode_t Mode)
|
||||
{
|
||||
/* TODO: cache */
|
||||
|
||||
return Target->__Open(Flags, Mode);
|
||||
}
|
||||
|
||||
int Virtual::Close(Node &Target)
|
||||
{
|
||||
/* TODO: cache */
|
||||
|
||||
return Target->__Close();
|
||||
}
|
||||
|
||||
eNode Virtual::Mount(Node &Parent, Inode *inode, std::string Name, FileSystemInfo *fsi)
|
||||
{
|
||||
assert(Parent);
|
||||
assert(inode);
|
||||
|
||||
Node ret = this->Convert(inode);
|
||||
ret->fsi = fsi;
|
||||
ret->Name = Name;
|
||||
|
||||
std::string unormalized = Parent->Path == "/" ? "/" + Name : Parent->Path + "/" + Name;
|
||||
ret->Path = fs->NormalizePath(Parent, unormalized);
|
||||
// ret->Link =
|
||||
ret->Parent = Parent;
|
||||
Parent->Children.push_back(ret);
|
||||
return {ret, 0};
|
||||
}
|
||||
|
||||
int Virtual::Umount(Node &node)
|
||||
{
|
||||
if (!node->Flags.MountPoint)
|
||||
{
|
||||
debug("node %s is not a mountpoint", node->Path.c_str());
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fixme("untested code");
|
||||
std::shared_ptr<NodeCache> &ptr = node;
|
||||
ptr.reset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Virtual::Umount(Node &Parent, std::string Name)
|
||||
{
|
||||
eNode node = Parent->CachedSearch(Name);
|
||||
if (!node)
|
||||
{
|
||||
debug("mountpoint %s not found: %s", Name.c_str(), node.what());
|
||||
return -node.Error;
|
||||
}
|
||||
|
||||
return this->Umount(node.Value);
|
||||
}
|
||||
|
||||
void Virtual::Initialize()
|
||||
{
|
||||
debug("Initializing virtual file system...");
|
||||
Node root = this->GetRoot(0);
|
||||
|
||||
/* d rwx rwx rwx */
|
||||
mode_t mode = S_IRWXU |
|
||||
S_IRWXG |
|
||||
S_IRWXO |
|
||||
S_IFDIR;
|
||||
Node var = this->Create(root, "var", mode, false);
|
||||
Node log = this->Create(var, "log", mode, false);
|
||||
}
|
||||
|
||||
Virtual::Virtual() {}
|
||||
Virtual::~Virtual() {}
|
||||
}
|
@ -22,7 +22,8 @@
|
||||
|
||||
#include <interface/driver.h>
|
||||
#include <interface/input.h>
|
||||
#include <filesystem.hpp>
|
||||
#include <interface/block.h>
|
||||
#include <fs/vfs.hpp>
|
||||
#include <unordered_map>
|
||||
#include <memory.hpp>
|
||||
#include <ints.hpp>
|
||||
@ -120,17 +121,15 @@ namespace Driver
|
||||
* 1 - input/... devices
|
||||
*/
|
||||
dev_t DriverIDCounter = 2;
|
||||
FileNode *devNode = nullptr;
|
||||
FileNode *devInputNode = nullptr;
|
||||
Node devNode = nullptr;
|
||||
Node devInputNode = nullptr;
|
||||
Node devBlockNode = nullptr;
|
||||
|
||||
bool IsDriverTrusted(FileNode *File);
|
||||
int LoadDriverFile(DriverObject &Drv, FileNode *File);
|
||||
bool IsDriverTrusted(Node File);
|
||||
int LoadDriverFile(DriverObject &Drv, Node File);
|
||||
void ReloadDriver(dev_t driverID);
|
||||
|
||||
void InitializeDaemonFS();
|
||||
|
||||
dev_t RegisterInputDevice(std::unordered_map<dev_t, DriverHandlers> *, dev_t, size_t, const InodeOperations *);
|
||||
dev_t RegisterBlockDevice(std::unordered_map<dev_t, DriverHandlers> *, dev_t, size_t, const InodeOperations *);
|
||||
void InitializeDeviceDirectory();
|
||||
|
||||
public:
|
||||
RingBuffer<KeyboardReport> GlobalKeyboardInputReports;
|
||||
@ -138,11 +137,16 @@ namespace Driver
|
||||
|
||||
struct DeviceInode
|
||||
{
|
||||
struct Inode Node;
|
||||
FileNode *Parent;
|
||||
struct Inode inode;
|
||||
Node Parent;
|
||||
Inode *ParentInode;
|
||||
std::string Name;
|
||||
std::vector<DeviceInode *> Children;
|
||||
|
||||
size_t Size;
|
||||
time_t AccessTime, ModifyTime, ChangeTime;
|
||||
uint32_t BlockSize;
|
||||
uint32_t Blocks;
|
||||
};
|
||||
|
||||
std::unordered_map<dev_t, DriverObject> &
|
||||
@ -185,6 +189,9 @@ namespace Driver
|
||||
int ReportInputEvent(dev_t DriverID, InputReport *Report);
|
||||
int UnregisterDevice(dev_t DriverID, dev_t Device);
|
||||
|
||||
dev_t RegisterBlockDevice(dev_t DriverID, struct BlockDevice *Device);
|
||||
int UnregisterBlockDevice(dev_t DriverID, dev_t DeviceID);
|
||||
|
||||
void *AllocateMemory(dev_t DriverID, size_t Pages);
|
||||
void FreeMemory(dev_t DriverID, void *Pointer, size_t Pages);
|
||||
|
||||
@ -193,8 +200,6 @@ namespace Driver
|
||||
private:
|
||||
~Manager();
|
||||
};
|
||||
|
||||
void ManagerDaemonWrapper();
|
||||
}
|
||||
|
||||
void *GetSymbolByName(const char *Name, int Version);
|
||||
@ -215,9 +220,12 @@ namespace v0
|
||||
int UnregisterInterruptHandler(dev_t DriverID, uint8_t IRQ, void *Handler);
|
||||
int UnregisterAllInterruptHandlers(dev_t DriverID, void *Handler);
|
||||
|
||||
dev_t RegisterFileSystem(dev_t DriverID, FileSystemInfo *Info, struct Inode *Root);
|
||||
dev_t RegisterFileSystem(dev_t DriverID, FileSystemInfo *Info);
|
||||
int UnregisterFileSystem(dev_t DriverID, dev_t Device);
|
||||
|
||||
dev_t RegisterBlockDevice(dev_t DriverID, struct BlockDevice *Device);
|
||||
int UnregisterBlockDevice(dev_t DriverID, dev_t DeviceID);
|
||||
|
||||
pid_t CreateKernelProcess(dev_t DriverID, const char *Name);
|
||||
pid_t CreateKernelThread(dev_t DriverID, pid_t pId, const char *Name, void *EntryPoint, void *Argument);
|
||||
pid_t GetCurrentProcess(dev_t DriverID);
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
#include <task.hpp>
|
||||
#include <errno.h>
|
||||
#include <vector>
|
||||
@ -50,15 +50,15 @@ namespace Execute
|
||||
void *ELFProgramHeaders;
|
||||
|
||||
void GenerateAuxiliaryVector(Memory::VirtualMemoryArea *vma,
|
||||
FileNode *fd, Elf_Ehdr ELFHeader,
|
||||
Node &fd, Elf_Ehdr ELFHeader,
|
||||
uintptr_t EntryPoint,
|
||||
uintptr_t BaseAddress);
|
||||
|
||||
void LoadSegments(FileNode *fd, Tasking::PCB *TargetProcess, Elf_Ehdr &ELFHeader, uintptr_t &BaseAddress);
|
||||
void LoadSegments(Node &fd, Tasking::PCB *TargetProcess, Elf_Ehdr &ELFHeader, uintptr_t &BaseAddress);
|
||||
|
||||
void LoadExec(FileNode *fd, Tasking::PCB *TargetProcess);
|
||||
void LoadDyn(FileNode *fd, Tasking::PCB *TargetProcess);
|
||||
bool LoadInterpreter(FileNode *fd, Tasking::PCB *TargetProcess);
|
||||
void LoadExec(Node &fd, Tasking::PCB *TargetProcess);
|
||||
void LoadDyn(Node &fd, Tasking::PCB *TargetProcess);
|
||||
bool LoadInterpreter(Node &fd, Tasking::PCB *TargetProcess);
|
||||
|
||||
public:
|
||||
decltype(IsElfValid) &IsValid = IsElfValid;
|
||||
@ -74,7 +74,7 @@ namespace Execute
|
||||
~ELFObject();
|
||||
};
|
||||
|
||||
BinaryType GetBinaryType(FileNode *Path);
|
||||
BinaryType GetBinaryType(Node &Path);
|
||||
BinaryType GetBinaryType(std::string Path);
|
||||
|
||||
int Spawn(const char *Path, const char **argv, const char **envp,
|
||||
@ -88,12 +88,12 @@ namespace Execute
|
||||
char *GetELFStringTable(Elf_Ehdr *Header);
|
||||
char *ELFLookupString(Elf_Ehdr *Header, uintptr_t Offset);
|
||||
Elf_Sym *ELFLookupSymbol(Elf_Ehdr *Header, std::string Name);
|
||||
Elf_Sym ELFLookupSymbol(FileNode *fd, std::string Name);
|
||||
Elf_Sym ELFLookupSymbol(Node &fd, std::string Name);
|
||||
uintptr_t ELFGetSymbolValue(Elf_Ehdr *Header, uintptr_t Table, uintptr_t Index);
|
||||
|
||||
std::vector<Elf_Phdr> ELFGetSymbolType(FileNode *fd, SegmentTypes Tag);
|
||||
std::vector<Elf_Shdr> ELFGetSections(FileNode *fd, std::string SectionName);
|
||||
std::vector<Elf_Dyn> ELFGetDynamicTag(FileNode *fd, DynamicArrayTags Tag);
|
||||
std::vector<Elf_Phdr> ELFGetSymbolType(Node &fd, SegmentTypes Tag);
|
||||
std::vector<Elf_Shdr> ELFGetSections(Node &fd, std::string SectionName);
|
||||
std::vector<Elf_Dyn> ELFGetDynamicTag(Node &fd, DynamicArrayTags Tag);
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_FILE_EXECUTE_H__
|
||||
|
@ -1,260 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __FENNIX_KERNEL_FILESYSTEM_H__
|
||||
#define __FENNIX_KERNEL_FILESYSTEM_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <interface/fs.h>
|
||||
#include <unordered_map>
|
||||
#include <lock.hpp>
|
||||
#include <errno.h>
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
static_assert(DTTOIF(DT_FIFO) == S_IFIFO);
|
||||
static_assert(IFTODT(S_IFCHR) == DT_CHR);
|
||||
|
||||
/**
|
||||
* This macro is used to check if a filesystem operation is available.
|
||||
*
|
||||
* TL;DR
|
||||
*
|
||||
* @code
|
||||
* if FileSystemInfo.Ops.op == nullptr
|
||||
* return -err
|
||||
* else
|
||||
* return FileSystemInfo.Ops.op(this->Node, ...);
|
||||
* @endcode
|
||||
*
|
||||
* @param op The operation to check.
|
||||
* @param err The error to return if the operation is not available.
|
||||
* @param ... The arguments to pass to the operation.
|
||||
*
|
||||
* @return The result of the operation.
|
||||
*/
|
||||
#define __check_op(op, err, ...) \
|
||||
if (fsi->Ops.op == nullptr) \
|
||||
return -err; \
|
||||
else \
|
||||
return fsi->Ops.op(this->Node, ##__VA_ARGS__)
|
||||
|
||||
#define FSROOT(num) "\x06root-" #num "\x06"
|
||||
|
||||
class FileNode
|
||||
{
|
||||
public:
|
||||
std::string Name, Path;
|
||||
FileNode *Parent;
|
||||
std::vector<FileNode *> Children;
|
||||
Inode *Node;
|
||||
FileSystemInfo *fsi;
|
||||
|
||||
std::string GetName();
|
||||
std::string GetPath();
|
||||
|
||||
bool IsDirectory() { return S_ISDIR(Node->Mode); }
|
||||
bool IsCharacterDevice() { return S_ISCHR(Node->Mode); }
|
||||
bool IsBlockDevice() { return S_ISBLK(Node->Mode); }
|
||||
bool IsRegularFile() { return S_ISREG(Node->Mode); }
|
||||
bool IsFIFO() { return S_ISFIFO(Node->Mode); }
|
||||
bool IsSymbolicLink() { return S_ISLNK(Node->Mode); }
|
||||
bool IsSocket() { return S_ISSOCK(Node->Mode); }
|
||||
|
||||
int Lookup(const char *Name, Inode **Node) { __check_op(Lookup, ENOTSUP, Name, Node); }
|
||||
int Create(const char *Name, mode_t Mode, Inode **Node) { __check_op(Create, EROFS, Name, Mode, Node); }
|
||||
int Remove(const char *Name) { __check_op(Remove, EROFS, Name); }
|
||||
int Rename(const char *OldName, const char *NewName) { __check_op(Rename, EROFS, OldName, NewName); }
|
||||
ssize_t Read(auto Buffer, size_t Size, off_t Offset) { __check_op(Read, ENOTSUP, (void *)Buffer, Size, Offset); }
|
||||
ssize_t Write(const auto Buffer, size_t Size, off_t Offset) { __check_op(Write, EROFS, (const void *)Buffer, Size, Offset); }
|
||||
int Truncate(off_t Size) { __check_op(Truncate, EROFS, Size); }
|
||||
int Open(int Flags, mode_t Mode) { __check_op(Open, ENOTSUP, Flags, Mode); }
|
||||
int Close() { __check_op(Close, ENOTSUP); }
|
||||
int Ioctl(unsigned long Request, void *Argp) { __check_op(Ioctl, ENOTSUP, Request, Argp); }
|
||||
ssize_t ReadDir(struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) { __check_op(ReadDir, ENOTSUP, Buffer, Size, Offset, Entries); }
|
||||
int MkDir(const char *Name, mode_t Mode, struct Inode **Result) { __check_op(MkDir, EROFS, Name, Mode, Result); }
|
||||
int RmDir(const char *Name) { __check_op(RmDir, EROFS, Name); }
|
||||
int SymLink(const char *Name, const char *Target, struct Inode **Result) { __check_op(SymLink, EROFS, Name, Target, Result); }
|
||||
ssize_t ReadLink(auto Buffer, size_t Size) { __check_op(ReadLink, ENOTSUP, (char *)Buffer, Size); }
|
||||
off_t Seek(off_t Offset) { __check_op(Seek, ENOTSUP, Offset); }
|
||||
int Stat(struct kstat *Stat) { __check_op(Stat, ENOTSUP, Stat); }
|
||||
|
||||
~FileNode() = delete;
|
||||
};
|
||||
|
||||
#undef __check_op
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
struct vfsInode
|
||||
{
|
||||
Inode Node;
|
||||
std::string Name;
|
||||
std::string FriendlyName;
|
||||
std::vector<Inode *> Children;
|
||||
};
|
||||
|
||||
class Virtual
|
||||
{
|
||||
private:
|
||||
NewLock(VirtualLock);
|
||||
|
||||
struct FSMountInfo
|
||||
{
|
||||
FileSystemInfo *fsi;
|
||||
Inode *Root;
|
||||
};
|
||||
|
||||
struct CacheNode
|
||||
{
|
||||
FileNode *fn;
|
||||
std::atomic_int References;
|
||||
};
|
||||
|
||||
std::unordered_map<dev_t, FSMountInfo> DeviceMap;
|
||||
std::atomic_bool RegisterLock = false;
|
||||
|
||||
FileNode *CacheSearchReturnLast(FileNode *Parent, const char **Path);
|
||||
FileNode *CacheRecursiveSearch(FileNode *Root, const char *NameOrPath, bool IsName);
|
||||
FileNode *CacheLookup(FileNode *Parent, const char *Path);
|
||||
FileNode *CreateCacheNode(FileNode *Parent, Inode *Node, const char *Name, mode_t Mode);
|
||||
|
||||
int RemoveCacheNode(FileNode *Node);
|
||||
|
||||
public:
|
||||
vfsInode *FileSystemRoots = nullptr;
|
||||
|
||||
/**
|
||||
* Default reserved roots:
|
||||
*
|
||||
* 0 - Native
|
||||
* 1 - Linux
|
||||
* 2 - Windows
|
||||
*/
|
||||
std::unordered_map<ino_t, FileNode *> FileRoots;
|
||||
|
||||
bool PathIsRelative(const char *Path);
|
||||
bool PathIsAbsolute(const char *Path) { return !PathIsRelative(Path); }
|
||||
|
||||
/**
|
||||
* Reserve a device number for a filesystem
|
||||
*
|
||||
* @note After this function is called, the filesystem must
|
||||
* call LateRegisterFileSystem to release the lock
|
||||
*/
|
||||
dev_t EarlyReserveDevice();
|
||||
|
||||
/**
|
||||
* Register a filesystem after the device number has been reserved
|
||||
*/
|
||||
int LateRegisterFileSystem(dev_t Device, FileSystemInfo *fsi, Inode *Root);
|
||||
|
||||
dev_t RegisterFileSystem(FileSystemInfo *fsi, Inode *Root);
|
||||
int UnregisterFileSystem(dev_t Device);
|
||||
|
||||
void AddRoot(Inode *Root);
|
||||
void AddRootAt(Inode *Root, size_t Index);
|
||||
bool SetRootAt(Inode *Root, size_t Index);
|
||||
void RemoveRoot(Inode *Root);
|
||||
FileNode *GetRoot(size_t Index);
|
||||
bool RootExists(size_t Index);
|
||||
|
||||
FileNode *Create(FileNode *Parent, const char *Name, mode_t Mode);
|
||||
FileNode *ForceCreate(FileNode *Parent, const char *Name, mode_t Mode);
|
||||
|
||||
FileNode *Mount(FileNode *Parent, Inode *Node, const char *Path);
|
||||
int Unmount(const char *Path);
|
||||
|
||||
FileNode *GetByPath(const char *Path, FileNode *Parent);
|
||||
std::string GetByNode(FileNode *Node);
|
||||
FileNode *CreateLink(const char *Path, FileNode *Parent, const char *Target);
|
||||
FileNode *CreateLink(const char *Path, FileNode *Parent, FileNode *Target);
|
||||
bool PathExists(const char *Path, FileNode *Parent);
|
||||
|
||||
int Remove(FileNode *Node);
|
||||
|
||||
void Initialize();
|
||||
Virtual();
|
||||
~Virtual();
|
||||
};
|
||||
|
||||
class FileDescriptorTable
|
||||
{
|
||||
public:
|
||||
struct Fildes
|
||||
{
|
||||
enum FildesType
|
||||
{
|
||||
FD_INODE,
|
||||
FD_PIPE,
|
||||
FD_SOCKET,
|
||||
} Type;
|
||||
mode_t Mode = 0;
|
||||
int Flags = 0;
|
||||
FileNode *Node = nullptr;
|
||||
int References = 0;
|
||||
off_t Offset = 0;
|
||||
|
||||
int operator==(const Fildes &other)
|
||||
{
|
||||
return Type == other.Type &&
|
||||
Mode == other.Mode &&
|
||||
Flags == other.Flags &&
|
||||
Node == other.Node &&
|
||||
References == other.References &&
|
||||
Offset == other.Offset;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
FileNode *fdDir = nullptr;
|
||||
void *Owner;
|
||||
|
||||
int AddFileDescriptor(const char *AbsolutePath, mode_t Mode, int Flags);
|
||||
int RemoveFileDescriptor(int FileDescriptor);
|
||||
int GetFreeFileDescriptor();
|
||||
|
||||
public:
|
||||
std::unordered_map<int, Fildes> FileMap;
|
||||
|
||||
int GetFlags(int FileDescriptor);
|
||||
int SetFlags(int FileDescriptor, int Flags);
|
||||
void Fork(FileDescriptorTable *Parent);
|
||||
|
||||
int usr_open(const char *pathname, int flags, mode_t mode);
|
||||
int usr_creat(const char *pathname, mode_t mode);
|
||||
ssize_t usr_read(int fd, void *buf, size_t count);
|
||||
ssize_t usr_write(int fd, const void *buf, size_t count);
|
||||
ssize_t usr_pread(int fd, void *buf, size_t count, off_t offset);
|
||||
ssize_t usr_pwrite(int fd, const void *buf, size_t count, off_t offset);
|
||||
int usr_close(int fd);
|
||||
off_t usr_lseek(int fd, off_t offset, int whence);
|
||||
int usr_stat(const char *pathname, struct kstat *statbuf);
|
||||
int usr_fstat(int fd, struct kstat *statbuf);
|
||||
int usr_lstat(const char *pathname, struct kstat *statbuf);
|
||||
int usr_dup(int oldfd);
|
||||
int usr_dup2(int oldfd, int newfd);
|
||||
int usr_ioctl(int fd, unsigned long request, void *argp);
|
||||
|
||||
FileDescriptorTable(void *Owner);
|
||||
~FileDescriptorTable() = default;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_FILESYSTEM_H__
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __FENNIX_KERNEL_FILESYSTEM_INITRD_H__
|
||||
#define __FENNIX_KERNEL_FILESYSTEM_INITRD_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <filesystem.hpp>
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
class Initrd
|
||||
{
|
||||
public:
|
||||
struct InitrdHeader
|
||||
{
|
||||
uint32_t nfiles;
|
||||
};
|
||||
|
||||
struct InitrdFileHeader
|
||||
{
|
||||
uint8_t magic;
|
||||
char name[64];
|
||||
uint32_t offset;
|
||||
uint32_t length;
|
||||
};
|
||||
|
||||
Initrd(uintptr_t Address);
|
||||
~Initrd();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_FILESYSTEM_INITRD_H__
|
86
Kernel/include/fs/fdt.hpp
Normal file
86
Kernel/include/fs/fdt.hpp
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fs/node.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
class FileDescriptorTable
|
||||
{
|
||||
public:
|
||||
struct Fildes
|
||||
{
|
||||
enum FildesType
|
||||
{
|
||||
FD_INODE,
|
||||
FD_PIPE,
|
||||
FD_SOCKET,
|
||||
} Type;
|
||||
mode_t Mode = 0;
|
||||
int Flags = 0;
|
||||
Node node = nullptr;
|
||||
int References = 0;
|
||||
off_t Offset = 0;
|
||||
|
||||
int operator==(const Fildes &other)
|
||||
{
|
||||
return Type == other.Type &&
|
||||
Mode == other.Mode &&
|
||||
Flags == other.Flags &&
|
||||
node.get() == other.node.get() &&
|
||||
References == other.References &&
|
||||
Offset == other.Offset;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
Node fdDir = nullptr;
|
||||
void *Owner;
|
||||
|
||||
int AddFileDescriptor(const char *AbsolutePath, mode_t Mode, int Flags);
|
||||
int RemoveFileDescriptor(int FileDescriptor);
|
||||
int GetFreeFileDescriptor();
|
||||
|
||||
public:
|
||||
std::unordered_map<int, Fildes> FileMap;
|
||||
|
||||
int GetFlags(int FileDescriptor);
|
||||
int SetFlags(int FileDescriptor, int Flags);
|
||||
void Fork(FileDescriptorTable *Parent);
|
||||
|
||||
int usr_open(const char *pathname, int flags, mode_t mode);
|
||||
int usr_creat(const char *pathname, mode_t mode);
|
||||
ssize_t usr_read(int fd, void *buf, size_t count);
|
||||
ssize_t usr_write(int fd, const void *buf, size_t count);
|
||||
ssize_t usr_pread(int fd, void *buf, size_t count, off_t offset);
|
||||
ssize_t usr_pwrite(int fd, const void *buf, size_t count, off_t offset);
|
||||
int usr_close(int fd);
|
||||
off_t usr_lseek(int fd, off_t offset, int whence);
|
||||
int usr_stat(const char *pathname, kstat *statbuf);
|
||||
int usr_fstat(int fd, kstat *statbuf);
|
||||
int usr_lstat(const char *pathname, kstat *statbuf);
|
||||
int usr_dup(int oldfd);
|
||||
int usr_dup2(int oldfd, int newfd);
|
||||
int usr_ioctl(int fd, unsigned long request, void *argp);
|
||||
|
||||
FileDescriptorTable(void *Owner);
|
||||
~FileDescriptorTable() = default;
|
||||
};
|
||||
}
|
207
Kernel/include/fs/node.hpp
Normal file
207
Kernel/include/fs/node.hpp
Normal file
@ -0,0 +1,207 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <interface/fs.h>
|
||||
#include <errno.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* This macro is used to check if a filesystem operation is available.
|
||||
*
|
||||
* TL;DR
|
||||
*
|
||||
* @code
|
||||
* if FileSystemInfo.Ops.op == nullptr
|
||||
* return -err
|
||||
* else
|
||||
* return FileSystemInfo.Ops.op(this->Node, ...);
|
||||
* @endcode
|
||||
*
|
||||
* @param op The operation to check.
|
||||
* @param err The error to return if the operation is not available.
|
||||
* @param ... The arguments to pass to the operation.
|
||||
*
|
||||
* @return The result of the operation.
|
||||
*/
|
||||
#define __check_op(op, err, ...) \
|
||||
if (unlikely(fsi->Ops.op == nullptr)) \
|
||||
return -err; \
|
||||
else \
|
||||
return fsi->Ops.op(this->inode, ##__VA_ARGS__)
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
class NodeObject
|
||||
{
|
||||
public:
|
||||
Inode *inode;
|
||||
FileSystemInfo *fsi;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t MountPoint : 1;
|
||||
uint8_t __reserved : 7;
|
||||
};
|
||||
uint8_t raw;
|
||||
} Flags;
|
||||
|
||||
int __Lookup(const char *Name, Inode **Node) { __check_op(Lookup, ENOTSUP, Name, Node); }
|
||||
int __Create(const char *Name, mode_t Mode, Inode **Node) { __check_op(Create, ENOTSUP, Name, Mode, Node); }
|
||||
int __Remove(const char *Name) { __check_op(Remove, ENOTSUP, Name); }
|
||||
int __Rename(const char *OldName, const char *NewName) { __check_op(Rename, ENOTSUP, OldName, NewName); }
|
||||
ssize_t __Read(auto Buffer, size_t Size, off_t Offset) { __check_op(Read, ENOTSUP, (void *)Buffer, Size, Offset); }
|
||||
ssize_t __Write(const auto Buffer, size_t Size, off_t Offset) { __check_op(Write, ENOTSUP, (const void *)Buffer, Size, Offset); }
|
||||
int __Truncate(off_t Size) { __check_op(Truncate, ENOTSUP, Size); }
|
||||
int __Open(int Flags, mode_t Mode) { __check_op(Open, ENOTSUP, Flags, Mode); }
|
||||
int __Close() { __check_op(Close, ENOTSUP); }
|
||||
int __Ioctl(unsigned long Request, void *Argp) { __check_op(Ioctl, ENOTSUP, Request, Argp); }
|
||||
ssize_t __ReadDir(struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries) { __check_op(ReadDir, ENOTSUP, Buffer, Size, Offset, Entries); }
|
||||
int __MkDir(const char *Name, mode_t Mode, struct Inode **Result) { __check_op(MkDir, ENOTSUP, Name, Mode, Result); }
|
||||
int __RmDir(const char *Name) { __check_op(RmDir, ENOTSUP, Name); }
|
||||
int __SymLink(const char *Name, const char *Target, struct Inode **Result) { __check_op(SymLink, ENOTSUP, Name, Target, Result); }
|
||||
ssize_t __ReadLink(auto Buffer, size_t Size) { __check_op(ReadLink, ENOTSUP, (char *)Buffer, Size); }
|
||||
off_t __Seek(off_t Offset) { __check_op(Seek, ENOTSUP, Offset); }
|
||||
int __Stat(struct kstat *Stat) { __check_op(Stat, ENOTSUP, Stat); }
|
||||
|
||||
~NodeObject()
|
||||
{
|
||||
debug("%#lx destructor called", this);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class NodeCache;
|
||||
|
||||
/**
|
||||
* @brief Node is a type that represents a filesystem node.
|
||||
* It is a shared pointer to a NodeCache object.
|
||||
*
|
||||
* If the refcount of the NodeCache object goes to zero, the data is synced to disk.
|
||||
*/
|
||||
typedef std::shared_ptr<NodeCache> Node;
|
||||
|
||||
/**
|
||||
* @brief NodeResult is a type that represents the result of a filesystem operation.
|
||||
* It contains a Node object and an error code.
|
||||
*/
|
||||
typedef struct NodeResult
|
||||
{
|
||||
/* Value must be the first member of the struct to allow for implicit conversion */
|
||||
Node Value;
|
||||
int Error;
|
||||
|
||||
operator bool() const { return Error == 0 && Value.get() != nullptr; }
|
||||
operator Node() const { return Value; }
|
||||
const char *what() const { return strerror(Error); }
|
||||
} eNode;
|
||||
|
||||
class NodeCache : public vfs::NodeObject
|
||||
{
|
||||
public:
|
||||
std::string Name, Path, Link;
|
||||
|
||||
/**
|
||||
* @brief Parent of this node
|
||||
*
|
||||
* Maximum depth is 1, otherwise undefined behavior.
|
||||
*/
|
||||
Node Parent;
|
||||
|
||||
/**
|
||||
* @brief Childrens of this node
|
||||
*
|
||||
* On access, children are loaded, but not children of children!
|
||||
* Accessing children of children is undefined behavior.
|
||||
*/
|
||||
std::vector<Node> Children;
|
||||
|
||||
std::string GetName() { return Name; }
|
||||
std::string GetPath() { return Path; }
|
||||
std::string GetLink() { return Link; }
|
||||
|
||||
bool IsDirectory() { return S_ISDIR(inode->Mode); }
|
||||
bool IsCharacterDevice() { return S_ISCHR(inode->Mode); }
|
||||
bool IsBlockDevice() { return S_ISBLK(inode->Mode); }
|
||||
bool IsRegularFile() { return S_ISREG(inode->Mode); }
|
||||
bool IsFIFO() { return S_ISFIFO(inode->Mode); }
|
||||
bool IsSymbolicLink() { return S_ISLNK(inode->Mode); }
|
||||
bool IsSocket() { return S_ISSOCK(inode->Mode); }
|
||||
bool IsMountPoint() { return Flags.MountPoint; }
|
||||
|
||||
/**
|
||||
* @brief Search through the cached children of this node
|
||||
*
|
||||
* Searches through the cached children of this node.
|
||||
*
|
||||
* @param Name The name to search for
|
||||
* @return 0 and a Node on success, ENOENT on failure
|
||||
*/
|
||||
eNode CachedSearch(std::string Name)
|
||||
{
|
||||
for (auto it = Children.begin(); it != Children.end(); ++it)
|
||||
{
|
||||
if ((*it).get() == nullptr)
|
||||
{
|
||||
Children.erase(it);
|
||||
continue;
|
||||
}
|
||||
|
||||
debug("comparing \"%s\" with \"%s\"", (*it)->Name.c_str(), Name.c_str());
|
||||
if ((*it)->Name == Name)
|
||||
{
|
||||
debug("\"%s\" found", Name.c_str());
|
||||
return {*it, 0};
|
||||
}
|
||||
}
|
||||
|
||||
return {nullptr, ENOENT};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the allocation size of this object
|
||||
*
|
||||
* @return The allocated size
|
||||
*/
|
||||
size_t GetAllocationSize()
|
||||
{
|
||||
size_t size = sizeof(NodeCache);
|
||||
size += Name.capacity();
|
||||
size += Path.capacity();
|
||||
size += Link.capacity();
|
||||
size += Children.capacity();
|
||||
return size;
|
||||
}
|
||||
|
||||
~NodeCache()
|
||||
{
|
||||
debug("%#lx\"%s\" destructor called", this, Name.c_str());
|
||||
|
||||
if (this->Parent)
|
||||
this->Parent->Children.erase(std::remove(this->Parent->Children.begin(), this->Parent->Children.end(), Node(this)), this->Parent->Children.end());
|
||||
|
||||
if (fsi->SuperOps.Synchronize)
|
||||
fsi->SuperOps.Synchronize(this->fsi, this->inode);
|
||||
|
||||
// FIXME: recursive deletion of nodes children
|
||||
}
|
||||
};
|
||||
|
||||
#undef __check_op
|
@ -17,7 +17,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
#include <memory.hpp>
|
||||
|
||||
namespace vfs
|
||||
@ -147,4 +147,4 @@ namespace vfs
|
||||
};
|
||||
}
|
||||
|
||||
bool MountRAMFS(FileNode *Parent, const char *Name, size_t Index);
|
||||
bool MountAndRootRAMFS(Node Parent, const char *Name, size_t Index);
|
@ -18,7 +18,7 @@
|
||||
#ifndef __FENNIX_KERNEL_FILESYSTEM_USTAR_H__
|
||||
#define __FENNIX_KERNEL_FILESYSTEM_USTAR_H__
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
|
||||
namespace vfs
|
||||
{
|
179
Kernel/include/fs/vfs.hpp
Normal file
179
Kernel/include/fs/vfs.hpp
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fs/fdt.hpp>
|
||||
#include <errno.h>
|
||||
#include <cwalk.h>
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
/* sanity checks */
|
||||
static_assert(DTTOIF(DT_FIFO) == S_IFIFO);
|
||||
static_assert(IFTODT(S_IFCHR) == DT_CHR);
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
class Virtual
|
||||
{
|
||||
private:
|
||||
std::unordered_map<dev_t, Node> Roots;
|
||||
std::unordered_map<dev_t, FileSystemInfo *> FileSystems;
|
||||
|
||||
public:
|
||||
#pragma region Utilities
|
||||
|
||||
inline bool PathIsRelative(const char *Path) { return cwk_path_is_relative(Path); }
|
||||
inline bool PathIsAbsolute(const char *Path) { return !PathIsRelative(Path); }
|
||||
inline bool PathIsRelative(std::string &Path) { return cwk_path_is_relative(Path.c_str()); }
|
||||
inline bool PathIsAbsolute(std::string &Path) { return !PathIsRelative(Path.c_str()); }
|
||||
|
||||
eNode Convert(Node node) { return {node, 0}; }
|
||||
|
||||
/**
|
||||
* @brief Converts an Inode to a Node
|
||||
*
|
||||
* Result of this function will be empty.
|
||||
* You are responsible to populate the Node.
|
||||
*
|
||||
* @param inode Inode to convert
|
||||
* @return eNode{Node, errno}
|
||||
*/
|
||||
eNode Convert(Inode *inode);
|
||||
|
||||
/**
|
||||
* @brief Converts an Inode to a Node
|
||||
*
|
||||
* Result of this function will be populated using the Parent Node.
|
||||
* This function will automatically assign the FSI, parents and children.
|
||||
*
|
||||
* @note Name and Path won't be set.
|
||||
*
|
||||
* @param Parent Parent Node
|
||||
* @param inode Inode to convert
|
||||
* @return eNode{Node, errno}
|
||||
*/
|
||||
eNode Convert(Node &Parent, Inode *inode);
|
||||
|
||||
/**
|
||||
* @brief Normalizes a path
|
||||
*
|
||||
* If the path is relative, it will be normalized using the Parent Node.
|
||||
* Example if Join is true:
|
||||
* Parent = /home/user/Desktop
|
||||
* Path = ../Documents
|
||||
* Result = /home/user/Documents
|
||||
*
|
||||
* If Join is false:
|
||||
* Path = /var/foo/bar/../../
|
||||
* Result = /var
|
||||
*
|
||||
* @param Parent Parent Node
|
||||
* @param Path Path to normalize
|
||||
* @param Join If true, the path will be joined with the Parent Node
|
||||
* @return Normalized Path
|
||||
*/
|
||||
std::string NormalizePath(Node &Parent, std::string Path, bool Join = false);
|
||||
|
||||
#pragma endregion Utilities
|
||||
|
||||
#pragma region Roots
|
||||
|
||||
bool RootExists(dev_t Index);
|
||||
eNode GetRoot(dev_t Index);
|
||||
ssize_t GetRoot(Node Index);
|
||||
int AddRoot(dev_t Index, Node Root, bool Replace = false);
|
||||
int AddRoot(dev_t Index, eNode Root, bool Replace = false) { return AddRoot(Index, Root.Value, Replace); }
|
||||
|
||||
#pragma endregion Roots
|
||||
|
||||
#pragma region Registrations
|
||||
|
||||
dev_t RegisterFileSystem(FileSystemInfo *fsi);
|
||||
int UnregisterFileSystem(dev_t Device);
|
||||
|
||||
#pragma endregion Registrations
|
||||
|
||||
#pragma region Node Operations
|
||||
|
||||
eNode Lookup(Node &Parent, std::string Path);
|
||||
|
||||
eNode Create(Node &Parent, std::string Name, mode_t Mode, bool ErrorIfExists = true);
|
||||
|
||||
int Remove(Node &Parent, std::string Name);
|
||||
int Remove(Node &node);
|
||||
|
||||
int Rename(Node &node, std::string NewName);
|
||||
|
||||
ssize_t Read(Node &Target, void *Buffer, size_t Size, off_t Offset);
|
||||
ssize_t Write(Node &Target, const void *Buffer, size_t Size, off_t Offset);
|
||||
|
||||
int Truncate(Node &Target, off_t Size);
|
||||
|
||||
/**
|
||||
* @brief Read directory entries
|
||||
*
|
||||
* @note This function includes "." and ".."
|
||||
*
|
||||
* @param Target
|
||||
* @param Buffer
|
||||
* @param Size
|
||||
* @param Offset
|
||||
* @param Entries
|
||||
* @return
|
||||
*/
|
||||
ssize_t ReadDirectory(Node &Target, kdirent *Buffer, size_t Size, off_t Offset, off_t Entries);
|
||||
|
||||
/**
|
||||
* @brief Read directory entries
|
||||
*
|
||||
* @note This function does NOT include "." and ".."
|
||||
*
|
||||
* @param Target
|
||||
* @return
|
||||
*/
|
||||
std::list<Node> ReadDirectory(Node &Target);
|
||||
|
||||
eNode CreateLink(Node &Parent, std::string Name, std::string Target);
|
||||
eNode CreateLink(Node &Parent, std::string Name, Node &Target) { return this->CreateLink(Parent, Name, Target->Path); }
|
||||
|
||||
int Stat(Node &Target, kstat *Stat);
|
||||
int ReadLink(Node &Target, char *Buffer, size_t Size) { return Target->__ReadLink(Buffer, Size); }
|
||||
off_t Seek(Node &Target, off_t Offset);
|
||||
|
||||
int Open(Node &Target, int Flags, mode_t Mode);
|
||||
int Close(Node &Target);
|
||||
int Ioctl(Node &Target, unsigned long Request, void *Argp) { return Target->__Ioctl(Request, Argp); }
|
||||
|
||||
#pragma endregion Node Operations
|
||||
|
||||
#pragma region Mounting
|
||||
|
||||
eNode Mount(Node &Parent, Inode *inode, std::string Name, FileSystemInfo *fsi);
|
||||
|
||||
int Umount(Node &node);
|
||||
int Umount(Node &Parent, std::string Name);
|
||||
|
||||
#pragma endregion Mounting
|
||||
|
||||
void Initialize();
|
||||
Virtual();
|
||||
~Virtual();
|
||||
};
|
||||
}
|
110
Kernel/include/interface/block.h
Normal file
110
Kernel/include/interface/block.h
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __FENNIX_API_BLOCK_H__
|
||||
#define __FENNIX_API_BLOCK_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#if __has_include(<interface/fs.h>)
|
||||
#include <interface/fs.h>
|
||||
#else
|
||||
#include <fs.h>
|
||||
#endif
|
||||
|
||||
struct BlockDevice
|
||||
{
|
||||
/**
|
||||
* @brief Base name of the device.
|
||||
*
|
||||
* This name is used to identify the device in the system. It should be unique
|
||||
* across all block devices. The kernel may append a number to this name to
|
||||
* create a unique device name (e.g., "ahci0", "ahci1").
|
||||
*/
|
||||
const char *Name;
|
||||
|
||||
/**
|
||||
* @brief Total size of the device in bytes.
|
||||
*
|
||||
* This value represents the total addressable storage capacity of the device.
|
||||
* It is used for bounds checking and partitioning.
|
||||
*/
|
||||
size_t Size;
|
||||
|
||||
/**
|
||||
* @brief Size of a single block in bytes.
|
||||
*
|
||||
* All read and write operations are performed in multiples of this block size.
|
||||
* Typical values are 512 or 4096 bytes.
|
||||
*/
|
||||
uint32_t BlockSize;
|
||||
|
||||
/**
|
||||
* @brief Number of blocks in the device.
|
||||
*
|
||||
* This value is calculated as Size / BlockSize. It represents the total number
|
||||
* of addressable blocks on the device.
|
||||
*/
|
||||
size_t BlockCount;
|
||||
|
||||
/**
|
||||
* @brief Pointer to the block device operations structure.
|
||||
*
|
||||
* This structure contains function pointers for various operations that can
|
||||
* be performed on the block device, such as read, write, and ioctl.
|
||||
*
|
||||
* Yea, inode operations are used for block devices too.
|
||||
*/
|
||||
const InodeOperations *Ops;
|
||||
|
||||
/**
|
||||
* @brief Opaque pointer to driver-specific or hardware-specific data.
|
||||
*
|
||||
* This field allows the driver to associate private context or state with the
|
||||
* device, such as controller registers or internal buffers.
|
||||
*/
|
||||
void *PrivateData;
|
||||
};
|
||||
|
||||
#ifndef __kernel__
|
||||
/**
|
||||
* @brief Registers a block device with the kernel block subsystem.
|
||||
*
|
||||
* This function should be called by block device drivers after initializing
|
||||
* a device. The kernel will take ownership of the device structure and assign
|
||||
* it a unique device ID. The device will then be accessible for filesystem
|
||||
* mounting and I/O operations.
|
||||
*
|
||||
* @param Device Pointer to a fully initialized BlockDevice structure. All required fields must be set and valid for the lifetime of the device.
|
||||
* @return Device ID (dev_t) assigned by the kernel on success, or an error code on failure.
|
||||
*/
|
||||
dev_t RegisterBlockDevice(struct BlockDevice *Device);
|
||||
|
||||
/**
|
||||
* @brief Unregisters a block device from the kernel block subsystem.
|
||||
*
|
||||
* This function should be called by drivers when a device is being removed
|
||||
* or is no longer available. The kernel will release any resources associated
|
||||
* with the device and invalidate its device ID.
|
||||
*
|
||||
* @param DeviceID The device ID (dev_t) previously returned by RegisterBlockDevice().
|
||||
* @return 0 on success, or an error code.
|
||||
*/
|
||||
int UnregisterBlockDevice(dev_t DeviceID);
|
||||
#endif // __kernel__
|
||||
|
||||
#endif // __FENNIX_API_BLOCK_H__
|
@ -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__
|
||||
|
@ -19,7 +19,7 @@
|
||||
#define __FENNIX_KERNEL_INTERNAL_MEMORY_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
#include <boot/binfo.h>
|
||||
#include <bitmap.hpp>
|
||||
#include <lock.hpp>
|
||||
|
@ -19,7 +19,7 @@
|
||||
#define __FENNIX_KERNEL_MEMORY_VMA_H__
|
||||
|
||||
#include <types.h>
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
#include <bitmap.hpp>
|
||||
#include <lock.hpp>
|
||||
#include <list>
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
#include <memory/va.hpp>
|
||||
#include <symbols.hpp>
|
||||
#include <memory.hpp>
|
||||
@ -219,7 +219,7 @@ namespace Tasking
|
||||
TaskArchitecture Architecture = TaskArchitecture::UnknownArchitecture;
|
||||
TaskCompatibility Compatibility = TaskCompatibility::UnknownPlatform;
|
||||
cwk_path_style PathStyle = CWK_STYLE_UNIX;
|
||||
FileNode *RootNode = nullptr;
|
||||
Node RootNode = nullptr;
|
||||
};
|
||||
|
||||
struct ThreadLocalStorage
|
||||
@ -445,7 +445,7 @@ namespace Tasking
|
||||
PID ID = -1;
|
||||
const char *Name = nullptr;
|
||||
PCB *Parent = nullptr;
|
||||
FileNode *ProcDirectory = nullptr;
|
||||
Node ProcDirectory = nullptr;
|
||||
|
||||
/* Statuses */
|
||||
std::atomic_int ExitCode;
|
||||
@ -489,14 +489,14 @@ namespace Tasking
|
||||
} Linux{};
|
||||
|
||||
/* Filesystem */
|
||||
FileNode *CWD;
|
||||
FileNode *Executable;
|
||||
Node CWD;
|
||||
Node Executable;
|
||||
FileDescriptorTable *FileDescriptors;
|
||||
|
||||
/* stdio */
|
||||
FileNode *stdin;
|
||||
FileNode *stdout;
|
||||
FileNode *stderr;
|
||||
Node stdin;
|
||||
Node stdout;
|
||||
Node stderr;
|
||||
/*TTY::TeletypeDriver*/ void *tty;
|
||||
|
||||
/* Memory */
|
||||
@ -521,7 +521,7 @@ namespace Tasking
|
||||
void SetState(TaskState state);
|
||||
void SetExitCode(int code);
|
||||
void Rename(const char *name);
|
||||
void SetWorkingDirectory(FileNode *node);
|
||||
void SetWorkingDirectory(Node node);
|
||||
void SetExe(const char *path);
|
||||
size_t GetSize();
|
||||
TCB *GetThread(TID ID);
|
||||
|
@ -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
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "kernel.h"
|
||||
|
||||
#include <filesystem/ustar.hpp>
|
||||
#include <fs/ustar.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <convert.h>
|
||||
#include <ints.hpp>
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
#include <boot/binfo.h>
|
||||
#ifdef __cplusplus
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
#include <display.hpp>
|
||||
#include <symbols.hpp>
|
||||
#include <kconfig.hpp>
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "tests/t.h"
|
||||
#endif
|
||||
|
||||
#include <filesystem/ustar.hpp>
|
||||
#include <fs/ustar.hpp>
|
||||
#include <subsystems.hpp>
|
||||
#include <kshell.hpp>
|
||||
#include <power.hpp>
|
||||
@ -70,11 +70,11 @@ int SpawnLinuxInit()
|
||||
"/startup/init"};
|
||||
|
||||
const char *foundPath = nullptr;
|
||||
FileNode *root = fs->GetRoot(1);
|
||||
Node root = fs->GetRoot(1);
|
||||
for (const std::string &path : fallbackPaths)
|
||||
{
|
||||
const char *str = path.c_str();
|
||||
if (!fs->PathExists(str, root))
|
||||
if (fs->Lookup(root, str) == false)
|
||||
continue;
|
||||
foundPath = str;
|
||||
break;
|
||||
@ -123,8 +123,6 @@ void KernelMainThread()
|
||||
|
||||
KPrint("Initializing Driver Manager");
|
||||
DriverManager = new Driver::Manager;
|
||||
TaskManager->CreateThread(thisProcess, Tasking::IP(Driver::ManagerDaemonWrapper))
|
||||
->Rename("Device Service");
|
||||
|
||||
KPrint("Loading Drivers");
|
||||
DriverManager->PreloadDrivers();
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "kernel.h"
|
||||
|
||||
#include <filesystem/ustar.hpp>
|
||||
#include <fs/ustar.hpp>
|
||||
#include <memory.hpp>
|
||||
|
||||
vfs::Virtual *fs = nullptr;
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "../cmds.hpp"
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
@ -28,7 +28,7 @@ void cmd_cat(const char *args)
|
||||
if (args[0] == '\0')
|
||||
return;
|
||||
|
||||
FileNode *node = fs->GetByPath(args, nullptr);
|
||||
Node node = fs->Lookup(thisProcess->CWD, args);
|
||||
|
||||
if (node == nullptr)
|
||||
{
|
||||
@ -48,11 +48,11 @@ void cmd_cat(const char *args)
|
||||
return;
|
||||
}
|
||||
|
||||
kstat stat = {};
|
||||
node->Stat(&stat);
|
||||
kstat stat;
|
||||
fs->Stat(node, &stat);
|
||||
|
||||
uint8_t *buffer = new uint8_t[stat.Size + 1];
|
||||
ssize_t rBytes = node->Read(buffer, stat.Size, 0);
|
||||
ssize_t rBytes = fs->Read(node, buffer, stat.Size, 0);
|
||||
if (rBytes > 0)
|
||||
printf("%s\n", buffer);
|
||||
else
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "../cmds.hpp"
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
@ -28,8 +28,7 @@ void cmd_cd(const char *args)
|
||||
if (args[0] == '\0')
|
||||
return;
|
||||
|
||||
FileNode *node = fs->GetByPath(args, nullptr);
|
||||
|
||||
Node node = fs->Lookup(thisProcess->CWD, args);
|
||||
if (node == nullptr)
|
||||
{
|
||||
printf("cd: %s: No such file or directory\n", args);
|
||||
@ -43,4 +42,5 @@ void cmd_cd(const char *args)
|
||||
}
|
||||
|
||||
thisProcess->CWD = node;
|
||||
debug("changed cwd to %s", node->Path.c_str());
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "../cmds.hpp"
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
#include <acpi.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
@ -38,9 +38,41 @@ void cmd_dump(const char *args)
|
||||
*strLen = '\0';
|
||||
strLen++;
|
||||
|
||||
void *Address = (void *)strtoul(strAddr, nullptr, 16);
|
||||
void *Address;
|
||||
unsigned long Length = strtoul(strLen, nullptr, 10);
|
||||
|
||||
Node root = fs->GetRoot(0);
|
||||
Node fileNode = fs->Lookup(root, strAddr);
|
||||
if (fileNode && !fileNode->IsDirectory() && !fileNode->IsFIFO() && !fileNode->IsSocket())
|
||||
{
|
||||
kstat stat;
|
||||
int status = fs->Stat(fileNode, &stat);
|
||||
if (status != 0)
|
||||
{
|
||||
printf("cannot get stat: %s\n", strerror(status));
|
||||
return;
|
||||
}
|
||||
|
||||
size_t size = stat.Size > (off_t)Length ? Length : stat.Size;
|
||||
Address = new char[size]; /* FIXME: memory leak */
|
||||
size_t read = fs->Read(fileNode, Address, size, 0);
|
||||
if (read < Length)
|
||||
{
|
||||
debug("clamp %lu to %lu", Length, read);
|
||||
Length = read;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fileNode)
|
||||
{
|
||||
printf("file %s cannot be dumped\n", strAddr);
|
||||
return;
|
||||
}
|
||||
Address = (void *)strtoul(strAddr, nullptr, 16);
|
||||
debug("address %s", strAddr);
|
||||
}
|
||||
|
||||
{
|
||||
unsigned char *AddressChar = (unsigned char *)Address;
|
||||
unsigned char Buffer[17];
|
||||
@ -74,4 +106,4 @@ void cmd_dump(const char *args)
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "../cmds.hpp"
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
#include <task.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "../cmds.hpp"
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
#include <task.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "../cmds.hpp"
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
#include <task.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
@ -17,98 +17,60 @@
|
||||
|
||||
#include "../cmds.hpp"
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
using namespace vfs;
|
||||
|
||||
const char *ColorNodeType(FileNode *node)
|
||||
const char *ColorNodeType(Node node)
|
||||
{
|
||||
if (node->IsRegularFile())
|
||||
return "\x1b[32m";
|
||||
return "\x1b[0m";
|
||||
else if (node->IsDirectory())
|
||||
return "\x1b[34m";
|
||||
return "\x1b[1;34m";
|
||||
else if (node->IsBlockDevice())
|
||||
return "\x1b[33m";
|
||||
return "\x1b[1;33m";
|
||||
else if (node->IsCharacterDevice())
|
||||
return "\x1b[33m";
|
||||
return "\x1b[1;33m";
|
||||
else if (node->IsFIFO())
|
||||
return "\x1b[33m";
|
||||
return "\x1b[0;33m";
|
||||
else if (node->IsSymbolicLink())
|
||||
return "\x1b[35m";
|
||||
return "\x1b[1;36m";
|
||||
else
|
||||
return "\x1b[0m";
|
||||
}
|
||||
|
||||
__no_sanitize("alignment") size_t MaxNameLength(FileNode *nodes)
|
||||
__no_sanitize("alignment") void PrintLS(Node node)
|
||||
{
|
||||
size_t maxLength = 0;
|
||||
|
||||
kdirent *dirBuffer = new kdirent[16];
|
||||
ssize_t read = 0;
|
||||
off_t offset = 0;
|
||||
while ((read = nodes->ReadDir(dirBuffer, sizeof(kdirent) * 16, offset, LONG_MAX)) > 0)
|
||||
{
|
||||
if (read / sizeof(kdirent) == 0)
|
||||
break;
|
||||
|
||||
off_t bufOffset = 0;
|
||||
debug("There are %ld entries in this directory", read / sizeof(kdirent));
|
||||
for (size_t i = 0; i < read / sizeof(kdirent); i++)
|
||||
{
|
||||
kdirent *dirent = (kdirent *)((uintptr_t)dirBuffer + bufOffset);
|
||||
if (dirent->d_reclen == 0)
|
||||
break;
|
||||
bufOffset += dirent->d_reclen;
|
||||
maxLength = std::max(maxLength, strlen(dirent->d_name));
|
||||
debug("dirent->d_name: %s (max length: %ld)", dirent->d_name, maxLength);
|
||||
}
|
||||
offset += read / sizeof(kdirent);
|
||||
}
|
||||
delete[] dirBuffer;
|
||||
return maxLength;
|
||||
}
|
||||
|
||||
__no_sanitize("alignment") void PrintLS(FileNode *node)
|
||||
{
|
||||
size_t maxNameLength = MaxNameLength(node);
|
||||
size_t maxNameLength = 0;
|
||||
int count = 0;
|
||||
bool first = true;
|
||||
|
||||
kdirent *dirBuffer = new kdirent[16];
|
||||
ssize_t read = 0;
|
||||
off_t offset = 0;
|
||||
while ((read = node->ReadDir(dirBuffer, sizeof(kdirent) * 16, offset, LONG_MAX)) > 0)
|
||||
{
|
||||
if (read / sizeof(kdirent) == 0)
|
||||
break;
|
||||
std::list<Node> children = fs->ReadDirectory(node);
|
||||
|
||||
off_t bufOffset = 0;
|
||||
for (size_t i = 0; i < read / sizeof(kdirent); i++)
|
||||
{
|
||||
if (count % 5 == 0 && !first)
|
||||
printf("\n");
|
||||
kdirent *dirent = (kdirent *)((uintptr_t)dirBuffer + bufOffset);
|
||||
if (dirent->d_reclen == 0)
|
||||
break;
|
||||
bufOffset += dirent->d_reclen;
|
||||
printf(" %s%-*s ", ColorNodeType(node), (int)maxNameLength, dirent->d_name);
|
||||
count++;
|
||||
first = false;
|
||||
}
|
||||
offset += read / sizeof(kdirent);
|
||||
for (auto &&i : children)
|
||||
std::max(maxNameLength, i->Name.length());
|
||||
|
||||
for (auto &&i : children)
|
||||
{
|
||||
if (count % 5 == 0 && !first)
|
||||
printf("\n");
|
||||
|
||||
printf(" %s%-*s ", ColorNodeType(i), (int)maxNameLength, i->Name.c_str());
|
||||
|
||||
count++;
|
||||
first = false;
|
||||
}
|
||||
|
||||
printf("\x1b[0m\n");
|
||||
delete[] dirBuffer;
|
||||
}
|
||||
|
||||
void cmd_ls(const char *args)
|
||||
{
|
||||
if (args[0] == '\0')
|
||||
{
|
||||
FileNode *rootNode = thisProcess->CWD;
|
||||
Node rootNode = thisProcess->CWD;
|
||||
|
||||
if (rootNode == nullptr)
|
||||
rootNode = fs->GetRoot(0);
|
||||
@ -117,7 +79,7 @@ void cmd_ls(const char *args)
|
||||
return;
|
||||
}
|
||||
|
||||
FileNode *thisNode = fs->GetByPath(args, nullptr);
|
||||
Node thisNode = fs->Lookup(thisProcess->CWD, args);
|
||||
|
||||
if (thisNode == nullptr)
|
||||
{
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "../cmds.hpp"
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
#include <acpi.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "../cmds.hpp"
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "../cmds.hpp"
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
#include <task.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "../cmds.hpp"
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "../cmds.hpp"
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
#include <task.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "../cmds.hpp"
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
#include <task.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "../cmds.hpp"
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
#include <task.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "../cmds.hpp"
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
#include <task.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
@ -17,70 +17,38 @@
|
||||
|
||||
#include "../cmds.hpp"
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
void tree_loop(FileNode *rootNode, int depth = 0)
|
||||
// Enhancing the tree_loop function to display a fancier tree structure
|
||||
|
||||
__no_sanitize("alignment") void tree_loop(Node rootNode, int depth = 0, std::string prefix = "")
|
||||
{
|
||||
// for (auto Child : rootNode->GetChildren(true))
|
||||
// {
|
||||
// Display->UpdateBuffer();
|
||||
// if (Child->Stat.IsType(DIRECTORY) || Child->Stat.IsType(MOUNTPOINT))
|
||||
// {
|
||||
// printf("%*s%*s%*s|- %s\n",
|
||||
// depth, "",
|
||||
// depth, "",
|
||||
// depth, "",
|
||||
// Child->FileName);
|
||||
// tree_loop(Child, depth + 1);
|
||||
// }
|
||||
// else
|
||||
// printf("%*s%*s%*s|- %s\n",
|
||||
// depth, "",
|
||||
// depth, "",
|
||||
// depth, "",
|
||||
// Child->FileName);
|
||||
// }
|
||||
std::list<Node> children = fs->ReadDirectory(rootNode);
|
||||
size_t count = children.size();
|
||||
size_t index = 0;
|
||||
|
||||
kdirent *dirBuffer = new kdirent[16];
|
||||
ssize_t read = 0;
|
||||
off_t offset = 0;
|
||||
while ((read = rootNode->ReadDir(dirBuffer, sizeof(kdirent) * 16, offset, LONG_MAX)) > 0)
|
||||
{
|
||||
if (read / sizeof(kdirent) == 0)
|
||||
break;
|
||||
for (auto &&child : children)
|
||||
{
|
||||
if (child->Name == "." || child->Name == "..")
|
||||
continue;
|
||||
|
||||
off_t bufOffset = 0;
|
||||
for (size_t i = 0; i < read / sizeof(kdirent); i++)
|
||||
{
|
||||
kdirent *dirent = (kdirent *)((uintptr_t)dirBuffer + bufOffset);
|
||||
if (dirent->d_reclen == 0)
|
||||
break;
|
||||
bufOffset += dirent->d_reclen;
|
||||
bool isLast = (++index == count);
|
||||
|
||||
if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0)
|
||||
continue;
|
||||
printf("%s%s- %s\n", prefix.c_str(), isLast ? "\\" : "|-", child->Name.c_str());
|
||||
|
||||
FileNode *node = fs->GetByPath(dirent->d_name, rootNode);
|
||||
if (node == nullptr)
|
||||
continue;
|
||||
|
||||
for (int i = 0; i < depth; i++)
|
||||
printf(" ");
|
||||
printf("|- %s\n", dirent->d_name);
|
||||
|
||||
if (node->IsDirectory())
|
||||
tree_loop(node, depth + 1);
|
||||
}
|
||||
offset += read;
|
||||
}
|
||||
delete[] dirBuffer;
|
||||
if (child->IsDirectory())
|
||||
{
|
||||
std::string newPrefix = prefix + (isLast ? " " : "| ");
|
||||
tree_loop(child, depth + 1, newPrefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cmd_tree(const char *args)
|
||||
{
|
||||
FileNode *rootNode = thisProcess->CWD;
|
||||
Node rootNode = thisProcess->CWD;
|
||||
if (args[0] == '\0')
|
||||
{
|
||||
if (rootNode == nullptr)
|
||||
@ -88,7 +56,7 @@ void cmd_tree(const char *args)
|
||||
}
|
||||
else
|
||||
{
|
||||
rootNode = fs->GetByPath(args, nullptr);
|
||||
rootNode = fs->Lookup(thisProcess->CWD, args);
|
||||
if (rootNode == nullptr)
|
||||
{
|
||||
printf("ls: %s: No such file or directory\n", args);
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "../cmds.hpp"
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "../cmds.hpp"
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "../cmds.hpp"
|
||||
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
#include <interface/driver.h>
|
||||
#include <interface/input.h>
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
#include <driver.hpp>
|
||||
#include <lock.hpp>
|
||||
#include <exec.hpp>
|
||||
@ -88,6 +88,7 @@ void KShellThread()
|
||||
|
||||
KPrint("Starting kernel shell...");
|
||||
thisThread->SetPriority(Tasking::TaskPriority::Normal);
|
||||
thisProcess->CWD = fs->GetRoot(0);
|
||||
|
||||
std::string strBuf = "";
|
||||
std::vector<std::string *> history;
|
||||
@ -97,7 +98,8 @@ void KShellThread()
|
||||
bool tabDblPress = false;
|
||||
|
||||
const char *keyDevPath = "/dev/input/keyboard";
|
||||
FileNode *kfd = fs->GetByPath(keyDevPath, fs->GetRoot(0));
|
||||
Node root = fs->GetRoot(0);
|
||||
Node kfd = fs->Lookup(root, keyDevPath);
|
||||
if (kfd == nullptr)
|
||||
{
|
||||
KPrint("Failed to open keyboard device!");
|
||||
@ -125,21 +127,20 @@ void KShellThread()
|
||||
debug("clearing strBuf(\"%s\")", strBuf.c_str());
|
||||
strBuf.clear();
|
||||
|
||||
FileNode *cwd = thisProcess->CWD;
|
||||
Node cwd = thisProcess->CWD;
|
||||
if (!cwd)
|
||||
cwd = fs->GetRoot(0);
|
||||
std::string cwdStr = fs->GetByNode(cwd);
|
||||
debug("cwd: %*s", (int)cwdStr.size(), cwdStr.c_str());
|
||||
debug("cwd: %s", cwd->Path.c_str());
|
||||
|
||||
printf("\x1b[1;34m%s@%s:%s$ \x1b[0m",
|
||||
"kernel", "fennix",
|
||||
cwdStr.c_str());
|
||||
cwd->Path.c_str());
|
||||
|
||||
KeyboardReport scBuf{};
|
||||
ssize_t nBytes;
|
||||
while (true)
|
||||
{
|
||||
nBytes = kfd->Read(&scBuf, sizeof(KeyboardReport), 0);
|
||||
nBytes = fs->Read(kfd, &scBuf, sizeof(KeyboardReport), 0);
|
||||
if (nBytes == 0)
|
||||
{
|
||||
debug("Empty read from keyboard device!");
|
||||
@ -561,14 +562,14 @@ void KShellThread()
|
||||
if (fs->PathIsRelative(cmd_only.c_str()))
|
||||
{
|
||||
path += cmd_only;
|
||||
if (!fs->PathExists(path.c_str(), nullptr))
|
||||
if (!fs->Lookup(root, path.c_str()))
|
||||
path = "/usr/bin/" + cmd_only;
|
||||
}
|
||||
else
|
||||
path = cmd_only;
|
||||
|
||||
debug("path: %s", path.c_str());
|
||||
if (fs->PathExists(path.c_str(), nullptr))
|
||||
if (fs->Lookup(root, path.c_str()))
|
||||
{
|
||||
const char *envp[5] = {
|
||||
"PATH=/bin:/usr/bin",
|
||||
|
@ -158,11 +158,9 @@ void terminate_header_stub()
|
||||
CPU::Stop(); /* FIXME: Panic */
|
||||
}
|
||||
|
||||
void exception_cleanup_stub(_Unwind_Reason_Code Code,
|
||||
_Unwind_Exception *Exception)
|
||||
void exception_cleanup_stub(_Unwind_Reason_Code Code, _Unwind_Exception *Exception)
|
||||
{
|
||||
fixme("exception_cleanup( %d %p ) called.",
|
||||
Code, Exception);
|
||||
fixme("exception_cleanup( %d %p ) called.", Code, Exception);
|
||||
}
|
||||
|
||||
extern "C" void *__cxa_allocate_exception(size_t thrown_size) throw()
|
||||
@ -175,12 +173,10 @@ extern "C" void *__cxa_allocate_exception(size_t thrown_size) throw()
|
||||
return Exception + 1;
|
||||
}
|
||||
|
||||
extern "C" __noreturn void __cxa_throw(void *thrown_object,
|
||||
std::type_info *tinfo,
|
||||
void (*dest)(void *))
|
||||
extern "C" __noreturn void __cxa_throw(void *thrown_object, void *tinfo, void (*dest)(void *))
|
||||
{
|
||||
trace("Throwing exception of type \"%s\". ( object: %p, destructor: %p )",
|
||||
tinfo->name(), thrown_object, dest);
|
||||
((std::type_info *)tinfo)->name(), thrown_object, dest);
|
||||
|
||||
__cxa_eh_globals *Globals = __cxa_get_globals();
|
||||
Globals->uncaughtExceptions++;
|
||||
@ -218,10 +214,9 @@ extern "C" void __cxa_throw_bad_array_new_length()
|
||||
fixme("__cxa_throw_bad_array_new_length() called.");
|
||||
}
|
||||
|
||||
extern "C" void __cxa_free_exception(void *thrown_exception)
|
||||
extern "C" void __cxa_free_exception(void *thrown_exception) throw()
|
||||
{
|
||||
fixme("__cxa_free_exception( %p ) called.",
|
||||
thrown_exception);
|
||||
fixme("__cxa_free_exception( %p ) called.", thrown_exception);
|
||||
}
|
||||
|
||||
__extension__ typedef int __guard __attribute__((mode(__DI__)));
|
||||
|
@ -1,227 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem.hpp>
|
||||
|
||||
#include <convert.h>
|
||||
#include <printf.h>
|
||||
#include <rand.hpp>
|
||||
#include <cwalk.h>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
FileNode *Virtual::CacheSearchReturnLast(FileNode *Parent, const char **Path)
|
||||
{
|
||||
assert(Parent != nullptr);
|
||||
|
||||
struct cwk_segment segment;
|
||||
if (!cwk_path_get_first_segment(*Path, &segment))
|
||||
{
|
||||
if (strcmp(*Path, Parent->fsi->RootName) == 0)
|
||||
return Parent;
|
||||
|
||||
ReturnLogError(nullptr, "Failed to get first segment of path");
|
||||
}
|
||||
|
||||
size_t segments = 0;
|
||||
while (cwk_path_get_next_segment(&segment))
|
||||
segments++;
|
||||
|
||||
if (segments == 0)
|
||||
return Parent;
|
||||
|
||||
const char *tmpPath = *Path;
|
||||
if (strncmp(tmpPath, "\x06root-", 6) == 0) /* FIXME: deduce the index */
|
||||
{
|
||||
tmpPath += 6;
|
||||
while (*tmpPath != '\0' && *tmpPath != '\x06')
|
||||
tmpPath++;
|
||||
if (*tmpPath == '\x06')
|
||||
tmpPath++;
|
||||
}
|
||||
else
|
||||
tmpPath = *Path;
|
||||
|
||||
FileNode *__Parent = Parent;
|
||||
if (this->PathIsAbsolute(tmpPath))
|
||||
{
|
||||
while (__Parent->Parent)
|
||||
__Parent = __Parent->Parent;
|
||||
}
|
||||
|
||||
cwk_path_get_first_segment(tmpPath, &segment);
|
||||
do
|
||||
{
|
||||
std::string segmentName(segment.begin, segment.size);
|
||||
|
||||
bool found = false;
|
||||
for (FileNode *fn : __Parent->Children)
|
||||
{
|
||||
if (fn->Name != segmentName)
|
||||
continue;
|
||||
|
||||
cwk_segment __seg = segment;
|
||||
assert(cwk_path_get_next_segment(&__seg)); /* There's something wrong */
|
||||
|
||||
__Parent = fn;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
*Path = segment.begin;
|
||||
break;
|
||||
}
|
||||
} while (cwk_path_get_next_segment(&segment));
|
||||
|
||||
return __Parent;
|
||||
}
|
||||
|
||||
FileNode *Virtual::CacheRecursiveSearch(FileNode *Root, const char *NameOrPath, bool IsName)
|
||||
{
|
||||
if (Root == nullptr)
|
||||
return nullptr;
|
||||
|
||||
debug("%s cache search for \"%s\" in \"%s\"",
|
||||
IsName ? "Relative" : "Absolute",
|
||||
NameOrPath,
|
||||
Root->Path.c_str());
|
||||
|
||||
struct cwk_segment segment;
|
||||
if (!cwk_path_get_first_segment(NameOrPath, &segment))
|
||||
{
|
||||
if (strcmp(NameOrPath, Root->fsi->RootName) == 0)
|
||||
return Root;
|
||||
ReturnLogError(nullptr, "Failed to get first segment of path");
|
||||
}
|
||||
|
||||
size_t segments = 0;
|
||||
while (cwk_path_get_next_segment(&segment))
|
||||
segments++;
|
||||
|
||||
if (IsName && segments == 0)
|
||||
{
|
||||
for (FileNode *fn : Root->Children)
|
||||
{
|
||||
if (fn->Name == NameOrPath)
|
||||
return fn;
|
||||
}
|
||||
|
||||
ReturnLogError(nullptr, "Failed to find \"%s\" in \"%s\"", NameOrPath, Root->Path.c_str());
|
||||
}
|
||||
|
||||
const char *path = NameOrPath;
|
||||
if (strncmp(path, "\x06root-", 6) == 0) /* FIXME: deduce the index */
|
||||
{
|
||||
path += 6;
|
||||
while (*path != '\0' && *path != '\x06')
|
||||
path++;
|
||||
if (*path == '\x06')
|
||||
path++;
|
||||
}
|
||||
else
|
||||
path = NameOrPath;
|
||||
|
||||
FileNode *__Parent = Root;
|
||||
if (this->PathIsAbsolute(path))
|
||||
{
|
||||
/* Get the root if Root is not the root 【・_・?】 */
|
||||
while (__Parent->Parent)
|
||||
__Parent = __Parent->Parent;
|
||||
}
|
||||
|
||||
cwk_path_get_first_segment(path, &segment);
|
||||
do
|
||||
{
|
||||
std::string segmentName(segment.begin, segment.size);
|
||||
|
||||
bool found = false;
|
||||
for (FileNode *fn : __Parent->Children)
|
||||
{
|
||||
if (fn->Name != segmentName)
|
||||
continue;
|
||||
|
||||
cwk_segment __seg = segment;
|
||||
if (!cwk_path_get_next_segment(&__seg))
|
||||
return fn;
|
||||
|
||||
__Parent = fn;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
break;
|
||||
} while (cwk_path_get_next_segment(&segment));
|
||||
|
||||
debug("Failed to find \"%s\" in \"%s\"", NameOrPath, Root->Path.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileNode *Virtual::CacheLookup(FileNode *Parent, const char *Path)
|
||||
{
|
||||
debug("Cache lookup for \"%s\"", Path);
|
||||
if (Parent == nullptr)
|
||||
Parent = thisProcess ? thisProcess->Info.RootNode : this->GetRoot(0);
|
||||
|
||||
FileNode *ret = CacheRecursiveSearch(Parent, Path, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
debug("Path \"%s\" not found", Path);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileNode *Virtual::CreateCacheNode(FileNode *Parent, Inode *Node, const char *Name, mode_t Mode)
|
||||
{
|
||||
FileNode *fn = new FileNode;
|
||||
fn->Name = Name;
|
||||
if (Parent)
|
||||
{
|
||||
fn->Path = Parent->Path + "/" + Name;
|
||||
Parent->Children.push_back(fn);
|
||||
}
|
||||
else
|
||||
fn->Path = Name;
|
||||
fn->Parent = Parent;
|
||||
fn->Node = Node;
|
||||
fn->fsi = DeviceMap[Node->Device].fsi;
|
||||
if (fn->fsi == nullptr)
|
||||
warn("Failed to find filesystem for device %d", Node->Device);
|
||||
|
||||
debug("Created cache node %s", fn->Path.c_str());
|
||||
return fn;
|
||||
}
|
||||
|
||||
int Virtual::RemoveCacheNode(FileNode *Node)
|
||||
{
|
||||
if (Node == nullptr)
|
||||
return -EINVAL;
|
||||
|
||||
if (Node->Parent)
|
||||
{
|
||||
Node->Parent->Children.erase(std::find(Node->Parent->Children.begin(), Node->Parent->Children.end(), Node));
|
||||
// delete Node;
|
||||
fixme("Node deletion is disabled for now (for debugging purposes)");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -1,390 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem.hpp>
|
||||
|
||||
#include <convert.h>
|
||||
#include <printf.h>
|
||||
#include <rand.hpp>
|
||||
#include <cwalk.h>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
bool Virtual::PathIsRelative(const char *Path)
|
||||
{
|
||||
return cwk_path_is_relative(Path);
|
||||
}
|
||||
|
||||
void Virtual::AddRoot(Inode *Root)
|
||||
{
|
||||
SmartLock(VirtualLock);
|
||||
FileSystemRoots->Children.push_back(Root);
|
||||
}
|
||||
|
||||
void Virtual::AddRootAt(Inode *Root, size_t Index)
|
||||
{
|
||||
SmartLock(VirtualLock);
|
||||
if (Index >= FileSystemRoots->Children.size())
|
||||
FileSystemRoots->Children.resize(Index + 1);
|
||||
|
||||
if (FileSystemRoots->Children[Index] == nullptr)
|
||||
FileSystemRoots->Children[Index] = Root;
|
||||
else
|
||||
{
|
||||
debug("Root %ld already exists", Index);
|
||||
}
|
||||
}
|
||||
|
||||
bool Virtual::SetRootAt(Inode *Root, size_t Index)
|
||||
{
|
||||
SmartLock(VirtualLock);
|
||||
assert(Index < FileSystemRoots->Children.size());
|
||||
|
||||
if (FileSystemRoots->Children[Index] != nullptr)
|
||||
{
|
||||
debug("Root %ld already exists", Index);
|
||||
return false;
|
||||
}
|
||||
FileSystemRoots->Children[Index] = Root;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Virtual::RemoveRoot(Inode *Root)
|
||||
{
|
||||
SmartLock(VirtualLock);
|
||||
for (size_t i = 0; i < FileSystemRoots->Children.size(); i++)
|
||||
{
|
||||
if (FileSystemRoots->Children[i] != Root)
|
||||
continue;
|
||||
FileSystemRoots->Children[i] = nullptr;
|
||||
break;
|
||||
}
|
||||
debug("removed root %p", Root);
|
||||
}
|
||||
|
||||
FileNode *Virtual::GetRoot(size_t Index)
|
||||
{
|
||||
assert(Index < FileSystemRoots->Children.size());
|
||||
|
||||
auto it = FileRoots.find(Index);
|
||||
if (it != FileRoots.end())
|
||||
return it->second;
|
||||
|
||||
Inode *rootNode = FileSystemRoots->Children[Index];
|
||||
assert(rootNode != nullptr);
|
||||
char rootName[128]{};
|
||||
snprintf(rootName, sizeof(rootName), "\x06root-%ld\x06", Index);
|
||||
FileNode *ret = this->CreateCacheNode(nullptr, rootNode, rootName, 0);
|
||||
FileRoots.insert({Index, ret});
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Virtual::RootExists(size_t Index)
|
||||
{
|
||||
if (Index >= FileSystemRoots->Children.size())
|
||||
return false;
|
||||
return FileSystemRoots->Children[Index] != nullptr;
|
||||
}
|
||||
|
||||
FileNode *Virtual::Create(FileNode *Parent, const char *Name, mode_t Mode)
|
||||
{
|
||||
FileNode *existingNode = this->GetByPath(Name, Parent);
|
||||
if (existingNode != nullptr)
|
||||
ReturnLogError(existingNode, "File %s already exists", Name);
|
||||
|
||||
if (Parent == nullptr)
|
||||
{
|
||||
assert(thisProcess != nullptr);
|
||||
Parent = thisProcess->Info.RootNode;
|
||||
}
|
||||
|
||||
auto it = DeviceMap.find(Parent->Node->Device);
|
||||
if (it == DeviceMap.end())
|
||||
ReturnLogError(nullptr, "Device %d not found", Parent->Node->Device);
|
||||
|
||||
Inode *Node = NULL;
|
||||
if (it->second.fsi->Ops.Create == NULL)
|
||||
ReturnLogError(nullptr, "Create not supported for %d", it->first);
|
||||
|
||||
int ret = it->second.fsi->Ops.Create(Parent->Node, Name, Mode, &Node);
|
||||
if (ret < 0)
|
||||
ReturnLogError(nullptr, "Create for %d failed with %d", it->first, ret);
|
||||
|
||||
return this->CreateCacheNode(Parent, Node, Name, Mode);
|
||||
}
|
||||
|
||||
FileNode *Virtual::ForceCreate(FileNode *Parent, const char *Name, mode_t Mode)
|
||||
{
|
||||
fixme("ForceCreate: %s", Name);
|
||||
return this->Create(Parent, Name, Mode);
|
||||
}
|
||||
|
||||
FileNode *Virtual::Mount(FileNode *Parent, Inode *Node, const char *Path)
|
||||
{
|
||||
char *path = strdup(Path);
|
||||
char *lastSlash = strrchr(path, '/');
|
||||
if (lastSlash)
|
||||
{
|
||||
if (lastSlash == path)
|
||||
lastSlash++;
|
||||
*lastSlash = '\0';
|
||||
}
|
||||
|
||||
FileNode *parentNode = this->GetByPath(path, Parent);
|
||||
if (parentNode == nullptr && Parent != nullptr)
|
||||
parentNode = Parent;
|
||||
free(path);
|
||||
lastSlash = strrchr(Path, '/');
|
||||
if (lastSlash)
|
||||
lastSlash++;
|
||||
else
|
||||
lastSlash = (char *)Path;
|
||||
return this->CreateCacheNode(parentNode, Node, lastSlash, Node->Mode);
|
||||
}
|
||||
|
||||
int Virtual::Unmount(const char *Path)
|
||||
{
|
||||
FileNode *node = this->GetByPath(Path, nullptr);
|
||||
if (node == nullptr)
|
||||
ReturnLogError(-ENOENT, "Path %s not found", Path);
|
||||
|
||||
return this->RemoveCacheNode(node);
|
||||
}
|
||||
|
||||
FileNode *Virtual::GetByPath(const char *Path, FileNode *Parent)
|
||||
{
|
||||
debug("GetByPath: %s", Path);
|
||||
if (Parent == nullptr)
|
||||
{
|
||||
if (fs->PathIsRelative(Path))
|
||||
Parent = thisProcess ? thisProcess->CWD : thisProcess->Info.RootNode;
|
||||
else
|
||||
Parent = thisProcess ? thisProcess->Info.RootNode : this->GetRoot(0);
|
||||
}
|
||||
|
||||
if (strcmp(Path, ".") == 0)
|
||||
return Parent;
|
||||
|
||||
if (strcmp(Path, "..") == 0)
|
||||
return Parent->Parent ? Parent->Parent : Parent;
|
||||
|
||||
FileNode *fn = this->CacheRecursiveSearch(Parent, Path, this->PathIsRelative(Path));
|
||||
if (fn)
|
||||
return fn;
|
||||
|
||||
if (strncmp(Path, "\x06root-", 6) == 0) /* FIXME: deduce the index */
|
||||
{
|
||||
Path += 7;
|
||||
while (*Path != '\0' && *Path != '\x06')
|
||||
Path++;
|
||||
if (*Path == '\x06')
|
||||
Path++;
|
||||
}
|
||||
|
||||
FileNode *__Parent = CacheSearchReturnLast(Parent, &Path);
|
||||
|
||||
struct cwk_segment segment;
|
||||
if (!cwk_path_get_first_segment(Path, &segment))
|
||||
{
|
||||
auto it = DeviceMap.find(Parent->Node->Device);
|
||||
if (unlikely(it == DeviceMap.end()))
|
||||
ReturnLogError(nullptr, "Device %d not found", Parent->Node->Device);
|
||||
|
||||
if (it->second.fsi->Ops.Lookup == NULL)
|
||||
ReturnLogError(nullptr, "Lookup not supported for %d", it->first);
|
||||
|
||||
Inode *Node = NULL;
|
||||
int ret = it->second.fsi->Ops.Lookup(Parent->Node, Path, &Node);
|
||||
if (ret < 0)
|
||||
ReturnLogError(nullptr, "Lookup for \"%s\"(%d) failed with %d", Path, it->first, ret);
|
||||
|
||||
if (Parent->Node == Node) /* root / */
|
||||
{
|
||||
debug("Returning root (%#lx)", Node);
|
||||
return Parent;
|
||||
}
|
||||
ReturnLogError(nullptr, "Path has no segments");
|
||||
}
|
||||
|
||||
Inode *Node = NULL;
|
||||
bool readSymlinks = true; /* FIXME: implement */
|
||||
do
|
||||
{
|
||||
auto it = DeviceMap.find(__Parent->Node->Device);
|
||||
if (unlikely(it == DeviceMap.end()))
|
||||
ReturnLogError(nullptr, "Device %d not found", __Parent->Node->Device);
|
||||
debug("found fs %s", it->second.fsi->Name);
|
||||
|
||||
if (it->second.fsi->Ops.Lookup == NULL)
|
||||
ReturnLogError(nullptr, "Lookup not supported for %d", it->first);
|
||||
|
||||
if (readSymlinks && __Parent->IsSymbolicLink())
|
||||
{
|
||||
if (it->second.fsi->Ops.ReadLink == NULL)
|
||||
ReturnLogError(nullptr, "Readlink not supported for %d", it->first);
|
||||
|
||||
char buffer[256];
|
||||
int ret = it->second.fsi->Ops.ReadLink(__Parent->Node, buffer, sizeof(buffer));
|
||||
if (ret < 0)
|
||||
ReturnLogError(nullptr, "Readlink for \"%s\"(%d) failed with %d", __Parent->Path.c_str(), it->first, ret);
|
||||
|
||||
FileNode *target = this->GetByPath(buffer, __Parent->Parent ? __Parent->Parent : __Parent);
|
||||
if (target == nullptr)
|
||||
ReturnLogError(nullptr, "Failed to find target for \"%s\"", __Parent->Path.c_str());
|
||||
__Parent = target;
|
||||
}
|
||||
|
||||
std::string segmentName(segment.begin, segment.size);
|
||||
int ret = it->second.fsi->Ops.Lookup(__Parent->Node, segmentName.c_str(), &Node);
|
||||
if (ret < 0)
|
||||
ReturnLogError(nullptr, "Lookup for \"%s\"(%d) failed with %d", segmentName.c_str(), it->first, ret);
|
||||
__Parent = this->CreateCacheNode(__Parent, Node, segmentName.c_str(), 0);
|
||||
} while (cwk_path_get_next_segment(&segment));
|
||||
|
||||
FileNode *ret = __Parent;
|
||||
if (!ret->IsDirectory())
|
||||
return ret;
|
||||
|
||||
auto it = DeviceMap.find(__Parent->Node->Device);
|
||||
if (unlikely(it == DeviceMap.end()))
|
||||
ReturnLogError(nullptr, "Device %d not found", __Parent->Node->Device);
|
||||
|
||||
size_t dirAllocLen = sizeof(struct kdirent) + strlen(Path);
|
||||
struct kdirent *dirent = (struct kdirent *)malloc(dirAllocLen);
|
||||
size_t offset = 2; /* Skip . and .. */
|
||||
while (it->second.fsi->Ops.ReadDir(Node, dirent, dirAllocLen, offset++, 1) > 0)
|
||||
{
|
||||
Inode *ChildNode = NULL;
|
||||
int luRet = it->second.fsi->Ops.Lookup(Node, dirent->d_name, &ChildNode);
|
||||
if (luRet < 0)
|
||||
{
|
||||
debug("Lookup for %d failed with %d", it->first, luRet);
|
||||
break;
|
||||
}
|
||||
|
||||
this->CreateCacheNode(ret, ChildNode, dirent->d_name, 0);
|
||||
}
|
||||
free(dirent);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string Virtual::GetByNode(FileNode *Node)
|
||||
{
|
||||
assert(Node != nullptr);
|
||||
if (Node->Parent == nullptr)
|
||||
{
|
||||
if (Node->Node->Flags & I_FLAG_ROOT)
|
||||
return Node->fsi->RootName;
|
||||
assert(Node->Parent != nullptr);
|
||||
}
|
||||
|
||||
std::string path;
|
||||
|
||||
auto appendPath = [&path](const char *name)
|
||||
{
|
||||
if (path.size() > 0)
|
||||
path += "/";
|
||||
path += name;
|
||||
};
|
||||
|
||||
FileNode *current = Node;
|
||||
while (current->Parent != nullptr)
|
||||
{
|
||||
appendPath(current->Name.c_str());
|
||||
current = current->Parent;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
FileNode *Virtual::CreateLink(const char *Path, FileNode *Parent, const char *Target)
|
||||
{
|
||||
auto it = DeviceMap.find(Parent->Node->Device);
|
||||
if (it == DeviceMap.end())
|
||||
ReturnLogError(nullptr, "Device %d not found", Parent->Node->Device);
|
||||
|
||||
Inode *Node = NULL;
|
||||
|
||||
if (it->second.fsi->Ops.SymLink == NULL)
|
||||
ReturnLogError(nullptr, "SymLink not supported for %d", it->first);
|
||||
|
||||
int ret = it->second.fsi->Ops.SymLink(Parent->Node, Path, Target, &Node);
|
||||
if (ret < 0)
|
||||
ReturnLogError(nullptr, "SymLink for %d failed with %d", it->first, ret);
|
||||
return this->CreateCacheNode(Parent, Node, Path, 0);
|
||||
}
|
||||
|
||||
FileNode *Virtual::CreateLink(const char *Path, FileNode *Parent, FileNode *Target)
|
||||
{
|
||||
return this->CreateLink(Path, Parent, Target->Path.c_str());
|
||||
}
|
||||
|
||||
bool Virtual::PathExists(const char *Path, FileNode *Parent)
|
||||
{
|
||||
FileNode *fn = this->CacheLookup(Parent, Path);
|
||||
if (fn)
|
||||
return true;
|
||||
|
||||
FileNode *Node = this->GetByPath(Path, Parent);
|
||||
if (Node)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int Virtual::Remove(FileNode *Node)
|
||||
{
|
||||
auto it = DeviceMap.find(Node->Node->Device);
|
||||
if (it == DeviceMap.end())
|
||||
ReturnLogError(-ENODEV, "Device %d not found", Node->Node->Device);
|
||||
|
||||
if (it->second.fsi->Ops.Remove == NULL)
|
||||
ReturnLogError(-ENOTSUP, "Remove not supported for %d", it->first);
|
||||
|
||||
int ret = it->second.fsi->Ops.Remove(Node->Parent->Node, Node->Name.c_str());
|
||||
if (ret < 0)
|
||||
ReturnLogError(ret, "Remove for %d failed with %d", it->first, ret);
|
||||
|
||||
this->RemoveCacheNode(Node);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::string FileNode::GetName()
|
||||
{
|
||||
return this->Name;
|
||||
}
|
||||
|
||||
std::string FileNode::GetPath()
|
||||
{
|
||||
const char *path = this->Path.c_str();
|
||||
if (strncmp(path, "\x06root-", 6) == 0) /* FIXME: deduce the index */
|
||||
{
|
||||
path += 6;
|
||||
while (*path != '\0' && *path != '\x06')
|
||||
path++;
|
||||
if (*path == '\x06')
|
||||
path++;
|
||||
}
|
||||
else
|
||||
return this->Path;
|
||||
|
||||
if (path[0] == '\0')
|
||||
return std::string(this->fsi->RootName);
|
||||
return std::string(path);
|
||||
}
|
@ -1,257 +0,0 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem.hpp>
|
||||
|
||||
#include <convert.h>
|
||||
#include <printf.h>
|
||||
#include <cwalk.h>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
namespace vfs
|
||||
{
|
||||
/* maj = 0
|
||||
min:
|
||||
0 - <ROOT>
|
||||
1 - /proc/self
|
||||
...
|
||||
*/
|
||||
|
||||
int __vfs_Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result)
|
||||
{
|
||||
vfsInode *Parent = (vfsInode *)_Parent;
|
||||
|
||||
if (!S_ISDIR(Parent->Node.Mode))
|
||||
return -ENOTDIR;
|
||||
|
||||
assert(Parent->Node.Flags & I_FLAG_MOUNTPOINT);
|
||||
|
||||
if (Parent->Children.empty())
|
||||
return -ENOENT;
|
||||
|
||||
off_t offset = 0;
|
||||
for (const auto &Root : Parent->Children)
|
||||
{
|
||||
char rootName[128]{};
|
||||
snprintf(rootName, sizeof(rootName), "\x06root-%ld\x06", offset);
|
||||
|
||||
if (strcmp(rootName, Name) == 0)
|
||||
{
|
||||
*Result = Root;
|
||||
return 0;
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int __vfs_Create(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result)
|
||||
{
|
||||
assert(Parent != nullptr);
|
||||
assert(!"Not implemented");
|
||||
}
|
||||
|
||||
/* This implementation is used internally by the kernel, so no "." & ".." */
|
||||
__no_sanitize("alignment")
|
||||
ssize_t __vfs_Readdir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
|
||||
{
|
||||
if (_Node->GetMinor() != 0)
|
||||
{
|
||||
debug("_Node->GetMinor() != 0");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
assert(_Node->Flags & I_FLAG_MOUNTPOINT);
|
||||
|
||||
fixme("maybe wrong implementation of readdir");
|
||||
|
||||
size_t totalSize = 0;
|
||||
off_t entriesSkipped = 0;
|
||||
struct kdirent *ent = nullptr;
|
||||
vfsInode *Node = (vfsInode *)_Node;
|
||||
off_t entries = 0;
|
||||
for (const auto &Root : Node->Children)
|
||||
{
|
||||
if (entries >= Entries)
|
||||
break;
|
||||
|
||||
uint16_t reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen("root") + 1);
|
||||
|
||||
if (Offset > entriesSkipped)
|
||||
{
|
||||
entriesSkipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (totalSize + reclen >= Size)
|
||||
break;
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = Root->Index;
|
||||
ent->d_off = Root->Offset;
|
||||
ent->d_reclen = reclen;
|
||||
ent->d_type = IFTODT(Root->Mode);
|
||||
strncpy(ent->d_name, "root", strlen("root"));
|
||||
|
||||
totalSize += reclen;
|
||||
entries++;
|
||||
}
|
||||
|
||||
if (ent)
|
||||
ent->d_off = INT32_MAX;
|
||||
|
||||
if (totalSize + sizeof(struct kdirent) >= Size)
|
||||
return totalSize;
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = 0;
|
||||
ent->d_off = 0;
|
||||
ent->d_reclen = 0;
|
||||
ent->d_type = DT_UNKNOWN;
|
||||
ent->d_name[0] = '\0';
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
ssize_t __vfs_ReadLink(struct Inode *Node, char *Buffer, size_t Size)
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
/* FIXME: https://github.com/torvalds/linux/blob/c942a0cd3603e34dd2d7237e064d9318cb7f9654/fs/proc/self.c#L11
|
||||
https://lxr.linux.no/#linux+v3.2.9/fs/proc/base.c#L2482 */
|
||||
|
||||
int ret = snprintf(Buffer, Size, "/proc/%d", thisProcess->ID);
|
||||
debug("ReadLink: %s (%d bytes)", Buffer, ret);
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
void Virtual::Initialize()
|
||||
{
|
||||
SmartLock(VirtualLock);
|
||||
|
||||
trace("Initializing virtual file system...");
|
||||
uint32_t iFlags = I_FLAG_CACHE_KEEP;
|
||||
|
||||
/* d rwx rwx rwx */
|
||||
mode_t mode = S_IRWXU |
|
||||
S_IRWXG |
|
||||
S_IRWXO |
|
||||
S_IFDIR;
|
||||
FileNode *proc = this->ForceCreate(this->GetRoot(0), "proc", mode);
|
||||
FileNode *var = this->ForceCreate(this->GetRoot(0), "var", mode);
|
||||
FileNode *log = this->ForceCreate(var, "log", mode);
|
||||
proc->Node->Flags = iFlags;
|
||||
log->Node->Flags = iFlags;
|
||||
|
||||
/* l rwx rwx rwx */
|
||||
mode = S_IRWXU |
|
||||
S_IRWXG |
|
||||
S_IRWXO |
|
||||
S_IFLNK;
|
||||
FileNode *self = this->ForceCreate(proc, "self", mode);
|
||||
self->Node->Device = FileSystemRoots->Node.Device;
|
||||
self->Node->SetDevice(0, 1);
|
||||
self->Node->Flags = iFlags;
|
||||
}
|
||||
|
||||
dev_t Virtual::EarlyReserveDevice()
|
||||
{
|
||||
RegisterLock.store(true);
|
||||
size_t len = DeviceMap.size();
|
||||
return len;
|
||||
}
|
||||
|
||||
int Virtual::LateRegisterFileSystem(dev_t Device, FileSystemInfo *fsi, Inode *Root)
|
||||
{
|
||||
auto it = DeviceMap.find(Device);
|
||||
if (it != DeviceMap.end())
|
||||
ReturnLogError(-EEXIST, "Device %d already registered", Device);
|
||||
|
||||
Root->Flags |= I_FLAG_ROOT;
|
||||
FSMountInfo fsmi{.fsi = fsi, .Root = Root};
|
||||
DeviceMap.insert({Device, fsmi});
|
||||
RegisterLock.store(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_t Virtual::RegisterFileSystem(FileSystemInfo *fsi, Inode *Root)
|
||||
{
|
||||
RegisterLock.store(true);
|
||||
size_t len = DeviceMap.size();
|
||||
Root->Flags |= I_FLAG_ROOT;
|
||||
FSMountInfo fsmi{.fsi = fsi, .Root = Root};
|
||||
DeviceMap.insert({len, fsmi});
|
||||
RegisterLock.store(false);
|
||||
return len;
|
||||
}
|
||||
|
||||
int Virtual::UnregisterFileSystem(dev_t Device)
|
||||
{
|
||||
auto it = DeviceMap.find(Device);
|
||||
if (it == DeviceMap.end())
|
||||
ReturnLogError(-ENOENT, "Device %d not found", Device);
|
||||
|
||||
if (it->second.fsi->SuperOps.Synchronize)
|
||||
it->second.fsi->SuperOps.Synchronize(it->second.fsi, NULL);
|
||||
if (it->second.fsi->SuperOps.Destroy)
|
||||
it->second.fsi->SuperOps.Destroy(it->second.fsi);
|
||||
DeviceMap.erase(it);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Virtual::Virtual()
|
||||
{
|
||||
SmartLock(VirtualLock);
|
||||
|
||||
FileSystemRoots = new vfsInode;
|
||||
FileSystemRoots->Node.Index = -1;
|
||||
|
||||
FileSystemRoots->Node.Mode = S_IRWXU |
|
||||
S_IRWXG |
|
||||
S_IROTH | S_IXOTH |
|
||||
S_IFDIR;
|
||||
|
||||
FileSystemRoots->Node.Flags = I_FLAG_ROOT | I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
|
||||
|
||||
FileSystemRoots->Node.Offset = INT32_MAX;
|
||||
FileSystemRoots->Name = "<ROOT>";
|
||||
|
||||
FileSystemInfo *fsi = new FileSystemInfo;
|
||||
fsi->Name = "Virtual Roots";
|
||||
fsi->RootName = "ROOT";
|
||||
fsi->Flags = I_FLAG_ROOT | I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
|
||||
fsi->SuperOps = {};
|
||||
fsi->Ops.Lookup = __vfs_Lookup;
|
||||
fsi->Ops.Create = __vfs_Create;
|
||||
fsi->Ops.ReadDir = __vfs_Readdir;
|
||||
fsi->Ops.ReadLink = __vfs_ReadLink;
|
||||
|
||||
FileSystemRoots->Node.Device = this->RegisterFileSystem(fsi, &FileSystemRoots->Node);
|
||||
FileSystemRoots->Node.SetDevice(0, 0);
|
||||
}
|
||||
|
||||
Virtual::~Virtual()
|
||||
{
|
||||
}
|
||||
}
|
@ -15,45 +15,88 @@
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem/ramfs.hpp>
|
||||
#include <fs/ramfs.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
#include <fs/ustar.hpp>
|
||||
#include <ini.h>
|
||||
|
||||
namespace Subsystem::Linux
|
||||
{
|
||||
bool Initialized = false;
|
||||
|
||||
void __CreateStubRoot()
|
||||
{
|
||||
Node root = fs->GetRoot(0);
|
||||
Node nmnt = fs->Lookup(root, "/mnt");
|
||||
assert(MountAndRootRAMFS(nmnt, "linux", 1));
|
||||
Node linux = fs->GetRoot(1);
|
||||
|
||||
Node bin = fs->Create(linux, "bin", 0755);
|
||||
Node boot = fs->Create(linux, "boot", 0755);
|
||||
Node dev = fs->Create(linux, "dev", 0755);
|
||||
Node etc = fs->Create(linux, "etc", 0755);
|
||||
Node home = fs->Create(linux, "home", 0755);
|
||||
Node lib = fs->Create(linux, "lib", 0755);
|
||||
Node lib64 = fs->Create(linux, "lib64", 0755);
|
||||
Node media = fs->Create(linux, "media", 0755);
|
||||
Node mnt = fs->Create(linux, "mnt", 0755);
|
||||
Node opt = fs->Create(linux, "opt", 0755);
|
||||
Node proc = fs->Create(linux, "proc", 0755);
|
||||
|
||||
UNUSED(bin);
|
||||
UNUSED(boot);
|
||||
UNUSED(dev);
|
||||
UNUSED(etc);
|
||||
UNUSED(home);
|
||||
UNUSED(lib);
|
||||
UNUSED(lib64);
|
||||
UNUSED(media);
|
||||
UNUSED(mnt);
|
||||
UNUSED(opt);
|
||||
UNUSED(proc);
|
||||
}
|
||||
|
||||
void InitializeSubSystem()
|
||||
{
|
||||
if (fs->RootExists(1) == false)
|
||||
{
|
||||
FileNode *nmnt = fs->GetByPath("/mnt", fs->GetRoot(0));
|
||||
assert(MountRAMFS(nmnt, "linux", 1));
|
||||
FileNode *linux = fs->GetRoot(1);
|
||||
Node root = fs->GetRoot(0);
|
||||
Node cfg = fs->Lookup(root, "/sys/cfg/subsystem/linux");
|
||||
if (cfg)
|
||||
{
|
||||
struct kstat st;
|
||||
fs->Stat(cfg, &st);
|
||||
|
||||
FileNode *bin = fs->ForceCreate(linux, "bin", 0755);
|
||||
FileNode *boot = fs->ForceCreate(linux, "boot", 0755);
|
||||
FileNode *dev = fs->ForceCreate(linux, "dev", 0755);
|
||||
FileNode *etc = fs->ForceCreate(linux, "etc", 0755);
|
||||
FileNode *home = fs->ForceCreate(linux, "home", 0755);
|
||||
FileNode *lib = fs->ForceCreate(linux, "lib", 0755);
|
||||
FileNode *lib64 = fs->ForceCreate(linux, "lib64", 0755);
|
||||
FileNode *media = fs->ForceCreate(linux, "media", 0755);
|
||||
FileNode *mnt = fs->ForceCreate(linux, "mnt", 0755);
|
||||
FileNode *opt = fs->ForceCreate(linux, "opt", 0755);
|
||||
FileNode *proc = fs->ForceCreate(linux, "proc", 0755);
|
||||
std::unique_ptr<char[]> buf(new char[st.Size]);
|
||||
fs->Read(cfg, buf.get(), st.Size, 0);
|
||||
|
||||
UNUSED(bin);
|
||||
UNUSED(boot);
|
||||
UNUSED(dev);
|
||||
UNUSED(etc);
|
||||
UNUSED(home);
|
||||
UNUSED(lib);
|
||||
UNUSED(lib64);
|
||||
UNUSED(media);
|
||||
UNUSED(mnt);
|
||||
UNUSED(opt);
|
||||
UNUSED(proc);
|
||||
ini_t *ini = ini_load(buf.get(), NULL);
|
||||
int section = ini_find_section(ini, "rootfs", NULL);
|
||||
int pathIdx = ini_find_property(ini, section, "path", NULL);
|
||||
const char *uPath = ini_property_value(ini, section, pathIdx);
|
||||
debug("path=%s", uPath);
|
||||
ini_destroy(ini);
|
||||
|
||||
if (fs->Lookup(root, uPath) != false)
|
||||
{
|
||||
root = fs->Lookup(root, uPath);
|
||||
|
||||
// if (TestAndInitializeUSTAR(moduleAddress, moduleSize, 0))
|
||||
// {
|
||||
// }
|
||||
}
|
||||
else
|
||||
{
|
||||
warn("Couldn't find rootfs path %s", uPath);
|
||||
__CreateStubRoot();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
warn("Couldn't open /sys/cfg/subsystem/linux");
|
||||
__CreateStubRoot();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -816,7 +816,7 @@ static int linux_open(SysFrm *sf, const char *pathname, int flags, mode_t mode)
|
||||
|
||||
if (flags & 0200000 /* O_DIRECTORY */)
|
||||
{
|
||||
FileNode *node = fs->GetByPath(pPathname, pcb->CWD);
|
||||
Node node = fs->Lookup(pcb->CWD, pPathname);
|
||||
if (node == nullptr)
|
||||
{
|
||||
debug("Couldn't find %s", pPathname);
|
||||
@ -1313,7 +1313,7 @@ static int linux_access(SysFrm *, const char *pathname, int mode)
|
||||
|
||||
debug("access(%s, %d)", (char *)pPathname, mode);
|
||||
|
||||
if (!fs->PathExists(pPathname, pcb->CWD))
|
||||
if (!fs->Lookup(pcb->CWD, pPathname))
|
||||
return -linux_ENOENT;
|
||||
|
||||
stub;
|
||||
@ -1717,7 +1717,7 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn
|
||||
safeEnvp[i + 1] = nullptr;
|
||||
}
|
||||
|
||||
FileNode *file = fs->GetByPath(pPathname, pcb->CWD);
|
||||
Node file = fs->Lookup(pcb->CWD, pPathname);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
@ -1726,7 +1726,7 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn
|
||||
}
|
||||
|
||||
char shebangMagic[2]{};
|
||||
file->Read((uint8_t *)shebangMagic, 2, 0);
|
||||
fs->Read(file, (uint8_t *)shebangMagic, 2, 0);
|
||||
|
||||
if (shebangMagic[0] == '#' && shebangMagic[1] == '!')
|
||||
{
|
||||
@ -1740,7 +1740,7 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn
|
||||
while (true)
|
||||
{
|
||||
char c;
|
||||
if (file->Read((uint8_t *)&c, 1, shebangOffset) == 0)
|
||||
if (fs->Read(file, (uint8_t *)&c, 1, shebangOffset) == 0)
|
||||
break;
|
||||
if (c == '\n' || shebangLength == shebangLengthMax)
|
||||
break;
|
||||
@ -1870,7 +1870,7 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn
|
||||
cwk_path_get_basename(pPathname, &baseName, nullptr);
|
||||
|
||||
pcb->Rename(baseName);
|
||||
pcb->SetWorkingDirectory(file->Parent);
|
||||
pcb->SetWorkingDirectory(fs->Convert(file->Parent));
|
||||
pcb->SetExe(pPathname);
|
||||
|
||||
Tasking::Task *ctx = pcb->GetContext();
|
||||
@ -2208,14 +2208,15 @@ static int linux_uname(SysFrm *, struct utsname *buf)
|
||||
#endif
|
||||
};
|
||||
|
||||
FileNode *rn = fs->GetByPath("/sys/cfg/cross/linux", pcb->Info.RootNode);
|
||||
Node root = fs->GetRoot(0);
|
||||
Node rn = fs->Lookup(root, "/sys/cfg/subsystem/linux");
|
||||
if (rn)
|
||||
{
|
||||
struct kstat st{};
|
||||
rn->Stat(&st);
|
||||
struct kstat st;
|
||||
fs->Stat(rn, &st);
|
||||
|
||||
char *sh = new char[st.Size];
|
||||
rn->Read(sh, st.Size, 0);
|
||||
fs->Read(rn, sh, st.Size, 0);
|
||||
|
||||
ini_t *ini = ini_load(sh, NULL);
|
||||
int section = ini_find_section(ini, "uname", NULL);
|
||||
@ -2250,7 +2251,7 @@ static int linux_uname(SysFrm *, struct utsname *buf)
|
||||
delete[] sh;
|
||||
}
|
||||
else
|
||||
warn("Couldn't open /sys/cfg/cross/linux");
|
||||
warn("Couldn't open /sys/cfg/subsystem/linux");
|
||||
|
||||
memcpy(pBuf, &uname, sizeof(struct utsname));
|
||||
return 0;
|
||||
@ -2360,7 +2361,7 @@ static int linux_chdir(SysFrm *, const char *path)
|
||||
if (!pPath)
|
||||
return -linux_EFAULT;
|
||||
|
||||
FileNode *n = fs->GetByPath(pPath, pcb->CWD);
|
||||
Node n = fs->Lookup(pcb->CWD, pPath);
|
||||
if (!n)
|
||||
return -linux_ENOENT;
|
||||
|
||||
@ -2378,8 +2379,8 @@ static int linux_fchdir(SysFrm *, int fd)
|
||||
if (it == fdt->FileMap.end())
|
||||
return -linux_EBADF;
|
||||
|
||||
pcb->SetWorkingDirectory(it->second.Node);
|
||||
debug("Changed cwd to \"%s\"", it->second.Node->GetPath().c_str());
|
||||
pcb->SetWorkingDirectory(it->second.node);
|
||||
debug("Changed cwd to \"%s\"", it->second.node->GetPath().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2395,7 +2396,7 @@ static int linux_mkdir(SysFrm *, const char *pathname, mode_t mode)
|
||||
|
||||
mode &= ~pcb->FileCreationMask & 0777;
|
||||
|
||||
FileNode *n = fs->Create(pcb->CWD, pPathname, mode);
|
||||
Node n = fs->Create(pcb->CWD, pPathname, mode);
|
||||
if (!n)
|
||||
return -linux_EEXIST;
|
||||
return 0;
|
||||
@ -2432,13 +2433,13 @@ static ssize_t linux_readlink(SysFrm *, const char *pathname,
|
||||
ReturnLogError(-linux_EBADF, "Invalid fd %d", fd);
|
||||
|
||||
vfs::FileDescriptorTable::Fildes &fildes = it->second;
|
||||
FileNode *node = fildes.Node;
|
||||
Node node = fildes.node;
|
||||
fdt->usr_close(fd);
|
||||
|
||||
if (!node->IsSymbolicLink())
|
||||
return -linux_EINVAL;
|
||||
|
||||
return ConvertErrnoToLinux(node->ReadLink(pBuf, bufsiz));
|
||||
return ConvertErrnoToLinux(fs->ReadLink(node, pBuf, bufsiz));
|
||||
}
|
||||
|
||||
static int linux_fchmod(SysFrm *, int fd, mode_t mode)
|
||||
@ -2480,7 +2481,7 @@ static int linux_chmod(SysFrm *sf, const char *pathname, mode_t mode)
|
||||
if (pPathname == nullptr)
|
||||
return -linux_EFAULT;
|
||||
|
||||
FileNode *node = fs->GetByPath(pPathname, pcb->CWD);
|
||||
Node node = fs->Lookup(pcb->CWD, pPathname);
|
||||
if (!node)
|
||||
return -linux_ENOENT;
|
||||
|
||||
@ -3114,7 +3115,7 @@ __no_sanitize("undefined") static ssize_t linux_getdents64(SysFrm *,
|
||||
}
|
||||
|
||||
vfs::FileDescriptorTable::Fildes &fildes = it->second;
|
||||
if (!fildes.Node->IsDirectory())
|
||||
if (!fildes.node->IsDirectory())
|
||||
{
|
||||
debug("Not a directory");
|
||||
return -ENOTDIR;
|
||||
@ -3138,8 +3139,7 @@ __no_sanitize("undefined") static ssize_t linux_getdents64(SysFrm *,
|
||||
#endif
|
||||
|
||||
/* The structs are the same, no need for conversion. */
|
||||
ssize_t ret = fildes.Node->ReadDir((struct kdirent *)pDirp, count, fildes.Offset,
|
||||
count / sizeof(kdirent));
|
||||
ssize_t ret = fs->ReadDirectory(fildes.node, (struct kdirent *)pDirp, count, fildes.Offset, count / sizeof(kdirent));
|
||||
|
||||
if (ret > 0)
|
||||
fildes.Offset += ret;
|
||||
@ -3324,7 +3324,7 @@ static int linux_openat(SysFrm *, int dirfd, const char *pathname, int flags, mo
|
||||
|
||||
if (dirfd == linux_AT_FDCWD)
|
||||
{
|
||||
FileNode *absoluteNode = fs->GetByPath(pPathname, pcb->CWD);
|
||||
Node absoluteNode = fs->Lookup(pcb->CWD, pPathname);
|
||||
if (!absoluteNode)
|
||||
return -linux_ENOENT;
|
||||
|
||||
@ -3373,7 +3373,7 @@ static long linux_newfstatat(SysFrm *, int dirfd, const char *pathname,
|
||||
case linux_AT_FDCWD:
|
||||
{
|
||||
debug("dirfd is AT_FDCWD for \"%s\"", pPathname);
|
||||
FileNode *node = fs->GetByPath(pPathname, pcb->CWD);
|
||||
Node node = fs->Lookup(pcb->CWD, pPathname);
|
||||
if (!node)
|
||||
return -linux_ENOENT;
|
||||
|
||||
@ -3390,7 +3390,7 @@ static long linux_newfstatat(SysFrm *, int dirfd, const char *pathname,
|
||||
ReturnLogError(-linux_EBADF, "Invalid fd %d", dirfd);
|
||||
|
||||
vfs::FileDescriptorTable::Fildes &fildes = it->second;
|
||||
FileNode *node = fs->GetByPath(pPathname, fildes.Node);
|
||||
Node node = fs->Lookup(fildes.node, pPathname);
|
||||
debug("node: %s", node->GetPath().c_str());
|
||||
if (!node)
|
||||
return -linux_ENOENT;
|
||||
|
@ -15,7 +15,7 @@
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <filesystem/ramfs.hpp>
|
||||
#include <fs/ramfs.hpp>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
@ -23,25 +23,30 @@ namespace Subsystem::Windows
|
||||
{
|
||||
bool Initialized = false;
|
||||
|
||||
void __CreateStubRoot()
|
||||
{
|
||||
Node root = fs->GetRoot(0);
|
||||
Node nmnt = fs->Lookup(root, "/mnt");
|
||||
assert(MountAndRootRAMFS(nmnt, "windows", 2));
|
||||
Node win = fs->GetRoot(2);
|
||||
|
||||
Node windows = fs->Create(win, "Windows", 0755);
|
||||
Node programFiles = fs->Create(windows, "Program Files", 0755);
|
||||
Node programFilesX86 = fs->Create(windows, "Program Files (x86)", 0755);
|
||||
Node programData = fs->Create(windows, "ProgramData", 0755);
|
||||
Node users = fs->Create(windows, "Users", 0755);
|
||||
|
||||
UNUSED(windows);
|
||||
UNUSED(programFiles);
|
||||
UNUSED(programFilesX86);
|
||||
UNUSED(programData);
|
||||
UNUSED(users);
|
||||
}
|
||||
|
||||
void InitializeSubSystem()
|
||||
{
|
||||
if (fs->RootExists(2) == false)
|
||||
{
|
||||
FileNode *nmnt = fs->GetByPath("/mnt", fs->GetRoot(0));
|
||||
assert(MountRAMFS(nmnt, "windows", 2));
|
||||
FileNode *win = fs->GetRoot(2);
|
||||
|
||||
FileNode *windows = fs->ForceCreate(win, "Windows", 0755);
|
||||
FileNode *programFiles = fs->ForceCreate(windows, "Program Files", 0755);
|
||||
FileNode *programFilesX86 = fs->ForceCreate(windows, "Program Files (x86)", 0755);
|
||||
FileNode *programData = fs->ForceCreate(windows, "ProgramData", 0755);
|
||||
FileNode *users = fs->ForceCreate(windows, "Users", 0755);
|
||||
|
||||
UNUSED(windows);
|
||||
UNUSED(programFiles);
|
||||
UNUSED(programFilesX86);
|
||||
UNUSED(programData);
|
||||
UNUSED(users);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ static int sys_open(SysFrm *Frame, const char *pathname, int flags, mode_t mode)
|
||||
|
||||
if (flags & 0200000 /* O_DIRECTORY */)
|
||||
{
|
||||
FileNode *node = fs->GetByPath(pPathname, pcb->CWD);
|
||||
Node node = fs->Lookup(pcb->CWD, pPathname);
|
||||
if (node == nullptr)
|
||||
{
|
||||
debug("Couldn't find %s", pPathname);
|
||||
@ -150,7 +150,7 @@ static int sys_access(SysFrm *Frame, const char *pathname, int mode)
|
||||
|
||||
debug("access(%s, %d)", (char *)pPathname, mode);
|
||||
|
||||
if (!fs->PathExists(pPathname, pcb->CWD))
|
||||
if (!fs->Lookup(pcb->CWD, pPathname))
|
||||
return -ENOENT;
|
||||
|
||||
stub;
|
||||
|
@ -95,34 +95,34 @@ namespace Tasking
|
||||
strcpy((char *)this->Name, name);
|
||||
}
|
||||
|
||||
void PCB::SetWorkingDirectory(FileNode *node)
|
||||
void PCB::SetWorkingDirectory(Node node)
|
||||
{
|
||||
trace("Setting working directory of process %s to %#lx (%s)",
|
||||
this->Name, node, node->Name.c_str());
|
||||
CWD = node;
|
||||
FileNode *cwd = fs->GetByPath("cwd", ProcDirectory);
|
||||
trace("Setting working directory of process %s", node->Name.c_str());
|
||||
this->CWD = node;
|
||||
Node cwd = fs->Lookup(ProcDirectory, "cwd");
|
||||
if (cwd)
|
||||
fs->Remove(cwd);
|
||||
cwd = fs->CreateLink("cwd", ProcDirectory, node);
|
||||
cwd = fs->CreateLink(ProcDirectory, "cwd", node);
|
||||
if (cwd == nullptr)
|
||||
error("Failed to create cwd link");
|
||||
}
|
||||
|
||||
void PCB::SetExe(const char *path)
|
||||
{
|
||||
trace("Setting exe %s to %s",
|
||||
this->Name, path);
|
||||
Executable = fs->GetByPath(path, ProcDirectory);
|
||||
trace("Setting exe %s to %s", this->Name, path);
|
||||
|
||||
Executable = fs->Lookup(ProcDirectory, path);
|
||||
if (Executable->IsSymbolicLink())
|
||||
{
|
||||
char buffer[512];
|
||||
Executable->ReadLink(buffer, sizeof(buffer));
|
||||
Executable = fs->GetByPath(buffer, Executable->Parent);
|
||||
fs->ReadLink(Executable, buffer, sizeof(buffer));
|
||||
Executable = fs->Lookup(Executable->Parent, buffer);
|
||||
}
|
||||
FileNode *exe = fs->GetByPath("exe", ProcDirectory);
|
||||
|
||||
Node exe = fs->Lookup(ProcDirectory, "exe");
|
||||
if (exe)
|
||||
fs->Remove(exe);
|
||||
exe = fs->CreateLink("exe", ProcDirectory, path);
|
||||
exe = fs->CreateLink(ProcDirectory, "exe", path);
|
||||
if (exe == nullptr)
|
||||
error("Failed to create exe link");
|
||||
}
|
||||
@ -155,7 +155,8 @@ namespace Tasking
|
||||
assert(ExecutionMode >= _ExecuteModeMin);
|
||||
assert(ExecutionMode <= _ExecuteModeMax);
|
||||
|
||||
FileNode *procDir = fs->GetByPath("/proc", nullptr);
|
||||
Node root = fs->GetRoot(0);
|
||||
Node procDir = fs->Lookup(root, "/proc");
|
||||
assert(procDir != nullptr);
|
||||
|
||||
/* d r-x r-x r-x */
|
||||
|
@ -246,23 +246,222 @@ namespace Tasking
|
||||
debug("Tasking Started");
|
||||
}
|
||||
|
||||
struct TaskNode : public Inode
|
||||
{
|
||||
kstat Stat;
|
||||
Inode *Parent;
|
||||
std::string Name;
|
||||
std::vector<TaskNode *> Children;
|
||||
};
|
||||
|
||||
int __task_Lookup(struct Inode *Parent, const char *Name, struct Inode **Result)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int __task_Create(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result)
|
||||
{
|
||||
TaskNode *p = (TaskNode *)Parent;
|
||||
|
||||
if (!S_ISDIR(p->Mode))
|
||||
return -ENOTDIR;
|
||||
|
||||
TaskNode *newNode = new TaskNode;
|
||||
newNode->Parent = p;
|
||||
newNode->Name = Name;
|
||||
newNode->Mode = Mode;
|
||||
p->Children.push_back(newNode);
|
||||
*Result = newNode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t __task_Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
ssize_t __task_Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
__no_sanitize("alignment") ssize_t __task_Readdir(struct Inode *_Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries)
|
||||
{
|
||||
auto node = (TaskNode *)_Node;
|
||||
off_t realOffset = Offset;
|
||||
size_t totalSize = 0;
|
||||
uint16_t reclen = 0;
|
||||
struct kdirent *ent = nullptr;
|
||||
|
||||
if (!S_ISDIR(node->Mode))
|
||||
return -ENOTDIR;
|
||||
|
||||
if (Offset == 0)
|
||||
{
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(".") + 1);
|
||||
if (totalSize + reclen > Size)
|
||||
return -EINVAL;
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = node->Index;
|
||||
ent->d_off = 0;
|
||||
ent->d_reclen = reclen;
|
||||
ent->d_type = DT_DIR;
|
||||
strcpy(ent->d_name, ".");
|
||||
totalSize += reclen;
|
||||
Offset++;
|
||||
}
|
||||
|
||||
if (Offset == 1)
|
||||
{
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen("..") + 1);
|
||||
if (totalSize + reclen > Size)
|
||||
return totalSize;
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = node->Parent ? node->Parent->Index : 0;
|
||||
ent->d_off = 1;
|
||||
ent->d_reclen = reclen;
|
||||
ent->d_type = DT_DIR;
|
||||
strcpy(ent->d_name, "..");
|
||||
totalSize += reclen;
|
||||
Offset++;
|
||||
}
|
||||
|
||||
off_t entryIndex = 0;
|
||||
for (const auto &var : node->Children)
|
||||
{
|
||||
if (entryIndex + 2 < realOffset)
|
||||
{
|
||||
entryIndex++;
|
||||
continue;
|
||||
}
|
||||
if (Entries && entryIndex >= Entries)
|
||||
break;
|
||||
|
||||
reclen = (uint16_t)(offsetof(struct kdirent, d_name) + strlen(var->Name.c_str()) + 1);
|
||||
if (totalSize + reclen > Size)
|
||||
break;
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = var->Index;
|
||||
ent->d_off = entryIndex + 2;
|
||||
ent->d_reclen = reclen;
|
||||
ent->d_type = IFTODT(var->Mode);
|
||||
strcpy(ent->d_name, var->Name.c_str());
|
||||
totalSize += reclen;
|
||||
entryIndex++;
|
||||
}
|
||||
|
||||
if (totalSize + offsetof(struct kdirent, d_name) + 1 > Size)
|
||||
return totalSize;
|
||||
|
||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||
ent->d_ino = 0;
|
||||
ent->d_off = 0;
|
||||
ent->d_reclen = 0;
|
||||
ent->d_type = DT_UNKNOWN;
|
||||
ent->d_name[0] = '\0';
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
int __task_SymLink(Inode *Parent, const char *Name, const char *Target, Inode **Result)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
ssize_t __task_ReadLink(Inode *Node, char *Buffer, size_t Size)
|
||||
{
|
||||
switch (Node->GetMajor())
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
switch (Node->GetMinor())
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
/* FIXME: https://github.com/torvalds/linux/blob/c942a0cd3603e34dd2d7237e064d9318cb7f9654/fs/proc/self.c#L11
|
||||
https://lxr.linux.no/#linux+v3.2.9/fs/proc/base.c#L2482 */
|
||||
|
||||
int ret = snprintf(Buffer, Size, "/proc/%d", thisProcess->ID);
|
||||
debug("ReadLink: %s (%d bytes)", Buffer, ret);
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
int __task_Stat(struct Inode *Node, kstat *Stat)
|
||||
{
|
||||
TaskNode *node = (TaskNode *)Node;
|
||||
*Stat = node->Stat;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __task_AllocateInode(struct FileSystemInfo *, struct Inode **Result)
|
||||
{
|
||||
TaskNode *ret = new TaskNode;
|
||||
*Result = (Inode *)ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __task_DeleteInode(struct FileSystemInfo *, struct Inode *Node)
|
||||
{
|
||||
delete Node;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Task::Task(const IP EntryPoint)
|
||||
{
|
||||
Node root = fs->GetRoot(0);
|
||||
FileSystemInfo *fsi = new FileSystemInfo;
|
||||
fsi->Name = "procfs";
|
||||
fsi->SuperOps.AllocateInode = __task_AllocateInode;
|
||||
fsi->SuperOps.DeleteInode = __task_DeleteInode;
|
||||
fsi->Ops.Lookup = __task_Lookup;
|
||||
fsi->Ops.Create = __task_Create;
|
||||
fsi->Ops.Read = __task_Read;
|
||||
fsi->Ops.Write = __task_Write;
|
||||
fsi->Ops.ReadDir = __task_Readdir;
|
||||
fsi->Ops.SymLink = __task_SymLink;
|
||||
fsi->Ops.ReadLink = __task_ReadLink;
|
||||
fsi->Ops.Stat = __task_Stat;
|
||||
|
||||
/* d rwx rwx rwx */
|
||||
mode_t mode = S_IRWXU |
|
||||
S_IRWXG |
|
||||
S_IRWXO |
|
||||
S_IFDIR;
|
||||
TaskNode *inode = new TaskNode;
|
||||
inode->Device = fs->RegisterFileSystem(fsi);
|
||||
inode->Mode = mode;
|
||||
Node proc = fs->Mount(root, inode, "proc", fsi);
|
||||
// proc->fsi = fsi;
|
||||
// inode->Parent = root->inode;
|
||||
// inode->Name = "proc";
|
||||
|
||||
/* l rwx rwx rwx */
|
||||
mode = S_IRWXU |
|
||||
S_IRWXG |
|
||||
S_IRWXO |
|
||||
S_IFLNK;
|
||||
Node self = fs->Create(proc, "self", mode);
|
||||
self->inode->Device = inode->Device;
|
||||
self->inode->SetDevice(0, 0);
|
||||
|
||||
/* I don't know if this is the best way to do this. */
|
||||
Scheduler::Custom *custom_sched = new Scheduler::Custom(this);
|
||||
Scheduler::Base *sched = r_cst(Scheduler::Base *, custom_sched);
|
||||
__sched_ctx = custom_sched;
|
||||
Scheduler = sched;
|
||||
|
||||
KernelProcess = CreateProcess(nullptr, "Kernel",
|
||||
TaskExecutionMode::Kernel, true);
|
||||
KernelProcess->PageTable = KernelPageTable;
|
||||
TCB *kthrd = CreateThread(KernelProcess, EntryPoint,
|
||||
nullptr, nullptr,
|
||||
std::vector<AuxiliaryVector>(), GetKArch());
|
||||
KernelProcess = CreateProcess(nullptr, "Kernel", Kernel, true, 0, 0);
|
||||
TCB *kthrd = CreateThread(KernelProcess, EntryPoint, nullptr, nullptr, {}, GetKArch());
|
||||
kthrd->Rename("Main Thread");
|
||||
debug("Created Kernel Process: %s and Thread: %s",
|
||||
KernelProcess->Name, kthrd->Name);
|
||||
debug("Created Kernel Process: %s and Thread: %s", KernelProcess->Name, kthrd->Name);
|
||||
|
||||
if (!CPU::Interrupts(CPU::Check))
|
||||
{
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include <task.hpp>
|
||||
|
||||
#include <filesystem/ioctl.hpp>
|
||||
#include <fs/ioctl.hpp>
|
||||
#include <dumper.hpp>
|
||||
#include <convert.h>
|
||||
#include <lock.hpp>
|
||||
|
@ -18,11 +18,11 @@
|
||||
#ifdef DEBUG
|
||||
|
||||
#include <types.h>
|
||||
#include <filesystem/ioctl.hpp>
|
||||
#include <fs/ioctl.hpp>
|
||||
#include <interface/syscalls.h>
|
||||
#include <memory/macro.hpp>
|
||||
#include <memory/vma.hpp>
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
|
||||
|
94
Kernel/tests/readdir.cpp
Normal file
94
Kernel/tests/readdir.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
This file is part of Fennix Kernel.
|
||||
|
||||
Fennix Kernel is free software: you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
Fennix Kernel is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <fs/vfs.hpp>
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
void TestReadDirectory(Node &Target)
|
||||
{
|
||||
const size_t bufLen = 4096;
|
||||
std::unique_ptr<uint8_t[]> buf(new uint8_t[bufLen]);
|
||||
off_t off = 0;
|
||||
off_t max = LONG_MAX;
|
||||
|
||||
KPrint("Listing directory: \x1b[1;36m%s\x1b[0m", Target->Name.c_str());
|
||||
|
||||
while (true)
|
||||
{
|
||||
ssize_t bytes = fs->ReadDirectory(Target, (kdirent *)buf.get(), bufLen, off, max);
|
||||
if (bytes < 0)
|
||||
{
|
||||
KPrint("ReadDirectory returned error: %d", bytes);
|
||||
break;
|
||||
}
|
||||
if (bytes == 0)
|
||||
break;
|
||||
|
||||
ssize_t Pos = 0;
|
||||
while (Pos < bytes)
|
||||
{
|
||||
kdirent *Entry = (kdirent *)(buf.get() + Pos);
|
||||
if (Entry->d_reclen == 0)
|
||||
{
|
||||
KPrint("Entry with zero length detected at offset %ld!", off + Pos);
|
||||
break;
|
||||
}
|
||||
|
||||
KPrint("name=\"%s\" inode=%lu type=%u reclen=%u", Entry->d_name, Entry->d_ino, Entry->d_type, Entry->d_reclen);
|
||||
|
||||
Pos += Entry->d_reclen;
|
||||
}
|
||||
off += bytes;
|
||||
}
|
||||
}
|
||||
|
||||
void readdir_sanity_tests()
|
||||
{
|
||||
Node root = fs->GetRoot(0);
|
||||
Node t0 = fs->Lookup(root, "/");
|
||||
Node t1 = fs->Lookup(root, "/dev");
|
||||
Node t2 = fs->Lookup(root, "/home");
|
||||
Node t3 = fs->Lookup(root, "/var");
|
||||
Node t4 = fs->Lookup(root, "/tmp");
|
||||
|
||||
KPrint("TEST /");
|
||||
TestReadDirectory(t0);
|
||||
TaskManager->Sleep(2000);
|
||||
|
||||
KPrint("TEST /dev");
|
||||
TestReadDirectory(t1);
|
||||
TaskManager->Sleep(2000);
|
||||
|
||||
KPrint("TEST /home");
|
||||
TestReadDirectory(t2);
|
||||
TaskManager->Sleep(2000);
|
||||
|
||||
KPrint("TEST /var");
|
||||
TestReadDirectory(t3);
|
||||
TaskManager->Sleep(2000);
|
||||
|
||||
KPrint("TEST /tmp");
|
||||
TestReadDirectory(t4);
|
||||
TaskManager->Sleep(2000);
|
||||
|
||||
CPU::Stop();
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
@ -20,14 +20,14 @@
|
||||
#ifdef DEBUG
|
||||
|
||||
#include <types.h>
|
||||
#include <filesystem.hpp>
|
||||
#include <fs/vfs.hpp>
|
||||
|
||||
void Test_stl();
|
||||
void TestMemoryAllocation();
|
||||
void tasking_test_fb();
|
||||
void tasking_test_mutex();
|
||||
void TaskMgr();
|
||||
void TreeFS(FileNode *node, int Depth);
|
||||
void TreeFS(Node node, int Depth);
|
||||
void TaskHeartbeat();
|
||||
void StressKernel();
|
||||
void coroutineTest();
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
#include "../kernel.h"
|
||||
|
||||
void TreeFS(FileNode *node, int Depth)
|
||||
void TreeFS(Node node, int Depth)
|
||||
{
|
||||
return;
|
||||
// for (auto Chld : node->GetChildren(true))
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
#include <tty.hpp>
|
||||
#include <filesystem/ioctl.hpp>
|
||||
#include <fs/ioctl.hpp>
|
||||
#include <smp.hpp>
|
||||
#include <errno.h>
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include <kcon.hpp>
|
||||
|
||||
#include <filesystem/ioctl.hpp>
|
||||
#include <fs/ioctl.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <stropts.h>
|
||||
#include <string.h>
|
||||
|
Loading…
x
Reference in New Issue
Block a user