From cd1e11f0baad1fa5cedbd780d69939fc11f4504c Mon Sep 17 00:00:00 2001 From: ProgrammerIn-wonderland <3838shah@gmail.com> Date: Thu, 19 Sep 2024 12:22:48 -0400 Subject: [PATCH] some work on localFS --- src/api/Filesystem.ts | 3 +- src/api/LocalFS.ts | 148 +++++++++++++++++++++++++++++++++--------- 2 files changed, 118 insertions(+), 33 deletions(-) diff --git a/src/api/Filesystem.ts b/src/api/Filesystem.ts index 12a8b2da..dfd9eeaf 100644 --- a/src/api/Filesystem.ts +++ b/src/api/Filesystem.ts @@ -3,6 +3,7 @@ const AnuraFDSymbol = Symbol.for("AnuraFD"); type AnuraFD = { fd: number; [AnuraFDSymbol]: string; + path?: string; }; abstract class AnuraFSOperations { @@ -989,7 +990,7 @@ class AnuraFilesystem implements AnuraFSOperations { if (!path.startsWith("/")) { throw new Error("Path must be absolute"); } - path = path.replace(/^\/+/, "/"); + path = path.replace(/\/\//g, "/"); let provider = this.providerCache[path]; if (provider) { diff --git a/src/api/LocalFS.ts b/src/api/LocalFS.ts index 6cd1a435..6a014652 100644 --- a/src/api/LocalFS.ts +++ b/src/api/LocalFS.ts @@ -47,6 +47,7 @@ class LocalFSStats { } class LocalFS extends AFSProvider { + stats: any; dirHandle: FileSystemDirectoryHandle; domain: string; name = "LocalFS"; @@ -89,6 +90,20 @@ class LocalFS extends AFSProvider { } const fs = new LocalFS(dirHandle, anuraPath); anura.fs.installProvider(fs); + try { + fs.stats = JSON.parse( + new TextDecoder().decode( + await fs.promises.readFile( + anuraPath + "/.anura-fs-stats.json", + ), + ), + ); + } catch (e) { + anura.fs.promises.writeFile( + anuraPath + "/.anura-fs-stats.json", + "{}", + ); + } return fs; } static async new(anuraPath: string) { @@ -281,7 +296,8 @@ class LocalFS extends AFSProvider { ); const nodes: string[] = []; for await (const entry of dirHandle.values()) { - nodes.push(entry.name); + if (entry.name !== ".anura-fs-stats.json") + nodes.push(entry.name); } return nodes; }, @@ -346,11 +362,14 @@ class LocalFS extends AFSProvider { } catch (e) { try { const handle = await this.getChildDirHandle(path); - return new LocalFSStats({ - name: handle.name, - mode: 0o40777, - type: "DIRECTORY", - }); + let fstats: any = {}; + if (this.stats[path]) { + fstats = this.stats[path]; + } + fstats.name ||= handle.name; + fstats.mode ||= 0o40777; + fstats.type ||= "DIRECTORY"; + return new LocalFSStats(fstats); } catch (e) { throw { name: "ENOENT", @@ -362,27 +381,52 @@ class LocalFS extends AFSProvider { }; } } + let fstats: any = {}; + if (this.stats[path]) { + fstats = this.stats[path]; + } const file = await handle.getFile(); - return new LocalFSStats({ - name: file.name, - size: file.size, - }); + fstats.name ||= file.name; + fstats.size ||= file.size; + + return new LocalFSStats(fstats); }, truncate: async (path: string, len: number) => { const data = await this.promises.readFile(path); await this.promises.writeFile(path, data.slice(0, len)); }, - access: () => { - console.error("Not implemented: access"); - throw new Error("Not implemented"); + access: async (path: string) => { + await this.stat(path); }, - chown: () => { - console.error("Not implemented: chown"); - throw new Error("Not implemented"); + chown: async (path: string, uid: number, gid: number) => { + await this.promises.access(path); + path = this.relativizePath(path); + if (this.stats[path]) { + this.stats[path].uid = uid; + this.stats[path].gid = gid; + } else { + this.stats[path] = { uid: uid, gid: gid }; + } + await anura.fs.promises.writeFile( + this.domain + "/.anura-fs-stats.json", + JSON.stringify(this.stats), + ); }, - chmod: () => { - console.error("Not implemented: chmod"); - throw new Error("Not implemented"); + chmod: async (path: string, mode: number) => { + await this.promises.access(path); + path = this.relativizePath(path); + if (mode < 0o100000) mode += 0o100000; + if (this.stats[path]) { + this.stats[path].mode = mode; + } else { + this.stats[path] = { mode: mode }; + } + await anura.fs.promises.writeFile( + this.domain + "/.anura-fs-stats.json", + JSON.stringify(this.stats), + ); + // console.error("Not implemented: chmod"); + // throw new Error("Not implemented"); }, getxattr: () => { console.error("Not implemented: getxattr"); @@ -422,6 +466,7 @@ class LocalFS extends AFSProvider { this.fds.push(handle); return { fd: this.fds.length - 1, + path: path, //for internal stuff [AnuraFDSymbol]: this.domain, }; }, @@ -447,9 +492,35 @@ class LocalFS extends AFSProvider { }, }; - ftruncate() { - console.error("Not implemented: ftruncate"); - throw new Error("Method not implemented."); + ftruncate(fd: AnuraFD, ...rest: any[]) { + let cb = rest[2]; + const handle = this.fds[fd.fd]; + let len = 0; + if (!cb) { + len = rest[1]; + } else { + cb = rest[1]; + } + + if (handle === undefined) { + cb({ + name: "EBADF", + code: "EBADF", + errno: 9, + message: "bad file descriptor", + stack: "Error: bad file descriptor", + } as Error); + return; + } + + this.promises + .truncate(fd.path!, len) + .then(() => { + cb(); + }) + .catch((err) => { + cb(err); + }); } fstat(fd: AnuraFD, callback: (err: Error | null, stats: any) => void) { @@ -515,9 +586,18 @@ class LocalFS extends AFSProvider { throw new Error("Method not implemented."); } - access() { - console.error("Not implemented: access"); - throw new Error("Method not implemented."); + access(path: string, ...rest: any[]) { + let cb = (e: Error) => {}; + if (typeof rest[1] === "function") { + cb = rest[1]; + } + if (typeof rest[2] === "function") { + cb = rest[2]; + } + this.promises + .access(path) + .then(() => {}) + .catch((e) => cb(e)); } mkdtemp() { @@ -530,9 +610,12 @@ class LocalFS extends AFSProvider { throw new Error("Method not implemented."); } - chmod() { - console.error("Not implemented: chmod"); - throw new Error("Method not implemented."); + chmod(path: string, ...rest: any[]) { + const cb = rest[2]; + this.promises + .chmod(path, rest[1]) + .then(() => {}) + .catch((e) => cb(e)); } fchmod() { @@ -540,9 +623,9 @@ class LocalFS extends AFSProvider { throw new Error("Method not implemented."); } - fsync() { - console.error("Not implemented: fsync"); - throw new Error("Method not implemented."); + fsync(fd: AnuraFD, callback?: (err: Error | null) => void) { + // we're always sync + if (callback) callback(null); } write( @@ -600,7 +683,7 @@ class LocalFS extends AFSProvider { console.error("Not implemented: read"); throw new Error("Method not implemented."); } - + // From here to below are not in normal nodejs setxattr() { console.error("Not implemented: setxattr"); throw new Error("Method not implemented."); @@ -630,6 +713,7 @@ class LocalFS extends AFSProvider { console.error("Not implemented: fremovexattr"); throw new Error("Method not implemented."); } + // below utimes() { console.error("Not implemented: utimes");