Implement sysfs
This commit is contained in:
51
src/system/src/kernel/filesystem/fs/entity.ts
Normal file
51
src/system/src/kernel/filesystem/fs/entity.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
61
src/system/src/kernel/filesystem/fs/fs.ts
Normal file
61
src/system/src/kernel/filesystem/fs/fs.ts
Normal 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");
|
||||
}
|
||||
}
|
||||
75
src/system/src/kernel/filesystem/sys.fs.ts
Normal file
75
src/system/src/kernel/filesystem/sys.fs.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
89
src/system/src/kernel/modules/vfs/vfs.kmod.ts
Normal file
89
src/system/src/kernel/modules/vfs/vfs.kmod.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
13
src/system/src/lib/path.ts
Normal file
13
src/system/src/lib/path.ts
Normal 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("/");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user