@zenfs/core 2.0.0 → 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 (87) hide show
  1. package/dist/backends/backend.js +6 -5
  2. package/dist/backends/cow.d.ts +2 -2
  3. package/dist/backends/cow.js +39 -58
  4. package/dist/backends/fetch.js +27 -29
  5. package/dist/backends/passthrough.d.ts +2 -3
  6. package/dist/backends/passthrough.js +84 -199
  7. package/dist/backends/port.d.ts +16 -3
  8. package/dist/backends/port.js +61 -30
  9. package/dist/backends/single_buffer.d.ts +52 -46
  10. package/dist/backends/single_buffer.js +462 -219
  11. package/dist/backends/store/fs.d.ts +16 -10
  12. package/dist/backends/store/fs.js +227 -242
  13. package/dist/backends/store/store.d.ts +3 -3
  14. package/dist/backends/store/store.js +11 -10
  15. package/dist/config.d.ts +2 -2
  16. package/dist/config.js +10 -11
  17. package/dist/internal/devices.d.ts +2 -2
  18. package/dist/internal/devices.js +39 -49
  19. package/dist/internal/error.d.ts +9 -204
  20. package/dist/internal/error.js +19 -288
  21. package/dist/internal/file_index.d.ts +1 -1
  22. package/dist/internal/file_index.js +9 -9
  23. package/dist/internal/filesystem.d.ts +23 -8
  24. package/dist/internal/index.d.ts +1 -1
  25. package/dist/internal/index.js +1 -1
  26. package/dist/internal/index_fs.d.ts +2 -2
  27. package/dist/internal/index_fs.js +19 -19
  28. package/dist/internal/inode.d.ts +81 -103
  29. package/dist/internal/inode.js +336 -195
  30. package/dist/mixins/async.js +32 -28
  31. package/dist/mixins/mutexed.d.ts +4 -4
  32. package/dist/mixins/mutexed.js +39 -39
  33. package/dist/mixins/readonly.d.ts +2 -2
  34. package/dist/mixins/readonly.js +20 -20
  35. package/dist/mixins/sync.js +2 -2
  36. package/dist/polyfills.js +1 -1
  37. package/dist/readline.js +1 -1
  38. package/dist/utils.d.ts +8 -5
  39. package/dist/utils.js +14 -17
  40. package/dist/vfs/acl.d.ts +8 -8
  41. package/dist/vfs/acl.js +66 -47
  42. package/dist/vfs/async.d.ts +2 -2
  43. package/dist/vfs/async.js +6 -8
  44. package/dist/vfs/dir.d.ts +1 -1
  45. package/dist/vfs/dir.js +3 -4
  46. package/dist/vfs/file.js +33 -24
  47. package/dist/vfs/flags.js +3 -3
  48. package/dist/vfs/ioctl.d.ts +8 -7
  49. package/dist/vfs/ioctl.js +132 -27
  50. package/dist/vfs/promises.d.ts +3 -3
  51. package/dist/vfs/promises.js +200 -235
  52. package/dist/vfs/shared.d.ts +1 -12
  53. package/dist/vfs/shared.js +7 -35
  54. package/dist/vfs/streams.js +9 -9
  55. package/dist/vfs/sync.d.ts +1 -2
  56. package/dist/vfs/sync.js +158 -170
  57. package/dist/vfs/watchers.js +8 -8
  58. package/dist/vfs/xattr.js +89 -106
  59. package/package.json +4 -2
  60. package/scripts/test.js +2 -2
  61. package/tests/assignment.ts +1 -1
  62. package/tests/backend/port.test.ts +4 -4
  63. package/tests/backend/single-buffer.test.ts +39 -10
  64. package/tests/backend/single-buffer.worker.js +30 -0
  65. package/tests/common/context.test.ts +2 -2
  66. package/tests/common/mutex.test.ts +9 -9
  67. package/tests/fetch/fetch.ts +1 -1
  68. package/tests/fs/append.test.ts +4 -4
  69. package/tests/fs/directory.test.ts +25 -25
  70. package/tests/fs/errors.test.ts +15 -19
  71. package/tests/fs/links.test.ts +3 -2
  72. package/tests/fs/open.test.ts +4 -21
  73. package/tests/fs/permissions.test.ts +8 -13
  74. package/tests/fs/read.test.ts +10 -9
  75. package/tests/fs/readFile.test.ts +8 -24
  76. package/tests/fs/rename.test.ts +4 -9
  77. package/tests/fs/stat.test.ts +2 -2
  78. package/tests/fs/times.test.ts +6 -6
  79. package/tests/fs/truncate.test.ts +8 -36
  80. package/tests/fs/watch.test.ts +10 -10
  81. package/tests/fs/write.test.ts +77 -13
  82. package/tests/fs/xattr.test.ts +7 -7
  83. package/tests/logs.js +2 -2
  84. package/tests/setup/port.ts +6 -0
  85. package/dist/internal/log.d.ts +0 -139
  86. package/dist/internal/log.js +0 -219
  87. package/tests/fs/writeFile.test.ts +0 -70
