UNPKG

@zenfs/core

Version:

A filesystem, anywhere

97 lines (96 loc) 3.81 kB
import { checkOptions, isBackend, isBackendConfig } from './backends/backend.js'; import { credentials } from './credentials.js'; import { DeviceFS, fullDevice, nullDevice, randomDevice, zeroDevice } from './devices.js'; import * as cache from './emulation/cache.js'; import * as fs from './emulation/index.js'; import { config } from './emulation/config.js'; import { Errno, ErrnoError } from './error.js'; import { FileSystem } from './filesystem.js'; function isMountConfig(arg) { return isBackendConfig(arg) || isBackend(arg) || arg instanceof FileSystem; } /** * Retrieve a file system with `configuration`. * @see MountConfiguration */ export async function resolveMountConfig(configuration, _depth = 0) { if (typeof configuration !== 'object' || configuration == null) { throw new ErrnoError(Errno.EINVAL, 'Invalid options on mount configuration'); } if (!isMountConfig(configuration)) { throw new ErrnoError(Errno.EINVAL, 'Invalid mount configuration'); } if (configuration instanceof FileSystem) { await configuration.ready(); return configuration; } if (isBackend(configuration)) { configuration = { backend: configuration }; } for (const [key, value] of Object.entries(configuration)) { if (key == 'backend') { continue; } if (!isMountConfig(value)) { continue; } if (_depth > 10) { throw new ErrnoError(Errno.EINVAL, 'Invalid configuration, too deep and possibly infinite'); } configuration[key] = await resolveMountConfig(value, ++_depth); } const { backend } = configuration; if (!(await backend.isAvailable())) { throw new ErrnoError(Errno.EPERM, 'Backend not available: ' + backend.name); } await checkOptions(backend, configuration); const mount = (await backend.create(configuration)); mount._disableSync = configuration.disableAsyncCache || false; await mount.ready(); return mount; } /** * Configures ZenFS with single mount point / */ export async function configureSingle(configuration) { if (!isBackendConfig(configuration)) { throw new TypeError('Invalid single mount point configuration'); } const resolved = await resolveMountConfig(configuration); fs.umount('/'); fs.mount('/', resolved); } /** * Configures ZenFS with `configuration` * @see Configuration */ export async function configure(configuration) { const uid = 'uid' in configuration ? configuration.uid || 0 : 0; const gid = 'gid' in configuration ? configuration.gid || 0 : 0; Object.assign(credentials, { uid, gid, suid: uid, sgid: gid, euid: uid, egid: gid }); cache.setEnabled(configuration.cacheStats ?? false); config.checkAccess = !configuration.disableAccessChecks; config.syncOnRead = !configuration.disableSyncOnRead; if (configuration.addDevices) { const devfs = new DeviceFS(); devfs.createDevice('/null', nullDevice); devfs.createDevice('/zero', zeroDevice); devfs.createDevice('/full', fullDevice); devfs.createDevice('/random', randomDevice); await devfs.ready(); fs.mount('/dev', devfs); } if (!configuration.mounts) { return; } for (const [point, mountConfig] of Object.entries(configuration.mounts)) { if (!point.startsWith('/')) { throw new ErrnoError(Errno.EINVAL, 'Mount points must have absolute paths'); } if (isBackendConfig(mountConfig)) { mountConfig.disableAsyncCache ?? (mountConfig.disableAsyncCache = configuration.disableAsyncCache || false); } configuration.mounts[point] = await resolveMountConfig(mountConfig); } fs.mountObject(configuration.mounts); }