@zenfs/core 1.8.8 → 1.9.1
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 +1 -1
- package/dist/backends/backend.js +7 -4
- package/dist/backends/fetch.d.ts +23 -32
- package/dist/backends/fetch.js +94 -134
- package/dist/backends/index.d.ts +1 -4
- package/dist/backends/index.js +1 -4
- package/dist/backends/memory.d.ts +7 -5
- package/dist/backends/memory.js +6 -4
- package/dist/backends/overlay.d.ts +4 -5
- package/dist/backends/overlay.js +16 -20
- package/dist/backends/passthrough.d.ts +3 -3
- package/dist/backends/passthrough.js +4 -6
- package/dist/backends/port/fs.d.ts +4 -5
- package/dist/backends/port/fs.js +7 -12
- package/dist/backends/port/rpc.d.ts +1 -1
- package/dist/backends/port/rpc.js +15 -13
- package/dist/backends/store/fs.d.ts +51 -40
- package/dist/backends/store/fs.js +347 -241
- package/dist/backends/store/map.d.ts +41 -0
- package/dist/backends/store/map.js +45 -0
- package/dist/backends/store/simple.d.ts +10 -58
- package/dist/backends/store/simple.js +8 -115
- package/dist/backends/store/store.d.ts +111 -44
- package/dist/backends/store/store.js +230 -38
- package/dist/config.d.ts +7 -3
- package/dist/config.js +17 -14
- package/dist/context.d.ts +1 -1
- package/dist/context.js +1 -1
- package/dist/index.d.ts +1 -5
- package/dist/index.js +1 -5
- package/dist/{devices.d.ts → internal/devices.d.ts} +4 -4
- package/dist/{devices.js → internal/devices.js} +18 -14
- package/dist/{file.d.ts → internal/file.d.ts} +3 -2
- package/dist/{file.js → internal/file.js} +17 -12
- package/dist/{backends/store → internal}/file_index.d.ts +13 -3
- package/dist/{backends/store → internal}/file_index.js +28 -5
- package/dist/{filesystem.d.ts → internal/filesystem.d.ts} +99 -32
- package/dist/internal/filesystem.js +83 -0
- package/dist/internal/index.d.ts +9 -0
- package/dist/internal/index.js +9 -0
- package/dist/internal/index_fs.d.ts +56 -0
- package/dist/internal/index_fs.js +188 -0
- package/dist/{backends/store → internal}/inode.d.ts +6 -1
- package/dist/{backends/store → internal}/inode.js +14 -6
- package/dist/internal/log.d.ts +132 -0
- package/dist/internal/log.js +177 -0
- package/dist/mixins/async.d.ts +2 -2
- package/dist/mixins/async.js +19 -16
- package/dist/mixins/mutexed.d.ts +9 -3
- package/dist/mixins/mutexed.js +22 -3
- package/dist/mixins/readonly.d.ts +2 -2
- package/dist/mixins/readonly.js +4 -3
- package/dist/mixins/shared.d.ts +1 -1
- package/dist/mixins/sync.d.ts +2 -2
- package/dist/stats.d.ts +2 -3
- package/dist/stats.js +7 -5
- package/dist/utils.d.ts +2 -15
- package/dist/utils.js +10 -47
- package/dist/vfs/async.d.ts +2 -2
- package/dist/vfs/async.js +3 -3
- package/dist/vfs/dir.js +1 -1
- package/dist/vfs/promises.d.ts +6 -6
- package/dist/vfs/promises.js +54 -49
- package/dist/vfs/shared.d.ts +3 -3
- package/dist/vfs/shared.js +16 -10
- package/dist/vfs/streams.js +1 -1
- package/dist/vfs/sync.d.ts +1 -2
- package/dist/vfs/sync.js +14 -15
- package/dist/vfs/types.d.ts +1 -0
- package/dist/vfs/watchers.d.ts +5 -1
- package/dist/vfs/watchers.js +16 -19
- package/package.json +3 -3
- package/readme.md +12 -12
- package/scripts/test.js +15 -3
- package/tests/backend/fetch.test.ts +49 -0
- package/tests/backend/port.test.ts +130 -0
- package/tests/common/context.test.ts +9 -4
- package/tests/common.ts +21 -3
- package/tests/data/image.jpg +0 -0
- package/tests/data/utf8.txt +1 -0
- package/tests/fetch/config.js +40 -0
- package/tests/fetch/fetch.ts +20 -0
- package/tests/fetch/run.sh +3 -3
- package/tests/fetch/{server.ts → server.js} +15 -11
- package/tests/fs/directory.test.ts +1 -1
- package/tests/fs/errors.test.ts +1 -1
- package/tests/fs/links.test.ts +1 -1
- package/tests/fs/open.test.ts +1 -1
- package/tests/fs/permissions.test.ts +2 -3
- package/tests/fs/rename.test.ts +1 -1
- package/tests/fs/stat.test.ts +1 -1
- package/tests/fs/times.test.ts +1 -1
- package/tests/fs/watch.test.ts +21 -22
- package/tests/fs/writeFile.test.ts +8 -7
- package/tests/readme.md +3 -3
- package/tests/setup/_overlay.ts +7 -0
- package/tests/setup/context.ts +2 -2
- package/tests/setup/index.ts +3 -3
- package/tests/setup/memory.ts +2 -2
- package/tests/setup/port.ts +2 -2
- package/tests/setup.ts +25 -5
- package/tests/tsconfig.json +3 -2
- package/dist/backends/store/index_fs.d.ts +0 -34
- package/dist/backends/store/index_fs.js +0 -67
- package/dist/filesystem.js +0 -52
- package/tests/fetch/cow+fetch.ts +0 -13
- package/tests/port/channel.test.ts +0 -39
- package/tests/port/config.test.ts +0 -30
- package/tests/port/remote.test.ts +0 -32
- package/tests/port/timeout.test.ts +0 -48
- /package/dist/{credentials.d.ts → internal/credentials.d.ts} +0 -0
- /package/dist/{credentials.js → internal/credentials.js} +0 -0
- /package/dist/{error.d.ts → internal/error.d.ts} +0 -0
- /package/dist/{error.js → internal/error.js} +0 -0
- /package/tests/{port → backend}/config.worker.js +0 -0
- /package/tests/{port → backend}/remote.worker.js +0 -0
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Resource } from 'utilium/cache.js';
|
|
2
|
+
import { ErrnoError } from '../../internal/error.js';
|
|
3
|
+
import { err, warn } from '../../internal/log.js';
|
|
2
4
|
import '../../polyfills.js';
|
|
3
5
|
/**
|
|
4
6
|
* A transaction for a store.
|
|
@@ -6,20 +8,6 @@ import '../../polyfills.js';
|
|
|
6
8
|
export class Transaction {
|
|
7
9
|
constructor(store) {
|
|
8
10
|
this.store = store;
|
|
9
|
-
/**
|
|
10
|
-
* Whether the transaction was committed or aborted
|
|
11
|
-
*/
|
|
12
|
-
this.done = false;
|
|
13
|
-
}
|
|
14
|
-
async [Symbol.asyncDispose]() {
|
|
15
|
-
if (this.done)
|
|
16
|
-
return;
|
|
17
|
-
await this.abort();
|
|
18
|
-
}
|
|
19
|
-
[Symbol.dispose]() {
|
|
20
|
-
if (this.done)
|
|
21
|
-
return;
|
|
22
|
-
this.abortSync();
|
|
23
11
|
}
|
|
24
12
|
}
|
|
25
13
|
/**
|
|
@@ -27,45 +15,249 @@ export class Transaction {
|
|
|
27
15
|
*/
|
|
28
16
|
export class SyncTransaction extends Transaction {
|
|
29
17
|
/* eslint-disable @typescript-eslint/require-await */
|
|
30
|
-
async
|
|
31
|
-
return this.
|
|
32
|
-
}
|
|
33
|
-
async get(id) {
|
|
34
|
-
return this.getSync(id);
|
|
18
|
+
async get(id, offset, end) {
|
|
19
|
+
return this.getSync(id, offset, end);
|
|
35
20
|
}
|
|
36
|
-
async set(id, data,
|
|
37
|
-
return this.setSync(id, data,
|
|
21
|
+
async set(id, data, offset) {
|
|
22
|
+
return this.setSync(id, data, offset);
|
|
38
23
|
}
|
|
39
24
|
async remove(id) {
|
|
40
25
|
return this.removeSync(id);
|
|
41
26
|
}
|
|
42
|
-
|
|
43
|
-
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Transaction that implements synchronous operations with a cache
|
|
30
|
+
* @implementors You *must* update the cache and wait for `store.asyncDone` in your asynchronous methods.
|
|
31
|
+
* @todo Make sure we handle abortions correctly, especially since the cache is shared between transactions.
|
|
32
|
+
*/
|
|
33
|
+
export class AsyncTransaction extends Transaction {
|
|
34
|
+
constructor() {
|
|
35
|
+
super(...arguments);
|
|
36
|
+
this.asyncDone = Promise.resolve();
|
|
44
37
|
}
|
|
45
|
-
|
|
46
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Run a asynchronous operation from a sync context. Not magic and subject to (race) conditions.
|
|
40
|
+
* @internal
|
|
41
|
+
*/
|
|
42
|
+
async(promise) {
|
|
43
|
+
this.asyncDone = this.asyncDone.then(() => promise);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Gets a cache resource
|
|
47
|
+
* If `info` is set and the resource doesn't exist, it will be created
|
|
48
|
+
* @internal
|
|
49
|
+
*/
|
|
50
|
+
_cached(id, info) {
|
|
51
|
+
var _a;
|
|
52
|
+
var _b;
|
|
53
|
+
(_a = (_b = this.store).cache) !== null && _a !== void 0 ? _a : (_b.cache = new Map());
|
|
54
|
+
const resource = this.store.cache.get(id);
|
|
55
|
+
if (!resource)
|
|
56
|
+
return !info ? undefined : new Resource(id, info.size, {}, this.store.cache);
|
|
57
|
+
if (info)
|
|
58
|
+
resource.size = info.size;
|
|
59
|
+
return resource;
|
|
60
|
+
}
|
|
61
|
+
getSync(id, offset, end) {
|
|
62
|
+
var _a;
|
|
63
|
+
const resource = this._cached(id);
|
|
64
|
+
if (!resource)
|
|
65
|
+
return;
|
|
66
|
+
end !== null && end !== void 0 ? end : (end = resource.size);
|
|
67
|
+
const missing = resource.missing(offset, end);
|
|
68
|
+
for (const { start, end } of missing) {
|
|
69
|
+
this.async(this.get(id, start, end));
|
|
70
|
+
}
|
|
71
|
+
if (missing.length)
|
|
72
|
+
throw err(ErrnoError.With('EAGAIN', (_a = this.store._fs) === null || _a === void 0 ? void 0 : _a._path(id)));
|
|
73
|
+
const region = resource.regionAt(offset);
|
|
74
|
+
if (!region) {
|
|
75
|
+
warn('Missing cache region for ' + id);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
return region.data.subarray(offset - region.offset, end - region.offset);
|
|
79
|
+
}
|
|
80
|
+
setSync(id, data, offset) {
|
|
81
|
+
this.async(this.set(id, data, offset));
|
|
82
|
+
}
|
|
83
|
+
removeSync(id) {
|
|
84
|
+
var _a;
|
|
85
|
+
this.async(this.remove(id));
|
|
86
|
+
(_a = this.store.cache) === null || _a === void 0 ? void 0 : _a.delete(id);
|
|
47
87
|
}
|
|
48
88
|
}
|
|
49
89
|
/**
|
|
50
|
-
*
|
|
90
|
+
* Wraps a transaction with the ability to roll-back changes, among other things.
|
|
91
|
+
* This is used by `StoreFS`
|
|
92
|
+
* @internal @hidden
|
|
51
93
|
*/
|
|
52
|
-
export class
|
|
53
|
-
|
|
54
|
-
|
|
94
|
+
export class WrappedTransaction {
|
|
95
|
+
flag(flag) {
|
|
96
|
+
var _a, _b;
|
|
97
|
+
return (_b = (_a = this.raw.store.flags) === null || _a === void 0 ? void 0 : _a.includes(flag)) !== null && _b !== void 0 ? _b : false;
|
|
98
|
+
}
|
|
99
|
+
constructor(raw, fs) {
|
|
100
|
+
this.raw = raw;
|
|
101
|
+
this.fs = fs;
|
|
102
|
+
/**
|
|
103
|
+
* Whether the transaction was committed or aborted
|
|
104
|
+
*/
|
|
105
|
+
this.done = false;
|
|
106
|
+
/**
|
|
107
|
+
* Stores data in the keys we modify prior to modifying them.
|
|
108
|
+
* Allows us to roll back commits.
|
|
109
|
+
*/
|
|
110
|
+
this.originalData = new Map();
|
|
111
|
+
/**TransactionEntry
|
|
112
|
+
* List of keys modified in this transaction, if any.
|
|
113
|
+
*/
|
|
114
|
+
this.modifiedKeys = new Set();
|
|
115
|
+
}
|
|
116
|
+
keys() {
|
|
117
|
+
return this.raw.keys();
|
|
55
118
|
}
|
|
56
|
-
|
|
57
|
-
|
|
119
|
+
async get(id, offset = 0, end) {
|
|
120
|
+
const data = await this.raw.get(id, offset, end);
|
|
121
|
+
this.stash(id);
|
|
122
|
+
return data;
|
|
58
123
|
}
|
|
59
|
-
|
|
60
|
-
|
|
124
|
+
getSync(id, offset = 0, end) {
|
|
125
|
+
const data = this.raw.getSync(id, offset, end);
|
|
126
|
+
this.stash(id);
|
|
127
|
+
return data;
|
|
61
128
|
}
|
|
62
|
-
|
|
63
|
-
|
|
129
|
+
async set(id, data, offset = 0) {
|
|
130
|
+
await this.markModified(id, offset, data.byteLength);
|
|
131
|
+
await this.raw.set(id, data, offset);
|
|
132
|
+
}
|
|
133
|
+
setSync(id, data, offset = 0) {
|
|
134
|
+
this.markModifiedSync(id, offset, data.byteLength);
|
|
135
|
+
this.raw.setSync(id, data, offset);
|
|
136
|
+
}
|
|
137
|
+
async remove(id) {
|
|
138
|
+
await this.markModified(id, 0, undefined);
|
|
139
|
+
await this.raw.remove(id);
|
|
140
|
+
}
|
|
141
|
+
removeSync(id) {
|
|
142
|
+
this.markModifiedSync(id, 0, undefined);
|
|
143
|
+
this.raw.removeSync(id);
|
|
144
|
+
}
|
|
145
|
+
commit() {
|
|
146
|
+
this.done = true;
|
|
147
|
+
return Promise.resolve();
|
|
64
148
|
}
|
|
65
149
|
commitSync() {
|
|
66
|
-
|
|
150
|
+
this.done = true;
|
|
151
|
+
}
|
|
152
|
+
async abort() {
|
|
153
|
+
if (this.done)
|
|
154
|
+
return;
|
|
155
|
+
// Rollback old values.
|
|
156
|
+
for (const [id, entries] of this.originalData) {
|
|
157
|
+
if (!this.modifiedKeys.has(id))
|
|
158
|
+
continue;
|
|
159
|
+
// Key didn't exist.
|
|
160
|
+
if (entries.some(ent => !ent.data)) {
|
|
161
|
+
await this.raw.remove(id);
|
|
162
|
+
this.fs._remove(id);
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
for (const entry of entries.reverse()) {
|
|
166
|
+
await this.raw.set(id, entry.data, entry.offset);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
this.done = true;
|
|
67
170
|
}
|
|
68
171
|
abortSync() {
|
|
69
|
-
|
|
172
|
+
if (this.done)
|
|
173
|
+
return;
|
|
174
|
+
// Rollback old values.
|
|
175
|
+
for (const [id, entries] of this.originalData) {
|
|
176
|
+
if (!this.modifiedKeys.has(id))
|
|
177
|
+
continue;
|
|
178
|
+
// Key didn't exist.
|
|
179
|
+
if (entries.some(ent => !ent.data)) {
|
|
180
|
+
this.raw.removeSync(id);
|
|
181
|
+
this.fs._remove(id);
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
for (const entry of entries.reverse()) {
|
|
185
|
+
this.raw.setSync(id, entry.data, entry.offset);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
this.done = true;
|
|
189
|
+
}
|
|
190
|
+
async [Symbol.asyncDispose]() {
|
|
191
|
+
if (this.done)
|
|
192
|
+
return;
|
|
193
|
+
await this.abort();
|
|
194
|
+
}
|
|
195
|
+
[Symbol.dispose]() {
|
|
196
|
+
if (this.done)
|
|
197
|
+
return;
|
|
198
|
+
this.abortSync();
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Stashes given key value pair into `originalData` if it doesn't already exist.
|
|
202
|
+
* Allows us to stash values the program is requesting anyway to
|
|
203
|
+
* prevent needless `get` requests if the program modifies the data later
|
|
204
|
+
* on during the transaction.
|
|
205
|
+
*/
|
|
206
|
+
stash(id, data, offset = 0) {
|
|
207
|
+
if (!this.originalData.has(id))
|
|
208
|
+
this.originalData.set(id, []);
|
|
209
|
+
this.originalData.get(id).push({ data, offset });
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Marks an id as modified, and stashes its value if it has not been stashed already.
|
|
213
|
+
*/
|
|
214
|
+
async markModified(id, offset, length) {
|
|
215
|
+
this.modifiedKeys.add(id);
|
|
216
|
+
const end = length ? offset + length : undefined;
|
|
217
|
+
try {
|
|
218
|
+
this.stash(id, await this.raw.get(id, offset, end), offset);
|
|
219
|
+
}
|
|
220
|
+
catch (e) {
|
|
221
|
+
if (!(this.raw instanceof AsyncTransaction))
|
|
222
|
+
throw e;
|
|
223
|
+
/*
|
|
224
|
+
async transaction has a quirk:
|
|
225
|
+
setting the buffer to a larger size doesn't work correctly due to cache ranges
|
|
226
|
+
so, we cache the existing sub-ranges
|
|
227
|
+
*/
|
|
228
|
+
const tx = this.raw;
|
|
229
|
+
const resource = tx._cached(id);
|
|
230
|
+
if (!resource)
|
|
231
|
+
throw e;
|
|
232
|
+
for (const range of resource.cached(offset, end !== null && end !== void 0 ? end : offset)) {
|
|
233
|
+
this.stash(id, await this.raw.get(id, range.start, range.end), range.start);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Marks an id as modified, and stashes its value if it has not been stashed already.
|
|
239
|
+
*/
|
|
240
|
+
markModifiedSync(id, offset, length) {
|
|
241
|
+
this.modifiedKeys.add(id);
|
|
242
|
+
const end = length ? offset + length : undefined;
|
|
243
|
+
try {
|
|
244
|
+
this.stash(id, this.raw.getSync(id, offset, end), offset);
|
|
245
|
+
}
|
|
246
|
+
catch (e) {
|
|
247
|
+
if (!(this.raw instanceof AsyncTransaction))
|
|
248
|
+
throw e;
|
|
249
|
+
/*
|
|
250
|
+
async transaction has a quirk:
|
|
251
|
+
setting the buffer to a larger size doesn't work correctly due to cache ranges
|
|
252
|
+
so, we cache the existing sub-ranges
|
|
253
|
+
*/
|
|
254
|
+
const tx = this.raw;
|
|
255
|
+
const resource = tx._cached(id);
|
|
256
|
+
if (!resource)
|
|
257
|
+
throw e;
|
|
258
|
+
for (const range of resource.cached(offset, end !== null && end !== void 0 ? end : offset)) {
|
|
259
|
+
this.stash(id, this.raw.getSync(id, range.start, range.end), range.start);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
70
262
|
}
|
|
71
263
|
}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Backend, BackendConfiguration, FilesystemOf, SharedConfig } from './backends/backend.js';
|
|
2
|
-
import type { Device, DeviceDriver } from './devices.js';
|
|
2
|
+
import type { Device, DeviceDriver } from './internal/devices.js';
|
|
3
|
+
import type { LogConfiguration } from './internal/log.js';
|
|
3
4
|
/**
|
|
4
5
|
* Configuration for a specific mount point
|
|
5
6
|
*/
|
|
@@ -37,7 +38,6 @@ export interface Configuration<T extends ConfigMounts> extends SharedConfig {
|
|
|
37
38
|
gid: number;
|
|
38
39
|
/**
|
|
39
40
|
* Whether to automatically add normal Linux devices
|
|
40
|
-
* @experimental
|
|
41
41
|
* @default false
|
|
42
42
|
*/
|
|
43
43
|
addDevices: boolean;
|
|
@@ -60,7 +60,6 @@ export interface Configuration<T extends ConfigMounts> extends SharedConfig {
|
|
|
60
60
|
* If true, disables *all* permissions checking.
|
|
61
61
|
*
|
|
62
62
|
* This can increase performance.
|
|
63
|
-
* @experimental
|
|
64
63
|
* @default false
|
|
65
64
|
*/
|
|
66
65
|
disableAccessChecks: boolean;
|
|
@@ -81,6 +80,11 @@ export interface Configuration<T extends ConfigMounts> extends SharedConfig {
|
|
|
81
80
|
* @default false
|
|
82
81
|
*/
|
|
83
82
|
onlySyncOnClose: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Configurations options for the log.
|
|
85
|
+
* @experimental
|
|
86
|
+
*/
|
|
87
|
+
log: LogConfiguration;
|
|
84
88
|
}
|
|
85
89
|
/**
|
|
86
90
|
* Configures ZenFS with single mount point /
|
package/dist/config.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { checkOptions, isBackend, isBackendConfig } from './backends/backend.js';
|
|
2
|
-
import { useCredentials } from './credentials.js';
|
|
3
|
-
import { DeviceFS } from './devices.js';
|
|
4
|
-
import { Errno, ErrnoError } from './error.js';
|
|
5
|
-
import { FileSystem } from './filesystem.js';
|
|
2
|
+
import { useCredentials } from './internal/credentials.js';
|
|
3
|
+
import { DeviceFS } from './internal/devices.js';
|
|
4
|
+
import { Errno, ErrnoError } from './internal/error.js';
|
|
5
|
+
import { FileSystem } from './internal/filesystem.js';
|
|
6
|
+
import { configure as configureLog, crit, err, info } from './internal/log.js';
|
|
6
7
|
import * as cache from './vfs/cache.js';
|
|
7
8
|
import { config } from './vfs/config.js';
|
|
8
9
|
import * as fs from './vfs/index.js';
|
|
@@ -16,10 +17,10 @@ function isMountConfig(arg) {
|
|
|
16
17
|
*/
|
|
17
18
|
export async function resolveMountConfig(configuration, _depth = 0) {
|
|
18
19
|
if (typeof configuration !== 'object' || configuration == null) {
|
|
19
|
-
throw new ErrnoError(Errno.EINVAL, 'Invalid options on mount configuration');
|
|
20
|
+
throw err(new ErrnoError(Errno.EINVAL, 'Invalid options on mount configuration'));
|
|
20
21
|
}
|
|
21
22
|
if (!isMountConfig(configuration)) {
|
|
22
|
-
throw new ErrnoError(Errno.EINVAL, 'Invalid mount configuration');
|
|
23
|
+
throw err(new ErrnoError(Errno.EINVAL, 'Invalid mount configuration'));
|
|
23
24
|
}
|
|
24
25
|
if (configuration instanceof FileSystem) {
|
|
25
26
|
await configuration.ready();
|
|
@@ -29,24 +30,24 @@ export async function resolveMountConfig(configuration, _depth = 0) {
|
|
|
29
30
|
configuration = { backend: configuration };
|
|
30
31
|
}
|
|
31
32
|
for (const [key, value] of Object.entries(configuration)) {
|
|
32
|
-
if (key == 'backend')
|
|
33
|
+
if (key == 'backend')
|
|
33
34
|
continue;
|
|
34
|
-
|
|
35
|
-
if (!isMountConfig(value)) {
|
|
35
|
+
if (!isMountConfig(value))
|
|
36
36
|
continue;
|
|
37
|
-
|
|
37
|
+
info('Resolving nested mount configuration: ' + key);
|
|
38
38
|
if (_depth > 10) {
|
|
39
|
-
throw new ErrnoError(Errno.EINVAL, 'Invalid configuration, too deep and possibly infinite');
|
|
39
|
+
throw err(new ErrnoError(Errno.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
44
|
if (typeof backend.isAvailable == 'function' && !(await backend.isAvailable())) {
|
|
45
|
-
throw new ErrnoError(Errno.EPERM, 'Backend not available: ' + backend.name);
|
|
45
|
+
throw err(new ErrnoError(Errno.EPERM, 'Backend not available: ' + backend.name));
|
|
46
46
|
}
|
|
47
47
|
await checkOptions(backend, configuration);
|
|
48
48
|
const mount = (await backend.create(configuration));
|
|
49
|
-
|
|
49
|
+
if (configuration.disableAsyncCache)
|
|
50
|
+
mount.attributes.set('no_async');
|
|
50
51
|
await mount.ready();
|
|
51
52
|
return mount;
|
|
52
53
|
}
|
|
@@ -84,7 +85,7 @@ async function mount(path, mount) {
|
|
|
84
85
|
export function addDevice(driver, options) {
|
|
85
86
|
const devfs = mounts.get('/dev');
|
|
86
87
|
if (!(devfs instanceof DeviceFS))
|
|
87
|
-
throw new ErrnoError(Errno.ENOTSUP, '/dev does not exist or is not a device file system');
|
|
88
|
+
throw crit(new ErrnoError(Errno.ENOTSUP, '/dev does not exist or is not a device file system'));
|
|
88
89
|
return devfs._createDevice(driver, options);
|
|
89
90
|
}
|
|
90
91
|
/**
|
|
@@ -101,6 +102,8 @@ export async function configure(configuration) {
|
|
|
101
102
|
config.checkAccess = !configuration.disableAccessChecks;
|
|
102
103
|
config.updateOnRead = !configuration.disableUpdateOnRead;
|
|
103
104
|
config.syncImmediately = !configuration.onlySyncOnClose;
|
|
105
|
+
if (configuration.log)
|
|
106
|
+
configureLog(configuration.log);
|
|
104
107
|
if (configuration.mounts) {
|
|
105
108
|
// sort to make sure any root replacement is done first
|
|
106
109
|
for (const [_point, mountConfig] of Object.entries(configuration.mounts).sort(([a], [b]) => (a.length > b.length ? 1 : -1))) {
|
package/dist/context.d.ts
CHANGED
package/dist/context.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createCredentials, credentials as defaultCredentials } from './credentials.js';
|
|
1
|
+
import { createCredentials, credentials as defaultCredentials } from './internal/credentials.js';
|
|
2
2
|
import * as fs from './vfs/index.js';
|
|
3
3
|
/**
|
|
4
4
|
* Binds a this value for all of the functions in an object (not recursive)
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
export * from './backends/index.js';
|
|
2
2
|
export * from './config.js';
|
|
3
3
|
export * from './context.js';
|
|
4
|
-
export * from './
|
|
5
|
-
export * from './devices.js';
|
|
6
|
-
export * from './error.js';
|
|
7
|
-
export * from './file.js';
|
|
8
|
-
export * from './filesystem.js';
|
|
4
|
+
export * from './internal/index.js';
|
|
9
5
|
export * from './mixins/index.js';
|
|
10
6
|
export * from './stats.js';
|
|
11
7
|
export * from './utils.js';
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
export * from './backends/index.js';
|
|
2
2
|
export * from './config.js';
|
|
3
3
|
export * from './context.js';
|
|
4
|
-
export * from './
|
|
5
|
-
export * from './devices.js';
|
|
6
|
-
export * from './error.js';
|
|
7
|
-
export * from './file.js';
|
|
8
|
-
export * from './filesystem.js';
|
|
4
|
+
export * from './internal/index.js';
|
|
9
5
|
export * from './mixins/index.js';
|
|
10
6
|
export * from './stats.js';
|
|
11
7
|
export * from './utils.js';
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { InMemoryStore } from '../backends/memory.js';
|
|
2
|
+
import { StoreFS } from '../backends/store/fs.js';
|
|
3
|
+
import { Stats } from '../stats.js';
|
|
4
4
|
import type { FileReadResult } from './file.js';
|
|
5
5
|
import { File } from './file.js';
|
|
6
6
|
import type { CreationOptions } from './filesystem.js';
|
|
7
|
-
import {
|
|
7
|
+
import { Inode } from './inode.js';
|
|
8
8
|
/**
|
|
9
9
|
* A device
|
|
10
10
|
* @todo Maybe add some other device information, like a UUID?
|
|
@@ -53,15 +53,17 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
53
53
|
var e = new Error(message);
|
|
54
54
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
55
55
|
});
|
|
56
|
-
import {
|
|
57
|
-
import { InMemoryStore } from '
|
|
58
|
-
import { StoreFS } from '
|
|
56
|
+
import { canary } from 'utilium';
|
|
57
|
+
import { InMemoryStore } from '../backends/memory.js';
|
|
58
|
+
import { StoreFS } from '../backends/store/fs.js';
|
|
59
|
+
import { Stats } from '../stats.js';
|
|
60
|
+
import { decodeUTF8 } from '../utils.js';
|
|
61
|
+
import { S_IFBLK, S_IFCHR } from '../vfs/constants.js';
|
|
62
|
+
import { basename, dirname } from '../vfs/path.js';
|
|
59
63
|
import { Errno, ErrnoError } from './error.js';
|
|
60
64
|
import { File } from './file.js';
|
|
61
|
-
import {
|
|
62
|
-
import {
|
|
63
|
-
import { S_IFBLK, S_IFCHR } from './vfs/constants.js';
|
|
64
|
-
import { basename, dirname } from './vfs/path.js';
|
|
65
|
+
import { Inode } from './inode.js';
|
|
66
|
+
import { alert, debug, err, info, log_deprecated } from './log.js';
|
|
65
67
|
/**
|
|
66
68
|
* The base class for device files
|
|
67
69
|
* This class only does some simple things:
|
|
@@ -162,18 +164,19 @@ export class DeviceFile extends File {
|
|
|
162
164
|
* A temporary file system that manages and interfaces with devices
|
|
163
165
|
*/
|
|
164
166
|
export class DeviceFS extends StoreFS {
|
|
167
|
+
/* node:coverage disable */
|
|
165
168
|
/**
|
|
166
169
|
* Creates a new device at `path` relative to the `DeviceFS` root.
|
|
167
170
|
* @deprecated
|
|
168
171
|
*/
|
|
169
|
-
/* node:coverage disable */
|
|
170
172
|
createDevice(path, driver, options = {}) {
|
|
171
173
|
var _a;
|
|
174
|
+
log_deprecated('DeviceFS#createDevice');
|
|
172
175
|
if (this.existsSync(path)) {
|
|
173
176
|
throw ErrnoError.With('EEXIST', path, 'mknod');
|
|
174
177
|
}
|
|
175
178
|
let ino = 1;
|
|
176
|
-
const silence = canary(path, 'mknod');
|
|
179
|
+
const silence = canary(ErrnoError.With('EDEADLK', path, 'mknod'));
|
|
177
180
|
while (this.store.has(ino))
|
|
178
181
|
ino++;
|
|
179
182
|
silence();
|
|
@@ -191,7 +194,7 @@ export class DeviceFS extends StoreFS {
|
|
|
191
194
|
/* node:coverage enable */
|
|
192
195
|
devicesWithDriver(driver, forceIdentity) {
|
|
193
196
|
if (forceIdentity && typeof driver == 'string') {
|
|
194
|
-
throw new ErrnoError(Errno.EINVAL, 'Can not fetch devices using only a driver name');
|
|
197
|
+
throw err(new ErrnoError(Errno.EINVAL, 'Can not fetch devices using only a driver name'), { fs: this });
|
|
195
198
|
}
|
|
196
199
|
const devs = [];
|
|
197
200
|
for (const device of this.devices.values()) {
|
|
@@ -220,10 +223,10 @@ export class DeviceFS extends StoreFS {
|
|
|
220
223
|
...(_a = driver.init) === null || _a === void 0 ? void 0 : _a.call(driver, ino, options),
|
|
221
224
|
};
|
|
222
225
|
const path = '/' + (dev.name || driver.name) + (driver.singleton ? '' : this.devicesWithDriver(driver).length);
|
|
223
|
-
if (this.existsSync(path))
|
|
226
|
+
if (this.existsSync(path))
|
|
224
227
|
throw ErrnoError.With('EEXIST', path, 'mknod');
|
|
225
|
-
}
|
|
226
228
|
this.devices.set(path, dev);
|
|
229
|
+
info('Initialized device: ' + this._mountPoint + path);
|
|
227
230
|
return dev;
|
|
228
231
|
}
|
|
229
232
|
/**
|
|
@@ -235,6 +238,7 @@ export class DeviceFS extends StoreFS {
|
|
|
235
238
|
this._createDevice(fullDevice);
|
|
236
239
|
this._createDevice(randomDevice);
|
|
237
240
|
this._createDevice(consoleDevice);
|
|
241
|
+
debug('Added default devices.');
|
|
238
242
|
}
|
|
239
243
|
constructor() {
|
|
240
244
|
super(new InMemoryStore('devfs'));
|
|
@@ -386,13 +390,13 @@ export class DeviceFS extends StoreFS {
|
|
|
386
390
|
}
|
|
387
391
|
async sync(path, data, stats) {
|
|
388
392
|
if (this.devices.has(path)) {
|
|
389
|
-
throw new ErrnoError(Errno.EINVAL, 'Attempted to sync a device incorrectly (bug)', path, 'sync');
|
|
393
|
+
throw alert(new ErrnoError(Errno.EINVAL, 'Attempted to sync a device incorrectly (bug)', path, 'sync'), { fs: this });
|
|
390
394
|
}
|
|
391
395
|
return super.sync(path, data, stats);
|
|
392
396
|
}
|
|
393
397
|
syncSync(path, data, stats) {
|
|
394
398
|
if (this.devices.has(path)) {
|
|
395
|
-
throw new ErrnoError(Errno.EINVAL, 'Attempted to sync a device incorrectly (bug)', path, 'sync');
|
|
399
|
+
throw alert(new ErrnoError(Errno.EINVAL, 'Attempted to sync a device incorrectly (bug)', path, 'sync'), { fs: this });
|
|
396
400
|
}
|
|
397
401
|
return super.syncSync(path, data, stats);
|
|
398
402
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { Stats, type StatsLike } from '../stats.js';
|
|
1
2
|
import type { FileSystem } from './filesystem.js';
|
|
2
|
-
import '
|
|
3
|
-
import { Stats, type StatsLike } from './stats.js';
|
|
3
|
+
import '../polyfills.js';
|
|
4
4
|
export declare function parseFlag(flag: string | number): string;
|
|
5
5
|
export declare function flagToString(flag: number): string;
|
|
6
6
|
export declare function flagToNumber(flag: string): number;
|
|
@@ -220,6 +220,7 @@ export declare class PreloadFile<FS extends FileSystem> extends File<FS> {
|
|
|
220
220
|
* @deprecated
|
|
221
221
|
*/
|
|
222
222
|
export declare class NoSyncFile<T extends FileSystem> extends PreloadFile<T> {
|
|
223
|
+
constructor(...args: ConstructorParameters<typeof PreloadFile<T>>);
|
|
223
224
|
sync(): Promise<void>;
|
|
224
225
|
syncSync(): void;
|
|
225
226
|
close(): Promise<void>;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { extendBuffer } from 'utilium/buffer.js';
|
|
2
|
+
import { _chown, Stats } from '../stats.js';
|
|
3
|
+
import { config } from '../vfs/config.js';
|
|
4
|
+
import * as c from '../vfs/constants.js';
|
|
1
5
|
import { Errno, ErrnoError } from './error.js';
|
|
2
|
-
import './
|
|
3
|
-
import
|
|
4
|
-
import { growBuffer } from './utils.js';
|
|
5
|
-
import { config } from './vfs/config.js';
|
|
6
|
-
import * as c from './vfs/constants.js';
|
|
6
|
+
import { log_deprecated } from './log.js';
|
|
7
|
+
import '../polyfills.js';
|
|
7
8
|
const maxByteLength = 0x100000; // 1 MiB
|
|
8
9
|
const validFlags = ['r', 'r+', 'rs', 'rs+', 'w', 'wx', 'w+', 'wx+', 'a', 'ax', 'a+', 'ax+'];
|
|
9
10
|
export function parseFlag(flag) {
|
|
@@ -148,7 +149,7 @@ export class PreloadFile extends File {
|
|
|
148
149
|
/**
|
|
149
150
|
* A buffer containing the entire contents of the file.
|
|
150
151
|
*/
|
|
151
|
-
_buffer = new Uint8Array(new ArrayBuffer(0, fs.
|
|
152
|
+
_buffer = new Uint8Array(new ArrayBuffer(0, fs.attributes.has('no_buffer_resize') ? {} : { maxByteLength }))) {
|
|
152
153
|
super(fs, path);
|
|
153
154
|
this.flag = flag;
|
|
154
155
|
this.stats = stats;
|
|
@@ -208,7 +209,7 @@ export class PreloadFile extends File {
|
|
|
208
209
|
throw ErrnoError.With('EBADF', this.path, 'sync');
|
|
209
210
|
if (!this.dirty)
|
|
210
211
|
return;
|
|
211
|
-
if (!this.fs.
|
|
212
|
+
if (!this.fs.attributes.has('no_write'))
|
|
212
213
|
await this.fs.sync(this.path, this._buffer, this.stats);
|
|
213
214
|
this.dirty = false;
|
|
214
215
|
}
|
|
@@ -217,7 +218,7 @@ export class PreloadFile extends File {
|
|
|
217
218
|
throw ErrnoError.With('EBADF', this.path, 'sync');
|
|
218
219
|
if (!this.dirty)
|
|
219
220
|
return;
|
|
220
|
-
if (!this.fs.
|
|
221
|
+
if (!this.fs.attributes.has('no_write'))
|
|
221
222
|
this.fs.syncSync(this.path, this._buffer, this.stats);
|
|
222
223
|
this.dirty = false;
|
|
223
224
|
}
|
|
@@ -291,7 +292,7 @@ export class PreloadFile extends File {
|
|
|
291
292
|
this.dirty = true;
|
|
292
293
|
const end = position + length;
|
|
293
294
|
const slice = buffer.subarray(offset, offset + length);
|
|
294
|
-
this._buffer =
|
|
295
|
+
this._buffer = extendBuffer(this._buffer, end);
|
|
295
296
|
if (end > this.stats.size)
|
|
296
297
|
this.stats.size = end;
|
|
297
298
|
this._buffer.set(slice, position);
|
|
@@ -433,12 +434,16 @@ export class PreloadFile extends File {
|
|
|
433
434
|
this.syncSync();
|
|
434
435
|
}
|
|
435
436
|
}
|
|
437
|
+
/* node:coverage disable */
|
|
436
438
|
/**
|
|
437
439
|
* For the file systems which do not sync to anything.
|
|
438
440
|
* @deprecated
|
|
439
441
|
*/
|
|
440
|
-
/* node:coverage disable */
|
|
441
442
|
export class NoSyncFile extends PreloadFile {
|
|
443
|
+
constructor(...args) {
|
|
444
|
+
log_deprecated('NoSyncFile');
|
|
445
|
+
super(...args);
|
|
446
|
+
}
|
|
442
447
|
sync() {
|
|
443
448
|
return Promise.resolve();
|
|
444
449
|
}
|
|
@@ -495,7 +500,7 @@ export class LazyFile extends File {
|
|
|
495
500
|
throw ErrnoError.With('EBADF', this.path, 'sync');
|
|
496
501
|
if (!this.dirty)
|
|
497
502
|
return;
|
|
498
|
-
if (!this.fs.
|
|
503
|
+
if (!this.fs.attributes.has('no_write'))
|
|
499
504
|
await this.fs.sync(this.path, undefined, this.stats);
|
|
500
505
|
this.dirty = false;
|
|
501
506
|
}
|
|
@@ -504,7 +509,7 @@ export class LazyFile extends File {
|
|
|
504
509
|
throw ErrnoError.With('EBADF', this.path, 'sync');
|
|
505
510
|
if (!this.dirty)
|
|
506
511
|
return;
|
|
507
|
-
if (!this.fs.
|
|
512
|
+
if (!this.fs.attributes.has('no_write'))
|
|
508
513
|
this.fs.syncSync(this.path, undefined, this.stats);
|
|
509
514
|
this.dirty = false;
|
|
510
515
|
}
|