@zenfs/core 0.12.0 → 0.12.2
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.d.ts +15 -5
- package/dist/backends/index/fs.d.ts +1 -0
- package/dist/backends/index/index.d.ts +5 -0
- package/dist/backends/index/index.js +1 -0
- package/dist/backends/overlay.js +1 -1
- package/dist/backends/port/fs.d.ts +3 -1
- package/dist/browser.min.js +4 -4
- package/dist/browser.min.js.map +4 -4
- package/dist/config.d.ts +33 -11
- package/dist/config.js +16 -7
- package/dist/emulation/async.d.ts +5 -4
- package/dist/emulation/async.js +3 -2
- package/dist/emulation/index.d.ts +1 -1
- package/dist/emulation/index.js +1 -1
- package/dist/emulation/path.d.ts +4 -1
- package/dist/emulation/promises.d.ts +4 -4
- package/dist/emulation/promises.js +27 -27
- package/dist/emulation/shared.d.ts +6 -0
- package/dist/emulation/shared.js +19 -1
- package/dist/emulation/sync.d.ts +4 -4
- package/dist/emulation/sync.js +76 -38
- package/dist/file.d.ts +5 -10
- package/dist/file.js +38 -55
- package/dist/filesystem.d.ts +45 -3
- package/dist/filesystem.js +37 -8
- package/dist/stats.d.ts +16 -16
- package/dist/stats.js +42 -49
- package/package.json +2 -2
- package/src/backends/backend.ts +15 -6
- package/src/backends/index/index.ts +5 -0
- package/src/backends/overlay.ts +1 -1
- package/src/config.ts +62 -21
- package/src/emulation/async.ts +19 -18
- package/src/emulation/index.ts +1 -1
- package/src/emulation/path.ts +4 -1
- package/src/emulation/promises.ts +33 -31
- package/src/emulation/shared.ts +22 -1
- package/src/emulation/sync.ts +83 -54
- package/src/error.ts +1 -1
- package/src/file.ts +39 -57
- package/src/filesystem.ts +133 -51
- package/src/stats.ts +48 -60
package/src/emulation/sync.ts
CHANGED
|
@@ -1,31 +1,14 @@
|
|
|
1
1
|
import { Buffer } from 'buffer';
|
|
2
2
|
import type * as fs from 'node:fs';
|
|
3
|
-
import {
|
|
3
|
+
import { Errno, ErrnoError } from '../error.js';
|
|
4
4
|
import { ActionType, File, isAppendable, isReadable, isWriteable, parseFlag, pathExistsAction, pathNotExistsAction } from '../file.js';
|
|
5
|
-
import { FileContents
|
|
6
|
-
import { BigIntStats, FileType, type
|
|
5
|
+
import { FileContents } from '../filesystem.js';
|
|
6
|
+
import { BigIntStats, FileType, type Stats } from '../stats.js';
|
|
7
7
|
import { normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '../utils.js';
|
|
8
8
|
import { COPYFILE_EXCL, F_OK, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLNK, S_IFMT, S_IFREG, S_IFSOCK } from './constants.js';
|
|
9
9
|
import { Dir, Dirent } from './dir.js';
|
|
10
10
|
import { dirname, join, parse } from './path.js';
|
|
11
|
-
import { cred, fd2file, fdMap,
|
|
12
|
-
|
|
13
|
-
type FileSystemMethod = {
|
|
14
|
-
[K in keyof FileSystem]: FileSystem[K] extends (...args: any[]) => unknown
|
|
15
|
-
? (name: K, resolveSymlinks: boolean, ...args: Parameters<FileSystem[K]>) => ReturnType<FileSystem[K]>
|
|
16
|
-
: never;
|
|
17
|
-
}[keyof FileSystem]; // https://stackoverflow.com/a/76335220/17637456
|
|
18
|
-
|
|
19
|
-
function wrap<M extends FileSystemMethod, RT extends ReturnType<M>>(...[name, resolveSymlinks, path, ...args]: Parameters<M>): RT {
|
|
20
|
-
path = normalizePath(path!);
|
|
21
|
-
const { fs, path: resolvedPath } = resolveMount(resolveSymlinks && existsSync(path) ? realpathSync(path) : path);
|
|
22
|
-
try {
|
|
23
|
-
// @ts-expect-error 2556 (since ...args is not correctly picked up as being a tuple)
|
|
24
|
-
return fs[name](resolvedPath, ...args) as RT;
|
|
25
|
-
} catch (e) {
|
|
26
|
-
throw fixError(e as Error, { [resolvedPath]: path });
|
|
27
|
-
}
|
|
28
|
-
}
|
|
11
|
+
import { _statfs, cred, fd2file, fdMap, file2fd, fixError, mounts, resolveMount } from './shared.js';
|
|
29
12
|
|
|
30
13
|
/**
|
|
31
14
|
* Synchronous rename.
|
|
@@ -78,8 +61,14 @@ existsSync satisfies typeof fs.existsSync;
|
|
|
78
61
|
export function statSync(path: fs.PathLike, options?: { bigint?: boolean }): Stats;
|
|
79
62
|
export function statSync(path: fs.PathLike, options: { bigint: true }): BigIntStats;
|
|
80
63
|
export function statSync(path: fs.PathLike, options?: fs.StatOptions): Stats | BigIntStats {
|
|
81
|
-
|
|
82
|
-
|
|
64
|
+
path = normalizePath(path);
|
|
65
|
+
const { fs, path: resolved } = resolveMount(existsSync(path) ? realpathSync(path) : path);
|
|
66
|
+
try {
|
|
67
|
+
const stats = fs.statSync(resolved, cred);
|
|
68
|
+
return options?.bigint ? new BigIntStats(stats) : stats;
|
|
69
|
+
} catch (e) {
|
|
70
|
+
throw fixError(e as Error, { [resolved]: path });
|
|
71
|
+
}
|
|
83
72
|
}
|
|
84
73
|
statSync satisfies typeof fs.statSync;
|
|
85
74
|
|
|
@@ -92,8 +81,14 @@ statSync satisfies typeof fs.statSync;
|
|
|
92
81
|
export function lstatSync(path: fs.PathLike, options?: { bigint?: boolean }): Stats;
|
|
93
82
|
export function lstatSync(path: fs.PathLike, options: { bigint: true }): BigIntStats;
|
|
94
83
|
export function lstatSync(path: fs.PathLike, options?: fs.StatOptions): Stats | BigIntStats {
|
|
95
|
-
|
|
96
|
-
|
|
84
|
+
path = normalizePath(path);
|
|
85
|
+
const { fs, path: resolved } = resolveMount(path);
|
|
86
|
+
try {
|
|
87
|
+
const stats = fs.statSync(resolved, cred);
|
|
88
|
+
return options?.bigint ? new BigIntStats(stats) : stats;
|
|
89
|
+
} catch (e) {
|
|
90
|
+
throw fixError(e as Error, { [resolved]: path });
|
|
91
|
+
}
|
|
97
92
|
}
|
|
98
93
|
lstatSync satisfies typeof fs.lstatSync;
|
|
99
94
|
|
|
@@ -117,34 +112,42 @@ truncateSync satisfies typeof fs.truncateSync;
|
|
|
117
112
|
* @param path
|
|
118
113
|
*/
|
|
119
114
|
export function unlinkSync(path: fs.PathLike): void {
|
|
120
|
-
|
|
115
|
+
path = normalizePath(path);
|
|
116
|
+
const { fs, path: resolved } = resolveMount(path);
|
|
117
|
+
try {
|
|
118
|
+
return fs.unlinkSync(resolved, cred);
|
|
119
|
+
} catch (e) {
|
|
120
|
+
throw fixError(e as Error, { [resolved]: path });
|
|
121
|
+
}
|
|
121
122
|
}
|
|
122
123
|
unlinkSync satisfies typeof fs.unlinkSync;
|
|
123
124
|
|
|
124
|
-
function _openSync(
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
function _openSync(path: fs.PathLike, _flag: fs.OpenMode, _mode?: fs.Mode | null, resolveSymlinks: boolean = true): File {
|
|
126
|
+
path = normalizePath(path);
|
|
127
|
+
const mode = normalizeMode(_mode, 0o644),
|
|
127
128
|
flag = parseFlag(_flag);
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
// File does not exist.
|
|
129
|
+
|
|
130
|
+
path = resolveSymlinks && existsSync(path) ? realpathSync(path) : path;
|
|
131
|
+
const { fs, path: resolved } = resolveMount(path);
|
|
132
|
+
|
|
133
|
+
if (!fs.existsSync(resolved, cred)) {
|
|
134
134
|
switch (pathNotExistsAction(flag)) {
|
|
135
135
|
case ActionType.CREATE:
|
|
136
136
|
// Ensure parent exists.
|
|
137
|
-
const parentStats: Stats =
|
|
137
|
+
const parentStats: Stats = fs.statSync(dirname(resolved), cred);
|
|
138
138
|
if (!parentStats.isDirectory()) {
|
|
139
139
|
throw ErrnoError.With('ENOTDIR', dirname(path), '_open');
|
|
140
140
|
}
|
|
141
|
-
return
|
|
141
|
+
return fs.createFileSync(resolved, flag, mode, cred);
|
|
142
142
|
case ActionType.THROW:
|
|
143
143
|
throw ErrnoError.With('ENOENT', path, '_open');
|
|
144
144
|
default:
|
|
145
145
|
throw new ErrnoError(Errno.EINVAL, 'Invalid FileFlag object.');
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
|
+
|
|
149
|
+
const stats: Stats = fs.statSync(resolved, cred);
|
|
150
|
+
|
|
148
151
|
if (!stats.hasAccess(mode, cred)) {
|
|
149
152
|
throw ErrnoError.With('EACCES', path, '_open');
|
|
150
153
|
}
|
|
@@ -155,16 +158,16 @@ function _openSync(_path: fs.PathLike, _flag: fs.OpenMode, _mode?: fs.Mode | nul
|
|
|
155
158
|
throw ErrnoError.With('EEXIST', path, '_open');
|
|
156
159
|
case ActionType.TRUNCATE:
|
|
157
160
|
// Delete file.
|
|
158
|
-
|
|
161
|
+
fs.unlinkSync(resolved, cred);
|
|
159
162
|
/*
|
|
160
163
|
Create file. Use the same mode as the old file.
|
|
161
164
|
Node itself modifies the ctime when this occurs, so this action
|
|
162
165
|
will preserve that behavior if the underlying file system
|
|
163
166
|
supports those properties.
|
|
164
167
|
*/
|
|
165
|
-
return
|
|
168
|
+
return fs.createFileSync(resolved, flag, stats.mode, cred);
|
|
166
169
|
case ActionType.NOP:
|
|
167
|
-
return
|
|
170
|
+
return fs.openFileSync(resolved, flag, cred);
|
|
168
171
|
default:
|
|
169
172
|
throw new ErrnoError(Errno.EINVAL, 'Invalid FileFlag object.');
|
|
170
173
|
}
|
|
@@ -372,7 +375,7 @@ export function writeSync(fd: number, data: FileContents, posOrOff?: number | nu
|
|
|
372
375
|
if (typeof data === 'string') {
|
|
373
376
|
// Signature 1: (fd, string, [position?, [encoding?]])
|
|
374
377
|
position = typeof posOrOff === 'number' ? posOrOff : null;
|
|
375
|
-
const encoding =
|
|
378
|
+
const encoding = typeof lenOrEnc === 'string' ? lenOrEnc : ('utf8' as BufferEncoding);
|
|
376
379
|
offset = 0;
|
|
377
380
|
buffer = Buffer.from(data, encoding);
|
|
378
381
|
length = buffer.byteLength;
|
|
@@ -380,7 +383,7 @@ export function writeSync(fd: number, data: FileContents, posOrOff?: number | nu
|
|
|
380
383
|
// Signature 2: (fd, buffer, offset, length, position?)
|
|
381
384
|
buffer = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
382
385
|
offset = posOrOff!;
|
|
383
|
-
length =
|
|
386
|
+
length = lenOrEnc as number;
|
|
384
387
|
position = typeof pos === 'number' ? pos : null;
|
|
385
388
|
}
|
|
386
389
|
|
|
@@ -463,7 +466,13 @@ futimesSync satisfies typeof fs.futimesSync;
|
|
|
463
466
|
* @param path
|
|
464
467
|
*/
|
|
465
468
|
export function rmdirSync(path: fs.PathLike): void {
|
|
466
|
-
|
|
469
|
+
path = normalizePath(path);
|
|
470
|
+
const { fs, path: resolved } = resolveMount(existsSync(path) ? realpathSync(path) : path);
|
|
471
|
+
try {
|
|
472
|
+
fs.rmdirSync(resolved, cred);
|
|
473
|
+
} catch (e) {
|
|
474
|
+
throw fixError(e as Error, { [resolved]: path });
|
|
475
|
+
}
|
|
467
476
|
}
|
|
468
477
|
rmdirSync satisfies typeof fs.rmdirSync;
|
|
469
478
|
|
|
@@ -477,9 +486,15 @@ export function mkdirSync(path: fs.PathLike, options: fs.MakeDirectoryOptions &
|
|
|
477
486
|
export function mkdirSync(path: fs.PathLike, options?: fs.Mode | (fs.MakeDirectoryOptions & { recursive?: false }) | null): void;
|
|
478
487
|
export function mkdirSync(path: fs.PathLike, options?: fs.Mode | fs.MakeDirectoryOptions | null): string | undefined;
|
|
479
488
|
export function mkdirSync(path: fs.PathLike, options?: fs.Mode | fs.MakeDirectoryOptions | null): string | undefined | void {
|
|
480
|
-
const mode: fs.Mode
|
|
489
|
+
const mode: fs.Mode = normalizeMode(typeof options == 'number' || typeof options == 'string' ? options : options?.mode, 0o777);
|
|
481
490
|
const recursive = typeof options == 'object' && options?.recursive;
|
|
482
|
-
|
|
491
|
+
path = normalizePath(path);
|
|
492
|
+
const { fs, path: resolved } = resolveMount(existsSync(path) ? realpathSync(path) : path);
|
|
493
|
+
try {
|
|
494
|
+
return fs.mkdirSync(resolved, mode, cred);
|
|
495
|
+
} catch (e) {
|
|
496
|
+
throw fixError(e as Error, { [resolved]: path });
|
|
497
|
+
}
|
|
483
498
|
}
|
|
484
499
|
mkdirSync satisfies typeof fs.mkdirSync;
|
|
485
500
|
|
|
@@ -496,7 +511,13 @@ export function readdirSync(
|
|
|
496
511
|
options?: { recursive?: boolean; encoding?: BufferEncoding | 'buffer' | null; withFileTypes?: boolean } | BufferEncoding | 'buffer' | null
|
|
497
512
|
): string[] | Dirent[] | Buffer[] {
|
|
498
513
|
path = normalizePath(path);
|
|
499
|
-
const
|
|
514
|
+
const { fs, path: resolved } = resolveMount(existsSync(path) ? realpathSync(path) : path);
|
|
515
|
+
let entries: string[];
|
|
516
|
+
try {
|
|
517
|
+
entries = fs.readdirSync(resolved, cred);
|
|
518
|
+
} catch (e) {
|
|
519
|
+
throw fixError(e as Error, { [resolved]: path });
|
|
520
|
+
}
|
|
500
521
|
for (const mount of mounts.keys()) {
|
|
501
522
|
if (!mount.startsWith(path)) {
|
|
502
523
|
continue;
|
|
@@ -508,7 +529,7 @@ export function readdirSync(
|
|
|
508
529
|
}
|
|
509
530
|
entries.push(entry);
|
|
510
531
|
}
|
|
511
|
-
return
|
|
532
|
+
return entries.map((entry: string) => {
|
|
512
533
|
if (typeof options == 'object' && options?.withFileTypes) {
|
|
513
534
|
return new Dirent(entry, statSync(join(path.toString(), entry)));
|
|
514
535
|
}
|
|
@@ -518,7 +539,7 @@ export function readdirSync(
|
|
|
518
539
|
}
|
|
519
540
|
|
|
520
541
|
return entry;
|
|
521
|
-
});
|
|
542
|
+
}) as string[] | Dirent[] | Buffer[];
|
|
522
543
|
}
|
|
523
544
|
readdirSync satisfies typeof fs.readdirSync;
|
|
524
545
|
|
|
@@ -530,8 +551,14 @@ readdirSync satisfies typeof fs.readdirSync;
|
|
|
530
551
|
* @param newpath
|
|
531
552
|
*/
|
|
532
553
|
export function linkSync(existing: fs.PathLike, newpath: fs.PathLike): void {
|
|
554
|
+
existing = normalizePath(existing);
|
|
533
555
|
newpath = normalizePath(newpath);
|
|
534
|
-
|
|
556
|
+
const { fs, path: resolved } = resolveMount(existing);
|
|
557
|
+
try {
|
|
558
|
+
return fs.linkSync(resolved, newpath, cred);
|
|
559
|
+
} catch (e) {
|
|
560
|
+
throw fixError(e as Error, { [resolved]: existing });
|
|
561
|
+
}
|
|
535
562
|
}
|
|
536
563
|
linkSync satisfies typeof fs.linkSync;
|
|
537
564
|
|
|
@@ -872,9 +899,11 @@ cpSync satisfies typeof fs.cpSync;
|
|
|
872
899
|
* @param path A path to an existing file or directory on the file system to be queried.
|
|
873
900
|
* @param callback
|
|
874
901
|
*/
|
|
875
|
-
export function statfsSync(path: fs.PathLike, options?: fs.StatFsOptions & { bigint?: false }): StatsFs;
|
|
876
|
-
export function statfsSync(path: fs.PathLike, options: fs.StatFsOptions & { bigint: true }): BigIntStatsFs;
|
|
877
|
-
export function statfsSync(path: fs.PathLike, options?: fs.StatFsOptions): StatsFs | BigIntStatsFs;
|
|
878
|
-
export function statfsSync(path: fs.PathLike, options?: fs.StatFsOptions): StatsFs | BigIntStatsFs {
|
|
879
|
-
|
|
902
|
+
export function statfsSync(path: fs.PathLike, options?: fs.StatFsOptions & { bigint?: false }): fs.StatsFs;
|
|
903
|
+
export function statfsSync(path: fs.PathLike, options: fs.StatFsOptions & { bigint: true }): fs.BigIntStatsFs;
|
|
904
|
+
export function statfsSync(path: fs.PathLike, options?: fs.StatFsOptions): fs.StatsFs | fs.BigIntStatsFs;
|
|
905
|
+
export function statfsSync(path: fs.PathLike, options?: fs.StatFsOptions): fs.StatsFs | fs.BigIntStatsFs {
|
|
906
|
+
path = normalizePath(path);
|
|
907
|
+
const { fs } = resolveMount(path);
|
|
908
|
+
return _statfs(fs, options?.bigint);
|
|
880
909
|
}
|
package/src/error.ts
CHANGED
|
@@ -279,7 +279,7 @@ export class ErrnoError extends Error implements NodeJS.ErrnoException {
|
|
|
279
279
|
public syscall: string = ''
|
|
280
280
|
) {
|
|
281
281
|
super(message);
|
|
282
|
-
this.code =
|
|
282
|
+
this.code = Errno[errno] as keyof typeof Errno;
|
|
283
283
|
this.message = `${this.code}: ${message}${this.path ? `, '${this.path}'` : ''}`;
|
|
284
284
|
}
|
|
285
285
|
|
package/src/file.ts
CHANGED
|
@@ -359,7 +359,7 @@ export abstract class File {
|
|
|
359
359
|
*/
|
|
360
360
|
export class PreloadFile<FS extends FileSystem> extends File {
|
|
361
361
|
protected _position: number = 0;
|
|
362
|
-
protected
|
|
362
|
+
protected dirty: boolean = false;
|
|
363
363
|
/**
|
|
364
364
|
* Creates a file with the given path and, optionally, the given contents. Note
|
|
365
365
|
* that, if contents is specified, it will be mutated by the file!
|
|
@@ -383,7 +383,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
|
|
|
383
383
|
public readonly path: string,
|
|
384
384
|
public readonly flag: string,
|
|
385
385
|
public readonly stats: Stats,
|
|
386
|
-
protected _buffer: Uint8Array = new Uint8Array(new ArrayBuffer(0, { maxByteLength: size_max }))
|
|
386
|
+
protected _buffer: Uint8Array = new Uint8Array(new ArrayBuffer(0, fs.metadata().noResizableBuffers ? {} : { maxByteLength: size_max }))
|
|
387
387
|
) {
|
|
388
388
|
super();
|
|
389
389
|
|
|
@@ -400,7 +400,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
|
|
|
400
400
|
throw new Error(`Size mismatch: buffer length ${_buffer.byteLength}, stats size ${this.stats.size}`);
|
|
401
401
|
}
|
|
402
402
|
|
|
403
|
-
this.
|
|
403
|
+
this.dirty = true;
|
|
404
404
|
}
|
|
405
405
|
|
|
406
406
|
/**
|
|
@@ -435,19 +435,19 @@ export class PreloadFile<FS extends FileSystem> extends File {
|
|
|
435
435
|
}
|
|
436
436
|
|
|
437
437
|
public async sync(): Promise<void> {
|
|
438
|
-
if (!this.
|
|
438
|
+
if (!this.dirty) {
|
|
439
439
|
return;
|
|
440
440
|
}
|
|
441
441
|
await this.fs.sync(this.path, this._buffer, this.stats);
|
|
442
|
-
this.
|
|
442
|
+
this.dirty = false;
|
|
443
443
|
}
|
|
444
444
|
|
|
445
445
|
public syncSync(): void {
|
|
446
|
-
if (!this.
|
|
446
|
+
if (!this.dirty) {
|
|
447
447
|
return;
|
|
448
448
|
}
|
|
449
449
|
this.fs.syncSync(this.path, this._buffer, this.stats);
|
|
450
|
-
this.
|
|
450
|
+
this.dirty = false;
|
|
451
451
|
}
|
|
452
452
|
|
|
453
453
|
public async close(): Promise<void> {
|
|
@@ -474,40 +474,33 @@ export class PreloadFile<FS extends FileSystem> extends File {
|
|
|
474
474
|
|
|
475
475
|
/**
|
|
476
476
|
* Asynchronous truncate.
|
|
477
|
-
* @param
|
|
477
|
+
* @param length
|
|
478
478
|
*/
|
|
479
|
-
public async truncate(
|
|
480
|
-
this.truncateSync(
|
|
481
|
-
|
|
482
|
-
return this.sync();
|
|
483
|
-
}
|
|
479
|
+
public async truncate(length: number): Promise<void> {
|
|
480
|
+
this.truncateSync(length);
|
|
481
|
+
return this.sync();
|
|
484
482
|
}
|
|
485
483
|
|
|
486
484
|
/**
|
|
487
485
|
* Synchronous truncate.
|
|
488
|
-
* @param
|
|
486
|
+
* @param length
|
|
489
487
|
*/
|
|
490
|
-
public truncateSync(
|
|
491
|
-
this.
|
|
488
|
+
public truncateSync(length: number): void {
|
|
489
|
+
this.dirty = true;
|
|
492
490
|
if (!isWriteable(this.flag)) {
|
|
493
491
|
throw new ErrnoError(Errno.EPERM, 'File not opened with a writeable mode.');
|
|
494
492
|
}
|
|
495
493
|
this.stats.mtimeMs = Date.now();
|
|
496
|
-
if (
|
|
497
|
-
const
|
|
498
|
-
// Write will set stats.size
|
|
499
|
-
this.writeSync(
|
|
500
|
-
if (isSynchronous(this.flag)) {
|
|
501
|
-
this.syncSync();
|
|
502
|
-
}
|
|
494
|
+
if (length > this._buffer.length) {
|
|
495
|
+
const data = new Uint8Array(length - this._buffer.length);
|
|
496
|
+
// Write will set stats.size and handle syncing.
|
|
497
|
+
this.writeSync(data, 0, data.length, this._buffer.length);
|
|
503
498
|
return;
|
|
504
499
|
}
|
|
505
|
-
this.stats.size =
|
|
506
|
-
// Truncate
|
|
507
|
-
this._buffer = this._buffer.
|
|
508
|
-
|
|
509
|
-
this.syncSync();
|
|
510
|
-
}
|
|
500
|
+
this.stats.size = length;
|
|
501
|
+
// Truncate.
|
|
502
|
+
this._buffer = this._buffer.slice(0, length);
|
|
503
|
+
this.syncSync();
|
|
511
504
|
}
|
|
512
505
|
|
|
513
506
|
/**
|
|
@@ -542,20 +535,21 @@ export class PreloadFile<FS extends FileSystem> extends File {
|
|
|
542
535
|
* @returns bytes written
|
|
543
536
|
*/
|
|
544
537
|
public writeSync(buffer: Uint8Array, offset: number = 0, length: number = this.stats.size, position: number = 0): number {
|
|
545
|
-
this.
|
|
538
|
+
this.dirty = true;
|
|
546
539
|
position ??= this.position;
|
|
547
540
|
if (!isWriteable(this.flag)) {
|
|
548
541
|
throw new ErrnoError(Errno.EPERM, 'File not opened with a writeable mode.');
|
|
549
542
|
}
|
|
550
|
-
const
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
543
|
+
const end = position + length;
|
|
544
|
+
|
|
545
|
+
if (end > this.stats.size) {
|
|
546
|
+
this.stats.size = end;
|
|
547
|
+
if (end > this._buffer.byteLength) {
|
|
548
|
+
if (this._buffer.buffer.resizable && this._buffer.buffer.maxByteLength! <= end) {
|
|
549
|
+
this._buffer.buffer.resize(end);
|
|
556
550
|
} else {
|
|
557
551
|
// Extend the buffer!
|
|
558
|
-
const newBuffer = new Uint8Array(new ArrayBuffer(
|
|
552
|
+
const newBuffer = new Uint8Array(new ArrayBuffer(end, this.fs.metadata().noResizableBuffers ? {} : { maxByteLength: size_max }));
|
|
559
553
|
newBuffer.set(this._buffer);
|
|
560
554
|
this._buffer = newBuffer;
|
|
561
555
|
}
|
|
@@ -565,11 +559,8 @@ export class PreloadFile<FS extends FileSystem> extends File {
|
|
|
565
559
|
this._buffer.set(slice, position);
|
|
566
560
|
const bytesWritten = slice.byteLength;
|
|
567
561
|
this.stats.mtimeMs = Date.now();
|
|
568
|
-
if (isSynchronous(this.flag)) {
|
|
569
|
-
this.syncSync();
|
|
570
|
-
return bytesWritten;
|
|
571
|
-
}
|
|
572
562
|
this.position = position + bytesWritten;
|
|
563
|
+
this.syncSync();
|
|
573
564
|
return bytesWritten;
|
|
574
565
|
}
|
|
575
566
|
|
|
@@ -608,6 +599,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
|
|
|
608
599
|
if (!isReadable(this.flag)) {
|
|
609
600
|
throw new ErrnoError(Errno.EPERM, 'File not opened with a readable mode.');
|
|
610
601
|
}
|
|
602
|
+
this.dirty = true;
|
|
611
603
|
position ??= this.position;
|
|
612
604
|
let end = position + length;
|
|
613
605
|
if (end > this.stats.size) {
|
|
@@ -616,6 +608,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
|
|
|
616
608
|
this.stats.atimeMs = Date.now();
|
|
617
609
|
this._position = end;
|
|
618
610
|
const bytesRead = end - position;
|
|
611
|
+
this.syncSync();
|
|
619
612
|
if (bytesRead == 0) {
|
|
620
613
|
// No copy/read. Return immediatly for better performance
|
|
621
614
|
return bytesRead;
|
|
@@ -637,7 +630,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
|
|
|
637
630
|
* @param mode
|
|
638
631
|
*/
|
|
639
632
|
public chmodSync(mode: number): void {
|
|
640
|
-
this.
|
|
633
|
+
this.dirty = true;
|
|
641
634
|
this.stats.chmod(mode);
|
|
642
635
|
this.syncSync();
|
|
643
636
|
}
|
|
@@ -657,7 +650,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
|
|
|
657
650
|
* @param gid
|
|
658
651
|
*/
|
|
659
652
|
public chownSync(uid: number, gid: number): void {
|
|
660
|
-
this.
|
|
653
|
+
this.dirty = true;
|
|
661
654
|
this.stats.chown(uid, gid);
|
|
662
655
|
this.syncSync();
|
|
663
656
|
}
|
|
@@ -667,31 +660,20 @@ export class PreloadFile<FS extends FileSystem> extends File {
|
|
|
667
660
|
}
|
|
668
661
|
|
|
669
662
|
public utimesSync(atime: Date, mtime: Date): void {
|
|
670
|
-
this.
|
|
663
|
+
this.dirty = true;
|
|
671
664
|
this.stats.atime = atime;
|
|
672
665
|
this.stats.mtime = mtime;
|
|
673
666
|
this.syncSync();
|
|
674
667
|
}
|
|
675
668
|
|
|
676
|
-
protected isDirty(): boolean {
|
|
677
|
-
return this._dirty;
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
/**
|
|
681
|
-
* Resets the dirty bit. Should only be called after a sync has completed successfully.
|
|
682
|
-
*/
|
|
683
|
-
protected resetDirty() {
|
|
684
|
-
this._dirty = false;
|
|
685
|
-
}
|
|
686
|
-
|
|
687
669
|
public _setType(type: FileType): Promise<void> {
|
|
688
|
-
this.
|
|
670
|
+
this.dirty = true;
|
|
689
671
|
this.stats.mode = (this.stats.mode & ~S_IFMT) | type;
|
|
690
672
|
return this.sync();
|
|
691
673
|
}
|
|
692
674
|
|
|
693
675
|
public _setTypeSync(type: FileType): void {
|
|
694
|
-
this.
|
|
676
|
+
this.dirty = true;
|
|
695
677
|
this.stats.mode = (this.stats.mode & ~S_IFMT) | type;
|
|
696
678
|
this.syncSync();
|
|
697
679
|
}
|