@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
|
@@ -50,16 +50,18 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
50
50
|
var e = new Error(message);
|
|
51
51
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
52
|
});
|
|
53
|
-
import {
|
|
54
|
-
import {
|
|
55
|
-
import {
|
|
56
|
-
import {
|
|
57
|
-
import {
|
|
53
|
+
import { _throw, canary, serialize } from 'utilium';
|
|
54
|
+
import { extendBuffer } from 'utilium/buffer.js';
|
|
55
|
+
import { Errno, ErrnoError } from '../../internal/error.js';
|
|
56
|
+
import { LazyFile } from '../../internal/file.js';
|
|
57
|
+
import { Index } from '../../internal/file_index.js';
|
|
58
|
+
import { FileSystem } from '../../internal/filesystem.js';
|
|
59
|
+
import { __inode_sz, Inode, rootIno } from '../../internal/inode.js';
|
|
60
|
+
import { crit, debug, err, log_deprecated, notice, warn } from '../../internal/log.js';
|
|
61
|
+
import { decodeDirListing, encodeDirListing, encodeUTF8 } from '../../utils.js';
|
|
58
62
|
import { S_IFDIR, S_IFREG, S_ISGID, S_ISUID, size_max } from '../../vfs/constants.js';
|
|
59
|
-
import { basename, dirname, join, parse,
|
|
60
|
-
import {
|
|
61
|
-
import { Inode, rootIno } from './inode.js';
|
|
62
|
-
const maxInodeAllocTries = 5;
|
|
63
|
+
import { basename, dirname, join, parse, relative } from '../../vfs/path.js';
|
|
64
|
+
import { WrappedTransaction } from './store.js';
|
|
63
65
|
/**
|
|
64
66
|
* A file system which uses a key-value store.
|
|
65
67
|
*
|
|
@@ -70,24 +72,85 @@ const maxInodeAllocTries = 5;
|
|
|
70
72
|
* @internal
|
|
71
73
|
*/
|
|
72
74
|
export class StoreFS extends FileSystem {
|
|
75
|
+
/**
|
|
76
|
+
* Gets the first path associated with an inode
|
|
77
|
+
*/
|
|
78
|
+
_path(id) {
|
|
79
|
+
var _a;
|
|
80
|
+
const [path] = (_a = this._paths.get(id)) !== null && _a !== void 0 ? _a : [];
|
|
81
|
+
return path;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Add a inode/path pair
|
|
85
|
+
*/
|
|
86
|
+
_add(ino, path) {
|
|
87
|
+
if (!this._paths.has(ino))
|
|
88
|
+
this._paths.set(ino, new Set());
|
|
89
|
+
this._paths.get(ino).add(path);
|
|
90
|
+
this._ids.set(path, ino);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Remove a inode/path pair
|
|
94
|
+
*/
|
|
95
|
+
_remove(ino) {
|
|
96
|
+
var _a;
|
|
97
|
+
for (const path of (_a = this._paths.get(ino)) !== null && _a !== void 0 ? _a : []) {
|
|
98
|
+
this._ids.delete(path);
|
|
99
|
+
}
|
|
100
|
+
this._paths.delete(ino);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Move paths in the tables
|
|
104
|
+
*/
|
|
105
|
+
_move(from, to) {
|
|
106
|
+
const toMove = [];
|
|
107
|
+
for (const [path, ino] of this._ids) {
|
|
108
|
+
const rel = relative(from, path);
|
|
109
|
+
if (rel.startsWith('..'))
|
|
110
|
+
continue;
|
|
111
|
+
let newKey = join(to, rel);
|
|
112
|
+
if (newKey.endsWith('/'))
|
|
113
|
+
newKey = newKey.slice(0, -1);
|
|
114
|
+
toMove.push({ oldKey: path, newKey, ino });
|
|
115
|
+
}
|
|
116
|
+
for (const { oldKey, newKey, ino } of toMove) {
|
|
117
|
+
this._ids.delete(oldKey);
|
|
118
|
+
this._ids.set(newKey, ino);
|
|
119
|
+
const p = this._paths.get(ino);
|
|
120
|
+
if (!p) {
|
|
121
|
+
warn('Missing paths in table for ino ' + ino);
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
p.delete(oldKey);
|
|
125
|
+
p.add(newKey);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
73
128
|
async ready() {
|
|
74
|
-
if (this._initialized)
|
|
129
|
+
if (this._initialized)
|
|
75
130
|
return;
|
|
76
|
-
|
|
131
|
+
this.checkRootSync();
|
|
77
132
|
await this.checkRoot();
|
|
133
|
+
await this._populate();
|
|
78
134
|
this._initialized = true;
|
|
79
135
|
}
|
|
80
136
|
constructor(store) {
|
|
81
|
-
|
|
137
|
+
var _a, _b;
|
|
138
|
+
super((_a = store.id) !== null && _a !== void 0 ? _a : 0x6b766673, store.name);
|
|
82
139
|
this.store = store;
|
|
140
|
+
/**
|
|
141
|
+
* A map of paths to inode IDs
|
|
142
|
+
* @internal @hidden
|
|
143
|
+
*/
|
|
144
|
+
this._ids = new Map([['/', 0]]);
|
|
145
|
+
/**
|
|
146
|
+
* A map of inode IDs to paths
|
|
147
|
+
* @internal @hidden
|
|
148
|
+
*/
|
|
149
|
+
this._paths = new Map([[0, new Set('/')]]);
|
|
83
150
|
this._initialized = false;
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
...super.metadata(),
|
|
88
|
-
name: this.store.name,
|
|
89
|
-
features: ['setid'],
|
|
90
|
-
};
|
|
151
|
+
this.attributes.set('setid');
|
|
152
|
+
store._fs = this;
|
|
153
|
+
debug(this.name + ': supports features: ' + ((_b = this.store.flags) === null || _b === void 0 ? void 0 : _b.join(', ')));
|
|
91
154
|
}
|
|
92
155
|
/* node:coverage disable */
|
|
93
156
|
/**
|
|
@@ -95,7 +158,7 @@ export class StoreFS extends FileSystem {
|
|
|
95
158
|
* @deprecated
|
|
96
159
|
*/
|
|
97
160
|
async empty() {
|
|
98
|
-
|
|
161
|
+
log_deprecated('StoreFS#empty');
|
|
99
162
|
// Root always exists.
|
|
100
163
|
await this.checkRoot();
|
|
101
164
|
}
|
|
@@ -104,7 +167,7 @@ export class StoreFS extends FileSystem {
|
|
|
104
167
|
* @deprecated
|
|
105
168
|
*/
|
|
106
169
|
emptySync() {
|
|
107
|
-
|
|
170
|
+
log_deprecated('StoreFS#emptySync');
|
|
108
171
|
// Root always exists.
|
|
109
172
|
this.checkRootSync();
|
|
110
173
|
}
|
|
@@ -116,9 +179,10 @@ export class StoreFS extends FileSystem {
|
|
|
116
179
|
async loadIndex(index) {
|
|
117
180
|
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
118
181
|
try {
|
|
119
|
-
const tx = __addDisposableResource(env_1, this.
|
|
182
|
+
const tx = __addDisposableResource(env_1, this.transaction(), true);
|
|
120
183
|
const dirs = index.directories();
|
|
121
184
|
for (const [path, inode] of index) {
|
|
185
|
+
this._add(inode.ino, path);
|
|
122
186
|
await tx.set(inode.ino, serialize(inode));
|
|
123
187
|
if (dirs.has(path))
|
|
124
188
|
await tx.set(inode.data, encodeDirListing(dirs.get(path)));
|
|
@@ -142,9 +206,10 @@ export class StoreFS extends FileSystem {
|
|
|
142
206
|
loadIndexSync(index) {
|
|
143
207
|
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
144
208
|
try {
|
|
145
|
-
const tx = __addDisposableResource(env_2, this.
|
|
209
|
+
const tx = __addDisposableResource(env_2, this.transaction(), false);
|
|
146
210
|
const dirs = index.directories();
|
|
147
211
|
for (const [path, inode] of index) {
|
|
212
|
+
this._add(inode.ino, path);
|
|
148
213
|
tx.setSync(inode.ino, serialize(inode));
|
|
149
214
|
if (dirs.has(path))
|
|
150
215
|
tx.setSync(inode.data, encodeDirListing(dirs.get(path)));
|
|
@@ -160,18 +225,19 @@ export class StoreFS extends FileSystem {
|
|
|
160
225
|
}
|
|
161
226
|
}
|
|
162
227
|
async createIndex() {
|
|
228
|
+
var _a;
|
|
163
229
|
const env_3 = { stack: [], error: void 0, hasError: false };
|
|
164
230
|
try {
|
|
165
231
|
const index = new Index();
|
|
166
|
-
const tx = __addDisposableResource(env_3, this.
|
|
232
|
+
const tx = __addDisposableResource(env_3, this.transaction(), true);
|
|
167
233
|
const queue = [['/', 0]];
|
|
168
|
-
const silence = canary();
|
|
234
|
+
const silence = canary(ErrnoError.With('EDEADLK'));
|
|
169
235
|
while (queue.length) {
|
|
170
236
|
const [path, ino] = queue.shift();
|
|
171
237
|
const inode = new Inode(await tx.get(ino));
|
|
172
238
|
index.set(path, inode);
|
|
173
239
|
if (inode.mode & S_IFDIR) {
|
|
174
|
-
const dir = decodeDirListing(await tx.get(inode.data));
|
|
240
|
+
const dir = decodeDirListing((_a = (await tx.get(inode.data))) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENODATA', path)));
|
|
175
241
|
for (const [name, id] of Object.entries(dir)) {
|
|
176
242
|
queue.push([join(path, name), id]);
|
|
177
243
|
}
|
|
@@ -191,18 +257,19 @@ export class StoreFS extends FileSystem {
|
|
|
191
257
|
}
|
|
192
258
|
}
|
|
193
259
|
createIndexSync() {
|
|
260
|
+
var _a;
|
|
194
261
|
const env_4 = { stack: [], error: void 0, hasError: false };
|
|
195
262
|
try {
|
|
196
263
|
const index = new Index();
|
|
197
|
-
const tx = __addDisposableResource(env_4, this.
|
|
264
|
+
const tx = __addDisposableResource(env_4, this.transaction(), false);
|
|
198
265
|
const queue = [['/', 0]];
|
|
199
|
-
const silence = canary();
|
|
266
|
+
const silence = canary(ErrnoError.With('EDEADLK'));
|
|
200
267
|
while (queue.length) {
|
|
201
268
|
const [path, ino] = queue.shift();
|
|
202
269
|
const inode = new Inode(tx.getSync(ino));
|
|
203
270
|
index.set(path, inode);
|
|
204
271
|
if (inode.mode & S_IFDIR) {
|
|
205
|
-
const dir = decodeDirListing(tx.getSync(inode.data));
|
|
272
|
+
const dir = decodeDirListing((_a = tx.getSync(inode.data)) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENODATA', path)));
|
|
206
273
|
for (const [name, id] of Object.entries(dir)) {
|
|
207
274
|
queue.push([join(path, name), id]);
|
|
208
275
|
}
|
|
@@ -226,36 +293,35 @@ export class StoreFS extends FileSystem {
|
|
|
226
293
|
var _a, _b, _c;
|
|
227
294
|
const env_5 = { stack: [], error: void 0, hasError: false };
|
|
228
295
|
try {
|
|
229
|
-
const tx = __addDisposableResource(env_5, this.
|
|
296
|
+
const tx = __addDisposableResource(env_5, this.transaction(), true);
|
|
230
297
|
const _old = parse(oldPath), _new = parse(newPath),
|
|
231
298
|
// Remove oldPath from parent's directory listing.
|
|
232
|
-
oldDirNode = await this.findInode(tx, _old.dir, 'rename'), oldDirList = decodeDirListing((_a = (await tx.get(oldDirNode.data))) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('
|
|
233
|
-
if (!oldDirList[_old.base])
|
|
299
|
+
oldDirNode = await this.findInode(tx, _old.dir, 'rename'), oldDirList = decodeDirListing((_a = (await tx.get(oldDirNode.data))) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENODATA', _old.dir, 'rename')));
|
|
300
|
+
if (!oldDirList[_old.base])
|
|
234
301
|
throw ErrnoError.With('ENOENT', oldPath, 'rename');
|
|
235
|
-
}
|
|
236
302
|
const ino = oldDirList[_old.base];
|
|
303
|
+
if (ino != this._ids.get(oldPath))
|
|
304
|
+
err(`Ino mismatch while renaming ${oldPath} to ${newPath}`);
|
|
237
305
|
delete oldDirList[_old.base];
|
|
238
306
|
/*
|
|
239
307
|
Can't move a folder inside itself.
|
|
240
308
|
This ensures that the check passes only if `oldPath` is a subpath of `_new.dir`.
|
|
241
309
|
We append '/' to avoid matching folders that are a substring of the bottom-most folder in the path.
|
|
242
310
|
*/
|
|
243
|
-
if ((_new.dir + '/').
|
|
311
|
+
if ((_new.dir + '/').startsWith(oldPath + '/'))
|
|
244
312
|
throw new ErrnoError(Errno.EBUSY, _old.dir);
|
|
245
|
-
}
|
|
246
313
|
// Add newPath to parent's directory listing.
|
|
247
314
|
const sameParent = _new.dir == _old.dir;
|
|
248
315
|
// Prevent us from re-grabbing the same directory listing, which still contains `old_path.base.`
|
|
249
316
|
const newDirNode = sameParent ? oldDirNode : await this.findInode(tx, _new.dir, 'rename');
|
|
250
317
|
const newDirList = sameParent
|
|
251
318
|
? oldDirList
|
|
252
|
-
: decodeDirListing((_b = (await tx.get(newDirNode.data))) !== null && _b !== void 0 ? _b : _throw(ErrnoError.With('
|
|
319
|
+
: decodeDirListing((_b = (await tx.get(newDirNode.data))) !== null && _b !== void 0 ? _b : _throw(ErrnoError.With('ENODATA', _new.dir, 'rename')));
|
|
253
320
|
if (newDirList[_new.base]) {
|
|
254
321
|
// If it's a file, delete it, if it's a directory, throw a permissions error.
|
|
255
322
|
const existing = new Inode((_c = (await tx.get(newDirList[_new.base]))) !== null && _c !== void 0 ? _c : _throw(ErrnoError.With('ENOENT', newPath, 'rename')));
|
|
256
|
-
if (!existing.toStats().isFile())
|
|
323
|
+
if (!existing.toStats().isFile())
|
|
257
324
|
throw ErrnoError.With('EPERM', newPath, 'rename');
|
|
258
|
-
}
|
|
259
325
|
await tx.remove(existing.data);
|
|
260
326
|
await tx.remove(newDirList[_new.base]);
|
|
261
327
|
}
|
|
@@ -264,6 +330,7 @@ export class StoreFS extends FileSystem {
|
|
|
264
330
|
await tx.set(oldDirNode.data, encodeDirListing(oldDirList));
|
|
265
331
|
await tx.set(newDirNode.data, encodeDirListing(newDirList));
|
|
266
332
|
await tx.commit();
|
|
333
|
+
this._move(oldPath, newPath);
|
|
267
334
|
}
|
|
268
335
|
catch (e_5) {
|
|
269
336
|
env_5.error = e_5;
|
|
@@ -279,36 +346,35 @@ export class StoreFS extends FileSystem {
|
|
|
279
346
|
var _a, _b, _c;
|
|
280
347
|
const env_6 = { stack: [], error: void 0, hasError: false };
|
|
281
348
|
try {
|
|
282
|
-
const tx = __addDisposableResource(env_6, this.
|
|
349
|
+
const tx = __addDisposableResource(env_6, this.transaction(), false);
|
|
283
350
|
const _old = parse(oldPath), _new = parse(newPath),
|
|
284
351
|
// Remove oldPath from parent's directory listing.
|
|
285
|
-
oldDirNode = this.findInodeSync(tx, _old.dir, 'rename'), oldDirList = decodeDirListing((_a = tx.getSync(oldDirNode.data)) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('
|
|
286
|
-
if (!oldDirList[_old.base])
|
|
352
|
+
oldDirNode = this.findInodeSync(tx, _old.dir, 'rename'), oldDirList = decodeDirListing((_a = tx.getSync(oldDirNode.data)) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENODATA', _old.dir, 'rename')));
|
|
353
|
+
if (!oldDirList[_old.base])
|
|
287
354
|
throw ErrnoError.With('ENOENT', oldPath, 'rename');
|
|
288
|
-
}
|
|
289
355
|
const ino = oldDirList[_old.base];
|
|
356
|
+
if (ino != this._ids.get(oldPath))
|
|
357
|
+
err(`Ino mismatch while renaming ${oldPath} to ${newPath}`);
|
|
290
358
|
delete oldDirList[_old.base];
|
|
291
359
|
/*
|
|
292
360
|
Can't move a folder inside itself.
|
|
293
361
|
This ensures that the check passes only if `oldPath` is a subpath of `_new.dir`.
|
|
294
362
|
We append '/' to avoid matching folders that are a substring of the bottom-most folder in the path.
|
|
295
363
|
*/
|
|
296
|
-
if ((_new.dir + '/').
|
|
364
|
+
if ((_new.dir + '/').startsWith(oldPath + '/'))
|
|
297
365
|
throw new ErrnoError(Errno.EBUSY, _old.dir);
|
|
298
|
-
}
|
|
299
366
|
// Add newPath to parent's directory listing.
|
|
300
367
|
const sameParent = _new.dir === _old.dir;
|
|
301
368
|
// Prevent us from re-grabbing the same directory listing, which still contains `old_path.base.`
|
|
302
369
|
const newDirNode = sameParent ? oldDirNode : this.findInodeSync(tx, _new.dir, 'rename');
|
|
303
370
|
const newDirList = sameParent
|
|
304
371
|
? oldDirList
|
|
305
|
-
: decodeDirListing((_b = tx.getSync(newDirNode.data)) !== null && _b !== void 0 ? _b : _throw(ErrnoError.With('
|
|
372
|
+
: decodeDirListing((_b = tx.getSync(newDirNode.data)) !== null && _b !== void 0 ? _b : _throw(ErrnoError.With('ENODATA', _new.dir, 'rename')));
|
|
306
373
|
if (newDirList[_new.base]) {
|
|
307
374
|
// If it's a file, delete it, if it's a directory, throw a permissions error.
|
|
308
375
|
const existing = new Inode((_c = tx.getSync(newDirList[_new.base])) !== null && _c !== void 0 ? _c : _throw(ErrnoError.With('ENOENT', newPath, 'rename')));
|
|
309
|
-
if (!existing.toStats().isFile())
|
|
376
|
+
if (!existing.toStats().isFile())
|
|
310
377
|
throw ErrnoError.With('EPERM', newPath, 'rename');
|
|
311
|
-
}
|
|
312
378
|
tx.removeSync(existing.data);
|
|
313
379
|
tx.removeSync(newDirList[_new.base]);
|
|
314
380
|
}
|
|
@@ -317,6 +383,7 @@ export class StoreFS extends FileSystem {
|
|
|
317
383
|
tx.setSync(oldDirNode.data, encodeDirListing(oldDirList));
|
|
318
384
|
tx.setSync(newDirNode.data, encodeDirListing(newDirList));
|
|
319
385
|
tx.commitSync();
|
|
386
|
+
this._move(oldPath, newPath);
|
|
320
387
|
}
|
|
321
388
|
catch (e_6) {
|
|
322
389
|
env_6.error = e_6;
|
|
@@ -329,7 +396,7 @@ export class StoreFS extends FileSystem {
|
|
|
329
396
|
async stat(path) {
|
|
330
397
|
const env_7 = { stack: [], error: void 0, hasError: false };
|
|
331
398
|
try {
|
|
332
|
-
const tx = __addDisposableResource(env_7, this.
|
|
399
|
+
const tx = __addDisposableResource(env_7, this.transaction(), true);
|
|
333
400
|
return (await this.findInode(tx, path, 'stat')).toStats();
|
|
334
401
|
}
|
|
335
402
|
catch (e_7) {
|
|
@@ -345,7 +412,7 @@ export class StoreFS extends FileSystem {
|
|
|
345
412
|
statSync(path) {
|
|
346
413
|
const env_8 = { stack: [], error: void 0, hasError: false };
|
|
347
414
|
try {
|
|
348
|
-
const tx = __addDisposableResource(env_8, this.
|
|
415
|
+
const tx = __addDisposableResource(env_8, this.transaction(), false);
|
|
349
416
|
return this.findInodeSync(tx, path, 'stat').toStats();
|
|
350
417
|
}
|
|
351
418
|
catch (e_8) {
|
|
@@ -357,19 +424,18 @@ export class StoreFS extends FileSystem {
|
|
|
357
424
|
}
|
|
358
425
|
}
|
|
359
426
|
async createFile(path, flag, mode, options) {
|
|
360
|
-
const node = await this.commitNew(path,
|
|
427
|
+
const node = await this.commitNew(path, { mode: mode | S_IFREG, ...options }, new Uint8Array(), 'createFile');
|
|
361
428
|
return new LazyFile(this, path, flag, node.toStats());
|
|
362
429
|
}
|
|
363
430
|
createFileSync(path, flag, mode, options) {
|
|
364
|
-
const node = this.commitNewSync(path,
|
|
431
|
+
const node = this.commitNewSync(path, { mode: mode | S_IFREG, ...options }, new Uint8Array(), 'createFile');
|
|
365
432
|
return new LazyFile(this, path, flag, node.toStats());
|
|
366
433
|
}
|
|
367
434
|
async openFile(path, flag) {
|
|
368
435
|
const env_9 = { stack: [], error: void 0, hasError: false };
|
|
369
436
|
try {
|
|
370
|
-
const tx = __addDisposableResource(env_9, this.
|
|
437
|
+
const tx = __addDisposableResource(env_9, this.transaction(), true);
|
|
371
438
|
const node = await this.findInode(tx, path, 'openFile');
|
|
372
|
-
//const data = (await tx.get(node.data)) ?? _throw(ErrnoError.With('ENODATA', path, 'openFile'));
|
|
373
439
|
return new LazyFile(this, path, flag, node.toStats());
|
|
374
440
|
}
|
|
375
441
|
catch (e_9) {
|
|
@@ -385,9 +451,8 @@ export class StoreFS extends FileSystem {
|
|
|
385
451
|
openFileSync(path, flag) {
|
|
386
452
|
const env_10 = { stack: [], error: void 0, hasError: false };
|
|
387
453
|
try {
|
|
388
|
-
const tx = __addDisposableResource(env_10, this.
|
|
454
|
+
const tx = __addDisposableResource(env_10, this.transaction(), false);
|
|
389
455
|
const node = this.findInodeSync(tx, path, 'openFile');
|
|
390
|
-
//const data = tx.getSync(node.data) ?? _throw(ErrnoError.With('ENODATA', path, 'openFile'));
|
|
391
456
|
return new LazyFile(this, path, flag, node.toStats());
|
|
392
457
|
}
|
|
393
458
|
catch (e_10) {
|
|
@@ -399,34 +464,34 @@ export class StoreFS extends FileSystem {
|
|
|
399
464
|
}
|
|
400
465
|
}
|
|
401
466
|
async unlink(path) {
|
|
402
|
-
return this.remove(path, false
|
|
467
|
+
return this.remove(path, false);
|
|
403
468
|
}
|
|
404
469
|
unlinkSync(path) {
|
|
405
|
-
this.removeSync(path, false
|
|
470
|
+
this.removeSync(path, false);
|
|
406
471
|
}
|
|
407
472
|
async rmdir(path) {
|
|
408
473
|
if ((await this.readdir(path)).length) {
|
|
409
474
|
throw ErrnoError.With('ENOTEMPTY', path, 'rmdir');
|
|
410
475
|
}
|
|
411
|
-
await this.remove(path, true
|
|
476
|
+
await this.remove(path, true);
|
|
412
477
|
}
|
|
413
478
|
rmdirSync(path) {
|
|
414
479
|
if (this.readdirSync(path).length) {
|
|
415
480
|
throw ErrnoError.With('ENOTEMPTY', path, 'rmdir');
|
|
416
481
|
}
|
|
417
|
-
this.removeSync(path, true
|
|
482
|
+
this.removeSync(path, true);
|
|
418
483
|
}
|
|
419
484
|
async mkdir(path, mode, options) {
|
|
420
|
-
await this.commitNew(path,
|
|
485
|
+
await this.commitNew(path, { mode: mode | S_IFDIR, ...options }, encodeUTF8('{}'), 'mkdir');
|
|
421
486
|
}
|
|
422
487
|
mkdirSync(path, mode, options) {
|
|
423
|
-
this.commitNewSync(path,
|
|
488
|
+
this.commitNewSync(path, { mode: mode | S_IFDIR, ...options }, encodeUTF8('{}'), 'mkdir');
|
|
424
489
|
}
|
|
425
490
|
async readdir(path) {
|
|
426
491
|
var _a;
|
|
427
492
|
const env_11 = { stack: [], error: void 0, hasError: false };
|
|
428
493
|
try {
|
|
429
|
-
const tx = __addDisposableResource(env_11, this.
|
|
494
|
+
const tx = __addDisposableResource(env_11, this.transaction(), true);
|
|
430
495
|
const node = await this.findInode(tx, path, 'readdir');
|
|
431
496
|
return Object.keys(decodeDirListing((_a = (await tx.get(node.data))) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENOENT', path, 'readdir'))));
|
|
432
497
|
}
|
|
@@ -444,7 +509,7 @@ export class StoreFS extends FileSystem {
|
|
|
444
509
|
var _a;
|
|
445
510
|
const env_12 = { stack: [], error: void 0, hasError: false };
|
|
446
511
|
try {
|
|
447
|
-
const tx = __addDisposableResource(env_12, this.
|
|
512
|
+
const tx = __addDisposableResource(env_12, this.transaction(), false);
|
|
448
513
|
const node = this.findInodeSync(tx, path, 'readdir');
|
|
449
514
|
return Object.keys(decodeDirListing((_a = tx.getSync(node.data)) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENOENT', path, 'readdir'))));
|
|
450
515
|
}
|
|
@@ -463,12 +528,14 @@ export class StoreFS extends FileSystem {
|
|
|
463
528
|
async sync(path, data, metadata) {
|
|
464
529
|
const env_13 = { stack: [], error: void 0, hasError: false };
|
|
465
530
|
try {
|
|
466
|
-
const tx = __addDisposableResource(env_13, this.
|
|
531
|
+
const tx = __addDisposableResource(env_13, this.transaction(), true);
|
|
467
532
|
const inode = await this.findInode(tx, path, 'sync');
|
|
468
533
|
if (data)
|
|
469
534
|
await tx.set(inode.data, data);
|
|
470
|
-
if (inode.update(metadata))
|
|
535
|
+
if (inode.update(metadata)) {
|
|
536
|
+
this._add(inode.ino, path);
|
|
471
537
|
await tx.set(inode.ino, serialize(inode));
|
|
538
|
+
}
|
|
472
539
|
await tx.commit();
|
|
473
540
|
}
|
|
474
541
|
catch (e_13) {
|
|
@@ -488,12 +555,14 @@ export class StoreFS extends FileSystem {
|
|
|
488
555
|
syncSync(path, data, metadata) {
|
|
489
556
|
const env_14 = { stack: [], error: void 0, hasError: false };
|
|
490
557
|
try {
|
|
491
|
-
const tx = __addDisposableResource(env_14, this.
|
|
558
|
+
const tx = __addDisposableResource(env_14, this.transaction(), false);
|
|
492
559
|
const inode = this.findInodeSync(tx, path, 'sync');
|
|
493
560
|
if (data)
|
|
494
561
|
tx.setSync(inode.data, data);
|
|
495
|
-
if (inode.update(metadata))
|
|
562
|
+
if (inode.update(metadata)) {
|
|
563
|
+
this._add(inode.ino, path);
|
|
496
564
|
tx.setSync(inode.ino, serialize(inode));
|
|
565
|
+
}
|
|
497
566
|
tx.commitSync();
|
|
498
567
|
}
|
|
499
568
|
catch (e_14) {
|
|
@@ -508,14 +577,15 @@ export class StoreFS extends FileSystem {
|
|
|
508
577
|
var _a;
|
|
509
578
|
const env_15 = { stack: [], error: void 0, hasError: false };
|
|
510
579
|
try {
|
|
511
|
-
const tx = __addDisposableResource(env_15, this.
|
|
580
|
+
const tx = __addDisposableResource(env_15, this.transaction(), true);
|
|
512
581
|
const newDir = dirname(link), newDirNode = await this.findInode(tx, newDir, 'link'), listing = decodeDirListing((_a = (await tx.get(newDirNode.data))) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENOENT', newDir, 'link')));
|
|
513
582
|
const inode = await this.findInode(tx, target, 'link');
|
|
514
583
|
inode.nlink++;
|
|
515
584
|
listing[basename(link)] = inode.ino;
|
|
516
|
-
|
|
517
|
-
tx.
|
|
518
|
-
tx.
|
|
585
|
+
this._add(inode.ino, link);
|
|
586
|
+
await tx.set(inode.ino, serialize(inode));
|
|
587
|
+
await tx.set(newDirNode.data, encodeDirListing(listing));
|
|
588
|
+
await tx.commit();
|
|
519
589
|
}
|
|
520
590
|
catch (e_15) {
|
|
521
591
|
env_15.error = e_15;
|
|
@@ -531,11 +601,12 @@ export class StoreFS extends FileSystem {
|
|
|
531
601
|
var _a;
|
|
532
602
|
const env_16 = { stack: [], error: void 0, hasError: false };
|
|
533
603
|
try {
|
|
534
|
-
const tx = __addDisposableResource(env_16, this.
|
|
604
|
+
const tx = __addDisposableResource(env_16, this.transaction(), false);
|
|
535
605
|
const newDir = dirname(link), newDirNode = this.findInodeSync(tx, newDir, 'link'), listing = decodeDirListing((_a = tx.getSync(newDirNode.data)) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENOENT', newDir, 'link')));
|
|
536
606
|
const inode = this.findInodeSync(tx, target, 'link');
|
|
537
607
|
inode.nlink++;
|
|
538
608
|
listing[basename(link)] = inode.ino;
|
|
609
|
+
this._add(inode.ino, link);
|
|
539
610
|
tx.setSync(inode.ino, serialize(inode));
|
|
540
611
|
tx.setSync(newDirNode.data, encodeDirListing(listing));
|
|
541
612
|
tx.commitSync();
|
|
@@ -552,10 +623,15 @@ export class StoreFS extends FileSystem {
|
|
|
552
623
|
var _a;
|
|
553
624
|
const env_17 = { stack: [], error: void 0, hasError: false };
|
|
554
625
|
try {
|
|
555
|
-
const tx = __addDisposableResource(env_17, this.
|
|
626
|
+
const tx = __addDisposableResource(env_17, this.transaction(), true);
|
|
556
627
|
const inode = await this.findInode(tx, path, 'read');
|
|
557
|
-
|
|
558
|
-
|
|
628
|
+
if (inode.size == 0)
|
|
629
|
+
return;
|
|
630
|
+
const data = (_a = (await tx.get(inode.data, offset, end))) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENODATA', path, 'read'));
|
|
631
|
+
const _ = tx.flag('partial') ? data : data.subarray(offset, end);
|
|
632
|
+
if (_.byteLength > buffer.byteLength)
|
|
633
|
+
err(`Trying to place ${_.byteLength} bytes into a ${buffer.byteLength} byte buffer on read`);
|
|
634
|
+
buffer.set(_);
|
|
559
635
|
}
|
|
560
636
|
catch (e_17) {
|
|
561
637
|
env_17.error = e_17;
|
|
@@ -571,10 +647,15 @@ export class StoreFS extends FileSystem {
|
|
|
571
647
|
var _a;
|
|
572
648
|
const env_18 = { stack: [], error: void 0, hasError: false };
|
|
573
649
|
try {
|
|
574
|
-
const tx = __addDisposableResource(env_18, this.
|
|
650
|
+
const tx = __addDisposableResource(env_18, this.transaction(), false);
|
|
575
651
|
const inode = this.findInodeSync(tx, path, 'read');
|
|
576
|
-
|
|
577
|
-
|
|
652
|
+
if (inode.size == 0)
|
|
653
|
+
return;
|
|
654
|
+
const data = (_a = tx.getSync(inode.data, offset, end)) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENODATA', path, 'read'));
|
|
655
|
+
const _ = tx.flag('partial') ? data : data.subarray(offset, end);
|
|
656
|
+
if (_.byteLength > buffer.byteLength)
|
|
657
|
+
err(`Trying to place ${_.byteLength} bytes into a ${buffer.byteLength} byte buffer on read`);
|
|
658
|
+
buffer.set(_);
|
|
578
659
|
}
|
|
579
660
|
catch (e_18) {
|
|
580
661
|
env_18.error = e_18;
|
|
@@ -585,15 +666,21 @@ export class StoreFS extends FileSystem {
|
|
|
585
666
|
}
|
|
586
667
|
}
|
|
587
668
|
async write(path, data, offset) {
|
|
669
|
+
var _a;
|
|
588
670
|
const env_19 = { stack: [], error: void 0, hasError: false };
|
|
589
671
|
try {
|
|
590
|
-
const tx = __addDisposableResource(env_19, this.
|
|
672
|
+
const tx = __addDisposableResource(env_19, this.transaction(), true);
|
|
591
673
|
const inode = await this.findInode(tx, path, 'write');
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
674
|
+
let buffer = data;
|
|
675
|
+
if (!tx.flag('partial')) {
|
|
676
|
+
buffer = extendBuffer((_a = (await tx.get(inode.data))) !== null && _a !== void 0 ? _a : new Uint8Array(), offset + data.byteLength);
|
|
677
|
+
buffer.set(data, offset);
|
|
678
|
+
offset = 0;
|
|
679
|
+
}
|
|
680
|
+
await tx.set(inode.data, buffer, offset);
|
|
681
|
+
inode.update({ mtimeMs: Date.now(), size: Math.max(inode.size, data.byteLength + offset) });
|
|
682
|
+
this._add(inode.ino, path);
|
|
595
683
|
await tx.set(inode.ino, serialize(inode));
|
|
596
|
-
await tx.set(inode.data, buffer);
|
|
597
684
|
await tx.commit();
|
|
598
685
|
}
|
|
599
686
|
catch (e_19) {
|
|
@@ -607,15 +694,21 @@ export class StoreFS extends FileSystem {
|
|
|
607
694
|
}
|
|
608
695
|
}
|
|
609
696
|
writeSync(path, data, offset) {
|
|
697
|
+
var _a;
|
|
610
698
|
const env_20 = { stack: [], error: void 0, hasError: false };
|
|
611
699
|
try {
|
|
612
|
-
const tx = __addDisposableResource(env_20, this.
|
|
700
|
+
const tx = __addDisposableResource(env_20, this.transaction(), false);
|
|
613
701
|
const inode = this.findInodeSync(tx, path, 'write');
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
702
|
+
let buffer = data;
|
|
703
|
+
if (!tx.flag('partial')) {
|
|
704
|
+
buffer = extendBuffer((_a = tx.getSync(inode.data)) !== null && _a !== void 0 ? _a : new Uint8Array(), offset + data.byteLength);
|
|
705
|
+
buffer.set(data, offset);
|
|
706
|
+
offset = 0;
|
|
707
|
+
}
|
|
708
|
+
tx.setSync(inode.data, buffer, offset);
|
|
709
|
+
inode.update({ mtimeMs: Date.now(), size: Math.max(inode.size, data.byteLength + offset) });
|
|
710
|
+
this._add(inode.ino, path);
|
|
617
711
|
tx.setSync(inode.ino, serialize(inode));
|
|
618
|
-
tx.setSync(inode.data, buffer);
|
|
619
712
|
tx.commitSync();
|
|
620
713
|
}
|
|
621
714
|
catch (e_20) {
|
|
@@ -626,21 +719,25 @@ export class StoreFS extends FileSystem {
|
|
|
626
719
|
__disposeResources(env_20);
|
|
627
720
|
}
|
|
628
721
|
}
|
|
722
|
+
/**
|
|
723
|
+
* Wraps a transaction
|
|
724
|
+
* @internal @hidden
|
|
725
|
+
*/
|
|
726
|
+
transaction() {
|
|
727
|
+
return new WrappedTransaction(this.store.transaction(), this);
|
|
728
|
+
}
|
|
629
729
|
/**
|
|
630
730
|
* Checks if the root directory exists. Creates it if it doesn't.
|
|
631
731
|
*/
|
|
632
732
|
async checkRoot() {
|
|
633
733
|
const env_21 = { stack: [], error: void 0, hasError: false };
|
|
634
734
|
try {
|
|
635
|
-
const tx = __addDisposableResource(env_21, this.
|
|
735
|
+
const tx = __addDisposableResource(env_21, this.transaction(), true);
|
|
636
736
|
if (await tx.get(rootIno))
|
|
637
737
|
return;
|
|
638
|
-
|
|
639
|
-
const inode = new Inode();
|
|
640
|
-
inode.ino = rootIno;
|
|
641
|
-
inode.mode = 0o777 | S_IFDIR;
|
|
642
|
-
// If the root doesn't exist, the first random ID shouldn't exist either.
|
|
738
|
+
const inode = new Inode({ ino: rootIno, data: 1, mode: 0o777 | S_IFDIR });
|
|
643
739
|
await tx.set(inode.data, encodeUTF8('{}'));
|
|
740
|
+
this._add(rootIno, '/');
|
|
644
741
|
await tx.set(rootIno, serialize(inode));
|
|
645
742
|
await tx.commit();
|
|
646
743
|
}
|
|
@@ -660,15 +757,12 @@ export class StoreFS extends FileSystem {
|
|
|
660
757
|
checkRootSync() {
|
|
661
758
|
const env_22 = { stack: [], error: void 0, hasError: false };
|
|
662
759
|
try {
|
|
663
|
-
const tx = __addDisposableResource(env_22, this.
|
|
760
|
+
const tx = __addDisposableResource(env_22, this.transaction(), false);
|
|
664
761
|
if (tx.getSync(rootIno))
|
|
665
762
|
return;
|
|
666
|
-
|
|
667
|
-
const inode = new Inode();
|
|
668
|
-
inode.ino = rootIno;
|
|
669
|
-
inode.mode = 0o777 | S_IFDIR;
|
|
670
|
-
// If the root doesn't exist, the first random ID shouldn't exist either.
|
|
763
|
+
const inode = new Inode({ ino: rootIno, data: 1, mode: 0o777 | S_IFDIR });
|
|
671
764
|
tx.setSync(inode.data, encodeUTF8('{}'));
|
|
765
|
+
this._add(rootIno, '/');
|
|
672
766
|
tx.setSync(rootIno, serialize(inode));
|
|
673
767
|
tx.commitSync();
|
|
674
768
|
}
|
|
@@ -681,64 +775,90 @@ export class StoreFS extends FileSystem {
|
|
|
681
775
|
}
|
|
682
776
|
}
|
|
683
777
|
/**
|
|
684
|
-
*
|
|
685
|
-
* @param parent The parent directory of the file we are attempting to find.
|
|
686
|
-
* @param filename The filename of the inode we are attempting to find, minus
|
|
687
|
-
* the parent.
|
|
688
|
-
*/
|
|
689
|
-
async _findInode(tx, path, syscall, visited = new Set()) {
|
|
690
|
-
var _a, _b;
|
|
691
|
-
if (visited.has(path)) {
|
|
692
|
-
throw new ErrnoError(Errno.EIO, 'Infinite loop detected while finding inode', path);
|
|
693
|
-
}
|
|
694
|
-
visited.add(path);
|
|
695
|
-
if (path == '/') {
|
|
696
|
-
return rootIno;
|
|
697
|
-
}
|
|
698
|
-
const { dir: parent, base: filename } = parse(path);
|
|
699
|
-
const inode = parent == '/'
|
|
700
|
-
? new Inode((_a = (await tx.get(rootIno))) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENOENT', parent, syscall)))
|
|
701
|
-
: await this.findInode(tx, parent, syscall, visited);
|
|
702
|
-
const dirList = decodeDirListing((_b = (await tx.get(inode.data))) !== null && _b !== void 0 ? _b : _throw(ErrnoError.With('ENODATA', parent, syscall)));
|
|
703
|
-
if (!(filename in dirList)) {
|
|
704
|
-
throw ErrnoError.With('ENOENT', resolve(parent, filename), syscall);
|
|
705
|
-
}
|
|
706
|
-
return dirList[filename];
|
|
707
|
-
}
|
|
708
|
-
/**
|
|
709
|
-
* Helper function for findINode.
|
|
710
|
-
* @param parent The parent directory of the file we are attempting to find.
|
|
711
|
-
* @param filename The filename of the inode we are attempting to find, minus
|
|
712
|
-
* the parent.
|
|
713
|
-
* @return string The ID of the file's inode in the file system.
|
|
778
|
+
* Populates the `_ids` and `_paths` maps with all existing files stored in the underlying `Store`.
|
|
714
779
|
*/
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
780
|
+
async _populate() {
|
|
781
|
+
const env_23 = { stack: [], error: void 0, hasError: false };
|
|
782
|
+
try {
|
|
783
|
+
if (this._initialized) {
|
|
784
|
+
warn('Attempted to populate tables after initialization');
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
debug('Populating tables with existing store metadata.');
|
|
788
|
+
const tx = __addDisposableResource(env_23, this.transaction(), true);
|
|
789
|
+
const rootData = await tx.get(rootIno);
|
|
790
|
+
if (!rootData) {
|
|
791
|
+
notice('Store does not have a root inode.');
|
|
792
|
+
const inode = new Inode({ ino: rootIno, data: 1, mode: 0o777 | S_IFDIR });
|
|
793
|
+
await tx.set(inode.data, encodeUTF8('{}'));
|
|
794
|
+
this._add(rootIno, '/');
|
|
795
|
+
await tx.set(rootIno, serialize(inode));
|
|
796
|
+
await tx.commit();
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
if (rootData.length != __inode_sz) {
|
|
800
|
+
crit('Store contains an invalid root inode. Refusing to populate tables.');
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
803
|
+
// Keep track of directories we have already traversed to avoid loops
|
|
804
|
+
const visitedDirectories = new Set();
|
|
805
|
+
let i = 0;
|
|
806
|
+
// Start BFS from root
|
|
807
|
+
const queue = [['/', rootIno]];
|
|
808
|
+
while (queue.length > 0) {
|
|
809
|
+
i++;
|
|
810
|
+
const [path, ino] = queue.shift();
|
|
811
|
+
this._add(ino, path);
|
|
812
|
+
// Get the inode data from the store
|
|
813
|
+
const inodeData = await tx.get(ino);
|
|
814
|
+
if (!inodeData) {
|
|
815
|
+
warn('Store is missing data for inode: ' + ino);
|
|
816
|
+
continue;
|
|
817
|
+
}
|
|
818
|
+
if (inodeData.length != __inode_sz) {
|
|
819
|
+
warn(`Invalid inode size for ino ${ino}: ${inodeData.length}`);
|
|
820
|
+
continue;
|
|
821
|
+
}
|
|
822
|
+
// Parse the raw data into our Inode object
|
|
823
|
+
const inode = new Inode(inodeData);
|
|
824
|
+
// If it is a directory and not yet visited, read its directory listing
|
|
825
|
+
if ((inode.mode & S_IFDIR) != S_IFDIR || visitedDirectories.has(ino)) {
|
|
826
|
+
continue;
|
|
827
|
+
}
|
|
828
|
+
visitedDirectories.add(ino);
|
|
829
|
+
// Grab the directory listing from the store
|
|
830
|
+
const dirData = await tx.get(inode.data);
|
|
831
|
+
if (!dirData) {
|
|
832
|
+
warn('Store is missing directory data: ' + inode.data);
|
|
833
|
+
continue;
|
|
834
|
+
}
|
|
835
|
+
const dirListing = decodeDirListing(dirData);
|
|
836
|
+
for (const [entryName, childIno] of Object.entries(dirListing)) {
|
|
837
|
+
queue.push([join(path, entryName), childIno]);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
debug(`Added ${i} existing inode(s) from store`);
|
|
719
841
|
}
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
842
|
+
catch (e_23) {
|
|
843
|
+
env_23.error = e_23;
|
|
844
|
+
env_23.hasError = true;
|
|
723
845
|
}
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
const dir = decodeDirListing((_b = tx.getSync(inode.data)) !== null && _b !== void 0 ? _b : _throw(ErrnoError.With('ENODATA', parent, syscall)));
|
|
729
|
-
if (!(filename in dir)) {
|
|
730
|
-
throw ErrnoError.With('ENOENT', resolve(parent, filename), syscall);
|
|
846
|
+
finally {
|
|
847
|
+
const result_12 = __disposeResources(env_23);
|
|
848
|
+
if (result_12)
|
|
849
|
+
await result_12;
|
|
731
850
|
}
|
|
732
|
-
return dir[filename];
|
|
733
851
|
}
|
|
734
852
|
/**
|
|
735
853
|
* Finds the Inode of `path`.
|
|
736
854
|
* @param path The path to look up.
|
|
737
855
|
* @todo memoize/cache
|
|
738
856
|
*/
|
|
739
|
-
async findInode(tx, path, syscall
|
|
857
|
+
async findInode(tx, path, syscall) {
|
|
740
858
|
var _a;
|
|
741
|
-
const ino =
|
|
859
|
+
const ino = this._ids.get(path);
|
|
860
|
+
if (ino === undefined)
|
|
861
|
+
throw ErrnoError.With('ENOENT', path, syscall);
|
|
742
862
|
return new Inode((_a = (await tx.get(ino))) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENOENT', path, syscall)));
|
|
743
863
|
}
|
|
744
864
|
/**
|
|
@@ -747,76 +867,61 @@ export class StoreFS extends FileSystem {
|
|
|
747
867
|
* @return The Inode of the path p.
|
|
748
868
|
* @todo memoize/cache
|
|
749
869
|
*/
|
|
750
|
-
findInodeSync(tx, path, syscall
|
|
870
|
+
findInodeSync(tx, path, syscall) {
|
|
751
871
|
var _a;
|
|
752
|
-
const ino = this.
|
|
872
|
+
const ino = this._ids.get(path);
|
|
873
|
+
if (ino === undefined)
|
|
874
|
+
throw ErrnoError.With('ENOENT', path, syscall);
|
|
753
875
|
return new Inode((_a = tx.getSync(ino)) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENOENT', path, syscall)));
|
|
754
876
|
}
|
|
755
877
|
/**
|
|
756
|
-
*
|
|
757
|
-
* the exceedingly unlikely chance that we try to reuse a random id.
|
|
758
|
-
*/
|
|
759
|
-
async allocNew(tx, path, syscall) {
|
|
760
|
-
for (let i = 0; i < maxInodeAllocTries; i++) {
|
|
761
|
-
const ino = randomInt(0, size_max);
|
|
762
|
-
if (await tx.get(ino)) {
|
|
763
|
-
continue;
|
|
764
|
-
}
|
|
765
|
-
return ino;
|
|
766
|
-
}
|
|
767
|
-
throw new ErrnoError(Errno.ENOSPC, 'No IDs available', path, syscall);
|
|
768
|
-
}
|
|
769
|
-
/**
|
|
770
|
-
* Creates a new node under a random ID. Retries before giving up in
|
|
771
|
-
* the exceedingly unlikely chance that we try to reuse a random id.
|
|
772
|
-
* @return The ino that the data was stored under.
|
|
878
|
+
* Allocates a new ID and adds the ID/path
|
|
773
879
|
*/
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
880
|
+
allocNew(path, syscall) {
|
|
881
|
+
var _a;
|
|
882
|
+
(_a = this._lastID) !== null && _a !== void 0 ? _a : (this._lastID = Math.max(...this._paths.keys()));
|
|
883
|
+
this._lastID += 2;
|
|
884
|
+
const id = this._lastID;
|
|
885
|
+
if (id > size_max)
|
|
886
|
+
throw err(new ErrnoError(Errno.ENOSPC, 'No IDs available', path, syscall), { fs: this });
|
|
887
|
+
this._add(id, path);
|
|
888
|
+
return id;
|
|
783
889
|
}
|
|
784
890
|
/**
|
|
785
891
|
* Commits a new file (well, a FILE or a DIRECTORY) to the file system with `mode`.
|
|
786
892
|
* Note: This will commit the transaction.
|
|
787
893
|
* @param path The path to the new file.
|
|
788
|
-
* @param
|
|
789
|
-
* @param mode The mode to create the new file with.
|
|
894
|
+
* @param options The options to create the new file with.
|
|
790
895
|
* @param data The data to store at the file's data node.
|
|
791
896
|
*/
|
|
792
|
-
async commitNew(path,
|
|
897
|
+
async commitNew(path, options, data, syscall) {
|
|
793
898
|
var _a;
|
|
794
|
-
const
|
|
899
|
+
const env_24 = { stack: [], error: void 0, hasError: false };
|
|
795
900
|
try {
|
|
796
901
|
/*
|
|
797
902
|
The root always exists.
|
|
798
903
|
If we don't check this prior to taking steps below,
|
|
799
904
|
we will create a file with name '' in root if path is '/'.
|
|
800
905
|
*/
|
|
801
|
-
if (path == '/')
|
|
906
|
+
if (path == '/')
|
|
802
907
|
throw ErrnoError.With('EEXIST', path, syscall);
|
|
803
|
-
|
|
804
|
-
const tx = __addDisposableResource(env_23, this.store.transaction(), true);
|
|
908
|
+
const tx = __addDisposableResource(env_24, this.transaction(), true);
|
|
805
909
|
const { dir: parentPath, base: fname } = parse(path);
|
|
806
910
|
const parent = await this.findInode(tx, parentPath, syscall);
|
|
807
911
|
const listing = decodeDirListing((_a = (await tx.get(parent.data))) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENOENT', parentPath, syscall)));
|
|
808
912
|
// Check if file already exists.
|
|
809
|
-
if (listing[fname])
|
|
913
|
+
if (listing[fname])
|
|
810
914
|
throw ErrnoError.With('EEXIST', path, syscall);
|
|
811
|
-
|
|
915
|
+
const id = this.allocNew(path, syscall);
|
|
812
916
|
// Commit data.
|
|
813
|
-
const inode = new Inode(
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
917
|
+
const inode = new Inode({
|
|
918
|
+
ino: id,
|
|
919
|
+
data: id + 1,
|
|
920
|
+
mode: options.mode,
|
|
921
|
+
size: data.byteLength,
|
|
922
|
+
uid: parent.mode & S_ISUID ? parent.uid : options.uid,
|
|
923
|
+
gid: parent.mode & S_ISGID ? parent.gid : options.gid,
|
|
924
|
+
});
|
|
820
925
|
await tx.set(inode.ino, serialize(inode));
|
|
821
926
|
await tx.set(inode.data, data);
|
|
822
927
|
// Update and commit parent directory listing.
|
|
@@ -825,53 +930,52 @@ export class StoreFS extends FileSystem {
|
|
|
825
930
|
await tx.commit();
|
|
826
931
|
return inode;
|
|
827
932
|
}
|
|
828
|
-
catch (
|
|
829
|
-
|
|
830
|
-
|
|
933
|
+
catch (e_24) {
|
|
934
|
+
env_24.error = e_24;
|
|
935
|
+
env_24.hasError = true;
|
|
831
936
|
}
|
|
832
937
|
finally {
|
|
833
|
-
const
|
|
834
|
-
if (
|
|
835
|
-
await
|
|
938
|
+
const result_13 = __disposeResources(env_24);
|
|
939
|
+
if (result_13)
|
|
940
|
+
await result_13;
|
|
836
941
|
}
|
|
837
942
|
}
|
|
838
943
|
/**
|
|
839
944
|
* Commits a new file (well, a FILE or a DIRECTORY) to the file system with `mode`.
|
|
840
945
|
* Note: This will commit the transaction.
|
|
841
946
|
* @param path The path to the new file.
|
|
842
|
-
* @param
|
|
843
|
-
* @param mode The mode to create the new file with.
|
|
947
|
+
* @param options The options to create the new file with.
|
|
844
948
|
* @param data The data to store at the file's data node.
|
|
845
949
|
* @return The Inode for the new file.
|
|
846
950
|
*/
|
|
847
|
-
commitNewSync(path,
|
|
951
|
+
commitNewSync(path, options, data, syscall) {
|
|
848
952
|
var _a;
|
|
849
|
-
const
|
|
953
|
+
const env_25 = { stack: [], error: void 0, hasError: false };
|
|
850
954
|
try {
|
|
851
955
|
/*
|
|
852
956
|
The root always exists.
|
|
853
957
|
If we don't check this prior to taking steps below,
|
|
854
958
|
we will create a file with name '' in root if path is '/'.
|
|
855
959
|
*/
|
|
856
|
-
if (path == '/')
|
|
960
|
+
if (path == '/')
|
|
857
961
|
throw ErrnoError.With('EEXIST', path, syscall);
|
|
858
|
-
|
|
859
|
-
const tx = __addDisposableResource(env_24, this.store.transaction(), false);
|
|
962
|
+
const tx = __addDisposableResource(env_25, this.transaction(), false);
|
|
860
963
|
const { dir: parentPath, base: fname } = parse(path);
|
|
861
964
|
const parent = this.findInodeSync(tx, parentPath, syscall);
|
|
862
965
|
const listing = decodeDirListing((_a = tx.getSync(parent.data)) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENOENT', parentPath, syscall)));
|
|
863
966
|
// Check if file already exists.
|
|
864
|
-
if (listing[fname])
|
|
967
|
+
if (listing[fname])
|
|
865
968
|
throw ErrnoError.With('EEXIST', path, syscall);
|
|
866
|
-
|
|
969
|
+
const id = this.allocNew(path, syscall);
|
|
867
970
|
// Commit data.
|
|
868
|
-
const inode = new Inode(
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
971
|
+
const inode = new Inode({
|
|
972
|
+
ino: id,
|
|
973
|
+
data: id + 1,
|
|
974
|
+
mode: options.mode,
|
|
975
|
+
size: data.byteLength,
|
|
976
|
+
uid: parent.mode & S_ISUID ? parent.uid : options.uid,
|
|
977
|
+
gid: parent.mode & S_ISGID ? parent.gid : options.gid,
|
|
978
|
+
});
|
|
875
979
|
// Update and commit parent directory listing.
|
|
876
980
|
tx.setSync(inode.ino, serialize(inode));
|
|
877
981
|
tx.setSync(inode.data, data);
|
|
@@ -880,12 +984,12 @@ export class StoreFS extends FileSystem {
|
|
|
880
984
|
tx.commitSync();
|
|
881
985
|
return inode;
|
|
882
986
|
}
|
|
883
|
-
catch (
|
|
884
|
-
|
|
885
|
-
|
|
987
|
+
catch (e_25) {
|
|
988
|
+
env_25.error = e_25;
|
|
989
|
+
env_25.hasError = true;
|
|
886
990
|
}
|
|
887
991
|
finally {
|
|
888
|
-
__disposeResources(
|
|
992
|
+
__disposeResources(env_25);
|
|
889
993
|
}
|
|
890
994
|
}
|
|
891
995
|
/**
|
|
@@ -894,40 +998,41 @@ export class StoreFS extends FileSystem {
|
|
|
894
998
|
* @param isDir Does the path belong to a directory, or a file?
|
|
895
999
|
* @todo Update mtime.
|
|
896
1000
|
*/
|
|
897
|
-
async remove(path, isDir
|
|
1001
|
+
async remove(path, isDir) {
|
|
898
1002
|
var _a, _b;
|
|
899
|
-
const
|
|
1003
|
+
const env_26 = { stack: [], error: void 0, hasError: false };
|
|
900
1004
|
try {
|
|
901
|
-
const
|
|
1005
|
+
const syscall = isDir ? 'rmdir' : 'unlink';
|
|
1006
|
+
const tx = __addDisposableResource(env_26, this.transaction(), true);
|
|
902
1007
|
const { dir: parent, base: fileName } = parse(path), parentNode = await this.findInode(tx, parent, syscall), listing = decodeDirListing((_a = (await tx.get(parentNode.data))) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENOENT', parent, syscall)));
|
|
903
1008
|
if (!listing[fileName]) {
|
|
904
|
-
throw ErrnoError.With('ENOENT', path,
|
|
1009
|
+
throw ErrnoError.With('ENOENT', path, syscall);
|
|
905
1010
|
}
|
|
906
1011
|
const fileIno = listing[fileName];
|
|
907
1012
|
// Get file inode.
|
|
908
1013
|
const fileNode = new Inode((_b = (await tx.get(fileIno))) !== null && _b !== void 0 ? _b : _throw(ErrnoError.With('ENOENT', path, syscall)));
|
|
909
1014
|
// Remove from directory listing of parent.
|
|
910
1015
|
delete listing[fileName];
|
|
911
|
-
if (!isDir && fileNode.toStats().isDirectory())
|
|
912
|
-
throw ErrnoError.With('EISDIR', path,
|
|
913
|
-
}
|
|
1016
|
+
if (!isDir && fileNode.toStats().isDirectory())
|
|
1017
|
+
throw ErrnoError.With('EISDIR', path, syscall);
|
|
914
1018
|
await tx.set(parentNode.data, encodeDirListing(listing));
|
|
915
1019
|
if (--fileNode.nlink < 1) {
|
|
916
1020
|
// remove file
|
|
917
1021
|
await tx.remove(fileNode.data);
|
|
918
1022
|
await tx.remove(fileIno);
|
|
1023
|
+
this._remove(fileIno);
|
|
919
1024
|
}
|
|
920
1025
|
// Success.
|
|
921
1026
|
await tx.commit();
|
|
922
1027
|
}
|
|
923
|
-
catch (
|
|
924
|
-
|
|
925
|
-
|
|
1028
|
+
catch (e_26) {
|
|
1029
|
+
env_26.error = e_26;
|
|
1030
|
+
env_26.hasError = true;
|
|
926
1031
|
}
|
|
927
1032
|
finally {
|
|
928
|
-
const
|
|
929
|
-
if (
|
|
930
|
-
await
|
|
1033
|
+
const result_14 = __disposeResources(env_26);
|
|
1034
|
+
if (result_14)
|
|
1035
|
+
await result_14;
|
|
931
1036
|
}
|
|
932
1037
|
}
|
|
933
1038
|
/**
|
|
@@ -936,21 +1041,21 @@ export class StoreFS extends FileSystem {
|
|
|
936
1041
|
* @param isDir Does the path belong to a directory, or a file?
|
|
937
1042
|
* @todo Update mtime.
|
|
938
1043
|
*/
|
|
939
|
-
removeSync(path, isDir
|
|
1044
|
+
removeSync(path, isDir) {
|
|
940
1045
|
var _a, _b;
|
|
941
|
-
const
|
|
1046
|
+
const env_27 = { stack: [], error: void 0, hasError: false };
|
|
942
1047
|
try {
|
|
943
|
-
const
|
|
1048
|
+
const syscall = isDir ? 'rmdir' : 'unlink';
|
|
1049
|
+
const tx = __addDisposableResource(env_27, this.transaction(), false);
|
|
944
1050
|
const { dir: parent, base: fileName } = parse(path), parentNode = this.findInodeSync(tx, parent, syscall), listing = decodeDirListing((_a = tx.getSync(parentNode.data)) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENOENT', parent, syscall))), fileIno = listing[fileName];
|
|
945
|
-
if (!fileIno)
|
|
946
|
-
throw ErrnoError.With('ENOENT', path,
|
|
947
|
-
}
|
|
1051
|
+
if (!fileIno)
|
|
1052
|
+
throw ErrnoError.With('ENOENT', path, syscall);
|
|
948
1053
|
// Get file inode.
|
|
949
1054
|
const fileNode = new Inode((_b = tx.getSync(fileIno)) !== null && _b !== void 0 ? _b : _throw(ErrnoError.With('ENOENT', path, syscall)));
|
|
950
1055
|
// Remove from directory listing of parent.
|
|
951
1056
|
delete listing[fileName];
|
|
952
1057
|
if (!isDir && fileNode.toStats().isDirectory()) {
|
|
953
|
-
throw ErrnoError.With('EISDIR', path,
|
|
1058
|
+
throw ErrnoError.With('EISDIR', path, syscall);
|
|
954
1059
|
}
|
|
955
1060
|
// Update directory listing.
|
|
956
1061
|
tx.setSync(parentNode.data, encodeDirListing(listing));
|
|
@@ -958,16 +1063,17 @@ export class StoreFS extends FileSystem {
|
|
|
958
1063
|
// remove file
|
|
959
1064
|
tx.removeSync(fileNode.data);
|
|
960
1065
|
tx.removeSync(fileIno);
|
|
1066
|
+
this._remove(fileIno);
|
|
961
1067
|
}
|
|
962
1068
|
// Success.
|
|
963
1069
|
tx.commitSync();
|
|
964
1070
|
}
|
|
965
|
-
catch (
|
|
966
|
-
|
|
967
|
-
|
|
1071
|
+
catch (e_27) {
|
|
1072
|
+
env_27.error = e_27;
|
|
1073
|
+
env_27.hasError = true;
|
|
968
1074
|
}
|
|
969
1075
|
finally {
|
|
970
|
-
__disposeResources(
|
|
1076
|
+
__disposeResources(env_27);
|
|
971
1077
|
}
|
|
972
1078
|
}
|
|
973
1079
|
}
|