@zenfs/core 0.5.3 → 0.5.5
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/ApiError.d.ts +5 -12
- package/dist/ApiError.js +6 -27
- package/dist/FileIndex.js +10 -10
- package/dist/backends/AsyncStore.js +36 -44
- package/dist/backends/Overlay.js +17 -17
- package/dist/backends/SyncStore.d.ts +1 -1
- package/dist/backends/SyncStore.js +29 -34
- package/dist/backends/backend.d.ts +3 -3
- package/dist/browser.min.js +4 -4
- package/dist/browser.min.js.map +3 -3
- package/dist/emulation/promises.d.ts +2 -3
- package/dist/emulation/promises.js +15 -11
- package/dist/emulation/shared.d.ts +9 -1
- package/dist/emulation/shared.js +28 -40
- package/dist/emulation/sync.d.ts +3 -6
- package/dist/emulation/sync.js +17 -7
- package/dist/file.d.ts +4 -0
- package/dist/file.js +10 -14
- package/dist/stats.d.ts +2 -3
- package/dist/stats.js +6 -22
- package/dist/utils.js +6 -2
- package/package.json +1 -1
- package/readme.md +2 -2
|
@@ -214,10 +214,9 @@ export declare function lopen(path: PathLike, flag: string, mode?: Node.Mode): P
|
|
|
214
214
|
export declare function readFile(filename: PathLike, options?: {
|
|
215
215
|
flag?: Node.OpenMode;
|
|
216
216
|
}): Promise<Uint8Array>;
|
|
217
|
-
export declare function readFile(filename: PathLike, options: {
|
|
218
|
-
encoding?: BufferEncoding;
|
|
217
|
+
export declare function readFile(filename: PathLike, options: (Node.BaseEncodingOptions & {
|
|
219
218
|
flag?: Node.OpenMode;
|
|
220
|
-
} | BufferEncoding): Promise<string>;
|
|
219
|
+
}) | BufferEncoding): Promise<string>;
|
|
221
220
|
/**
|
|
222
221
|
* Synchronously writes data to a file, replacing the file if it already exists.
|
|
223
222
|
*
|
|
@@ -6,6 +6,7 @@ import { BigIntStats, FileType } from '../stats.js';
|
|
|
6
6
|
import { decode, encode } from '../utils.js';
|
|
7
7
|
import { Dirent } from './dir.js';
|
|
8
8
|
import { dirname, join } from './path.js';
|
|
9
|
+
import { F_OK } from './constants.js';
|
|
9
10
|
export class FileHandle {
|
|
10
11
|
constructor(
|
|
11
12
|
/**
|
|
@@ -98,7 +99,7 @@ export class FileHandle {
|
|
|
98
99
|
return fd2file(this.fd).read(buffer, offset, length, position);
|
|
99
100
|
}
|
|
100
101
|
async readFile(_options) {
|
|
101
|
-
const options = normalizeOptions(_options, null, 'r',
|
|
102
|
+
const options = normalizeOptions(_options, null, 'r', 0o444);
|
|
102
103
|
const flag = parseFlag(options.flag);
|
|
103
104
|
if (!isReadable(flag)) {
|
|
104
105
|
throw new ApiError(ErrorCode.EINVAL, 'Flag passed must allow for reading.');
|
|
@@ -208,15 +209,18 @@ async function doOp(...[name, resolveSymlinks, rawPath, ...args]) {
|
|
|
208
209
|
export async function rename(oldPath, newPath) {
|
|
209
210
|
oldPath = normalizePath(oldPath);
|
|
210
211
|
newPath = normalizePath(newPath);
|
|
211
|
-
const
|
|
212
|
-
const
|
|
212
|
+
const src = resolveFS(oldPath);
|
|
213
|
+
const dst = resolveFS(newPath);
|
|
213
214
|
try {
|
|
214
|
-
|
|
215
|
-
|
|
215
|
+
if (src.mountPoint == dst.mountPoint) {
|
|
216
|
+
await src.fs.rename(src.path, dst.path, cred);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
await writeFile(newPath, await readFile(oldPath));
|
|
216
220
|
await unlink(oldPath);
|
|
217
221
|
}
|
|
218
222
|
catch (e) {
|
|
219
|
-
throw fixError(e, { [
|
|
223
|
+
throw fixError(e, { [src.path]: oldPath, [dst.path]: newPath });
|
|
220
224
|
}
|
|
221
225
|
}
|
|
222
226
|
rename;
|
|
@@ -279,7 +283,7 @@ async function _open(_path, _flag, _mode = 0o644, resolveSymlinks) {
|
|
|
279
283
|
try {
|
|
280
284
|
switch (pathExistsAction(flag)) {
|
|
281
285
|
case ActionType.THROW:
|
|
282
|
-
throw ApiError.EEXIST
|
|
286
|
+
throw ApiError.With('EEXIST', path, '_open');
|
|
283
287
|
case ActionType.TRUNCATE:
|
|
284
288
|
/*
|
|
285
289
|
In a previous implementation, we deleted the file and
|
|
@@ -307,11 +311,11 @@ async function _open(_path, _flag, _mode = 0o644, resolveSymlinks) {
|
|
|
307
311
|
// Ensure parent exists.
|
|
308
312
|
const parentStats = await doOp('stat', resolveSymlinks, dirname(path), cred);
|
|
309
313
|
if (parentStats && !parentStats.isDirectory()) {
|
|
310
|
-
throw ApiError.ENOTDIR
|
|
314
|
+
throw ApiError.With('ENOTDIR', dirname(path), '_open');
|
|
311
315
|
}
|
|
312
316
|
return await doOp('createFile', resolveSymlinks, path, flag, mode, cred);
|
|
313
317
|
case ActionType.THROW:
|
|
314
|
-
throw ApiError.ENOENT
|
|
318
|
+
throw ApiError.With('ENOENT', path, '_open');
|
|
315
319
|
default:
|
|
316
320
|
throw new ApiError(ErrorCode.EINVAL, 'Invalid file flag');
|
|
317
321
|
}
|
|
@@ -527,7 +531,7 @@ export async function symlink(target, path, type = 'file') {
|
|
|
527
531
|
throw new ApiError(ErrorCode.EINVAL, 'Invalid symlink type: ' + type);
|
|
528
532
|
}
|
|
529
533
|
if (await exists(path)) {
|
|
530
|
-
throw ApiError.EEXIST
|
|
534
|
+
throw ApiError.With('EEXIST', path, 'symlink');
|
|
531
535
|
}
|
|
532
536
|
await writeFile(path, target);
|
|
533
537
|
const file = await _open(path, 'r+', 0o644, false);
|
|
@@ -668,7 +672,7 @@ export async function watch(filename, arg2, listener = nop) {
|
|
|
668
672
|
* @param path
|
|
669
673
|
* @param mode
|
|
670
674
|
*/
|
|
671
|
-
export async function access(path, mode =
|
|
675
|
+
export async function access(path, mode = F_OK) {
|
|
672
676
|
const stats = await stat(path);
|
|
673
677
|
if (!stats.hasAccess(mode, cred)) {
|
|
674
678
|
throw new ApiError(ErrorCode.EACCES);
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
2
3
|
import { Cred } from '../cred.js';
|
|
3
4
|
import { FileSystem } from '../filesystem.js';
|
|
4
5
|
import type { File } from '../file.js';
|
|
6
|
+
import type { BaseEncodingOptions, OpenMode, WriteFileOptions } from 'node:fs';
|
|
5
7
|
/**
|
|
6
8
|
* converts Date or number to a integer UNIX timestamp
|
|
7
9
|
* Grabbed from NodeJS sources (lib/fs.js)
|
|
@@ -26,9 +28,15 @@ export declare function normalizeTime(time: string | number | Date): Date;
|
|
|
26
28
|
export declare function normalizePath(p: string): string;
|
|
27
29
|
/**
|
|
28
30
|
* Normalizes options
|
|
31
|
+
* @param options options to normalize
|
|
32
|
+
* @param encoding default encoding
|
|
33
|
+
* @param flag default flag
|
|
34
|
+
* @param mode default mode
|
|
29
35
|
* @internal
|
|
30
36
|
*/
|
|
31
|
-
export declare function normalizeOptions(options
|
|
37
|
+
export declare function normalizeOptions(options?: WriteFileOptions | (BaseEncodingOptions & {
|
|
38
|
+
flag?: OpenMode;
|
|
39
|
+
}), encoding?: BufferEncoding, flag?: string, mode?: number): {
|
|
32
40
|
encoding: BufferEncoding;
|
|
33
41
|
flag: string;
|
|
34
42
|
mode: number;
|
package/dist/emulation/shared.js
CHANGED
|
@@ -23,16 +23,14 @@ export function _toUnixTimestamp(time) {
|
|
|
23
23
|
* @internal
|
|
24
24
|
*/
|
|
25
25
|
export function normalizeMode(mode, def) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return trueMode;
|
|
35
|
-
}
|
|
26
|
+
if (typeof mode == 'number') {
|
|
27
|
+
return mode;
|
|
28
|
+
}
|
|
29
|
+
if (typeof mode == 'string') {
|
|
30
|
+
const parsed = parseInt(mode, 8);
|
|
31
|
+
if (!isNaN(parsed)) {
|
|
32
|
+
return parsed;
|
|
33
|
+
}
|
|
36
34
|
}
|
|
37
35
|
if (typeof def == 'number') {
|
|
38
36
|
return def;
|
|
@@ -61,45 +59,35 @@ export function normalizeTime(time) {
|
|
|
61
59
|
*/
|
|
62
60
|
export function normalizePath(p) {
|
|
63
61
|
// Node doesn't allow null characters in paths.
|
|
64
|
-
if (p.
|
|
62
|
+
if (p.includes('\x00')) {
|
|
65
63
|
throw new ApiError(ErrorCode.EINVAL, 'Path must be a string without null bytes.');
|
|
66
64
|
}
|
|
67
|
-
if (p
|
|
65
|
+
if (p.length == 0) {
|
|
68
66
|
throw new ApiError(ErrorCode.EINVAL, 'Path must not be empty.');
|
|
69
67
|
}
|
|
70
|
-
|
|
71
|
-
return resolve(p);
|
|
68
|
+
return resolve(p.replaceAll(/[/\\]+/g, '/'));
|
|
72
69
|
}
|
|
73
70
|
/**
|
|
74
71
|
* Normalizes options
|
|
72
|
+
* @param options options to normalize
|
|
73
|
+
* @param encoding default encoding
|
|
74
|
+
* @param flag default flag
|
|
75
|
+
* @param mode default mode
|
|
75
76
|
* @internal
|
|
76
77
|
*/
|
|
77
|
-
export function normalizeOptions(options,
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
mode: defMode,
|
|
91
|
-
};
|
|
92
|
-
case 'null':
|
|
93
|
-
case 'undefined':
|
|
94
|
-
case 'function':
|
|
95
|
-
return {
|
|
96
|
-
encoding: defEnc,
|
|
97
|
-
flag: defFlag,
|
|
98
|
-
mode: defMode,
|
|
99
|
-
};
|
|
100
|
-
default:
|
|
101
|
-
throw new TypeError(`"options" must be a string or an object, got ${typeof options} instead.`);
|
|
102
|
-
}
|
|
78
|
+
export function normalizeOptions(options, encoding = 'utf8', flag, mode = 0) {
|
|
79
|
+
if (typeof options != 'object' || options === null) {
|
|
80
|
+
return {
|
|
81
|
+
encoding: typeof options == 'string' ? options : encoding,
|
|
82
|
+
flag,
|
|
83
|
+
mode,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
encoding: typeof options?.encoding == 'string' ? options.encoding : encoding,
|
|
88
|
+
flag: typeof options?.flag == 'string' ? options.flag : flag,
|
|
89
|
+
mode: normalizeMode('mode' in options ? options?.mode : null, mode),
|
|
90
|
+
};
|
|
103
91
|
}
|
|
104
92
|
/**
|
|
105
93
|
* Do nothing
|
package/dist/emulation/sync.d.ts
CHANGED
|
@@ -76,11 +76,9 @@ export declare function lopenSync(path: PathLike, flag: string, mode?: Node.Mode
|
|
|
76
76
|
export declare function readFileSync(filename: string, options?: {
|
|
77
77
|
flag?: string;
|
|
78
78
|
}): Uint8Array;
|
|
79
|
-
export declare function readFileSync(filename: string, options: {
|
|
80
|
-
encoding: string;
|
|
79
|
+
export declare function readFileSync(filename: string, options: (Node.BaseEncodingOptions & {
|
|
81
80
|
flag?: string;
|
|
82
|
-
}): string;
|
|
83
|
-
export declare function readFileSync(filename: string, encoding: string): string;
|
|
81
|
+
}) | BufferEncoding): string;
|
|
84
82
|
/**
|
|
85
83
|
* Synchronously writes data to a file, replacing the file if it already
|
|
86
84
|
* exists.
|
|
@@ -106,8 +104,7 @@ export declare function writeFileSync(filename: string, data: FileContents, enco
|
|
|
106
104
|
* @option options mode Defaults to `0644`.
|
|
107
105
|
* @option options flag Defaults to `'a'`.
|
|
108
106
|
*/
|
|
109
|
-
export declare function appendFileSync(filename: string, data: FileContents,
|
|
110
|
-
export declare function appendFileSync(filename: string, data: FileContents, encoding?: string): void;
|
|
107
|
+
export declare function appendFileSync(filename: string, data: FileContents, arg3?: Node.WriteFileOptions): void;
|
|
111
108
|
/**
|
|
112
109
|
* Synchronous `fstat`.
|
|
113
110
|
* `fstat()` is identical to `stat()`, except that the file to be stat-ed is
|
package/dist/emulation/sync.js
CHANGED
|
@@ -31,8 +31,7 @@ export function renameSync(oldPath, newPath) {
|
|
|
31
31
|
if (_old === _new) {
|
|
32
32
|
return _old.fs.renameSync(_old.path, _new.path, cred);
|
|
33
33
|
}
|
|
34
|
-
|
|
35
|
-
writeFileSync(newPath, data);
|
|
34
|
+
writeFileSync(newPath, readFileSync(oldPath));
|
|
36
35
|
unlinkSync(oldPath);
|
|
37
36
|
}
|
|
38
37
|
catch (e) {
|
|
@@ -105,22 +104,22 @@ function _openSync(_path, _flag, _mode, resolveSymlinks) {
|
|
|
105
104
|
// Ensure parent exists.
|
|
106
105
|
const parentStats = doOp('statSync', resolveSymlinks, dirname(path), cred);
|
|
107
106
|
if (!parentStats.isDirectory()) {
|
|
108
|
-
throw ApiError.ENOTDIR
|
|
107
|
+
throw ApiError.With('ENOTDIR', dirname(path), '_openSync');
|
|
109
108
|
}
|
|
110
109
|
return doOp('createFileSync', resolveSymlinks, path, flag, mode, cred);
|
|
111
110
|
case ActionType.THROW:
|
|
112
|
-
throw ApiError.ENOENT
|
|
111
|
+
throw ApiError.With('ENOENT', path, '_openSync');
|
|
113
112
|
default:
|
|
114
113
|
throw new ApiError(ErrorCode.EINVAL, 'Invalid FileFlag object.');
|
|
115
114
|
}
|
|
116
115
|
}
|
|
117
116
|
if (!stats.hasAccess(mode, cred)) {
|
|
118
|
-
throw ApiError.EACCES
|
|
117
|
+
throw ApiError.With('EACCES', path, '_openSync');
|
|
119
118
|
}
|
|
120
119
|
// File exists.
|
|
121
120
|
switch (pathExistsAction(flag)) {
|
|
122
121
|
case ActionType.THROW:
|
|
123
|
-
throw ApiError.EEXIST
|
|
122
|
+
throw ApiError.With('EEXIST', path, '_openSync');
|
|
124
123
|
case ActionType.TRUNCATE:
|
|
125
124
|
// Delete file.
|
|
126
125
|
doOp('unlinkSync', resolveSymlinks, path, cred);
|
|
@@ -228,6 +227,17 @@ function _appendFileSync(fname, data, flag, mode, resolveSymlinks) {
|
|
|
228
227
|
file.closeSync();
|
|
229
228
|
}
|
|
230
229
|
}
|
|
230
|
+
/**
|
|
231
|
+
* Asynchronously append data to a file, creating the file if it not yet
|
|
232
|
+
* exists.
|
|
233
|
+
*
|
|
234
|
+
* @param filename
|
|
235
|
+
* @param data
|
|
236
|
+
* @param options
|
|
237
|
+
* @option options encoding Defaults to `'utf8'`.
|
|
238
|
+
* @option options mode Defaults to `0644`.
|
|
239
|
+
* @option options flag Defaults to `'a'`.
|
|
240
|
+
*/
|
|
231
241
|
export function appendFileSync(filename, data, arg3) {
|
|
232
242
|
const options = normalizeOptions(arg3, 'utf8', 'a', 0o644);
|
|
233
243
|
const flag = parseFlag(options.flag);
|
|
@@ -414,7 +424,7 @@ export function symlinkSync(target, path, type = 'file') {
|
|
|
414
424
|
throw new ApiError(ErrorCode.EINVAL, 'Invalid type: ' + type);
|
|
415
425
|
}
|
|
416
426
|
if (existsSync(path)) {
|
|
417
|
-
throw ApiError.EEXIST
|
|
427
|
+
throw ApiError.With('EEXIST', path, 'symlinkSync');
|
|
418
428
|
}
|
|
419
429
|
writeFileSync(path, target);
|
|
420
430
|
const file = _openSync(path, 'r+', 0o644, false);
|
package/dist/file.d.ts
CHANGED
|
@@ -29,6 +29,10 @@ export declare enum ActionType {
|
|
|
29
29
|
export declare function parseFlag(flag: string | number): string;
|
|
30
30
|
export declare function flagToString(flag: number): string;
|
|
31
31
|
export declare function flagToNumber(flag: string): number;
|
|
32
|
+
/**
|
|
33
|
+
* Parses a flag as a mode (W_OK, R_OK, and/or X_OK)
|
|
34
|
+
* @param flag the flag to parse
|
|
35
|
+
*/
|
|
32
36
|
export declare function flagToMode(flag: string): number;
|
|
33
37
|
export declare function isReadable(flag: string): boolean;
|
|
34
38
|
export declare function isWriteable(flag: string): boolean;
|
package/dist/file.js
CHANGED
|
@@ -86,6 +86,10 @@ export function flagToNumber(flag) {
|
|
|
86
86
|
throw new Error('Invalid flag string: ' + flag);
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Parses a flag as a mode (W_OK, R_OK, and/or X_OK)
|
|
91
|
+
* @param flag the flag to parse
|
|
92
|
+
*/
|
|
89
93
|
export function flagToMode(flag) {
|
|
90
94
|
let mode = 0;
|
|
91
95
|
mode <<= 1;
|
|
@@ -323,15 +327,16 @@ export class PreloadFile extends File {
|
|
|
323
327
|
}
|
|
324
328
|
}
|
|
325
329
|
}
|
|
326
|
-
|
|
327
|
-
|
|
330
|
+
const slice = buffer.slice(offset, offset + length);
|
|
331
|
+
this._buffer.set(slice, position);
|
|
332
|
+
const bytesWritten = slice.byteLength;
|
|
328
333
|
this.stats.mtimeMs = Date.now();
|
|
329
334
|
if (isSynchronous(this.flag)) {
|
|
330
335
|
this.syncSync();
|
|
331
|
-
return
|
|
336
|
+
return bytesWritten;
|
|
332
337
|
}
|
|
333
|
-
this.position = position +
|
|
334
|
-
return
|
|
338
|
+
this.position = position + bytesWritten;
|
|
339
|
+
return bytesWritten;
|
|
335
340
|
}
|
|
336
341
|
/**
|
|
337
342
|
* Read data from the file.
|
|
@@ -389,9 +394,6 @@ export class PreloadFile extends File {
|
|
|
389
394
|
* @param mode
|
|
390
395
|
*/
|
|
391
396
|
chmodSync(mode) {
|
|
392
|
-
if (!this.fs.metadata().supportsProperties) {
|
|
393
|
-
throw new ApiError(ErrorCode.ENOTSUP);
|
|
394
|
-
}
|
|
395
397
|
this._dirty = true;
|
|
396
398
|
this.stats.chmod(mode);
|
|
397
399
|
this.syncSync();
|
|
@@ -410,9 +412,6 @@ export class PreloadFile extends File {
|
|
|
410
412
|
* @param gid
|
|
411
413
|
*/
|
|
412
414
|
chownSync(uid, gid) {
|
|
413
|
-
if (!this.fs.metadata().supportsProperties) {
|
|
414
|
-
throw new ApiError(ErrorCode.ENOTSUP);
|
|
415
|
-
}
|
|
416
415
|
this._dirty = true;
|
|
417
416
|
this.stats.chown(uid, gid);
|
|
418
417
|
this.syncSync();
|
|
@@ -421,9 +420,6 @@ export class PreloadFile extends File {
|
|
|
421
420
|
this.utimesSync(atime, mtime);
|
|
422
421
|
}
|
|
423
422
|
utimesSync(atime, mtime) {
|
|
424
|
-
if (!this.fs.metadata().supportsProperties) {
|
|
425
|
-
throw new ApiError(ErrorCode.ENOTSUP);
|
|
426
|
-
}
|
|
427
423
|
this._dirty = true;
|
|
428
424
|
this.stats.atime = atime;
|
|
429
425
|
this.stats.mtime = mtime;
|
package/dist/stats.d.ts
CHANGED
|
@@ -146,9 +146,8 @@ export declare abstract class StatsCommon<T extends number | bigint> implements
|
|
|
146
146
|
isFIFO(): boolean;
|
|
147
147
|
/**
|
|
148
148
|
* Checks if a given user/group has access to this item
|
|
149
|
-
* @param mode The
|
|
150
|
-
* @param
|
|
151
|
-
* @param gid The requesting GID
|
|
149
|
+
* @param mode The requested access, combination of W_OK, R_OK, and X_OK
|
|
150
|
+
* @param cred The requesting credentials
|
|
152
151
|
* @returns True if the request has access, false if the request does not
|
|
153
152
|
* @internal
|
|
154
153
|
*/
|
package/dist/stats.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S_IFDIR, S_IFLNK, S_IFMT, S_IFREG } from './emulation/constants.js';
|
|
1
|
+
import { S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, S_IRWXG, S_IRWXO, S_IRWXU } from './emulation/constants.js';
|
|
2
2
|
/**
|
|
3
3
|
* Indicates the type of the given file. Applied to 'mode'.
|
|
4
4
|
*/
|
|
@@ -145,9 +145,8 @@ export class StatsCommon {
|
|
|
145
145
|
}
|
|
146
146
|
/**
|
|
147
147
|
* Checks if a given user/group has access to this item
|
|
148
|
-
* @param mode The
|
|
149
|
-
* @param
|
|
150
|
-
* @param gid The requesting GID
|
|
148
|
+
* @param mode The requested access, combination of W_OK, R_OK, and X_OK
|
|
149
|
+
* @param cred The requesting credentials
|
|
151
150
|
* @returns True if the request has access, false if the request does not
|
|
152
151
|
* @internal
|
|
153
152
|
*/
|
|
@@ -156,24 +155,9 @@ export class StatsCommon {
|
|
|
156
155
|
//Running as root
|
|
157
156
|
return true;
|
|
158
157
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
const uPerms = (0xf00 & perms) >> 8;
|
|
163
|
-
uMode = (mode ^ uPerms) & mode;
|
|
164
|
-
}
|
|
165
|
-
if (cred.egid == this.gid) {
|
|
166
|
-
const gPerms = (0xf0 & perms) >> 4;
|
|
167
|
-
gMode = (mode ^ gPerms) & mode;
|
|
168
|
-
}
|
|
169
|
-
const wPerms = 0xf & perms;
|
|
170
|
-
wMode = (mode ^ wPerms) & mode;
|
|
171
|
-
/*
|
|
172
|
-
Result = 0b0xxx (read, write, execute)
|
|
173
|
-
If any bits are set that means the request does not have that permission.
|
|
174
|
-
*/
|
|
175
|
-
const result = uMode & gMode & wMode;
|
|
176
|
-
return !result;
|
|
158
|
+
// Mask for
|
|
159
|
+
const adjusted = (cred.uid == this.uid ? S_IRWXU : 0) | (cred.gid == this.gid ? S_IRWXG : 0) | S_IRWXO;
|
|
160
|
+
return (mode & this.mode & adjusted) == mode;
|
|
177
161
|
}
|
|
178
162
|
/**
|
|
179
163
|
* Convert the current stats object into a credentials object
|
package/dist/utils.js
CHANGED
|
@@ -103,6 +103,7 @@ export function encode(input, encoding = 'utf8') {
|
|
|
103
103
|
}
|
|
104
104
|
switch (encoding) {
|
|
105
105
|
case 'ascii':
|
|
106
|
+
return new Uint8Array(Array.from(input).map(char => char.charCodeAt(0) & 0x7f));
|
|
106
107
|
case 'latin1':
|
|
107
108
|
case 'binary':
|
|
108
109
|
return new Uint8Array(Array.from(input).map(char => char.charCodeAt(0)));
|
|
@@ -124,7 +125,7 @@ export function encode(input, encoding = 'utf8') {
|
|
|
124
125
|
return [(code >> 18) | 0xf0, ((code >> 12) & 0x3f) | 0x80, b, a];
|
|
125
126
|
}));
|
|
126
127
|
case 'base64':
|
|
127
|
-
return encode(atob(input), '
|
|
128
|
+
return encode(atob(input), 'binary');
|
|
128
129
|
case 'base64url':
|
|
129
130
|
return encode(input.replace('_', '/').replace('-', '+'), 'base64');
|
|
130
131
|
case 'hex':
|
|
@@ -151,6 +152,9 @@ export function decode(input, encoding = 'utf8') {
|
|
|
151
152
|
}
|
|
152
153
|
switch (encoding) {
|
|
153
154
|
case 'ascii':
|
|
155
|
+
return Array.from(input)
|
|
156
|
+
.map(char => String.fromCharCode(char & 0x7f))
|
|
157
|
+
.join('');
|
|
154
158
|
case 'latin1':
|
|
155
159
|
case 'binary':
|
|
156
160
|
return Array.from(input)
|
|
@@ -186,7 +190,7 @@ export function decode(input, encoding = 'utf8') {
|
|
|
186
190
|
}
|
|
187
191
|
return utf16leString;
|
|
188
192
|
case 'base64':
|
|
189
|
-
return btoa(decode(input, '
|
|
193
|
+
return btoa(decode(input, 'binary'));
|
|
190
194
|
case 'base64url':
|
|
191
195
|
return decode(input, 'base64').replace('/', '_').replace('+', '-');
|
|
192
196
|
case 'hex':
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -17,7 +17,7 @@ ZenFS is modular and extensible. The core includes a few built-in backends:
|
|
|
17
17
|
> [!NOTE]
|
|
18
18
|
> When constructed, `AsyncMirror` loads the entire contents of the async file system into a synchronous backend. It performs operations on the synchronous file system and then queues them to be mirrored onto the asynchronous backend.
|
|
19
19
|
|
|
20
|
-
ZenFS supports a number of other backends. Many are provided as
|
|
20
|
+
ZenFS supports a number of other backends. Many are provided as separate packages under `@zenfs`. More backends can be defined by separate libraries by extending the `FileSystem` class and/or providing a `Backend` object.
|
|
21
21
|
|
|
22
22
|
For more information, see the [docs](https://zen-fs.github.io/core).
|
|
23
23
|
|
|
@@ -110,7 +110,7 @@ if (!exists) {
|
|
|
110
110
|
> You can import the promises API using `promises`, or using `fs.promises` on the exported `fs`.
|
|
111
111
|
|
|
112
112
|
> [!IMPORTANT]
|
|
113
|
-
> ZenFS does _not_ provide a
|
|
113
|
+
> ZenFS does _not_ provide a separate public import for importing promises like `fs/promises`. If you are using ESM, you can import promises functions like `fs/promises` from the `dist/emulation/promises.ts` file, though this may change at any time and is **not recommended**.
|
|
114
114
|
|
|
115
115
|
#### Using asynchronous backends synchronously
|
|
116
116
|
|