@zenfs/core 0.12.0 → 0.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/backends/backend.d.ts +15 -5
  2. package/dist/backends/index/fs.d.ts +1 -0
  3. package/dist/backends/index/index.d.ts +5 -0
  4. package/dist/backends/index/index.js +1 -0
  5. package/dist/backends/overlay.js +1 -1
  6. package/dist/backends/port/fs.d.ts +3 -1
  7. package/dist/browser.min.js +4 -4
  8. package/dist/browser.min.js.map +4 -4
  9. package/dist/config.d.ts +33 -11
  10. package/dist/config.js +16 -7
  11. package/dist/emulation/async.d.ts +5 -4
  12. package/dist/emulation/async.js +3 -2
  13. package/dist/emulation/index.d.ts +1 -1
  14. package/dist/emulation/index.js +1 -1
  15. package/dist/emulation/path.d.ts +4 -1
  16. package/dist/emulation/promises.d.ts +4 -4
  17. package/dist/emulation/promises.js +27 -27
  18. package/dist/emulation/shared.d.ts +6 -0
  19. package/dist/emulation/shared.js +19 -1
  20. package/dist/emulation/sync.d.ts +4 -4
  21. package/dist/emulation/sync.js +76 -38
  22. package/dist/file.d.ts +5 -10
  23. package/dist/file.js +38 -55
  24. package/dist/filesystem.d.ts +45 -3
  25. package/dist/filesystem.js +37 -8
  26. package/dist/stats.d.ts +16 -16
  27. package/dist/stats.js +42 -49
  28. package/package.json +2 -2
  29. package/src/backends/backend.ts +15 -6
  30. package/src/backends/index/index.ts +5 -0
  31. package/src/backends/overlay.ts +1 -1
  32. package/src/config.ts +62 -21
  33. package/src/emulation/async.ts +19 -18
  34. package/src/emulation/index.ts +1 -1
  35. package/src/emulation/path.ts +4 -1
  36. package/src/emulation/promises.ts +33 -31
  37. package/src/emulation/shared.ts +22 -1
  38. package/src/emulation/sync.ts +83 -54
  39. package/src/error.ts +1 -1
  40. package/src/file.ts +39 -57
  41. package/src/filesystem.ts +133 -51
  42. package/src/stats.ts +48 -60
package/dist/config.d.ts CHANGED
@@ -1,25 +1,47 @@
1
- import type { Backend, BackendConfiguration } from './backends/backend.js';
2
- import { FileSystem } from './filesystem.js';
1
+ import type { Backend, BackendConfiguration, FilesystemOf } from './backends/backend.js';
3
2
  import type { AbsolutePath } from './emulation/path.js';
4
3
  /**
5
4
  * Configuration for a specific mount point
6
5
  */
7
- export type MountConfiguration<FS extends FileSystem = FileSystem, TOptions extends object = object> = FS | BackendConfiguration<Backend<FS, TOptions>> | Backend<FS, TOptions>;
6
+ export type MountConfiguration<T extends Backend> = FilesystemOf<T> | BackendConfiguration<T> | T;
8
7
  /**
9
8
  * Retrieve a file system with the given configuration.
10
9
  * @param config A BackendConfig object.
11
10
  */
12
- export declare function resolveMountConfig<FS extends FileSystem, TOptions extends object = object>(config: MountConfiguration<FS, TOptions>, _depth?: number): Promise<FS>;
11
+ export declare function resolveMountConfig<T extends Backend>(config: MountConfiguration<T>, _depth?: number): Promise<FilesystemOf<T>>;
12
+ type ConfigMounts = {
13
+ [K in AbsolutePath]: Backend;
14
+ };
13
15
  /**
14
16
  * Configuration
15
17
  */
