@zenfs/core 2.3.1 → 2.3.3
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/single_buffer.js +1 -1
- package/dist/internal/inode.js +1 -1
- package/dist/vfs/dir.d.ts +48 -5
- package/dist/vfs/dir.js +177 -39
- package/dist/vfs/ioctl.js +1 -1
- package/dist/vfs/promises.d.ts +7 -9
- package/dist/vfs/promises.js +31 -35
- package/dist/vfs/sync.js +19 -23
- package/package.json +1 -1
- package/scripts/test.js +10 -9
- package/tests/fs/dir.test.ts +6 -6
- package/tests/fs/directory.test.ts +7 -4
- package/tests/fs/links.test.ts +10 -0
- package/tests/fs/read.test.ts +24 -1
|
@@ -102,7 +102,7 @@ const { format } = new Intl.NumberFormat('en-US', {
|
|
|
102
102
|
});
|
|
103
103
|
let MetadataEntry = (() => {
|
|
104
104
|
var _a, _b, _c, _d;
|
|
105
|
-
let _classDecorators = [struct(packed)];
|
|
105
|
+
let _classDecorators = [struct(packed, { name: 'MetadataEntry' })];
|
|
106
106
|
let _classDescriptor;
|
|
107
107
|
let _classExtraInitializers = [];
|
|
108
108
|
let _classThis;
|
package/dist/internal/inode.js
CHANGED
|
@@ -49,7 +49,7 @@ export const rootIno = 0;
|
|
|
49
49
|
const maxDynamicData = 3968;
|
|
50
50
|
let Attribute = (() => {
|
|
51
51
|
var _a, _b;
|
|
52
|
-
let _classDecorators = [struct(packed)];
|
|
52
|
+
let _classDecorators = [struct(packed, { name: 'Attribute' })];
|
|
53
53
|
let _classDescriptor;
|
|
54
54
|
let _classExtraInitializers = [];
|
|
55
55
|
let _classThis;
|
package/dist/vfs/dir.d.ts
CHANGED
|
@@ -2,13 +2,56 @@ import type { Dir as _Dir, Dirent as _Dirent } from 'node:fs';
|
|
|
2
2
|
import type { V_Context } from '../context.js';
|
|
3
3
|
import type { InodeLike } from '../internal/inode.js';
|
|
4
4
|
import type { Callback } from '../utils.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
import { Buffer } from 'buffer';
|
|
6
|
+
import { BufferView } from 'utilium/buffer.js';
|
|
7
|
+
/**
|
|
8
|
+
* @see `DT_*` in `dirent.h`
|
|
9
|
+
*/
|
|
10
|
+
export declare enum DirType {
|
|
11
|
+
UNKNOWN = 0,
|
|
12
|
+
FIFO = 1,
|
|
13
|
+
CHR = 2,
|
|
14
|
+
DIR = 4,
|
|
15
|
+
BLK = 6,
|
|
16
|
+
REG = 8,
|
|
17
|
+
LNK = 10,
|
|
18
|
+
SOCK = 12,
|
|
19
|
+
WHT = 14
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Converts a file mode to a directory type.
|
|
23
|
+
* @see `IFTODT` in `dirent.h`
|
|
24
|
+
*/
|
|
25
|
+
export declare function ifToDt(mode: number): DirType;
|
|
26
|
+
/**
|
|
27
|
+
* Converts a directory type to a file mode.
|
|
28
|
+
* @see `DTTOIF` in `dirent.h`
|
|
29
|
+
*/
|
|
30
|
+
export declare function dtToIf(dt: DirType): number;
|
|
31
|
+
export declare class Dirent<Name extends string | Buffer = string, TArrayBuffer extends ArrayBufferLike = ArrayBufferLike> extends BufferView<TArrayBuffer> implements _Dirent<Name> {
|
|
32
|
+
protected accessor ino: number;
|
|
33
|
+
/** Reserved for 64-bit inodes */
|
|
34
|
+
private accessor _ino;
|
|
35
|
+
protected accessor type: DirType;
|
|
36
|
+
protected accessor _name: Uint8Array;
|
|
9
37
|
get name(): Name;
|
|
10
|
-
|
|
38
|
+
/**
|
|
39
|
+
* @internal @protected
|
|
40
|
+
*/
|
|
41
|
+
_encoding?: BufferEncoding | 'buffer' | null;
|
|
42
|
+
/**
|
|
43
|
+
* @internal @protected
|
|
44
|
+
*/
|
|
45
|
+
_parentPath: string;
|
|
11
46
|
get parentPath(): string;
|
|
47
|
+
/**
|
|
48
|
+
* @deprecated Removed in Node v24, use `parentPath` instead.
|
|
49
|
+
*/
|
|
50
|
+
get path(): string;
|
|
51
|
+
/**
|
|
52
|
+
* @internal
|
|
53
|
+
*/
|
|
54
|
+
static from(path: string, stats: InodeLike, encoding?: BufferEncoding | 'buffer' | null): Dirent;
|
|
12
55
|
isFile(): boolean;
|
|
13
56
|
isDirectory(): boolean;
|
|
14
57
|
isBlockDevice(): boolean;
|
package/dist/vfs/dir.js
CHANGED
|
@@ -1,46 +1,184 @@
|
|
|
1
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
2
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
3
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
4
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
5
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
6
|
+
var _, done = false;
|
|
7
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
8
|
+
var context = {};
|
|
9
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
10
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
11
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
12
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
13
|
+
if (kind === "accessor") {
|
|
14
|
+
if (result === void 0) continue;
|
|
15
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
16
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
17
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
18
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
19
|
+
}
|
|
20
|
+
else if (_ = accept(result)) {
|
|
21
|
+
if (kind === "field") initializers.unshift(_);
|
|
22
|
+
else descriptor[key] = _;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
26
|
+
done = true;
|
|
27
|
+
};
|
|
28
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
29
|
+
var useValue = arguments.length > 2;
|
|
30
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
31
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
32
|
+
}
|
|
33
|
+
return useValue ? value : void 0;
|
|
34
|
+
};
|
|
35
|
+
import { Buffer } from 'buffer';
|
|
1
36
|
import { withErrno } from 'kerium';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
37
|
+
import { packed, sizeof, struct, types as t } from 'memium';
|
|
38
|
+
import { warn } from 'kerium/log';
|
|
39
|
+
import { encodeUTF8 } from 'utilium';
|
|
40
|
+
import { BufferView } from 'utilium/buffer.js';
|
|
41
|
+
import { basename, dirname } from '../path.js';
|
|
4
42
|
import { readdir } from './promises.js';
|
|
5
43
|
import { readdirSync } from './sync.js';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
isSymbolicLink() {
|
|
35
|
-
return isSymbolicLink(this.stats);
|
|
36
|
-
}
|
|
37
|
-
isFIFO() {
|
|
38
|
-
return isFIFO(this.stats);
|
|
39
|
-
}
|
|
40
|
-
isSocket() {
|
|
41
|
-
return isSocket(this.stats);
|
|
42
|
-
}
|
|
44
|
+
/**
|
|
45
|
+
* @see `DT_*` in `dirent.h`
|
|
46
|
+
*/
|
|
47
|
+
export var DirType;
|
|
48
|
+
(function (DirType) {
|
|
49
|
+
DirType[DirType["UNKNOWN"] = 0] = "UNKNOWN";
|
|
50
|
+
DirType[DirType["FIFO"] = 1] = "FIFO";
|
|
51
|
+
DirType[DirType["CHR"] = 2] = "CHR";
|
|
52
|
+
DirType[DirType["DIR"] = 4] = "DIR";
|
|
53
|
+
DirType[DirType["BLK"] = 6] = "BLK";
|
|
54
|
+
DirType[DirType["REG"] = 8] = "REG";
|
|
55
|
+
DirType[DirType["LNK"] = 10] = "LNK";
|
|
56
|
+
DirType[DirType["SOCK"] = 12] = "SOCK";
|
|
57
|
+
DirType[DirType["WHT"] = 14] = "WHT";
|
|
58
|
+
})(DirType || (DirType = {}));
|
|
59
|
+
/**
|
|
60
|
+
* Converts a file mode to a directory type.
|
|
61
|
+
* @see `IFTODT` in `dirent.h`
|
|
62
|
+
*/
|
|
63
|
+
export function ifToDt(mode) {
|
|
64
|
+
return ((mode & 0o170000) >> 12);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Converts a directory type to a file mode.
|
|
68
|
+
* @see `DTTOIF` in `dirent.h`
|
|
69
|
+
*/
|
|
70
|
+
export function dtToIf(dt) {
|
|
71
|
+
return dt << 12;
|
|
43
72
|
}
|
|
73
|
+
let Dirent = (() => {
|
|
74
|
+
var _a, _b, _c;
|
|
75
|
+
let _classDecorators = [struct(packed, { name: 'Dirent' })];
|
|
76
|
+
let _classDescriptor;
|
|
77
|
+
let _classExtraInitializers = [];
|
|
78
|
+
let _classThis;
|
|
79
|
+
let _classSuper = BufferView;
|
|
80
|
+
let _ino_decorators;
|
|
81
|
+
let _ino_initializers = [];
|
|
82
|
+
let _ino_extraInitializers = [];
|
|
83
|
+
let __ino_decorators;
|
|
84
|
+
let __ino_initializers = [];
|
|
85
|
+
let __ino_extraInitializers = [];
|
|
86
|
+
let _type_decorators;
|
|
87
|
+
let _type_initializers = [];
|
|
88
|
+
let _type_extraInitializers = [];
|
|
89
|
+
let __name_decorators;
|
|
90
|
+
let __name_initializers = [];
|
|
91
|
+
let __name_extraInitializers = [];
|
|
92
|
+
var Dirent = class extends _classSuper {
|
|
93
|
+
static { _classThis = this; }
|
|
94
|
+
static {
|
|
95
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
96
|
+
_ino_decorators = [(_a = t).uint32.bind(_a)];
|
|
97
|
+
__ino_decorators = [(_b = t).uint32.bind(_b)];
|
|
98
|
+
_type_decorators = [(_c = t).uint8.bind(_c)];
|
|
99
|
+
__name_decorators = [t.char(256)];
|
|
100
|
+
__esDecorate(this, null, _ino_decorators, { kind: "accessor", name: "ino", static: false, private: false, access: { has: obj => "ino" in obj, get: obj => obj.ino, set: (obj, value) => { obj.ino = value; } }, metadata: _metadata }, _ino_initializers, _ino_extraInitializers);
|
|
101
|
+
__esDecorate(this, null, __ino_decorators, { kind: "accessor", name: "_ino", static: false, private: false, access: { has: obj => "_ino" in obj, get: obj => obj._ino, set: (obj, value) => { obj._ino = value; } }, metadata: _metadata }, __ino_initializers, __ino_extraInitializers);
|
|
102
|
+
__esDecorate(this, null, _type_decorators, { kind: "accessor", name: "type", static: false, private: false, access: { has: obj => "type" in obj, get: obj => obj.type, set: (obj, value) => { obj.type = value; } }, metadata: _metadata }, _type_initializers, _type_extraInitializers);
|
|
103
|
+
__esDecorate(this, null, __name_decorators, { kind: "accessor", name: "_name", static: false, private: false, access: { has: obj => "_name" in obj, get: obj => obj._name, set: (obj, value) => { obj._name = value; } }, metadata: _metadata }, __name_initializers, __name_extraInitializers);
|
|
104
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
105
|
+
Dirent = _classThis = _classDescriptor.value;
|
|
106
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
107
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
108
|
+
}
|
|
109
|
+
#ino_accessor_storage = __runInitializers(this, _ino_initializers, void 0);
|
|
110
|
+
get ino() { return this.#ino_accessor_storage; }
|
|
111
|
+
set ino(value) { this.#ino_accessor_storage = value; }
|
|
112
|
+
#_ino_accessor_storage = (__runInitializers(this, _ino_extraInitializers), __runInitializers(this, __ino_initializers, void 0));
|
|
113
|
+
/** Reserved for 64-bit inodes */
|
|
114
|
+
get _ino() { return this.#_ino_accessor_storage; }
|
|
115
|
+
set _ino(value) { this.#_ino_accessor_storage = value; }
|
|
116
|
+
#type_accessor_storage = (__runInitializers(this, __ino_extraInitializers), __runInitializers(this, _type_initializers, void 0));
|
|
117
|
+
get type() { return this.#type_accessor_storage; }
|
|
118
|
+
set type(value) { this.#type_accessor_storage = value; }
|
|
119
|
+
#_name_accessor_storage = (__runInitializers(this, _type_extraInitializers), __runInitializers(this, __name_initializers, void 0));
|
|
120
|
+
get _name() { return this.#_name_accessor_storage; }
|
|
121
|
+
set _name(value) { this.#_name_accessor_storage = value; }
|
|
122
|
+
get name() {
|
|
123
|
+
const end = (this._name.indexOf(0) + 1 || 256) - 1;
|
|
124
|
+
const name = Buffer.from(this._name.subarray(0, end));
|
|
125
|
+
return (this._encoding == 'buffer' ? name : name.toString(this._encoding));
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* @internal @protected
|
|
129
|
+
*/
|
|
130
|
+
_encoding = __runInitializers(this, __name_extraInitializers);
|
|
131
|
+
/**
|
|
132
|
+
* @internal @protected
|
|
133
|
+
*/
|
|
134
|
+
_parentPath;
|
|
135
|
+
get parentPath() {
|
|
136
|
+
return this._parentPath;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* @deprecated Removed in Node v24, use `parentPath` instead.
|
|
140
|
+
*/
|
|
141
|
+
get path() {
|
|
142
|
+
warn('Dirent.path was removed in Node v24, use parentPath instead');
|
|
143
|
+
return this._parentPath;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* @internal
|
|
147
|
+
*/
|
|
148
|
+
static from(path, stats, encoding) {
|
|
149
|
+
const dirent = new Dirent(new ArrayBuffer(sizeof(Dirent) + 1));
|
|
150
|
+
dirent._parentPath = dirname(path);
|
|
151
|
+
dirent._name = encodeUTF8(basename(path));
|
|
152
|
+
dirent.ino = stats.ino;
|
|
153
|
+
dirent.type = ifToDt(stats.mode);
|
|
154
|
+
dirent._encoding = encoding;
|
|
155
|
+
return dirent;
|
|
156
|
+
}
|
|
157
|
+
isFile() {
|
|
158
|
+
return this.type === DirType.REG;
|
|
159
|
+
}
|
|
160
|
+
isDirectory() {
|
|
161
|
+
return this.type === DirType.DIR;
|
|
162
|
+
}
|
|
163
|
+
isBlockDevice() {
|
|
164
|
+
return this.type === DirType.BLK;
|
|
165
|
+
}
|
|
166
|
+
isCharacterDevice() {
|
|
167
|
+
return this.type === DirType.CHR;
|
|
168
|
+
}
|
|
169
|
+
isSymbolicLink() {
|
|
170
|
+
return this.type === DirType.LNK;
|
|
171
|
+
}
|
|
172
|
+
isFIFO() {
|
|
173
|
+
return this.type === DirType.FIFO;
|
|
174
|
+
}
|
|
175
|
+
isSocket() {
|
|
176
|
+
return this.type === DirType.SOCK;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
return Dirent = _classThis;
|
|
180
|
+
})();
|
|
181
|
+
export { Dirent };
|
|
44
182
|
/**
|
|
45
183
|
* A class representing a directory stream.
|
|
46
184
|
*/
|
package/dist/vfs/ioctl.js
CHANGED
|
@@ -87,7 +87,7 @@ var XFlag;
|
|
|
87
87
|
})(XFlag || (XFlag = {}));
|
|
88
88
|
let fsxattr = (() => {
|
|
89
89
|
var _a, _b, _c, _d, _e;
|
|
90
|
-
let _classDecorators = [struct()];
|
|
90
|
+
let _classDecorators = [struct({ name: 'fsxattr' })];
|
|
91
91
|
let _classDescriptor;
|
|
92
92
|
let _classExtraInitializers = [];
|
|
93
93
|
let _classThis;
|
package/dist/vfs/promises.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type { FileContents, ReaddirOptions } from './types.js';
|
|
|
11
11
|
import { Buffer } from 'buffer';
|
|
12
12
|
import '../polyfills.js';
|
|
13
13
|
import { Dir, Dirent } from './dir.js';
|
|
14
|
+
import { SyncHandle } from './file.js';
|
|
14
15
|
import { BigIntStats, Stats } from './stats.js';
|
|
15
16
|
import { ReadStream, WriteStream } from './streams.js';
|
|
16
17
|
export * as constants from './constants.js';
|
|
@@ -18,10 +19,6 @@ export declare class FileHandle implements promises.FileHandle {
|
|
|
18
19
|
protected context: V_Context;
|
|
19
20
|
readonly fd: number;
|
|
20
21
|
protected _buffer?: Uint8Array;
|
|
21
|
-
/**
|
|
22
|
-
* Current position
|
|
23
|
-
*/
|
|
24
|
-
protected _position: number;
|
|
25
22
|
/**
|
|
26
23
|
* Get the current file position.
|
|
27
24
|
*
|
|
@@ -42,15 +39,16 @@ export declare class FileHandle implements promises.FileHandle {
|
|
|
42
39
|
*/
|
|
43
40
|
protected closed: boolean;
|
|
44
41
|
/** The path relative to the context's root */
|
|
45
|
-
|
|
42
|
+
get path(): string;
|
|
46
43
|
/** The internal FS associated with the handle */
|
|
47
|
-
protected
|
|
44
|
+
protected get fs(): FileSystem;
|
|
48
45
|
/** The path relative to the `FileSystem`'s root */
|
|
49
|
-
|
|
46
|
+
get internalPath(): string;
|
|
50
47
|
/** The flag the handle was opened with */
|
|
51
|
-
|
|
48
|
+
get flag(): number;
|
|
52
49
|
/** Stats for the handle */
|
|
53
|
-
|
|
50
|
+
get inode(): InodeLike;
|
|
51
|
+
protected _sync: SyncHandle;
|
|
54
52
|
constructor(context: V_Context, fd: number);
|
|
55
53
|
private get _isSync();
|
|
56
54
|
private _emitChange;
|
package/dist/vfs/promises.js
CHANGED
|
@@ -52,10 +52,9 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
52
52
|
});
|
|
53
53
|
import { Buffer } from 'buffer';
|
|
54
54
|
import { Exception, rethrow, setUVMessage, UV } from 'kerium';
|
|
55
|
-
import { decodeUTF8, pick } from 'utilium';
|
|
56
55
|
import { defaultContext } from '../internal/contexts.js';
|
|
57
56
|
import { hasAccess, InodeFlags, isBlockDevice, isCharacterDevice, isDirectory, isSymbolicLink } from '../internal/inode.js';
|
|
58
|
-
import { dirname, join, matchesGlob, parse, resolve } from '../path.js';
|
|
57
|
+
import { basename, dirname, join, matchesGlob, parse, resolve } from '../path.js';
|
|
59
58
|
import '../polyfills.js';
|
|
60
59
|
import { createInterface } from '../readline.js';
|
|
61
60
|
import { __assertType, globToRegex, normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '../utils.js';
|
|
@@ -73,10 +72,6 @@ export class FileHandle {
|
|
|
73
72
|
context;
|
|
74
73
|
fd;
|
|
75
74
|
_buffer;
|
|
76
|
-
/**
|
|
77
|
-
* Current position
|
|
78
|
-
*/
|
|
79
|
-
_position = 0;
|
|
80
75
|
/**
|
|
81
76
|
* Get the current file position.
|
|
82
77
|
*
|
|
@@ -87,10 +82,10 @@ export class FileHandle {
|
|
|
87
82
|
* @returns The current file position.
|
|
88
83
|
*/
|
|
89
84
|
get position() {
|
|
90
|
-
return this.
|
|
85
|
+
return this._sync.position;
|
|
91
86
|
}
|
|
92
87
|
set position(value) {
|
|
93
|
-
this.
|
|
88
|
+
this._sync.position = value;
|
|
94
89
|
}
|
|
95
90
|
/**
|
|
96
91
|
* Whether the file has changes which have not been written to the FS
|
|
@@ -101,20 +96,30 @@ export class FileHandle {
|
|
|
101
96
|
*/
|
|
102
97
|
closed = false;
|
|
103
98
|
/** The path relative to the context's root */
|
|
104
|
-
path
|
|
99
|
+
get path() {
|
|
100
|
+
return this._sync.path;
|
|
101
|
+
}
|
|
105
102
|
/** The internal FS associated with the handle */
|
|
106
|
-
fs
|
|
103
|
+
get fs() {
|
|
104
|
+
return this._sync.fs;
|
|
105
|
+
}
|
|
107
106
|
/** The path relative to the `FileSystem`'s root */
|
|
108
|
-
internalPath
|
|
107
|
+
get internalPath() {
|
|
108
|
+
return this._sync.internalPath;
|
|
109
|
+
}
|
|
109
110
|
/** The flag the handle was opened with */
|
|
110
|
-
flag
|
|
111
|
+
get flag() {
|
|
112
|
+
return this._sync.flag;
|
|
113
|
+
}
|
|
111
114
|
/** Stats for the handle */
|
|
112
|
-
inode
|
|
115
|
+
get inode() {
|
|
116
|
+
return this._sync.inode;
|
|
117
|
+
}
|
|
118
|
+
_sync;
|
|
113
119
|
constructor(context, fd) {
|
|
114
120
|
this.context = context;
|
|
115
121
|
this.fd = fd;
|
|
116
|
-
|
|
117
|
-
Object.assign(this, pick(sync, 'path', 'fs', 'internalPath', 'flag', 'inode'));
|
|
122
|
+
this._sync = fromFD(context, fd);
|
|
118
123
|
}
|
|
119
124
|
get _isSync() {
|
|
120
125
|
return !!(this.flag & constants.O_SYNC || this.inode.flags & InodeFlags.Sync);
|
|
@@ -246,7 +251,7 @@ export class FileHandle {
|
|
|
246
251
|
if (!isCharacterDevice(this.inode) && !isBlockDevice(this.inode) && end > this.inode.size) {
|
|
247
252
|
end = position + Math.max(this.inode.size - position, 0);
|
|
248
253
|
}
|
|
249
|
-
this.
|
|
254
|
+
this._sync.position = end;
|
|
250
255
|
const uint8 = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
251
256
|
await this.fs.read(this.internalPath, uint8.subarray(offset, offset + length), position, end);
|
|
252
257
|
if (this._isSync)
|
|
@@ -348,7 +353,7 @@ export class FileHandle {
|
|
|
348
353
|
this.inode.size = end;
|
|
349
354
|
this.inode.mtimeMs = Date.now();
|
|
350
355
|
this.inode.ctimeMs = Date.now();
|
|
351
|
-
this.
|
|
356
|
+
this._sync.position = position + slice.byteLength;
|
|
352
357
|
await this.fs.write(this.internalPath, slice, position);
|
|
353
358
|
if (this._isSync)
|
|
354
359
|
await this.sync();
|
|
@@ -534,8 +539,9 @@ export async function stat(path, options) {
|
|
|
534
539
|
stat;
|
|
535
540
|
export async function lstat(path, options) {
|
|
536
541
|
path = normalizePath(path);
|
|
537
|
-
const { fs, path: resolved } = resolveMount(path, this);
|
|
538
542
|
const $ex = { syscall: 'lstat', path };
|
|
543
|
+
path = join(await realpath.call(this, dirname(path)), basename(path));
|
|
544
|
+
const { fs, path: resolved } = resolveMount(path, this);
|
|
539
545
|
const stats = await fs.stat(resolved).catch(rethrow($ex));
|
|
540
546
|
if (checkAccess && !hasAccess(this, stats, constants.R_OK))
|
|
541
547
|
throw UV('EACCES', $ex);
|
|
@@ -747,9 +753,9 @@ export async function mkdir(path, options) {
|
|
|
747
753
|
return dirs[0][0];
|
|
748
754
|
}
|
|
749
755
|
mkdir;
|
|
750
|
-
export async function readdir(
|
|
756
|
+
export async function readdir(_path, options) {
|
|
751
757
|
const opt = typeof options === 'object' && options != null ? options : { encoding: options, withFileTypes: false, recursive: false };
|
|
752
|
-
path = await realpath.call(this,
|
|
758
|
+
const path = await realpath.call(this, _path);
|
|
753
759
|
const { fs, path: resolved } = resolveMount(path, this);
|
|
754
760
|
const $ex = { syscall: 'readdir', path };
|
|
755
761
|
const stats = await fs.stat(resolved).catch(rethrow({ syscall: 'stat', path }));
|
|
@@ -773,7 +779,7 @@ export async function readdir(path, options) {
|
|
|
773
779
|
return;
|
|
774
780
|
}
|
|
775
781
|
if (opt.withFileTypes) {
|
|
776
|
-
values.push(
|
|
782
|
+
values.push(Dirent.from(join(_path.toString(), entry), entryStats, opt.encoding));
|
|
777
783
|
}
|
|
778
784
|
else if (opt.encoding == 'buffer') {
|
|
779
785
|
values.push(Buffer.from(entry));
|
|
@@ -783,19 +789,9 @@ export async function readdir(path, options) {
|
|
|
783
789
|
}
|
|
784
790
|
if (!opt.recursive || !isDirectory(entryStats))
|
|
785
791
|
return;
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
values.push(subEntry);
|
|
790
|
-
}
|
|
791
|
-
else if (Buffer.isBuffer(subEntry)) {
|
|
792
|
-
// Convert Buffer to string, prefix with the full path
|
|
793
|
-
values.push(Buffer.from(join(entry, decodeUTF8(subEntry))));
|
|
794
|
-
}
|
|
795
|
-
else {
|
|
796
|
-
values.push(join(entry, subEntry));
|
|
797
|
-
}
|
|
798
|
-
}
|
|
792
|
+
const children = await fs.readdir(join(resolved, entry)).catch(rethrow({ syscall: 'readdir', path: join(path, entry) }));
|
|
793
|
+
for (const child of children)
|
|
794
|
+
await addEntry(join(entry, child));
|
|
799
795
|
};
|
|
800
796
|
await Promise.all(entries.map(addEntry));
|
|
801
797
|
return values;
|
|
@@ -1232,7 +1228,7 @@ export function glob(pattern, opt) {
|
|
|
1232
1228
|
async function* recursiveList(dir) {
|
|
1233
1229
|
const entries = await readdir(dir, { withFileTypes, encoding: 'utf8' });
|
|
1234
1230
|
for (const entry of entries) {
|
|
1235
|
-
const fullPath = withFileTypes ? entry.
|
|
1231
|
+
const fullPath = withFileTypes ? join(entry.parentPath, entry.name) : dir + '/' + entry;
|
|
1236
1232
|
if (typeof exclude != 'function' ? exclude.some(p => matchesGlob(p, fullPath)) : exclude((withFileTypes ? entry : fullPath)))
|
|
1237
1233
|
continue;
|
|
1238
1234
|
/**
|
package/dist/vfs/sync.js
CHANGED
|
@@ -52,11 +52,11 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
52
52
|
});
|
|
53
53
|
import { Buffer } from 'buffer';
|
|
54
54
|
import { Errno, Exception, setUVMessage, UV } from 'kerium';
|
|
55
|
-
import {
|
|
55
|
+
import { encodeUTF8 } from 'utilium';
|
|
56
56
|
import { defaultContext } from '../internal/contexts.js';
|
|
57
57
|
import { wrap } from '../internal/error.js';
|
|
58
58
|
import { hasAccess, isDirectory, isSymbolicLink } from '../internal/inode.js';
|
|
59
|
-
import { dirname, join, matchesGlob, parse, resolve } from '../path.js';
|
|
59
|
+
import { basename, dirname, join, matchesGlob, parse, resolve } from '../path.js';
|
|
60
60
|
import { __assertType, globToRegex, normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '../utils.js';
|
|
61
61
|
import { checkAccess } from './config.js';
|
|
62
62
|
import * as constants from './constants.js';
|
|
@@ -139,7 +139,8 @@ export function statSync(path, options) {
|
|
|
139
139
|
statSync;
|
|
140
140
|
export function lstatSync(path, options) {
|
|
141
141
|
path = normalizePath(path);
|
|
142
|
-
const
|
|
142
|
+
const real = join(realpathSync.call(this, dirname(path)), basename(path));
|
|
143
|
+
const { fs, path: resolved } = resolveMount(real, this);
|
|
143
144
|
const stats = wrap(fs, 'statSync', path)(resolved);
|
|
144
145
|
if (checkAccess && !hasAccess(this, stats, constants.R_OK))
|
|
145
146
|
throw UV('EACCES', { syscall: 'lstat', path });
|
|
@@ -485,16 +486,18 @@ export function readdirSync(path, options) {
|
|
|
485
486
|
const entries = wrap(fs, 'readdirSync', path)(resolved);
|
|
486
487
|
// Iterate over entries and handle recursive case if needed
|
|
487
488
|
const values = [];
|
|
488
|
-
|
|
489
|
+
const addEntry = (entry) => {
|
|
489
490
|
let entryStat;
|
|
490
491
|
try {
|
|
491
492
|
entryStat = fs.statSync(join(resolved, entry));
|
|
492
493
|
}
|
|
493
|
-
catch {
|
|
494
|
-
|
|
494
|
+
catch (e) {
|
|
495
|
+
if (e.code == 'ENOENT')
|
|
496
|
+
return;
|
|
497
|
+
throw setUVMessage(Object.assign(e, { syscall: 'stat', path: join(path, entry) }));
|
|
495
498
|
}
|
|
496
499
|
if (options?.withFileTypes) {
|
|
497
|
-
values.push(
|
|
500
|
+
values.push(Dirent.from(entry, entryStat, options.encoding));
|
|
498
501
|
}
|
|
499
502
|
else if (options?.encoding == 'buffer') {
|
|
500
503
|
values.push(Buffer.from(entry));
|
|
@@ -503,20 +506,13 @@ export function readdirSync(path, options) {
|
|
|
503
506
|
values.push(entry);
|
|
504
507
|
}
|
|
505
508
|
if (!isDirectory(entryStat) || !options?.recursive)
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
values.push(Buffer.from(join(entry, decodeUTF8(subEntry))));
|
|
514
|
-
}
|
|
515
|
-
else {
|
|
516
|
-
values.push(join(entry, subEntry));
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
}
|
|
509
|
+
return;
|
|
510
|
+
const children = wrap(fs, 'readdirSync', join(path, entry))(join(resolved, entry));
|
|
511
|
+
for (const child of children)
|
|
512
|
+
addEntry(join(entry, child));
|
|
513
|
+
};
|
|
514
|
+
for (const entry of entries)
|
|
515
|
+
addEntry(entry);
|
|
520
516
|
return values;
|
|
521
517
|
}
|
|
522
518
|
readdirSync;
|
|
@@ -862,7 +858,7 @@ export function globSync(pattern, options = {}) {
|
|
|
862
858
|
function recursiveList(dir) {
|
|
863
859
|
const entries = readdirSync(dir, { withFileTypes, encoding: 'utf8' });
|
|
864
860
|
for (const entry of entries) {
|
|
865
|
-
const fullPath = withFileTypes ? entry.
|
|
861
|
+
const fullPath = withFileTypes ? join(entry.parentPath, entry.name) : dir + '/' + entry;
|
|
866
862
|
if (typeof exclude != 'function' ? exclude.some(p => matchesGlob(p, fullPath)) : exclude((withFileTypes ? entry : fullPath)))
|
|
867
863
|
continue;
|
|
868
864
|
/**
|
|
@@ -872,7 +868,7 @@ export function globSync(pattern, options = {}) {
|
|
|
872
868
|
recursiveList(fullPath);
|
|
873
869
|
}
|
|
874
870
|
if (regexPatterns.some(pattern => pattern.test(fullPath.replace(/^\/+/g, '')))) {
|
|
875
|
-
results.push(withFileTypes ? entry
|
|
871
|
+
results.push(withFileTypes ? entry : fullPath.replace(/^\/+/g, ''));
|
|
876
872
|
}
|
|
877
873
|
}
|
|
878
874
|
}
|
package/package.json
CHANGED
package/scripts/test.js
CHANGED
|
@@ -40,13 +40,14 @@ if (options.help) {
|
|
|
40
40
|
Paths: The setup files to run tests on
|
|
41
41
|
|
|
42
42
|
Behavior:
|
|
43
|
-
-a, --auto
|
|
44
|
-
-b, --build
|
|
45
|
-
-c, --common
|
|
46
|
-
-e, --exit-on-fail
|
|
47
|
-
-t, --test <glob>
|
|
48
|
-
-f, --force
|
|
49
|
-
-I, --inspect
|
|
43
|
+
-a, --auto Automatically detect setup files
|
|
44
|
+
-b, --build Run the npm build script prior to running tests
|
|
45
|
+
-c, --common Also run tests not specific to any backend
|
|
46
|
+
-e, --exit-on-fail If any tests suites fail, exit immediately
|
|
47
|
+
-t, --test <glob> Which FS test suite(s) to run
|
|
48
|
+
-f, --force Whether to use --test-force-exit
|
|
49
|
+
-I, --inspect Use the inspector for debugging
|
|
50
|
+
-s, --skip <pattern> Skip tests with names matching the given pattern.
|
|
50
51
|
|
|
51
52
|
Output:
|
|
52
53
|
-h, --help Outputs this help message
|
|
@@ -211,11 +212,11 @@ for (const setupFile of positionals) {
|
|
|
211
212
|
execSync(
|
|
212
213
|
[
|
|
213
214
|
'tsx --trace-deprecation',
|
|
214
|
-
options.inspect ? 'inspect' : '',
|
|
215
|
+
options.inspect ? '--inspect' : '',
|
|
215
216
|
'--test --experimental-test-coverage',
|
|
216
217
|
options.force ? '--test-force-exit' : '',
|
|
217
218
|
options.skip ? `--test-skip-pattern=${options.skip}` : '',
|
|
218
|
-
testsGlob,
|
|
219
|
+
`'${testsGlob.replaceAll("'", "\\'")}'`,
|
|
219
220
|
process.env.CMD,
|
|
220
221
|
].join(' '),
|
|
221
222
|
{
|
package/tests/fs/dir.test.ts
CHANGED
|
@@ -16,15 +16,15 @@ for (const file of testFiles) {
|
|
|
16
16
|
suite('Dirent', () => {
|
|
17
17
|
test('name and parentPath getters', async () => {
|
|
18
18
|
const stats = await fs.promises.lstat(testFile);
|
|
19
|
-
const dirent =
|
|
19
|
+
const dirent = fs.Dirent.from(testFile, stats);
|
|
20
20
|
|
|
21
21
|
assert.equal(dirent.name, testFile);
|
|
22
|
-
assert.equal(dirent.parentPath,
|
|
22
|
+
assert.equal(dirent.parentPath, '.');
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
test('isFile', async () => {
|
|
26
26
|
const fileStats = await fs.promises.lstat(testFile);
|
|
27
|
-
const fileDirent =
|
|
27
|
+
const fileDirent = fs.Dirent.from(testFile, fileStats);
|
|
28
28
|
|
|
29
29
|
assert(fileDirent.isFile());
|
|
30
30
|
assert(!fileDirent.isDirectory());
|
|
@@ -32,7 +32,7 @@ suite('Dirent', () => {
|
|
|
32
32
|
|
|
33
33
|
test('isDirectory', async () => {
|
|
34
34
|
const dirStats = await fs.promises.lstat('test-directory');
|
|
35
|
-
const dirDirent =
|
|
35
|
+
const dirDirent = fs.Dirent.from('test-directory', dirStats);
|
|
36
36
|
|
|
37
37
|
assert(!dirDirent.isFile());
|
|
38
38
|
assert(dirDirent.isDirectory());
|
|
@@ -40,14 +40,14 @@ suite('Dirent', () => {
|
|
|
40
40
|
|
|
41
41
|
test('isSymbolicLink', async () => {
|
|
42
42
|
const symlinkStats = await fs.promises.lstat('test-symlink');
|
|
43
|
-
const symlinkDirent =
|
|
43
|
+
const symlinkDirent = fs.Dirent.from('test-symlink', symlinkStats);
|
|
44
44
|
|
|
45
45
|
assert(symlinkDirent.isSymbolicLink());
|
|
46
46
|
});
|
|
47
47
|
|
|
48
48
|
test('other methods return false', async () => {
|
|
49
49
|
const fileStats = await fs.promises.lstat(testFile);
|
|
50
|
-
const fileDirent =
|
|
50
|
+
const fileDirent = fs.Dirent.from(testFile, fileStats);
|
|
51
51
|
|
|
52
52
|
assert(!fileDirent.isBlockDevice());
|
|
53
53
|
assert(!fileDirent.isCharacterDevice());
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
|
+
import { join } from 'node:path/posix';
|
|
2
3
|
import { suite, test } from 'node:test';
|
|
3
4
|
import { fs } from '../common.js';
|
|
4
5
|
|
|
@@ -143,10 +144,12 @@ suite('Directories', () => {
|
|
|
143
144
|
|
|
144
145
|
test('readdir returns Dirent recursively', async () => {
|
|
145
146
|
const entries = await fs.promises.readdir(testDir, { recursive: true, withFileTypes: true });
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
assert.
|
|
147
|
+
entries.sort((a, b) => join(a.parentPath, a.name).localeCompare(join(b.parentPath, b.name)));
|
|
148
|
+
const values = entries.map(entry => [entry.parentPath, entry.name]);
|
|
149
|
+
|
|
150
|
+
assert.deepEqual(values[0], [testDir, 'file1.txt']);
|
|
151
|
+
assert.deepEqual(values[4], [join(testDir, 'subdir1'), 'file4.txt']);
|
|
152
|
+
assert.deepEqual(values[8], [join(testDir, 'subdir2'), 'file5.txt']);
|
|
150
153
|
});
|
|
151
154
|
|
|
152
155
|
test('readdirSync returns files recursively', () => {
|
package/tests/fs/links.test.ts
CHANGED
|
@@ -18,6 +18,16 @@ suite('Links', () => {
|
|
|
18
18
|
assert(stats.isSymbolicLink());
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
+
test('lstat file inside symlinked directory', async () => {
|
|
22
|
+
// @zenfs/core#241
|
|
23
|
+
await fs.promises.mkdir('/a');
|
|
24
|
+
await fs.promises.writeFile('/a/hello.txt', 'hello world');
|
|
25
|
+
await fs.promises.symlink('/a', '/b');
|
|
26
|
+
|
|
27
|
+
const stat = await fs.promises.lstat('/b/hello.txt');
|
|
28
|
+
assert(stat.isFile());
|
|
29
|
+
});
|
|
30
|
+
|
|
21
31
|
test('readlink', async () => {
|
|
22
32
|
const destination = await fs.promises.readlink(symlink);
|
|
23
33
|
assert.equal(destination, target);
|
package/tests/fs/read.test.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { Buffer } from 'buffer';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
|
+
import type { OpenMode, PathLike } from 'node:fs';
|
|
3
4
|
import { suite, test } from 'node:test';
|
|
4
|
-
import {
|
|
5
|
+
import { promisify } from 'node:util';
|
|
6
|
+
import { fs, type Callback } from '../common.js';
|
|
5
7
|
|
|
6
8
|
const filepath = 'x.txt';
|
|
7
9
|
const expected = 'xyz\n';
|
|
@@ -65,4 +67,25 @@ suite('read', () => {
|
|
|
65
67
|
assert.equal(buffer.subarray(10, buffer.length).toString(), expected);
|
|
66
68
|
assert.equal(bytesRead, expected.length);
|
|
67
69
|
});
|
|
70
|
+
|
|
71
|
+
test('read using callback API', async () => {
|
|
72
|
+
// @zenfs/core#239
|
|
73
|
+
const path = '/text.txt';
|
|
74
|
+
|
|
75
|
+
fs.writeFileSync(path, 'hello world');
|
|
76
|
+
const fd: number = (await promisify<PathLike, OpenMode, number | string>(fs.open)(path, 0, 0)) as any;
|
|
77
|
+
|
|
78
|
+
const read = promisify(fs.read);
|
|
79
|
+
|
|
80
|
+
const buf = Buffer.alloc(1024);
|
|
81
|
+
const n0 = await read(fd, buf, 0, 1024, undefined);
|
|
82
|
+
assert.equal(n0, 11);
|
|
83
|
+
assert.equal(buf.subarray(0, n0).toString('utf8'), 'hello world');
|
|
84
|
+
|
|
85
|
+
const n1 = await read(fd, buf, 0, 1024, undefined);
|
|
86
|
+
assert.equal(n1, 0);
|
|
87
|
+
assert.equal(buf.subarray(0, n1).toString('utf8'), '');
|
|
88
|
+
|
|
89
|
+
await promisify(fs.close)(fd);
|
|
90
|
+
});
|
|
68
91
|
});
|