@zenfs/core 1.11.4 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/dist/backends/backend.d.ts +19 -15
  2. package/dist/backends/backend.js +36 -19
  3. package/dist/backends/cow.d.ts +20 -30
  4. package/dist/backends/cow.js +83 -192
  5. package/dist/backends/fetch.d.ts +1 -0
  6. package/dist/backends/fetch.js +30 -30
  7. package/dist/backends/index.d.ts +1 -1
  8. package/dist/backends/index.js +1 -1
  9. package/dist/backends/memory.d.ts +5 -7
  10. package/dist/backends/memory.js +2 -3
  11. package/dist/backends/passthrough.d.ts +19 -23
  12. package/dist/backends/passthrough.js +98 -288
  13. package/dist/backends/port.d.ts +220 -0
  14. package/dist/backends/port.js +328 -0
  15. package/dist/backends/single_buffer.d.ts +59 -47
  16. package/dist/backends/single_buffer.js +468 -219
  17. package/dist/backends/store/fs.d.ts +25 -35
  18. package/dist/backends/store/fs.js +276 -315
  19. package/dist/backends/store/store.d.ts +10 -15
  20. package/dist/backends/store/store.js +11 -10
  21. package/dist/config.d.ts +3 -12
  22. package/dist/config.js +17 -19
  23. package/dist/context.d.ts +8 -21
  24. package/dist/context.js +33 -10
  25. package/dist/index.d.ts +2 -1
  26. package/dist/index.js +2 -1
  27. package/dist/internal/contexts.d.ts +63 -0
  28. package/dist/internal/contexts.js +15 -0
  29. package/dist/internal/credentials.d.ts +2 -11
  30. package/dist/internal/credentials.js +0 -19
  31. package/dist/internal/devices.d.ts +18 -80
  32. package/dist/internal/devices.js +103 -316
  33. package/dist/internal/error.d.ts +9 -204
  34. package/dist/internal/error.js +19 -288
  35. package/dist/internal/file_index.d.ts +1 -1
  36. package/dist/internal/file_index.js +11 -11
  37. package/dist/internal/filesystem.d.ts +51 -94
  38. package/dist/internal/filesystem.js +21 -20
  39. package/dist/internal/index.d.ts +1 -2
  40. package/dist/internal/index.js +1 -2
  41. package/dist/internal/index_fs.d.ts +12 -30
  42. package/dist/internal/index_fs.js +37 -69
  43. package/dist/internal/inode.d.ts +140 -24
  44. package/dist/internal/inode.js +515 -66
  45. package/dist/mixins/async.js +52 -112
  46. package/dist/mixins/mutexed.d.ts +19 -18
  47. package/dist/mixins/mutexed.js +62 -64
  48. package/dist/mixins/readonly.d.ts +7 -6
  49. package/dist/mixins/readonly.js +24 -18
  50. package/dist/mixins/sync.js +8 -8
  51. package/dist/{vfs/path.d.ts → path.d.ts} +3 -4
  52. package/dist/{vfs/path.js → path.js} +6 -9
  53. package/dist/polyfills.js +1 -1
  54. package/dist/readline.d.ts +134 -0
  55. package/dist/readline.js +623 -0
  56. package/dist/utils.d.ts +9 -37
  57. package/dist/utils.js +17 -85
  58. package/dist/vfs/acl.d.ts +42 -0
  59. package/dist/vfs/acl.js +268 -0
  60. package/dist/vfs/async.d.ts +9 -23
  61. package/dist/vfs/async.js +25 -27
  62. package/dist/vfs/config.d.ts +6 -18
  63. package/dist/vfs/config.js +8 -18
  64. package/dist/vfs/dir.d.ts +3 -3
  65. package/dist/vfs/dir.js +12 -12
  66. package/dist/vfs/file.d.ts +106 -0
  67. package/dist/vfs/file.js +244 -0
  68. package/dist/vfs/flags.d.ts +19 -0
  69. package/dist/vfs/flags.js +62 -0
  70. package/dist/vfs/index.d.ts +4 -10
  71. package/dist/vfs/index.js +4 -13
  72. package/dist/vfs/ioctl.d.ts +88 -0
  73. package/dist/vfs/ioctl.js +409 -0
  74. package/dist/vfs/promises.d.ts +81 -19
  75. package/dist/vfs/promises.js +404 -288
  76. package/dist/vfs/shared.d.ts +7 -37
  77. package/dist/vfs/shared.js +29 -85
  78. package/dist/{stats.d.ts → vfs/stats.d.ts} +14 -28
  79. package/dist/{stats.js → vfs/stats.js} +11 -66
  80. package/dist/vfs/streams.d.ts +1 -0
  81. package/dist/vfs/streams.js +32 -27
  82. package/dist/vfs/sync.d.ts +3 -3
  83. package/dist/vfs/sync.js +263 -260
  84. package/dist/vfs/watchers.d.ts +2 -2
  85. package/dist/vfs/watchers.js +12 -12
  86. package/dist/vfs/xattr.d.ts +116 -0
  87. package/dist/vfs/xattr.js +201 -0
  88. package/package.json +5 -3
  89. package/readme.md +1 -1
  90. package/scripts/test.js +2 -2
  91. package/tests/assignment.ts +1 -1
  92. package/tests/backend/config.worker.js +4 -1
  93. package/tests/backend/fetch.test.ts +3 -0
  94. package/tests/backend/port.test.ts +19 -33
  95. package/tests/backend/remote.worker.js +4 -1
  96. package/tests/backend/single-buffer.test.ts +53 -0
  97. package/tests/backend/single-buffer.worker.js +30 -0
  98. package/tests/common/context.test.ts +3 -3
  99. package/tests/common/handle.test.ts +17 -12
  100. package/tests/common/mutex.test.ts +9 -9
  101. package/tests/common/path.test.ts +1 -1
  102. package/tests/common/readline.test.ts +104 -0
  103. package/tests/common.ts +4 -19
  104. package/tests/fetch/fetch.ts +2 -2
  105. package/tests/fs/append.test.ts +4 -4
  106. package/tests/fs/directory.test.ts +25 -25
  107. package/tests/fs/errors.test.ts +15 -19
  108. package/tests/fs/links.test.ts +4 -3
  109. package/tests/fs/open.test.ts +4 -21
  110. package/tests/fs/permissions.test.ts +14 -18
  111. package/tests/fs/read.test.ts +10 -9
  112. package/tests/fs/readFile.test.ts +10 -26
  113. package/tests/fs/rename.test.ts +4 -9
  114. package/tests/fs/stat.test.ts +8 -8
  115. package/tests/fs/streams.test.ts +2 -11
  116. package/tests/fs/times.test.ts +7 -7
  117. package/tests/fs/truncate.test.ts +8 -36
  118. package/tests/fs/watch.test.ts +10 -10
  119. package/tests/fs/write.test.ts +77 -13
  120. package/tests/fs/xattr.test.ts +85 -0
  121. package/tests/logs.js +22 -0
  122. package/tests/setup/context.ts +1 -1
  123. package/tests/setup/index.ts +3 -3
  124. package/tests/setup/port.ts +7 -1
  125. package/dist/backends/port/fs.d.ts +0 -84
  126. package/dist/backends/port/fs.js +0 -151
  127. package/dist/backends/port/rpc.d.ts +0 -77
  128. package/dist/backends/port/rpc.js +0 -100
  129. package/dist/backends/store/simple.d.ts +0 -20
  130. package/dist/backends/store/simple.js +0 -13
  131. package/dist/internal/file.d.ts +0 -359
  132. package/dist/internal/file.js +0 -751
  133. package/dist/internal/log.d.ts +0 -133
  134. package/dist/internal/log.js +0 -218
  135. package/tests/fs/writeFile.test.ts +0 -70