16
- export interface Configuration {
17
- mounts: Record<AbsolutePath, MountConfiguration>;
18
- uid?: number;
19
- gid?: number;
18
+ export interface Configuration<T extends ConfigMounts> {
19
+ /**
20
+ * An object mapping mount points to mount configuration
21
+ */
22
+ mounts: {
23
+ [K in keyof T & AbsolutePath]: MountConfiguration<T[K]>;
24
+ };
25
+ /**
26
+ * The uid to use
27
+ */
28
+ uid: number;
29
+ /**
30
+ * The gid to use
31
+ */
32
+ gid: number;
33
+ /**
34
+ * If set, disables the sync cache and sync operations on async file systems.
35
+ */
36
+ disableAsyncCache: boolean;
20
37
  }
21
38
  /**
22
- * Creates filesystems with the given configuration, and initializes ZenFS with it.
23
- * @see Configuration for more info on the configuration object.
39
+ * Configures ZenFS with single mount point /
24
40
  */
25
- export declare function configure<T extends MountConfiguration | Configuration>(config: T | Configuration): Promise<void>;
41
+ export declare function configure<T extends Backend>(config: MountConfiguration<T>): Promise<void>;
42
+ /**
43
+ * Configures ZenFS with the given configuration
44
+ * @see Configuration
45
+ */
46
+ export declare function configure<T extends ConfigMounts>(config: Partial<Configuration<T>>): Promise<void>;
47
+ export {};
package/dist/config.js CHANGED
@@ -1,7 +1,7 @@
1
- import { ErrnoError, Errno } from './error.js';
2
1
  import { checkOptions, isBackend, isBackendConfig } from './backends/backend.js';
3
2
  import * as fs from './emulation/index.js';
4
3
  import { setCred } from './emulation/shared.js';
4
+ import { Errno, ErrnoError } from './error.js';
5
5
  import { FileSystem } from './filesystem.js';
6
6
  function isMountConfig(arg) {
7
7
  return isBackendConfig(arg) || isBackend(arg) || arg instanceof FileSystem;
@@ -40,13 +40,16 @@ export async function resolveMountConfig(config, _depth = 0) {
40
40
  throw new ErrnoError(Errno.EPERM, 'Backend not available: ' + backend);
41
41
  }
42
42
  checkOptions(backend, config);
43
- const mount = await backend.create(config);
43
+ const mount = (await backend.create(config));
44
+ if ('_disableSync' in mount) {
45
+ mount._disableSync = config.disableAsyncCache || false;
46
+ }
44
47
  await mount.ready();
45
48
  return mount;
46
49
  }
47
50
  /**
48
- * Creates filesystems with the given configuration, and initializes ZenFS with it.
49
- * @see Configuration for more info on the configuration object.
51
+ * Configures ZenFS with the given configuration
52
+ * @see Configuration
50
53
  */
51
54
  export async function configure(config) {
52
55
  const uid = 'uid' in config ? config.uid || 0 : 0;
@@ -55,12 +58,18 @@ export async function configure(config) {
55
58
  // single FS
56
59
  config = { mounts: { '/': config } };
57
60
  }
58
- for (const [point, value] of Object.entries(config.mounts)) {
61
+ setCred({ uid, gid, suid: uid, sgid: gid, euid: uid, egid: gid });
62
+ if (!config.mounts) {
63
+ return;
64
+ }
65
+ for (const [point, mountConfig] of Object.entries(config.mounts)) {
59
66
  if (!point.startsWith('/')) {
60
67
  throw new ErrnoError(Errno.EINVAL, 'Mount points must have absolute paths');
61
68
  }
62
- config.mounts[point] = await resolveMountConfig(value);
69
+ if (isBackendConfig(mountConfig)) {
70
+ mountConfig.disableAsyncCache ?? (mountConfig.disableAsyncCache = config.disableAsyncCache || false);
71
+ }
72
+ config.mounts[point] = await resolveMountConfig(mountConfig);
63
73
  }
64
74
  fs.mountObject(config.mounts);
65
- setCred({ uid, gid, suid: uid, sgid: gid, euid: uid, egid: gid });
66
75
  }
@@ -1,9 +1,10 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
2
  /// <reference types="node" resolution-mode="require"/>
3
3
  /// <reference types="node" resolution-mode="require"/>
4
+ import { Buffer } from 'buffer';
4
5
  import type * as fs from 'node:fs';
5
6
  import type { FileContents } from '../filesystem.js';
6
- import { BigIntStats, type BigIntStatsFs, type Stats, type StatsFs } from '../stats.js';
7
+ import { BigIntStats, type Stats } from '../stats.js';
7
8
  import { type Callback } from '../utils.js';
8
9
  import { Dirent, type Dir } from './dir.js';
9
10
  import * as promises from './promises.js';
@@ -440,12 +441,12 @@ export declare function opendir(path: fs.PathLike, cb: Callback<[Dir]>): void;
440
441
  export declare function opendir(path: fs.PathLike, options: fs.OpenDirOptions, cb: Callback<[Dir]>): void;
441
442
  export declare function cp(source: fs.PathLike, destination: fs.PathLike, callback: Callback): void;
442
443
  export declare function cp(source: fs.PathLike, destination: fs.PathLike, opts: fs.CopyOptions, callback: Callback): void;
443
- export declare function statfs(path: fs.PathLike, callback: Callback<[StatsFs]>): void;
444
+ export declare function statfs(path: fs.PathLike, callback: Callback<[fs.StatsFs]>): void;
444
445
  export declare function statfs(path: fs.PathLike, options: fs.StatFsOptions & {
445
446
  bigint?: false;
446
- }, callback: Callback<[StatsFs]>): void;
447
+ }, callback: Callback<[fs.StatsFs]>): void;
447
448
  export declare function statfs(path: fs.PathLike, options: fs.StatFsOptions & {
448
449
  bigint: true;
449
- }, callback: Callback<[BigIntStatsFs]>): void;
450
+ }, callback: Callback<[fs.BigIntStatsFs]>): void;
450
451
  export declare function openAsBlob(path: fs.PathLike, options?: fs.OpenAsBlobOptions): Promise<Blob>;
