UNPKG

@zenfs/core

Version:

A filesystem, anywhere

315 lines (314 loc) 10.1 kB
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) { if (value !== null && value !== void 0) { if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected."); var dispose, inner; if (async) { if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined."); dispose = value[Symbol.asyncDispose]; } if (dispose === void 0) { if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined."); dispose = value[Symbol.dispose]; if (async) inner = dispose; } if (typeof dispose !== "function") throw new TypeError("Object not disposable."); if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } }; env.stack.push({ value: value, dispose: dispose, async: async }); } else if (async) { env.stack.push({ async: true }); } return value; }; var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) { return function (env) { function fail(e) { env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e; env.hasError = true; } var r, s = 0; function next() { while (r = env.stack.pop()) { try { if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next); if (r.dispose) { var result = r.dispose.call(r.value); if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); }); } else s |= 1; } catch (e) { fail(e); } } if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve(); if (env.hasError) throw env.error; } return next(); }; })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }); // SPDX-License-Identifier: LGPL-3.0-or-later import { err, warn } from 'kerium/log'; import { FileSystem } from '../internal/filesystem.js'; import { isDirectory } from '../internal/inode.js'; export class PassthroughFS extends FileSystem { nodeFS; prefix; constructor(nodeFS, prefix) { super(0x6e6f6465, 'nodefs'); this.nodeFS = nodeFS; this.prefix = prefix; } usage() { const info = this.nodeFS.statfsSync(this.prefix); return { totalSpace: info.bsize * info.blocks, freeSpace: info.bsize * info.bfree, }; } path(path) { return this.prefix + path; } /** * Rename a file or directory. */ async rename(oldPath, newPath) { await this.nodeFS.promises.rename(this.path(oldPath), this.path(newPath)); } /** * Rename a file or directory synchronously. */ renameSync(oldPath, newPath) { this.nodeFS.renameSync(this.path(oldPath), this.path(newPath)); } /** * Get file statistics. */ async stat(path) { return await this.nodeFS.promises.stat(this.path(path)); } /** * Get file statistics synchronously. */ statSync(path) { return this.nodeFS.statSync(this.path(path)); } /** * @privateRemarks * Timestamps should be updated by the underlying file system. */ async touch(path, metadata) { const env_1 = { stack: [], error: void 0, hasError: false }; try { const handle = __addDisposableResource(env_1, await this.nodeFS.promises.open(this.path(path), 'r'), true); await handle.chmod(metadata.mode); try { await handle.chown(metadata.uid, metadata.gid); } catch (error) { err('Failed to chown passthrough file: ' + error.message); } } catch (e_1) { env_1.error = e_1; env_1.hasError = true; } finally { const result_1 = __disposeResources(env_1); if (result_1) await result_1; } } /** * @privateRemarks * Timestamps should be updated by the underlying file system. */ touchSync(path, metadata) { this.nodeFS.chmodSync(this.path(path), metadata.mode); try { this.nodeFS.chownSync(this.path(path), metadata.uid, metadata.gid); } catch (error) { err('Failed to chown passthrough file: ' + error.message); } } /** * Unlink (delete) a file. */ async unlink(path) { await this.nodeFS.promises.unlink(this.path(path)); } /** * Unlink (delete) a file synchronously. */ unlinkSync(path) { this.nodeFS.unlinkSync(this.path(path)); } /** * Create a directory. */ async mkdir(path, options) { await this.nodeFS.promises.mkdir(this.path(path), options); return await this.nodeFS.promises.stat(this.path(path)); } /** * Create a directory synchronously. */ mkdirSync(path, options) { this.nodeFS.mkdirSync(this.path(path), options); return this.nodeFS.statSync(this.path(path)); } /** * Read the contents of a directory. */ async readdir(path) { return await this.nodeFS.promises.readdir(this.path(path)); } /** * Read the contents of a directory synchronously. */ readdirSync(path) { return this.nodeFS.readdirSync(this.path(path)); } /** * Create a file. */ async createFile(path, options) { if (isDirectory(options)) { await this.nodeFS.promises.mkdir(this.path(path), { mode: options.mode }); } else { const env_2 = { stack: [], error: void 0, hasError: false }; try { const handle = __addDisposableResource(env_2, await this.nodeFS.promises.open(this.path(path), 'wx'), true); await handle.close(); } catch (e_2) { env_2.error = e_2; env_2.hasError = true; } finally { const result_2 = __disposeResources(env_2); if (result_2) await result_2; } } return await this.nodeFS.promises.stat(this.path(path)); } /** * Create a file synchronously. */ createFileSync(path, options) { if (isDirectory(options)) { this.nodeFS.mkdirSync(this.path(path), { mode: options.mode }); } else { const fd = this.nodeFS.openSync(this.path(path), 'wx'); this.nodeFS.closeSync(fd); } return this.nodeFS.statSync(this.path(path)); } /** * Remove a directory. */ async rmdir(path) { await this.nodeFS.promises.rmdir(this.path(path)); } /** * Remove a directory synchronously. */ rmdirSync(path) { this.nodeFS.rmdirSync(this.path(path)); } /** * Synchronize data to the file system. */ async sync() { warn('Sync on passthrough is unnecessary'); } /** * Synchronize data to the file system synchronously. */ syncSync() { warn('Sync on passthrough is unnecessary'); } /** * Create a hard link. */ async link(target, link) { await this.nodeFS.promises.link(this.path(target), this.path(link)); } /** * Create a hard link synchronously. */ linkSync(target, link) { this.nodeFS.linkSync(this.path(target), this.path(link)); } async read(path, buffer, offset, end) { const env_3 = { stack: [], error: void 0, hasError: false }; try { const handle = __addDisposableResource(env_3, await this.nodeFS.promises.open(this.path(path), 'r'), true); await handle.read({ buffer, offset, length: end - offset }); } catch (e_3) { env_3.error = e_3; env_3.hasError = true; } finally { const result_3 = __disposeResources(env_3); if (result_3) await result_3; } } readSync(path, buffer, offset, end) { const fd = this.nodeFS.openSync(this.path(path), 'r'); try { this.nodeFS.readSync(fd, buffer, { offset, length: end - offset }); } finally { this.nodeFS.closeSync(fd); } } async write(path, buffer, offset) { const env_4 = { stack: [], error: void 0, hasError: false }; try { const handle = __addDisposableResource(env_4, await this.nodeFS.promises.open(this.path(path), 'w'), true); await handle.write(buffer, offset); } catch (e_4) { env_4.error = e_4; env_4.hasError = true; } finally { const result_4 = __disposeResources(env_4); if (result_4) await result_4; } } writeSync(path, buffer, offset) { const fd = this.nodeFS.openSync(this.path(path), 'w'); try { this.nodeFS.writeSync(fd, buffer, offset); } finally { this.nodeFS.closeSync(fd); } } } const _Passthrough = { name: 'Passthrough', options: { fs: { type: 'object', required: true }, prefix: { type: 'string', required: true }, }, create({ fs, prefix }) { return new PassthroughFS(fs, prefix); }, }; /** * A file system that passes through to another FS */ export const Passthrough = _Passthrough;