Partially fixed logic in the file system class with changes to support fs table structure instead of a tree
This commit is contained in:
@@ -15,6 +15,12 @@ export type BashInitArgs = {
|
||||
fs: any;
|
||||
};
|
||||
|
||||
export type TimeStamps = {
|
||||
mTime: Date;
|
||||
cTime: Date;
|
||||
aTime: Date;
|
||||
}
|
||||
|
||||
// TODO: Finish this
|
||||
// TODO: Change into a type instead of an enum for performance (low priority)
|
||||
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
|
||||
home: string; //TODO: Make a formated type
|
||||
history: string[];
|
||||
cwd?: string[]; //TODO: Make a formated type
|
||||
pwd?: string[]; //TODO: Make a formated type
|
||||
cwd?: number; //TODO: Make a formated type
|
||||
pwd?: number; //TODO: Make a formated type
|
||||
};
|
||||
|
||||
export type Group = {
|
||||
@@ -69,11 +75,11 @@ export class Bash {
|
||||
}
|
||||
}
|
||||
|
||||
getCwd(): string[] {
|
||||
getCwd(): number {
|
||||
return this.vfs.cwd;
|
||||
}
|
||||
|
||||
getPwd(): string[] {
|
||||
getPwd(): number {
|
||||
return this.vfs.pwd;
|
||||
}
|
||||
|
||||
@@ -89,13 +95,6 @@ export class Bash {
|
||||
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 {
|
||||
let result: Result = { exitCode: ExitCode.ERROR };
|
||||
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() {
|
||||
this._instances.pop();
|
||||
if (this._instances.size() === 0) {
|
||||
//TODO: Implement system logout
|
||||
} else {
|
||||
this.changeUser(this._instances.peek()!);
|
||||
//this.changeUser(this._instances.peek()!);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
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 {
|
||||
Directory = 16384,
|
||||
File = 32768
|
||||
File = 32768,
|
||||
SymblicLink = 40960
|
||||
}
|
||||
|
||||
export type NodePerms = {
|
||||
@@ -18,118 +21,132 @@ export type FsInitArgs = {
|
||||
};
|
||||
|
||||
export type TreeNode = {
|
||||
inode: number;
|
||||
parent?: number;
|
||||
name: string;
|
||||
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;
|
||||
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 {
|
||||
private root: TreeNode; // TODO make this the correct type
|
||||
private FsTable: Map<number, TreeNode>;
|
||||
private rootINode: number;
|
||||
|
||||
home: string[];
|
||||
cwd: string[];
|
||||
pwd: string[];
|
||||
home: number;
|
||||
cwd: number;
|
||||
pwd: number;
|
||||
|
||||
constructor(args: FsInitArgs) {
|
||||
this.root = args.fs;
|
||||
this.home = this._splitPathString(args.user.home);
|
||||
this.FsTable = args.fs;
|
||||
this.rootINode = 1;
|
||||
this.home = this._pathStringToINode(args.user.home);
|
||||
this.cwd = args.user.cwd ? args.user.cwd : this.home;
|
||||
this.pwd = args.user.pwd ? args.user.pwd : this.cwd;
|
||||
|
||||
console.log(this.home);
|
||||
console.log(this.cwd);
|
||||
console.log(this.pwd);
|
||||
|
||||
console.log('VFS INIT ', this._getNodeByPathArray(['/', 'home', 'kamil']));
|
||||
}
|
||||
|
||||
_splitPathString(path: string): string[] {
|
||||
if (path === '/') return ['/'];
|
||||
private _iNodeToPathString(inode: number): string {
|
||||
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('/');
|
||||
const parts: string[] = [];
|
||||
components.push(currentNode.name);
|
||||
|
||||
for (let i = 0; i < raw.length; i++) {
|
||||
if (raw[i].length > 0) parts.push(raw[i]);
|
||||
if(!currentNode.parent) {
|
||||
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('/');
|
||||
};
|
||||
|
||||
pathArrayToString(path: string[]): string {
|
||||
if (path.length === 1 && path[0] === '/') return '/';
|
||||
return '/' + path.join('/');
|
||||
}
|
||||
|
||||
formatPath(path: string): string {
|
||||
const prefix = this.pathArrayToString(this.home);
|
||||
const prefix = this._iNodeToPathString(this.home);
|
||||
if (path.startsWith(prefix)) {
|
||||
return path.replace(prefix, '~');
|
||||
} else return path;
|
||||
}
|
||||
|
||||
resolvePath(path: string): string[] {
|
||||
if (path === '' || path === undefined || path === null) return this.cwd.slice();
|
||||
if (path.startsWith('/') && path.length === 1) return [];
|
||||
resolvePath(path: string): TreeNode{
|
||||
if(path === '/') return this._getNodeByINode(this.rootINode);
|
||||
|
||||
if (path.startsWith('~')) {
|
||||
const trail: string = path === '~' ? '' : path.slice(1);
|
||||
const home: string = this.pathArrayToString(this.home);
|
||||
path = home + (trail ? (trail.startsWith('/') ? '' : '/') + trail : '');
|
||||
if (!this._isAbsolutePath(path)) {
|
||||
const trail: string = this._iNodeToPathString(this.cwd);
|
||||
path = trail + path;
|
||||
|
||||
}
|
||||
else if (path.startsWith('~')) {
|
||||
const trail: string = this._iNodeToPathString(this.home);
|
||||
path = trail + path
|
||||
}
|
||||
|
||||
const start = this._isAbsolutePath(path) ? [] : this.cwd.slice();
|
||||
const parts = this._splitPathString(path);
|
||||
console.log(path);
|
||||
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
const seg = parts[i];
|
||||
const INode: number = this._pathStringToINode(path);
|
||||
const Node: TreeNode = this._getNodeByINode(INode);
|
||||
|
||||
if (seg === '.' || seg === '') continue;
|
||||
if (seg === '..') {
|
||||
if (start.length > 1) start.pop();
|
||||
continue;
|
||||
}
|
||||
start.push(seg);
|
||||
}
|
||||
|
||||
if (start.length === 0) return [];
|
||||
console.log('OUTPUT', start);
|
||||
return start;
|
||||
return Node;
|
||||
}
|
||||
|
||||
_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;
|
||||
}
|
||||
|
||||
_getPathToNode(node: TreeNode): string[] {
|
||||
private _getPathToNode(node: TreeNode): string[] {
|
||||
const path: string[] = [];
|
||||
let current = node;
|
||||
path.push(node.name);
|
||||
|
||||
@@ -8,44 +8,52 @@ export function isInitializing(): boolean {
|
||||
return initializing;
|
||||
}
|
||||
|
||||
function jsonToTreeNode(data: any, parent?: TreeNode): TreeNode {
|
||||
const node: TreeNode = {
|
||||
name: data.Name,
|
||||
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
|
||||
};
|
||||
function jsonToNodeTable(data: any, parent?: number): Map<number, TreeNode> {
|
||||
const FsTable: Map<number, TreeNode> = new Map<number, TreeNode>;
|
||||
const keyList = Object.keys(data);
|
||||
|
||||
node.children = data.Children
|
||||
? data.Children.map((child: any) => jsonToTreeNode(child, node))
|
||||
: [];
|
||||
for(const key in keyList) {
|
||||
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> {
|
||||
@@ -95,7 +103,7 @@ export async function initTerminal(user: User, callbackInit: any): Promise<Termi
|
||||
try {
|
||||
const sig = await fetchFsSignature('/src/lib/assets/fs/signature');
|
||||
const fsJson = await fetchFsJson(sig);
|
||||
const fs: TreeNode = jsonToTreeNode(fsJson);
|
||||
const fs: Map<number, TreeNode> = jsonToNodeTable(fsJson);
|
||||
|
||||
const args: TermInitArgs = {
|
||||
bash: {
|
||||
|
||||
Reference in New Issue
Block a user