451
452
  export {};
@@ -1,3 +1,4 @@
1
+ import { Buffer } from 'buffer';
1
2
  import { ErrnoError, Errno } from '../error.js';
2
3
  import { BigIntStats } from '../stats.js';
3
4
  import { nop, normalizeMode } from '../utils.js';
@@ -173,7 +174,7 @@ export function write(fd, data, cbPosOff, cbLenEnc, cbPos, cb = nop) {
173
174
  case 'number':
174
175
  // (fd, string, position, encoding?, cb?)
175
176
  position = cbPosOff;
176
- encoding = (typeof cbLenEnc === 'string' ? cbLenEnc : 'utf8');
177
+ encoding = typeof cbLenEnc === 'string' ? cbLenEnc : 'utf8';
177
178
  cb = typeof cbPos === 'function' ? cbPos : cb;
178
179
  break;
179
180
  default:
@@ -197,7 +198,7 @@ export function write(fd, data, cbPosOff, cbLenEnc, cbPos, cb = nop) {
197
198
  offset = cbPosOff;
198
199
  length = cbLenEnc;
199
200
  position = typeof cbPos === 'number' ? cbPos : null;
200
- const _cb = (typeof cbPos === 'function' ? cbPos : cb);
201
+ const _cb = typeof cbPos === 'function' ? cbPos : cb;
201
202
  handle
202
203
  .write(buffer, offset, length, position)
203
204
  .then(({ bytesWritten }) => _cb(undefined, bytesWritten, buffer))
@@ -5,4 +5,4 @@ export * as constants from './constants.js';
5
5
  export * from './streams.js';
6
6
  export * from './dir.js';
7
7
  export { mountObject, mounts, mount, umount } from './shared.js';
8
- export { Stats, BigIntStats, StatsFs } from '../stats.js';
8
+ export { Stats, StatsFs, BigIntStatsFs } from '../stats.js';
@@ -5,4 +5,4 @@ export * as constants from './constants.js';
5
5
  export * from './streams.js';
6
6
  export * from './dir.js';
7
7
  export { mountObject, mounts, mount, umount } from './shared.js';
8
- export { Stats, BigIntStats, StatsFs } from '../stats.js';
8
+ export { Stats, StatsFs, BigIntStatsFs } from '../stats.js';
@@ -1,5 +1,8 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
2
  import type { ParsedPath } from 'node:path';
3
+ /**
4
+ * An absolute path
5
+ */
3
6
  export type AbsolutePath = `/${string}`;
4
7
  export declare let cwd: string;
5
8
  export declare function cd(path: string): void;
@@ -8,7 +11,7 @@ export declare function normalizeString(path: string, allowAboveRoot: boolean):
8
11
  export declare function formatExt(ext: string): string;
9
12
  export declare function resolve(...parts: string[]): AbsolutePath;
10
13
  export declare function normalize(path: string): string;
11
- export declare function isAbsolute(path: string): boolean;
14
+ export declare function isAbsolute(path: string): path is AbsolutePath;
12
15
  export declare function join(...parts: string[]): string;
13
16
  export declare function relative(from: string, to: string): string;
14
17
  export declare function dirname(path: string): string;
@@ -14,7 +14,7 @@ import type { ReadableStream as TReadableStream } from 'node:stream/web';
14
14
  import type { Interface as ReadlineInterface } from 'readline';
15
15
  import { File } from '../file.js';
16
16
  import type { FileContents } from '../filesystem.js';
17
- import { BigIntStats, type BigIntStatsFs, type Stats, type StatsFs } from '../stats.js';
17
+ import { BigIntStats, type Stats } from '../stats.js';
18
18
  import { Dir, Dirent } from './dir.js';
19
19
  import { ReadStream, WriteStream } from './streams.js';
20
20
  export * as constants from './constants.js';
@@ -437,8 +437,8 @@ export declare function cp(source: fs.PathLike, destination: fs.PathLike, opts?:
437
437
  */
438
438
  export declare function statfs(path: fs.PathLike, opts?: fs.StatFsOptions & {
439
439
  bigint?: false;
440
- }): Promise<StatsFs>;
440
+ }): Promise<fs.StatsFs>;
441
441
  export declare function statfs(path: fs.PathLike, opts: fs.StatFsOptions & {
442
442
  bigint: true;
443
- }): Promise<BigIntStatsFs>;
444
- export declare function statfs(path: fs.PathLike, opts?: fs.StatFsOptions): Promise<StatsFs | BigIntStatsFs>;
443
+ }): Promise<fs.BigIntStatsFs>;
444
+ export declare function statfs(path: fs.PathLike, opts?: fs.StatFsOptions): Promise<fs.StatsFs | fs.BigIntStatsFs>;
@@ -1,12 +1,12 @@
1
1
  import { Buffer } from 'buffer';