@@ -50,17 +50,17 @@ 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 { _throw, canary, serialize } from 'utilium';
53
+ import { withErrno } from 'kerium';
54
+ import { crit, debug, err, notice, warn } from 'kerium/log';
55
+ import { sizeof } from 'memium';
56
+ import { _throw, canary, encodeUTF8 } from 'utilium';
54
57
  import { extendBuffer } from 'utilium/buffer.js';
55
- import { Errno, ErrnoError } from '../../internal/error.js';
56
- import { LazyFile } from '../../internal/file.js';
57
58
  import { Index } from '../../internal/file_index.js';
58
59
  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';
62
- import { S_IFDIR, S_IFREG, S_ISGID, S_ISUID, size_max } from '../../vfs/constants.js';
63
- import { basename, dirname, join, parse, relative } from '../../vfs/path.js';
60
+ import { Inode, isDirectory, rootIno } from '../../internal/inode.js';
61
+ import { basename, dirname, join, parse, relative } from '../../path.js';
62
+ import { decodeDirListing, encodeDirListing } from '../../utils.js';
63
+ import { S_IFDIR, S_IFREG, size_max } from '../../vfs/constants.js';
64
64
  import { WrappedTransaction } from './store.js';
65
65
  /**
66
66
  * A file system which uses a `Store`
@@ -132,8 +132,8 @@ export class StoreFS extends FileSystem {
132
132
  this._initialized = true;
133
133
  }
134
134
  constructor(store) {
135
- var _a, _b;
136
- super((_a = store.id) !== null && _a !== void 0 ? _a : 0x6b766673, store.name);
135
+ var _a, _b, _c;
136
+ super((_a = store.type) !== null && _a !== void 0 ? _a : 0x6b766673, store.name);
137
137
  this.store = store;
138
138
  /**
139
139
  * A map of paths to inode IDs
@@ -146,9 +146,10 @@ export class StoreFS extends FileSystem {
146
146
  */
147
147
  this._paths = new Map([[0, new Set('/')]]);
148
148
  this._initialized = false;
149
- this.attributes.set('setid');
150
- store._fs = this;
151
- debug(this.name + ': supports features: ' + ((_b = this.store.flags) === null || _b === void 0 ? void 0 : _b.join(', ')));
149
+ store.fs = this;
150
+ this._uuid = (_b = store.uuid) !== null && _b !== void 0 ? _b : this.uuid;
151
+ this.label = store.label;
152
+ debug(this.name + ': supports features: ' + ((_c = this.store.flags) === null || _c === void 0 ? void 0 : _c.join(', ')));
152
153
  }
153
154
  /**
154
155
  * @experimental
@@ -160,26 +161,6 @@ export class StoreFS extends FileSystem {
160
161
  freeSpace: 0,
161
162
  });
162
163
  }
163
- /* node:coverage disable */
164
- /**
165
- * Delete all contents stored in the file system.
166
- * @deprecated
167
- */
168
- async empty() {
169
- log_deprecated('StoreFS#empty');
170
- // Root always exists.
171
- await this.checkRoot();
172
- }
173
- /**
174
- * Delete all contents stored in the file system.
175
- * @deprecated
176
- */
177
- emptySync() {
178
- log_deprecated('StoreFS#emptySync');
179
- // Root always exists.
180
- this.checkRootSync();
181
- }
182
- /* node:coverage enable */
183
164
  /**
184
165
  * Load an index into the StoreFS.
185
166
  * You *must* manually add non-directory files
@@ -191,7 +172,7 @@ export class StoreFS extends FileSystem {
191
172
  const dirs = index.directories();
192
173
  for (const [path, inode] of index) {
193
174
  this._add(inode.ino, path);
194
- await tx.set(inode.ino, serialize(inode));
175
+ await tx.set(inode.ino, inode);
195
176
  if (dirs.has(path))
196
177
  await tx.set(inode.data, encodeDirListing(dirs.get(path)));
197
178
  }
@@ -218,7 +199,7 @@ export class StoreFS extends FileSystem {
218
199
  const dirs = index.directories();
219
200
  for (const [path, inode] of index) {
220
201
  this._add(inode.ino, path);
221
- tx.setSync(inode.ino, serialize(inode));
202
+ tx.setSync(inode.ino, inode);
222
203
  if (dirs.has(path))
223
204
  tx.setSync(inode.data, encodeDirListing(dirs.get(path)));
224
205
  }
@@ -239,13 +220,13 @@ export class StoreFS extends FileSystem {
239
220
  const index = new Index();
240
221
  const tx = __addDisposableResource(env_3, this.transaction(), true);
241
222
  const queue = [['/', 0]];
242
- const silence = canary(ErrnoError.With('EDEADLK'));
223
+ const silence = canary(withErrno('EDEADLK'));
243
224
  while (queue.length) {
244
225
  const [path, ino] = queue.shift();
245
226
  const inode = new Inode(await tx.get(ino));
246
227
  index.set(path, inode);
247
228
  if (inode.mode & S_IFDIR) {
248
- const dir = decodeDirListing((_a = (await tx.get(inode.data))) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENODATA', path)));
229
+ const dir = decodeDirListing((_a = (await tx.get(inode.data))) !== null && _a !== void 0 ? _a : _throw(withErrno('ENODATA')));
249
230
  for (const [name, id] of Object.entries(dir)) {
250
231
  queue.push([join(path, name), id]);
251
232
  }
@@ -271,13 +252,13 @@ export class StoreFS extends FileSystem {
271
252
  const index = new Index();
272
253
  const tx = __addDisposableResource(env_4, this.transaction(), false);
273
254
  const queue = [['/', 0]];
274
- const silence = canary(ErrnoError.With('EDEADLK'));
255
+ const silence = canary(withErrno('EDEADLK'));
275
256
  while (queue.length) {
276
257
  const [path, ino] = queue.shift();
277
258
  const inode = new Inode(tx.getSync(ino));
278
259
  index.set(path, inode);
279
260
  if (inode.mode & S_IFDIR) {
280
- const dir = decodeDirListing((_a = tx.getSync(inode.data)) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENODATA', path)));
261
+ const dir = decodeDirListing((_a = tx.getSync(inode.data)) !== null && _a !== void 0 ? _a : _throw(withErrno('ENODATA')));
281
262
  for (const [name, id] of Object.entries(dir)) {
282
263
  queue.push([join(path, name), id]);
283
264
  }
@@ -304,9 +285,9 @@ export class StoreFS extends FileSystem {
304
285
  const tx = __addDisposableResource(env_5, this.transaction(), true);
305
286
  const _old = parse(oldPath), _new = parse(newPath),
306
287
  // Remove oldPath from parent's directory listing.
307
- 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')));
288
+ oldDirNode = await this.findInode(tx, _old.dir), oldDirList = decodeDirListing((_a = (await tx.get(oldDirNode.data))) !== null && _a !== void 0 ? _a : _throw(withErrno('ENODATA')));
308
289
  if (!oldDirList[_old.base])
309
- throw ErrnoError.With('ENOENT', oldPath, 'rename');
290
+ throw withErrno('ENOENT');
310
291
  const ino = oldDirList[_old.base];
311
292
  if (ino != this._ids.get(oldPath))
312
293
  err(`Ino mismatch while renaming ${oldPath} to ${newPath}`);
@@ -317,19 +298,17 @@ export class StoreFS extends FileSystem {
317
298
  We append '/' to avoid matching folders that are a substring of the bottom-most folder in the path.
318
299
  */
