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 { Logger } from "../lib/logger";
|
||||||
|
import { SysFS } from "./filesystem/sys.fs";
|
||||||
import { ConsoleKModule } from "./modules/console/console.kmod";
|
import { ConsoleKModule } from "./modules/console/console.kmod";
|
||||||
|
import { VFSKModule } from "./modules/vfs/vfs.kmod";
|
||||||
|
|
||||||
export function KMain() {
|
export function KMain() {
|
||||||
Logger.clear();
|
Logger.clear();
|
||||||
Logger.log("[Kernel] Initializing kernel...");
|
Logger.log("[Kernel] Initializing kernel...");
|
||||||
|
|
||||||
ConsoleKModule.init();
|
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