@@ -1,292 +1,23 @@
1
+ import { Exception, setUVMessage } from 'kerium';
1
2
  /**
2
- * Standard libc error codes. More will be added to this enum and error strings as they are
3
- * needed.
3
+ * @deprecated Use {@link Exception} instead
4
4
  * @category Internals
5
- * @see https://en.wikipedia.org/wiki/Errno.h
6
5
  */
7
- export var Errno;
8
- (function (Errno) {
9
- /** Operation not permitted */
10
- Errno[Errno["EPERM"] = 1] = "EPERM";
11
- /** No such file or directory */
12
- Errno[Errno["ENOENT"] = 2] = "ENOENT";
13
- /** Interrupted system call */
14
- Errno[Errno["EINTR"] = 4] = "EINTR";
15
- /** Input/output error */
16
- Errno[Errno["EIO"] = 5] = "EIO";
17
- /** No such device or address */
18
- Errno[Errno["ENXIO"] = 6] = "ENXIO";
19
- /** Bad file descriptor */
20
- Errno[Errno["EBADF"] = 9] = "EBADF";
21
- /** Resource temporarily unavailable */
22
- Errno[Errno["EAGAIN"] = 11] = "EAGAIN";
23
- /** Cannot allocate memory */
24
- Errno[Errno["ENOMEM"] = 12] = "ENOMEM";
25
- /** Permission denied */
26
- Errno[Errno["EACCES"] = 13] = "EACCES";
27
- /** Bad address */
28
- Errno[Errno["EFAULT"] = 14] = "EFAULT";
29
- /** Block device required */
30
- Errno[Errno["ENOTBLK"] = 15] = "ENOTBLK";
31
- /** Resource busy or locked */
32
- Errno[Errno["EBUSY"] = 16] = "EBUSY";
33
- /** File exists */
34
- Errno[Errno["EEXIST"] = 17] = "EEXIST";
35
- /** Invalid cross-device link */
36
- Errno[Errno["EXDEV"] = 18] = "EXDEV";
37
- /** No such device */
38
- Errno[Errno["ENODEV"] = 19] = "ENODEV";
39
- /** File is not a directory */
40
- Errno[Errno["ENOTDIR"] = 20] = "ENOTDIR";
41
- /** File is a directory */
42
- Errno[Errno["EISDIR"] = 21] = "EISDIR";
43
- /** Invalid argument */
44
- Errno[Errno["EINVAL"] = 22] = "EINVAL";
45
- /** Too many open files in system */
46
- Errno[Errno["ENFILE"] = 23] = "ENFILE";
47
- /** Too many open files */
48
- Errno[Errno["EMFILE"] = 24] = "EMFILE";
49
- /** Text file busy */
50
- Errno[Errno["ETXTBSY"] = 26] = "ETXTBSY";
51
- /** File is too big */
52
- Errno[Errno["EFBIG"] = 27] = "EFBIG";
53
- /** No space left on disk */
54
- Errno[Errno["ENOSPC"] = 28] = "ENOSPC";
55
- /** Illegal seek */
56
- Errno[Errno["ESPIPE"] = 29] = "ESPIPE";
57
- /** Cannot modify a read-only file system */
58
- Errno[Errno["EROFS"] = 30] = "EROFS";
59
- /** Too many links */
60
- Errno[Errno["EMLINK"] = 31] = "EMLINK";
61
- /** Broken pipe */
62
- Errno[Errno["EPIPE"] = 32] = "EPIPE";
63
- /** Numerical argument out of domain */
64
- Errno[Errno["EDOM"] = 33] = "EDOM";
65
- /** Numerical result out of range */
66
- Errno[Errno["ERANGE"] = 34] = "ERANGE";
67
- /** Resource deadlock would occur */
68
- Errno[Errno["EDEADLK"] = 35] = "EDEADLK";
69
- /** File name too long */
70
- Errno[Errno["ENAMETOOLONG"] = 36] = "ENAMETOOLONG";
71
- /** No locks available */
72
- Errno[Errno["ENOLCK"] = 37] = "ENOLCK";
73
- /** Function not implemented */
74
- Errno[Errno["ENOSYS"] = 38] = "ENOSYS";
75
- /** Directory is not empty */
76
- Errno[Errno["ENOTEMPTY"] = 39] = "ENOTEMPTY";
77
- /** Too many levels of symbolic links */
78
- Errno[Errno["ELOOP"] = 40] = "ELOOP";
79
- /** No message of desired type */
80
- Errno[Errno["ENOMSG"] = 42] = "ENOMSG";
81
- /** Invalid exchange */
82
- Errno[Errno["EBADE"] = 52] = "EBADE";
83
- /** Invalid request descriptor */
84
- Errno[Errno["EBADR"] = 53] = "EBADR";
85
- /** Exchange full */
86
- Errno[Errno["EXFULL"] = 54] = "EXFULL";
87
- /** No anode */
88
- Errno[Errno["ENOANO"] = 55] = "ENOANO";
89
- /** Invalid request code */
90
- Errno[Errno["EBADRQC"] = 56] = "EBADRQC";
91
- /** Device not a stream */
92
- Errno[Errno["ENOSTR"] = 60] = "ENOSTR";
93
- /** No data available */
94
- Errno[Errno["ENODATA"] = 61] = "ENODATA";
95
- /** Timer expired */
96
- Errno[Errno["ETIME"] = 62] = "ETIME";
97
- /** Out of streams resources */
98
- Errno[Errno["ENOSR"] = 63] = "ENOSR";
99
- /** Machine is not on the network */
100
- Errno[Errno["ENONET"] = 64] = "ENONET";
101
- /** Object is remote */
102
- Errno[Errno["EREMOTE"] = 66] = "EREMOTE";
103
- /** Link has been severed */
104
- Errno[Errno["ENOLINK"] = 67] = "ENOLINK";
105
- /** Communication error on send */
106
- Errno[Errno["ECOMM"] = 70] = "ECOMM";
107
- /** Protocol error */
108
- Errno[Errno["EPROTO"] = 71] = "EPROTO";
109
- /** Bad message */
110
- Errno[Errno["EBADMSG"] = 74] = "EBADMSG";
111
- /** Value too large for defined data type */
112
- Errno[Errno["EOVERFLOW"] = 75] = "EOVERFLOW";
113
- /** File descriptor in bad state */
114
- Errno[Errno["EBADFD"] = 77] = "EBADFD";
115
- /** Streams pipe error */
116
- Errno[Errno["ESTRPIPE"] = 86] = "ESTRPIPE";
117
- /** Socket operation on non-socket */
118
- Errno[Errno["ENOTSOCK"] = 88] = "ENOTSOCK";
119
- /** Destination address required */
120
- Errno[Errno["EDESTADDRREQ"] = 89] = "EDESTADDRREQ";
121
- /** Message too long */
122
- Errno[Errno["EMSGSIZE"] = 90] = "EMSGSIZE";
123
- /** Protocol wrong type for socket */
124
- Errno[Errno["EPROTOTYPE"] = 91] = "EPROTOTYPE";
125
- /** Protocol not available */
126
- Errno[Errno["ENOPROTOOPT"] = 92] = "ENOPROTOOPT";
127
- /** Protocol not supported */
128
- Errno[Errno["EPROTONOSUPPORT"] = 93] = "EPROTONOSUPPORT";
129
- /** Socket type not supported */
130
- Errno[Errno["ESOCKTNOSUPPORT"] = 94] = "ESOCKTNOSUPPORT";
131
- /** Operation is not supported */
132
- Errno[Errno["ENOTSUP"] = 95] = "ENOTSUP";
133
- /** Network is down */
134
- Errno[Errno["ENETDOWN"] = 100] = "ENETDOWN";
135
- /** Network is unreachable */
136
- Errno[Errno["ENETUNREACH"] = 101] = "ENETUNREACH";
137
- /** Network dropped connection on reset */
138
- Errno[Errno["ENETRESET"] = 102] = "ENETRESET";
139
- /** Connection timed out */
140
- Errno[Errno["ETIMEDOUT"] = 110] = "ETIMEDOUT";
141
- /** Connection refused */
142
- Errno[Errno["ECONNREFUSED"] = 111] = "ECONNREFUSED";
143
- /** Host is down */
144
- Errno[Errno["EHOSTDOWN"] = 112] = "EHOSTDOWN";
145
- /** No route to host */
146
- Errno[Errno["EHOSTUNREACH"] = 113] = "EHOSTUNREACH";
147
- /** Operation already in progress */
148
- Errno[Errno["EALREADY"] = 114] = "EALREADY";
149
- /** Operation now in progress */
150
- Errno[Errno["EINPROGRESS"] = 115] = "EINPROGRESS";
151
- /** Stale file handle */
152
- Errno[Errno["ESTALE"] = 116] = "ESTALE";
153
- /** Remote I/O error */
154
- Errno[Errno["EREMOTEIO"] = 121] = "EREMOTEIO";
155
- /** Disk quota exceeded */
156
- Errno[Errno["EDQUOT"] = 122] = "EDQUOT";
157
- })(Errno || (Errno = {}));
158
- /**
159
- * Strings associated with each error code.
160
- * @category Internals
161
- * @internal
162
- */
163
- export const errorMessages = {
164
- [Errno.EPERM]: 'Operation not permitted',
165
- [Errno.ENOENT]: 'No such file or directory',
166
- [Errno.EINTR]: 'Interrupted system call',
167
- [Errno.EIO]: 'Input/output error',
168
- [Errno.ENXIO]: 'No such device or address',
169
- [Errno.EBADF]: 'Bad file descriptor',
170
- [Errno.EAGAIN]: 'Resource temporarily unavailable',
171
- [Errno.ENOMEM]: 'Cannot allocate memory',
172
- [Errno.EACCES]: 'Permission denied',
173
- [Errno.EFAULT]: 'Bad address',
174
- [Errno.ENOTBLK]: 'Block device required',
175
- [Errno.EBUSY]: 'Resource busy or locked',
176
- [Errno.EEXIST]: 'File exists',
177
- [Errno.EXDEV]: 'Invalid cross-device link',
178
- [Errno.ENODEV]: 'No such device',
179
- [Errno.ENOTDIR]: 'File is not a directory',
180
- [Errno.EISDIR]: 'File is a directory',
181
- [Errno.EINVAL]: 'Invalid argument',
182
- [Errno.ENFILE]: 'Too many open files in system',
183
- [Errno.EMFILE]: 'Too many open files',
184
- [Errno.ETXTBSY]: 'Text file busy',
185
- [Errno.EFBIG]: 'File is too big',
186
- [Errno.ENOSPC]: 'No space left on disk',
187
- [Errno.ESPIPE]: 'Illegal seek',
188
- [Errno.EROFS]: 'Cannot modify a read-only file system',
189
- [Errno.EMLINK]: 'Too many links',
190
- [Errno.EPIPE]: 'Broken pipe',
191
- [Errno.EDOM]: 'Numerical argument out of domain',
192
- [Errno.ERANGE]: 'Numerical result out of range',
193
- [Errno.EDEADLK]: 'Resource deadlock would occur',
194
- [Errno.ENAMETOOLONG]: 'File name too long',
195
- [Errno.ENOLCK]: 'No locks available',
196
- [Errno.ENOSYS]: 'Function not implemented',
197
- [Errno.ENOTEMPTY]: 'Directory is not empty',
198
- [Errno.ELOOP]: 'Too many levels of symbolic links',
199
- [Errno.ENOMSG]: 'No message of desired type',
200
- [Errno.EBADE]: 'Invalid exchange',
201
- [Errno.EBADR]: 'Invalid request descriptor',
202
- [Errno.EXFULL]: 'Exchange full',
203
- [Errno.ENOANO]: 'No anode',
204
- [Errno.EBADRQC]: 'Invalid request code',
205
- [Errno.ENOSTR]: 'Device not a stream',
206
- [Errno.ENODATA]: 'No data available',
207
- [Errno.ETIME]: 'Timer expired',
208
- [Errno.ENOSR]: 'Out of streams resources',
209
- [Errno.ENONET]: 'Machine is not on the network',
210
- [Errno.EREMOTE]: 'Object is remote',
211
- [Errno.ENOLINK]: 'Link has been severed',
212
- [Errno.ECOMM]: 'Communication error on send',
213
- [Errno.EPROTO]: 'Protocol error',
214
- [Errno.EBADMSG]: 'Bad message',
215
- [Errno.EOVERFLOW]: 'Value too large for defined data type',
216
- [Errno.EBADFD]: 'File descriptor in bad state',
217
- [Errno.ESTRPIPE]: 'Streams pipe error',
218
- [Errno.ENOTSOCK]: 'Socket operation on non-socket',
219
- [Errno.EDESTADDRREQ]: 'Destination address required',
220
- [Errno.EMSGSIZE]: 'Message too long',
221
- [Errno.EPROTOTYPE]: 'Protocol wrong type for socket',
222
- [Errno.ENOPROTOOPT]: 'Protocol not available',
223
- [Errno.EPROTONOSUPPORT]: 'Protocol not supported',
224
- [Errno.ESOCKTNOSUPPORT]: 'Socket type not supported',
225
- [Errno.ENOTSUP]: 'Operation is not supported',
226
- [Errno.ENETDOWN]: 'Network is down',
227
- [Errno.ENETUNREACH]: 'Network is unreachable',
228
- [Errno.ENETRESET]: 'Network dropped connection on reset',
229
- [Errno.ETIMEDOUT]: 'Connection timed out',
230
- [Errno.ECONNREFUSED]: 'Connection refused',
231
- [Errno.EHOSTDOWN]: 'Host is down',
232
- [Errno.EHOSTUNREACH]: 'No route to host',
233
- [Errno.EALREADY]: 'Operation already in progress',
234
- [Errno.EINPROGRESS]: 'Operation now in progress',
235
- [Errno.ESTALE]: 'Stale file handle',
236
- [Errno.EREMOTEIO]: 'Remote I/O error',
237
- [Errno.EDQUOT]: 'Disk quota exceeded',
238
- };
239
- /**
240
- * An error with additional information about what happened
241
- * @category Internals
242
- */
243
- export class ErrnoError extends Error {
244
- static fromJSON(json) {
245
- const err = new ErrnoError(json.errno, json.message, json.path, json.syscall);
246
- err.code = json.code;
247
- err.stack = json.stack;
248
- return err;
249
- }
250
- static With(code, path, syscall) {
251
- return new ErrnoError(Errno[code], errorMessages[Errno[code]], path, syscall);
252
- }
253
- constructor(
254
- /**
255
- * The kind of error
256
- */
257
- errno,
258
- /**
259
- * A descriptive error message
260
- */
261
- message = errorMessages[errno], path, syscall = '') {
262
- super(message);
263
- this.errno = errno;
264
- this.message = message;
265
- this.path = path;
266
- this.syscall = syscall;
267
- this.code = Errno[errno];
268
- }
269
- /**
270
- * @returns A friendly error message.
271
- */
272
- toString() {
273
- return this.code + ': ' + this.message + (this.path ? `, '${this.path}'` : '');
274
- }
275
- toJSON() {
276
- return {
277
- errno: this.errno,
278
- code: this.code,
279
- path: this.path,
280
- stack: this.stack,
281
- message: this.message,
282
- syscall: this.syscall,
283
- };
284
- }
285
- /**
286
- * The size of the API error in buffer-form in bytes.
287
- */
288
- bufferSize() {
289
- // 4 bytes for string length.
290
- return 4 + JSON.stringify(this.toJSON()).length;
291
- }
6
+ export const ErrnoError = Exception;
7
+ export function withPath(e, path) {
8
+ e.path = path;
9
+ return e;
10
+ }
11
+ export function wrap(fs, prop, path, dest) {
12
+ const fn = fs[prop];
13
+ if (typeof fn !== 'function')
14
+ throw new TypeError(`${prop} is not a function`);
15
+ return function (...args) {
16
+ try {
17
+ return fn.call(fs, ...args);
18
+ }
19
+ catch (e) {
20
+ throw setUVMessage(Object.assign(e, { path, dest, syscall: prop.endsWith('Sync') ? prop.slice(0, -4) : prop }));
21
+ }
22
+ };
292
23
  }
@@ -1,6 +1,6 @@
1
+ import type { UsageInfo } from './filesystem.js';
1
2
  import type { InodeLike } from './inode.js';
2
3
  import { Inode } from './inode.js';
3
- import type { UsageInfo } from './filesystem.js';
4
4
  /**
5
5
  * An Index in JSON form
6
6
  * @internal
@@ -1,8 +1,9 @@
1
1
  /* Note: this file is named file_index.ts because Typescript has special behavior regarding index.ts which can't be disabled. */
2
- import { isJSON, randomInt, sizeof } from 'utilium';
3
- import { S_IFDIR, S_IFMT, size_max } from '../vfs/constants.js';
2
+ import { withErrno } from 'kerium';
3
+ import { sizeof } from 'memium';
4
+ import { isJSON, randomInt } from 'utilium';
4
5
  import { basename, dirname } from '../path.js';
5
- import { Errno, ErrnoError } from './error.js';
6
+ import { S_IFDIR, S_IFMT, size_max } from '../vfs/constants.js';
6
7
  import { Inode } from './inode.js';
7
8
  export const version = 1;
8
9
  /**
@@ -65,9 +66,9 @@ export class Index extends Map {
65
66
  directoryEntries(path) {
66
67
  const node = this.get(path);
67
68
  if (!node)
68
- throw ErrnoError.With('ENOENT', path);
69
+ throw withErrno('ENOENT');
69
70
  if ((node.mode & S_IFMT) != S_IFDIR)
70
- throw ErrnoError.With('ENOTDIR', path);
71
+ throw withErrno('ENOTDIR');
71
72
  const entries = {};
72
73
  for (const entry of this.keys()) {
73
74
  if (dirname(entry) == path && entry != path) {
@@ -106,9 +107,8 @@ export class Index extends Map {
106
107
  */
107
108
  fromJSON(json) {
108
109
  var _a;
109
- if (json.version != version) {
110
- throw new ErrnoError(Errno.EINVAL, 'Index version mismatch');
111
- }
110
+ if (json.version != version)
111
+ throw withErrno('EINVAL', 'Index version mismatch');
112
112
  this.clear();
113
113
  for (const [path, node] of Object.entries(json.entries)) {
114
114
  (_a = node.data) !== null && _a !== void 0 ? _a : (node.data = randomInt(1, size_max));
@@ -123,7 +123,7 @@ export class Index extends Map {
123
123
  */
124
124
  static parse(data) {
125
125
  if (!isJSON(data))
126
- throw new ErrnoError(Errno.EINVAL, 'Invalid JSON');
126
+ throw withErrno('EINVAL', 'Invalid JSON');
127
127
  const json = JSON.parse(data);
128
128
  const index = new Index();
129
129
  index.fromJSON(json);
@@ -1,6 +1,6 @@
1
+ import type { UUID } from 'node:crypto';
1
2
  import type { ConstMap } from 'utilium';
2
3
  import type { InodeLike } from './inode.js';
3
- import type { UUID } from 'node:crypto';
4
4
  /**
5
5
  * Usage information about a file system
6
6
  * @category Internals
@@ -36,22 +36,22 @@ export interface UsageInfo {
36
36
  * @internal
37
37
  */
38
38
  export type FileSystemAttributes = {
39
- /** If set, disables `PreloadFile` from using a resizable array buffer. */
40
- no_buffer_resize: void;
41
39
  /**
42
40
  * If set disables async file systems from preloading their contents.
43
41
  * This means *sync operations will not work* (unless the contents are cached)
44
42
  * It has no affect on sync file systems.
45
43
  */
46
- no_async: void;
44
+ no_async_preload: void;
47
45
  /**
48
46
  * Currently unused. In the future, this will disable caching.
49
- * Not recommended due to performance impact.
47
+ * Analogous to `S_DAX` on every file.
50
48
  */
51
49
  no_cache: void;
52
50
  /**
53
51
  * If set, the file system should not be written to.
54
52
  * This should be set for read-only file systems.
53
+ * Note this does NOT trigger EROFS errors;
54
+ * writes will silently be dropped.
55
55
  */
56
56
  no_write: void;
57
57
  /**
@@ -64,6 +64,21 @@ export type FileSystemAttributes = {
64
64
  * @internal
65
65
  */
66
66
  default_stream_write: void;
67
+ /**
68
+ * Do not update access times.
69
+ */
70
+ no_atime: void;
71
+ /**
72
+ * Ignore suid and sgid bits.
73
+ * @todo Implement
74
+ * @experimental
75
+ */
76
+ no_suid: void;
77
+ /**
78
+ * Writes are synced at once
79
+ * @experimental
80
+ */
81
+ sync: void;
67
82
  };
68
83
  /**
69
84
  * Options used when creating files and directories.
@@ -71,7 +86,7 @@ export type FileSystemAttributes = {
71
86
  * @category Internals
72
87
  * @internal
73
88
  */
74
- export interface CreationOptions {
89
+ export interface CreationOptions extends Partial<InodeLike> {
75
90
  /**
76
91
  * The uid to create the file.
77
92
  * This is ignored if the FS supports setuid and the setuid bit is set
@@ -184,8 +199,8 @@ export declare abstract class FileSystem {
184
199
  existsSync(path: string): boolean;
185
200
  abstract link(target: string, link: string): Promise<void>;
186
201
  abstract linkSync(target: string, link: string): void;
187
- abstract sync(path: string): Promise<void>;
188
- abstract syncSync(path: string): void;
202
+ abstract sync(): Promise<void>;
203
+ abstract syncSync(): void;
189
204
  /**
190
205
  * Reads into a buffer
191
206
  * @param buffer The buffer to read into. You must set the `byteOffset` and `byteLength` appropriately!
@@ -1,3 +1,4 @@
1
+ export { log } from 'kerium';
1
2
  export * from './credentials.js';
2
3
  export * from './devices.js';
3
4
  export * from './error.js';
@@ -5,4 +6,3 @@ export * from './file_index.js';
5
6
  export * from './filesystem.js';
6
7
  export * from './index_fs.js';
7
8
  export * from './inode.js';
8
- export * as log from './log.js';
@@ -1,3 +1,4 @@
1
+ export { log } from 'kerium'; // DO NOT USE
1
2
  export * from './credentials.js';
2
3
  export * from './devices.js';
3
4
  export * from './error.js';
@@ -5,4 +6,3 @@ export * from './file_index.js';
5
6
  export * from './filesystem.js';
6
7
  export * from './index_fs.js';
7
8
  export * from './inode.js';
8
- export * as log from './log.js';
@@ -36,6 +36,6 @@ export declare abstract class IndexFS extends FileSystem {
36
36
  linkSync(target: string, link: string): void;
37
37
  readdir(path: string): Promise<string[]>;
38
38
  readdirSync(path: string): string[];
39
- sync(path: string): Promise<void>;
40
- syncSync(path: string): void;
39
+ sync(): Promise<void>;
40
+ syncSync(): void;
41
41
  }
@@ -1,8 +1,8 @@
1
1
  /* eslint-disable @typescript-eslint/require-await */
2
+ import { withErrno } from 'kerium';
2
3
  import { _throw } from 'utilium';
3
- import { S_IFDIR, S_IFMT, S_IFREG, S_ISGID, S_ISUID } from '../vfs/constants.js';
4
4
  import { dirname, join, relative } from '../path.js';
5
- import { ErrnoError } from './error.js';
5
+ import { S_IFDIR, S_IFMT, S_IFREG, S_ISGID, S_ISUID } from '../vfs/constants.js';
6
6
  import { Index } from './file_index.js';
7
7
  import { FileSystem } from './filesystem.js';
8
8
  import { Inode } from './inode.js';
@@ -24,9 +24,9 @@ export class IndexFS extends FileSystem {
24
24
  */
25
25
  pathsForRename(oldPath, newPath) {
26
26
  if (!this.index.has(oldPath))
27
- throw ErrnoError.With('ENOENT', oldPath, 'rename');
27
+ throw withErrno('ENOENT');
28
28
  if ((dirname(newPath) + '/').startsWith(oldPath + '/'))
29
- throw ErrnoError.With('EBUSY', dirname(oldPath), 'rename');
29
+ throw withErrno('EBUSY');
30
30
  const toRename = [];
31
31
  for (const [from, inode] of this.index.entries()) {
32
32
  const rel = relative(oldPath, from);
@@ -66,35 +66,36 @@ export class IndexFS extends FileSystem {
66
66
  async stat(path) {
67
67
  const inode = this.index.get(path);
68
68
  if (!inode)
69
- throw ErrnoError.With('ENOENT', path, 'stat');
69
+ throw withErrno('ENOENT');
70
70
  return inode;
71
71
  }
72
72
  statSync(path) {
73
73
  const inode = this.index.get(path);
74
74
  if (!inode)
75
- throw ErrnoError.With('ENOENT', path, 'stat');
75
+ throw withErrno('ENOENT');
76
76
  return inode;
77
77
  }
78
78
  async touch(path, metadata) {
79
79
  var _a;
80
- const inode = (_a = this.index.get(path)) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENOENT', path, 'touch'));
80
+ const inode = (_a = this.index.get(path)) !== null && _a !== void 0 ? _a : _throw(withErrno('ENOENT'));
81
81
  inode.update(metadata);
82
82
  }
83
83
  touchSync(path, metadata) {
84
84
  var _a;
85
- const inode = (_a = this.index.get(path)) !== null && _a !== void 0 ? _a : _throw(ErrnoError.With('ENOENT', path, 'touch'));
85
+ const inode = (_a = this.index.get(path)) !== null && _a !== void 0 ? _a : _throw(withErrno('ENOENT'));
86
86
  inode.update(metadata);
87
87
  }
88
88
  _remove(path, isUnlink) {
89
- const syscall = isUnlink ? 'unlink' : 'rmdir';
90
89
  const inode = this.index.get(path);
91
90
  if (!inode)
92
- throw ErrnoError.With('ENOENT', path, syscall);
91
+ throw withErrno('ENOENT');
93
92
  const isDir = (inode.mode & S_IFMT) == S_IFDIR;
94
93
  if (!isDir && !isUnlink)
95
- throw ErrnoError.With('ENOTDIR', path, syscall);
94
+ throw withErrno('ENOTDIR');
96
95
  if (isDir && isUnlink)
97
- throw ErrnoError.With('EISDIR', path, syscall);
96
+ throw withErrno('EISDIR');
97
+ if (isDir && this.readdirSync(path).length)
98
+ throw withErrno('ENOTEMPTY');
98
99
  this.index.delete(path);
99
100
  }
100
101
  async unlink(path) {
@@ -114,12 +115,11 @@ export class IndexFS extends FileSystem {
114
115
  this.removeSync(path);
115
116
  }
116
117
  create(path, options) {
117
- const syscall = (options.mode & S_IFMT) == S_IFDIR ? 'mkdir' : 'createFile';
118
118
  if (this.index.has(path))
119
- throw ErrnoError.With('EEXIST', path, syscall);
119
+ throw withErrno('EEXIST');
120
120
  const parent = this.index.get(dirname(path));
121
121
  if (!parent)
122
- throw ErrnoError.With('ENOENT', dirname(path), syscall);
122
+ throw withErrno('ENOENT');
123
123
  const id = this.index._alloc();
124
124
  const inode = new Inode({
125
125
  ino: id,
@@ -149,10 +149,10 @@ export class IndexFS extends FileSystem {
149
149
  return this.create(path, options);
150
150
  }
151
151
  link(target, link) {
152
- throw ErrnoError.With('ENOSYS', link, 'link');
152
+ throw withErrno('ENOSYS');
153
153
  }
154
154
  linkSync(target, link) {
155
- throw ErrnoError.With('ENOSYS', link, 'link');
155
+ throw withErrno('ENOSYS');
156
156
  }
157
157
  async readdir(path) {
158
158
  return Object.keys(this.index.directoryEntries(path));
@@ -160,6 +160,6 @@ export class IndexFS extends FileSystem {
160
160
  readdirSync(path) {
161
161
  return Object.keys(this.index.directoryEntries(path));
162
162
  }
163
- async sync(path) { }
164
- syncSync(path) { }
163
+ async sync() { }
164
+ syncSync() { }
165
165
  }