319
300
  if ((_new.dir + '/').startsWith(oldPath + '/'))
320
- throw new ErrnoError(Errno.EBUSY, _old.dir);
321
- // Add newPath to parent's directory listing.
301
+ throw withErrno('EBUSY');
322
302
  const sameParent = _new.dir == _old.dir;
323
303
  // Prevent us from re-grabbing the same directory listing, which still contains `old_path.base.`
324
- const newDirNode = sameParent ? oldDirNode : await this.findInode(tx, _new.dir, 'rename');
304
+ const newDirNode = sameParent ? oldDirNode : await this.findInode(tx, _new.dir);
325
305
  const newDirList = sameParent
326
306
  ? oldDirList
327
- : decodeDirListing((_b = (await tx.get(newDirNode.data))) !== null && _b !== void 0 ? _b : _throw(ErrnoError.With('ENODATA', _new.dir, 'rename')));
307
+ : decodeDirListing((_b = (await tx.get(newDirNode.data))) !== null && _b !== void 0 ? _b : _throw(withErrno('ENODATA')));
328
308
  if (newDirList[_new.base]) {
329
- // If it's a file, delete it, if it's a directory, throw a permissions error.
330
- const existing = new Inode((_c = (await tx.get(newDirList[_new.base]))) !== null && _c !== void 0 ? _c : _throw(ErrnoError.With('ENOENT', newPath, 'rename')));
309
+ const existing = new Inode((_c = (await tx.get(newDirList[_new.base]))) !== null && _c !== void 0 ? _c : _throw(withErrno('ENOENT')));
331
310
  if (!existing.toStats().isFile())
332
- throw ErrnoError.With('EPERM', newPath, 'rename');
311
+ throw withErrno('EISDIR');
333
312
  await tx.remove(existing.data);
334
313
  await tx.remove(newDirList[_new.base]);
335
314
  }