2
- import { ErrnoError, Errno } from '../error.js';
2
+ import { Errno, ErrnoError } from '../error.js';
3
3
  import { ActionType, isAppendable, isReadable, isWriteable, parseFlag, pathExistsAction, pathNotExistsAction } from '../file.js';
4
4
  import { BigIntStats, FileType } from '../stats.js';
5
5
  import { normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '../utils.js';
6
6
  import * as constants from './constants.js';
7
7
  import { Dir, Dirent } from './dir.js';
8
8
  import { dirname, join, parse } from './path.js';
9
- import { cred, fd2file, fdMap, file2fd, fixError, mounts, resolveMount } from './shared.js';
9
+ import { _statfs, cred, fd2file, fdMap, file2fd, fixError, mounts, resolveMount } from './shared.js';
10
10
  import { ReadStream, WriteStream } from './streams.js';
11
11
  export * as constants from './constants.js';
12
12
  export class FileHandle {
@@ -162,7 +162,7 @@ export class FileHandle {
162
162
  if (typeof data === 'string') {
163
163
  // Signature 1: (fd, string, [position?, [encoding?]])
164
164
  position = typeof posOrOff === 'number' ? posOrOff : null;
165
- const encoding = (typeof lenOrEnc === 'string' ? lenOrEnc : 'utf8');
165
+ const encoding = typeof lenOrEnc === 'string' ? lenOrEnc : 'utf8';
166
166
  offset = 0;
167
167
  buffer = Buffer.from(data, encoding);
168
168
  length = buffer.length;
@@ -386,29 +386,7 @@ async function _open(path, _flag, _mode = 0o644, resolveSymlinks) {
386
386
  const mode = normalizeMode(_mode, 0o644), flag = parseFlag(_flag);
387
387
  path = resolveSymlinks && (await exists(path)) ? await realpath(path) : path;
388
388
  const { fs, path: resolved } = resolveMount(path);
389
- try {
390
- switch (pathExistsAction(flag)) {
391
- case ActionType.THROW:
392
- throw ErrnoError.With('EEXIST', path, '_open');
393
- case ActionType.TRUNCATE:
394
- /*
395
- In a previous implementation, we deleted the file and
396
- re-created it. However, this created a race condition if another
397
- asynchronous request was trying to read the file, as the file
398
- would not exist for a small period of time.
399
- */
400
- const file = await fs.openFile(resolved, flag, cred);
401
- await file.truncate(0);
402
- await file.sync();
403
- return new FileHandle(file);
404
- case ActionType.NOP:
405
- // Must await so thrown errors are caught by the catch below
406
- return new FileHandle(await fs.openFile(resolved, flag, cred));
407
- default:
408
- throw new ErrnoError(Errno.EINVAL, 'Invalid file flag');
409
- }
410
- }
411
- catch (e) {
389
+ if (!(await fs.exists(path, cred))) {
412
390
  switch (pathNotExistsAction(flag)) {
413
391
  case ActionType.CREATE:
414
392
  // Ensure parent exists.
@@ -423,6 +401,26 @@ async function _open(path, _flag, _mode = 0o644, resolveSymlinks) {
423
401
  throw new ErrnoError(Errno.EINVAL, 'Invalid file flag');
424
402
  }
425
403
  }
404
+ switch (pathExistsAction(flag)) {
405
+ case ActionType.THROW:
406
+ throw ErrnoError.With('EEXIST', path, '_open');
407
+ case ActionType.TRUNCATE:
408
+ /*
409
+ In a previous implementation, we deleted the file and
410
+ re-created it. However, this created a race condition if another
411
+ asynchronous request was trying to read the file, as the file
412
+ would not exist for a small period of time.
413
+ */
414
+ const file = await fs.openFile(resolved, flag, cred);
415
+ await file.truncate(0);
416
+ await file.sync();
417
+ return new FileHandle(file);
418
+ case ActionType.NOP:
419
+ // Must await so thrown errors are caught by the catch below
420
+ return new FileHandle(await fs.openFile(resolved, flag, cred));
421
+ default:
422
+ throw new ErrnoError(Errno.EINVAL, 'Invalid file flag');
423
+ }
426
424
  }
427
425
  /**
428
426
  * Asynchronous file open.
@@ -847,5 +845,7 @@ export async function cp(source, destination, opts) {
847
845
  }
848
846
  cp;
849
847
  export async function statfs(path, opts) {
850
- throw ErrnoError.With('ENOSYS', path.toString(), 'statfs');
848
+ path = normalizePath(path);
849
+ const { fs } = resolveMount(path);
850
+ return _statfs(fs, opts?.bigint);
851
851
  }
@@ -1,3 +1,5 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ import type { BigIntStatsFs, StatsFs } from 'node:fs';
1
3
  import { Cred } from '../cred.js';
2
4
  import type { File } from '../file.js';
3
5
  import { FileSystem } from '../filesystem.js';
@@ -35,3 +37,7 @@ export declare function resolveMount(path: string): {
35
37
  export declare function fixPaths(text: string, paths: Record<string, string>): string;
36
38
  export declare function fixError<E extends Error>(e: E, paths: Record<string, string>): E;
37
39
  export declare function mountObject(mounts: MountObject): void;
40
+ /**
41
+ * @hidden
42
+ */
43
+ export declare function _statfs<const T extends boolean>(fs: FileSystem, bigint?: T): T extends true ? BigIntStatsFs : StatsFs;
@@ -1,7 +1,9 @@
1
1
  // Utilities and shared data
2
- import { ErrnoError, Errno } from '../error.js';
3
2
  import { InMemory } from '../backends/memory.js';
4
3
  import { rootCred } from '../cred.js';
4
+ import { Errno, ErrnoError } from '../error.js';
5
+ import { size_max } from '../inode.js';
6
+ import { ZenFsType } from '../stats.js';
5
7
  import { normalizePath } from '../utils.js';
6
8
  import { resolve } from './path.js';
7
9
  // credentials
@@ -100,3 +102,19 @@ export function mountObject(mounts) {
100
102
  mount(point, fs);
101
103
  }
102
104
  }
105
+ /**
106
+ * @hidden
107
+ */
108
+ export function _statfs(fs, bigint) {
109
+ const md = fs.metadata();
110
+ const bs = md.blockSize || 4096;
111
+ return {
112
+ type: (bigint ? BigInt : Number)(md.type || ZenFsType),
113
+ bsize: (bigint ? BigInt : Number)(bs),
114
+ ffree: (bigint ? BigInt : Number)(md.freeNodes || size_max),
115
+ files: (bigint ? BigInt : Number)(md.totalNodes || size_max),
116
+ bavail: (bigint ? BigInt : Number)(md.freeSpace / bs),
117
+ bfree: (bigint ? BigInt : Number)(md.freeSpace / bs),
118
+ blocks: (bigint ? BigInt : Number)(md.totalSpace / bs),
119
+ };
120
+ }
@@ -4,7 +4,7 @@
4
4
  import { Buffer } from 'buffer';
5
5
  import type * as fs from 'node:fs';
6
6
  import { FileContents } from '../filesystem.js';
7
- import { BigIntStats, type BigIntStatsFs, type Stats, type StatsFs } from '../stats.js';
7
+ import { BigIntStats, type Stats } from '../stats.js';
8
8
  import { Dir, Dirent } from './dir.js';
9
9
  /**
10
10
  * Synchronous rename.
@@ -368,8 +368,8 @@ export declare function cpSync(source: fs.PathLike, destination: fs.PathLike, op
368
368
  */
369
369
  export declare function statfsSync(path: fs.PathLike, options?: fs.StatFsOptions & {
370
370
  bigint?: false;
371
- }): StatsFs;
371
+ }): fs.StatsFs;
372
372
  export declare function statfsSync(path: fs.PathLike, options: fs.StatFsOptions & {
373
373
  bigint: true;
374
- }): BigIntStatsFs;
375
- export declare function statfsSync(path: fs.PathLike, options?: fs.StatFsOptions): StatsFs | BigIntStatsFs;
374
+ }): fs.BigIntStatsFs;
375
+ export declare function statfsSync(path: fs.PathLike, options?: fs.StatFsOptions): fs.StatsFs | fs.BigIntStatsFs;
@@ -1,23 +1,12 @@
1
1
  import { Buffer } from 'buffer';
2
- import { ErrnoError, Errno } from '../error.js';
2
+ import { Errno, ErrnoError } from '../error.js';
3
3
  import { ActionType, isAppendable, isReadable, isWriteable, parseFlag, pathExistsAction, pathNotExistsAction } from '../file.js';
4
4
  import { BigIntStats, FileType } from '../stats.js';
5
5
  import { normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '../utils.js';
6
6
  import { COPYFILE_EXCL, F_OK, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLNK, S_IFMT, S_IFREG, S_IFSOCK } from './constants.js';
7
7
  import { Dir, Dirent } from './dir.js';
8
8
  import { dirname, join, parse } from './path.js';
9
- import { cred, fd2file, fdMap, fixError, file2fd, mounts, resolveMount } from './shared.js';
10
- function wrap(...[name, resolveSymlinks, path, ...args]) {
11
- path = normalizePath(path);
12
- const { fs, path: resolvedPath } = resolveMount(resolveSymlinks && existsSync(path) ? realpathSync(path) : path);
13
- try {
14
- // @ts-expect-error 2556 (since ...args is not correctly picked up as being a tuple)
15
- return fs[name](resolvedPath, ...args);
16
- }
17
- catch (e) {
18
- throw fixError(e, { [resolvedPath]: path });
19
- }
20
- }
9
+ import { _statfs, cred, fd2file, fdMap, file2fd, fixError, mounts, resolveMount } from './shared.js';
21
10
  /**
22
11
  * Synchronous rename.
23
12
  * @param oldPath
@@ -60,13 +49,27 @@ export function existsSync(path) {
60
49
  }
61
50
  existsSync;
62
51
  export function statSync(path, options) {
63
- const stats = wrap('statSync', true, path.toString(), cred);
64
- return options?.bigint ? new BigIntStats(stats) : stats;
52
+ path = normalizePath(path);
53
+ const { fs, path: resolved } = resolveMount(existsSync(path) ? realpathSync(path) : path);
54
+ try {
55
+ const stats = fs.statSync(resolved, cred);
56
+ return options?.bigint ? new BigIntStats(stats) : stats;
57
+ }
58
+ catch (e) {
59
+ throw fixError(e, { [resolved]: path });
60
+ }
65
61
  }
66
62
  statSync;
67
63
  export function lstatSync(path, options) {
68
- const stats = wrap('statSync', false, path.toString(), cred);
69
- return options?.bigint ? new BigIntStats(stats) : stats;
64
+ path = normalizePath(path);
65
+ const { fs, path: resolved } = resolveMount(path);
66
+ try {
67
+ const stats = fs.statSync(resolved, cred);
68
+ return options?.bigint ? new BigIntStats(stats) : stats;
69
+ }
70
+ catch (e) {
71
+ throw fixError(e, { [resolved]: path });
72
+ }
70
73
  }
71
74
  lstatSync;
72
75
  /**
@@ -89,32 +92,37 @@ truncateSync;
89
92
  * @param path
90
93
  */
91
94
  export function unlinkSync(path) {
92
- return wrap('unlinkSync', false, path.toString(), cred);
93
- }
94
- unlinkSync;
95
- function _openSync(_path, _flag, _mode, resolveSymlinks = true) {
96
- const path = normalizePath(_path), mode = normalizeMode(_mode, 0o644), flag = parseFlag(_flag);
97
- // Check if the path exists, and is a file.
98
- let stats;
95
+ path = normalizePath(path);
96
+ const { fs, path: resolved } = resolveMount(path);
99
97
  try {
100
- stats = wrap('statSync', resolveSymlinks, path, cred);
98
+ return fs.unlinkSync(resolved, cred);
101
99
  }
102
100
  catch (e) {
103
- // File does not exist.
101
+ throw fixError(e, { [resolved]: path });
102
+ }
103
+ }
104
+ unlinkSync;
105
+ function _openSync(path, _flag, _mode, resolveSymlinks = true) {
106
+ path = normalizePath(path);
107
+ const mode = normalizeMode(_mode, 0o644), flag = parseFlag(_flag);
108
+ path = resolveSymlinks && existsSync(path) ? realpathSync(path) : path;
109
+ const { fs, path: resolved } = resolveMount(path);
110
+ if (!fs.existsSync(resolved, cred)) {
104
111
  switch (pathNotExistsAction(flag)) {
105
112
  case ActionType.CREATE:
106
113
  // Ensure parent exists.
107
- const parentStats = wrap('statSync', resolveSymlinks, dirname(path), cred);
114
+ const parentStats = fs.statSync(dirname(resolved), cred);
108
115
  if (!parentStats.isDirectory()) {
109
116
  throw ErrnoError.With('ENOTDIR', dirname(path), '_open');
110
117
  }
111
- return wrap('createFileSync', resolveSymlinks, path, flag, mode, cred);
118
+ return fs.createFileSync(resolved, flag, mode, cred);
112
119
  case ActionType.THROW:
113
120
  throw ErrnoError.With('ENOENT', path, '_open');
114
121
  default:
115
122
  throw new ErrnoError(Errno.EINVAL, 'Invalid FileFlag object.');
116
123
  }
117
124
  }
125
+ const stats = fs.statSync(resolved, cred);
118
126
  if (!stats.hasAccess(mode, cred)) {
119
127
  throw ErrnoError.With('EACCES', path, '_open');
120
128
  }
@@ -124,16 +132,16 @@ function _openSync(_path, _flag, _mode, resolveSymlinks = true) {
124
132
  throw ErrnoError.With('EEXIST', path, '_open');
125
133
  case ActionType.TRUNCATE:
126
134
  // Delete file.
127
- wrap('unlinkSync', resolveSymlinks, path, cred);
135
+ fs.unlinkSync(resolved, cred);
128
136
  /*
129
137
  Create file. Use the same mode as the old file.
130
138
  Node itself modifies the ctime when this occurs, so this action
131
139
  will preserve that behavior if the underlying file system
132
140
  supports those properties.
133
141
  */
134
- return wrap('createFileSync', resolveSymlinks, path, flag, stats.mode, cred);
142
+ return fs.createFileSync(resolved, flag, stats.mode, cred);
135
143
  case ActionType.NOP:
136
- return wrap('openFileSync', resolveSymlinks, path, flag, cred);
144
+ return fs.openFileSync(resolved, flag, cred);
137
145
  default:
138
146
  throw new ErrnoError(Errno.EINVAL, 'Invalid FileFlag object.');
139
147
  }
@@ -285,7 +293,7 @@ export function writeSync(fd, data, posOrOff, lenOrEnc, pos) {
285
293
  if (typeof data === 'string') {
286
294
  // Signature 1: (fd, string, [position?, [encoding?]])
287
295
  position = typeof posOrOff === 'number' ? posOrOff : null;
288
- const encoding = (typeof lenOrEnc === 'string' ? lenOrEnc : 'utf8');
296
+ const encoding = typeof lenOrEnc === 'string' ? lenOrEnc : 'utf8';
289
297
  offset = 0;
290
298
  buffer = Buffer.from(data, encoding);
291
299
  length = buffer.byteLength;
@@ -355,18 +363,39 @@ futimesSync;
355
363
  * @param path
356
364
  */
357
365
  export function rmdirSync(path) {
358
- return wrap('rmdirSync', true, path.toString(), cred);
366
+ path = normalizePath(path);
367
+ const { fs, path: resolved } = resolveMount(existsSync(path) ? realpathSync(path) : path);
368
+ try {
369
+ fs.rmdirSync(resolved, cred);
370
+ }
371
+ catch (e) {
372
+ throw fixError(e, { [resolved]: path });
373
+ }
359
374
  }
360
375
  rmdirSync;
361
376
  export function mkdirSync(path, options) {
362
- const mode = typeof options == 'number' || typeof options == 'string' ? options : options?.mode;
377
+ const mode = normalizeMode(typeof options == 'number' || typeof options == 'string' ? options : options?.mode, 0o777);
363
378
  const recursive = typeof options == 'object' && options?.recursive;
364
- wrap('mkdirSync', true, path.toString(), normalizeMode(mode, 0o777), cred);
379
+ path = normalizePath(path);
380
+ const { fs, path: resolved } = resolveMount(existsSync(path) ? realpathSync(path) : path);
381
+ try {
382
+ return fs.mkdirSync(resolved, mode, cred);
383
+ }
384
+ catch (e) {
385
+ throw fixError(e, { [resolved]: path });
386
+ }
365
387
  }
366
388
  mkdirSync;
367
389
  export function readdirSync(path, options) {
368
390
  path = normalizePath(path);
369
- const entries = wrap('readdirSync', true, path, cred);
391
+ const { fs, path: resolved } = resolveMount(existsSync(path) ? realpathSync(path) : path);
392
+ let entries;
393
+ try {
394
+ entries = fs.readdirSync(resolved, cred);
395
+ }
396
+ catch (e) {
397
+ throw fixError(e, { [resolved]: path });
398
+ }
370
399
  for (const mount of mounts.keys()) {
371
400
  if (!mount.startsWith(path)) {
372
401
  continue;
@@ -396,8 +425,15 @@ readdirSync;
396
425
  * @param newpath
397
426
  */
398
427
  export function linkSync(existing, newpath) {
428
+ existing = normalizePath(existing);
399
429
  newpath = normalizePath(newpath);
400
- return wrap('linkSync', false, existing.toString(), newpath.toString(), cred);
430
+ const { fs, path: resolved } = resolveMount(existing);
431
+ try {
432
+ return fs.linkSync(resolved, newpath, cred);
433
+ }
434
+ catch (e) {
435
+ throw fixError(e, { [resolved]: existing });
436
+ }
401
437
  }
402
438
  linkSync;
403
439
  /**
@@ -673,5 +709,7 @@ export function cpSync(source, destination, opts) {
673
709
  }
674
710
  cpSync;
675
711
  export function statfsSync(path, options) {
676
- throw ErrnoError.With('ENOSYS', path.toString(), 'statfs');
712
+ path = normalizePath(path);
713
+ const { fs } = resolveMount(path);
714
+ return _statfs(fs, options?.bigint);
677
715
  }
package/dist/file.d.ts CHANGED
@@ -204,7 +204,7 @@ export declare class PreloadFile<FS extends FileSystem> extends File {
204
204
  readonly stats: Stats;
205
205
  protected _buffer: Uint8Array;
206
206
  protected _position: number;
207
- protected _dirty: boolean;
207
+ protected dirty: boolean;
208
208
  /**
209
209
  * Creates a file with the given path and, optionally, the given contents. Note
210
210
  * that, if contents is specified, it will be mutated by the file!
@@ -259,14 +259,14 @@ export declare class PreloadFile<FS extends FileSystem> extends File {
259
259
  statSync(): Stats;
260
260
  /**
261
261
  * Asynchronous truncate.
262
- * @param len
262
+ * @param length
263
263
  */
264
- truncate(len: number): Promise<void>;
264
+ truncate(length: number): Promise<void>;
265
265
  /**
266
266
  * Synchronous truncate.
267
- * @param len
267
+ * @param length
268
268
  */
269
- truncateSync(len: number): void;
269
+ truncateSync(length: number): void;
270
270
  /**
271
271
  * Write buffer to the file.
272
272
  * Note that it is unsafe to use fs.write multiple times on the same file
@@ -345,11 +345,6 @@ export declare class PreloadFile<FS extends FileSystem> extends File {
345
345
  chownSync(uid: number, gid: number): void;
346
346
  utimes(atime: Date, mtime: Date): Promise<void>;
347
347
  utimesSync(atime: Date, mtime: Date): void;
348
- protected isDirty(): boolean;
349
- /**
350
- * Resets the dirty bit. Should only be called after a sync has completed successfully.
351
- */
352
- protected resetDirty(): void;
353
348
  _setType(type: FileType): Promise<void>;
354
349
  _setTypeSync(type: FileType): void;
355
350
  }