UNPKG

@zenfs/core

Version:

A filesystem, anywhere

118 lines (117 loc) 3.62 kB
// Utilities and shared data import { InMemory } from '../backends/memory.js'; import { Errno, ErrnoError } from '../error.js'; import { normalizePath } from '../utils.js'; import { resolve } from './path.js'; import { size_max } from './constants.js'; // descriptors export const fdMap = new Map(); let nextFd = 100; export function file2fd(file) { const fd = nextFd++; fdMap.set(fd, file); return fd; } export function fd2file(fd) { if (!fdMap.has(fd)) { throw new ErrnoError(Errno.EBADF); } return fdMap.get(fd); } /** * The map of mount points * @internal */ export const mounts = new Map(); // Set a default root. mount('/', InMemory.create({ name: 'root' })); /** * Mounts the file system at `mountPoint`. */ export function mount(mountPoint, fs) { if (mountPoint[0] !== '/') { mountPoint = '/' + mountPoint; } mountPoint = resolve(mountPoint); if (mounts.has(mountPoint)) { throw new ErrnoError(Errno.EINVAL, 'Mount point ' + mountPoint + ' is already in use.'); } mounts.set(mountPoint, fs); } /** * Unmounts the file system at `mountPoint`. */ export function umount(mountPoint) { if (mountPoint[0] !== '/') { mountPoint = `/${mountPoint}`; } mountPoint = resolve(mountPoint); if (!mounts.has(mountPoint)) { throw new ErrnoError(Errno.EINVAL, 'Mount point ' + mountPoint + ' is already unmounted.'); } mounts.delete(mountPoint); } /** * Gets the internal FileSystem for the path, then returns it along with the path relative to the FS' root */ export function resolveMount(path) { path = normalizePath(path); // Maybe do something for devices here const sortedMounts = [...mounts].sort((a, b) => (a[0].length > b[0].length ? -1 : 1)); // descending order of the string length for (const [mountPoint, fs] of sortedMounts) { // We know path is normalized, so it would be a substring of the mount point. if (mountPoint.length <= path.length && path.startsWith(mountPoint)) { path = path.slice(mountPoint.length > 1 ? mountPoint.length : 0); // Resolve the path relative to the mount point if (path === '') { path = '/'; } return { fs, path, mountPoint }; } } throw new ErrnoError(Errno.EIO, 'ZenFS not initialized with a file system'); } /** * Reverse maps the paths in text from the mounted FileSystem to the global path * @hidden */ export function fixPaths(text, paths) { for (const [from, to] of Object.entries(paths)) { text = text?.replaceAll(from, to); } return text; } /** * Fix paths in error stacks * @hidden */ export function fixError(e, paths) { if (typeof e.stack == 'string') { e.stack = fixPaths(e.stack, paths); } e.message = fixPaths(e.message, paths); return e; } export function mountObject(mounts) { if ('/' in mounts) { umount('/'); } for (const [point, fs] of Object.entries(mounts)) { mount(point, fs); } } /** * @hidden */ export function _statfs(fs, bigint) { const md = fs.metadata(); const bs = md.blockSize || 4096; return { type: (bigint ? BigInt : Number)(md.type), bsize: (bigint ? BigInt : Number)(bs), ffree: (bigint ? BigInt : Number)(md.freeNodes || size_max), files: (bigint ? BigInt : Number)(md.totalNodes || size_max), bavail: (bigint ? BigInt : Number)(md.freeSpace / bs), bfree: (bigint ? BigInt : Number)(md.freeSpace / bs), blocks: (bigint ? BigInt : Number)(md.totalSpace / bs), }; }