@zenfs/core 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/file.js CHANGED
@@ -16,209 +16,118 @@ export var ActionType;
16
16
  // Indicates that the code should create the file.
17
17
  ActionType[ActionType["CREATE"] = 3] = "CREATE";
18
18
  })(ActionType = ActionType || (ActionType = {}));
19
- /**
20
- * Represents one of the following file flags. A convenience object.
21
- *
22
- * - r: Open file for reading. An exception occurs if the file does not exist.
23
- * - r+: Open file for reading and writing. An exception occurs if the file does not exist.
24
- * - rs: Open file for reading in synchronous mode. Instructs the filesystem to not cache writes.
25
- * - rs+: Open file for reading and writing, and opens the file in synchronous mode.
26
- * - w: Open file for writing. The file is created (if it does not exist) or truncated (if it exists).
27
- * - wx: Like 'w' but opens the file in exclusive mode.
28
- * - w+: Open file for reading and writing. The file is created (if it does not exist) or truncated (if it exists).
29
- * - wx+: Like 'w+' but opens the file in exclusive mode.
30
- * - a: Open file for appending. The file is created if it does not exist.
31
- * - ax: Like 'a' but opens the file in exclusive mode.
32
- * - a+: Open file for reading and appending. The file is created if it does not exist.
33
- * - ax+: Like 'a+' but opens the file in exclusive mode.
34
- *
35
- * Exclusive mode ensures that the file path is newly created.
36
- */
37
- export class FileFlag {
38
- /**
39
- * Get an object representing the given file flag.
40
- * @param flag The string or number representing the flag
41
- * @return The FileFlag object representing the flag
42
- * @throw when the flag string is invalid
43
- */
44
- static Get(flag) {
45
- // Check cache first.
46
- if (!FileFlag.cache.has(flag)) {
47
- FileFlag.cache.set(flag, new FileFlag(flag));
48
- }
49
- return FileFlag.cache.get(flag);
50
- }
51
- /**
52
- * @param flag The string or number representing the flag
53
- * @throw when the flag is invalid
54
- */
55
- constructor(flag) {
56
- if (typeof flag == 'number') {
57
- flag = FileFlag.StringOf(flag);
58
- }
59
- if (!FileFlag.validStrings.includes(flag)) {
60
- throw new ApiError(ErrorCode.EINVAL, 'Invalid flag string: ' + flag);
61
- }
62
- this._flag = flag;
63
- }
64
- /**
65
- * @param flag The number representing the flag
66
- * @returns The string representing the flag
67
- * @throws when the flag number is invalid
68
- */
69
- static StringOf(flag) {
70
- // based on https://github.com/nodejs/node/blob/abbdc3efaa455e6c907ebef5409ac8b0f222f969/lib/internal/fs/utils.js#L619
71
- switch (flag) {
72
- case O_RDONLY:
73
- return 'r';
74
- case O_RDONLY | O_SYNC:
75
- return 'rs';
76
- case O_RDWR:
77
- return 'r+';
78
- case O_RDWR | O_SYNC:
79
- return 'rs+';
80
- case O_TRUNC | O_CREAT | O_WRONLY:
81
- return 'w';
82
- case O_TRUNC | O_CREAT | O_WRONLY | O_EXCL:
83
- return 'wx';
84
- case O_TRUNC | O_CREAT | O_RDWR:
85
- return 'w+';
86
- case O_TRUNC | O_CREAT | O_RDWR | O_EXCL:
87
- return 'wx+';
88
- case O_APPEND | O_CREAT | O_WRONLY:
89
- return 'a';
90
- case O_APPEND | O_CREAT | O_WRONLY | O_EXCL:
91
- return 'ax';
92
- case O_APPEND | O_CREAT | O_RDWR:
93
- return 'a+';
94
- case O_APPEND | O_CREAT | O_RDWR | O_EXCL:
95
- return 'ax+';
96
- default:
97
- throw new ApiError(ErrorCode.EINVAL, 'Invalid flag number: ' + flag);
98
- }
99
- }
100
- /**
101
- * @param flag The string representing the flag
102
- * @returns The number representing the flag
103
- * @throws when the flag string is invalid
104
- */
105
- static NumberOf(flag) {
106
- switch (flag) {
107
- case 'r':
108
- return O_RDONLY;
109
- case 'rs':
110
- return O_RDONLY | O_SYNC;
111
- case 'r+':
112
- return O_RDWR;
113
- case 'rs+':
114
- return O_RDWR | O_SYNC;
115
- case 'w':
116
- return O_TRUNC | O_CREAT | O_WRONLY;
117
- case 'wx':
118
- return O_TRUNC | O_CREAT | O_WRONLY | O_EXCL;
119
- case 'w+':
120
- return O_TRUNC | O_CREAT | O_RDWR;
121
- case 'wx+':
122
- return O_TRUNC | O_CREAT | O_RDWR | O_EXCL;
123
- case 'a':
124
- return O_APPEND | O_CREAT | O_WRONLY;
125
- case 'ax':
126
- return O_APPEND | O_CREAT | O_WRONLY | O_EXCL;
127
- case 'a+':
128
- return O_APPEND | O_CREAT | O_RDWR;
129
- case 'ax+':
130
- return O_APPEND | O_CREAT | O_RDWR | O_EXCL;
131
- default:
132
- throw new ApiError(ErrorCode.EINVAL, 'Invalid flag string: ' + flag);
133
- }
134
- }
135
- /**
136
- * Get the underlying flag string for this flag.
137
- */
138
- toString() {
139
- return this._flag;
140
- }
141
- /**
142
- * Get the equivalent mode (0b0xxx: read, write, execute)
143
- * Note: Execute will always be 0
144
- */
145
- get mode() {
146
- let mode = 0;
147
- mode <<= 1;
148
- mode += +this.isReadable();
149
- mode <<= 1;
150
- mode += +this.isWriteable();
151
- mode <<= 1;
152
- return mode;
153
- }
154
- /**
155
- * Returns true if the file is readable.
156
- */
157
- isReadable() {
158
- return this._flag.indexOf('r') != -1 || this._flag.indexOf('+') != -1;
159
- }
160
- /**
161
- * Returns true if the file is writeable.
162
- */
163
- isWriteable() {
164
- return this._flag.indexOf('w') != -1 || this._flag.indexOf('a') != -1 || this._flag.indexOf('+') != -1;
19
+ const validFlags = ['r', 'r+', 'rs', 'rs+', 'w', 'wx', 'w+', 'wx+', 'a', 'ax', 'a+', 'ax+'];
20
+ export function parseFlag(flag) {
21
+ if (typeof flag === 'number') {
22
+ return flagToString(flag);
165
23
  }
166
- /**
167
- * Returns true if the file mode should truncate.
168
- */
169
- isTruncating() {
170
- return this._flag.indexOf('w') !== -1;
24
+ if (!validFlags.includes(flag)) {
25
+ throw new Error('Invalid flag string: ' + flag);
171
26
  }
172
- /**
173
- * Returns true if the file is appendable.
174
- */
175
- isAppendable() {
176
- return this._flag.indexOf('a') !== -1;
27
+ return flag;
28
+ }
29
+ export function flagToString(flag) {
30
+ switch (flag) {
31
+ case O_RDONLY:
32
+ return 'r';
33
+ case O_RDONLY | O_SYNC:
34
+ return 'rs';
35
+ case O_RDWR:
36
+ return 'r+';
37
+ case O_RDWR | O_SYNC:
38
+ return 'rs+';
39
+ case O_TRUNC | O_CREAT | O_WRONLY:
40
+ return 'w';
41
+ case O_TRUNC | O_CREAT | O_WRONLY | O_EXCL:
42
+ return 'wx';
43
+ case O_TRUNC | O_CREAT | O_RDWR:
44
+ return 'w+';
45
+ case O_TRUNC | O_CREAT | O_RDWR | O_EXCL:
46
+ return 'wx+';
47
+ case O_APPEND | O_CREAT | O_WRONLY:
48
+ return 'a';
49
+ case O_APPEND | O_CREAT | O_WRONLY | O_EXCL:
50
+ return 'ax';
51
+ case O_APPEND | O_CREAT | O_RDWR:
52
+ return 'a+';
53
+ case O_APPEND | O_CREAT | O_RDWR | O_EXCL:
54
+ return 'ax+';
55
+ default:
56
+ throw new Error('Invalid flag number: ' + flag);
177
57
  }
178
- /**
179
- * Returns true if the file is open in synchronous mode.
180
- */
181
- isSynchronous() {
182
- return this._flag.indexOf('s') !== -1;
58
+ }
59
+ export function flagToNumber(flag) {
60
+ switch (flag) {
61
+ case 'r':
62
+ return O_RDONLY;
63
+ case 'rs':
64
+ return O_RDONLY | O_SYNC;
65
+ case 'r+':
66
+ return O_RDWR;
67
+ case 'rs+':
68
+ return O_RDWR | O_SYNC;
69
+ case 'w':
70
+ return O_TRUNC | O_CREAT | O_WRONLY;
71
+ case 'wx':
72
+ return O_TRUNC | O_CREAT | O_WRONLY | O_EXCL;
73
+ case 'w+':
74
+ return O_TRUNC | O_CREAT | O_RDWR;
75
+ case 'wx+':
76
+ return O_TRUNC | O_CREAT | O_RDWR | O_EXCL;
77
+ case 'a':
78
+ return O_APPEND | O_CREAT | O_WRONLY;
79
+ case 'ax':
80
+ return O_APPEND | O_CREAT | O_WRONLY | O_EXCL;
81
+ case 'a+':
82
+ return O_APPEND | O_CREAT | O_RDWR;
83
+ case 'ax+':
84
+ return O_APPEND | O_CREAT | O_RDWR | O_EXCL;
85
+ default:
86
+ throw new Error('Invalid flag string: ' + flag);
183
87
  }
184
- /**
185
- * Returns true if the file is open in exclusive mode.
186
- */
187
- isExclusive() {
188
- return this._flag.indexOf('x') !== -1;
88
+ }
89
+ export function flagToMode(flag) {
90
+ let mode = 0;
91
+ mode <<= 1;
92
+ mode += +isReadable(flag);
93
+ mode <<= 1;
94
+ mode += +isWriteable(flag);
95
+ mode <<= 1;
96
+ return mode;
97
+ }
98
+ export function isReadable(flag) {
99
+ return flag.indexOf('r') !== -1 || flag.indexOf('+') !== -1;
100
+ }
101
+ export function isWriteable(flag) {
102
+ return flag.indexOf('w') !== -1 || flag.indexOf('a') !== -1 || flag.indexOf('+') !== -1;
103
+ }
104
+ export function isTruncating(flag) {
105
+ return flag.indexOf('w') !== -1;
106
+ }
107
+ export function isAppendable(flag) {
108
+ return flag.indexOf('a') !== -1;
109
+ }
110
+ export function isSynchronous(flag) {
111
+ return flag.indexOf('s') !== -1;
112
+ }
113
+ export function isExclusive(flag) {
114
+ return flag.indexOf('x') !== -1;
115
+ }
116
+ export function pathExistsAction(flag) {
117
+ if (isExclusive(flag)) {
118
+ return ActionType.THROW;
189
119
  }
190
- /**
191
- * Returns one of the static fields on this object that indicates the
192
- * appropriate response to the path existing.
193
- */
194
- pathExistsAction() {
195
- if (this.isExclusive()) {
196
- return ActionType.THROW;
197
- }
198
- if (this.isTruncating()) {
199
- return ActionType.TRUNCATE;
200
- }
201
- return ActionType.NOP;
120
+ if (isTruncating(flag)) {
121
+ return ActionType.TRUNCATE;
202
122
  }
203
- /**
204
- * Returns one of the static fields on this object that indicates the
205
- * appropriate response to the path not existing.
206
- */
207
- pathNotExistsAction() {
208
- if ((this.isWriteable() || this.isAppendable()) && this._flag != 'r+') {
209
- return ActionType.CREATE;
210
- }
211
- return ActionType.THROW;
123
+ return ActionType.NOP;
124
+ }
125
+ export function pathNotExistsAction(flag) {
126
+ if ((isWriteable(flag) || isAppendable(flag)) && flag !== 'r+') {
127
+ return ActionType.CREATE;
212
128
  }
129
+ return ActionType.THROW;
213
130
  }
214
- /**
215
- * Contains cached FileMode instances.
216
- */
217
- FileFlag.cache = new Map();
218
- /**
219
- * Array of valid mode strings.
220
- */
221
- FileFlag.validStrings = ['r', 'r+', 'rs', 'rs+', 'w', 'wx', 'w+', 'wx+', 'a', 'ax', 'a+', 'ax+'];
222
131
  export class File {
223
132
  /**
224
133
  * Asynchronous `datasync`.
@@ -284,7 +193,7 @@ export class PreloadFile extends File {
284
193
  if (this.stats.size == _buffer.byteLength) {
285
194
  return;
286
195
  }
287
- if (this.flag.isReadable()) {
196
+ if (isReadable(this.flag)) {
288
197
  throw new Error(`Size mismatch: buffer length ${_buffer.byteLength}, stats size ${this.stats.size}`);
289
198
  }
290
199
  this._dirty = true;
@@ -305,7 +214,7 @@ export class PreloadFile extends File {
305
214
  * @return The current file position.
306
215
  */
307
216
  get position() {
308
- if (this.flag.isAppendable()) {
217
+ if (isAppendable(this.flag)) {
309
218
  return this.stats.size;
310
219
  }
311
220
  return this._position;
@@ -335,7 +244,7 @@ export class PreloadFile extends File {
335
244
  */
336
245
  truncate(len) {
337
246
  this.truncateSync(len);
338
- if (this.flag.isSynchronous() && !this.fs.metadata().synchronous) {
247
+ if (isSynchronous(this.flag) && !this.fs.metadata().synchronous) {
339
248
  return this.sync();
340
249
  }
341
250
  }
@@ -345,7 +254,7 @@ export class PreloadFile extends File {
345
254
  */
346
255
  truncateSync(len) {
347
256
  this._dirty = true;
348
- if (!this.flag.isWriteable()) {
257
+ if (!isWriteable(this.flag)) {
349
258
  throw new ApiError(ErrorCode.EPERM, 'File not opened with a writeable mode.');
350
259
  }
351
260
  this.stats.mtimeMs = Date.now();
@@ -353,7 +262,7 @@ export class PreloadFile extends File {
353
262
  const buf = new Uint8Array(len - this._buffer.length);
354
263
  // Write will set stats.size for us.
355
264
  this.writeSync(buf, 0, buf.length, this._buffer.length);
356
- if (this.flag.isSynchronous() && this.fs.metadata().synchronous) {
265
+ if (isSynchronous(this.flag) && this.fs.metadata().synchronous) {
357
266
  this.syncSync();
358
267
  }
359
268
  return;
@@ -361,7 +270,7 @@ export class PreloadFile extends File {
361
270
  this.stats.size = len;
362
271
  // Truncate buffer to 'len'.
363
272
  this._buffer = this._buffer.subarray(0, len);
364
- if (this.flag.isSynchronous() && this.fs.metadata().synchronous) {
273
+ if (isSynchronous(this.flag) && this.fs.metadata().synchronous) {
365
274
  this.syncSync();
366
275
  }
367
276
  }
@@ -396,7 +305,7 @@ export class PreloadFile extends File {
396
305
  writeSync(buffer, offset = 0, length = this.stats.size, position = 0) {
397
306
  this._dirty = true;
398
307
  position ?? (position = this.position);
399
- if (!this.flag.isWriteable()) {
308
+ if (!isWriteable(this.flag)) {
400
309
  throw new ApiError(ErrorCode.EPERM, 'File not opened with a writeable mode.');
401
310
  }
402
311
  const endFp = position + length;
@@ -417,7 +326,7 @@ export class PreloadFile extends File {
417
326
  this._buffer.set(buffer.slice(offset, offset + length), position);
418
327
  const len = this._buffer.byteOffset;
419
328
  this.stats.mtimeMs = Date.now();
420
- if (this.flag.isSynchronous()) {
329
+ if (isSynchronous(this.flag)) {
421
330
  this.syncSync();
422
331
  return len;
423
332
  }
@@ -450,7 +359,7 @@ export class PreloadFile extends File {
450
359
  * @returns number of bytes written
451
360
  */
452
361
  readSync(buffer, offset = 0, length = this.stats.size, position = 0) {
453
- if (!this.flag.isReadable()) {
362
+ if (!isReadable(this.flag)) {
454
363
  throw new ApiError(ErrorCode.EPERM, 'File not opened with a readable mode.');
455
364
  }
456
365
  position ?? (position = this.position);
@@ -1,6 +1,6 @@
1
1
  import { ApiError } from './ApiError.js';
2
2
  import type { Stats } from './stats.js';
3
- import type { File, FileFlag } from './file.js';
3
+ import type { File } from './file.js';
4
4
  import type { Cred } from './cred.js';
5
5
  export type NoArgCallback = (e?: ApiError) => unknown;
6
6
  export type TwoArgCallback<T> = (e?: ApiError, rv?: T) => unknown;
@@ -71,24 +71,24 @@ export declare abstract class FileSystem {
71
71
  * @param p The path to open.
72
72
  * @param flag The flag to use when opening the file.
73
73
  */
74
- abstract openFile(path: string, flag: FileFlag, cred: Cred): Promise<File>;
74
+ abstract openFile(path: string, flag: string, cred: Cred): Promise<File>;
75
75
  /**
76
76
  * Opens the file at path p with the given flag. The file must exist.
77
77
  * @param p The path to open.
78
78
  * @param flag The flag to use when opening the file.
79
79
  * @return A File object corresponding to the opened file.
80
80
  */
81
- abstract openFileSync(path: string, flag: FileFlag, cred: Cred): File;
81
+ abstract openFileSync(path: string, flag: string, cred: Cred): File;
82
82
  /**
83
83
  * Create the file at path p with the given mode. Then, open it with the given
84
84
  * flag.
85
85
  */
86
- abstract createFile(path: string, flag: FileFlag, mode: number, cred: Cred): Promise<File>;
86
+ abstract createFile(path: string, flag: string, mode: number, cred: Cred): Promise<File>;
87
87
  /**
88
88
  * Create the file at path p with the given mode. Then, open it with the given
89
89
  * flag.
90
90
  */
91
- abstract createFileSync(path: string, flag: FileFlag, mode: number, cred: Cred): File;
91
+ abstract createFileSync(path: string, flag: string, mode: number, cred: Cred): File;
92
92
  /**
93
93
  * Asynchronous `unlink`.
94
94
  */
@@ -162,8 +162,8 @@ declare abstract class SyncFileSystem extends FileSystem {
162
162
  exists(path: string, cred: Cred): Promise<boolean>;
163
163
  rename(oldPath: string, newPath: string, cred: Cred): Promise<void>;
164
164
  stat(path: string, cred: Cred): Promise<Stats>;
165
- createFile(path: string, flag: FileFlag, mode: number, cred: Cred): Promise<File>;
166
- openFile(path: string, flag: FileFlag, cred: Cred): Promise<File>;
165
+ createFile(path: string, flag: string, mode: number, cred: Cred): Promise<File>;
166
+ openFile(path: string, flag: string, cred: Cred): Promise<File>;
167
167
  unlink(path: string, cred: Cred): Promise<void>;
168
168
  rmdir(path: string, cred: Cred): Promise<void>;
169
169
  mkdir(path: string, mode: number, cred: Cred): Promise<void>;
@@ -182,8 +182,8 @@ declare abstract class AsyncFileSystem {
182
182
  metadata(): FileSystemMetadata;
183
183
  renameSync(oldPath: string, newPath: string, cred: Cred): void;
184
184
  statSync(path: string, cred: Cred): Stats;
185
- createFileSync(path: string, flag: FileFlag, mode: number, cred: Cred): File;
186
- openFileSync(path: string, flag: FileFlag, cred: Cred): File;
185
+ createFileSync(path: string, flag: string, mode: number, cred: Cred): File;
186
+ openFileSync(path: string, flag: string, cred: Cred): File;
187
187
  unlinkSync(path: string, cred: Cred): void;
188
188
  rmdirSync(path: string, cred: Cred): void;
189
189
  mkdirSync(path: string, mode: number, cred: Cred): void;
@@ -199,8 +199,8 @@ declare abstract class ReadonlyFileSystem {
199
199
  metadata(): FileSystemMetadata;
200
200
  rename(oldPath: string, newPath: string, cred: Cred): Promise<void>;
201
201
  renameSync(oldPath: string, newPath: string, cred: Cred): void;
202
- createFile(path: string, flag: FileFlag, mode: number, cred: Cred): Promise<File>;
203
- createFileSync(path: string, flag: FileFlag, mode: number, cred: Cred): File;
202
+ createFile(path: string, flag: string, mode: number, cred: Cred): Promise<File>;
203
+ createFileSync(path: string, flag: string, mode: number, cred: Cred): File;
204
204
  unlink(path: string, cred: Cred): Promise<void>;
205
205
  unlinkSync(path: string, cred: Cred): void;
206
206
  rmdir(path: string, cred: Cred): Promise<void>;
package/dist/stats.d.ts CHANGED
@@ -154,10 +154,10 @@ export declare abstract class StatsCommon<T extends number | bigint> implements
154
154
  */
155
155
  hasAccess(mode: number, cred: Cred): boolean;
156
156
  /**
157
- * Convert the current stats object into a cred object
157
+ * Convert the current stats object into a credentials object
158
158
  * @internal
159
159
  */
160
- getCred(uid?: number, gid?: number): Cred;
160
+ cred(uid?: number, gid?: number): Cred;
161
161
  /**
162
162
  * Change the mode of the file. We use this helper function to prevent messing
163
163
  * up the type of the file, which is encoded in mode.
package/dist/stats.js CHANGED
@@ -1,4 +1,3 @@
1
- import { Cred } from './cred.js';
2
1
  import { S_IFDIR, S_IFLNK, S_IFMT, S_IFREG } from './emulation/constants.js';
3
2
  /**
4
3
  * Indicates the type of the given file. Applied to 'mode'.
@@ -177,11 +176,18 @@ export class StatsCommon {
177
176
  return !result;
178
177
  }
179
178
  /**
180
- * Convert the current stats object into a cred object
179
+ * Convert the current stats object into a credentials object
181
180
  * @internal
182
181
  */
183
- getCred(uid = Number(this.uid), gid = Number(this.gid)) {
184
- return new Cred(uid, gid, Number(this.uid), Number(this.gid), uid, gid);
182
+ cred(uid = Number(this.uid), gid = Number(this.gid)) {
183
+ return {
184
+ uid,
185
+ gid,
186
+ suid: Number(this.uid),
187
+ sgid: Number(this.gid),
188
+ euid: uid,
189
+ egid: gid,
190
+ };
185
191
  }
186
192
  /**
187
193
  * Change the mode of the file. We use this helper function to prevent messing
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenfs/core",
3
- "version": "0.4.2",
3
+ "version": "0.5.0",
4
4
  "description": "A filesystem in your browser",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist",