From e4b18fc8d71e8f2fc717bc2eba42c007e9f3db3b Mon Sep 17 00:00:00 2001 From: Martin Petr Date: Wed, 3 Dec 2025 20:41:52 +0100 Subject: [PATCH] Implement sysfs --- src/system/src/kernel/filesystem/fs/entity.ts | 51 +++++++++++ src/system/src/kernel/filesystem/fs/fs.ts | 61 +++++++++++++ src/system/src/kernel/filesystem/sys.fs.ts | 75 ++++++++++++++++ src/system/src/kernel/index.ts | 9 ++ src/system/src/kernel/modules/vfs/vfs.kmod.ts | 89 +++++++++++++++++++ src/system/src/lib/path.ts | 13 +++ 6 files changed, 298 insertions(+) create mode 100644 src/system/src/kernel/filesystem/fs/entity.ts create mode 100644 src/system/src/kernel/filesystem/fs/fs.ts create mode 100644 src/system/src/kernel/filesystem/sys.fs.ts create mode 100644 src/system/src/kernel/modules/vfs/vfs.kmod.ts create mode 100644 src/system/src/lib/path.ts diff --git a/src/system/src/kernel/filesystem/fs/entity.ts b/src/system/src/kernel/filesystem/fs/entity.ts new file mode 100644 index 0000000..c6d79ff --- /dev/null +++ b/src/system/src/kernel/filesystem/fs/entity.ts @@ -0,0 +1,51 @@ +export class FSEntity { + #name: string; + #path: string; + #size: number; + #type: "d" | "f"; + #content: string | string[] | FSEntity[]; + + constructor( + name: string, + path: string, + size: number, + type: "d" | "f", + content: string | string[] | FSEntity[] + ) { + this.#name = name; + this.#path = path; + this.#size = size; + this.#type = type; + this.#content = content; + } + + get name() { + return this.#name; + } + + get path() { + return this.#path; + } + + get size() { + return this.#size; + } + + get type() { + return this.#type; + } + + get content() { + return this.#content; + } + + set content(content: string | string[] | FSEntity[]) { + this.#content = content; + this.#size = + this.#type == "d" + ? 0 + : content instanceof Array + ? this.#content.length + : this.#content.length; + } +} diff --git a/src/system/src/kernel/filesystem/fs/fs.ts b/src/system/src/kernel/filesystem/fs/fs.ts new file mode 100644 index 0000000..99017bd --- /dev/null +++ b/src/system/src/kernel/filesystem/fs/fs.ts @@ -0,0 +1,61 @@ +import { Logger } from "../../../lib/logger"; +import { FSEntity } from "./entity"; + +export class FileSystem { + #id: string; + #root: FSEntity; + + constructor(id: string) { + this.#id = id; + + this.#root = new FSEntity("", "/", 0, "d", []); + } + + get id() { + return this.#id; + } + + protected getEntity(path: string) { + if (path === "/") return this.#root; + + const parts = path.split("/"); + let entity = this.#root; + + for (let i = 1; i < parts.length; i++) { + if (!entity.content || entity.content.length === 0) return null; + if (entity.type !== "d") return null; + + entity = (entity.content as FSEntity[]).find((e) => e.name === parts[i])!; + } + + return entity; + } + + mkdir(path: string) { + throw new Error("FS::Mkdir Not implemented"); + } + + ls(path: string) { + throw new Error("FS::Ls Not implemented"); + } + + readFile(path: string) { + throw new Error("FS::ReadFile Not implemented"); + } + + writeFile(path: string, content: string) { + throw new Error("FS::WriteFile Not implemented"); + } + + createFile(path: string) { + throw new Error("FS::CreateFile Not implemented"); + } + + remove(path: string) { + throw new Error("FS::Remove Not implemented"); + } + + stat(path: string) { + throw new Error("FS::Stat Not implemented"); + } +} diff --git a/src/system/src/kernel/filesystem/sys.fs.ts b/src/system/src/kernel/filesystem/sys.fs.ts new file mode 100644 index 0000000..91cc08d --- /dev/null +++ b/src/system/src/kernel/filesystem/sys.fs.ts @@ -0,0 +1,75 @@ +import { Logger } from "../../lib/logger"; +import { Path } from "../../lib/path"; +import { FSEntity } from "./fs/entity"; +import { FileSystem } from "./fs/fs"; + +export class SysFS extends FileSystem { + static instance: SysFS = new this(); + + constructor() { + super("sysfs"); + } + + override mkdir(path: string): void { + throw new Error("SysFS::Mkdir sysfs is read-only"); + } + + public pMkdir(path: string): void { + const parent = this.getEntity(Path.dirname(path)); + if (!parent || parent.type !== "d") return; + + (parent.content as FSEntity[]).push( + new FSEntity(Path.filename(path), path, 0, "d", []) + ); + } + + public pWriteFile(path: string, content: string): void { + const parent = this.getEntity(Path.dirname(path)); + if (!parent || parent.type !== "d") return; + + const existing = (parent.content as FSEntity[]).find( + (e) => e.name === Path.filename(path) + ); + if (existing) { + existing.content = content; + return; + } + + (parent.content as FSEntity[]).push( + new FSEntity(Path.filename(path), path, content.length, "f", content) + ); + } + + override ls(path: string): FSEntity[] { + const entity = this.getEntity(path); + if (!entity || entity.type !== "d") return []; + + return entity.content as FSEntity[]; + } + + override createFile(path: string): void { + throw new Error("SysFS::CreateFile sysfs is read-only"); + } + + override writeFile(path: string, content: string): void { + throw new Error("SysFS::WriteFile sysfs is read-only"); + } + + override readFile(path: string): string { + const entity = this.getEntity(path); + if (!entity || entity.type !== "f") return ""; + + return entity.content as string; + } + + override remove(path: string): void { + throw new Error("SysFS::Remove sysfs is read-only"); + } + + override stat(path: string): FSEntity | null { + const entity = this.getEntity(path); + if (!entity) return null; + + return entity; + } +} diff --git a/src/system/src/kernel/index.ts b/src/system/src/kernel/index.ts index 2b83bb2..6bef37b 100644 --- a/src/system/src/kernel/index.ts +++ b/src/system/src/kernel/index.ts @@ -1,9 +1,18 @@ import { Logger } from "../lib/logger"; +import { SysFS } from "./filesystem/sys.fs"; import { ConsoleKModule } from "./modules/console/console.kmod"; +import { VFSKModule } from "./modules/vfs/vfs.kmod"; export function KMain() { Logger.clear(); Logger.log("[Kernel] Initializing kernel..."); ConsoleKModule.init(); + VFSKModule.init(); + VFSKModule.instance.mount(SysFS.instance, "/sys"); + + SysFS.instance.pMkdir("/pci"); + SysFS.instance.pWriteFile("/pci/test", "test"); + + Logger.log(SysFS.instance.readFile("/pci/test")); } diff --git a/src/system/src/kernel/modules/vfs/vfs.kmod.ts b/src/system/src/kernel/modules/vfs/vfs.kmod.ts new file mode 100644 index 0000000..969b19c --- /dev/null +++ b/src/system/src/kernel/modules/vfs/vfs.kmod.ts @@ -0,0 +1,89 @@ +import { Logger } from "../../../lib/logger"; +import type { FileSystem } from "../../filesystem/fs/fs"; +import { KernelModule } from "../kmod"; + +export class VFSKModule extends KernelModule { + static instance: VFSKModule = new this(); + + #mounts: Map = new Map(); + + constructor() { + super("vfs"); + } + + static init() { + VFSKModule.instance.init(); + } + + mount(fs: FileSystem, mountPoint: string) { + if (!this.initialized) return; + + Logger.log(`Mounting ${fs.id} at ${mountPoint}`); + this.#mounts.set(mountPoint, fs); + } + + #resolveMount(path: string) { + const parts = path.split("/"); + + for (let i = 0; i < parts.length; i++) { + const mountPoint = parts.slice(0, i + 1).join("/"); + + if (this.#mounts.has(mountPoint)) + return { + fs: this.#mounts.get(mountPoint)!, + path: parts.slice(i + 1).join("/"), + }; + } + + return null; + } + + mkdir(path: string) { + const mount = this.#resolveMount(path); + if (!mount) return; + + mount.fs.mkdir(mount.path); + } + + ls(path: string) { + const mount = this.#resolveMount(path); + if (!mount) return; + + return mount.fs.ls(mount.path); + } + + createFile(path: string) { + const mount = this.#resolveMount(path); + if (!mount) return; + + mount.fs.createFile(mount.path); + } + + writeFile(path: string, content: string) { + const mount = this.#resolveMount(path); + if (!mount) return; + + mount.fs.writeFile(mount.path, content); + } + + readFile(path: string) { + const mount = this.#resolveMount(path); + if (!mount) return; + + return mount.fs.readFile(mount.path); + } + + remove(path: string) { + const mount = this.#resolveMount(path); + if (!mount) return; + + mount.fs.remove(mount.path); + } + + stat(path: string) { + const mount = this.#resolveMount(path); + if (!mount) return; + + return mount.fs.stat(mount.path); + } +} diff --git a/src/system/src/lib/path.ts b/src/system/src/lib/path.ts new file mode 100644 index 0000000..8412f92 --- /dev/null +++ b/src/system/src/lib/path.ts @@ -0,0 +1,13 @@ +export class Path { + static dirname(path: string) { + return path.split("/").slice(0, -1).join("/"); + } + + static filename(path: string) { + return path.split("/").pop()!; + } + + static join(...paths: string[]) { + return paths.join("/"); + } +}