Partially fixed logic in the file system class with changes to support fs table structure instead of a tree

This commit is contained in:
2025-12-02 04:02:19 +01:00
parent 85d98a41c1
commit 8e0ae3dd83
3 changed files with 145 additions and 132 deletions

View File

@@ -15,6 +15,12 @@ export type BashInitArgs = {
fs: any; fs: any;
}; };
export type TimeStamps = {
mTime: Date;
cTime: Date;
aTime: Date;
}
// TODO: Finish this // TODO: Finish this
// TODO: Change into a type instead of an enum for performance (low priority) // TODO: Change into a type instead of an enum for performance (low priority)
export enum ExitCode { export enum ExitCode {
@@ -29,8 +35,8 @@ export type User = {
readonly gid: number; // Primary group | 'Users' 1000 - Others - 1000+ root - 0 //TODO: Make a formated type readonly gid: number; // Primary group | 'Users' 1000 - Others - 1000+ root - 0 //TODO: Make a formated type
home: string; //TODO: Make a formated type home: string; //TODO: Make a formated type
history: string[]; history: string[];
cwd?: string[]; //TODO: Make a formated type cwd?: number; //TODO: Make a formated type
pwd?: string[]; //TODO: Make a formated type pwd?: number; //TODO: Make a formated type
}; };
export type Group = { export type Group = {
@@ -69,11 +75,11 @@ export class Bash {
} }
} }
getCwd(): string[] { getCwd(): number {
return this.vfs.cwd; return this.vfs.cwd;
} }
getPwd(): string[] { getPwd(): number {
return this.vfs.pwd; return this.vfs.pwd;
} }
@@ -89,13 +95,6 @@ export class Bash {
return this._group[1].members.includes(uid); return this._group[1].members.includes(uid);
} }
changeUser(user: User) {
this.user = user;
this.vfs.home = this.vfs._splitPathString(user.home);
this.vfs.cwd = user.cwd ? user.cwd : this.vfs._splitPathString(user.home);
this.vfs.pwd = user.pwd ? user.pwd : this.vfs._splitPathString(user.home);
}
executeCommand(commandName: string, args: CommandArgs): void { executeCommand(commandName: string, args: CommandArgs): void {
let result: Result = { exitCode: ExitCode.ERROR }; let result: Result = { exitCode: ExitCode.ERROR };
const command = this._commands[commandName]; const command = this._commands[commandName];
@@ -121,23 +120,12 @@ export class Bash {
} }
} }
userLogin(username: string, passwd: string): ExitCode {
const user: User | undefined = this._passwd.find((u) => u.username === username);
if (user === undefined) return ExitCode.ERROR;
if (user.passwd === passwd) {
this._instances.push(user);
this.changeUser(user);
return ExitCode.ERROR; //TODO: Make it return the exitcode of changeUser() if needed
} else return ExitCode.ERROR;
}
userLogout() { userLogout() {
this._instances.pop(); this._instances.pop();
if (this._instances.size() === 0) { if (this._instances.size() === 0) {
//TODO: Implement system logout //TODO: Implement system logout
} else { } else {
this.changeUser(this._instances.peek()!); //this.changeUser(this._instances.peek()!);
} }
} }

View File

