mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-05-28 15:34:31 +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);
|
int (*Stat)(struct Inode *Node, struct kstat *Stat);
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
#define I_FLAG_ROOT 0x1
|
|
||||||
#define I_FLAG_MOUNTPOINT 0x2
|
|
||||||
#define I_FLAG_CACHE_KEEP 0x4
|
|
||||||
|
|
||||||
struct FileSystemInfo;
|
struct FileSystemInfo;
|
||||||
struct SuperBlockOperations
|
struct SuperBlockOperations
|
||||||
{
|
{
|
||||||
@ -337,8 +333,8 @@ struct SuperBlockOperations
|
|||||||
*
|
*
|
||||||
* Write all pending changes to the disk.
|
* Write all pending changes to the disk.
|
||||||
*
|
*
|
||||||
* @param Info Inode to synchronize. If NULL, synchronize all inodes.
|
* @param Info Inode to synchronize.
|
||||||
* @param Node Inode to synchronize.
|
* @param Node Inode to synchronize. If NULL, synchronize all inodes.
|
||||||
*
|
*
|
||||||
* @return Zero on success, otherwise an error code.
|
* @return Zero on success, otherwise an error code.
|
||||||
*/
|
*/
|
||||||
@ -354,13 +350,50 @@ struct SuperBlockOperations
|
|||||||
* @return Zero on success, otherwise an error code.
|
* @return Zero on success, otherwise an error code.
|
||||||
*/
|
*/
|
||||||
int (*Destroy)(struct FileSystemInfo *Info);
|
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));
|
} __attribute__((packed));
|
||||||
|
|
||||||
struct FileSystemInfo
|
struct FileSystemInfo
|
||||||
{
|
{
|
||||||
const char *Name;
|
const char *Name;
|
||||||
const char *RootName;
|
|
||||||
int Flags;
|
int Flags;
|
||||||
|
int Capabilities;
|
||||||
|
|
||||||
struct SuperBlockOperations SuperOps;
|
struct SuperBlockOperations SuperOps;
|
||||||
struct InodeOperations Ops;
|
struct InodeOperations Ops;
|
||||||
|
|
||||||
@ -368,6 +401,9 @@ struct FileSystemInfo
|
|||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
#ifndef __kernel__
|
#ifndef __kernel__
|
||||||
|
dev_t RegisterMountPoint(FileSystemInfo *fsi, Inode *Root);
|
||||||
|
int UnregisterMountPoint(dev_t Device);
|
||||||
|
|
||||||
dev_t RegisterFileSystem(struct FileSystemInfo *Info, struct Inode *Root);
|
dev_t RegisterFileSystem(struct FileSystemInfo *Info, struct Inode *Root);
|
||||||
int UnregisterFileSystem(dev_t Device);
|
int UnregisterFileSystem(dev_t Device);
|
||||||
#endif // !__kernel__
|
#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))
|
- [ ] ~~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.
|
- [ ] Implementation of logging (beside serial) with log rotation.
|
||||||
- [x] Implement a better task manager. (replace struct P/TCB with classes)
|
- [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.
|
- [ ] Colors in crash screen are not following the kernel color scheme.
|
||||||
- [x] ~~Find a way to add intrinsics.~~ (not feasible, use inline assembly)
|
- [x] ~~Find a way to add intrinsics.~~ (not feasible, use inline assembly)
|
||||||
- [ ] Rework PSF1 font loader.
|
- [ ] Rework PSF1 font loader.
|
||||||
|
@ -156,15 +156,15 @@ namespace KernelConsole
|
|||||||
|
|
||||||
bool SetTheme(std::string Theme)
|
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)
|
if (rn == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
kstat st{};
|
kstat st;
|
||||||
rn->Stat(&st);
|
fs->Stat(rn, &st);
|
||||||
|
|
||||||
char *sh = new char[st.Size];
|
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);
|
ini_t *ini = ini_load(sh, NULL);
|
||||||
int themeSection, c0, c1, c2, c3, c4, c5, c6, c7, colorsIdx;
|
int themeSection, c0, c1, c2, c3, c4, c5, c6, c7, colorsIdx;
|
||||||
@ -370,16 +370,16 @@ namespace KernelConsole
|
|||||||
|
|
||||||
void LateInit()
|
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)
|
if (rn == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
{
|
{
|
||||||
kstat st;
|
kstat st;
|
||||||
rn->Stat(&st);
|
fs->Stat(rn, &st);
|
||||||
std::string cfg;
|
std::string cfg;
|
||||||
cfg.reserve(st.Size);
|
cfg.resize(st.Size);
|
||||||
rn->Read(cfg.data(), st.Size, 0);
|
fs->Read(rn, cfg.data(), st.Size, 0);
|
||||||
LoadConsoleConfig(cfg);
|
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)
|
int UnregisterFileSystem(dev_t DriverID, dev_t Device)
|
||||||
@ -710,6 +710,20 @@ namespace v0
|
|||||||
|
|
||||||
return DriverManager->ReportInputEvent(DriverID, Report);
|
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
|
struct APISymbols
|
||||||
@ -777,6 +791,8 @@ static struct APISymbols APISymbols_v0[] = {
|
|||||||
{"__RegisterDevice", (void *)v0::RegisterDevice},
|
{"__RegisterDevice", (void *)v0::RegisterDevice},
|
||||||
{"__UnregisterDevice", (void *)v0::UnregisterDevice},
|
{"__UnregisterDevice", (void *)v0::UnregisterDevice},
|
||||||
{"__ReportInputEvent", (void *)v0::ReportInputEvent},
|
{"__ReportInputEvent", (void *)v0::ReportInputEvent},
|
||||||
|
{"__RegisterBlockDevice", (void *)v0::RegisterBlockDevice},
|
||||||
|
{"__UnregisterBlockDevice", (void *)v0::UnregisterBlockDevice},
|
||||||
};
|
};
|
||||||
|
|
||||||
long __KernelUndefinedFunction(long arg0, long arg1, long arg2, long arg3,
|
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
|
namespace Driver
|
||||||
{
|
{
|
||||||
bool Manager::IsDriverTrusted(FileNode *File)
|
bool Manager::IsDriverTrusted(Node File)
|
||||||
{
|
{
|
||||||
kstat st;
|
kstat st;
|
||||||
File->Stat(&st);
|
fs->Stat(File, &st);
|
||||||
std::unique_ptr<uint8_t[]> ptr(new uint8_t[st.Size]);
|
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);
|
uint8_t *sha = sha512_sum(ptr.get(), st.Size);
|
||||||
char hash_str[129];
|
char hash_str[129];
|
||||||
for (int j = 0; j < 64; j++)
|
for (int j = 0; j < 64; j++)
|
||||||
@ -102,7 +102,8 @@ namespace Driver
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char *DriverDirectory = Config.DriverDirectory;
|
const char *DriverDirectory = Config.DriverDirectory;
|
||||||
FileNode *drvDirNode = fs->GetByPath(DriverDirectory, nullptr);
|
Node root = fs->GetRoot(0);
|
||||||
|
Node drvDirNode = fs->Lookup(root, DriverDirectory);
|
||||||
if (!drvDirNode)
|
if (!drvDirNode)
|
||||||
{
|
{
|
||||||
error("Failed to open driver directory %s", DriverDirectory);
|
error("Failed to open driver directory %s", DriverDirectory);
|
||||||
@ -110,7 +111,7 @@ namespace Driver
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &drvNode : drvDirNode->Children)
|
for (const auto &drvNode : fs->ReadDirectory(drvDirNode))
|
||||||
{
|
{
|
||||||
debug("Checking driver %s", drvNode->Path.c_str());
|
debug("Checking driver %s", drvNode->Path.c_str());
|
||||||
if (!drvNode->IsRegularFile())
|
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());
|
trace("Loading driver %s in memory", File->Name.c_str());
|
||||||
|
|
||||||
Elf_Ehdr ELFHeader{};
|
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_CLASS] == ELFCLASS64, -ENOEXEC);
|
||||||
AssertReturnError(ELFHeader.e_ident[EI_DATA] == ELFDATA2LSB, -ENOEXEC);
|
AssertReturnError(ELFHeader.e_ident[EI_DATA] == ELFDATA2LSB, -ENOEXEC);
|
||||||
@ -295,7 +296,7 @@ namespace Driver
|
|||||||
Elf_Phdr phdr{};
|
Elf_Phdr phdr{};
|
||||||
for (Elf_Half i = 0; i < ELFHeader.e_phnum; i++)
|
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 (phdr.p_type == PT_LOAD || phdr.p_type == PT_DYNAMIC)
|
||||||
{
|
{
|
||||||
if (segSize < phdr.p_vaddr + phdr.p_memsz)
|
if (segSize < phdr.p_vaddr + phdr.p_memsz)
|
||||||
@ -306,7 +307,7 @@ namespace Driver
|
|||||||
if (phdr.p_type == PT_INTERP)
|
if (phdr.p_type == PT_INTERP)
|
||||||
{
|
{
|
||||||
char interp[17];
|
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)
|
if (strncmp(interp, "/boot/fennix.elf", sizeof(interp)) != 0)
|
||||||
{
|
{
|
||||||
error("Interpreter is not /boot/fennix.elf");
|
error("Interpreter is not /boot/fennix.elf");
|
||||||
@ -326,13 +327,13 @@ namespace Driver
|
|||||||
Elf_Shdr shstrtab{};
|
Elf_Shdr shstrtab{};
|
||||||
Elf_Shdr shdr{};
|
Elf_Shdr shdr{};
|
||||||
__DriverInfo driverInfo{};
|
__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++)
|
for (Elf_Half i = 0; i < ELFHeader.e_shnum; i++)
|
||||||
{
|
{
|
||||||
if (i == ELFHeader.e_shstrndx)
|
if (i == ELFHeader.e_shstrndx)
|
||||||
continue;
|
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)
|
switch (shdr.sh_type)
|
||||||
{
|
{
|
||||||
@ -350,11 +351,11 @@ namespace Driver
|
|||||||
}
|
}
|
||||||
|
|
||||||
char symName[16];
|
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)
|
if (strcmp(symName, ".driver.info") != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
File->Read(&driverInfo, sizeof(__DriverInfo), shdr.sh_offset);
|
fs->Read(File, &driverInfo, sizeof(__DriverInfo), shdr.sh_offset);
|
||||||
|
|
||||||
/* Perform relocations */
|
/* Perform relocations */
|
||||||
driverInfo.Name = (const char *)(Drv.BaseAddress + (uintptr_t)driverInfo.Name);
|
driverInfo.Name = (const char *)(Drv.BaseAddress + (uintptr_t)driverInfo.Name);
|
||||||
@ -367,13 +368,13 @@ namespace Driver
|
|||||||
{
|
{
|
||||||
Elf_Sym symEntry{};
|
Elf_Sym symEntry{};
|
||||||
uintptr_t symOffset = sht_symtab.sh_offset + (h * sizeof(Elf_Sym));
|
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)
|
if (symEntry.st_name == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
char symName[16];
|
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)
|
switch (symEntry.st_shndx)
|
||||||
{
|
{
|
||||||
@ -405,7 +406,7 @@ namespace Driver
|
|||||||
|
|
||||||
for (Elf_Half i = 0; i < ELFHeader.e_phnum; i++)
|
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)
|
switch (phdr.p_type)
|
||||||
{
|
{
|
||||||
@ -421,7 +422,7 @@ namespace Driver
|
|||||||
phdr.p_filesz, phdr.p_memsz);
|
phdr.p_filesz, phdr.p_memsz);
|
||||||
|
|
||||||
if (phdr.p_filesz > 0)
|
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)
|
if (phdr.p_memsz - phdr.p_filesz > 0)
|
||||||
{
|
{
|
||||||
@ -620,7 +621,8 @@ namespace Driver
|
|||||||
delete Drv.DeviceOperations;
|
delete Drv.DeviceOperations;
|
||||||
|
|
||||||
/* Reload the driver */
|
/* 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)
|
if (!drvNode)
|
||||||
{
|
{
|
||||||
error("Failed to open driver file %s", Drv.Path.c_str());
|
error("Failed to open driver file %s", Drv.Path.c_str());
|
||||||
@ -684,7 +686,7 @@ namespace Driver
|
|||||||
newDrvObj.Initialized = true;
|
newDrvObj.Initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager::Manager() { this->InitializeDaemonFS(); }
|
Manager::Manager() { this->InitializeDeviceDirectory(); }
|
||||||
|
|
||||||
Manager::~Manager()
|
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 <memory.hpp>
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
#include <signal.hpp>
|
#include <signal.hpp>
|
||||||
#include <utsname.h>
|
#include <utsname.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
@ -64,7 +64,7 @@ struct DiagnosticFile
|
|||||||
} Data;
|
} Data;
|
||||||
};
|
};
|
||||||
|
|
||||||
nsa bool WriteDiagDataToNode(FileNode *node)
|
nsa bool WriteDiagDataToNode(Node node)
|
||||||
{
|
{
|
||||||
uintptr_t KStart = (uintptr_t)&_kernel_start;
|
uintptr_t KStart = (uintptr_t)&_kernel_start;
|
||||||
uintptr_t kEnd = (uintptr_t)&_kernel_end;
|
uintptr_t kEnd = (uintptr_t)&_kernel_end;
|
||||||
@ -89,7 +89,7 @@ nsa bool WriteDiagDataToNode(FileNode *node)
|
|||||||
memcpy(file->Data.KernelMemory, (void *)KStart, kSize);
|
memcpy(file->Data.KernelMemory, (void *)KStart, kSize);
|
||||||
|
|
||||||
ExPrint("Writing to %s\n", node->Path.c_str());
|
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)
|
if (w != fileSize)
|
||||||
{
|
{
|
||||||
debug("%d out of %d bytes written", w, fileSize);
|
debug("%d out of %d bytes written", w, fileSize);
|
||||||
@ -115,7 +115,8 @@ nsa void DiagnosticDataCollection()
|
|||||||
S_IROTH |
|
S_IROTH |
|
||||||
S_IFDIR;
|
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)
|
if (!panicDir)
|
||||||
{
|
{
|
||||||
ExPrint("\x1b[0;30;41mFailed to create /sys/log/panic\x1b[0m\n");
|
ExPrint("\x1b[0;30;41mFailed to create /sys/log/panic\x1b[0m\n");
|
||||||
@ -123,14 +124,14 @@ nsa void DiagnosticDataCollection()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileNode *dumpFile;
|
Node dumpFile;
|
||||||
Time::Clock clock = Time::ReadClock();
|
Time::Clock clock = Time::ReadClock();
|
||||||
char filename[64];
|
char filename[64];
|
||||||
for (int i = 0; i < INT32_MAX; i++)
|
for (int i = 0; i < INT32_MAX; i++)
|
||||||
{
|
{
|
||||||
sprintf(filename, "dump-%d-%d-%d-%d.dmp",
|
sprintf(filename, "dump-%d-%d-%d-%d.dmp",
|
||||||
clock.Year, clock.Month, clock.Day, i);
|
clock.Year, clock.Month, clock.Day, i);
|
||||||
if (fs->PathExists(filename, panicDir))
|
if (fs->Lookup(panicDir, filename))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
mode = S_IRWXU |
|
mode = S_IRWXU |
|
||||||
|
@ -408,8 +408,7 @@ nsa __noreturn void HandleBufferOverflow()
|
|||||||
CPU::Stop();
|
CPU::Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
EXTERNC nsa __noreturn void HandleAssertionFailed(const char *File, int Line,
|
EXTERNC nsa __noreturn void HandleAssertionFailed(const char *File, int Line, const char *Expression)
|
||||||
const char *Expression)
|
|
||||||
{
|
{
|
||||||
DisplayAssertionFailed(File, Line, Expression);
|
DisplayAssertionFailed(File, Line, Expression);
|
||||||
CPU::Stop();
|
CPU::Stop();
|
||||||
|
@ -20,9 +20,9 @@
|
|||||||
|
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
|
|
||||||
namespace vfs
|
namespace Driver::ExtendedFilesystem
|
||||||
{
|
{
|
||||||
class EXT2
|
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 <driver.hpp>
|
||||||
|
#include <interface/block.h>
|
||||||
#include <cpu.hpp>
|
#include <cpu.hpp>
|
||||||
#include <pci.hpp>
|
#include <pci.hpp>
|
||||||
|
|
||||||
@ -572,6 +573,9 @@ namespace Driver::AHCI
|
|||||||
HBAPort *HBAPortPtr;
|
HBAPort *HBAPortPtr;
|
||||||
uint8_t *Buffer;
|
uint8_t *Buffer;
|
||||||
uint8_t PortNumber;
|
uint8_t PortNumber;
|
||||||
|
uint32_t BlockSize;
|
||||||
|
uint32_t BlockCount;
|
||||||
|
size_t Size;
|
||||||
ATA_IDENTIFY *IdentifyData;
|
ATA_IDENTIFY *IdentifyData;
|
||||||
|
|
||||||
Port(PortType Type, HBAPort *PortPtr, uint8_t PortNumber)
|
Port(PortType Type, HBAPort *PortPtr, uint8_t PortNumber)
|
||||||
@ -614,6 +618,7 @@ namespace Driver::AHCI
|
|||||||
|
|
||||||
void Configure()
|
void Configure()
|
||||||
{
|
{
|
||||||
|
debug("Configuring port %d", PortNumber);
|
||||||
this->StopCMD();
|
this->StopCMD();
|
||||||
void *CmdBase = v0::AllocateMemory(DriverID, 1);
|
void *CmdBase = v0::AllocateMemory(DriverID, 1);
|
||||||
HBAPortPtr->CommandListBase = (uint32_t)(uint64_t)CmdBase;
|
HBAPortPtr->CommandListBase = (uint32_t)(uint64_t)CmdBase;
|
||||||
@ -639,19 +644,35 @@ namespace Driver::AHCI
|
|||||||
|
|
||||||
Identify();
|
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,
|
trace("Port %d \"%x %x %x %x\" configured", PortNumber,
|
||||||
HBAPortPtr->Vendor[0], HBAPortPtr->Vendor[1],
|
HBAPortPtr->Vendor[0], HBAPortPtr->Vendor[1],
|
||||||
HBAPortPtr->Vendor[2], HBAPortPtr->Vendor[3]);
|
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)
|
if (this->AHCIPortType == PortType::SATAPI && Write == true)
|
||||||
{
|
{
|
||||||
trace("SATAPI port does not support write.");
|
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 SectorL = (uint32_t)Sector;
|
||||||
uint32_t SectorH = (uint32_t)(Sector >> 32);
|
uint32_t SectorH = (uint32_t)(Sector >> 32);
|
||||||
|
|
||||||
@ -706,7 +727,7 @@ namespace Driver::AHCI
|
|||||||
if (spinLock == 1000000)
|
if (spinLock == 1000000)
|
||||||
{
|
{
|
||||||
trace("Port not responding.");
|
trace("Port not responding.");
|
||||||
return false;
|
return ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
HBAPortPtr->CommandIssue = 1;
|
HBAPortPtr->CommandIssue = 1;
|
||||||
@ -723,7 +744,7 @@ namespace Driver::AHCI
|
|||||||
spinLock = 0;
|
spinLock = 0;
|
||||||
retries++;
|
retries++;
|
||||||
if (retries > 10)
|
if (retries > 10)
|
||||||
return false;
|
return ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HBAPortPtr->CommandIssue == 0)
|
if (HBAPortPtr->CommandIssue == 0)
|
||||||
@ -733,11 +754,11 @@ namespace Driver::AHCI
|
|||||||
if (HBAPortPtr->InterruptStatus & HBA_PxIS_TFES)
|
if (HBAPortPtr->InterruptStatus & HBA_PxIS_TFES)
|
||||||
{
|
{
|
||||||
trace("Error reading/writing (%d).", Write);
|
trace("Error reading/writing (%d).", Write);
|
||||||
return false;
|
return EIO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Identify()
|
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)
|
ssize_t Read(struct Inode *Node, void *Buffer, size_t Size, off_t Offset)
|
||||||
{
|
{
|
||||||
uint64_t sector = Offset / 512;
|
Port *port = static_cast<Port *>(Node->PrivateData);
|
||||||
uint32_t sectorCount = uint32_t(Size / 512);
|
if ((Offset % port->BlockSize) != 0 || (Size % port->BlockSize) != 0)
|
||||||
int num = Node->GetMinor();
|
{
|
||||||
bool ok = PortDevices[num]->ReadWrite(sector, sectorCount, Buffer, false);
|
trace("Read offset or size not aligned to block size (BlockSize=%u)", port->BlockSize);
|
||||||
return ok ? Size : 0;
|
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)
|
ssize_t Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
|
||||||
{
|
{
|
||||||
uint64_t sector = Offset / 512;
|
Port *port = static_cast<Port *>(Node->PrivateData);
|
||||||
uint32_t sectorCount = uint32_t(Size / 512);
|
if ((Offset % port->BlockSize) != 0 || (Size % port->BlockSize) != 0)
|
||||||
int num = Node->GetMinor();
|
{
|
||||||
bool ok = PortDevices[num]->ReadWrite(sector, sectorCount, (void *)Buffer, true);
|
trace("Read offset or size not aligned to block size (BlockSize=%u)", port->BlockSize);
|
||||||
return ok ? Size : 0;
|
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 = {
|
const struct InodeOperations ops = {
|
||||||
.Lookup = nullptr,
|
.Lookup = nullptr,
|
||||||
.Create = nullptr,
|
.Create = nullptr,
|
||||||
@ -915,8 +963,18 @@ namespace Driver::AHCI
|
|||||||
{
|
{
|
||||||
KPrint("%s drive found at port %d", PortTypeName[portType], i);
|
KPrint("%s drive found at port %d", PortTypeName[portType], i);
|
||||||
Port *port = new Port(portType, &hba->Ports[i], 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;
|
PortDevices[ret] = port;
|
||||||
|
debug("Port %d \"%s\" registered as %d", i, port->IdentifyData->ModelNumber, ret);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PortType::SEMB:
|
case PortType::SEMB:
|
||||||
@ -942,10 +1000,6 @@ namespace Driver::AHCI
|
|||||||
return -ENODEV;
|
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 */
|
/* We don't use the interrupt handler now... maybe we will in the future */
|
||||||
// RegisterInterruptHandler(iLine(ctx->Device), (void *)OnInterruptReceived);
|
// RegisterInterruptHandler(iLine(ctx->Device), (void *)OnInterruptReceived);
|
||||||
|
|
||||||
@ -957,7 +1011,7 @@ namespace Driver::AHCI
|
|||||||
for (auto &&p : PortDevices)
|
for (auto &&p : PortDevices)
|
||||||
{
|
{
|
||||||
p.second->StopCMD();
|
p.second->StopCMD();
|
||||||
v0::UnregisterDevice(DriverID, p.first);
|
v0::UnregisterBlockDevice(DriverID, p.first);
|
||||||
delete p.second;
|
delete p.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
namespace Execute
|
namespace Execute
|
||||||
{
|
{
|
||||||
BinaryType GetBinaryType(FileNode *Node)
|
BinaryType GetBinaryType(Node &Node)
|
||||||
{
|
{
|
||||||
debug("Checking binary type of %s", Node->Path.c_str());
|
debug("Checking binary type of %s", Node->Path.c_str());
|
||||||
BinaryType type;
|
BinaryType type;
|
||||||
@ -34,13 +34,13 @@ namespace Execute
|
|||||||
ReturnLogError((BinaryType)-ENOENT, "Node is null");
|
ReturnLogError((BinaryType)-ENOENT, "Node is null");
|
||||||
|
|
||||||
Elf_Ehdr ehdr;
|
Elf_Ehdr ehdr;
|
||||||
Node->Read(&ehdr, sizeof(Elf_Ehdr), 0);
|
fs->Read(Node, &ehdr, sizeof(Elf_Ehdr), 0);
|
||||||
|
|
||||||
mach_header mach;
|
mach_header mach;
|
||||||
Node->Read(&mach, sizeof(mach_header), 0);
|
fs->Read(Node, &mach, sizeof(mach_header), 0);
|
||||||
|
|
||||||
IMAGE_DOS_HEADER mz;
|
IMAGE_DOS_HEADER mz;
|
||||||
Node->Read(&mz, sizeof(IMAGE_DOS_HEADER), 0);
|
fs->Read(Node, &mz, sizeof(IMAGE_DOS_HEADER), 0);
|
||||||
|
|
||||||
/* Check ELF header. */
|
/* Check ELF header. */
|
||||||
if (ehdr.e_ident[EI_MAG0] == ELFMAG0 &&
|
if (ehdr.e_ident[EI_MAG0] == ELFMAG0 &&
|
||||||
@ -64,10 +64,10 @@ namespace Execute
|
|||||||
else if (mz.e_magic == IMAGE_DOS_SIGNATURE)
|
else if (mz.e_magic == IMAGE_DOS_SIGNATURE)
|
||||||
{
|
{
|
||||||
IMAGE_NT_HEADERS pe;
|
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;
|
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 */
|
/* TODO: LE, EDOS */
|
||||||
if (pe.Signature == IMAGE_NT_SIGNATURE)
|
if (pe.Signature == IMAGE_NT_SIGNATURE)
|
||||||
@ -99,14 +99,14 @@ namespace Execute
|
|||||||
|
|
||||||
BinaryType GetBinaryType(std::string Path)
|
BinaryType GetBinaryType(std::string Path)
|
||||||
{
|
{
|
||||||
FileNode *node = fs->GetByPath(Path.c_str(), nullptr);
|
Node node = fs->Lookup(thisProcess->Info.RootNode, Path);
|
||||||
if (node->IsSymbolicLink())
|
if (node->IsSymbolicLink())
|
||||||
{
|
{
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
node->ReadLink(buffer, sizeof(buffer));
|
fs->ReadLink(node, buffer, sizeof(buffer));
|
||||||
node = fs->GetByPath(buffer, node->Parent);
|
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);
|
assert(node != nullptr);
|
||||||
return GetBinaryType(node);
|
return GetBinaryType(node);
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ using namespace vfs;
|
|||||||
|
|
||||||
namespace Execute
|
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 */
|
char *aux_platform = (char *)vma->RequestPages(1, true); /* TODO: 4KiB is too much for this */
|
||||||
strcpy(aux_platform, "x86_64");
|
strcpy(aux_platform, "x86_64");
|
||||||
@ -79,7 +79,7 @@ namespace Execute
|
|||||||
#endif
|
#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::Virtual vmm(TargetProcess->PageTable);
|
||||||
Memory::VirtualMemoryArea *vma = TargetProcess->vma;
|
Memory::VirtualMemoryArea *vma = TargetProcess->vma;
|
||||||
@ -91,7 +91,7 @@ namespace Execute
|
|||||||
size_t SegmentsSize = 0;
|
size_t SegmentsSize = 0;
|
||||||
for (Elf_Half i = 0; i < ELFHeader.e_phnum; i++)
|
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)
|
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++)
|
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)
|
switch (ProgramHeader.p_type)
|
||||||
{
|
{
|
||||||
@ -132,7 +132,7 @@ namespace Execute
|
|||||||
|
|
||||||
if (ProgramHeader.p_filesz > 0)
|
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)
|
if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0)
|
||||||
@ -158,7 +158,7 @@ namespace Execute
|
|||||||
|
|
||||||
if (ProgramHeader.p_filesz > 0)
|
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)
|
if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0)
|
||||||
@ -212,7 +212,7 @@ namespace Execute
|
|||||||
{
|
{
|
||||||
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
|
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)
|
switch (ProgramHeader.p_type)
|
||||||
{
|
{
|
||||||
case PT_LOAD:
|
case PT_LOAD:
|
||||||
@ -245,7 +245,7 @@ namespace Execute
|
|||||||
if (ProgramHeader.p_filesz > 0)
|
if (ProgramHeader.p_filesz > 0)
|
||||||
{
|
{
|
||||||
debug("%d %#lx %d", ProgramHeader.p_offset, (uint8_t *)pAddr + destOffset, ProgramHeader.p_filesz);
|
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)
|
if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0)
|
||||||
@ -265,35 +265,35 @@ namespace Execute
|
|||||||
case PT_NOTE:
|
case PT_NOTE:
|
||||||
{
|
{
|
||||||
Elf_Nhdr NoteHeader;
|
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)
|
switch (NoteHeader.n_type)
|
||||||
{
|
{
|
||||||
case NT_PRSTATUS:
|
case NT_PRSTATUS:
|
||||||
{
|
{
|
||||||
Elf_Prstatus 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]);
|
debug("PRSTATUS: %#lx", prstatus.pr_reg[0]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NT_PRPSINFO:
|
case NT_PRPSINFO:
|
||||||
{
|
{
|
||||||
Elf_Prpsinfo 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);
|
debug("PRPSINFO: %s", prpsinfo.pr_fname);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NT_PLATFORM:
|
case NT_PLATFORM:
|
||||||
{
|
{
|
||||||
char platform[256];
|
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);
|
debug("PLATFORM: %s", platform);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NT_AUXV:
|
case NT_AUXV:
|
||||||
{
|
{
|
||||||
Elf_auxv_t 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);
|
debug("AUXV: %#lx", auxv.a_un.a_val);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -311,7 +311,7 @@ namespace Execute
|
|||||||
debug("TLS Size: %ld (%ld pages)",
|
debug("TLS Size: %ld (%ld pages)",
|
||||||
tlsSize, TO_PAGES(tlsSize));
|
tlsSize, TO_PAGES(tlsSize));
|
||||||
void *tlsMemory = vma->RequestPages(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 = {
|
TargetProcess->TLS = {
|
||||||
.pBase = uintptr_t(tlsMemory),
|
.pBase = uintptr_t(tlsMemory),
|
||||||
.vBase = ProgramHeader.p_vaddr,
|
.vBase = ProgramHeader.p_vaddr,
|
||||||
@ -346,12 +346,12 @@ namespace Execute
|
|||||||
case PT_GNU_PROPERTY:
|
case PT_GNU_PROPERTY:
|
||||||
{
|
{
|
||||||
Elf_Nhdr NoteHeader;
|
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)
|
if (NoteHeader.n_type == NT_GNU_PROPERTY_TYPE_0)
|
||||||
{
|
{
|
||||||
char noteName[0x400];
|
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';
|
noteName[NoteHeader.n_namesz - 1] = '\0';
|
||||||
|
|
||||||
if (strcmp(noteName, "GNU") == 0)
|
if (strcmp(noteName, "GNU") == 0)
|
||||||
@ -394,10 +394,10 @@ namespace Execute
|
|||||||
TargetProcess->ProgramBreak->InitBrk(ProgramBreak);
|
TargetProcess->ProgramBreak->InitBrk(ProgramBreak);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ELFObject::LoadExec(FileNode *fd, PCB *TargetProcess)
|
void ELFObject::LoadExec(Node &fd, PCB *TargetProcess)
|
||||||
{
|
{
|
||||||
Elf_Ehdr ehdr{};
|
Elf_Ehdr ehdr{};
|
||||||
fd->Read(&ehdr, sizeof(Elf_Ehdr), 0);
|
fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0);
|
||||||
uintptr_t entry = ehdr.e_entry;
|
uintptr_t entry = ehdr.e_entry;
|
||||||
debug("Entry point is %#lx", entry);
|
debug("Entry point is %#lx", entry);
|
||||||
|
|
||||||
@ -424,10 +424,10 @@ namespace Execute
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ELFObject::LoadDyn(FileNode *fd, PCB *TargetProcess)
|
void ELFObject::LoadDyn(Node &fd, PCB *TargetProcess)
|
||||||
{
|
{
|
||||||
Elf_Ehdr ehdr{};
|
Elf_Ehdr ehdr{};
|
||||||
fd->Read(&ehdr, sizeof(Elf_Ehdr), 0);
|
fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0);
|
||||||
uintptr_t entry = ehdr.e_entry;
|
uintptr_t entry = ehdr.e_entry;
|
||||||
debug("Entry point is %#lx", entry);
|
debug("Entry point is %#lx", entry);
|
||||||
|
|
||||||
@ -465,24 +465,25 @@ namespace Execute
|
|||||||
Elf_Phdr interp = interpVec.front();
|
Elf_Phdr interp = interpVec.front();
|
||||||
std::string interpreterPath;
|
std::string interpreterPath;
|
||||||
interpreterPath.resize(256);
|
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());
|
debug("Interpreter: %s", interpreterPath.c_str());
|
||||||
|
|
||||||
FileNode *ifd = fs->GetByPath(interpreterPath.c_str(), TargetProcess->Info.RootNode);
|
eNode ret = fs->Lookup(TargetProcess->Info.RootNode, interpreterPath);
|
||||||
if (ifd == nullptr)
|
if (ret == false)
|
||||||
{
|
{
|
||||||
warn("Failed to open interpreter file: %s", interpreterPath.c_str());
|
warn("Failed to open interpreter file: %s", ret.what());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Node ifd = ret;
|
||||||
|
|
||||||
if (ifd->IsSymbolicLink())
|
if (ifd->IsSymbolicLink())
|
||||||
{
|
{
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
ifd->ReadLink(buffer, sizeof(buffer));
|
fs->ReadLink(ifd, buffer, sizeof(buffer));
|
||||||
ifd = fs->GetByPath(buffer, ifd->Parent);
|
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)
|
if (GetBinaryType(interpreterPath) != BinTypeELF)
|
||||||
{
|
{
|
||||||
warn("Interpreter %s is not an ELF file", interpreterPath.c_str());
|
warn("Interpreter %s is not an ELF file", interpreterPath.c_str());
|
||||||
@ -492,10 +493,10 @@ namespace Execute
|
|||||||
LoadInterpreter(ifd, TargetProcess);
|
LoadInterpreter(ifd, TargetProcess);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ELFObject::LoadInterpreter(FileNode *fd, PCB *TargetProcess)
|
bool ELFObject::LoadInterpreter(Node &fd, PCB *TargetProcess)
|
||||||
{
|
{
|
||||||
Elf_Ehdr ehdr;
|
Elf_Ehdr ehdr;
|
||||||
fd->Read(&ehdr, sizeof(Elf_Ehdr), 0);
|
fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0);
|
||||||
|
|
||||||
switch (ehdr.e_type)
|
switch (ehdr.e_type)
|
||||||
{
|
{
|
||||||
@ -550,18 +551,19 @@ namespace Execute
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileNode *fd = fs->GetByPath(AbsolutePath.c_str(), TargetProcess->Info.RootNode);
|
eNode ret = fs->Lookup(TargetProcess->Info.RootNode, AbsolutePath);
|
||||||
if (fd == nullptr)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
Node fd = ret;
|
||||||
|
|
||||||
if (fd->IsSymbolicLink())
|
if (fd->IsSymbolicLink())
|
||||||
{
|
{
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
fd->ReadLink(buffer, sizeof(buffer));
|
fs->ReadLink(fd, buffer, sizeof(buffer));
|
||||||
fd = fs->GetByPath(buffer, fd->Parent);
|
fd = fs->Lookup(fd->Parent, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug("Opened %s", AbsolutePath.c_str());
|
debug("Opened %s", AbsolutePath.c_str());
|
||||||
@ -575,7 +577,7 @@ namespace Execute
|
|||||||
envc++;
|
envc++;
|
||||||
|
|
||||||
Elf_Ehdr ehdr{};
|
Elf_Ehdr ehdr{};
|
||||||
fd->Read(&ehdr, sizeof(Elf_Ehdr), 0);
|
fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0);
|
||||||
|
|
||||||
// ELFargv = new const char *[argc + 2];
|
// ELFargv = new const char *[argc + 2];
|
||||||
size_t argv_size = argc + 2 * sizeof(char *);
|
size_t argv_size = argc + 2 * sizeof(char *);
|
||||||
|
@ -92,10 +92,10 @@ namespace Execute
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Elf_Sym ELFLookupSymbol(FileNode *fd, std::string Name)
|
Elf_Sym ELFLookupSymbol(Node fd, std::string Name)
|
||||||
{
|
{
|
||||||
Elf_Ehdr ehdr{};
|
Elf_Ehdr ehdr{};
|
||||||
fd->Read(&ehdr, sizeof(Elf_Ehdr), 0);
|
fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0);
|
||||||
|
|
||||||
Elf_Shdr symTable{};
|
Elf_Shdr symTable{};
|
||||||
Elf_Shdr stringTable{};
|
Elf_Shdr stringTable{};
|
||||||
@ -103,13 +103,13 @@ namespace Execute
|
|||||||
for (Elf64_Half i = 0; i < ehdr.e_shnum; i++)
|
for (Elf64_Half i = 0; i < ehdr.e_shnum; i++)
|
||||||
{
|
{
|
||||||
Elf_Shdr shdr;
|
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)
|
switch (shdr.sh_type)
|
||||||
{
|
{
|
||||||
case SHT_SYMTAB:
|
case SHT_SYMTAB:
|
||||||
symTable = shdr;
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
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 = (Elf_Sym *)((uintptr_t)Header + symTable->sh_offset + (i * sizeof(Elf_Sym)));
|
||||||
Elf_Sym 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 = (char *)((uintptr_t)Header + stringTable->sh_offset + sym->st_name);
|
||||||
char str[256];
|
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)
|
if (strcmp(str, Name.c_str()) == 0)
|
||||||
return sym;
|
return sym;
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
namespace Execute
|
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_Dyn> ret;
|
||||||
std::vector<Elf_Phdr> phdrs = ELFGetSymbolType(fd, PT_DYNAMIC);
|
std::vector<Elf_Phdr> phdrs = ELFGetSymbolType(fd, PT_DYNAMIC);
|
||||||
@ -37,7 +37,7 @@ namespace Execute
|
|||||||
Elf_Dyn dyn;
|
Elf_Dyn dyn;
|
||||||
for (size_t i = 0; i < phdr.p_filesz / sizeof(Elf_Dyn); i++)
|
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)
|
if (dyn.d_tag != Tag)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -21,18 +21,18 @@
|
|||||||
|
|
||||||
namespace Execute
|
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;
|
std::vector<Elf_Shdr> ret;
|
||||||
|
|
||||||
Elf_Ehdr ehdr;
|
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]);
|
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');
|
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)
|
for (Elf_Half i = 0; i < ehdr.e_shnum; ++i)
|
||||||
{
|
{
|
||||||
|
@ -21,15 +21,15 @@
|
|||||||
|
|
||||||
namespace Execute
|
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;
|
std::vector<Elf_Phdr> ret;
|
||||||
|
|
||||||
Elf_Ehdr ehdr;
|
Elf_Ehdr ehdr;
|
||||||
fd->Read(&ehdr, sizeof(Elf_Ehdr), 0);
|
fs->Read(fd, &ehdr, sizeof(Elf_Ehdr), 0);
|
||||||
|
|
||||||
Elf_Phdr phdr;
|
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;
|
off_t off = ehdr.e_phoff;
|
||||||
for (Elf_Half i = 0; i < ehdr.e_phnum; i++)
|
for (Elf_Half i = 0; i < ehdr.e_phnum; i++)
|
||||||
@ -38,7 +38,7 @@ namespace Execute
|
|||||||
ret.push_back(phdr);
|
ret.push_back(phdr);
|
||||||
|
|
||||||
off += sizeof(Elf_Phdr);
|
off += sizeof(Elf_Phdr);
|
||||||
fd->Read(&phdr, sizeof(Elf_Phdr), off);
|
fs->Read(fd, &phdr, sizeof(Elf_Phdr), off);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -35,7 +35,13 @@ namespace Execute
|
|||||||
Tasking::TaskCompatibility Compatibility,
|
Tasking::TaskCompatibility Compatibility,
|
||||||
bool Critical)
|
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)
|
if (fd == nullptr)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
@ -44,8 +50,8 @@ namespace Execute
|
|||||||
if (fd->IsSymbolicLink())
|
if (fd->IsSymbolicLink())
|
||||||
{
|
{
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
fd->ReadLink(buffer, sizeof(buffer));
|
fs->ReadLink(fd, buffer, sizeof(buffer));
|
||||||
fd = fs->GetByPath(buffer, fd->Parent);
|
fd = fs->Lookup(fd->Parent, buffer);
|
||||||
if (fd == nullptr)
|
if (fd == nullptr)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
@ -61,7 +67,7 @@ namespace Execute
|
|||||||
const char *BaseName;
|
const char *BaseName;
|
||||||
cwk_path_get_basename(Path, &BaseName, nullptr);
|
cwk_path_get_basename(Path, &BaseName, nullptr);
|
||||||
Elf32_Ehdr ELFHeader;
|
Elf32_Ehdr ELFHeader;
|
||||||
fd->Read(&ELFHeader, sizeof(Elf32_Ehdr), 0);
|
fs->Read(fd, &ELFHeader, sizeof(Elf32_Ehdr), 0);
|
||||||
|
|
||||||
switch (ELFHeader.e_machine)
|
switch (ELFHeader.e_machine)
|
||||||
{
|
{
|
||||||
@ -108,7 +114,6 @@ namespace Execute
|
|||||||
PCB *Process;
|
PCB *Process;
|
||||||
if (Fork)
|
if (Fork)
|
||||||
{
|
{
|
||||||
assert(Parent != nullptr);
|
|
||||||
CriticalSection cs;
|
CriticalSection cs;
|
||||||
|
|
||||||
Process = Parent;
|
Process = Parent;
|
||||||
@ -124,17 +129,13 @@ namespace Execute
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Parent == nullptr)
|
Process = TaskManager->CreateProcess(Parent, BaseName, User, false, 0, 0);
|
||||||
Parent = thisProcess;
|
|
||||||
|
|
||||||
Process = TaskManager->CreateProcess(Parent, BaseName,
|
|
||||||
TaskExecutionMode::User,
|
|
||||||
false, 0, 0);
|
|
||||||
Process->Info.Compatibility = Compatibility;
|
Process->Info.Compatibility = Compatibility;
|
||||||
Process->Info.Architecture = Arch;
|
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);
|
Process->SetExe(Path);
|
||||||
|
|
||||||
ELFObject *obj = new ELFObject(Path, Process, argv, envp);
|
ELFObject *obj = new ELFObject(Path, Process, argv, envp);
|
||||||
@ -148,9 +149,9 @@ namespace Execute
|
|||||||
vfs::FileDescriptorTable *pfdt = Parent->FileDescriptors;
|
vfs::FileDescriptorTable *pfdt = Parent->FileDescriptors;
|
||||||
vfs::FileDescriptorTable *fdt = Process->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;
|
return false;
|
||||||
|
|
||||||
for (const auto &ffd : pfdt->FileMap)
|
for (const auto &ffd : pfdt->FileMap)
|
||||||
@ -158,12 +159,11 @@ namespace Execute
|
|||||||
if (ffd.second.Flags & O_CLOEXEC)
|
if (ffd.second.Flags & O_CLOEXEC)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (ffd.second.Node == SearchNode)
|
if (ffd.second.node.get() != SearchNode.get())
|
||||||
{
|
continue;
|
||||||
fdt->usr_open(ffd.second.Node->Path.c_str(),
|
|
||||||
ffd.second.Flags, ffd.second.Mode);
|
fdt->usr_open(ffd.second.node->Path.c_str(), ffd.second.Flags, ffd.second.Mode);
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
|
|
||||||
#include <convert.h>
|
#include <convert.h>
|
||||||
#include <stropts.h>
|
#include <stropts.h>
|
||||||
@ -47,8 +47,7 @@ namespace vfs
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FileDescriptorTable::AddFileDescriptor(const char *AbsolutePath,
|
int FileDescriptorTable::AddFileDescriptor(const char *AbsolutePath, mode_t Mode, int Flags)
|
||||||
mode_t Mode, int Flags)
|
|
||||||
{
|
{
|
||||||
Tasking::PCB *pcb = thisProcess;
|
Tasking::PCB *pcb = thisProcess;
|
||||||
|
|
||||||
@ -77,8 +76,7 @@ namespace vfs
|
|||||||
|
|
||||||
if (Flags & O_RDWR)
|
if (Flags & O_RDWR)
|
||||||
{
|
{
|
||||||
if (!(Mode & S_IRUSR) ||
|
if (!(Mode & S_IRUSR) || !(Mode & S_IWUSR))
|
||||||
!(Mode & S_IWUSR))
|
|
||||||
{
|
{
|
||||||
debug("No read/write permission (%d)", Mode);
|
debug("No read/write permission (%d)", Mode);
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
@ -95,12 +93,11 @@ namespace vfs
|
|||||||
|
|
||||||
if (Flags & O_CREAT)
|
if (Flags & O_CREAT)
|
||||||
{
|
{
|
||||||
FileNode *ret = fs->Create(pcb->CWD, AbsolutePath, Mode);
|
eNode ret = fs->Create(pcb->CWD, AbsolutePath, Mode);
|
||||||
if (Flags & O_EXCL && ret == nullptr)
|
if (Flags & O_EXCL && ret == false)
|
||||||
{
|
{
|
||||||
debug("%s: File already exists?, returning EEXIST",
|
debug("%s: File already exists?, returning %s", AbsolutePath, ret.what());
|
||||||
AbsolutePath);
|
return -ret.Error;
|
||||||
return -EEXIST;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,18 +106,18 @@ namespace vfs
|
|||||||
fixme("O_CLOEXEC");
|
fixme("O_CLOEXEC");
|
||||||
}
|
}
|
||||||
|
|
||||||
FileNode *File = fs->GetByPath(AbsolutePath, pcb->CWD);
|
eNode ret = fs->Lookup(pcb->CWD, AbsolutePath);
|
||||||
|
if (ret == false)
|
||||||
if (!File)
|
|
||||||
{
|
{
|
||||||
error("Failed to open file %s", AbsolutePath);
|
error("Failed to open file %s, %s", AbsolutePath, ret.what());
|
||||||
return -ENOENT;
|
return -ret.Error;
|
||||||
}
|
}
|
||||||
|
Node node = ret;
|
||||||
|
|
||||||
if (Flags & O_TRUNC)
|
if (Flags & O_TRUNC)
|
||||||
{
|
{
|
||||||
debug("Truncating file %s", AbsolutePath);
|
debug("Truncating file %s", AbsolutePath);
|
||||||
File->Truncate(0);
|
fs->Truncate(node, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Fildes fd{};
|
Fildes fd{};
|
||||||
@ -129,13 +126,13 @@ namespace vfs
|
|||||||
{
|
{
|
||||||
debug("Appending to file %s", AbsolutePath);
|
debug("Appending to file %s", AbsolutePath);
|
||||||
struct kstat stat;
|
struct kstat stat;
|
||||||
File->Stat(&stat);
|
fs->Stat(node, &stat);
|
||||||
fd.Offset = File->Seek(stat.Size);
|
fd.Offset = fs->Seek(node, stat.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
fd.Mode = Mode;
|
fd.Mode = Mode;
|
||||||
fd.Flags = Flags;
|
fd.Flags = Flags;
|
||||||
fd.Node = File;
|
fd.node = node;
|
||||||
|
|
||||||
int fdn = this->GetFreeFileDescriptor();
|
int fdn = this->GetFreeFileDescriptor();
|
||||||
if (fdn < 0)
|
if (fdn < 0)
|
||||||
@ -145,9 +142,8 @@ namespace vfs
|
|||||||
|
|
||||||
char linkName[64];
|
char linkName[64];
|
||||||
snprintf(linkName, 64, "%d", fdn);
|
snprintf(linkName, 64, "%d", fdn);
|
||||||
assert(fs->CreateLink(linkName, this->fdDir, AbsolutePath) != nullptr);
|
assert(fs->CreateLink(this->fdDir, linkName, AbsolutePath) == true);
|
||||||
|
fs->Open(node, Flags, Mode);
|
||||||
File->Open(Flags, Mode);
|
|
||||||
return fdn;
|
return fdn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +153,7 @@ namespace vfs
|
|||||||
if (it == this->FileMap.end())
|
if (it == this->FileMap.end())
|
||||||
ReturnLogError(-EBADF, "Invalid fd %d", FileDescriptor);
|
ReturnLogError(-EBADF, "Invalid fd %d", FileDescriptor);
|
||||||
|
|
||||||
fs->Remove(it->second.Node);
|
fs->Remove(it->second.node);
|
||||||
this->FileMap.erase(it);
|
this->FileMap.erase(it);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -209,7 +205,7 @@ namespace vfs
|
|||||||
if (it == this->FileMap.end())
|
if (it == this->FileMap.end())
|
||||||
ReturnLogError(-EBADF, "Invalid fd %d", fd);
|
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)
|
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())
|
if (it == this->FileMap.end())
|
||||||
ReturnLogError(-EBADF, "Invalid fd %d", fd);
|
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)
|
ssize_t FileDescriptorTable::usr_write(int fd, const void *buf, size_t count)
|
||||||
@ -227,7 +223,7 @@ namespace vfs
|
|||||||
if (it == this->FileMap.end())
|
if (it == this->FileMap.end())
|
||||||
ReturnLogError(-EBADF, "Invalid fd %d", fd);
|
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)
|
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())
|
if (it == this->FileMap.end())
|
||||||
ReturnLogError(-EBADF, "Invalid fd %d", fd);
|
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)
|
int FileDescriptorTable::usr_close(int fd)
|
||||||
@ -260,21 +256,19 @@ namespace vfs
|
|||||||
{
|
{
|
||||||
case SEEK_SET:
|
case SEEK_SET:
|
||||||
{
|
{
|
||||||
newOffset = it->second.Node->Seek(offset);
|
newOffset = fs->Seek(it->second.node, offset);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SEEK_CUR:
|
case SEEK_CUR:
|
||||||
{
|
{
|
||||||
newOffset = it->second.Node->Seek(newOffset + offset);
|
newOffset = fs->Seek(it->second.node, newOffset + offset);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SEEK_END:
|
case SEEK_END:
|
||||||
{
|
{
|
||||||
struct kstat stat
|
struct kstat stat{};
|
||||||
{
|
fs->Stat(it->second.node, &stat);
|
||||||
};
|
newOffset = fs->Seek(it->second.node, stat.Size + offset);
|
||||||
it->second.Node->Stat(&stat);
|
|
||||||
newOffset = it->second.Node->Seek(stat.Size + offset);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -284,48 +278,48 @@ namespace vfs
|
|||||||
return newOffset;
|
return newOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FileDescriptorTable::usr_stat(const char *pathname,
|
int FileDescriptorTable::usr_stat(const char *pathname, kstat *statbuf)
|
||||||
struct kstat *statbuf)
|
|
||||||
{
|
{
|
||||||
FileNode *node = fs->GetByPath(pathname, nullptr);
|
Node root = thisProcess->Info.RootNode;
|
||||||
if (node == nullptr)
|
eNode ret = fs->Lookup(root, pathname);
|
||||||
ReturnLogError(-ENOENT, "Failed to find %s", pathname);
|
if (ret == false)
|
||||||
|
ReturnLogError(-ret.Error, "Error on %s, %s", pathname, ret.what());
|
||||||
|
Node node = ret;
|
||||||
|
|
||||||
if (node->IsSymbolicLink())
|
if (node->IsSymbolicLink())
|
||||||
{
|
{
|
||||||
std::unique_ptr<char[]> buffer(new char[1024]);
|
std::unique_ptr<char[]> buffer(new char[1024]);
|
||||||
ssize_t ret = node->ReadLink(buffer.get(), 1024);
|
ssize_t len = fs->ReadLink(node, buffer.get(), 1024);
|
||||||
if (ret < 0)
|
if (len < 0)
|
||||||
return ret;
|
return len;
|
||||||
|
|
||||||
FileNode *target = fs->GetByPath(buffer.get(), nullptr);
|
ret = fs->Lookup(root, buffer.get());
|
||||||
if (target == nullptr)
|
if (ret == false)
|
||||||
return -ENOENT;
|
return -ret.Error;
|
||||||
|
return fs->Stat(ret.Value, statbuf);
|
||||||
return target->Stat(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);
|
auto it = this->FileMap.find(fd);
|
||||||
if (it == this->FileMap.end())
|
if (it == this->FileMap.end())
|
||||||
ReturnLogError(-EBADF, "Invalid fd %d", fd);
|
ReturnLogError(-EBADF, "Invalid fd %d", fd);
|
||||||
|
|
||||||
vfs::FileDescriptorTable::Fildes &fildes = it->second;
|
vfs::FileDescriptorTable::Fildes &fildes = it->second;
|
||||||
|
return fs->Stat(fildes.node, statbuf);
|
||||||
return fildes.Node->Stat(statbuf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int FileDescriptorTable::usr_lstat(const char *pathname,
|
int FileDescriptorTable::usr_lstat(const char *pathname, kstat *statbuf)
|
||||||
struct kstat *statbuf)
|
|
||||||
{
|
{
|
||||||
FileNode *node = fs->GetByPath(pathname, nullptr);
|
Node root = thisProcess->Info.RootNode;
|
||||||
if (node == nullptr)
|
eNode ret = fs->Lookup(root, pathname);
|
||||||
ReturnLogError(-ENOENT, "Failed to find %s", pathname);
|
if (ret == false)
|
||||||
return node->Stat(statbuf);
|
ReturnLogError(-ret.Error, "Error on %s, %s", pathname, ret.what());
|
||||||
|
|
||||||
|
return fs->Stat(ret.Value, statbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
int FileDescriptorTable::usr_dup(int oldfd)
|
int FileDescriptorTable::usr_dup(int oldfd)
|
||||||
@ -339,7 +333,7 @@ namespace vfs
|
|||||||
return -EMFILE;
|
return -EMFILE;
|
||||||
|
|
||||||
Fildes new_dfd{};
|
Fildes new_dfd{};
|
||||||
new_dfd.Node = it->second.Node;
|
new_dfd.node = it->second.node;
|
||||||
new_dfd.Mode = it->second.Mode;
|
new_dfd.Mode = it->second.Mode;
|
||||||
|
|
||||||
this->FileMap.insert({newfd, new_dfd});
|
this->FileMap.insert({newfd, new_dfd});
|
||||||
@ -364,7 +358,7 @@ namespace vfs
|
|||||||
this->usr_close(newfd);
|
this->usr_close(newfd);
|
||||||
|
|
||||||
Fildes new_dfd{};
|
Fildes new_dfd{};
|
||||||
new_dfd.Node = it->second.Node;
|
new_dfd.node = it->second.node;
|
||||||
new_dfd.Mode = it->second.Mode;
|
new_dfd.Mode = it->second.Mode;
|
||||||
|
|
||||||
this->FileMap.insert({newfd, new_dfd});
|
this->FileMap.insert({newfd, new_dfd});
|
||||||
@ -378,7 +372,7 @@ namespace vfs
|
|||||||
if (it == this->FileMap.end())
|
if (it == this->FileMap.end())
|
||||||
ReturnLogError(-EBADF, "Invalid fd %d", fd);
|
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)
|
FileDescriptorTable::FileDescriptorTable(void *_Owner)
|
||||||
@ -386,11 +380,12 @@ namespace vfs
|
|||||||
{
|
{
|
||||||
debug("+ %#lx", this);
|
debug("+ %#lx", this);
|
||||||
|
|
||||||
mode_t Mode = S_IXOTH | S_IROTH |
|
/* d r-x r-x r-x */
|
||||||
S_IXGRP | S_IRGRP |
|
mode_t Mode = S_IROTH | S_IXOTH |
|
||||||
S_IXUSR | S_IRUSR |
|
S_IRGRP | S_IXGRP |
|
||||||
|
S_IRUSR | S_IXUSR |
|
||||||
S_IFDIR;
|
S_IFDIR;
|
||||||
|
Tasking::PCB *pcb = (Tasking::PCB *)_Owner;
|
||||||
this->fdDir = fs->Create(((Tasking::PCB *)_Owner)->ProcDirectory, "fd", Mode);
|
this->fdDir = fs->Create(pcb->ProcDirectory, "fd", Mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -15,12 +15,12 @@
|
|||||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <filesystem/ramfs.hpp>
|
#include <fs/ramfs.hpp>
|
||||||
#include <memory.hpp>
|
#include <memory.hpp>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../kernel.h"
|
||||||
|
|
||||||
namespace vfs
|
namespace vfs
|
||||||
{
|
{
|
||||||
@ -81,7 +81,6 @@ namespace vfs
|
|||||||
inode.Index = NextInode;
|
inode.Index = NextInode;
|
||||||
inode.Offset = 0;
|
inode.Offset = 0;
|
||||||
inode.PrivateData = this;
|
inode.PrivateData = this;
|
||||||
inode.Flags = I_FLAG_CACHE_KEEP;
|
|
||||||
|
|
||||||
const char *basename;
|
const char *basename;
|
||||||
size_t length;
|
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);
|
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);
|
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);
|
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);
|
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);
|
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);
|
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);
|
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);
|
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;
|
vfs::RAMFS::RAMFSInode *inode = (vfs::RAMFS::RAMFSInode *)Node;
|
||||||
delete inode;
|
delete inode;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
O2 int __ramfs_Destroy(FileSystemInfo *fsi)
|
int __ramfs_Destroy(FileSystemInfo *fsi)
|
||||||
{
|
{
|
||||||
assert(fsi->PrivateData);
|
assert(fsi->PrivateData);
|
||||||
delete (vfs::RAMFS *)fsi->PrivateData;
|
delete (vfs::RAMFS *)fsi->PrivateData;
|
||||||
@ -384,16 +383,13 @@ O2 int __ramfs_Destroy(FileSystemInfo *fsi)
|
|||||||
return 0;
|
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;
|
vfs::RAMFS *ramfs = new vfs::RAMFS;
|
||||||
ramfs->DeviceID = fs->EarlyReserveDevice();
|
|
||||||
ramfs->RootName.assign(Name);
|
ramfs->RootName.assign(Name);
|
||||||
|
|
||||||
FileSystemInfo *fsi = new FileSystemInfo;
|
FileSystemInfo *fsi = new FileSystemInfo;
|
||||||
fsi->Name = "ramfs";
|
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.DeleteInode = __ramfs_DestroyInode;
|
||||||
fsi->SuperOps.Destroy = __ramfs_Destroy;
|
fsi->SuperOps.Destroy = __ramfs_Destroy;
|
||||||
fsi->Ops.Lookup = __ramfs_Lookup;
|
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.ReadLink = __ramfs_ReadLink;
|
||||||
fsi->Ops.Stat = __ramfs_Stat;
|
fsi->Ops.Stat = __ramfs_Stat;
|
||||||
fsi->PrivateData = ramfs;
|
fsi->PrivateData = ramfs;
|
||||||
|
ramfs->DeviceID = fs->RegisterFileSystem(fsi);
|
||||||
|
|
||||||
Inode *root = nullptr;
|
Inode *root = nullptr;
|
||||||
ramfs->Create(nullptr, Name, S_IFDIR | 0755, &root);
|
ramfs->Create(nullptr, Name, S_IFDIR | 0755, &root);
|
||||||
|
|
||||||
fs->LateRegisterFileSystem(ramfs->DeviceID, fsi, root);
|
fs->Mount(Parent, root, Name, fsi);
|
||||||
fs->AddRootAt(root, Index);
|
fs->AddRoot(Index, fs->Convert(root));
|
||||||
|
|
||||||
fs->Mount(Parent, root, Name);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
@ -15,12 +15,12 @@
|
|||||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <filesystem/ustar.hpp>
|
#include <fs/ustar.hpp>
|
||||||
#include <memory.hpp>
|
#include <memory.hpp>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../kernel.h"
|
||||||
|
|
||||||
#define TMAGIC "ustar"
|
#define TMAGIC "ustar"
|
||||||
#define TMAGLEN 6
|
#define TMAGLEN 6
|
||||||
@ -32,7 +32,7 @@ namespace vfs
|
|||||||
int USTAR::Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result)
|
int USTAR::Lookup(struct Inode *_Parent, const char *Name, struct Inode **Result)
|
||||||
{
|
{
|
||||||
auto Parent = (USTARInode *)_Parent;
|
auto Parent = (USTARInode *)_Parent;
|
||||||
|
debug("looking up for %s", Name);
|
||||||
const char *basename;
|
const char *basename;
|
||||||
size_t length;
|
size_t length;
|
||||||
cwk_path_get_basename(Name, &basename, &length);
|
cwk_path_get_basename(Name, &basename, &length);
|
||||||
@ -91,7 +91,6 @@ namespace vfs
|
|||||||
inode.Index = NextInode;
|
inode.Index = NextInode;
|
||||||
inode.Offset = 0;
|
inode.Offset = 0;
|
||||||
inode.PrivateData = this;
|
inode.PrivateData = this;
|
||||||
inode.Flags = I_FLAG_CACHE_KEEP;
|
|
||||||
|
|
||||||
const char *basename;
|
const char *basename;
|
||||||
size_t length;
|
size_t length;
|
||||||
@ -217,6 +216,7 @@ namespace vfs
|
|||||||
{
|
{
|
||||||
/* FIXME: FIX ALIGNMENT FOR DIRENT! */
|
/* FIXME: FIX ALIGNMENT FOR DIRENT! */
|
||||||
auto Node = (USTARInode *)_Node;
|
auto Node = (USTARInode *)_Node;
|
||||||
|
debug("reading directory %s", Node->Path.c_str());
|
||||||
|
|
||||||
off_t realOffset = Offset;
|
off_t realOffset = Offset;
|
||||||
|
|
||||||
@ -237,6 +237,7 @@ namespace vfs
|
|||||||
ent->d_type = DT_DIR;
|
ent->d_type = DT_DIR;
|
||||||
strcpy(ent->d_name, ".");
|
strcpy(ent->d_name, ".");
|
||||||
totalSize += reclen;
|
totalSize += reclen;
|
||||||
|
debug(".");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Offset <= 1)
|
if (Offset <= 1)
|
||||||
@ -263,6 +264,7 @@ namespace vfs
|
|||||||
ent->d_type = DT_DIR;
|
ent->d_type = DT_DIR;
|
||||||
strcpy(ent->d_name, "..");
|
strcpy(ent->d_name, "..");
|
||||||
totalSize += reclen;
|
totalSize += reclen;
|
||||||
|
debug("..");
|
||||||
}
|
}
|
||||||
|
|
||||||
// off_t entriesSkipped = 0;
|
// off_t entriesSkipped = 0;
|
||||||
@ -309,10 +311,13 @@ namespace vfs
|
|||||||
if (var->Deleted)
|
if (var->Deleted)
|
||||||
continue;
|
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;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
ent = (struct kdirent *)((uintptr_t)Buffer + totalSize);
|
||||||
ent->d_ino = var->Node.Index;
|
ent->d_ino = var->Node.Index;
|
||||||
@ -349,7 +354,7 @@ namespace vfs
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
strncpy(ent->d_name, var->Name.c_str(), strlen(var->Name.c_str()));
|
strncpy(ent->d_name, var->Name.c_str(), strlen(var->Name.c_str()));
|
||||||
|
debug("%s", var->Name.c_str());
|
||||||
totalSize += reclen;
|
totalSize += reclen;
|
||||||
entries++;
|
entries++;
|
||||||
}
|
}
|
||||||
@ -601,7 +606,6 @@ namespace vfs
|
|||||||
uNode.RawDevice = 0;
|
uNode.RawDevice = 0;
|
||||||
uNode.Index = NextInode;
|
uNode.Index = NextInode;
|
||||||
SetMode(uNode, header);
|
SetMode(uNode, header);
|
||||||
uNode.Flags = I_FLAG_CACHE_KEEP;
|
|
||||||
uNode.Offset = 0;
|
uNode.Offset = 0;
|
||||||
uNode.PrivateData = this;
|
uNode.PrivateData = this;
|
||||||
|
|
||||||
@ -847,17 +851,8 @@ bool TestAndInitializeUSTAR(uintptr_t Address, size_t Size, size_t Index)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ustar->DeviceID = fs->EarlyReserveDevice();
|
|
||||||
ustar->ReadArchive(Address, Size);
|
|
||||||
|
|
||||||
Inode *rootfs = nullptr;
|
|
||||||
ustar->Lookup(nullptr, "/", &rootfs);
|
|
||||||
assert(rootfs != nullptr);
|
|
||||||
|
|
||||||
FileSystemInfo *fsi = new FileSystemInfo;
|
FileSystemInfo *fsi = new FileSystemInfo;
|
||||||
fsi->Name = "ustar";
|
fsi->Name = "ustar";
|
||||||
fsi->RootName = "/";
|
|
||||||
fsi->Flags = I_FLAG_ROOT | I_FLAG_MOUNTPOINT | I_FLAG_CACHE_KEEP;
|
|
||||||
fsi->SuperOps.DeleteInode = __ustar_DestroyInode;
|
fsi->SuperOps.DeleteInode = __ustar_DestroyInode;
|
||||||
fsi->SuperOps.Destroy = __ustar_Destroy;
|
fsi->SuperOps.Destroy = __ustar_Destroy;
|
||||||
fsi->Ops.Lookup = __ustar_Lookup;
|
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.ReadLink = __ustar_ReadLink;
|
||||||
fsi->Ops.Stat = __ustar_Stat;
|
fsi->Ops.Stat = __ustar_Stat;
|
||||||
fsi->PrivateData = ustar;
|
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;
|
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/driver.h>
|
||||||
#include <interface/input.h>
|
#include <interface/input.h>
|
||||||
#include <filesystem.hpp>
|
#include <interface/block.h>
|
||||||
|
#include <fs/vfs.hpp>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <memory.hpp>
|
#include <memory.hpp>
|
||||||
#include <ints.hpp>
|
#include <ints.hpp>
|
||||||
@ -120,17 +121,15 @@ namespace Driver
|
|||||||
* 1 - input/... devices
|
* 1 - input/... devices
|
||||||
*/
|
*/
|
||||||
dev_t DriverIDCounter = 2;
|
dev_t DriverIDCounter = 2;
|
||||||
FileNode *devNode = nullptr;
|
Node devNode = nullptr;
|
||||||
FileNode *devInputNode = nullptr;
|
Node devInputNode = nullptr;
|
||||||
|
Node devBlockNode = nullptr;
|
||||||
|
|
||||||
bool IsDriverTrusted(FileNode *File);
|
bool IsDriverTrusted(Node File);
|
||||||
int LoadDriverFile(DriverObject &Drv, FileNode *File);
|
int LoadDriverFile(DriverObject &Drv, Node File);
|
||||||
void ReloadDriver(dev_t driverID);
|
void ReloadDriver(dev_t driverID);
|
||||||
|
|
||||||
void InitializeDaemonFS();
|
void InitializeDeviceDirectory();
|
||||||
|
|
||||||
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 *);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RingBuffer<KeyboardReport> GlobalKeyboardInputReports;
|
RingBuffer<KeyboardReport> GlobalKeyboardInputReports;
|
||||||
@ -138,11 +137,16 @@ namespace Driver
|
|||||||
|
|
||||||
struct DeviceInode
|
struct DeviceInode
|
||||||
{
|
{
|
||||||
struct Inode Node;
|
struct Inode inode;
|
||||||
FileNode *Parent;
|
Node Parent;
|
||||||
Inode *ParentInode;
|
Inode *ParentInode;
|
||||||
std::string Name;
|
std::string Name;
|
||||||
std::vector<DeviceInode *> Children;
|
std::vector<DeviceInode *> Children;
|
||||||
|
|
||||||
|
size_t Size;
|
||||||
|
time_t AccessTime, ModifyTime, ChangeTime;
|
||||||
|
uint32_t BlockSize;
|
||||||
|
uint32_t Blocks;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unordered_map<dev_t, DriverObject> &
|
std::unordered_map<dev_t, DriverObject> &
|
||||||
@ -185,6 +189,9 @@ namespace Driver
|
|||||||
int ReportInputEvent(dev_t DriverID, InputReport *Report);
|
int ReportInputEvent(dev_t DriverID, InputReport *Report);
|
||||||
int UnregisterDevice(dev_t DriverID, dev_t Device);
|
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 *AllocateMemory(dev_t DriverID, size_t Pages);
|
||||||
void FreeMemory(dev_t DriverID, void *Pointer, size_t Pages);
|
void FreeMemory(dev_t DriverID, void *Pointer, size_t Pages);
|
||||||
|
|
||||||
@ -193,8 +200,6 @@ namespace Driver
|
|||||||
private:
|
private:
|
||||||
~Manager();
|
~Manager();
|
||||||
};
|
};
|
||||||
|
|
||||||
void ManagerDaemonWrapper();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *GetSymbolByName(const char *Name, int Version);
|
void *GetSymbolByName(const char *Name, int Version);
|
||||||
@ -215,9 +220,12 @@ namespace v0
|
|||||||
int UnregisterInterruptHandler(dev_t DriverID, uint8_t IRQ, void *Handler);
|
int UnregisterInterruptHandler(dev_t DriverID, uint8_t IRQ, void *Handler);
|
||||||
int UnregisterAllInterruptHandlers(dev_t DriverID, 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);
|
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 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 CreateKernelThread(dev_t DriverID, pid_t pId, const char *Name, void *EntryPoint, void *Argument);
|
||||||
pid_t GetCurrentProcess(dev_t DriverID);
|
pid_t GetCurrentProcess(dev_t DriverID);
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
#include <task.hpp>
|
#include <task.hpp>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -50,15 +50,15 @@ namespace Execute
|
|||||||
void *ELFProgramHeaders;
|
void *ELFProgramHeaders;
|
||||||
|
|
||||||
void GenerateAuxiliaryVector(Memory::VirtualMemoryArea *vma,
|
void GenerateAuxiliaryVector(Memory::VirtualMemoryArea *vma,
|
||||||
FileNode *fd, Elf_Ehdr ELFHeader,
|
Node &fd, Elf_Ehdr ELFHeader,
|
||||||
uintptr_t EntryPoint,
|
uintptr_t EntryPoint,
|
||||||
uintptr_t BaseAddress);
|
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 LoadExec(Node &fd, Tasking::PCB *TargetProcess);
|
||||||
void LoadDyn(FileNode *fd, Tasking::PCB *TargetProcess);
|
void LoadDyn(Node &fd, Tasking::PCB *TargetProcess);
|
||||||
bool LoadInterpreter(FileNode *fd, Tasking::PCB *TargetProcess);
|
bool LoadInterpreter(Node &fd, Tasking::PCB *TargetProcess);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
decltype(IsElfValid) &IsValid = IsElfValid;
|
decltype(IsElfValid) &IsValid = IsElfValid;
|
||||||
@ -74,7 +74,7 @@ namespace Execute
|
|||||||
~ELFObject();
|
~ELFObject();
|
||||||
};
|
};
|
||||||
|
|
||||||
BinaryType GetBinaryType(FileNode *Path);
|
BinaryType GetBinaryType(Node &Path);
|
||||||
BinaryType GetBinaryType(std::string Path);
|
BinaryType GetBinaryType(std::string Path);
|
||||||
|
|
||||||
int Spawn(const char *Path, const char **argv, const char **envp,
|
int Spawn(const char *Path, const char **argv, const char **envp,
|
||||||
@ -88,12 +88,12 @@ namespace Execute
|
|||||||
char *GetELFStringTable(Elf_Ehdr *Header);
|
char *GetELFStringTable(Elf_Ehdr *Header);
|
||||||
char *ELFLookupString(Elf_Ehdr *Header, uintptr_t Offset);
|
char *ELFLookupString(Elf_Ehdr *Header, uintptr_t Offset);
|
||||||
Elf_Sym *ELFLookupSymbol(Elf_Ehdr *Header, std::string Name);
|
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);
|
uintptr_t ELFGetSymbolValue(Elf_Ehdr *Header, uintptr_t Table, uintptr_t Index);
|
||||||
|
|
||||||
std::vector<Elf_Phdr> ELFGetSymbolType(FileNode *fd, SegmentTypes Tag);
|
std::vector<Elf_Phdr> ELFGetSymbolType(Node &fd, SegmentTypes Tag);
|
||||||
std::vector<Elf_Shdr> ELFGetSections(FileNode *fd, std::string SectionName);
|
std::vector<Elf_Shdr> ELFGetSections(Node &fd, std::string SectionName);
|
||||||
std::vector<Elf_Dyn> ELFGetDynamicTag(FileNode *fd, DynamicArrayTags Tag);
|
std::vector<Elf_Dyn> ELFGetDynamicTag(Node &fd, DynamicArrayTags Tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // !__FENNIX_KERNEL_FILE_EXECUTE_H__
|
#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
|
#pragma once
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
#include <memory.hpp>
|
#include <memory.hpp>
|
||||||
|
|
||||||
namespace vfs
|
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__
|
#ifndef __FENNIX_KERNEL_FILESYSTEM_USTAR_H__
|
||||||
#define __FENNIX_KERNEL_FILESYSTEM_USTAR_H__
|
#define __FENNIX_KERNEL_FILESYSTEM_USTAR_H__
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
|
|
||||||
namespace vfs
|
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);
|
int (*Stat)(struct Inode *Node, struct kstat *Stat);
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
#define I_FLAG_ROOT 0x1
|
|
||||||
#define I_FLAG_MOUNTPOINT 0x2
|
|
||||||
#define I_FLAG_CACHE_KEEP 0x4
|
|
||||||
|
|
||||||
struct FileSystemInfo;
|
struct FileSystemInfo;
|
||||||
struct SuperBlockOperations
|
struct SuperBlockOperations
|
||||||
{
|
{
|
||||||
@ -337,8 +333,8 @@ struct SuperBlockOperations
|
|||||||
*
|
*
|
||||||
* Write all pending changes to the disk.
|
* Write all pending changes to the disk.
|
||||||
*
|
*
|
||||||
* @param Info Inode to synchronize. If NULL, synchronize all inodes.
|
* @param Info Inode to synchronize.
|
||||||
* @param Node Inode to synchronize.
|
* @param Node Inode to synchronize. If NULL, synchronize all inodes.
|
||||||
*
|
*
|
||||||
* @return Zero on success, otherwise an error code.
|
* @return Zero on success, otherwise an error code.
|
||||||
*/
|
*/
|
||||||
@ -354,13 +350,50 @@ struct SuperBlockOperations
|
|||||||
* @return Zero on success, otherwise an error code.
|
* @return Zero on success, otherwise an error code.
|
||||||
*/
|
*/
|
||||||
int (*Destroy)(struct FileSystemInfo *Info);
|
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));
|
} __attribute__((packed));
|
||||||
|
|
||||||
struct FileSystemInfo
|
struct FileSystemInfo
|
||||||
{
|
{
|
||||||
const char *Name;
|
const char *Name;
|
||||||
const char *RootName;
|
|
||||||
int Flags;
|
int Flags;
|
||||||
|
int Capabilities;
|
||||||
|
|
||||||
struct SuperBlockOperations SuperOps;
|
struct SuperBlockOperations SuperOps;
|
||||||
struct InodeOperations Ops;
|
struct InodeOperations Ops;
|
||||||
|
|
||||||
@ -368,6 +401,9 @@ struct FileSystemInfo
|
|||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
#ifndef __kernel__
|
#ifndef __kernel__
|
||||||
|
dev_t RegisterMountPoint(FileSystemInfo *fsi, Inode *Root);
|
||||||
|
int UnregisterMountPoint(dev_t Device);
|
||||||
|
|
||||||
dev_t RegisterFileSystem(struct FileSystemInfo *Info, struct Inode *Root);
|
dev_t RegisterFileSystem(struct FileSystemInfo *Info, struct Inode *Root);
|
||||||
int UnregisterFileSystem(dev_t Device);
|
int UnregisterFileSystem(dev_t Device);
|
||||||
#endif // !__kernel__
|
#endif // !__kernel__
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
#define __FENNIX_KERNEL_INTERNAL_MEMORY_H__
|
#define __FENNIX_KERNEL_INTERNAL_MEMORY_H__
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
#include <boot/binfo.h>
|
#include <boot/binfo.h>
|
||||||
#include <bitmap.hpp>
|
#include <bitmap.hpp>
|
||||||
#include <lock.hpp>
|
#include <lock.hpp>
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
#define __FENNIX_KERNEL_MEMORY_VMA_H__
|
#define __FENNIX_KERNEL_MEMORY_VMA_H__
|
||||||
|
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
#include <bitmap.hpp>
|
#include <bitmap.hpp>
|
||||||
#include <lock.hpp>
|
#include <lock.hpp>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
#include <memory/va.hpp>
|
#include <memory/va.hpp>
|
||||||
#include <symbols.hpp>
|
#include <symbols.hpp>
|
||||||
#include <memory.hpp>
|
#include <memory.hpp>
|
||||||
@ -219,7 +219,7 @@ namespace Tasking
|
|||||||
TaskArchitecture Architecture = TaskArchitecture::UnknownArchitecture;
|
TaskArchitecture Architecture = TaskArchitecture::UnknownArchitecture;
|
||||||
TaskCompatibility Compatibility = TaskCompatibility::UnknownPlatform;
|
TaskCompatibility Compatibility = TaskCompatibility::UnknownPlatform;
|
||||||
cwk_path_style PathStyle = CWK_STYLE_UNIX;
|
cwk_path_style PathStyle = CWK_STYLE_UNIX;
|
||||||
FileNode *RootNode = nullptr;
|
Node RootNode = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ThreadLocalStorage
|
struct ThreadLocalStorage
|
||||||
@ -445,7 +445,7 @@ namespace Tasking
|
|||||||
PID ID = -1;
|
PID ID = -1;
|
||||||
const char *Name = nullptr;
|
const char *Name = nullptr;
|
||||||
PCB *Parent = nullptr;
|
PCB *Parent = nullptr;
|
||||||
FileNode *ProcDirectory = nullptr;
|
Node ProcDirectory = nullptr;
|
||||||
|
|
||||||
/* Statuses */
|
/* Statuses */
|
||||||
std::atomic_int ExitCode;
|
std::atomic_int ExitCode;
|
||||||
@ -489,14 +489,14 @@ namespace Tasking
|
|||||||
} Linux{};
|
} Linux{};
|
||||||
|
|
||||||
/* Filesystem */
|
/* Filesystem */
|
||||||
FileNode *CWD;
|
Node CWD;
|
||||||
FileNode *Executable;
|
Node Executable;
|
||||||
FileDescriptorTable *FileDescriptors;
|
FileDescriptorTable *FileDescriptors;
|
||||||
|
|
||||||
/* stdio */
|
/* stdio */
|
||||||
FileNode *stdin;
|
Node stdin;
|
||||||
FileNode *stdout;
|
Node stdout;
|
||||||
FileNode *stderr;
|
Node stderr;
|
||||||
/*TTY::TeletypeDriver*/ void *tty;
|
/*TTY::TeletypeDriver*/ void *tty;
|
||||||
|
|
||||||
/* Memory */
|
/* Memory */
|
||||||
@ -521,7 +521,7 @@ namespace Tasking
|
|||||||
void SetState(TaskState state);
|
void SetState(TaskState state);
|
||||||
void SetExitCode(int code);
|
void SetExitCode(int code);
|
||||||
void Rename(const char *name);
|
void Rename(const char *name);
|
||||||
void SetWorkingDirectory(FileNode *node);
|
void SetWorkingDirectory(Node node);
|
||||||
void SetExe(const char *path);
|
void SetExe(const char *path);
|
||||||
size_t GetSize();
|
size_t GetSize();
|
||||||
TCB *GetThread(TID ID);
|
TCB *GetThread(TID ID);
|
||||||
|
@ -458,6 +458,10 @@ typedef uint48_t uint_fast48_t;
|
|||||||
#define hot __attribute__((hot))
|
#define hot __attribute__((hot))
|
||||||
#define cold __attribute__((cold))
|
#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 NoSecurityAnalysis __no_stack_protector __no_sanitize_address __no_sanitize_undefined __no_sanitize_thread
|
||||||
#define nsa NoSecurityAnalysis
|
#define nsa NoSecurityAnalysis
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
|
|
||||||
#include <filesystem/ustar.hpp>
|
#include <fs/ustar.hpp>
|
||||||
#include <memory.hpp>
|
#include <memory.hpp>
|
||||||
#include <convert.h>
|
#include <convert.h>
|
||||||
#include <ints.hpp>
|
#include <ints.hpp>
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#include <boot/binfo.h>
|
#include <boot/binfo.h>
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
#include <display.hpp>
|
#include <display.hpp>
|
||||||
#include <symbols.hpp>
|
#include <symbols.hpp>
|
||||||
#include <kconfig.hpp>
|
#include <kconfig.hpp>
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#include "tests/t.h"
|
#include "tests/t.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <filesystem/ustar.hpp>
|
#include <fs/ustar.hpp>
|
||||||
#include <subsystems.hpp>
|
#include <subsystems.hpp>
|
||||||
#include <kshell.hpp>
|
#include <kshell.hpp>
|
||||||
#include <power.hpp>
|
#include <power.hpp>
|
||||||
@ -70,11 +70,11 @@ int SpawnLinuxInit()
|
|||||||
"/startup/init"};
|
"/startup/init"};
|
||||||
|
|
||||||
const char *foundPath = nullptr;
|
const char *foundPath = nullptr;
|
||||||
FileNode *root = fs->GetRoot(1);
|
Node root = fs->GetRoot(1);
|
||||||
for (const std::string &path : fallbackPaths)
|
for (const std::string &path : fallbackPaths)
|
||||||
{
|
{
|
||||||
const char *str = path.c_str();
|
const char *str = path.c_str();
|
||||||
if (!fs->PathExists(str, root))
|
if (fs->Lookup(root, str) == false)
|
||||||
continue;
|
continue;
|
||||||
foundPath = str;
|
foundPath = str;
|
||||||
break;
|
break;
|
||||||
@ -123,8 +123,6 @@ void KernelMainThread()
|
|||||||
|
|
||||||
KPrint("Initializing Driver Manager");
|
KPrint("Initializing Driver Manager");
|
||||||
DriverManager = new Driver::Manager;
|
DriverManager = new Driver::Manager;
|
||||||
TaskManager->CreateThread(thisProcess, Tasking::IP(Driver::ManagerDaemonWrapper))
|
|
||||||
->Rename("Device Service");
|
|
||||||
|
|
||||||
KPrint("Loading Drivers");
|
KPrint("Loading Drivers");
|
||||||
DriverManager->PreloadDrivers();
|
DriverManager->PreloadDrivers();
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
|
|
||||||
#include <filesystem/ustar.hpp>
|
#include <fs/ustar.hpp>
|
||||||
#include <memory.hpp>
|
#include <memory.hpp>
|
||||||
|
|
||||||
vfs::Virtual *fs = nullptr;
|
vfs::Virtual *fs = nullptr;
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "../cmds.hpp"
|
#include "../cmds.hpp"
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../../kernel.h"
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ void cmd_cat(const char *args)
|
|||||||
if (args[0] == '\0')
|
if (args[0] == '\0')
|
||||||
return;
|
return;
|
||||||
|
|
||||||
FileNode *node = fs->GetByPath(args, nullptr);
|
Node node = fs->Lookup(thisProcess->CWD, args);
|
||||||
|
|
||||||
if (node == nullptr)
|
if (node == nullptr)
|
||||||
{
|
{
|
||||||
@ -48,11 +48,11 @@ void cmd_cat(const char *args)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
kstat stat = {};
|
kstat stat;
|
||||||
node->Stat(&stat);
|
fs->Stat(node, &stat);
|
||||||
|
|
||||||
uint8_t *buffer = new uint8_t[stat.Size + 1];
|
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)
|
if (rBytes > 0)
|
||||||
printf("%s\n", buffer);
|
printf("%s\n", buffer);
|
||||||
else
|
else
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "../cmds.hpp"
|
#include "../cmds.hpp"
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../../kernel.h"
|
||||||
|
|
||||||
@ -28,8 +28,7 @@ void cmd_cd(const char *args)
|
|||||||
if (args[0] == '\0')
|
if (args[0] == '\0')
|
||||||
return;
|
return;
|
||||||
|
|
||||||
FileNode *node = fs->GetByPath(args, nullptr);
|
Node node = fs->Lookup(thisProcess->CWD, args);
|
||||||
|
|
||||||
if (node == nullptr)
|
if (node == nullptr)
|
||||||
{
|
{
|
||||||
printf("cd: %s: No such file or directory\n", args);
|
printf("cd: %s: No such file or directory\n", args);
|
||||||
@ -43,4 +42,5 @@ void cmd_cd(const char *args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
thisProcess->CWD = node;
|
thisProcess->CWD = node;
|
||||||
|
debug("changed cwd to %s", node->Path.c_str());
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "../cmds.hpp"
|
#include "../cmds.hpp"
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
#include <acpi.hpp>
|
#include <acpi.hpp>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../../kernel.h"
|
||||||
@ -38,9 +38,41 @@ void cmd_dump(const char *args)
|
|||||||
*strLen = '\0';
|
*strLen = '\0';
|
||||||
strLen++;
|
strLen++;
|
||||||
|
|
||||||
void *Address = (void *)strtoul(strAddr, nullptr, 16);
|
void *Address;
|
||||||
unsigned long Length = strtoul(strLen, nullptr, 10);
|
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 *AddressChar = (unsigned char *)Address;
|
||||||
unsigned char Buffer[17];
|
unsigned char Buffer[17];
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "../cmds.hpp"
|
#include "../cmds.hpp"
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
#include <task.hpp>
|
#include <task.hpp>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../../kernel.h"
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "../cmds.hpp"
|
#include "../cmds.hpp"
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
#include <task.hpp>
|
#include <task.hpp>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../../kernel.h"
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "../cmds.hpp"
|
#include "../cmds.hpp"
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
#include <task.hpp>
|
#include <task.hpp>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../../kernel.h"
|
||||||
|
@ -17,98 +17,60 @@
|
|||||||
|
|
||||||
#include "../cmds.hpp"
|
#include "../cmds.hpp"
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../../kernel.h"
|
||||||
|
|
||||||
using namespace vfs;
|
using namespace vfs;
|
||||||
|
|
||||||
const char *ColorNodeType(FileNode *node)
|
const char *ColorNodeType(Node node)
|
||||||
{
|
{
|
||||||
if (node->IsRegularFile())
|
if (node->IsRegularFile())
|
||||||
return "\x1b[32m";
|
return "\x1b[0m";
|
||||||
else if (node->IsDirectory())
|
else if (node->IsDirectory())
|
||||||
return "\x1b[34m";
|
return "\x1b[1;34m";
|
||||||
else if (node->IsBlockDevice())
|
else if (node->IsBlockDevice())
|
||||||
return "\x1b[33m";
|
return "\x1b[1;33m";
|
||||||
else if (node->IsCharacterDevice())
|
else if (node->IsCharacterDevice())
|
||||||
return "\x1b[33m";
|
return "\x1b[1;33m";
|
||||||
else if (node->IsFIFO())
|
else if (node->IsFIFO())
|
||||||
return "\x1b[33m";
|
return "\x1b[0;33m";
|
||||||
else if (node->IsSymbolicLink())
|
else if (node->IsSymbolicLink())
|
||||||
return "\x1b[35m";
|
return "\x1b[1;36m";
|
||||||
else
|
else
|
||||||
return "\x1b[0m";
|
return "\x1b[0m";
|
||||||
}
|
}
|
||||||
|
|
||||||
__no_sanitize("alignment") size_t MaxNameLength(FileNode *nodes)
|
__no_sanitize("alignment") void PrintLS(Node node)
|
||||||
{
|
{
|
||||||
size_t maxLength = 0;
|
size_t maxNameLength = 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);
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
|
||||||
kdirent *dirBuffer = new kdirent[16];
|
std::list<Node> children = fs->ReadDirectory(node);
|
||||||
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;
|
|
||||||
|
|
||||||
off_t bufOffset = 0;
|
for (auto &&i : children)
|
||||||
for (size_t i = 0; i < read / sizeof(kdirent); i++)
|
std::max(maxNameLength, i->Name.length());
|
||||||
{
|
|
||||||
if (count % 5 == 0 && !first)
|
for (auto &&i : children)
|
||||||
printf("\n");
|
{
|
||||||
kdirent *dirent = (kdirent *)((uintptr_t)dirBuffer + bufOffset);
|
if (count % 5 == 0 && !first)
|
||||||
if (dirent->d_reclen == 0)
|
printf("\n");
|
||||||
break;
|
|
||||||
bufOffset += dirent->d_reclen;
|
printf(" %s%-*s ", ColorNodeType(i), (int)maxNameLength, i->Name.c_str());
|
||||||
printf(" %s%-*s ", ColorNodeType(node), (int)maxNameLength, dirent->d_name);
|
|
||||||
count++;
|
count++;
|
||||||
first = false;
|
first = false;
|
||||||
}
|
|
||||||
offset += read / sizeof(kdirent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\x1b[0m\n");
|
printf("\x1b[0m\n");
|
||||||
delete[] dirBuffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_ls(const char *args)
|
void cmd_ls(const char *args)
|
||||||
{
|
{
|
||||||
if (args[0] == '\0')
|
if (args[0] == '\0')
|
||||||
{
|
{
|
||||||
FileNode *rootNode = thisProcess->CWD;
|
Node rootNode = thisProcess->CWD;
|
||||||
|
|
||||||
if (rootNode == nullptr)
|
if (rootNode == nullptr)
|
||||||
rootNode = fs->GetRoot(0);
|
rootNode = fs->GetRoot(0);
|
||||||
@ -117,7 +79,7 @@ void cmd_ls(const char *args)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileNode *thisNode = fs->GetByPath(args, nullptr);
|
Node thisNode = fs->Lookup(thisProcess->CWD, args);
|
||||||
|
|
||||||
if (thisNode == nullptr)
|
if (thisNode == nullptr)
|
||||||
{
|
{
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "../cmds.hpp"
|
#include "../cmds.hpp"
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
#include <acpi.hpp>
|
#include <acpi.hpp>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../../kernel.h"
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "../cmds.hpp"
|
#include "../cmds.hpp"
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../../kernel.h"
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "../cmds.hpp"
|
#include "../cmds.hpp"
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
#include <task.hpp>
|
#include <task.hpp>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../../kernel.h"
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "../cmds.hpp"
|
#include "../cmds.hpp"
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../../kernel.h"
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "../cmds.hpp"
|
#include "../cmds.hpp"
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
#include <task.hpp>
|
#include <task.hpp>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../../kernel.h"
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "../cmds.hpp"
|
#include "../cmds.hpp"
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
#include <task.hpp>
|
#include <task.hpp>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../../kernel.h"
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "../cmds.hpp"
|
#include "../cmds.hpp"
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
#include <task.hpp>
|
#include <task.hpp>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../../kernel.h"
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "../cmds.hpp"
|
#include "../cmds.hpp"
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
#include <task.hpp>
|
#include <task.hpp>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../../kernel.h"
|
||||||
|
@ -17,70 +17,38 @@
|
|||||||
|
|
||||||
#include "../cmds.hpp"
|
#include "../cmds.hpp"
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#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))
|
std::list<Node> children = fs->ReadDirectory(rootNode);
|
||||||
// {
|
size_t count = children.size();
|
||||||
// Display->UpdateBuffer();
|
size_t index = 0;
|
||||||
// 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);
|
|
||||||
// }
|
|
||||||
|
|
||||||
kdirent *dirBuffer = new kdirent[16];
|
for (auto &&child : children)
|
||||||
ssize_t read = 0;
|
{
|
||||||
off_t offset = 0;
|
if (child->Name == "." || child->Name == "..")
|
||||||
while ((read = rootNode->ReadDir(dirBuffer, sizeof(kdirent) * 16, offset, LONG_MAX)) > 0)
|
continue;
|
||||||
{
|
|
||||||
if (read / sizeof(kdirent) == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
off_t bufOffset = 0;
|
bool isLast = (++index == count);
|
||||||
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;
|
|
||||||
|
|
||||||
if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0)
|
printf("%s%s- %s\n", prefix.c_str(), isLast ? "\\" : "|-", child->Name.c_str());
|
||||||
continue;
|
|
||||||
|
|
||||||
FileNode *node = fs->GetByPath(dirent->d_name, rootNode);
|
if (child->IsDirectory())
|
||||||
if (node == nullptr)
|
{
|
||||||
continue;
|
std::string newPrefix = prefix + (isLast ? " " : "| ");
|
||||||
|
tree_loop(child, depth + 1, newPrefix);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_tree(const char *args)
|
void cmd_tree(const char *args)
|
||||||
{
|
{
|
||||||
FileNode *rootNode = thisProcess->CWD;
|
Node rootNode = thisProcess->CWD;
|
||||||
if (args[0] == '\0')
|
if (args[0] == '\0')
|
||||||
{
|
{
|
||||||
if (rootNode == nullptr)
|
if (rootNode == nullptr)
|
||||||
@ -88,7 +56,7 @@ void cmd_tree(const char *args)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rootNode = fs->GetByPath(args, nullptr);
|
rootNode = fs->Lookup(thisProcess->CWD, args);
|
||||||
if (rootNode == nullptr)
|
if (rootNode == nullptr)
|
||||||
{
|
{
|
||||||
printf("ls: %s: No such file or directory\n", args);
|
printf("ls: %s: No such file or directory\n", args);
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "../cmds.hpp"
|
#include "../cmds.hpp"
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../../kernel.h"
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "../cmds.hpp"
|
#include "../cmds.hpp"
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../../kernel.h"
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "../cmds.hpp"
|
#include "../cmds.hpp"
|
||||||
|
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../../kernel.h"
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include <interface/driver.h>
|
#include <interface/driver.h>
|
||||||
#include <interface/input.h>
|
#include <interface/input.h>
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
#include <driver.hpp>
|
#include <driver.hpp>
|
||||||
#include <lock.hpp>
|
#include <lock.hpp>
|
||||||
#include <exec.hpp>
|
#include <exec.hpp>
|
||||||
@ -88,6 +88,7 @@ void KShellThread()
|
|||||||
|
|
||||||
KPrint("Starting kernel shell...");
|
KPrint("Starting kernel shell...");
|
||||||
thisThread->SetPriority(Tasking::TaskPriority::Normal);
|
thisThread->SetPriority(Tasking::TaskPriority::Normal);
|
||||||
|
thisProcess->CWD = fs->GetRoot(0);
|
||||||
|
|
||||||
std::string strBuf = "";
|
std::string strBuf = "";
|
||||||
std::vector<std::string *> history;
|
std::vector<std::string *> history;
|
||||||
@ -97,7 +98,8 @@ void KShellThread()
|
|||||||
bool tabDblPress = false;
|
bool tabDblPress = false;
|
||||||
|
|
||||||
const char *keyDevPath = "/dev/input/keyboard";
|
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)
|
if (kfd == nullptr)
|
||||||
{
|
{
|
||||||
KPrint("Failed to open keyboard device!");
|
KPrint("Failed to open keyboard device!");
|
||||||
@ -125,21 +127,20 @@ void KShellThread()
|
|||||||
debug("clearing strBuf(\"%s\")", strBuf.c_str());
|
debug("clearing strBuf(\"%s\")", strBuf.c_str());
|
||||||
strBuf.clear();
|
strBuf.clear();
|
||||||
|
|
||||||
FileNode *cwd = thisProcess->CWD;
|
Node cwd = thisProcess->CWD;
|
||||||
if (!cwd)
|
if (!cwd)
|
||||||
cwd = fs->GetRoot(0);
|
cwd = fs->GetRoot(0);
|
||||||
std::string cwdStr = fs->GetByNode(cwd);
|
debug("cwd: %s", cwd->Path.c_str());
|
||||||
debug("cwd: %*s", (int)cwdStr.size(), cwdStr.c_str());
|
|
||||||
|
|
||||||
printf("\x1b[1;34m%s@%s:%s$ \x1b[0m",
|
printf("\x1b[1;34m%s@%s:%s$ \x1b[0m",
|
||||||
"kernel", "fennix",
|
"kernel", "fennix",
|
||||||
cwdStr.c_str());
|
cwd->Path.c_str());
|
||||||
|
|
||||||
KeyboardReport scBuf{};
|
KeyboardReport scBuf{};
|
||||||
ssize_t nBytes;
|
ssize_t nBytes;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
nBytes = kfd->Read(&scBuf, sizeof(KeyboardReport), 0);
|
nBytes = fs->Read(kfd, &scBuf, sizeof(KeyboardReport), 0);
|
||||||
if (nBytes == 0)
|
if (nBytes == 0)
|
||||||
{
|
{
|
||||||
debug("Empty read from keyboard device!");
|
debug("Empty read from keyboard device!");
|
||||||
@ -561,14 +562,14 @@ void KShellThread()
|
|||||||
if (fs->PathIsRelative(cmd_only.c_str()))
|
if (fs->PathIsRelative(cmd_only.c_str()))
|
||||||
{
|
{
|
||||||
path += cmd_only;
|
path += cmd_only;
|
||||||
if (!fs->PathExists(path.c_str(), nullptr))
|
if (!fs->Lookup(root, path.c_str()))
|
||||||
path = "/usr/bin/" + cmd_only;
|
path = "/usr/bin/" + cmd_only;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
path = cmd_only;
|
path = cmd_only;
|
||||||
|
|
||||||
debug("path: %s", path.c_str());
|
debug("path: %s", path.c_str());
|
||||||
if (fs->PathExists(path.c_str(), nullptr))
|
if (fs->Lookup(root, path.c_str()))
|
||||||
{
|
{
|
||||||
const char *envp[5] = {
|
const char *envp[5] = {
|
||||||
"PATH=/bin:/usr/bin",
|
"PATH=/bin:/usr/bin",
|
||||||
|
@ -158,11 +158,9 @@ void terminate_header_stub()
|
|||||||
CPU::Stop(); /* FIXME: Panic */
|
CPU::Stop(); /* FIXME: Panic */
|
||||||
}
|
}
|
||||||
|
|
||||||
void exception_cleanup_stub(_Unwind_Reason_Code Code,
|
void exception_cleanup_stub(_Unwind_Reason_Code Code, _Unwind_Exception *Exception)
|
||||||
_Unwind_Exception *Exception)
|
|
||||||
{
|
{
|
||||||
fixme("exception_cleanup( %d %p ) called.",
|
fixme("exception_cleanup( %d %p ) called.", Code, Exception);
|
||||||
Code, Exception);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void *__cxa_allocate_exception(size_t thrown_size) throw()
|
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;
|
return Exception + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" __noreturn void __cxa_throw(void *thrown_object,
|
extern "C" __noreturn void __cxa_throw(void *thrown_object, void *tinfo, void (*dest)(void *))
|
||||||
std::type_info *tinfo,
|
|
||||||
void (*dest)(void *))
|
|
||||||
{
|
{
|
||||||
trace("Throwing exception of type \"%s\". ( object: %p, destructor: %p )",
|
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();
|
__cxa_eh_globals *Globals = __cxa_get_globals();
|
||||||
Globals->uncaughtExceptions++;
|
Globals->uncaughtExceptions++;
|
||||||
@ -218,10 +214,9 @@ extern "C" void __cxa_throw_bad_array_new_length()
|
|||||||
fixme("__cxa_throw_bad_array_new_length() called.");
|
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.",
|
fixme("__cxa_free_exception( %p ) called.", thrown_exception);
|
||||||
thrown_exception);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__extension__ typedef int __guard __attribute__((mode(__DI__)));
|
__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/>.
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <filesystem/ramfs.hpp>
|
#include <fs/ramfs.hpp>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../../kernel.h"
|
||||||
|
#include <fs/ustar.hpp>
|
||||||
|
#include <ini.h>
|
||||||
|
|
||||||
namespace Subsystem::Linux
|
namespace Subsystem::Linux
|
||||||
{
|
{
|
||||||
bool Initialized = false;
|
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()
|
void InitializeSubSystem()
|
||||||
{
|
{
|
||||||
if (fs->RootExists(1) == false)
|
if (fs->RootExists(1) == false)
|
||||||
{
|
{
|
||||||
FileNode *nmnt = fs->GetByPath("/mnt", fs->GetRoot(0));
|
Node root = fs->GetRoot(0);
|
||||||
assert(MountRAMFS(nmnt, "linux", 1));
|
Node cfg = fs->Lookup(root, "/sys/cfg/subsystem/linux");
|
||||||
FileNode *linux = fs->GetRoot(1);
|
if (cfg)
|
||||||
|
{
|
||||||
|
struct kstat st;
|
||||||
|
fs->Stat(cfg, &st);
|
||||||
|
|
||||||
FileNode *bin = fs->ForceCreate(linux, "bin", 0755);
|
std::unique_ptr<char[]> buf(new char[st.Size]);
|
||||||
FileNode *boot = fs->ForceCreate(linux, "boot", 0755);
|
fs->Read(cfg, buf.get(), st.Size, 0);
|
||||||
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);
|
|
||||||
|
|
||||||
UNUSED(bin);
|
ini_t *ini = ini_load(buf.get(), NULL);
|
||||||
UNUSED(boot);
|
int section = ini_find_section(ini, "rootfs", NULL);
|
||||||
UNUSED(dev);
|
int pathIdx = ini_find_property(ini, section, "path", NULL);
|
||||||
UNUSED(etc);
|
const char *uPath = ini_property_value(ini, section, pathIdx);
|
||||||
UNUSED(home);
|
debug("path=%s", uPath);
|
||||||
UNUSED(lib);
|
ini_destroy(ini);
|
||||||
UNUSED(lib64);
|
|
||||||
UNUSED(media);
|
if (fs->Lookup(root, uPath) != false)
|
||||||
UNUSED(mnt);
|
{
|
||||||
UNUSED(opt);
|
root = fs->Lookup(root, uPath);
|
||||||
UNUSED(proc);
|
|
||||||
|
// 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 */)
|
if (flags & 0200000 /* O_DIRECTORY */)
|
||||||
{
|
{
|
||||||
FileNode *node = fs->GetByPath(pPathname, pcb->CWD);
|
Node node = fs->Lookup(pcb->CWD, pPathname);
|
||||||
if (node == nullptr)
|
if (node == nullptr)
|
||||||
{
|
{
|
||||||
debug("Couldn't find %s", pPathname);
|
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);
|
debug("access(%s, %d)", (char *)pPathname, mode);
|
||||||
|
|
||||||
if (!fs->PathExists(pPathname, pcb->CWD))
|
if (!fs->Lookup(pcb->CWD, pPathname))
|
||||||
return -linux_ENOENT;
|
return -linux_ENOENT;
|
||||||
|
|
||||||
stub;
|
stub;
|
||||||
@ -1717,7 +1717,7 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn
|
|||||||
safeEnvp[i + 1] = nullptr;
|
safeEnvp[i + 1] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileNode *file = fs->GetByPath(pPathname, pcb->CWD);
|
Node file = fs->Lookup(pcb->CWD, pPathname);
|
||||||
|
|
||||||
if (!file)
|
if (!file)
|
||||||
{
|
{
|
||||||
@ -1726,7 +1726,7 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn
|
|||||||
}
|
}
|
||||||
|
|
||||||
char shebangMagic[2]{};
|
char shebangMagic[2]{};
|
||||||
file->Read((uint8_t *)shebangMagic, 2, 0);
|
fs->Read(file, (uint8_t *)shebangMagic, 2, 0);
|
||||||
|
|
||||||
if (shebangMagic[0] == '#' && shebangMagic[1] == '!')
|
if (shebangMagic[0] == '#' && shebangMagic[1] == '!')
|
||||||
{
|
{
|
||||||
@ -1740,7 +1740,7 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn
|
|||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
if (file->Read((uint8_t *)&c, 1, shebangOffset) == 0)
|
if (fs->Read(file, (uint8_t *)&c, 1, shebangOffset) == 0)
|
||||||
break;
|
break;
|
||||||
if (c == '\n' || shebangLength == shebangLengthMax)
|
if (c == '\n' || shebangLength == shebangLengthMax)
|
||||||
break;
|
break;
|
||||||
@ -1870,7 +1870,7 @@ __no_sanitize("undefined") static int linux_execve(SysFrm *sf, const char *pathn
|
|||||||
cwk_path_get_basename(pPathname, &baseName, nullptr);
|
cwk_path_get_basename(pPathname, &baseName, nullptr);
|
||||||
|
|
||||||
pcb->Rename(baseName);
|
pcb->Rename(baseName);
|
||||||
pcb->SetWorkingDirectory(file->Parent);
|
pcb->SetWorkingDirectory(fs->Convert(file->Parent));
|
||||||
pcb->SetExe(pPathname);
|
pcb->SetExe(pPathname);
|
||||||
|
|
||||||
Tasking::Task *ctx = pcb->GetContext();
|
Tasking::Task *ctx = pcb->GetContext();
|
||||||
@ -2208,14 +2208,15 @@ static int linux_uname(SysFrm *, struct utsname *buf)
|
|||||||
#endif
|
#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)
|
if (rn)
|
||||||
{
|
{
|
||||||
struct kstat st{};
|
struct kstat st;
|
||||||
rn->Stat(&st);
|
fs->Stat(rn, &st);
|
||||||
|
|
||||||
char *sh = new char[st.Size];
|
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);
|
ini_t *ini = ini_load(sh, NULL);
|
||||||
int section = ini_find_section(ini, "uname", NULL);
|
int section = ini_find_section(ini, "uname", NULL);
|
||||||
@ -2250,7 +2251,7 @@ static int linux_uname(SysFrm *, struct utsname *buf)
|
|||||||
delete[] sh;
|
delete[] sh;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
warn("Couldn't open /sys/cfg/cross/linux");
|
warn("Couldn't open /sys/cfg/subsystem/linux");
|
||||||
|
|
||||||
memcpy(pBuf, &uname, sizeof(struct utsname));
|
memcpy(pBuf, &uname, sizeof(struct utsname));
|
||||||
return 0;
|
return 0;
|
||||||
@ -2360,7 +2361,7 @@ static int linux_chdir(SysFrm *, const char *path)
|
|||||||
if (!pPath)
|
if (!pPath)
|
||||||
return -linux_EFAULT;
|
return -linux_EFAULT;
|
||||||
|
|
||||||
FileNode *n = fs->GetByPath(pPath, pcb->CWD);
|
Node n = fs->Lookup(pcb->CWD, pPath);
|
||||||
if (!n)
|
if (!n)
|
||||||
return -linux_ENOENT;
|
return -linux_ENOENT;
|
||||||
|
|
||||||
@ -2378,8 +2379,8 @@ static int linux_fchdir(SysFrm *, int fd)
|
|||||||
if (it == fdt->FileMap.end())
|
if (it == fdt->FileMap.end())
|
||||||
return -linux_EBADF;
|
return -linux_EBADF;
|
||||||
|
|
||||||
pcb->SetWorkingDirectory(it->second.Node);
|
pcb->SetWorkingDirectory(it->second.node);
|
||||||
debug("Changed cwd to \"%s\"", it->second.Node->GetPath().c_str());
|
debug("Changed cwd to \"%s\"", it->second.node->GetPath().c_str());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2395,7 +2396,7 @@ static int linux_mkdir(SysFrm *, const char *pathname, mode_t mode)
|
|||||||
|
|
||||||
mode &= ~pcb->FileCreationMask & 0777;
|
mode &= ~pcb->FileCreationMask & 0777;
|
||||||
|
|
||||||
FileNode *n = fs->Create(pcb->CWD, pPathname, mode);
|
Node n = fs->Create(pcb->CWD, pPathname, mode);
|
||||||
if (!n)
|
if (!n)
|
||||||
return -linux_EEXIST;
|
return -linux_EEXIST;
|
||||||
return 0;
|
return 0;
|
||||||
@ -2432,13 +2433,13 @@ static ssize_t linux_readlink(SysFrm *, const char *pathname,
|
|||||||
ReturnLogError(-linux_EBADF, "Invalid fd %d", fd);
|
ReturnLogError(-linux_EBADF, "Invalid fd %d", fd);
|
||||||
|
|
||||||
vfs::FileDescriptorTable::Fildes &fildes = it->second;
|
vfs::FileDescriptorTable::Fildes &fildes = it->second;
|
||||||
FileNode *node = fildes.Node;
|
Node node = fildes.node;
|
||||||
fdt->usr_close(fd);
|
fdt->usr_close(fd);
|
||||||
|
|
||||||
if (!node->IsSymbolicLink())
|
if (!node->IsSymbolicLink())
|
||||||
return -linux_EINVAL;
|
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)
|
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)
|
if (pPathname == nullptr)
|
||||||
return -linux_EFAULT;
|
return -linux_EFAULT;
|
||||||
|
|
||||||
FileNode *node = fs->GetByPath(pPathname, pcb->CWD);
|
Node node = fs->Lookup(pcb->CWD, pPathname);
|
||||||
if (!node)
|
if (!node)
|
||||||
return -linux_ENOENT;
|
return -linux_ENOENT;
|
||||||
|
|
||||||
@ -3114,7 +3115,7 @@ __no_sanitize("undefined") static ssize_t linux_getdents64(SysFrm *,
|
|||||||
}
|
}
|
||||||
|
|
||||||
vfs::FileDescriptorTable::Fildes &fildes = it->second;
|
vfs::FileDescriptorTable::Fildes &fildes = it->second;
|
||||||
if (!fildes.Node->IsDirectory())
|
if (!fildes.node->IsDirectory())
|
||||||
{
|
{
|
||||||
debug("Not a directory");
|
debug("Not a directory");
|
||||||
return -ENOTDIR;
|
return -ENOTDIR;
|
||||||
@ -3138,8 +3139,7 @@ __no_sanitize("undefined") static ssize_t linux_getdents64(SysFrm *,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* The structs are the same, no need for conversion. */
|
/* The structs are the same, no need for conversion. */
|
||||||
ssize_t ret = fildes.Node->ReadDir((struct kdirent *)pDirp, count, fildes.Offset,
|
ssize_t ret = fs->ReadDirectory(fildes.node, (struct kdirent *)pDirp, count, fildes.Offset, count / sizeof(kdirent));
|
||||||
count / sizeof(kdirent));
|
|
||||||
|
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
fildes.Offset += ret;
|
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)
|
if (dirfd == linux_AT_FDCWD)
|
||||||
{
|
{
|
||||||
FileNode *absoluteNode = fs->GetByPath(pPathname, pcb->CWD);
|
Node absoluteNode = fs->Lookup(pcb->CWD, pPathname);
|
||||||
if (!absoluteNode)
|
if (!absoluteNode)
|
||||||
return -linux_ENOENT;
|
return -linux_ENOENT;
|
||||||
|
|
||||||
@ -3373,7 +3373,7 @@ static long linux_newfstatat(SysFrm *, int dirfd, const char *pathname,
|
|||||||
case linux_AT_FDCWD:
|
case linux_AT_FDCWD:
|
||||||
{
|
{
|
||||||
debug("dirfd is AT_FDCWD for \"%s\"", pPathname);
|
debug("dirfd is AT_FDCWD for \"%s\"", pPathname);
|
||||||
FileNode *node = fs->GetByPath(pPathname, pcb->CWD);
|
Node node = fs->Lookup(pcb->CWD, pPathname);
|
||||||
if (!node)
|
if (!node)
|
||||||
return -linux_ENOENT;
|
return -linux_ENOENT;
|
||||||
|
|
||||||
@ -3390,7 +3390,7 @@ static long linux_newfstatat(SysFrm *, int dirfd, const char *pathname,
|
|||||||
ReturnLogError(-linux_EBADF, "Invalid fd %d", dirfd);
|
ReturnLogError(-linux_EBADF, "Invalid fd %d", dirfd);
|
||||||
|
|
||||||
vfs::FileDescriptorTable::Fildes &fildes = it->second;
|
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());
|
debug("node: %s", node->GetPath().c_str());
|
||||||
if (!node)
|
if (!node)
|
||||||
return -linux_ENOENT;
|
return -linux_ENOENT;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <filesystem/ramfs.hpp>
|
#include <fs/ramfs.hpp>
|
||||||
|
|
||||||
#include "../../kernel.h"
|
#include "../../kernel.h"
|
||||||
|
|
||||||
@ -23,25 +23,30 @@ namespace Subsystem::Windows
|
|||||||
{
|
{
|
||||||
bool Initialized = false;
|
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()
|
void InitializeSubSystem()
|
||||||
{
|
{
|
||||||
if (fs->RootExists(2) == false)
|
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 */)
|
if (flags & 0200000 /* O_DIRECTORY */)
|
||||||
{
|
{
|
||||||
FileNode *node = fs->GetByPath(pPathname, pcb->CWD);
|
Node node = fs->Lookup(pcb->CWD, pPathname);
|
||||||
if (node == nullptr)
|
if (node == nullptr)
|
||||||
{
|
{
|
||||||
debug("Couldn't find %s", pPathname);
|
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);
|
debug("access(%s, %d)", (char *)pPathname, mode);
|
||||||
|
|
||||||
if (!fs->PathExists(pPathname, pcb->CWD))
|
if (!fs->Lookup(pcb->CWD, pPathname))
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
stub;
|
stub;
|
||||||
|
@ -95,34 +95,34 @@ namespace Tasking
|
|||||||
strcpy((char *)this->Name, name);
|
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)",
|
trace("Setting working directory of process %s", node->Name.c_str());
|
||||||
this->Name, node, node->Name.c_str());
|
this->CWD = node;
|
||||||
CWD = node;
|
Node cwd = fs->Lookup(ProcDirectory, "cwd");
|
||||||
FileNode *cwd = fs->GetByPath("cwd", ProcDirectory);
|
|
||||||
if (cwd)
|
if (cwd)
|
||||||
fs->Remove(cwd);
|
fs->Remove(cwd);
|
||||||
cwd = fs->CreateLink("cwd", ProcDirectory, node);
|
cwd = fs->CreateLink(ProcDirectory, "cwd", node);
|
||||||
if (cwd == nullptr)
|
if (cwd == nullptr)
|
||||||
error("Failed to create cwd link");
|
error("Failed to create cwd link");
|
||||||
}
|
}
|
||||||
|
|
||||||
void PCB::SetExe(const char *path)
|
void PCB::SetExe(const char *path)
|
||||||
{
|
{
|
||||||
trace("Setting exe %s to %s",
|
trace("Setting exe %s to %s", this->Name, path);
|
||||||
this->Name, path);
|
|
||||||
Executable = fs->GetByPath(path, ProcDirectory);
|
Executable = fs->Lookup(ProcDirectory, path);
|
||||||
if (Executable->IsSymbolicLink())
|
if (Executable->IsSymbolicLink())
|
||||||
{
|
{
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
Executable->ReadLink(buffer, sizeof(buffer));
|
fs->ReadLink(Executable, buffer, sizeof(buffer));
|
||||||
Executable = fs->GetByPath(buffer, Executable->Parent);
|
Executable = fs->Lookup(Executable->Parent, buffer);
|
||||||
}
|
}
|
||||||
FileNode *exe = fs->GetByPath("exe", ProcDirectory);
|
|
||||||
|
Node exe = fs->Lookup(ProcDirectory, "exe");
|
||||||
if (exe)
|
if (exe)
|
||||||
fs->Remove(exe);
|
fs->Remove(exe);
|
||||||
exe = fs->CreateLink("exe", ProcDirectory, path);
|
exe = fs->CreateLink(ProcDirectory, "exe", path);
|
||||||
if (exe == nullptr)
|
if (exe == nullptr)
|
||||||
error("Failed to create exe link");
|
error("Failed to create exe link");
|
||||||
}
|
}
|
||||||
@ -155,7 +155,8 @@ namespace Tasking
|
|||||||
assert(ExecutionMode >= _ExecuteModeMin);
|
assert(ExecutionMode >= _ExecuteModeMin);
|
||||||
assert(ExecutionMode <= _ExecuteModeMax);
|
assert(ExecutionMode <= _ExecuteModeMax);
|
||||||
|
|
||||||
FileNode *procDir = fs->GetByPath("/proc", nullptr);
|
Node root = fs->GetRoot(0);
|
||||||
|
Node procDir = fs->Lookup(root, "/proc");
|
||||||
assert(procDir != nullptr);
|
assert(procDir != nullptr);
|
||||||
|
|
||||||
/* d r-x r-x r-x */
|
/* d r-x r-x r-x */
|
||||||
|
@ -246,23 +246,222 @@ namespace Tasking
|
|||||||
debug("Tasking Started");
|
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)
|
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. */
|
/* I don't know if this is the best way to do this. */
|
||||||
Scheduler::Custom *custom_sched = new Scheduler::Custom(this);
|
Scheduler::Custom *custom_sched = new Scheduler::Custom(this);
|
||||||
Scheduler::Base *sched = r_cst(Scheduler::Base *, custom_sched);
|
Scheduler::Base *sched = r_cst(Scheduler::Base *, custom_sched);
|
||||||
__sched_ctx = custom_sched;
|
__sched_ctx = custom_sched;
|
||||||
Scheduler = sched;
|
Scheduler = sched;
|
||||||
|
|
||||||
KernelProcess = CreateProcess(nullptr, "Kernel",
|
KernelProcess = CreateProcess(nullptr, "Kernel", Kernel, true, 0, 0);
|
||||||
TaskExecutionMode::Kernel, true);
|
TCB *kthrd = CreateThread(KernelProcess, EntryPoint, nullptr, nullptr, {}, GetKArch());
|
||||||
KernelProcess->PageTable = KernelPageTable;
|
|
||||||
TCB *kthrd = CreateThread(KernelProcess, EntryPoint,
|
|
||||||
nullptr, nullptr,
|
|
||||||
std::vector<AuxiliaryVector>(), GetKArch());
|
|
||||||
kthrd->Rename("Main Thread");
|
kthrd->Rename("Main Thread");
|
||||||
debug("Created Kernel Process: %s and Thread: %s",
|
debug("Created Kernel Process: %s and Thread: %s", KernelProcess->Name, kthrd->Name);
|
||||||
KernelProcess->Name, kthrd->Name);
|
|
||||||
|
|
||||||
if (!CPU::Interrupts(CPU::Check))
|
if (!CPU::Interrupts(CPU::Check))
|
||||||
{
|
{
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include <task.hpp>
|
#include <task.hpp>
|
||||||
|
|
||||||
#include <filesystem/ioctl.hpp>
|
#include <fs/ioctl.hpp>
|
||||||
#include <dumper.hpp>
|
#include <dumper.hpp>
|
||||||
#include <convert.h>
|
#include <convert.h>
|
||||||
#include <lock.hpp>
|
#include <lock.hpp>
|
||||||
|
@ -18,11 +18,11 @@
|
|||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
#include <filesystem/ioctl.hpp>
|
#include <fs/ioctl.hpp>
|
||||||
#include <interface/syscalls.h>
|
#include <interface/syscalls.h>
|
||||||
#include <memory/macro.hpp>
|
#include <memory/macro.hpp>
|
||||||
#include <memory/vma.hpp>
|
#include <memory/vma.hpp>
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <debug.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
|
#ifdef DEBUG
|
||||||
|
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
#include <filesystem.hpp>
|
#include <fs/vfs.hpp>
|
||||||
|
|
||||||
void Test_stl();
|
void Test_stl();
|
||||||
void TestMemoryAllocation();
|
void TestMemoryAllocation();
|
||||||
void tasking_test_fb();
|
void tasking_test_fb();
|
||||||
void tasking_test_mutex();
|
void tasking_test_mutex();
|
||||||
void TaskMgr();
|
void TaskMgr();
|
||||||
void TreeFS(FileNode *node, int Depth);
|
void TreeFS(Node node, int Depth);
|
||||||
void TaskHeartbeat();
|
void TaskHeartbeat();
|
||||||
void StressKernel();
|
void StressKernel();
|
||||||
void coroutineTest();
|
void coroutineTest();
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
#include "../kernel.h"
|
#include "../kernel.h"
|
||||||
|
|
||||||
void TreeFS(FileNode *node, int Depth)
|
void TreeFS(Node node, int Depth)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
// for (auto Chld : node->GetChildren(true))
|
// for (auto Chld : node->GetChildren(true))
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <tty.hpp>
|
#include <tty.hpp>
|
||||||
#include <filesystem/ioctl.hpp>
|
#include <fs/ioctl.hpp>
|
||||||
#include <smp.hpp>
|
#include <smp.hpp>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include <kcon.hpp>
|
#include <kcon.hpp>
|
||||||
|
|
||||||
#include <filesystem/ioctl.hpp>
|
#include <fs/ioctl.hpp>
|
||||||
#include <memory.hpp>
|
#include <memory.hpp>
|
||||||
#include <stropts.h>
|
#include <stropts.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user