@zenfs/core 2.7.4 → 2.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backends/backend.js +0 -2
- package/dist/backends/cow.d.ts +2 -2
- package/dist/backends/cow.js +6 -14
- package/dist/backends/passthrough.d.ts +0 -54
- package/dist/backends/passthrough.js +0 -54
- package/dist/backends/port.d.ts +2 -6
- package/dist/backends/port.js +3 -11
- package/dist/backends/store/fs.d.ts +0 -9
- package/dist/backends/store/fs.js +1 -21
- package/dist/backends/store/store.d.ts +1 -1
- package/dist/backends/store/store.js +1 -5
- package/dist/internal/contexts.d.ts +1 -2
- package/dist/internal/credentials.d.ts +0 -3
- package/dist/internal/file_index.js +0 -1
- package/dist/internal/filesystem.js +2 -2
- package/dist/internal/index_fs.d.ts +2 -2
- package/dist/internal/index_fs.js +2 -2
- package/dist/internal/inode.d.ts +33 -45
- package/dist/internal/inode.js +12 -2
- package/dist/internal/ioctl.d.ts +83 -25
- package/dist/internal/ioctl.js +50 -185
- package/dist/internal/rpc.d.ts +16 -7
- package/dist/internal/rpc.js +2 -11
- package/dist/mixins/mutexed.d.ts +6 -41
- package/dist/mixins/mutexed.js +36 -109
- package/dist/mixins/sync.js +0 -2
- package/dist/node/async.js +2 -12
- package/dist/node/index.d.ts +1 -1
- package/dist/node/promises.d.ts +1 -6
- package/dist/node/promises.js +1 -1
- package/dist/node/stats.d.ts +25 -99
- package/dist/node/stats.js +18 -55
- package/dist/node/streams.d.ts +1 -37
- package/dist/node/sync.d.ts +1 -6
- package/dist/node/sync.js +2 -2
- package/dist/polyfills.js +9 -0
- package/dist/utils.d.ts +0 -4
- package/dist/vfs/acl.d.ts +1 -3
- package/dist/vfs/acl.js +1 -3
- package/dist/vfs/async.js +0 -5
- package/dist/vfs/dir.d.ts +3 -0
- package/dist/vfs/dir.js +4 -1
- package/dist/vfs/file.d.ts +1 -8
- package/dist/vfs/file.js +1 -3
- package/dist/vfs/sync.js +0 -1
- package/dist/vfs/vcache.js +0 -1
- package/dist/vfs/xattr.d.ts +2 -0
- package/dist/vfs/xattr.js +5 -4
- package/package.json +2 -3
- package/tests/common/context.test.ts +1 -1
- package/tests/common/mutex.test.ts +0 -61
package/dist/node/stats.js
CHANGED
|
@@ -15,41 +15,23 @@ export class StatsCommon {
|
|
|
15
15
|
return this._convert(Math.ceil(Number(this.size) / 512));
|
|
16
16
|
}
|
|
17
17
|
set blocks(value) { }
|
|
18
|
-
/**
|
|
19
|
-
* Unix-style file mode (e.g. 0o644) that includes the type of the item.
|
|
20
|
-
*/
|
|
18
|
+
/** Unix-style file mode (e.g. 0o644) that includes the type of the item. */
|
|
21
19
|
mode;
|
|
22
|
-
/**
|
|
23
|
-
* ID of device containing file
|
|
24
|
-
*/
|
|
20
|
+
/** ID of device containing file */
|
|
25
21
|
dev = this._convert(0);
|
|
26
|
-
/**
|
|
27
|
-
* Inode number
|
|
28
|
-
*/
|
|
22
|
+
/** Inode number */
|
|
29
23
|
ino = this._convert(0);
|
|
30
|
-
/**
|
|
31
|
-
* Device ID (if special file)
|
|
32
|
-
*/
|
|
24
|
+
/** Device ID (if special file) */
|
|
33
25
|
rdev = this._convert(0);
|
|
34
|
-
/**
|
|
35
|
-
* Number of hard links
|
|
36
|
-
*/
|
|
26
|
+
/** Number of hard links */
|
|
37
27
|
nlink = this._convert(1);
|
|
38
|
-
/**
|
|
39
|
-
* Block size for file system I/O
|
|
40
|
-
*/
|
|
28
|
+
/** Block size for file system I/O */
|
|
41
29
|
blksize = this._convert(4096);
|
|
42
|
-
/**
|
|
43
|
-
* User ID of owner
|
|
44
|
-
*/
|
|
30
|
+
/** User ID of owner */
|
|
45
31
|
uid = this._convert(0);
|
|
46
|
-
/**
|
|
47
|
-
* Group ID of owner
|
|
48
|
-
*/
|
|
32
|
+
/** Group ID of owner */
|
|
49
33
|
gid = this._convert(0);
|
|
50
|
-
/**
|
|
51
|
-
* Time of last access, since epoch
|
|
52
|
-
*/
|
|
34
|
+
/** Time of last access, since epoch */
|
|
53
35
|
atimeMs;
|
|
54
36
|
get atime() {
|
|
55
37
|
return new Date(Number(this.atimeMs));
|
|
@@ -63,9 +45,7 @@ export class StatsCommon {
|
|
|
63
45
|
set atimeInstant(value) {
|
|
64
46
|
this.atimeMs = this._convert(value.epochMilliseconds);
|
|
65
47
|
}
|
|
66
|
-
/**
|
|
67
|
-
* Time of last modification, since epoch
|
|
68
|
-
*/
|
|
48
|
+
/** Time of last modification, since epoch */
|
|
69
49
|
mtimeMs;
|
|
70
50
|
get mtime() {
|
|
71
51
|
return new Date(Number(this.mtimeMs));
|
|
@@ -79,9 +59,7 @@ export class StatsCommon {
|
|
|
79
59
|
set mtimeInstant(value) {
|
|
80
60
|
this.mtimeMs = this._convert(value.epochMilliseconds);
|
|
81
61
|
}
|
|
82
|
-
/**
|
|
83
|
-
* Time of last time file status was changed, since epoch
|
|
84
|
-
*/
|
|
62
|
+
/** Time of last time file status was changed, since epoch */
|
|
85
63
|
ctimeMs;
|
|
86
64
|
get ctime() {
|
|
87
65
|
return new Date(Number(this.ctimeMs));
|
|
@@ -95,9 +73,7 @@ export class StatsCommon {
|
|
|
95
73
|
set ctimeInstant(value) {
|
|
96
74
|
this.ctimeMs = this._convert(value.epochMilliseconds);
|
|
97
75
|
}
|
|
98
|
-
/**
|
|
99
|
-
* Time of file creation, since epoch
|
|
100
|
-
*/
|
|
76
|
+
/** Time of file creation, since epoch */
|
|
101
77
|
birthtimeMs;
|
|
102
78
|
get birthtime() {
|
|
103
79
|
return new Date(Number(this.birthtimeMs));
|
|
@@ -111,26 +87,15 @@ export class StatsCommon {
|
|
|
111
87
|
set birthtimeInstant(value) {
|
|
112
88
|
this.birthtimeMs = this._convert(value.epochMilliseconds);
|
|
113
89
|
}
|
|
114
|
-
/**
|
|
115
|
-
* Size of the item in bytes.
|
|
116
|
-
* For directories/symlinks, this is normally the size of the struct that represents the item.
|
|
117
|
-
*/
|
|
90
|
+
/** Size of the item in bytes. For directories/symlinks, this may be the size of the struct that represents the item. */
|
|
118
91
|
size;
|
|
119
|
-
/**
|
|
120
|
-
* @internal Used by inodes
|
|
121
|
-
*/
|
|
92
|
+
/** @internal Used by inodes */
|
|
122
93
|
data;
|
|
123
|
-
/**
|
|
124
|
-
* @internal Used by inodes
|
|
125
|
-
*/
|
|
94
|
+
/** @internal Used by inodes */
|
|
126
95
|
flags;
|
|
127
|
-
/**
|
|
128
|
-
* @internal Used by inodes
|
|
129
|
-
*/
|
|
96
|
+
/** @internal Used by inodes */
|
|
130
97
|
version;
|
|
131
|
-
/**
|
|
132
|
-
* Creates a new stats instance from a stats-like object. Can be used to copy stats (note)
|
|
133
|
-
*/
|
|
98
|
+
/** Creates a new stats instance from a stats-like object. Can be used to copy stats (note) */
|
|
134
99
|
constructor({ atimeMs, mtimeMs, ctimeMs, birthtimeMs, uid, gid, size, mode, ino, ...rest } = {}) {
|
|
135
100
|
const now = Date.now();
|
|
136
101
|
this.atimeMs = this._convert(atimeMs ?? now);
|
|
@@ -169,7 +134,7 @@ export class StatsCommon {
|
|
|
169
134
|
return (this.mode & c.S_IFMT) === c.S_IFIFO;
|
|
170
135
|
}
|
|
171
136
|
toJSON() {
|
|
172
|
-
return pick(this, _inode_fields);
|
|
137
|
+
return pick(this, ..._inode_fields, 'dev', 'blksize');
|
|
173
138
|
}
|
|
174
139
|
/**
|
|
175
140
|
* Checks if a given user/group has access to this item
|
|
@@ -225,8 +190,6 @@ export function isStatsEqual(left, right) {
|
|
|
225
190
|
&& +left.ctime == +right.ctime
|
|
226
191
|
&& left.mode == right.mode);
|
|
227
192
|
}
|
|
228
|
-
/** @internal */
|
|
229
|
-
export const ZenFsType = 0x7a656e6673; // 'z' 'e' 'n' 'f' 's'
|
|
230
193
|
/**
|
|
231
194
|
* @hidden
|
|
232
195
|
*/
|
package/dist/node/streams.d.ts
CHANGED
|
@@ -1,45 +1,10 @@
|
|
|
1
|
-
import type { Abortable } from 'node:events';
|
|
2
1
|
import type * as fs from 'node:fs';
|
|
3
2
|
import type { CreateReadStreamOptions, CreateWriteStreamOptions } from 'node:fs/promises';
|
|
4
3
|
import type { Callback } from '../utils.js';
|
|
5
4
|
import type { FileHandle } from './promises.js';
|
|
6
5
|
import { Readable } from '@zenfs/streams/readable';
|
|
7
6
|
import { Writable } from '@zenfs/streams/writable';
|
|
8
|
-
|
|
9
|
-
open?: (...args: unknown[]) => unknown;
|
|
10
|
-
close?: (...args: unknown[]) => unknown;
|
|
11
|
-
}
|
|
12
|
-
interface StreamOptions extends Abortable {
|
|
13
|
-
flags?: string;
|
|
14
|
-
encoding?: BufferEncoding;
|
|
15
|
-
fd?: number | FileHandle;
|
|
16
|
-
mode?: number;
|
|
17
|
-
autoClose?: boolean;
|
|
18
|
-
emitClose?: boolean;
|
|
19
|
-
start?: number;
|
|
20
|
-
highWaterMark?: number;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* This type is from node:fs but not exported.
|
|
24
|
-
* @hidden
|
|
25
|
-
*/
|
|
26
|
-
export interface ReadStreamOptions extends StreamOptions {
|
|
27
|
-
fs?: FSImplementation & {
|
|
28
|
-
read: (...args: unknown[]) => unknown;
|
|
29
|
-
};
|
|
30
|
-
end?: number;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* This type is from node:fs but not exported.
|
|
34
|
-
* @hidden
|
|
35
|
-
*/
|
|
36
|
-
export interface WriteStreamOptions extends StreamOptions {
|
|
37
|
-
flush?: boolean;
|
|
38
|
-
fs?: FSImplementation & {
|
|
39
|
-
write: (...args: unknown[]) => unknown;
|
|
40
|
-
writev?: (...args: unknown[]) => unknown;
|
|
41
|
-
};
|
|
42
|
-
}
|
|
7
|
+
export type { ReadStreamOptions, WriteStreamOptions } from 'node:fs';
|
|
43
8
|
/**
|
|
44
9
|
* A ReadStream implementation that wraps an underlying global ReadableStream.
|
|
45
10
|
*/
|
|
@@ -76,4 +41,3 @@ export declare class WriteStream extends Writable implements fs.WriteStream {
|
|
|
76
41
|
get path(): string;
|
|
77
42
|
get bytesWritten(): number;
|
|
78
43
|
}
|
|
79
|
-
export {};
|
package/dist/node/sync.d.ts
CHANGED
|
@@ -210,13 +210,8 @@ export declare function mkdtempSync(this: V_Context, prefix: fs.PathLike, option
|
|
|
210
210
|
* When the object is disposed, the directory and its contents will be removed if it still exists.
|
|
211
211
|
* If the directory cannot be deleted, disposal will throw an error.
|
|
212
212
|
* The object has a `remove()` method which will perform the same task.
|
|
213
|
-
* @todo Add `satisfies` and maybe change return type once @types/node adds this.
|
|
214
213
|
*/
|
|
215
|
-
export declare function mkdtempDisposableSync(this: V_Context, prefix: fs.PathLike, options?: fs.EncodingOption | fs.BufferEncodingOption):
|
|
216
|
-
path: string;
|
|
217
|
-
remove(): void;
|
|
218
|
-
[Symbol.dispose](): void;
|
|
219
|
-
};
|
|
214
|
+
export declare function mkdtempDisposableSync(this: V_Context, prefix: fs.PathLike, options?: fs.EncodingOption | fs.BufferEncodingOption): fs.DisposableTempDir;
|
|
220
215
|
/**
|
|
221
216
|
* Synchronous `copyFile`. Copies a file.
|
|
222
217
|
* @param flags Optional flags for the copy operation. Currently supports these flags:
|
package/dist/node/sync.js
CHANGED
|
@@ -541,7 +541,7 @@ export function rmSync(path, options) {
|
|
|
541
541
|
path = normalizePath.call(this, path);
|
|
542
542
|
let stats;
|
|
543
543
|
try {
|
|
544
|
-
stats = lstatSync.
|
|
544
|
+
stats = lstatSync.call(this, path);
|
|
545
545
|
}
|
|
546
546
|
catch (error) {
|
|
547
547
|
if (error.code != 'ENOENT' || !options?.force)
|
|
@@ -583,7 +583,6 @@ mkdtempSync;
|
|
|
583
583
|
* When the object is disposed, the directory and its contents will be removed if it still exists.
|
|
584
584
|
* If the directory cannot be deleted, disposal will throw an error.
|
|
585
585
|
* The object has a `remove()` method which will perform the same task.
|
|
586
|
-
* @todo Add `satisfies` and maybe change return type once @types/node adds this.
|
|
587
586
|
*/
|
|
588
587
|
export function mkdtempDisposableSync(prefix, options) {
|
|
589
588
|
const path = _tempDirName(prefix);
|
|
@@ -591,6 +590,7 @@ export function mkdtempDisposableSync(prefix, options) {
|
|
|
591
590
|
const remove = () => rmSync(path, { recursive: true, force: true });
|
|
592
591
|
return { path, remove, [Symbol.dispose]: remove };
|
|
593
592
|
}
|
|
593
|
+
mkdtempDisposableSync;
|
|
594
594
|
/**
|
|
595
595
|
* Synchronous `copyFile`. Copies a file.
|
|
596
596
|
* @param flags Optional flags for the copy operation. Currently supports these flags:
|
package/dist/polyfills.js
CHANGED
|
@@ -57,4 +57,13 @@ Uint8Array.fromHex ??=
|
|
|
57
57
|
}
|
|
58
58
|
return bytes;
|
|
59
59
|
});
|
|
60
|
+
Array.fromAsync ??=
|
|
61
|
+
(warn('Using a polyfill of Array.fromAsync'),
|
|
62
|
+
async function collectAsyncIterator(it) {
|
|
63
|
+
const results = [];
|
|
64
|
+
for await (const result of it) {
|
|
65
|
+
results.push(result);
|
|
66
|
+
}
|
|
67
|
+
return results;
|
|
68
|
+
});
|
|
60
69
|
/* node:coverage enable */
|
package/dist/utils.d.ts
CHANGED
|
@@ -3,10 +3,6 @@ import type * as fs from 'node:fs';
|
|
|
3
3
|
import type { Worker as NodeWorker } from 'node:worker_threads';
|
|
4
4
|
import { type OptionalTuple } from 'utilium';
|
|
5
5
|
import type { V_Context } from './internal/contexts.js';
|
|
6
|
-
declare global {
|
|
7
|
-
function atob(data: string): string;
|
|
8
|
-
function btoa(data: string): string;
|
|
9
|
-
}
|
|
10
6
|
/**
|
|
11
7
|
* Decodes a directory listing
|
|
12
8
|
* @hidden
|
package/dist/vfs/acl.d.ts
CHANGED
package/dist/vfs/acl.js
CHANGED
|
@@ -62,9 +62,7 @@ export var Tag;
|
|
|
62
62
|
Tag[Tag["Group"] = 8] = "Group";
|
|
63
63
|
Tag[Tag["Mask"] = 16] = "Mask";
|
|
64
64
|
Tag[Tag["Other"] = 32] = "Other";
|
|
65
|
-
/**
|
|
66
|
-
* @internal @hidden
|
|
67
|
-
*/
|
|
65
|
+
/** @internal @hidden */
|
|
68
66
|
Tag[Tag["_None"] = 0] = "_None";
|
|
69
67
|
})(Tag || (Tag = {}));
|
|
70
68
|
let Entry = (() => {
|
package/dist/vfs/async.js
CHANGED
|
@@ -80,7 +80,6 @@ export async function resolve($, path, preserveSymlinks, extra) {
|
|
|
80
80
|
that means we don't need to perform any resolution for parent directories. */
|
|
81
81
|
try {
|
|
82
82
|
const resolved = resolveMount(path, $);
|
|
83
|
-
// Stat it to make sure it exists. The vnode cache takes precedence since it may have unsynced changes
|
|
84
83
|
const stats = cacheOf(resolved.fs).get(resolved.path)?.inode ?? (await resolved.fs.stat(resolved.path));
|
|
85
84
|
if (!isSymbolicLink(stats)) {
|
|
86
85
|
return { ...resolved, fullPath: path, stats };
|
|
@@ -135,7 +134,6 @@ export async function open($, path, opt) {
|
|
|
135
134
|
throw UV('EISDIR', 'open', path);
|
|
136
135
|
// Serialize entry creation with other operations on the parent directory
|
|
137
136
|
const _ = __addDisposableResource(env_1, await lockPath(fs, parentPath, 'rw', parentStats), false);
|
|
138
|
-
// Another task may have created the file while we waited for the lock
|
|
139
137
|
stats = cacheOf(fs).get(resolved)?.inode ?? (await fs.stat(resolved).catch(() => undefined));
|
|
140
138
|
if (!stats) {
|
|
141
139
|
const { euid: uid, egid: gid } = contextOf($).credentials;
|
|
@@ -144,7 +142,6 @@ export async function open($, path, opt) {
|
|
|
144
142
|
uid: parentStats.mode & constants.S_ISUID ? parentStats.uid : uid,
|
|
145
143
|
gid: parentStats.mode & constants.S_ISGID ? parentStats.gid : gid,
|
|
146
144
|
});
|
|
147
|
-
// A new entry in the parent directory, which is a 'rename' event
|
|
148
145
|
emitChange($, 'rename', path);
|
|
149
146
|
return new Handle($, path, resolved, flag, cacheOf(fs).ref(resolved, inode));
|
|
150
147
|
}
|
|
@@ -239,7 +236,6 @@ export async function mkdir(path, options = {}) {
|
|
|
239
236
|
}
|
|
240
237
|
export async function readdir(path, options = {}) {
|
|
241
238
|
path = normalizePath.call(this, path);
|
|
242
|
-
// Node reports `readdir` failures as `scandir`
|
|
243
239
|
const $ex = { syscall: 'scandir', path };
|
|
244
240
|
const { fs, path: resolved, stats } = await resolve(this, path, false, $ex);
|
|
245
241
|
if (!stats)
|
|
@@ -329,7 +325,6 @@ export async function rename(oldPath, newPath) {
|
|
|
329
325
|
const _second = __addDisposableResource(env_4, oldParent.ino == newParent.ino ? null : await lockPath(fs, parents[1][0], 'rw', parents[1][1]), false);
|
|
330
326
|
await src.fs.rename(src.path, dst.path);
|
|
331
327
|
cacheOf(fs).rename(src.path, dst.path);
|
|
332
|
-
// Both names change which entries exist, so both are 'rename' events
|
|
333
328
|
emitChange(this, 'rename', oldPath);
|
|
334
329
|
emitChange(this, 'rename', newPath);
|
|
335
330
|
}
|
package/dist/vfs/dir.d.ts
CHANGED
|
@@ -22,6 +22,9 @@ export declare function ifToDt(mode: number): DirType;
|
|
|
22
22
|
* @see `DTTOIF` in `dirent.h`
|
|
23
23
|
*/
|
|
24
24
|
export declare function dtToIf(dt: DirType): number;
|
|
25
|
+
/**
|
|
26
|
+
* @todo [breaking] change this to an interface
|
|
27
|
+
*/
|
|
25
28
|
export declare class Dirent {
|
|
26
29
|
ino: number;
|
|
27
30
|
type: DirType;
|
package/dist/vfs/dir.js
CHANGED
|
@@ -19,7 +19,7 @@ export var DirType;
|
|
|
19
19
|
* @see `IFTODT` in `dirent.h`
|
|
20
20
|
*/
|
|
21
21
|
export function ifToDt(mode) {
|
|
22
|
-
return (
|
|
22
|
+
return (mode & 0o170000) >> 12;
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
25
|
* Converts a directory type to a file mode.
|
|
@@ -28,6 +28,9 @@ export function ifToDt(mode) {
|
|
|
28
28
|
export function dtToIf(dt) {
|
|
29
29
|
return dt << 12;
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* @todo [breaking] change this to an interface
|
|
33
|
+
*/
|
|
31
34
|
export class Dirent {
|
|
32
35
|
ino;
|
|
33
36
|
type;
|
package/dist/vfs/file.d.ts
CHANGED
|
@@ -3,11 +3,6 @@ import type { FileSystem, StreamOptions } from '../internal/filesystem.js';
|
|
|
3
3
|
import { type InodeLike } from '../internal/inode.js';
|
|
4
4
|
import '../polyfills.js';
|
|
5
5
|
import type { VNode } from './vnode.js';
|
|
6
|
-
/** @hidden */
|
|
7
|
-
export interface FileReadResult<T extends ArrayBufferView> {
|
|
8
|
-
bytesRead: number;
|
|
9
|
-
buffer: T;
|
|
10
|
-
}
|
|
11
6
|
/**
|
|
12
7
|
* @internal
|
|
13
8
|
*/
|
|
@@ -17,9 +12,7 @@ export declare class Handle {
|
|
|
17
12
|
readonly internalPath: string;
|
|
18
13
|
readonly flag: number;
|
|
19
14
|
readonly vnode: VNode;
|
|
20
|
-
/**
|
|
21
|
-
* Current position
|
|
22
|
-
*/
|
|
15
|
+
/** Current position */
|
|
23
16
|
protected _position: number;
|
|
24
17
|
/**
|
|
25
18
|
* Get the current file position.
|
package/dist/vfs/file.js
CHANGED
package/dist/vfs/sync.js
CHANGED
package/dist/vfs/vcache.js
CHANGED
package/dist/vfs/xattr.d.ts
CHANGED
|
@@ -44,6 +44,8 @@ export interface SetOptions extends Options {
|
|
|
44
44
|
*/
|
|
45
45
|
replace?: boolean;
|
|
46
46
|
}
|
|
47
|
+
/** Attributes outside the `user` namespace that are supported. */
|
|
48
|
+
export declare const allowedRestrictedNames: Set<`user.${string}` | `trusted.${string}` | `system.${string}` | `security.${string}`>;
|
|
47
49
|
/**
|
|
48
50
|
* Gets the value of an extended attribute.
|
|
49
51
|
*
|
package/dist/vfs/xattr.js
CHANGED
|
@@ -6,14 +6,15 @@ import { normalizePath } from '../utils.js';
|
|
|
6
6
|
import { checkAccess } from './config.js';
|
|
7
7
|
import { R_OK, W_OK } from '../constants.js';
|
|
8
8
|
import { resolveMount } from './shared.js';
|
|
9
|
-
|
|
9
|
+
/** Attributes outside the `user` namespace that are supported. */
|
|
10
|
+
export const allowedRestrictedNames = new Set();
|
|
10
11
|
/**
|
|
11
12
|
* Check permission for the attribute name.
|
|
12
|
-
*
|
|
13
|
-
* @throws ENOTSUP for
|
|
13
|
+
* Only the 'user' namespace and whatever is in {@link allowedRestrictedNames} are supported.
|
|
14
|
+
* @throws ENOTSUP for any other attribute
|
|
14
15
|
*/
|
|
15
16
|
function checkName($, name, path, syscall) {
|
|
16
|
-
if (!name.startsWith('user.') && !
|
|
17
|
+
if (!name.startsWith('user.') && !allowedRestrictedNames.has(name))
|
|
17
18
|
throw UV('ENOTSUP', syscall, path);
|
|
18
19
|
}
|
|
19
20
|
export async function get(path, name, opt = {}) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenfs/core",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.6",
|
|
4
4
|
"description": "A filesystem, anywhere",
|
|
5
5
|
"funding": {
|
|
6
6
|
"type": "individual",
|
|
@@ -23,7 +23,6 @@
|
|
|
23
23
|
"files": [
|
|
24
24
|
"dist",
|
|
25
25
|
"tests",
|
|
26
|
-
"types",
|
|
27
26
|
"license.md",
|
|
28
27
|
"eslint.shared.js"
|
|
29
28
|
],
|
|
@@ -93,7 +92,7 @@
|
|
|
93
92
|
"typedoc": "^0.28.18",
|
|
94
93
|
"typescript": "^6.0.0",
|
|
95
94
|
"typescript-eslint": "^8.58.0",
|
|
96
|
-
"zbench-js": "^0.
|
|
95
|
+
"zbench-js": "^0.2.0"
|
|
97
96
|
},
|
|
98
97
|
"prettier": {
|
|
99
98
|
"singleQuote": true,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
|
-
import { bindContext, configure, fs, InMemory
|
|
2
|
+
import { bindContext, configure, fs, InMemory } from '@zenfs/core';
|
|
3
3
|
import assert from 'node:assert/strict';
|
|
4
4
|
import { suite, test } from 'node:test';
|
|
5
5
|
import { canary } from 'utilium';
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
|
-
import { InMemoryStore, Mutexed, StoreFS } from '@zenfs/core';
|
|
3
|
-
import assert from 'node:assert/strict';
|
|
4
|
-
import { suite, test } from 'node:test';
|
|
5
|
-
import { wait } from 'utilium';
|
|
6
|
-
|
|
7
|
-
suite('Mutexed FS', () => {
|
|
8
|
-
const fs = new (Mutexed(StoreFS))(new InMemoryStore(0x10000, 'test'));
|
|
9
|
-
fs._fs.checkRootSync();
|
|
10
|
-
|
|
11
|
-
test('lock/unlock', () => {
|
|
12
|
-
const lock = fs.lockSync();
|
|
13
|
-
assert(fs.isLocked);
|
|
14
|
-
lock.unlock();
|
|
15
|
-
assert(!fs.isLocked);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
test('queueing multiple locks', async () => {
|
|
19
|
-
let lock1Resolved = false;
|
|
20
|
-
let lock2Resolved = false;
|
|
21
|
-
|
|
22
|
-
const lock1 = fs.lock(100).then(lock => {
|
|
23
|
-
lock1Resolved = true;
|
|
24
|
-
lock.unlock();
|
|
25
|
-
});
|
|
26
|
-
const lock2 = fs.lock(100).then(lock => {
|
|
27
|
-
lock2Resolved = true;
|
|
28
|
-
lock.unlock();
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
// Both locks are queued, so neither should be resolved initially
|
|
32
|
-
assert(!lock1Resolved);
|
|
33
|
-
assert(!lock2Resolved);
|
|
34
|
-
|
|
35
|
-
// Wait for the first lock to be resolved
|
|
36
|
-
await lock1;
|
|
37
|
-
|
|
38
|
-
assert(lock1Resolved);
|
|
39
|
-
assert(!lock2Resolved);
|
|
40
|
-
|
|
41
|
-
// Wait for the second lock to be resolved
|
|
42
|
-
await lock2;
|
|
43
|
-
|
|
44
|
-
assert(lock1Resolved);
|
|
45
|
-
assert(lock2Resolved);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('test race conditions', async () => {
|
|
49
|
-
let x = 1;
|
|
50
|
-
|
|
51
|
-
async function foo() {
|
|
52
|
-
const lock = await fs.lock(100);
|
|
53
|
-
await wait(25);
|
|
54
|
-
x++;
|
|
55
|
-
lock.unlock();
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
await Promise.all([foo(), foo(), foo()]);
|
|
59
|
-
assert.equal(x, 4);
|
|
60
|
-
});
|
|
61
|
-
});
|