@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.
- package/dist/backends/backend.d.ts +19 -15
- package/dist/backends/backend.js +36 -19
- package/dist/backends/cow.d.ts +20 -30
- package/dist/backends/cow.js +83 -192
- package/dist/backends/fetch.d.ts +1 -0
- package/dist/backends/fetch.js +30 -30
- package/dist/backends/index.d.ts +1 -1
- package/dist/backends/index.js +1 -1
- package/dist/backends/memory.d.ts +5 -7
- package/dist/backends/memory.js +2 -3
- package/dist/backends/passthrough.d.ts +19 -23
- package/dist/backends/passthrough.js +98 -288
- package/dist/backends/port.d.ts +220 -0
- package/dist/backends/port.js +328 -0
- package/dist/backends/single_buffer.d.ts +59 -47
- package/dist/backends/single_buffer.js +468 -219
- package/dist/backends/store/fs.d.ts +25 -35
- package/dist/backends/store/fs.js +276 -315
- package/dist/backends/store/store.d.ts +10 -15
- package/dist/backends/store/store.js +11 -10
- package/dist/config.d.ts +3 -12
- package/dist/config.js +17 -19
- package/dist/context.d.ts +8 -21
- package/dist/context.js +33 -10
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/internal/contexts.d.ts +63 -0
- package/dist/internal/contexts.js +15 -0
- package/dist/internal/credentials.d.ts +2 -11
- package/dist/internal/credentials.js +0 -19
- package/dist/internal/devices.d.ts +18 -80
- package/dist/internal/devices.js +103 -316
- package/dist/internal/error.d.ts +9 -204
- package/dist/internal/error.js +19 -288
- package/dist/internal/file_index.d.ts +1 -1
- package/dist/internal/file_index.js +11 -11
- package/dist/internal/filesystem.d.ts +51 -94
- package/dist/internal/filesystem.js +21 -20
- package/dist/internal/index.d.ts +1 -2
- package/dist/internal/index.js +1 -2
- package/dist/internal/index_fs.d.ts +12 -30
- package/dist/internal/index_fs.js +37 -69
- package/dist/internal/inode.d.ts +140 -24
- package/dist/internal/inode.js +515 -66
- package/dist/mixins/async.js +52 -112
- package/dist/mixins/mutexed.d.ts +19 -18
- package/dist/mixins/mutexed.js +62 -64
- package/dist/mixins/readonly.d.ts +7 -6
- package/dist/mixins/readonly.js +24 -18
- package/dist/mixins/sync.js +8 -8
- package/dist/{vfs/path.d.ts → path.d.ts} +3 -4
- package/dist/{vfs/path.js → path.js} +6 -9
- package/dist/polyfills.js +1 -1
- package/dist/readline.d.ts +134 -0
- package/dist/readline.js +623 -0
- package/dist/utils.d.ts +9 -37
- package/dist/utils.js +17 -85
- package/dist/vfs/acl.d.ts +42 -0
- package/dist/vfs/acl.js +268 -0
- package/dist/vfs/async.d.ts +9 -23
- package/dist/vfs/async.js +25 -27
- package/dist/vfs/config.d.ts +6 -18
- package/dist/vfs/config.js +8 -18
- package/dist/vfs/dir.d.ts +3 -3
- package/dist/vfs/dir.js +12 -12
- package/dist/vfs/file.d.ts +106 -0
- package/dist/vfs/file.js +244 -0
- package/dist/vfs/flags.d.ts +19 -0
- package/dist/vfs/flags.js +62 -0
- package/dist/vfs/index.d.ts +4 -10
- package/dist/vfs/index.js +4 -13
- package/dist/vfs/ioctl.d.ts +88 -0
- package/dist/vfs/ioctl.js +409 -0
- package/dist/vfs/promises.d.ts +81 -19
- package/dist/vfs/promises.js +404 -288
- package/dist/vfs/shared.d.ts +7 -37
- package/dist/vfs/shared.js +29 -85
- package/dist/{stats.d.ts → vfs/stats.d.ts} +14 -28
- package/dist/{stats.js → vfs/stats.js} +11 -66
- package/dist/vfs/streams.d.ts +1 -0
- package/dist/vfs/streams.js +32 -27
- package/dist/vfs/sync.d.ts +3 -3
- package/dist/vfs/sync.js +263 -260
- package/dist/vfs/watchers.d.ts +2 -2
- package/dist/vfs/watchers.js +12 -12
- package/dist/vfs/xattr.d.ts +116 -0
- package/dist/vfs/xattr.js +201 -0
- package/package.json +5 -3
- package/readme.md +1 -1
- package/scripts/test.js +2 -2
- package/tests/assignment.ts +1 -1
- package/tests/backend/config.worker.js +4 -1
- package/tests/backend/fetch.test.ts +3 -0
- package/tests/backend/port.test.ts +19 -33
- package/tests/backend/remote.worker.js +4 -1
- package/tests/backend/single-buffer.test.ts +53 -0
- package/tests/backend/single-buffer.worker.js +30 -0
- package/tests/common/context.test.ts +3 -3
- package/tests/common/handle.test.ts +17 -12
- package/tests/common/mutex.test.ts +9 -9
- package/tests/common/path.test.ts +1 -1
- package/tests/common/readline.test.ts +104 -0
- package/tests/common.ts +4 -19
- package/tests/fetch/fetch.ts +2 -2
- package/tests/fs/append.test.ts +4 -4
- package/tests/fs/directory.test.ts +25 -25
- package/tests/fs/errors.test.ts +15 -19
- package/tests/fs/links.test.ts +4 -3
- package/tests/fs/open.test.ts +4 -21
- package/tests/fs/permissions.test.ts +14 -18
- package/tests/fs/read.test.ts +10 -9
- package/tests/fs/readFile.test.ts +10 -26
- package/tests/fs/rename.test.ts +4 -9
- package/tests/fs/stat.test.ts +8 -8
- package/tests/fs/streams.test.ts +2 -11
- package/tests/fs/times.test.ts +7 -7
- package/tests/fs/truncate.test.ts +8 -36
- package/tests/fs/watch.test.ts +10 -10
- package/tests/fs/write.test.ts +77 -13
- package/tests/fs/xattr.test.ts +85 -0
- package/tests/logs.js +22 -0
- package/tests/setup/context.ts +1 -1
- package/tests/setup/index.ts +3 -3
- package/tests/setup/port.ts +7 -1
- package/dist/backends/port/fs.d.ts +0 -84
- package/dist/backends/port/fs.js +0 -151
- package/dist/backends/port/rpc.d.ts +0 -77
- package/dist/backends/port/rpc.js +0 -100
- package/dist/backends/store/simple.d.ts +0 -20
- package/dist/backends/store/simple.js +0 -13
- package/dist/internal/file.d.ts +0 -359
- package/dist/internal/file.js +0 -751
- package/dist/internal/log.d.ts +0 -133
- package/dist/internal/log.js +0 -218
- 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
|
|
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
|
-
*
|
|
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
|
-
|
|
34
|
+
readonly uuid?: UUID;
|
|
39
35
|
/**
|
|
40
|
-
*
|
|
41
|
-
* @deprecated
|
|
36
|
+
* Syncs the store
|
|
42
37
|
*/
|
|
43
|
-
|
|
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
|
-
|
|
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,
|
|
178
|
-
setSync(id: number,
|
|
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
|
|
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,
|
|
134
|
-
await this.markModified(id, offset,
|
|
135
|
-
|
|
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,
|
|
138
|
-
this.markModifiedSync(id, offset,
|
|
139
|
-
|
|
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
|
|
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:
|
|
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 {
|
|
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 {
|
|
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(
|
|
20
|
+
throw log.err(withErrno('EINVAL', 'Invalid options on mount configuration'));
|
|
21
21
|
}
|
|
22
22
|
if (!isMountConfig(configuration)) {
|
|
23
|
-
throw err(
|
|
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(
|
|
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(
|
|
44
|
+
if (typeof backend.isAvailable == 'function' && !(await backend.isAvailable(configuration))) {
|
|
45
|
+
throw log.err(withErrno('EPERM', 'Backend not available: ' + backend.name));
|
|
46
46
|
}
|
|
47
|
-
|
|
47
|
+
checkOptions(backend, configuration);
|
|
48
48
|
const mount = (await backend.create(configuration));
|
|
49
49
|
if (configuration.disableAsyncCache)
|
|
50
|
-
mount.attributes.set('
|
|
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
|
|
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(
|
|
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
|
-
|
|
105
|
-
|
|
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
|
-
|
|
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 {
|
|
2
|
-
|
|
1
|
+
import type { BoundContext, ContextInit, FSContext, V_Context } from './internal/contexts.js';
|
|
2
|
+
export type { BoundContext, ContextInit, FSContext, V_Context };
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* @
|
|
4
|
+
* A map of all contexts.
|
|
5
|
+
* @internal
|
|
6
|
+
* @category Contexts
|
|
6
7
|
*/
|
|
7
|
-
export
|
|
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
|
|
12
|
+
* @category Contexts
|
|
26
13
|
*/
|
|
27
|
-
export declare function bindContext(
|
|
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 {
|
|
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
|
-
*
|
|
9
|
+
* A map of all contexts.
|
|
5
10
|
* @internal
|
|
11
|
+
* @category Contexts
|
|
6
12
|
*/
|
|
7
|
-
|
|
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
|
|
17
|
+
* @category Contexts
|
|
14
18
|
*/
|
|
15
|
-
export function bindContext(root, credentials = structuredClone(
|
|
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
|
-
|
|
21
|
-
|
|
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
|
|
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:
|
|
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
|
-
*
|
|
18
|
+
* Device metadata
|
|
22
19
|
*/
|
|
23
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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?(
|
|
81
|
+
sync?(device: Device<TData>): void;
|
|
105
82
|
/**
|
|
106
83
|
* Close the device
|
|
107
84
|
* @group File operations
|
|
108
85
|
*/
|
|
109
|
-
close?(file:
|
|
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<
|
|
169
|
-
statSync(path: string):
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
createFile(path: string,
|
|
173
|
-
createFileSync(path: string,
|
|
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,
|
|
179
|
-
mkdirSync(path: string,
|
|
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(
|
|
185
|
-
syncSync(
|
|
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>;
|