From f1a7cc1fb755424bd60569c79cfb99cbc8f2d617 Mon Sep 17 00:00:00 2001 From: Zef Hemel Date: Wed, 6 Jul 2022 12:17:42 +0200 Subject: [PATCH] fs builtin (highly experimental and potentially dangerous) --- packages/plugos-syscall/fs.ts | 31 ++++++++++ packages/plugos/syscalls/fs.node.ts | 87 +++++++++++++++++++++++++++++ packages/server/express_server.ts | 3 + 3 files changed, 121 insertions(+) create mode 100644 packages/plugos-syscall/fs.ts create mode 100644 packages/plugos/syscalls/fs.node.ts diff --git a/packages/plugos-syscall/fs.ts b/packages/plugos-syscall/fs.ts new file mode 100644 index 0000000..80c937f --- /dev/null +++ b/packages/plugos-syscall/fs.ts @@ -0,0 +1,31 @@ +import { syscall } from "./syscall"; + +export type FileMeta = { + name: string; + lastModified: number; +}; + +export async function readFile( + path: string +): Promise<{ text: string; meta: FileMeta }> { + return syscall("fs.readFile", path); +} + +export async function getFileMeta(path: string): Promise { + return syscall("fs.getFileMeta", path); +} + +export async function writeFile(path: string, text: string): Promise { + return syscall("fs.writeFile", path, text); +} + +export async function deleteFile(path: string): Promise { + return syscall("fs.deleteFile", path); +} + +export async function listFiles( + dirName: string, + recursive = false +): Promise { + return syscall("fs.listFiles", dirName, recursive); +} diff --git a/packages/plugos/syscalls/fs.node.ts b/packages/plugos/syscalls/fs.node.ts new file mode 100644 index 0000000..a0f077c --- /dev/null +++ b/packages/plugos/syscalls/fs.node.ts @@ -0,0 +1,87 @@ +import { readdir, readFile, stat, writeFile, unlink } from "fs/promises"; +import path from "path"; +import type { SysCallMapping } from "../system"; + +export type FileMeta = { + name: string; + lastModified: number; +}; + +export default function fileSystemSyscalls(root: string = "/"): SysCallMapping { + function resolvedPath(p: string): string { + p = path.resolve(root, p); + if (!p.startsWith(root)) { + throw Error("Path outside root, not allowed"); + } + return p; + } + + return { + "fs.readFile": async ( + ctx, + filePath: string + ): Promise<{ text: string; meta: FileMeta }> => { + let p = resolvedPath(filePath); + let text = await readFile(p, "utf8"); + let s = await stat(p); + return { + text, + meta: { + name: filePath, + lastModified: s.mtime.getTime(), + }, + }; + }, + "fs.getFileMeta": async (ctx, filePath: string): Promise => { + let p = resolvedPath(filePath); + let s = await stat(p); + return { + name: filePath, + lastModified: s.mtime.getTime(), + }; + }, + "fs.writeFile": async ( + ctx, + filePath: string, + text: string + ): Promise => { + let p = resolvedPath(filePath); + await writeFile(p, text); + let s = await stat(p); + return { + name: filePath, + lastModified: s.mtime.getTime(), + }; + }, + "fs.deleteFile": async (ctx, filePath: string): Promise => { + let p = resolvedPath(filePath); + await unlink(p); + }, + "fs.listFiles": async ( + ctx, + dirPath: string, + recursive: boolean + ): Promise => { + dirPath = resolvedPath(dirPath); + let allFiles: FileMeta[] = []; + + async function walkPath(dir: string) { + let files = await readdir(dir); + for (let file of files) { + const fullPath = path.join(dir, file); + let s = await stat(fullPath); + if (s.isDirectory() && recursive) { + await walkPath(fullPath); + } else { + allFiles.push({ + name: fullPath.substring(dirPath.length + 1), + lastModified: s.mtime.getTime(), + }); + } + } + } + await walkPath(dirPath); + return allFiles; + }, + }; +} diff --git a/packages/server/express_server.ts b/packages/server/express_server.ts index 4c7466a..512f8f9 100644 --- a/packages/server/express_server.ts +++ b/packages/server/express_server.ts @@ -49,6 +49,7 @@ import { import { PlugSpacePrimitives } from "./hooks/plug_space_primitives"; import { PageNamespaceHook } from "./hooks/page_namespace"; import { readFileSync } from "fs"; +import fileSystemSyscalls from "@plugos/plugos/syscalls/fs.node"; const safeFilename = /^[a-zA-Z0-9_\-\.]+$/; @@ -115,6 +116,8 @@ export class ExpressServer { // Register syscalls available on the server sid this.system.registerSyscalls(["shell"], shellSyscalls(options.pagesPath)); + // YOLO + this.system.registerSyscalls([], fileSystemSyscalls("/")); this.system.registerSyscalls( [], pageIndexSyscalls(this.db),