Implement sysfs

This commit is contained in:
2025-12-03 20:41:52 +01:00
parent 19e034a982
commit e4b18fc8d7
6 changed files with 298 additions and 0 deletions

View File

@@ -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;
}
}

View File

@@ -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");
}
}

View File

@@ -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;
}
}

View File

@@ -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"));
}

View File

@@ -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<string, FileSystem> = 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);
}
}

View File

@@ -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("/");
}
}