@zenfs/core 1.11.4 → 2.1.0

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 (135) hide show
  1. package/dist/backends/backend.d.ts +19 -15
  2. package/dist/backends/backend.js +36 -19
  3. package/dist/backends/cow.d.ts +20 -30
  4. package/dist/backends/cow.js +83 -192
  5. package/dist/backends/fetch.d.ts +1 -0
  6. package/dist/backends/fetch.js +30 -30
  7. package/dist/backends/index.d.ts +1 -1
  8. package/dist/backends/index.js +1 -1
  9. package/dist/backends/memory.d.ts +5 -7
  10. package/dist/backends/memory.js +2 -3
  11. package/dist/backends/passthrough.d.ts +19 -23
  12. package/dist/backends/passthrough.js +98 -288
  13. package/dist/backends/port.d.ts +220 -0
  14. package/dist/backends/port.js +328 -0
  15. package/dist/backends/single_buffer.d.ts +59 -47
  16. package/dist/backends/single_buffer.js +468 -219
  17. package/dist/backends/store/fs.d.ts +25 -35
  18. package/dist/backends/store/fs.js +276 -315
  19. package/dist/backends/store/store.d.ts +10 -15
  20. package/dist/backends/store/store.js +11 -10
  21. package/dist/config.d.ts +3 -12
  22. package/dist/config.js +17 -19
  23. package/dist/context.d.ts +8 -21
  24. package/dist/context.js +33 -10
  25. package/dist/index.d.ts +2 -1
  26. package/dist/index.js +2 -1
  27. package/dist/internal/contexts.d.ts +63 -0
  28. package/dist/internal/contexts.js +15 -0
  29. package/dist/internal/credentials.d.ts +2 -11
  30. package/dist/internal/credentials.js +0 -19
  31. package/dist/internal/devices.d.ts +18 -80
  32. package/dist/internal/devices.js +103 -316
  33. package/dist/internal/error.d.ts +9 -204
  34. package/dist/internal/error.js +19 -288
  35. package/dist/internal/file_index.d.ts +1 -1
  36. package/dist/internal/file_index.js +11 -11
  37. package/dist/internal/filesystem.d.ts +51 -94
  38. package/dist/internal/filesystem.js +21 -20
  39. package/dist/internal/index.d.ts +1 -2
  40. package/dist/internal/index.js +1 -2
  41. package/dist/internal/index_fs.d.ts +12 -30
  42. package/dist/internal/index_fs.js +37 -69
  43. package/dist/internal/inode.d.ts +140 -24
  44. package/dist/internal/inode.js +515 -66
  45. package/dist/mixins/async.js +52 -112
  46. package/dist/mixins/mutexed.d.ts +19 -18
  47. package/dist/mixins/mutexed.js +62 -64
  48. package/dist/mixins/readonly.d.ts +7 -6
  49. package/dist/mixins/readonly.js +24 -18
  50. package/dist/mixins/sync.js +8 -8
  51. package/dist/{vfs/path.d.ts → path.d.ts} +3 -4
  52. package/dist/{vfs/path.js → path.js} +6 -9
  53. package/dist/polyfills.js +1 -1
  54. package/dist/readline.d.ts +134 -0
  55. package/dist/readline.js +623 -0
  56. package/dist/utils.d.ts +9 -37
  57. package/dist/utils.js +17 -85
  58. package/dist/vfs/acl.d.ts +42 -0
  59. package/dist/vfs/acl.js +268 -0
  60. package/dist/vfs/async.d.ts +9 -23
  61. package/dist/vfs/async.js +25 -27
  62. package/dist/vfs/config.d.ts +6 -18
  63. package/dist/vfs/config.js +8 -18
  64. package/dist/vfs/dir.d.ts +3 -3
  65. package/dist/vfs/dir.js +12 -12
  66. package/dist/vfs/file.d.ts +106 -0
  67. package/dist/vfs/file.js +244 -0
  68. package/dist/vfs/flags.d.ts +19 -0
  69. package/dist/vfs/flags.js +62 -0
  70. package/dist/vfs/index.d.ts +4 -10
  71. package/dist/vfs/index.js +4 -13
  72. package/dist/vfs/ioctl.d.ts +88 -0
  73. package/dist/vfs/ioctl.js +409 -0
  74. package/dist/vfs/promises.d.ts +81 -19
  75. package/dist/vfs/promises.js +404 -288
  76. package/dist/vfs/shared.d.ts +7 -37
  77. package/dist/vfs/shared.js +29 -85
  78. package/dist/{stats.d.ts → vfs/stats.d.ts} +14 -28
  79. package/dist/{stats.js → vfs/stats.js} +11 -66
  80. package/dist/vfs/streams.d.ts +1 -0
  81. package/dist/vfs/streams.js +32 -27
  82. package/dist/vfs/sync.d.ts +3 -3
  83. package/dist/vfs/sync.js +263 -260
  84. package/dist/vfs/watchers.d.ts +2 -2
  85. package/dist/vfs/watchers.js +12 -12
  86. package/dist/vfs/xattr.d.ts +116 -0
  87. package/dist/vfs/xattr.js +201 -0
  88. package/package.json +5 -3
  89. package/readme.md +1 -1
  90. package/scripts/test.js +2 -2
  91. package/tests/assignment.ts +1 -1
  92. package/tests/backend/config.worker.js +4 -1
  93. package/tests/backend/fetch.test.ts +3 -0
  94. package/tests/backend/port.test.ts +19 -33
  95. package/tests/backend/remote.worker.js +4 -1
  96. package/tests/backend/single-buffer.test.ts +53 -0
  97. package/tests/backend/single-buffer.worker.js +30 -0
  98. package/tests/common/context.test.ts +3 -3
  99. package/tests/common/handle.test.ts +17 -12
  100. package/tests/common/mutex.test.ts +9 -9
  101. package/tests/common/path.test.ts +1 -1
  102. package/tests/common/readline.test.ts +104 -0
  103. package/tests/common.ts +4 -19
  104. package/tests/fetch/fetch.ts +2 -2
  105. package/tests/fs/append.test.ts +4 -4
  106. package/tests/fs/directory.test.ts +25 -25
  107. package/tests/fs/errors.test.ts +15 -19
  108. package/tests/fs/links.test.ts +4 -3
  109. package/tests/fs/open.test.ts +4 -21
  110. package/tests/fs/permissions.test.ts +14 -18
  111. package/tests/fs/read.test.ts +10 -9
  112. package/tests/fs/readFile.test.ts +10 -26
  113. package/tests/fs/rename.test.ts +4 -9
  114. package/tests/fs/stat.test.ts +8 -8
  115. package/tests/fs/streams.test.ts +2 -11
  116. package/tests/fs/times.test.ts +7 -7
  117. package/tests/fs/truncate.test.ts +8 -36
  118. package/tests/fs/watch.test.ts +10 -10
  119. package/tests/fs/write.test.ts +77 -13
  120. package/tests/fs/xattr.test.ts +85 -0
  121. package/tests/logs.js +22 -0
  122. package/tests/setup/context.ts +1 -1
  123. package/tests/setup/index.ts +3 -3
  124. package/tests/setup/port.ts +7 -1
  125. package/dist/backends/port/fs.d.ts +0 -84
  126. package/dist/backends/port/fs.js +0 -151
  127. package/dist/backends/port/rpc.d.ts +0 -77
  128. package/dist/backends/port/rpc.js +0 -100
  129. package/dist/backends/store/simple.d.ts +0 -20
  130. package/dist/backends/store/simple.js +0 -13
  131. package/dist/internal/file.d.ts +0 -359
  132. package/dist/internal/file.js +0 -751
  133. package/dist/internal/log.d.ts +0 -133
  134. package/dist/internal/log.js +0 -218
  135. package/tests/fs/writeFile.test.ts +0 -70