@@ -1,9 +1,12 @@
import type { readonly } from 'svelte/store'; import type { readonly } from 'svelte/store';
import type { Permission, User } from './bash'; import type { Permission, TimeStamps, User } from './bash';
import { Stack } from '../stack';
import { Pause } from '@lucide/svelte';
export enum Type { export enum Type {
Directory = 16384, Directory = 16384,
File = 32768 File = 32768,
SymblicLink = 40960
} }
export type NodePerms = { export type NodePerms = {
@@ -18,118 +21,132 @@ export type FsInitArgs = {
}; };
export type TreeNode = { export type TreeNode = {
inode: number;
parent?: number;
name: string; name: string;
type: Type; type: Type;
readonly: boolean; children: number[];
content: string; // GUID of the cache file that contains the file contents.
link: number; // Links
permission: NodePerms;
owner: number;
group: number;
timestamps: TimeStamps;
interactible: boolean; interactible: boolean;
func: any; func: any;
children: TreeNode[];
content: string; // Path to the content of the file
link: string[]; // Symlink
permission: NodePerms;
owner: string;
group: string;
modtime: Date;
parent?: TreeNode;
}; };
export class VirtualFS { export class VirtualFS {
private root: TreeNode; // TODO make this the correct type private FsTable: Map<number, TreeNode>;
private rootINode: number;
home: string[]; home: number;
cwd: string[]; cwd: number;
pwd: string[]; pwd: number;
constructor(args: FsInitArgs) { constructor(args: FsInitArgs) {
this.root = args.fs; this.FsTable = args.fs;
this.home = this._splitPathString(args.user.home); this.rootINode = 1;
this.home = this._pathStringToINode(args.user.home);
this.cwd = args.user.cwd ? args.user.cwd : this.home; this.cwd = args.user.cwd ? args.user.cwd : this.home;
this.pwd = args.user.pwd ? args.user.pwd : this.cwd; this.pwd = args.user.pwd ? args.user.pwd : this.cwd;
console.log(this.home); console.log(this.home);
console.log(this.cwd); console.log(this.cwd);
console.log(this.pwd); console.log(this.pwd);
console.log('VFS INIT ', this._getNodeByPathArray(['/', 'home', 'kamil']));
} }
_splitPathString(path: string): string[] { private _iNodeToPathString(inode: number): string {
if (path === '/') return ['/']; let components: Stack<string> = new Stack<string>();
let currentNode = this.FsTable.get(inode);
let path: string = '';
if(!currentNode) throw new Error('iNode does not exist,');
const raw: string[] = path.split('/'); components.push(currentNode.name);
const parts: string[] = [];
for (let i = 0; i < raw.length; i++) { if(!currentNode.parent) {
if (raw[i].length > 0) parts.push(raw[i]); for(let i = 0; i < components.size(); i++) {
path += components.pop() + '/';
}
} else {
this._iNodeToPathString(currentNode.parent);
} }
return parts;
return path;
} }
_isAbsolutePath = (path: string): boolean => { private _pathStringToINode(path: string): number {
const normalizedPath = path.replace(/^\/+|\/+$/g, '');
const pathComponents = normalizedPath.split('/').filter(component => component.length > 0);
if(pathComponents.length === 0) return this.rootINode;
let currentNode = this.FsTable.get(this.rootINode);
if(!currentNode) throw new Error('iNode does not exist,');
for(const component of pathComponents) {
const childINode = this._findChildNodeByName(currentNode, component);
if(childINode === null) throw new Error('this child iNode does not exist,');
const nextNode = this.FsTable.get(childINode);
if(!nextNode) throw new Error('iNode child does not exist,');
currentNode = nextNode;
}
return currentNode.inode;
}
private _findChildNodeByName(node: TreeNode, name: string): number {
for(const childINode of node.children) {
const child = this.FsTable.get(childINode);
if(child && child.name === name) {
return childINode;
}
}
throw new Error('could not find the specified child node');
}
private _isAbsolutePath = (path: string): boolean => {
return typeof path === 'string' && path.startsWith('/'); return typeof path === 'string' && path.startsWith('/');
}; };
pathArrayToString(path: string[]): string {
if (path.length === 1 && path[0] === '/') return '/';
return '/' + path.join('/');
}
formatPath(path: string): string { formatPath(path: string): string {
const prefix = this.pathArrayToString(this.home); const prefix = this._iNodeToPathString(this.home);
if (path.startsWith(prefix)) { if (path.startsWith(prefix)) {
return path.replace(prefix, '~'); return path.replace(prefix, '~');
} else return path; } else return path;
} }
resolvePath(path: string): string[] { resolvePath(path: string): TreeNode{
if (path === '' || path === undefined || path === null) return this.cwd.slice(); if(path === '/') return this._getNodeByINode(this.rootINode);
if (path.startsWith('/') && path.length === 1) return [];
if (path.startsWith('~')) { if (!this._isAbsolutePath(path)) {
const trail: string = path === '~' ? '' : path.slice(1); const trail: string = this._iNodeToPathString(this.cwd);
const home: string = this.pathArrayToString(this.home); path = trail + path;
path = home + (trail ? (trail.startsWith('/') ? '' : '/') + trail : '');
}
else if (path.startsWith('~')) {
const trail: string = this._iNodeToPathString(this.home);
path = trail + path
} }
const start = this._isAbsolutePath(path) ? [] : this.cwd.slice(); console.log(path);
const parts = this._splitPathString(path);
for (let i = 0; i < parts.length; i++) { const INode: number = this._pathStringToINode(path);
const seg = parts[i]; const Node: TreeNode = this._getNodeByINode(INode);
if (seg === '.' || seg === '') continue; return Node;
if (seg === '..') {
if (start.length > 1) start.pop();
continue;
}
start.push(seg);
}
if (start.length === 0) return [];
console.log('OUTPUT', start);
return start;
} }
_getNodeByPathArray(path: string[]): TreeNode | null {
if (path.length === 1 && path[0] === '/') return this.root;
let node: TreeNode = this.root;
const parts: string[] = path.slice(path[0] === '/' ? 1 : 0);
for (let i = 0; i < parts.length; i++) {
const seg: string = parts[i];
if (node.type === Type.File) return node;
const newNode = node.children.find((child) => child.name === seg);
console.log(newNode);
if (newNode !== undefined) node = newNode;
else return null;
}
private _getNodeByINode(inode: number): TreeNode {
const node: TreeNode | undefined = this.FsTable.get(inode);
if(!node) throw new Error('Could not get the node, no such i node exists');
return node; return node;
} }
_getPathToNode(node: TreeNode): string[] { private _getPathToNode(node: TreeNode): string[] {
const path: string[] = []; const path: string[] = [];
let current = node; let current = node;
path.push(node.name); path.push(node.name);

View File

@@ -8,44 +8,52 @@ export function isInitializing(): boolean {
return initializing; return initializing;
} }
function jsonToTreeNode(data: any, parent?: TreeNode): TreeNode { function jsonToNodeTable(data: any, parent?: number): Map<number, TreeNode> {
const node: TreeNode = { const FsTable: Map<number, TreeNode> = new Map<number, TreeNode>;
name: data.Name, const keyList = Object.keys(data);
type: data.Type,
readonly: data.ReadOnly,
interactible: data.Interactible,
func: data.Func,
children: [],
content: data.Content,
link: data.Link || [],
permission: {
user: {
r: data.Permission[0]?.Read,
w: data.Permission[0]?.Write,
x: data.Permission[0]?.Exec
},
group: {
r: data.Permission[1]?.Read,
w: data.Permission[1]?.Write,
x: data.Permission[1]?.Exec
},
other: {
r: data.Permission[2]?.Read,
w: data.Permission[2]?.Write,
x: data.Permission[2]?.Exec
}
},
owner: data.Owner,
group: data.Group,
modtime: new Date(data.Mtime),
parent: parent
};
node.children = data.Children for(const key in keyList) {
? data.Children.map((child: any) => jsonToTreeNode(child, node)) const object = data[key];
: []; const node: TreeNode = {
inode: object.Inode,
name: object.Name,
type: object.Type,
interactible: object.Interactible,
func: object.Func,
children: [],
content: object.Content,
link: object.Link || [],
permission: {
user: {
r: object.Permission[0]?.Read,
w: object.Permission[0]?.Write,
x: object.Permission[0]?.Exec
},
group: {
r: object.Permission[1]?.Read,
w: object.Permission[1]?.Write,
x: object.Permission[1]?.Exec
},
other: {
r: object.Permission[2]?.Read,
w: object.Permission[2]?.Write,
x: object.Permission[2]?.Exec
}
},
owner: object.Owner,
group: object.Group,
timestamps: {
mTime: new Date(object.TimeStamps.MTime),
cTime: new Date(object.TimeStamps.CTime),
aTime: new Date(object.TimeStamps.ATime)
},
parent: object.parent
};
return node; FsTable.set(object.Inode, node);
}
console.log(FsTable);
return FsTable;
} }
async function fetchFsJson(sig: string): Promise<any> { async function fetchFsJson(sig: string): Promise<any> {
@@ -95,7 +103,7 @@ export async function initTerminal(user: User, callbackInit: any): Promise<Termi
try { try {
const sig = await fetchFsSignature('/src/lib/assets/fs/signature'); const sig = await fetchFsSignature('/src/lib/assets/fs/signature');
const fsJson = await fetchFsJson(sig); const fsJson = await fetchFsJson(sig);
const fs: TreeNode = jsonToTreeNode(fsJson); const fs: Map<number, TreeNode> = jsonToNodeTable(fsJson);
const args: TermInitArgs = { const args: TermInitArgs = {
bash: { bash: {