@zenfs/core 2.7.6 → 2.8.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/README.md +5 -0
- package/dist/backends/index.d.ts +3 -1
- package/dist/backends/index.js +3 -1
- package/dist/backends/single_buffer/backend.d.ts +42 -0
- package/dist/backends/single_buffer/backend.js +204 -0
- package/dist/backends/{single_buffer.d.ts → single_buffer/v1.d.ts} +24 -34
- package/dist/backends/{single_buffer.js → single_buffer/v1.js} +10 -26
- package/dist/backends/single_buffer/v2.d.ts +257 -0
- package/dist/backends/single_buffer/v2.js +1283 -0
- package/dist/backends/store/fs.d.ts +1 -1
- package/dist/backends/store/fs.js +35 -18
- package/dist/backends/store/map.d.ts +6 -6
- package/dist/backends/store/map.js +6 -6
- package/dist/backends/store/store.d.ts +18 -14
- package/dist/backends/store/store.js +12 -14
- package/dist/config.d.ts +7 -0
- package/dist/config.js +9 -3
- package/dist/internal/contexts.d.ts +5 -0
- package/dist/internal/contexts.js +7 -1
- package/dist/internal/error.d.ts +5 -0
- package/dist/internal/error.js +10 -0
- package/dist/internal/inode.d.ts +25 -0
- package/dist/internal/inode.js +75 -10
- package/dist/mixins/async.js +47 -30
- package/dist/node/promises.js +23 -124
- package/dist/node/stats.d.ts +1 -1
- package/dist/node/stats.js +4 -1
- package/dist/node/sync.js +20 -51
- package/dist/polyfills.js +16 -0
- package/dist/vfs/async.d.ts +4 -1
- package/dist/vfs/async.js +149 -69
- package/dist/vfs/config.d.ts +10 -1
- package/dist/vfs/config.js +5 -2
- package/dist/vfs/file.js +10 -4
- package/dist/vfs/ioctl.js +2 -2
- package/dist/vfs/shared.d.ts +2 -0
- package/dist/vfs/shared.js +3 -4
- package/dist/vfs/sync.d.ts +4 -1
- package/dist/vfs/sync.js +142 -64
- package/dist/vfs/vcache.d.ts +14 -14
- package/dist/vfs/vcache.js +65 -57
- package/dist/vfs/watchers.d.ts +1 -0
- package/dist/vfs/watchers.js +2 -4
- package/dist/vfs/xattr.js +18 -17
- package/package.json +3 -4
- package/scripts/make-index.js +1 -1
- package/tests/backend/single-buffer-rotate.worker.js +1 -1
- package/tests/backend/single-buffer-v2.test.ts +342 -0
- package/tests/backend/single-buffer-v2.worker.js +51 -0
- package/tests/backend/single-buffer.test.ts +6 -6
- package/tests/backend/single-buffer.worker.js +1 -0
- package/tests/common/async.test.ts +46 -0
- package/tests/common/config.test.ts +1 -1
- package/tests/common/context.test.ts +30 -0
- package/tests/common/file_index.test.ts +1 -1
- package/tests/common/mounts.test.ts +12 -0
- package/tests/common/vcache.test.ts +13 -0
- package/tests/fs/concurrency.test.ts +3 -3
- package/tests/fs/links.test.ts +76 -0
- package/tests/fs/permissions.test.ts +253 -0
- package/tests/fs/stat.test.ts +1 -1
- package/tests/fs/streams.test.ts +1 -1
- package/tests/fs/watch.test.ts +14 -0
- package/tests/fs/xattr.test.ts +10 -0
- package/tests/perf/config.json +31 -1
- package/tests/perf/single-buffer-random.ts +38 -0
- package/tests/perf/single-buffer-read.ts +28 -0
- package/tests/perf/single-buffer-write.ts +41 -0
- package/tests/setup/single-buffer-v2.ts +10 -0
- package/tests/setup/single-buffer.ts +1 -0
package/dist/mixins/async.js
CHANGED
|
@@ -57,6 +57,18 @@ import { StoreFS } from '../backends/store/fs.js';
|
|
|
57
57
|
import { isDirectory } from '../internal/inode.js';
|
|
58
58
|
import { join } from '../path.js';
|
|
59
59
|
import { _asyncFSKeys } from './shared.js';
|
|
60
|
+
/**
|
|
61
|
+
* Whether the stack of `error` has a patched method or `key`'s sync method below the innermost patched method.
|
|
62
|
+
*/
|
|
63
|
+
function isInLoop(key, error = new Error()) {
|
|
64
|
+
return new RegExp(`__patched__[^]*(__patched__|\\b${key}Sync\\b)`).test(error.stack ?? '');
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Whether the stack has a queued replay below the innermost patched method.
|
|
68
|
+
*/
|
|
69
|
+
function isReplay() {
|
|
70
|
+
return /__patched__[^]*__replay__/.test(new Error().stack ?? '');
|
|
71
|
+
}
|
|
60
72
|
/**
|
|
61
73
|
* Async() implements synchronous methods on an asynchronous file system
|
|
62
74
|
*
|
|
@@ -82,8 +94,21 @@ export function Async(FS) {
|
|
|
82
94
|
return this.sync();
|
|
83
95
|
}
|
|
84
96
|
_promise = Promise.resolve();
|
|
97
|
+
/** How many queued operations have not finished */
|
|
98
|
+
_pending = 0;
|
|
99
|
+
/** The async methods before patching, which do not update the sync cache */
|
|
100
|
+
_unpatched = {};
|
|
85
101
|
_async(thunk) {
|
|
86
|
-
this.
|
|
102
|
+
this._pending++;
|
|
103
|
+
const replay = async function __replay__() {
|
|
104
|
+
try {
|
|
105
|
+
await thunk();
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
this._pending--;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
this._promise = this._promise.finally(replay.bind(this));
|
|
87
112
|
}
|
|
88
113
|
_isInitialized = false;
|
|
89
114
|
/** Tracks how many updates to the sync. cache we skipped during initialization */
|
|
@@ -132,7 +157,7 @@ export function Async(FS) {
|
|
|
132
157
|
renameSync(oldPath, newPath) {
|
|
133
158
|
this.checkSync();
|
|
134
159
|
this._sync.renameSync(oldPath, newPath);
|
|
135
|
-
this._async(() => this.rename(oldPath, newPath));
|
|
160
|
+
this._async(() => this._unpatched.rename(oldPath, newPath));
|
|
136
161
|
}
|
|
137
162
|
statSync(path) {
|
|
138
163
|
this.checkSync();
|
|
@@ -141,28 +166,28 @@ export function Async(FS) {
|
|
|
141
166
|
touchSync(path, metadata) {
|
|
142
167
|
this.checkSync();
|
|
143
168
|
this._sync.touchSync(path, metadata);
|
|
144
|
-
this._async(() => this.touch(path, metadata));
|
|
169
|
+
this._async(() => this._unpatched.touch(path, metadata));
|
|
145
170
|
}
|
|
146
171
|
createFileSync(path, options) {
|
|
147
172
|
this.checkSync();
|
|
148
173
|
const result = this._sync.createFileSync(path, options);
|
|
149
|
-
this._async(() => this.createFile(path, options));
|
|
174
|
+
this._async(() => this._unpatched.createFile(path, options));
|
|
150
175
|
return result;
|
|
151
176
|
}
|
|
152
177
|
unlinkSync(path) {
|
|
153
178
|
this.checkSync();
|
|
154
179
|
this._sync.unlinkSync(path);
|
|
155
|
-
this._async(() => this.unlink(path));
|
|
180
|
+
this._async(() => this._unpatched.unlink(path));
|
|
156
181
|
}
|
|
157
182
|
rmdirSync(path) {
|
|
158
183
|
this.checkSync();
|
|
159
184
|
this._sync.rmdirSync(path);
|
|
160
|
-
this._async(() => this.rmdir(path));
|
|
185
|
+
this._async(() => this._unpatched.rmdir(path));
|
|
161
186
|
}
|
|
162
187
|
mkdirSync(path, options) {
|
|
163
188
|
this.checkSync();
|
|
164
189
|
const result = this._sync.mkdirSync(path, options);
|
|
165
|
-
this._async(() => this.mkdir(path, options));
|
|
190
|
+
this._async(() => this._unpatched.mkdir(path, options));
|
|
166
191
|
return result;
|
|
167
192
|
}
|
|
168
193
|
readdirSync(path) {
|
|
@@ -172,7 +197,7 @@ export function Async(FS) {
|
|
|
172
197
|
linkSync(srcpath, dstpath) {
|
|
173
198
|
this.checkSync();
|
|
174
199
|
this._sync.linkSync(srcpath, dstpath);
|
|
175
|
-
this._async(() => this.link(srcpath, dstpath));
|
|
200
|
+
this._async(() => this._unpatched.link(srcpath, dstpath));
|
|
176
201
|
}
|
|
177
202
|
async sync() {
|
|
178
203
|
if (!this.attributes.has('no_async_preload') && this._sync)
|
|
@@ -194,7 +219,7 @@ export function Async(FS) {
|
|
|
194
219
|
writeSync(path, buffer, offset) {
|
|
195
220
|
this.checkSync();
|
|
196
221
|
this._sync.writeSync(path, buffer, offset);
|
|
197
|
-
this._async(() => this.write(path, buffer, offset));
|
|
222
|
+
this._async(() => this._unpatched.write(path, buffer, offset));
|
|
198
223
|
}
|
|
199
224
|
ioctlSync(context, command, ...args) {
|
|
200
225
|
this.checkSync();
|
|
@@ -253,30 +278,19 @@ export function Async(FS) {
|
|
|
253
278
|
}
|
|
254
279
|
/**
|
|
255
280
|
* @internal
|
|
256
|
-
* Patch all async methods to
|
|
281
|
+
* Patch all async methods to wait for queued operations,
|
|
282
|
+
* and methods that change the file system to also call their synchronous counterparts unless called from themselves (either sync or async)
|
|
257
283
|
*/
|
|
258
284
|
_patchAsync() {
|
|
259
|
-
const
|
|
260
|
-
const
|
|
261
|
-
for (const key of toPatch) {
|
|
285
|
+
const reads = ['read', 'readdir', 'stat', 'exists'];
|
|
286
|
+
for (const key of _asyncFSKeys) {
|
|
262
287
|
// TS does not narrow the union based on the key
|
|
263
288
|
const originalMethod = this[key].bind(this);
|
|
264
|
-
function
|
|
265
|
-
if (!
|
|
266
|
-
|
|
267
|
-
Error.captureStackTrace(error, isInLoop);
|
|
268
|
-
}
|
|
269
|
-
if (!error.stack)
|
|
270
|
-
return false;
|
|
271
|
-
const stack = error.stack.split('\n').slice(depth).join('\n');
|
|
272
|
-
// From the async queue
|
|
273
|
-
return (stack.includes(`at <computed> [as ${key}]`)
|
|
274
|
-
|| stack.includes(`at async <computed> [as ${key}]`)
|
|
275
|
-
|| stack.includes(`${key}Sync `));
|
|
276
|
-
}
|
|
277
|
-
this[key] = async (...args) => {
|
|
289
|
+
const fn = async function __patched__(...args) {
|
|
290
|
+
if (this._pending && !isReplay())
|
|
291
|
+
await this._promise.catch(() => { });
|
|
278
292
|
const result = await originalMethod(...args);
|
|
279
|
-
if (isInLoop(
|
|
293
|
+
if (reads.includes(key) || isInLoop(key))
|
|
280
294
|
return result;
|
|
281
295
|
if (!this._isInitialized) {
|
|
282
296
|
this._skippedCacheUpdates++;
|
|
@@ -287,15 +301,18 @@ export function Async(FS) {
|
|
|
287
301
|
this._sync?.[`${key}Sync`]?.(...args);
|
|
288
302
|
}
|
|
289
303
|
catch (e) {
|
|
290
|
-
if (isInLoop(
|
|
304
|
+
if (isInLoop(key, e))
|
|
291
305
|
return result;
|
|
292
306
|
e.message += ' (Out of sync!)';
|
|
293
307
|
throw err(e);
|
|
294
308
|
}
|
|
295
309
|
return result;
|
|
296
310
|
};
|
|
311
|
+
Object.defineProperty(fn, 'name', { get: () => key });
|
|
312
|
+
this._unpatched[key] = originalMethod;
|
|
313
|
+
this[key] = fn;
|
|
297
314
|
}
|
|
298
|
-
debug(`Async: patched ${
|
|
315
|
+
debug(`Async: patched ${_asyncFSKeys.length} methods`);
|
|
299
316
|
}
|
|
300
317
|
}
|
|
301
318
|
return AsyncFS;
|
package/dist/node/promises.js
CHANGED
|
@@ -55,7 +55,7 @@ import { Exception, rethrow, UV } from 'kerium';
|
|
|
55
55
|
import { encodeUTF8 } from 'utilium';
|
|
56
56
|
import * as constants from '../constants.js';
|
|
57
57
|
import { contextOf } from '../internal/contexts.js';
|
|
58
|
-
import { hasAccess, InodeFlags, isDirectory } from '../internal/inode.js';
|
|
58
|
+
import { assertRemovable, hasAccess, InodeFlags, isDirectory } from '../internal/inode.js';
|
|
59
59
|
import { dirname, join, matchesGlob, relative, resolve } from '../path.js';
|
|
60
60
|
import '../polyfills.js';
|
|
61
61
|
import { _isNoEntry, _tempDirName, globToRegex, normalizeMode, normalizeOptions, normalizePath, normalizeTime, validateFD } from '../utils.js';
|
|
@@ -63,8 +63,7 @@ import * as _async from '../vfs/async.js';
|
|
|
63
63
|
import { checkAccess } from '../vfs/config.js';
|
|
64
64
|
import { deleteFD, fromFD, toFD } from '../vfs/file.js';
|
|
65
65
|
import * as flags from '../vfs/flags.js';
|
|
66
|
-
import { _statfs
|
|
67
|
-
import { cacheOf, lockPath } from '../vfs/vcache.js';
|
|
66
|
+
import { _statfs } from '../vfs/shared.js';
|
|
68
67
|
import { emitChange, FSWatcher } from '../vfs/watchers.js';
|
|
69
68
|
import { Dir, Dirent } from './dir.js';
|
|
70
69
|
import { createInterface } from './readline.js';
|
|
@@ -535,7 +534,7 @@ export async function exists(path) {
|
|
|
535
534
|
return await fs.exists(resolved);
|
|
536
535
|
}
|
|
537
536
|
catch (e) {
|
|
538
|
-
if (e instanceof Exception && e.code == 'ENOENT') {
|
|
537
|
+
if (e instanceof Exception && (e.code == 'ENOENT' || e.code == 'ENOTDIR' || e.code == 'EACCES')) {
|
|
539
538
|
return false;
|
|
540
539
|
}
|
|
541
540
|
throw e;
|
|
@@ -580,14 +579,13 @@ export async function unlink(path) {
|
|
|
580
579
|
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
581
580
|
try {
|
|
582
581
|
path = normalizePath.call(this, path);
|
|
583
|
-
const { fs, path: resolved } = resolveMount(path, this);
|
|
584
582
|
const $ex = { syscall: 'unlink', path };
|
|
585
|
-
const
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
const _ = __addDisposableResource(env_2, await
|
|
583
|
+
const { fs, cache, path: resolved } = await _async.resolve(this, path, true, $ex);
|
|
584
|
+
const stats = await cache.stat(resolved).catch(rethrow($ex));
|
|
585
|
+
assertRemovable(this, await cache.stat(dirname(resolved)).catch(rethrow($ex)), stats, $ex);
|
|
586
|
+
const _ = __addDisposableResource(env_2, await cache.lock(dirname(resolved), 'rw'), false);
|
|
589
587
|
await fs.unlink(resolved).catch(rethrow($ex));
|
|
590
|
-
|
|
588
|
+
cache.remove(resolved);
|
|
591
589
|
emitChange(this, 'rename', path.toString());
|
|
592
590
|
}
|
|
593
591
|
catch (e_2) {
|
|
@@ -692,18 +690,17 @@ export async function rmdir(path) {
|
|
|
692
690
|
const env_6 = { stack: [], error: void 0, hasError: false };
|
|
693
691
|
try {
|
|
694
692
|
path = normalizePath.call(this, path);
|
|
695
|
-
const { fs, path: resolved } = await _async.resolve(this, path);
|
|
693
|
+
const { fs, cache, path: resolved } = await _async.resolve(this, path, true);
|
|
696
694
|
const $ex = { syscall: 'rmdir', path };
|
|
697
|
-
const stats = await
|
|
695
|
+
const stats = await cache.stat(resolved).catch(rethrow($ex));
|
|
698
696
|
if (!stats)
|
|
699
697
|
throw UV('ENOENT', $ex);
|
|
700
698
|
if (!isDirectory(stats))
|
|
701
699
|
throw UV('ENOTDIR', $ex);
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
const _ = __addDisposableResource(env_6, await lockPath(fs, dirname(resolved), 'rw'), false);
|
|
700
|
+
assertRemovable(this, await cache.stat(dirname(resolved)).catch(rethrow($ex)), stats, $ex);
|
|
701
|
+
const _ = __addDisposableResource(env_6, await cache.lock(dirname(resolved), 'rw'), false);
|
|
705
702
|
await fs.rmdir(resolved).catch(rethrow($ex));
|
|
706
|
-
|
|
703
|
+
cache.remove(resolved);
|
|
707
704
|
emitChange(this, 'rename', path.toString());
|
|
708
705
|
}
|
|
709
706
|
catch (e_6) {
|
|
@@ -761,7 +758,7 @@ export async function symlink(dest, path, type = 'file') {
|
|
|
761
758
|
const handle = __addDisposableResource(env_7, await _async.open(this, path, { flag: 'w+', mode: 0o644, preserveSymlinks: true }), true);
|
|
762
759
|
const encoded = encodeUTF8(normalizePath.call(this, dest, true));
|
|
763
760
|
await handle.write(encoded, 0, encoded.length, 0);
|
|
764
|
-
await handle.chmod(constants.S_IFLNK);
|
|
761
|
+
await handle.chmod(constants.S_IFLNK | 0o777);
|
|
765
762
|
}
|
|
766
763
|
catch (e_7) {
|
|
767
764
|
env_7.error = e_7;
|
|
@@ -783,130 +780,33 @@ export async function readlink(path, options) {
|
|
|
783
780
|
}
|
|
784
781
|
readlink;
|
|
785
782
|
export async function chown(path, uid, gid) {
|
|
786
|
-
|
|
787
|
-
try {
|
|
788
|
-
const handle = __addDisposableResource(env_8, await open.call(this, path, 'r+'), true);
|
|
789
|
-
await handle.chown(uid, gid);
|
|
790
|
-
}
|
|
791
|
-
catch (e_8) {
|
|
792
|
-
env_8.error = e_8;
|
|
793
|
-
env_8.hasError = true;
|
|
794
|
-
}
|
|
795
|
-
finally {
|
|
796
|
-
const result_6 = __disposeResources(env_8);
|
|
797
|
-
if (result_6)
|
|
798
|
-
await result_6;
|
|
799
|
-
}
|
|
783
|
+
await _async.chown.call(this, path, uid, gid, false);
|
|
800
784
|
}
|
|
801
785
|
chown;
|
|
802
786
|
export async function lchown(path, uid, gid) {
|
|
803
|
-
|
|
804
|
-
try {
|
|
805
|
-
const handle = __addDisposableResource(env_9, await _async.open(this, path, {
|
|
806
|
-
flag: 'r+',
|
|
807
|
-
mode: 0o644,
|
|
808
|
-
preserveSymlinks: true,
|
|
809
|
-
allowDirectory: true,
|
|
810
|
-
}), true);
|
|
811
|
-
await handle.chown(uid, gid);
|
|
812
|
-
}
|
|
813
|
-
catch (e_9) {
|
|
814
|
-
env_9.error = e_9;
|
|
815
|
-
env_9.hasError = true;
|
|
816
|
-
}
|
|
817
|
-
finally {
|
|
818
|
-
const result_7 = __disposeResources(env_9);
|
|
819
|
-
if (result_7)
|
|
820
|
-
await result_7;
|
|
821
|
-
}
|
|
787
|
+
await _async.chown.call(this, path, uid, gid, true);
|
|
822
788
|
}
|
|
823
789
|
lchown;
|
|
824
790
|
export async function chmod(path, mode) {
|
|
825
|
-
|
|
826
|
-
try {
|
|
827
|
-
const handle = __addDisposableResource(env_10, await open.call(this, path, 'r+').catch(rethrow({ syscall: 'chmod', path: normalizePath.call(this, path) })), true);
|
|
828
|
-
await handle.chmod(mode);
|
|
829
|
-
}
|
|
830
|
-
catch (e_10) {
|
|
831
|
-
env_10.error = e_10;
|
|
832
|
-
env_10.hasError = true;
|
|
833
|
-
}
|
|
834
|
-
finally {
|
|
835
|
-
const result_8 = __disposeResources(env_10);
|
|
836
|
-
if (result_8)
|
|
837
|
-
await result_8;
|
|
838
|
-
}
|
|
791
|
+
await _async.chmod.call(this, path, mode, false);
|
|
839
792
|
}
|
|
840
793
|
chmod;
|
|
841
794
|
export async function lchmod(path, mode) {
|
|
842
|
-
|
|
843
|
-
try {
|
|
844
|
-
mode = normalizeMode(mode);
|
|
845
|
-
const handle = __addDisposableResource(env_11, await _async.open(this, path, {
|
|
846
|
-
flag: 'r+',
|
|
847
|
-
mode: 0o644,
|
|
848
|
-
preserveSymlinks: true,
|
|
849
|
-
allowDirectory: true,
|
|
850
|
-
}), true);
|
|
851
|
-
await handle.chmod(mode);
|
|
852
|
-
}
|
|
853
|
-
catch (e_11) {
|
|
854
|
-
env_11.error = e_11;
|
|
855
|
-
env_11.hasError = true;
|
|
856
|
-
}
|
|
857
|
-
finally {
|
|
858
|
-
const result_9 = __disposeResources(env_11);
|
|
859
|
-
if (result_9)
|
|
860
|
-
await result_9;
|
|
861
|
-
}
|
|
795
|
+
await _async.chmod.call(this, path, mode, true);
|
|
862
796
|
}
|
|
863
797
|
lchmod;
|
|
864
798
|
/**
|
|
865
799
|
* Change file timestamps of the file referenced by the supplied path.
|
|
866
800
|
*/
|
|
867
801
|
export async function utimes(path, atime, mtime) {
|
|
868
|
-
|
|
869
|
-
try {
|
|
870
|
-
const handle = __addDisposableResource(env_12, await _async.open(this, path, {
|
|
871
|
-
flag: 'r+',
|
|
872
|
-
allowDirectory: true,
|
|
873
|
-
}), true);
|
|
874
|
-
await handle.utimes(normalizeTime(atime), normalizeTime(mtime));
|
|
875
|
-
}
|
|
876
|
-
catch (e_12) {
|
|
877
|
-
env_12.error = e_12;
|
|
878
|
-
env_12.hasError = true;
|
|
879
|
-
}
|
|
880
|
-
finally {
|
|
881
|
-
const result_10 = __disposeResources(env_12);
|
|
882
|
-
if (result_10)
|
|
883
|
-
await result_10;
|
|
884
|
-
}
|
|
802
|
+
await _async.utimes.call(this, path, atime, mtime, false);
|
|
885
803
|
}
|
|
886
804
|
utimes;
|
|
887
805
|
/**
|
|
888
806
|
* Change file timestamps of the file referenced by the supplied path.
|
|
889
807
|
*/
|
|
890
808
|
export async function lutimes(path, atime, mtime) {
|
|
891
|
-
|
|
892
|
-
try {
|
|
893
|
-
const handle = __addDisposableResource(env_13, await _async.open(this, path, {
|
|
894
|
-
flag: 'r+',
|
|
895
|
-
mode: 0o644,
|
|
896
|
-
preserveSymlinks: true,
|
|
897
|
-
allowDirectory: true,
|
|
898
|
-
}), true);
|
|
899
|
-
await handle.utimes(normalizeTime(atime), normalizeTime(mtime));
|
|
900
|
-
}
|
|
901
|
-
catch (e_13) {
|
|
902
|
-
env_13.error = e_13;
|
|
903
|
-
env_13.hasError = true;
|
|
904
|
-
}
|
|
905
|
-
finally {
|
|
906
|
-
const result_11 = __disposeResources(env_13);
|
|
907
|
-
if (result_11)
|
|
908
|
-
await result_11;
|
|
909
|
-
}
|
|
809
|
+
await _async.utimes.call(this, path, atime, mtime, true);
|
|
910
810
|
}
|
|
911
811
|
lutimes;
|
|
912
812
|
export async function realpath(path, options) {
|
|
@@ -1079,8 +979,7 @@ export async function cp(source, destination, opts) {
|
|
|
1079
979
|
const [entries] = await Promise.all([
|
|
1080
980
|
readdir.call(this, source, { withFileTypes: true }),
|
|
1081
981
|
mkdir.call(this, destination, { recursive: true }),
|
|
1082
|
-
]
|
|
1083
|
-
);
|
|
982
|
+
]);
|
|
1084
983
|
const _cp = async (dirent) => {
|
|
1085
984
|
if (opts.filter && !opts.filter(join(source, dirent.name), join(destination, dirent.name))) {
|
|
1086
985
|
return; // Skip if the filter returns false
|
|
@@ -1117,8 +1016,8 @@ export async function cp(source, destination, opts) {
|
|
|
1117
1016
|
cp;
|
|
1118
1017
|
export async function statfs(path, opts) {
|
|
1119
1018
|
path = normalizePath.call(this, path);
|
|
1120
|
-
const { fs } =
|
|
1121
|
-
return
|
|
1019
|
+
const { fs } = await _async.resolve(this, path);
|
|
1020
|
+
return _statfs(fs, opts?.bigint);
|
|
1122
1021
|
}
|
|
1123
1022
|
export function glob(pattern, opt) {
|
|
1124
1023
|
pattern = Array.isArray(pattern) ? pattern : [pattern];
|
package/dist/node/stats.d.ts
CHANGED
|
@@ -65,7 +65,7 @@ export declare abstract class StatsCommon<T extends number | bigint> implements
|
|
|
65
65
|
/** @internal Used by inodes */
|
|
66
66
|
version?: number;
|
|
67
67
|
/** Creates a new stats instance from a stats-like object. Can be used to copy stats (note) */
|
|
68
|
-
constructor({ atimeMs, mtimeMs, ctimeMs, birthtimeMs, uid, gid, size, mode, ino, ...rest }?: Partial<InodeLike<number | bigint>>);
|
|
68
|
+
constructor({ atimeMs, mtimeMs, ctimeMs, birthtimeMs, uid, gid, size, mode, ino, rdev, dev, blksize, ...rest }?: Partial<InodeLike<number | bigint> & StatsExtra<number | bigint>>);
|
|
69
69
|
isFile(): boolean;
|
|
70
70
|
isDirectory(): boolean;
|
|
71
71
|
isSymbolicLink(): boolean;
|
package/dist/node/stats.js
CHANGED
|
@@ -96,7 +96,7 @@ export class StatsCommon {
|
|
|
96
96
|
/** @internal Used by inodes */
|
|
97
97
|
version;
|
|
98
98
|
/** Creates a new stats instance from a stats-like object. Can be used to copy stats (note) */
|
|
99
|
-
constructor({ atimeMs, mtimeMs, ctimeMs, birthtimeMs, uid, gid, size, mode, ino, ...rest } = {}) {
|
|
99
|
+
constructor({ atimeMs, mtimeMs, ctimeMs, birthtimeMs, uid, gid, size, mode, ino, rdev, dev, blksize, ...rest } = {}) {
|
|
100
100
|
const now = Date.now();
|
|
101
101
|
this.atimeMs = this._convert(atimeMs ?? now);
|
|
102
102
|
this.mtimeMs = this._convert(mtimeMs ?? now);
|
|
@@ -107,6 +107,9 @@ export class StatsCommon {
|
|
|
107
107
|
this.size = this._convert(size ?? 0);
|
|
108
108
|
this.ino = this._convert(ino ?? 0);
|
|
109
109
|
this.mode = this._convert(mode ?? 0o644 & c.S_IFREG);
|
|
110
|
+
this.rdev = this._convert(rdev ?? 0);
|
|
111
|
+
this.dev = this._convert(dev ?? 0);
|
|
112
|
+
this.blksize = this._convert(blksize ?? 4096);
|
|
110
113
|
if ((this.mode & c.S_IFMT) == 0) {
|
|
111
114
|
this.mode = (this.mode | this._convert(c.S_IFREG));
|
|
112
115
|
}
|
package/dist/node/sync.js
CHANGED
|
@@ -56,15 +56,14 @@ import { encodeUTF8 } from 'utilium';
|
|
|
56
56
|
import * as constants from '../constants.js';
|
|
57
57
|
import { contextOf } from '../internal/contexts.js';
|
|
58
58
|
import { wrap } from '../internal/error.js';
|
|
59
|
-
import { hasAccess, isDirectory } from '../internal/inode.js';
|
|
59
|
+
import { assertRemovable, hasAccess, isDirectory } from '../internal/inode.js';
|
|
60
60
|
import { dirname, join, matchesGlob, relative, resolve } from '../path.js';
|
|
61
61
|
import { _isNoEntry, _tempDirName, globToRegex, normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '../utils.js';
|
|
62
62
|
import { checkAccess } from '../vfs/config.js';
|
|
63
63
|
import { deleteFD, fromFD, toFD } from '../vfs/file.js';
|
|
64
64
|
import * as flags from '../vfs/flags.js';
|
|
65
|
-
import { _statfs
|
|
65
|
+
import { _statfs } from '../vfs/shared.js';
|
|
66
66
|
import * as _sync from '../vfs/sync.js';
|
|
67
|
-
import { cacheOf, lockPathSync } from '../vfs/vcache.js';
|
|
68
67
|
import { emitChange } from '../vfs/watchers.js';
|
|
69
68
|
import { Dir, Dirent } from './dir.js';
|
|
70
69
|
import { BigIntStats, Stats } from './stats.js';
|
|
@@ -82,7 +81,7 @@ export function existsSync(path) {
|
|
|
82
81
|
return fs.existsSync(resolvedPath);
|
|
83
82
|
}
|
|
84
83
|
catch (e) {
|
|
85
|
-
if (e.errno == Errno.ENOENT)
|
|
84
|
+
if (e.errno == Errno.ENOENT || e.errno == Errno.ENOTDIR || e.errno == Errno.EACCES)
|
|
86
85
|
return false;
|
|
87
86
|
throw e;
|
|
88
87
|
}
|
|
@@ -134,16 +133,14 @@ export function truncateSync(path, len = 0) {
|
|
|
134
133
|
truncateSync;
|
|
135
134
|
export function unlinkSync(path) {
|
|
136
135
|
path = normalizePath.call(this, path);
|
|
137
|
-
const { fs, path: resolved } =
|
|
136
|
+
const { fs, cache, path: resolved } = _sync.resolve(this, path, true, { syscall: 'unlink', path });
|
|
138
137
|
try {
|
|
139
138
|
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
140
139
|
try {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
const _ = __addDisposableResource(env_2, lockPathSync(fs, dirname(resolved), 'rw'), false);
|
|
140
|
+
assertRemovable(this, cache.statSync(dirname(resolved)), cache.statSync(resolved));
|
|
141
|
+
const _ = __addDisposableResource(env_2, cache.lockSync(dirname(resolved), 'rw'), false);
|
|
145
142
|
fs.unlinkSync(resolved);
|
|
146
|
-
|
|
143
|
+
cache.remove(resolved);
|
|
147
144
|
}
|
|
148
145
|
catch (e_2) {
|
|
149
146
|
env_2.error = e_2;
|
|
@@ -372,15 +369,14 @@ export function rmdirSync(path) {
|
|
|
372
369
|
const env_5 = { stack: [], error: void 0, hasError: false };
|
|
373
370
|
try {
|
|
374
371
|
path = normalizePath.call(this, path);
|
|
375
|
-
const { fs, path: resolved } = _sync.resolve(this, path);
|
|
376
|
-
const stats =
|
|
372
|
+
const { fs, cache, path: resolved } = _sync.resolve(this, path, true);
|
|
373
|
+
const stats = cache.statSync(resolved, { path, syscall: 'rmdir' });
|
|
377
374
|
if (!isDirectory(stats))
|
|
378
375
|
throw UV('ENOTDIR', 'rmdir', path);
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
const _ = __addDisposableResource(env_5, lockPathSync(fs, dirname(resolved), 'rw'), false);
|
|
376
|
+
assertRemovable(this, cache.statSync(dirname(resolved), { path, syscall: 'rmdir' }), stats, { syscall: 'rmdir', path });
|
|
377
|
+
const _ = __addDisposableResource(env_5, cache.lockSync(dirname(resolved), 'rw'), false);
|
|
382
378
|
wrap(fs, 'rmdirSync', path)(resolved);
|
|
383
|
-
|
|
379
|
+
cache.remove(resolved);
|
|
384
380
|
emitChange(this, 'rename', path.toString());
|
|
385
381
|
}
|
|
386
382
|
catch (e_5) {
|
|
@@ -435,7 +431,7 @@ export function symlinkSync(target, path, type = 'file') {
|
|
|
435
431
|
path = normalizePath.call(this, path);
|
|
436
432
|
const file = __addDisposableResource(env_6, _sync.open(this, path, { flag: 'wx', mode: 0o644 }), false);
|
|
437
433
|
file.writeSync(encodeUTF8(normalizePath.call(this, target, true)));
|
|
438
|
-
file.chmodSync(constants.S_IFLNK);
|
|
434
|
+
file.chmodSync(constants.S_IFLNK | 0o777);
|
|
439
435
|
}
|
|
440
436
|
catch (e_6) {
|
|
441
437
|
env_6.error = e_6;
|
|
@@ -457,60 +453,33 @@ export function readlinkSync(path, options) {
|
|
|
457
453
|
}
|
|
458
454
|
readlinkSync;
|
|
459
455
|
export function chownSync(path, uid, gid) {
|
|
460
|
-
|
|
461
|
-
try {
|
|
462
|
-
const handle = __addDisposableResource(env_7, _sync.open(this, path, { flag: 'r+', mode: constants.F_OK }), false);
|
|
463
|
-
handle.chownSync(uid, gid);
|
|
464
|
-
}
|
|
465
|
-
catch (e_7) {
|
|
466
|
-
env_7.error = e_7;
|
|
467
|
-
env_7.hasError = true;
|
|
468
|
-
}
|
|
469
|
-
finally {
|
|
470
|
-
__disposeResources(env_7);
|
|
471
|
-
}
|
|
456
|
+
_sync.chown.call(this, path, uid, gid);
|
|
472
457
|
}
|
|
473
458
|
chownSync;
|
|
474
459
|
export function lchownSync(path, uid, gid) {
|
|
475
|
-
|
|
476
|
-
fchownSync.call(this, fd, uid, gid);
|
|
477
|
-
closeSync.call(this, fd);
|
|
460
|
+
_sync.chown.call(this, path, uid, gid, true);
|
|
478
461
|
}
|
|
479
462
|
lchownSync;
|
|
480
463
|
export function chmodSync(path, mode) {
|
|
481
|
-
|
|
482
|
-
try {
|
|
483
|
-
fd = openSync.call(this, path, 'r+');
|
|
484
|
-
}
|
|
485
|
-
catch (e) {
|
|
486
|
-
throw setUVMessage(Object.assign(e, { syscall: 'chmod', path: normalizePath.call(this, path) }));
|
|
487
|
-
}
|
|
488
|
-
fchmodSync.call(this, fd, mode);
|
|
489
|
-
closeSync.call(this, fd);
|
|
464
|
+
_sync.chmod.call(this, path, mode);
|
|
490
465
|
}
|
|
491
466
|
chmodSync;
|
|
492
467
|
export function lchmodSync(path, mode) {
|
|
493
|
-
|
|
494
|
-
fchmodSync.call(this, fd, mode);
|
|
495
|
-
closeSync.call(this, fd);
|
|
468
|
+
_sync.chmod.call(this, path, mode, true);
|
|
496
469
|
}
|
|
497
470
|
lchmodSync;
|
|
498
471
|
/**
|
|
499
472
|
* Change file timestamps of the file referenced by the supplied path.
|
|
500
473
|
*/
|
|
501
474
|
export function utimesSync(path, atime, mtime) {
|
|
502
|
-
|
|
503
|
-
futimesSync.call(this, fd, atime, mtime);
|
|
504
|
-
closeSync.call(this, fd);
|
|
475
|
+
_sync.utimes.call(this, path, atime, mtime);
|
|
505
476
|
}
|
|
506
477
|
utimesSync;
|
|
507
478
|
/**
|
|
508
479
|
* Change file timestamps of the file referenced by the supplied path.
|
|
509
480
|
*/
|
|
510
481
|
export function lutimesSync(path, atime, mtime) {
|
|
511
|
-
|
|
512
|
-
futimesSync.call(this, fd, atime, mtime);
|
|
513
|
-
closeSync.call(this, fd);
|
|
482
|
+
_sync.utimes.call(this, path, atime, mtime, true);
|
|
514
483
|
}
|
|
515
484
|
lutimesSync;
|
|
516
485
|
export function realpathSync(path, options) {
|
|
@@ -706,7 +675,7 @@ export function cpSync(source, destination, opts) {
|
|
|
706
675
|
cpSync;
|
|
707
676
|
export function statfsSync(path, options) {
|
|
708
677
|
path = normalizePath.call(this, path);
|
|
709
|
-
const { fs } =
|
|
678
|
+
const { fs } = _sync.resolve(this, path);
|
|
710
679
|
return _statfs(fs, options?.bigint);
|
|
711
680
|
}
|
|
712
681
|
export function globSync(pattern, options = {}) {
|
package/dist/polyfills.js
CHANGED
|
@@ -66,4 +66,20 @@ Array.fromAsync ??=
|
|
|
66
66
|
}
|
|
67
67
|
return results;
|
|
68
68
|
});
|
|
69
|
+
Map.prototype.getOrInsert ??=
|
|
70
|
+
(warn('Using a polyfill of Map.prototype.getOrInsert'),
|
|
71
|
+
function getOrInsert(key, defaultValue) {
|
|
72
|
+
if (!this.has(key))
|
|
73
|
+
this.set(key, defaultValue);
|
|
74
|
+
return this.get(key);
|
|
75
|
+
});
|
|
76
|
+
Map.prototype.getOrInsertComputed ??=
|
|
77
|
+
(warn('Using a polyfill of Map.prototype.getOrInsertComputed'),
|
|
78
|
+
function getOrInsertComputed(key, callback) {
|
|
79
|
+
if (this.has(key))
|
|
80
|
+
return this.get(key);
|
|
81
|
+
const value = callback(key);
|
|
82
|
+
this.set(key, value);
|
|
83
|
+
return value;
|
|
84
|
+
});
|
|
69
85
|
/* node:coverage enable */
|
package/dist/vfs/async.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PathLike } from 'node:fs';
|
|
1
|
+
import type { Mode, PathLike, TimeLike } from 'node:fs';
|
|
2
2
|
import type { V_Context } from '../internal/contexts.js';
|
|
3
3
|
import type { MkdirOptions, OpenOptions, ReaddirOptions, ResolvedPath } from './shared.js';
|
|
4
4
|
import { type ExceptionExtra } from 'kerium';
|
|
@@ -22,3 +22,6 @@ export declare function readdir(this: V_Context, path: PathLike, options?: Readd
|
|
|
22
22
|
export declare function rename(this: V_Context, oldPath: PathLike, newPath: PathLike): Promise<void>;
|
|
23
23
|
export declare function link(this: V_Context, target: PathLike, link: PathLike): Promise<void>;
|
|
24
24
|
export declare function stat(this: V_Context, path: PathLike, lstat: boolean): Promise<InodeLike>;
|
|
25
|
+
export declare function chmod(this: V_Context, path: PathLike, mode: Mode, noFollow?: boolean): Promise<void>;
|
|
26
|
+
export declare function chown(this: V_Context, path: PathLike, uid: number, gid: number, noFollow?: boolean): Promise<void>;
|
|
27
|
+
export declare function utimes(this: V_Context, path: PathLike, atime: TimeLike, mtime: TimeLike, noFollow?: boolean): Promise<void>;
|