@@ -1,7 +1,8 @@
1
+ import type { UUID } from 'node:crypto';
1
2
  import { Resource } from 'utilium/cache.js';
3
+ import type { UsageInfo } from '../../internal/filesystem.js';
2
4
  import '../../polyfills.js';
3
5
  import type { StoreFS } from './fs.js';
4
- import type { UsageInfo } from '../../internal/filesystem.js';
5
6
  /**
6
7
  * @category Stores and Transactions
7
8
  */
@@ -16,7 +17,7 @@ export interface Store {
16
17
  /**
17
18
  * @see FileSystem#id
18
19
  */
19
- readonly id?: number;
20
+ readonly type?: number;
20
21
  /**
21
22
  * What the file system using this store should be called.
22
23
  * For example, tmpfs for an in memory store
@@ -28,19 +29,13 @@ export interface Store {
28
29
  */
29
30
  readonly label?: string;
30
31
  /**
31
- * Syncs the store
32
- */
33
- sync(): Promise<void>;
34
- /**
35
- * Empties the store completely.
36
- * @deprecated
32
+ * A UUID for this instance of the store.
37
33
  */
38
- clear?(): Promise<void> | void;
34
+ readonly uuid?: UUID;
39
35
  /**
40
- * Empties the store completely.
41
- * @deprecated
36
+ * Syncs the store
42
37
  */
43
- clearSync?(): void;
38
+ sync(): Promise<void>;
44
39
  /**
45
40
  * Begins a new transaction.
46
41
  */
@@ -56,7 +51,7 @@ export interface Store {
56
51
  /**
57
52
  * @internal @hidden
58
53
  */
59
- _fs?: StoreFS;
54
+ fs?: StoreFS;
60
55
  }
61
56
  /**
62
57
  * A transaction for a store.
@@ -174,8 +169,8 @@ export declare class WrappedTransaction<T extends Store = Store> {
174
169
  keys(): Promise<Iterable<number>>;
175
170
  get(id: number, offset?: number, end?: number): Promise<Uint8Array | undefined>;
176
171
  getSync(id: number, offset?: number, end?: number): Uint8Array | undefined;
177
- set(id: number, data: Uint8Array, offset?: number): Promise<void>;
178
- setSync(id: number, data: Uint8Array, offset?: number): void;
172
+ set(id: number, view: Uint8Array | ArrayBufferView, offset?: number): Promise<void>;
173
+ setSync(id: number, view: Uint8Array | ArrayBufferView, offset?: number): void;
179
174
  remove(id: number): Promise<void>;
180
175
  removeSync(id: number): void;
181
176
  commit(): Promise<void>;
@@ -1,6 +1,6 @@
1
+ import { withErrno } from 'kerium';
2
+ import { warn } from 'kerium/log';
1
3
  import { Resource } from 'utilium/cache.js';
2
- import { ErrnoError } from '../../internal/error.js';
3
- import { err, warn } from '../../internal/log.js';
4
4
  import '../../polyfills.js';
5
5
  /**
6
6
  * A transaction for a store.
@@ -62,7 +62,6 @@ export class AsyncTransaction extends Transaction {
62
62
  return resource;
63
63
  }
64
64
  getSync(id, offset, end) {
65
- var _a;
66
65
  const resource = this._cached(id);
67
66
  if (!resource)
68
67
  return;
@@ -72,7 +71,7 @@ export class AsyncTransaction extends Transaction {
72
71
  this.async(this.get(id, start, end));
73
72
  }
74
73
  if (missing.length)
75
- throw err(ErrnoError.With('EAGAIN', (_a = this.store._fs) === null || _a === void 0 ? void 0 : _a._path(id)));
74
+ throw withErrno('EAGAIN');
76
75
  const region = resource.regionAt(offset);
77
76
  if (!region) {
78
77
  warn('Missing cache region for ' + id);
@@ -130,13 +129,15 @@ export class WrappedTransaction {
130
129
  this.stash(id);
131
130
  return data;
132
131
  }
133
- async set(id, data, offset = 0) {
134
- await this.markModified(id, offset, data.byteLength);
135
- await this.raw.set(id, data, offset);
132
+ async set(id, view, offset = 0) {
133
+ await this.markModified(id, offset, view.byteLength);
134
+ const buffer = view instanceof Uint8Array ? view : new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
135
+ await this.raw.set(id, buffer, offset);
136
136
  }
137
- setSync(id, data, offset = 0) {
138
- this.markModifiedSync(id, offset, data.byteLength);
139
- this.raw.setSync(id, data, offset);
137
+ setSync(id, view, offset = 0) {
138
+ this.markModifiedSync(id, offset, view.byteLength);
139
+ const buffer = view instanceof Uint8Array ? view : new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
140
+ this.raw.setSync(id, buffer, offset);
140
141
  }
141
142
  async remove(id) {
142
143
  await this.markModified(id, 0, undefined);
package/dist/config.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { Backend, BackendConfiguration, FilesystemOf, SharedConfig } from './backends/backend.js';
2
2
  import type { Device, DeviceDriver } from './internal/devices.js';
3
- import type { LogConfiguration } from './internal/log.js';
3
+ import { log } from 'kerium';
4
4
  /**
5
5
  * Configuration for a specific mount point
6
6
  * @category Backends and Configuration
@@ -52,28 +52,19 @@ export interface Configuration<T extends ConfigMounts> extends SharedConfig {
52
52
  * @default false
53
53
  */
54
54
  disableAccessChecks: boolean;
55
- /**
56
- * If true, disables `read` and `readSync` from updating the atime.
57
- *
58
- * This can increase performance.
59
- * @experimental
60
- * @default false
61
- */
62
- disableUpdateOnRead: boolean;
63
55
  /**
64
56
  * If true, files will only sync to the file system when closed.
57
+ * This overrides `disableUpdateOnRead`
65
58
  *
66
59
  * This can increase performance.
67
60
  * @experimental
68
- * @overrides `disableUpdateOnRead`
69
61
  * @default false
70
62
  */
71
63
  onlySyncOnClose: boolean;
72
64
  /**
73
65
  * Configurations options for the log.
74
- * @experimental
75
66
  */
76
- log: LogConfiguration;
67
+ log: log.Configuration;
77
68
  }