@@ -357,9 +336,9 @@ export class StoreFS extends FileSystem {
357
336
  const tx = __addDisposableResource(env_6, this.transaction(), false);
358
337
  const _old = parse(oldPath), _new = parse(newPath),
359
338
  // Remove oldPath from parent's directory listing.
360
- 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')));
339
+ oldDirNode = this.findInodeSync(tx, _old.dir), oldDirList = decodeDirListing((_a = tx.getSync(oldDirNode.data)) !== null && _a !== void 0 ? _a : _throw(withErrno('ENODATA')));
361
340
  if (!oldDirList[_old.base])
362
- throw ErrnoError.With('ENOENT', oldPath, 'rename');
341
+ throw withErrno('ENOENT');
363
342
  const ino = oldDirList[_old.base];
364
343
  if (ino != this._ids.get(oldPath))
365
344
  err(`Ino mismatch while renaming ${oldPath} to ${newPath}`);
@@ -370,19 +349,16 @@ export class StoreFS extends FileSystem {
370
349
  We append '/' to avoid matching folders that are a substring of the bottom-most folder in the path.
371
350
  */
372
351
  if ((_new.dir + '/').startsWith(oldPath + '/'))
373
- throw new ErrnoError(Errno.EBUSY, _old.dir);
352
+ throw withErrno('EBUSY');
374
353
  // Add newPath to parent's directory listing.
375
354
  const sameParent = _new.dir === _old.dir;
376
355
  // Prevent us from re-grabbing the same directory listing, which still contains `old_path.base.`
377
- const newDirNode = sameParent ? oldDirNode : this.findInodeSync(tx, _new.dir, 'rename');
378
- const newDirList = sameParent
379
- ? oldDirList
380
- : decodeDirListing((_b = tx.getSync(newDirNode.data)) !== null && _b !== void 0 ? _b : _throw(ErrnoError.With('ENODATA', _new.dir, 'rename')));
356
+ const newDirNode = sameParent ? oldDirNode : this.findInodeSync(tx, _new.dir);
357
+ const newDirList = sameParent ? oldDirList : decodeDirListing((_b = tx.getSync(newDirNode.data)) !== null && _b !== void 0 ? _b : _throw(withErrno('ENODATA')));
381
358
  if (newDirList[_new.base]) {
382
- // If it's a file, delete it, if it's a directory, throw a permissions error.
383
- const existing = new Inode((_c = tx.getSync(newDirList[_new.base])) !== null && _c !== void 0 ? _c : _throw(ErrnoError.With('ENOENT', newPath, 'rename')));
359
+ const existing = new Inode((_c = tx.getSync(newDirList[_new.base])) !== null && _c !== void 0 ? _c : _throw(withErrno('ENOENT')));
384
360
  if (!existing.toStats().isFile())
385
- throw ErrnoError.With('EPERM', newPath, 'rename');
361
+ throw withErrno('EISDIR');
386
362
  tx.removeSync(existing.data);
387
363
  tx.removeSync(newDirList[_new.base]);
388
364
  }
@@ -405,7 +381,7 @@ export class StoreFS extends FileSystem {
405
381
  const env_7 = { stack: [], error: void 0, hasError: false };
406
382
  try {
407
383
  const tx = __addDisposableResource(env_7, this.transaction(), true);
408
- return (await this.findInode(tx, path, 'stat')).toStats();
384
+ return await this.findInode(tx, path);
409
385
  }
410
386
  catch (e_7) {
411
387
  env_7.error = e_7;
@@ -421,7 +397,7 @@ export class StoreFS extends FileSystem {
421
397
  const env_8 = { stack: [], error: void 0, hasError: false };
422
398
  try {
423
399
  const tx = __addDisposableResource(env_8, this.transaction(), false);
424
- return this.findInodeSync(tx, path, 'stat').toStats();
400
+ return this.findInodeSync(tx, path);
425
401
  }
426
402
  catch (e_8) {
427
403
  env_8.error = e_8;
@@ -431,20 +407,16 @@ export class StoreFS extends FileSystem {
431
407
  __disposeResources(env_8);
432
408
  }
433
409
  }
434
- async createFile(path, flag, mode, options) {
435
- const node = await this.commitNew(path, { mode: mode | S_IFREG, ...options }, new Uint8Array(), 'createFile');
436
- return new LazyFile(this, path, flag, node.toStats());
437
- }
438
- createFileSync(path, flag, mode, options) {
439
- const node = this.commitNewSync(path, { mode: mode | S_IFREG, ...options }, new Uint8Array(), 'createFile');
440
- return new LazyFile(this, path, flag, node.toStats());
441
- }
442
- async openFile(path, flag) {
410
+ async touch(path, metadata) {
443
411
  const env_9 = { stack: [], error: void 0, hasError: false };
444
412
  try {
445
413
  const tx = __addDisposableResource(env_9, this.transaction(), true);
446
- const node = await this.findInode(tx, path, 'openFile');
447
- return new LazyFile(this, path, flag, node.toStats());
414
+ const inode = await this.findInode(tx, path);
415
+ if (inode.update(metadata)) {
416
+ this._add(inode.ino, path);
417
+ tx.setSync(inode.ino, inode);
418
+ }
419
+ await tx.commit();
448
420
  }
449
421
  catch (e_9) {
450
422
  env_9.error = e_9;
@@ -456,12 +428,16 @@ export class StoreFS extends FileSystem {
456
428
  await result_5;
457
429
  }
458
430
  }
459
- openFileSync(path, flag) {
431
+ touchSync(path, metadata) {
460
432
  const env_10 = { stack: [], error: void 0, hasError: false };
461
433
  try {
462
434
  const tx = __addDisposableResource(env_10, this.transaction(), false);
463
- const node = this.findInodeSync(tx, path, 'openFile');
464
- return new LazyFile(this, path, flag, node.toStats());
435
+ const inode = this.findInodeSync(tx, path);
436
+ if (inode.update(metadata)) {
437
+ this._add(inode.ino, path);
438
+ tx.setSync(inode.ino, inode);
439
+ }
440
+ tx.commitSync();
465
441
  }
466
442
  catch (e_10) {
467
443
  env_10.error = e_10;
@@ -471,6 +447,14 @@ export class StoreFS extends FileSystem {
471
447
  __disposeResources(env_10);
472
448
  }
473
449
  }
450
+ async createFile(path, options) {
451
+ options.mode |= S_IFREG;
452
+ return await this.commitNew(path, options, new Uint8Array());
453
+ }
454
+ createFileSync(path, options) {
455
+ options.mode |= S_IFREG;
456
+ return this.commitNewSync(path, options, new Uint8Array());
457
+ }
474
458
  async unlink(path) {
475
459
  return this.remove(path, false);
476
460
  }
@@ -478,30 +462,30 @@ export class StoreFS extends FileSystem {
478
462
  this.removeSync(path, false);
479
463
  }
480
464
  async rmdir(path) {
481
- if ((await this.readdir(path)).length) {
482
- throw ErrnoError.With('ENOTEMPTY', path, 'rmdir');
483
- }
465
+ if ((await this.readdir(path)).length)
466
+ throw withErrno('ENOTEMPTY');
484
467
  await this.remove(path, true);
485
468
  }
486
469
  rmdirSync(path) {
487
- if (this.readdirSync(path).length) {
488
- throw ErrnoError.With('ENOTEMPTY', path, 'rmdir');
489
- }
470
+ if (this.readdirSync(path).length)
471
+ throw withErrno('ENOTEMPTY');
490
472
  this.removeSync(path, true);
491
473
  }
492
- async mkdir(path, mode, options) {
493
- await this.commitNew(path, { mode: mode | S_IFDIR, ...options }, encodeUTF8('{}'), 'mkdir');
474
+ async mkdir(path, options) {
475
+ options.mode |= S_IFDIR;
476
+ return await this.commitNew(path, options, encodeUTF8('{}'));
494
477
  }
495
- mkdirSync(path, mode, options) {
496
- this.commitNewSync(path, { mode: mode | S_IFDIR, ...options }, encodeUTF8('{}'), 'mkdir');
478
+ mkdirSync(path, options) {
479
+ options.mode |= S_IFDIR;
480
+ return this.commitNewSync(path, options, encodeUTF8('{}'));
497
481
  }
498
482
  async readdir(path) {
499
483
  var _a;
500
484
  const env_11 = { stack: [], error: void 0, hasError: false };
501
485
  try {
502
486
  const tx = __addDisposableResource(env_11, this.transaction(), true);
503
- const node = await this.findInode(tx, path, 'readdir');
504
- return Object.keys(decodeDirListing((_a = (await tx.get(node.data))) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENOENT', path, 'readdir'))));
487
+ const node = await this.findInode(tx, path);
488
+ return Object.keys(decodeDirListing((_a = (await tx.get(node.data))) !== null && _a !== void 0 ? _a : _throw(withErrno('ENOENT'))));
505
489
  }
506
490
  catch (e_11) {
507
491
  env_11.error = e_11;
@@ -518,8 +502,8 @@ export class StoreFS extends FileSystem {
518
502
  const env_12 = { stack: [], error: void 0, hasError: false };
519
503
  try {
520
504
  const tx = __addDisposableResource(env_12, this.transaction(), false);
521
- const node = this.findInodeSync(tx, path, 'readdir');
522
- return Object.keys(decodeDirListing((_a = tx.getSync(node.data)) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENOENT', path, 'readdir'))));
505
+ const node = this.findInodeSync(tx, path);
506
+ return Object.keys(decodeDirListing((_a = tx.getSync(node.data)) !== null && _a !== void 0 ? _a : _throw(withErrno('ENOENT'))));
523
507
  }
524
508
  catch (e_12) {
525
509
  env_12.error = e_12;
@@ -531,19 +515,24 @@ export class StoreFS extends FileSystem {
531
515
  }
532
516
  /**
533
517
  * Updated the inode and data node at `path`
534
- * @todo Ensure mtime updates properly, and use that to determine if a data update is required.
535
518
  */
536
- async sync(path, data, metadata) {
519
+ async sync() { }
520
+ /**
521
+ * Updated the inode and data node at `path`
522
+ */
523
+ syncSync() { }
524
+ async link(target, link) {
525
+ var _a;
537
526
  const env_13 = { stack: [], error: void 0, hasError: false };
538
527
  try {
539
528
  const tx = __addDisposableResource(env_13, this.transaction(), true);
540
- const inode = await this.findInode(tx, path, 'sync');
541
- if (data)
542
- await tx.set(inode.data, data);
543
- if (inode.update(metadata)) {
544
- this._add(inode.ino, path);
545
- await tx.set(inode.ino, serialize(inode));
546
- }
529
+ const newDir = dirname(link), newDirNode = await this.findInode(tx, newDir), listing = decodeDirListing((_a = (await tx.get(newDirNode.data))) !== null && _a !== void 0 ? _a : _throw(withErrno('ENOENT')));
530
+ const inode = await this.findInode(tx, target);
531
+ inode.nlink++;
532
+ listing[basename(link)] = inode.ino;
533
+ this._add(inode.ino, link);
534
+ await tx.set(inode.ino, inode);
535
+ await tx.set(newDirNode.data, encodeDirListing(listing));
547
536
  await tx.commit();
548
537
  }
549
538
  catch (e_13) {
@@ -556,21 +545,18 @@ export class StoreFS extends FileSystem {
556
545
  await result_7;
557
546
  }
558
547
  }
559
- /**
560
- * Updated the inode and data node at `path`
561
- * @todo Ensure mtime updates properly, and use that to determine if a data update is required.
562
- */
563
- syncSync(path, data, metadata) {
548
+ linkSync(target, link) {
549
+ var _a;
564
550
  const env_14 = { stack: [], error: void 0, hasError: false };
565
551
  try {
566
552
  const tx = __addDisposableResource(env_14, this.transaction(), false);
567
- const inode = this.findInodeSync(tx, path, 'sync');
568
- if (data)
569
- tx.setSync(inode.data, data);
570
- if (inode.update(metadata)) {
571
- this._add(inode.ino, path);
572
- tx.setSync(inode.ino, serialize(inode));
573
- }
553
+ const newDir = dirname(link), newDirNode = this.findInodeSync(tx, newDir), listing = decodeDirListing((_a = tx.getSync(newDirNode.data)) !== null && _a !== void 0 ? _a : _throw(withErrno('ENOENT')));
554
+ const inode = this.findInodeSync(tx, target);
555
+ inode.nlink++;
556
+ listing[basename(link)] = inode.ino;
557
+ this._add(inode.ino, link);
558
+ tx.setSync(inode.ino, inode);
559
+ tx.setSync(newDirNode.data, encodeDirListing(listing));
574
560
  tx.commitSync();
575
561
  }
576
562
  catch (e_14) {
@@ -581,19 +567,19 @@ export class StoreFS extends FileSystem {
581
567
  __disposeResources(env_14);
582
568
  }
583
569
  }
584
- async link(target, link) {
570
+ async read(path, buffer, offset, end) {
585
571
  var _a;
586
572
  const env_15 = { stack: [], error: void 0, hasError: false };
587
573
  try {
588
574
  const tx = __addDisposableResource(env_15, this.transaction(), true);
589
- 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')));
590
- const inode = await this.findInode(tx, target, 'link');
591
- inode.nlink++;
592
- listing[basename(link)] = inode.ino;
593
- this._add(inode.ino, link);
594
- await tx.set(inode.ino, serialize(inode));
595
- await tx.set(newDirNode.data, encodeDirListing(listing));
596
- await tx.commit();
575
+ const inode = await this.findInode(tx, path);
576
+ if (inode.size == 0)
577
+ return;
578
+ const data = (_a = (await tx.get(inode.data, offset, end))) !== null && _a !== void 0 ? _a : _throw(withErrno('ENODATA'));
579
+ const _ = tx.flag('partial') ? data : data.subarray(offset, end);
580
+ if (_.byteLength > buffer.byteLength)
581
+ err(`Trying to place ${_.byteLength} bytes into a ${buffer.byteLength} byte buffer on read`);
582
+ buffer.set(_);
597
583
  }
598
584
  catch (e_15) {
599
585
  env_15.error = e_15;
@@ -605,80 +591,34 @@ export class StoreFS extends FileSystem {
605
591
  await result_8;
606
592
  }
607
593
  }
608
- linkSync(target, link) {
594
+ readSync(path, buffer, offset, end) {
609
595
  var _a;
610
596
  const env_16 = { stack: [], error: void 0, hasError: false };
611
597
  try {
612
598
  const tx = __addDisposableResource(env_16, this.transaction(), false);
613
- 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')));
614
- const inode = this.findInodeSync(tx, target, 'link');
615
- inode.nlink++;
616
- listing[basename(link)] = inode.ino;
617
- this._add(inode.ino, link);
618
- tx.setSync(inode.ino, serialize(inode));
619
- tx.setSync(newDirNode.data, encodeDirListing(listing));
620
- tx.commitSync();
621
- }
622
- catch (e_16) {
623
- env_16.error = e_16;
624
- env_16.hasError = true;
625
- }
626
- finally {
627
- __disposeResources(env_16);
628
- }
629
- }
630
- async read(path, buffer, offset, end) {
631
- var _a;
632
- const env_17 = { stack: [], error: void 0, hasError: false };
633
- try {
634
- const tx = __addDisposableResource(env_17, this.transaction(), true);
635
- const inode = await this.findInode(tx, path, 'read');
599
+ const inode = this.findInodeSync(tx, path);
636
600
  if (inode.size == 0)
637
601
  return;
638
- const data = (_a = (await tx.get(inode.data, offset, end))) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENODATA', path, 'read'));
602
+ const data = (_a = tx.getSync(inode.data, offset, end)) !== null && _a !== void 0 ? _a : _throw(withErrno('ENODATA'));
639
603
  const _ = tx.flag('partial') ? data : data.subarray(offset, end);
640
604
  if (_.byteLength > buffer.byteLength)
641
605
  err(`Trying to place ${_.byteLength} bytes into a ${buffer.byteLength} byte buffer on read`);
642
606
  buffer.set(_);
643
607
  }
644
- catch (e_17) {
645
- env_17.error = e_17;
646
- env_17.hasError = true;
647
- }
648
- finally {
649
- const result_9 = __disposeResources(env_17);
650
- if (result_9)
651
- await result_9;
652
- }
653
- }
654
- readSync(path, buffer, offset, end) {
655
- var _a;
656
- const env_18 = { stack: [], error: void 0, hasError: false };
657
- try {
658
- const tx = __addDisposableResource(env_18, this.transaction(), false);
659
- const inode = this.findInodeSync(tx, path, 'read');
660
- if (inode.size == 0)
661
- return;
662
- const data = (_a = tx.getSync(inode.data, offset, end)) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENODATA', path, 'read'));
663
- const _ = tx.flag('partial') ? data : data.subarray(offset, end);
664
- if (_.byteLength > buffer.byteLength)
665
- err(`Trying to place ${_.byteLength} bytes into a ${buffer.byteLength} byte buffer on read`);
666
- buffer.set(_);
667
- }
668
- catch (e_18) {
669
- env_18.error = e_18;
670
- env_18.hasError = true;
608
+ catch (e_16) {
609
+ env_16.error = e_16;
610
+ env_16.hasError = true;
671
611
  }
672
612
  finally {
673
- __disposeResources(env_18);
613
+ __disposeResources(env_16);
674
614
  }
675
615
  }
676
616
  async write(path, data, offset) {
677
617
  var _a;
678
- const env_19 = { stack: [], error: void 0, hasError: false };
618
+ const env_17 = { stack: [], error: void 0, hasError: false };
679
619
  try {
680
- const tx = __addDisposableResource(env_19, this.transaction(), true);
681
- const inode = await this.findInode(tx, path, 'write');
620
+ const tx = __addDisposableResource(env_17, this.transaction(), true);
621
+ const inode = await this.findInode(tx, path);
682
622
  let buffer = data;
683
623
  if (!tx.flag('partial')) {
684
624
  buffer = extendBuffer((_a = (await tx.get(inode.data))) !== null && _a !== void 0 ? _a : new Uint8Array(), offset + data.byteLength);
@@ -686,27 +626,25 @@ export class StoreFS extends FileSystem {
686
626
  offset = 0;
687
627
  }
688
628
  await tx.set(inode.data, buffer, offset);
689
- inode.update({ mtimeMs: Date.now(), size: Math.max(inode.size, data.byteLength + offset) });
690
629
  this._add(inode.ino, path);
691
- await tx.set(inode.ino, serialize(inode));
692
630
  await tx.commit();
693
631
  }
694
- catch (e_19) {
695
- env_19.error = e_19;
696
- env_19.hasError = true;
632
+ catch (e_17) {
633
+ env_17.error = e_17;
634
+ env_17.hasError = true;
697
635
  }
698
636
  finally {
699
- const result_10 = __disposeResources(env_19);
700
- if (result_10)
701
- await result_10;
637
+ const result_9 = __disposeResources(env_17);
638
+ if (result_9)
639
+ await result_9;
702
640
  }
703
641
  }
704
642
  writeSync(path, data, offset) {
705
643
  var _a;
706
- const env_20 = { stack: [], error: void 0, hasError: false };
644
+ const env_18 = { stack: [], error: void 0, hasError: false };
707
645
  try {
708
- const tx = __addDisposableResource(env_20, this.transaction(), false);
709
- const inode = this.findInodeSync(tx, path, 'write');
646
+ const tx = __addDisposableResource(env_18, this.transaction(), false);
647
+ const inode = this.findInodeSync(tx, path);
710
648
  let buffer = data;
711
649
  if (!tx.flag('partial')) {
712
650
  buffer = extendBuffer((_a = tx.getSync(inode.data)) !== null && _a !== void 0 ? _a : new Uint8Array(), offset + data.byteLength);
@@ -714,17 +652,15 @@ export class StoreFS extends FileSystem {
714
652
  offset = 0;
715
653
  }
716
654
  tx.setSync(inode.data, buffer, offset);
717
- inode.update({ mtimeMs: Date.now(), size: Math.max(inode.size, data.byteLength + offset) });
718
655
  this._add(inode.ino, path);
719
- tx.setSync(inode.ino, serialize(inode));
720
656
  tx.commitSync();
721
657
  }
722
- catch (e_20) {
723
- env_20.error = e_20;
724
- env_20.hasError = true;
658
+ catch (e_18) {
659
+ env_18.error = e_18;
660
+ env_18.hasError = true;
725
661
  }
726
662
  finally {
727
- __disposeResources(env_20);
663
+ __disposeResources(env_18);
728
664
  }
729
665
  }
730
666
  /**
@@ -738,73 +674,73 @@ export class StoreFS extends FileSystem {
738
674
  * Checks if the root directory exists. Creates it if it doesn't.
739
675
  */
740
676
  async checkRoot() {
741
- const env_21 = { stack: [], error: void 0, hasError: false };
677
+ const env_19 = { stack: [], error: void 0, hasError: false };
742
678
  try {
743
- const tx = __addDisposableResource(env_21, this.transaction(), true);
679
+ const tx = __addDisposableResource(env_19, this.transaction(), true);
744
680
  if (await tx.get(rootIno))
745
681
  return;
746
682
  const inode = new Inode({ ino: rootIno, data: 1, mode: 0o777 | S_IFDIR });
747
683
  await tx.set(inode.data, encodeUTF8('{}'));
748
684
  this._add(rootIno, '/');
749
- await tx.set(rootIno, serialize(inode));
685
+ await tx.set(rootIno, inode);
750
686
  await tx.commit();
751
687
  }
752
- catch (e_21) {
753
- env_21.error = e_21;
754
- env_21.hasError = true;
688
+ catch (e_19) {
689
+ env_19.error = e_19;
690
+ env_19.hasError = true;
755
691
  }
756
692
  finally {
757
- const result_11 = __disposeResources(env_21);
758
- if (result_11)
759
- await result_11;
693
+ const result_10 = __disposeResources(env_19);
694
+ if (result_10)
695
+ await result_10;
760
696
  }
761
697
  }
762
698
  /**
763
699
  * Checks if the root directory exists. Creates it if it doesn't.
764
700
  */
765
701
  checkRootSync() {
766
- const env_22 = { stack: [], error: void 0, hasError: false };
702
+ const env_20 = { stack: [], error: void 0, hasError: false };
767
703
  try {
768
- const tx = __addDisposableResource(env_22, this.transaction(), false);
704
+ const tx = __addDisposableResource(env_20, this.transaction(), false);
769
705
  if (tx.getSync(rootIno))
770
706
  return;
771
707
  const inode = new Inode({ ino: rootIno, data: 1, mode: 0o777 | S_IFDIR });
772
708
  tx.setSync(inode.data, encodeUTF8('{}'));
773
709
  this._add(rootIno, '/');
774
- tx.setSync(rootIno, serialize(inode));
710
+ tx.setSync(rootIno, inode);
775
711
  tx.commitSync();
776
712
  }
777
- catch (e_22) {
778
- env_22.error = e_22;
779
- env_22.hasError = true;
713
+ catch (e_20) {
714
+ env_20.error = e_20;
715
+ env_20.hasError = true;
780
716
  }
781
717
  finally {
782
- __disposeResources(env_22);
718
+ __disposeResources(env_20);
783
719
  }
784
720
  }
785
721
  /**
786
722
  * Populates the `_ids` and `_paths` maps with all existing files stored in the underlying `Store`.
787
723
  */
788
724
  async _populate() {
789
- const env_23 = { stack: [], error: void 0, hasError: false };
725
+ const env_21 = { stack: [], error: void 0, hasError: false };
790
726
  try {
791
727
  if (this._initialized) {
792
728
  warn('Attempted to populate tables after initialization');
793
729
  return;
794
730
  }
795
731
  debug('Populating tables with existing store metadata');
796
- const tx = __addDisposableResource(env_23, this.transaction(), true);
732
+ const tx = __addDisposableResource(env_21, this.transaction(), true);
797
733
  const rootData = await tx.get(rootIno);
798
734
  if (!rootData) {
799
735
  notice('Store does not have a root inode');
800
736
  const inode = new Inode({ ino: rootIno, data: 1, mode: 0o777 | S_IFDIR });
801
737
  await tx.set(inode.data, encodeUTF8('{}'));
802
738
  this._add(rootIno, '/');
803
- await tx.set(rootIno, serialize(inode));
739
+ await tx.set(rootIno, inode);
804
740
  await tx.commit();
805
741
  return;
806
742
  }
807
- if (rootData.length != __inode_sz) {
743
+ if (rootData.length < sizeof(Inode)) {
808
744
  crit('Store contains an invalid root inode. Refusing to populate tables');
809
745
  return;
810
746
  }
@@ -823,7 +759,7 @@ export class StoreFS extends FileSystem {
823
759
  warn('Store is missing data for inode: ' + ino);
824
760
  continue;
825
761
  }
826
- if (inodeData.length != __inode_sz) {
762
+ if (inodeData.length < sizeof(Inode)) {
827
763
  warn(`Invalid inode size for ino ${ino}: ${inodeData.length}`);
828
764
  continue;
829
765
  }
@@ -847,27 +783,63 @@ export class StoreFS extends FileSystem {
847
783
  }
848
784
  debug(`Added ${i} existing inode(s) from store`);
849
785
  }
850
- catch (e_23) {
851
- env_23.error = e_23;
852
- env_23.hasError = true;
786
+ catch (e_21) {
787
+ env_21.error = e_21;
788
+ env_21.hasError = true;
853
789
  }
854
790
  finally {
855
- const result_12 = __disposeResources(env_23);
856
- if (result_12)
857
- await result_12;
791
+ const result_11 = __disposeResources(env_21);
792
+ if (result_11)
793
+ await result_11;
858
794
  }
859
795
  }
796
+ /**
797
+ * Find an inode without using the ID tables
798
+ */
799
+ async _findInode(tx, path, visited = new Set()) {
800
+ var _a, _b, _c;
801
+ if (visited.has(path))
802
+ throw crit(withErrno('EIO', 'Infinite loop detected while finding inode'));
803
+ visited.add(path);
804
+ if (path == '/')
805
+ return new Inode((_a = (await tx.get(rootIno))) !== null && _a !== void 0 ? _a : _throw(withErrno('ENODATA')));
806
+ const { dir: parent, base: filename } = parse(path);
807
+ const inode = await this._findInode(tx, parent, visited);
808
+ const dirList = decodeDirListing((_b = (await tx.get(inode.data))) !== null && _b !== void 0 ? _b : _throw(withErrno('ENODATA')));
809
+ if (!(filename in dirList))
810
+ throw withErrno('ENOENT');
811
+ return new Inode((_c = (await tx.get(dirList[filename]))) !== null && _c !== void 0 ? _c : _throw(withErrno('ENODATA')));
812
+ }
813
+ /**
814
+ * Find an inode without using the ID tables
815
+ */
816
+ _findInodeSync(tx, path, visited = new Set()) {
817
+ var _a, _b, _c;
818
+ if (visited.has(path))
819
+ throw crit(withErrno('EIO', 'Infinite loop detected while finding inode'));
820
+ visited.add(path);
821
+ if (path == '/')
822
+ return new Inode((_a = tx.getSync(rootIno)) !== null && _a !== void 0 ? _a : _throw(withErrno('ENOENT')));
823
+ const { dir: parent, base: filename } = parse(path);
824
+ const inode = this._findInodeSync(tx, parent, visited);
825
+ const dir = decodeDirListing((_b = tx.getSync(inode.data)) !== null && _b !== void 0 ? _b : _throw(withErrno('ENODATA')));
826
+ if (!(filename in dir))
827
+ throw withErrno('ENOENT');
828
+ return new Inode((_c = tx.getSync(dir[filename])) !== null && _c !== void 0 ? _c : _throw(withErrno('ENODATA')));
829
+ }
860
830
  /**
861
831
  * Finds the Inode of `path`.
862
832
  * @param path The path to look up.
863
833
  * @todo memoize/cache
864
834
  */
865
- async findInode(tx, path, syscall) {
835
+ async findInode(tx, path) {
866
836
  var _a;
837
+ if (this.attributes.has('no_id_tables'))
838
+ return await this._findInode(tx, path);
867
839
  const ino = this._ids.get(path);
868
840
  if (ino === undefined)
869
- throw ErrnoError.With('ENOENT', path, syscall);
870
- return new Inode((_a = (await tx.get(ino))) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENOENT', path, syscall)));
841
+ throw withErrno('ENOENT');
842
+ return new Inode((_a = (await tx.get(ino))) !== null && _a !== void 0 ? _a : _throw(withErrno('ENOENT')));
871
843
  }
872
844
  /**
873
845
  * Finds the Inode of `path`.
@@ -875,23 +847,23 @@ export class StoreFS extends FileSystem {
875
847
  * @return The Inode of the path p.
876
848
  * @todo memoize/cache
877
849
  */
878
- findInodeSync(tx, path, syscall) {
850
+ findInodeSync(tx, path) {
879
851
  var _a;
852
+ if (this.attributes.has('no_id_tables'))
853
+ return this._findInodeSync(tx, path);
880
854
  const ino = this._ids.get(path);
881
855
  if (ino === undefined)
882
- throw ErrnoError.With('ENOENT', path, syscall);
883
- return new Inode((_a = tx.getSync(ino)) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENOENT', path, syscall)));
856
+ throw withErrno('ENOENT');
857
+ return new Inode((_a = tx.getSync(ino)) !== null && _a !== void 0 ? _a : _throw(withErrno('ENOENT')));
884
858
  }
885
- /**
886
- * Allocates a new ID and adds the ID/path
887
- */
888
- allocNew(path, syscall) {
859
+ /** Allocates a new ID and adds the ID/path */
860
+ allocNew(path) {
889
861
  var _a;
890
862
  (_a = this._lastID) !== null && _a !== void 0 ? _a : (this._lastID = Math.max(...this._paths.keys()));
891
863
  this._lastID += 2;
892
864
  const id = this._lastID;
893
865
  if (id > size_max)
894
- throw err(new ErrnoError(Errno.ENOSPC, 'No IDs available', path, syscall), { fs: this });
866
+ throw err(withErrno('ENOSPC', 'No IDs available'));
895
867
  this._add(id, path);
896
868
  return id;
897
869
  }
@@ -902,9 +874,9 @@ export class StoreFS extends FileSystem {
902
874
  * @param options The options to create the new file with.
903
875
  * @param data The data to store at the file's data node.
904
876
  */
905
- async commitNew(path, options, data, syscall) {
877
+ async commitNew(path, options, data) {
906
878
  var _a;
907
- const env_24 = { stack: [], error: void 0, hasError: false };
879
+ const env_22 = { stack: [], error: void 0, hasError: false };
908
880
  try {
909
881
  /*
910
882
  The root always exists.
@@ -912,25 +884,24 @@ export class StoreFS extends FileSystem {
912
884
  we will create a file with name '' in root if path is '/'.
913
885
  */
914
886
  if (path == '/')
915
- throw ErrnoError.With('EEXIST', path, syscall);
916
- const tx = __addDisposableResource(env_24, this.transaction(), true);
887
+ throw withErrno('EEXIST');
888
+ const tx = __addDisposableResource(env_22, this.transaction(), true);
917
889
  const { dir: parentPath, base: fname } = parse(path);
918
- const parent = await this.findInode(tx, parentPath, syscall);
919
- const listing = decodeDirListing((_a = (await tx.get(parent.data))) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENOENT', parentPath, syscall)));
890
+ const parent = await this.findInode(tx, parentPath);
891
+ const listing = decodeDirListing((_a = (await tx.get(parent.data))) !== null && _a !== void 0 ? _a : _throw(withErrno('ENOENT')));
920
892
  // Check if file already exists.
921
893
  if (listing[fname])
922
- throw ErrnoError.With('EEXIST', path, syscall);
923
- const id = this.allocNew(path, syscall);
894
+ throw withErrno('EEXIST');
895
+ const id = this.allocNew(path);
924
896
  // Commit data.
925
897
  const inode = new Inode({
898
+ ...options,
926
899
  ino: id,
927
900
  data: id + 1,
928
- mode: options.mode,
929
901
  size: data.byteLength,
930
- uid: parent.mode & S_ISUID ? parent.uid : options.uid,
931
- gid: parent.mode & S_ISGID ? parent.gid : options.gid,
902
+ nlink: 1,
932
903
  });
933
- await tx.set(inode.ino, serialize(inode));
904
+ await tx.set(inode.ino, inode);
934
905
  await tx.set(inode.data, data);
935
906
  // Update and commit parent directory listing.
936
907
  listing[fname] = inode.ino;
@@ -938,14 +909,14 @@ export class StoreFS extends FileSystem {
938
909
  await tx.commit();
939
910
  return inode;
940
911
  }
941
- catch (e_24) {
942
- env_24.error = e_24;
943
- env_24.hasError = true;
912
+ catch (e_22) {
913
+ env_22.error = e_22;
914
+ env_22.hasError = true;
944
915
  }
945
916
  finally {
946
- const result_13 = __disposeResources(env_24);
947
- if (result_13)
948
- await result_13;
917
+ const result_12 = __disposeResources(env_22);
918
+ if (result_12)
919
+ await result_12;
949
920
  }
950
921
  }
951
922
  /**
@@ -956,9 +927,9 @@ export class StoreFS extends FileSystem {
956
927
  * @param data The data to store at the file's data node.
957
928
  * @return The Inode for the new file.
958
929
  */
959
- commitNewSync(path, options, data, syscall) {
930
+ commitNewSync(path, options, data) {
960
931
  var _a;
961
- const env_25 = { stack: [], error: void 0, hasError: false };
932
+ const env_23 = { stack: [], error: void 0, hasError: false };
962
933
  try {
963
934
  /*
964
935
  The root always exists.
@@ -966,122 +937,112 @@ export class StoreFS extends FileSystem {
966
937
  we will create a file with name '' in root if path is '/'.
967
938
  */
968
939
  if (path == '/')
969
- throw ErrnoError.With('EEXIST', path, syscall);
970
- const tx = __addDisposableResource(env_25, this.transaction(), false);
940
+ throw withErrno('EEXIST');
941
+ const tx = __addDisposableResource(env_23, this.transaction(), false);
971
942
  const { dir: parentPath, base: fname } = parse(path);
972
- const parent = this.findInodeSync(tx, parentPath, syscall);
973
- const listing = decodeDirListing((_a = tx.getSync(parent.data)) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENOENT', parentPath, syscall)));
974
- // Check if file already exists.
943
+ const parent = this.findInodeSync(tx, parentPath);
944
+ const listing = decodeDirListing((_a = tx.getSync(parent.data)) !== null && _a !== void 0 ? _a : _throw(withErrno('ENOENT')));
975
945
  if (listing[fname])
976
- throw ErrnoError.With('EEXIST', path, syscall);
977
- const id = this.allocNew(path, syscall);
978
- // Commit data.
946
+ throw withErrno('EEXIST');
947
+ const id = this.allocNew(path);
979
948
  const inode = new Inode({
949
+ ...options,
980
950
  ino: id,
981
951
  data: id + 1,
982
- mode: options.mode,
983
952
  size: data.byteLength,
984
- uid: parent.mode & S_ISUID ? parent.uid : options.uid,
985
- gid: parent.mode & S_ISGID ? parent.gid : options.gid,
953
+ nlink: 1,
986
954
  });
987
955
  // Update and commit parent directory listing.
988
- tx.setSync(inode.ino, serialize(inode));
956
+ tx.setSync(inode.ino, inode);
989
957
  tx.setSync(inode.data, data);
990
958
  listing[fname] = inode.ino;
991
959
  tx.setSync(parent.data, encodeDirListing(listing));
992
960
  tx.commitSync();
993
961
  return inode;
994
962
  }
995
- catch (e_25) {
996
- env_25.error = e_25;
997
- env_25.hasError = true;
963
+ catch (e_23) {
964
+ env_23.error = e_23;
965
+ env_23.hasError = true;
998
966
  }
999
967
  finally {
1000
- __disposeResources(env_25);
968
+ __disposeResources(env_23);
1001
969
  }
1002
970
  }
1003
971
  /**
1004
972
  * Remove all traces of `path` from the file system.
1005
973
  * @param path The path to remove from the file system.
1006
974
  * @param isDir Does the path belong to a directory, or a file?
1007
- * @todo Update mtime.
1008
975
  */
1009
976
  async remove(path, isDir) {
1010
977
  var _a, _b;
1011
- const env_26 = { stack: [], error: void 0, hasError: false };
978
+ const env_24 = { stack: [], error: void 0, hasError: false };
1012
979
  try {
1013
- const syscall = isDir ? 'rmdir' : 'unlink';
1014
- const tx = __addDisposableResource(env_26, this.transaction(), true);
1015
- 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)));
1016
- if (!listing[fileName]) {
1017
- throw ErrnoError.With('ENOENT', path, syscall);
1018
- }
1019
- const fileIno = listing[fileName];
1020
- // Get file inode.
1021
- const fileNode = new Inode((_b = (await tx.get(fileIno))) !== null && _b !== void 0 ? _b : _throw(ErrnoError.With('ENOENT', path, syscall)));
1022
- // Remove from directory listing of parent.
980
+ const tx = __addDisposableResource(env_24, this.transaction(), true);
981
+ const { dir: parent, base: fileName } = parse(path), parentNode = await this.findInode(tx, parent), listing = decodeDirListing((_a = (await tx.get(parentNode.data))) !== null && _a !== void 0 ? _a : _throw(withErrno('ENOENT')));
982
+ if (!listing[fileName])
983
+ throw withErrno('ENOENT');
984
+ const ino = listing[fileName];
985
+ const inode = new Inode((_b = (await tx.get(ino))) !== null && _b !== void 0 ? _b : _throw(withErrno('ENOENT')));
1023
986
  delete listing[fileName];
1024
- if (!isDir && fileNode.toStats().isDirectory())
1025
- throw ErrnoError.With('EISDIR', path, syscall);
987
+ if (!isDir && isDirectory(inode))
988
+ throw withErrno('EISDIR');
1026
989
  await tx.set(parentNode.data, encodeDirListing(listing));
1027
- if (--fileNode.nlink < 1) {
1028
- // remove file
1029
- await tx.remove(fileNode.data);
1030
- await tx.remove(fileIno);
1031
- this._remove(fileIno);
990
+ if (inode.nlink > 1) {
991
+ inode.update({ nlink: inode.nlink - 1 });
992
+ await tx.set(inode.ino, inode);
993
+ }
994
+ else {
995
+ await tx.remove(inode.data);
996
+ await tx.remove(ino);
997
+ this._remove(ino);
1032
998
  }
1033
- // Success.
1034
999
  await tx.commit();
1035
1000
  }
1036
- catch (e_26) {
1037
- env_26.error = e_26;
1038
- env_26.hasError = true;
1001
+ catch (e_24) {
1002
+ env_24.error = e_24;
1003
+ env_24.hasError = true;
1039
1004
  }
1040
1005
  finally {
1041
- const result_14 = __disposeResources(env_26);
1042
- if (result_14)
1043
- await result_14;
1006
+ const result_13 = __disposeResources(env_24);
1007
+ if (result_13)
1008
+ await result_13;
1044
1009
  }
1045
1010
  }
1046
1011
  /**
1047
1012
  * Remove all traces of `path` from the file system.
1048
1013
  * @param path The path to remove from the file system.
1049
1014
  * @param isDir Does the path belong to a directory, or a file?
1050
- * @todo Update mtime.
1051
1015
  */
1052
1016
  removeSync(path, isDir) {
1053
1017
  var _a, _b;
1054
- const env_27 = { stack: [], error: void 0, hasError: false };
1018
+ const env_25 = { stack: [], error: void 0, hasError: false };
1055
1019
  try {
1056
- const syscall = isDir ? 'rmdir' : 'unlink';
1057
- const tx = __addDisposableResource(env_27, this.transaction(), false);
1058
- 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];
1059
- if (!fileIno)
1060
- throw ErrnoError.With('ENOENT', path, syscall);
1061
- // Get file inode.
1062
- const fileNode = new Inode((_b = tx.getSync(fileIno)) !== null && _b !== void 0 ? _b : _throw(ErrnoError.With('ENOENT', path, syscall)));
1063
- // Remove from directory listing of parent.
1020
+ const tx = __addDisposableResource(env_25, this.transaction(), false);
1021
+ const { dir: parent, base: fileName } = parse(path), parentNode = this.findInodeSync(tx, parent), listing = decodeDirListing((_a = tx.getSync(parentNode.data)) !== null && _a !== void 0 ? _a : _throw(withErrno('ENOENT'))), ino = listing[fileName];
1022
+ if (!ino)
1023
+ throw withErrno('ENOENT');
1024
+ const inode = new Inode((_b = tx.getSync(ino)) !== null && _b !== void 0 ? _b : _throw(withErrno('ENOENT')));
1064
1025
  delete listing[fileName];
1065
- if (!isDir && fileNode.toStats().isDirectory()) {
1066
- throw ErrnoError.With('EISDIR', path, syscall);
1067
- }
1068
- // Update directory listing.
1026
+ if (!isDir && isDirectory(inode))
1027
+ throw withErrno('EISDIR');
1069
1028
  tx.setSync(parentNode.data, encodeDirListing(listing));
1070
- if (--fileNode.nlink < 1) {
1071
- // remove file
1072
- tx.removeSync(fileNode.data);
1073
- tx.removeSync(fileIno);
1074
- this._remove(fileIno);
1029
+ if (inode.nlink > 1) {
1030
+ inode.update({ nlink: inode.nlink - 1 });
1031
+ tx.setSync(inode.ino, inode);
1032
+ }
1033
+ else {
1034
+ tx.removeSync(inode.data);
1035
+ tx.removeSync(ino);
1036
+ this._remove(ino);
1075
1037
  }
1076
- // Success.
1077
1038
  tx.commitSync();
1078
1039
  }
1079
- catch (e_27) {
1080
- env_27.error = e_27;
1081
- env_27.hasError = true;
1040
+ catch (e_25) {
1041
+ env_25.error = e_25;
1042
+ env_25.hasError = true;
1082
1043
  }
1083
1044
  finally {
1084
- __disposeResources(env_27);
1045
+ __disposeResources(env_25);
1085
1046
  }
1086
1047
  }
1087
1048
  }