78
69
  /**
79
70
  * Configures ZenFS with single mount point /
package/dist/config.js CHANGED
@@ -1,10 +1,10 @@
1
+ import { log, withErrno } from 'kerium';
1
2
  import { checkOptions, isBackend, isBackendConfig } from './backends/backend.js';
2
- import { useCredentials } from './internal/credentials.js';
3
+ import { defaultContext } from './internal/contexts.js';
4
+ import { createCredentials } from './internal/credentials.js';
3
5
  import { DeviceFS } from './internal/devices.js';
4
- import { Errno, ErrnoError } from './internal/error.js';
5
6
  import { FileSystem } from './internal/filesystem.js';
6
- import { configure as configureLog, crit, err, info } from './internal/log.js';
7
- import { config } from './vfs/config.js';
7
+ import { _setAccessChecks } from './vfs/config.js';
8
8
  import * as fs from './vfs/index.js';
9
9
  import { mounts } from './vfs/shared.js';
10
10
  function isMountConfig(arg) {
@@ -17,10 +17,10 @@ function isMountConfig(arg) {
17
17
  */
18
18
  export async function resolveMountConfig(configuration, _depth = 0) {
19
19
  if (typeof configuration !== 'object' || configuration == null) {
20
- throw err(new ErrnoError(Errno.EINVAL, 'Invalid options on mount configuration'));
20
+ throw log.err(withErrno('EINVAL', 'Invalid options on mount configuration'));
21
21
  }
22
22
  if (!isMountConfig(configuration)) {
23
- throw err(new ErrnoError(Errno.EINVAL, 'Invalid mount configuration'));
23
+ throw log.err(withErrno('EINVAL', 'Invalid mount configuration'));
24
24
  }
25
25
  if (configuration instanceof FileSystem) {
26
26
  await configuration.ready();
@@ -34,20 +34,20 @@ export async function resolveMountConfig(configuration, _depth = 0) {
34
34
  continue;
35
35
  if (!isMountConfig(value))
36
36
  continue;
37
- info('Resolving nested mount configuration: ' + key);
37
+ log.info('Resolving nested mount configuration: ' + key);
38
38
  if (_depth > 10) {
39
- throw err(new ErrnoError(Errno.EINVAL, 'Invalid configuration, too deep and possibly infinite'));
39
+ throw log.err(withErrno('EINVAL', 'Invalid configuration, too deep and possibly infinite'));
40
40
  }
41
41
  configuration[key] = await resolveMountConfig(value, ++_depth);
42
42
  }
43
43
  const { backend } = configuration;
44
- if (typeof backend.isAvailable == 'function' && !(await backend.isAvailable())) {
45
- throw err(new ErrnoError(Errno.EPERM, 'Backend not available: ' + backend.name));
44
+ if (typeof backend.isAvailable == 'function' && !(await backend.isAvailable(configuration))) {
45
+ throw log.err(withErrno('EPERM', 'Backend not available: ' + backend.name));
46
46
  }
47
- await checkOptions(backend, configuration);
47
+ checkOptions(backend, configuration);
48
48
  const mount = (await backend.create(configuration));
49
49
  if (configuration.disableAsyncCache)
50
- mount.attributes.set('no_async');
50
+ mount.attributes.set('no_async_preload');
51
51
  await mount.ready();
52
52
  return mount;
53
53
  }
@@ -79,7 +79,7 @@ async function mount(path, mount) {
79
79
  await fs.promises.mkdir(path, { recursive: true });
80
80
  }
81
81
  else if (!stats.isDirectory()) {
82
- throw ErrnoError.With('ENOTDIR', path, 'configure');
82
+ throw withErrno('ENOTDIR', 'Missing directory at mount point: ' + path);
83
83
  }
84
84
  fs.mount(path, mount);
85
85
  }
@@ -89,7 +89,7 @@ async function mount(path, mount) {
89
89
  export function addDevice(driver, options) {
90
90
  const devfs = mounts.get('/dev');
91
91
  if (!(devfs instanceof DeviceFS))
92
- throw crit(new ErrnoError(Errno.ENOTSUP, '/dev does not exist or is not a device file system'));
92
+ throw log.crit(withErrno('ENOTSUP', '/dev does not exist or is not a device file system'));
93
93
  return devfs._createDevice(driver, options);
94
94
  }
95
95
  /**
@@ -101,12 +101,10 @@ export async function configure(configuration) {
101
101
  var _a;
102
102
  const uid = 'uid' in configuration ? configuration.uid || 0 : 0;
103
103
  const gid = 'gid' in configuration ? configuration.gid || 0 : 0;
104
- useCredentials({ uid, gid });
105
- config.checkAccess = !configuration.disableAccessChecks;
106
- config.updateOnRead = !configuration.disableUpdateOnRead;
107
- config.syncImmediately = !configuration.onlySyncOnClose;
104
+ Object.assign(defaultContext.credentials, createCredentials({ uid, gid }));
105
+ _setAccessChecks(!configuration.disableAccessChecks);
108
106
  if (configuration.log)
109
- configureLog(configuration.log);
107
+ log.configure(configuration.log);
110
108
  if (configuration.mounts) {
111
109
  // sort to make sure any root replacement is done first
112
110
  for (const [_point, mountConfig] of Object.entries(configuration.mounts).sort(([a], [b]) => (a.length > b.length ? 1 : -1))) {
package/dist/context.d.ts CHANGED
@@ -1,27 +1,14 @@
1
- import type { CredentialInit, Credentials } from './internal/credentials.js';
2
- import * as fs from './vfs/index.js';
1
+ import type { BoundContext, ContextInit, FSContext, V_Context } from './internal/contexts.js';
2
+ export type { BoundContext, ContextInit, FSContext, V_Context };
3
3
  /**
4
- * Represents some context used for FS operations
5
- * @category Backends and Configuration
4
+ * A map of all contexts.
5
+ * @internal
6
+ * @category Contexts
6
7
  */
7
- export interface FSContext {
8
- root: string;
9
- readonly credentials: Credentials;
10
- }
11
- /**
12
- * maybe an FS context
13
- */
14
- export type V_Context = void | (Partial<FSContext> & object);
15
- /**
16
- * Allows you to restrict operations to a specific root path and set of credentials.
17
- * @category Backends and Configuration
18
- */
19
- export interface BoundContext extends FSContext {
20
- fs: typeof fs;
21
- }
8
+ export declare const boundContexts: Map<number, BoundContext>;
22
9
  /**
23
10
  * Allows you to restrict operations to a specific root path and set of credentials.
24
11
  * Note that the default credentials of a bound context are copied from the global credentials.
25
- * @category Backends and Configuration
12
+ * @category Contexts
26
13
  */
27
- export declare function bindContext(root: string, credentials?: CredentialInit): BoundContext;
14
+ export declare function bindContext(this: void | null | FSContext, { root, pwd, credentials }?: ContextInit): BoundContext;
package/dist/context.js CHANGED
@@ -1,23 +1,46 @@
1
- import { createCredentials, credentials as defaultCredentials } from './internal/credentials.js';
1
+ import { bindFunctions } from 'utilium';
2
+ import { defaultContext } from './internal/contexts.js';
3
+ import { createCredentials } from './internal/credentials.js';
4
+ import * as path from './path.js';
2
5
  import * as fs from './vfs/index.js';
6
+ // 0 is reserved for the global/default context
7
+ let _nextId = 1;
3
8
  /**
4
- * Binds a this value for all of the functions in an object (not recursive)
9
+ * A map of all contexts.
5
10
  * @internal
11
+ * @category Contexts
6
12
  */
7
- function _bindFunctions(fns, thisValue) {
8
- return Object.fromEntries(Object.entries(fns).map(([k, v]) => [k, typeof v == 'function' ? v.bind(thisValue) : v]));
9
- }
13
+ export const boundContexts = new Map();
10
14
  /**
11
15
  * Allows you to restrict operations to a specific root path and set of credentials.
12
16
  * Note that the default credentials of a bound context are copied from the global credentials.
13
- * @category Backends and Configuration
17
+ * @category Contexts
14
18
  */
15
- export function bindContext(root, credentials = structuredClone(defaultCredentials)) {
19
+ export function bindContext({ root = (this === null || this === void 0 ? void 0 : this.root) || '/', pwd = (this === null || this === void 0 ? void 0 : this.pwd) || '/', credentials = structuredClone(defaultContext.credentials) } = {}) {
20
+ const parent = this !== null && this !== void 0 ? this : defaultContext;
16
21
  const ctx = {
22
+ id: _nextId++,
17
23
  root,
24
+ pwd,
18
25
  credentials: createCredentials(credentials),
26
+ descriptors: new Map(),
27
+ parent,
28
+ children: [],
29
+ };
30
+ const bound = {
31
+ ...ctx,
32
+ fs: {
33
+ ...bindFunctions(fs, ctx),
34
+ promises: bindFunctions(fs.promises, ctx),
35
+ xattr: bindFunctions(fs.xattr, ctx),
36
+ },
37
+ path: bindFunctions(path, ctx),
38
+ bind: (init) => {
39
+ const child = bindContext.call(ctx, init);
40
+ ctx.children.push(child);
41
+ return child;
42
+ },
19
43
  };
20
- const fn_fs = _bindFunctions(fs, ctx);
21
- const fn_promises = _bindFunctions(fs.promises, ctx);
22
- return { ...ctx, fs: { ...fs, ...fn_fs, promises: { ...fs.promises, ...fn_promises } } };
44
+ boundContexts.set(ctx.id, bound);
45
+ return bound;
23
46
  }
package/dist/index.d.ts CHANGED
@@ -3,8 +3,9 @@ export * from './config.js';
3
3
  export * from './context.js';
4
4
  export * from './internal/index.js';
5
5
  export * from './mixins/index.js';
6
- export * from './stats.js';
6
+ export * from './vfs/stats.js';
7
7
  export * from './utils.js';
8
+ export { mounts } from './vfs/shared.js';
8
9
  export * from './vfs/index.js';
9
10
  export { fs };
10
11
  import * as fs from './vfs/index.js';
package/dist/index.js CHANGED
@@ -3,8 +3,9 @@ export * from './config.js';
3
3
  export * from './context.js';
4
4
  export * from './internal/index.js';
5
5
  export * from './mixins/index.js';
6
- export * from './stats.js';
6
+ export * from './vfs/stats.js';
7
7
  export * from './utils.js';
8
+ export { mounts } from './vfs/shared.js';
8
9
  export * from './vfs/index.js';
9
10
  export { fs };
10
11
  import * as fs from './vfs/index.js';
@@ -0,0 +1,63 @@
1
+ import type { Bound } from 'utilium';
2
+ import type * as path from '../path.js';
3
+ import type { SyncHandle } from '../vfs/file.js';
4
+ import type * as fs from '../vfs/index.js';
5
+ import type { Credentials, CredentialsInit } from './credentials.js';
6
+ /**
7
+ * A context used for FS operations
8
+ * @category Contexts
9
+ */
10
+ export interface FSContext {
11
+ /** The unique ID of the context */
12
+ readonly id: number;
13
+ /**
14
+ * The absolute root path of the context
15
+ *
16
+ * Note the parent's root is not considered
17
+ */
18
+ root: string;
19
+ /** The current working directory of the context */
20
+ pwd: string;
21
+ /** The credentials of the context, used for access checks */
22
+ readonly credentials: Credentials;
23
+ /** A map of open file descriptors to their handles */
24
+ descriptors: Map<number, SyncHandle>;
25
+ /** The parent context, if any. */
26
+ parent: V_Context;
27
+ /** The child contexts */
28
+ children: FSContext[];
29
+ }
30
+ /**
31
+ * maybe an FS context
32
+ */
33
+ export type V_Context = void | null | (Partial<FSContext> & object);
34
+ /**
35
+ * Allows you to restrict operations to a specific root path and set of credentials.
36
+ * @category Contexts
37
+ */
38
+ export interface BoundContext extends FSContext {
39
+ fs: Bound<typeof fs, FSContext> & {
40
+ promises: Bound<typeof fs.promises, FSContext>;
41
+ xattr: Bound<typeof fs.xattr, FSContext>;
42
+ };
43
+ /** Path functions, bound to the context */
44
+ path: Bound<typeof path, FSContext>;
45
+ /** Creates a new child context with this context as the parent */
46
+ bind(init: ContextInit): BoundContext;
47
+ /** The parent context, if any. */
48
+ parent: FSContext;
49
+ }
50
+ /**
51
+ * @category Contexts
52
+ */
53
+ export interface ContextInit {
54
+ root?: string;
55
+ pwd?: string;
56
+ credentials?: CredentialsInit;
57
+ }
58
+ /**
59
+ * The default/global context.
60
+ * @internal @hidden
61
+ * @category Contexts
62
+ */
63
+ export declare const defaultContext: FSContext;
@@ -0,0 +1,15 @@
1
+ import { createCredentials } from './credentials.js';
2
+ /**
3
+ * The default/global context.
4
+ * @internal @hidden
5
+ * @category Contexts
6
+ */
7
+ export const defaultContext = {
8
+ id: 0,
9
+ root: '/',
10
+ pwd: '/',
11
+ credentials: createCredentials({ uid: 0, gid: 0 }),
12
+ descriptors: new Map(),
13
+ parent: null,
14
+ children: [],
15
+ };
@@ -16,24 +16,15 @@ export interface Credentials {
16
16
  */
17
17
  groups: number[];
18
18
  }
19
- /**
20
- * @category Internals
21
- */
22
- export declare const credentials: Credentials;
23
19
  /**
24
20
  * Initialization for a set of credentials
25
21
  * @category Internals
26
22
  */
27
- export interface CredentialInit extends Partial<Credentials> {
23
+ export interface CredentialsInit extends Partial<Credentials> {
28
24
  uid: number;
29
25
  gid: number;
30
26
  }
31
27
  /**
32
28
  * @category Internals
33
29
  */
34
- export declare function createCredentials(source: CredentialInit): Credentials;
35
- /**
36
- * Uses credentials from the provided uid and gid.
37
- * @category Internals
38
- */
39
- export declare function useCredentials(source: CredentialInit): void;
30
+ export declare function createCredentials(source: CredentialsInit): Credentials;
@@ -1,15 +1,3 @@
1
- /**
2
- * @category Internals
3
- */
4
- export const credentials = {
5
- uid: 0,
6
- gid: 0,
7
- suid: 0,
8
- sgid: 0,
9
- euid: 0,
10
- egid: 0,
11
- groups: [],
12
- };
13
1
  /**
14
2
  * @category Internals
15
3
  */
@@ -23,10 +11,3 @@ export function createCredentials(source) {
23
11
  ...source,
24
12
  };
25
13
  }
26
- /**
27
- * Uses credentials from the provided uid and gid.
28
- * @category Internals
29
- */
30
- export function useCredentials(source) {
31
- Object.assign(credentials, createCredentials(source));
32
- }
@@ -1,10 +1,7 @@
1
1
  import { InMemoryStore } from '../backends/memory.js';
2
2
  import { StoreFS } from '../backends/store/fs.js';
3
- import { Stats } from '../stats.js';
4
- import type { FileReadResult } from './file.js';
5
- import { File } from './file.js';
6
3
  import type { CreationOptions } from './filesystem.js';
7
- import { Inode } from './inode.js';
4
+ import { Inode, type InodeLike } from './inode.js';
8
5
  /**
9
6
  * A device
10
7
  * @todo Maybe add some other device information, like a UUID?
@@ -18,9 +15,9 @@ export interface Device<TData = any> {
18
15
  */
19
16
  driver: DeviceDriver<TData>;
20
17
  /**
21
- * Which inode the device is assigned
18
+ * Device metadata
22
19
  */
23
- ino: number;
20
+ inode: Inode;
24
21
  /**
25
22
  * Data associated with a device.
26
23
  * This is meant to be used by device drivers.
@@ -43,6 +40,7 @@ export interface DeviceInit<TData = any> {
43
40
  minor?: number;
44
41
  major?: number;
45
42
  name?: string;
43
+ metadata?: Partial<InodeLike>;
46
44
  }
47
45
  /**
48
46
  * A device driver
@@ -58,89 +56,34 @@ export interface DeviceDriver<TData = any> {
58
56
  * Note that if this is unset or false, auto-named devices will have a number suffix
59
57
  */
60
58
  singleton?: boolean;
61
- /**
62
- * Whether the device is buffered (a "block" device) or unbuffered (a "character" device)
63
- * @default false
64
- */
65
- isBuffered?: boolean;
66
59
  /**
67
60
  * Initializes a new device.
68
61
  * @returns `Device.data`
69
62
  */
70
63
  init?(ino: number, options: object): DeviceInit<TData>;
71
- /**
72
- * Synchronously read from a device file
73
- * @group File operations
74
- * @deprecated
75
- * @todo [BREAKING] Remove
76
- */
77
- read?(file: DeviceFile<TData>, buffer: ArrayBufferView, offset?: number, length?: number, position?: number): number;
78
64
  /**
79
65
  * Synchronously read from a device.
80
66
  * @privateRemarks
81
67
  * For many devices there is no concept of an offset or end.
82
68
  * For example, /dev/random will be "the same" regardless of where you read from- random data.
83
69
  * @group File operations
84
- * @todo [BREAKING] Rename to `read`
85
70
  */
86
- readD(device: Device<TData>, buffer: Uint8Array, offset: number, end: number): void;
87
- /**
88
- * Synchronously write to a device file
89
- * @group File operations
90
- * @deprecated
91
- * @todo [BREAKING] Remove
92
- */
93
- write?(file: DeviceFile<TData>, buffer: Uint8Array, offset: number, length: number, position?: number): number;
71
+ read(device: Device<TData>, buffer: Uint8Array, offset: number, end: number): void;
94
72
  /**
95
73
  * Synchronously write to a device
96
74
  * @group File operations
97
- * @todo [BREAKING] Rename to `write`
98
75
  */
99
- writeD(device: Device<TData>, buffer: Uint8Array, offset: number): void;
76
+ write(device: Device<TData>, buffer: Uint8Array, offset: number): void;
100
77
  /**
101
78
  * Sync the device
102
79
  * @group File operations
103
80
  */
104
- sync?(file: DeviceFile<TData>): void;
81
+ sync?(device: Device<TData>): void;
105
82
  /**
106
83
  * Close the device
107
84
  * @group File operations
108
85
  */
109
- close?(file: DeviceFile<TData>): void;
110
- }
111
- /**
112
- * The base class for device files
113
- * This class only does some simple things:
114
- * It implements `truncate` using `write` and it has non-device methods throw.
115
- * It is up to device drivers to implement the rest of the functionality.
116
- * @category Internals
117
- * @internal
118
- */
119
- export declare class DeviceFile<TData = any> extends File {
120
- fs: DeviceFS;
121
- readonly device: Device<TData>;
122
- position: number;
123
- constructor(fs: DeviceFS, path: string, device: Device<TData>);
124
- get driver(): DeviceDriver<TData>;
125
- protected stats: Inode;
126
- stat(): Promise<Stats>;
127
- statSync(): Stats;
128
- readSync(buffer: ArrayBufferView, offset?: number, length?: number, position?: number): number;
129
- read<TBuffer extends ArrayBufferView>(buffer: TBuffer, offset?: number, length?: number): Promise<FileReadResult<TBuffer>>;
130
- writeSync(buffer: Uint8Array, offset?: number, length?: number, position?: number): number;
131
- write(buffer: Uint8Array, offset?: number, length?: number, position?: number): Promise<number>;
132
- truncate(length: number): Promise<void>;
133
- truncateSync(length: number): void;
134
- closeSync(): void;
135
- close(): Promise<void>;
136
- syncSync(): void;
137
- sync(): Promise<void>;
138
- chown(): Promise<void>;
139
- chownSync(): void;
140
- chmod(): Promise<void>;
141
- chmodSync(): void;
142
- utimes(): Promise<void>;
143
- utimesSync(): void;
86
+ close?(file: Device<TData>): void;
144
87
  }
145
88
  /**
146
89
  * A temporary file system that manages and interfaces with devices
@@ -148,11 +91,6 @@ export declare class DeviceFile<TData = any> extends File {
148
91
  */
149
92
  export declare class DeviceFS extends StoreFS<InMemoryStore> {
150
93
  protected readonly devices: Map<string, Device<any>>;
151
- /**
152
- * Creates a new device at `path` relative to the `DeviceFS` root.
153
- * @deprecated
154
- */
155
- createDevice<TData = any>(path: string, driver: DeviceDriver<TData>, options?: object): Device<TData | Record<string, never>>;
156
94
  protected devicesWithDriver(driver: DeviceDriver<unknown> | string, forceIdentity?: boolean): Device[];
157
95
  /**
158
96
  * @internal
@@ -165,24 +103,24 @@ export declare class DeviceFS extends StoreFS<InMemoryStore> {
165
103
  constructor();
166
104
  rename(oldPath: string, newPath: string): Promise<void>;
167
105
  renameSync(oldPath: string, newPath: string): void;
168
- stat(path: string): Promise<Stats>;
169
- statSync(path: string): Stats;
170
- openFile(path: string, flag: string): Promise<File>;
171
- openFileSync(path: string, flag: string): File;
172
- createFile(path: string, flag: string, mode: number, options: CreationOptions): Promise<File>;
173
- createFileSync(path: string, flag: string, mode: number, options: CreationOptions): File;
106
+ stat(path: string): Promise<InodeLike>;
107
+ statSync(path: string): InodeLike;
108
+ touch(path: string, metadata: InodeLike): Promise<void>;
109
+ touchSync(path: string, metadata: InodeLike): void;
110
+ createFile(path: string, options: CreationOptions): Promise<InodeLike>;
111
+ createFileSync(path: string, options: CreationOptions): InodeLike;
174
112
  unlink(path: string): Promise<void>;
175
113
  unlinkSync(path: string): void;
176
114
  rmdir(path: string): Promise<void>;
177
115
  rmdirSync(path: string): void;
178
- mkdir(path: string, mode: number, options: CreationOptions): Promise<void>;
179
- mkdirSync(path: string, mode: number, options: CreationOptions): void;
116
+ mkdir(path: string, options: CreationOptions): Promise<InodeLike>;
117
+ mkdirSync(path: string, options: CreationOptions): InodeLike;
180
118
  readdir(path: string): Promise<string[]>;
181
119
  readdirSync(path: string): string[];
182
120
  link(target: string, link: string): Promise<void>;
183
121
  linkSync(target: string, link: string): void;
184
- sync(path: string, data: Uint8Array, stats: Readonly<Stats>): Promise<void>;
185
- syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
122
+ sync(): Promise<void>;
123
+ syncSync(): void;
186
124
  read(path: string, buffer: Uint8Array, offset: number, end: number): Promise<void>;
187
125
  readSync(path: string, buffer: Uint8Array, offset: number, end: number): void;
188
126
  write(path: string, data: Uint8Array, offset: number): Promise<void>;