@zenfs/core 0.12.1 → 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/index/fs.d.ts +1 -0
- package/dist/backends/overlay.js +1 -1
- package/dist/backends/port/fs.d.ts +1 -0
- package/dist/browser.min.js +4 -8
- package/dist/browser.min.js.map +3 -3
- package/dist/emulation/async.d.ts +4 -4
- package/dist/emulation/index.d.ts +1 -1
- package/dist/emulation/index.js +1 -1
- package/dist/emulation/promises.d.ts +4 -4
- package/dist/emulation/promises.js +33 -45
- 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 +86 -60
- package/dist/file.d.ts +5 -10
- package/dist/file.js +30 -47
- package/dist/filesystem.d.ts +23 -1
- package/dist/filesystem.js +2 -2
- package/dist/stats.d.ts +16 -16
- package/dist/stats.js +42 -49
- package/package.json +1 -1
- package/src/backends/overlay.ts +1 -1
- package/src/emulation/async.ts +6 -6
- package/src/emulation/index.ts +1 -1
- package/src/emulation/promises.ts +39 -48
- package/src/emulation/shared.ts +22 -1
- package/src/emulation/sync.ts +89 -71
- package/src/file.ts +30 -49
- package/src/filesystem.ts +29 -2
- package/src/stats.ts +46 -58
package/src/emulation/shared.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
// Utilities and shared data
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import type { BigIntStatsFs, StatsFs } from 'node:fs';
|
|
4
4
|
import { InMemory } from '../backends/memory.js';
|
|
5
5
|
import { Cred, rootCred } from '../cred.js';
|
|
6
|
+
import { Errno, ErrnoError } from '../error.js';
|
|
6
7
|
import type { File } from '../file.js';
|
|
7
8
|
import { FileSystem } from '../filesystem.js';
|
|
9
|
+
import { size_max } from '../inode.js';
|
|
10
|
+
import { ZenFsType } from '../stats.js';
|
|
8
11
|
import { normalizePath } from '../utils.js';
|
|
9
12
|
import { resolve, type AbsolutePath } from './path.js';
|
|
10
13
|
|
|
@@ -117,3 +120,21 @@ export function mountObject(mounts: MountObject): void {
|
|
|
117
120
|
mount(point, fs);
|
|
118
121
|
}
|
|
119
122
|
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* @hidden
|
|
126
|
+
*/
|
|
127
|
+
export function _statfs<const T extends boolean>(fs: FileSystem, bigint?: T): T extends true ? BigIntStatsFs : StatsFs {
|
|
128
|
+
const md = fs.metadata();
|
|
129
|
+
const bs = md.blockSize || 4096;
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
type: (bigint ? BigInt : Number)(md.type || ZenFsType),
|
|
133
|
+
bsize: (bigint ? BigInt : Number)(bs),
|
|
134
|
+
ffree: (bigint ? BigInt : Number)(md.freeNodes || size_max),
|
|
135
|
+
files: (bigint ? BigInt : Number)(md.totalNodes || size_max),
|
|
136
|
+
bavail: (bigint ? BigInt : Number)(md.freeSpace / bs),
|
|
137
|
+
bfree: (bigint ? BigInt : Number)(md.freeSpace / bs),
|
|
138
|
+
blocks: (bigint ? BigInt : Number)(md.totalSpace / bs),
|
|
139
|
+
} as T extends true ? BigIntStatsFs : StatsFs;
|
|
140
|
+
}
|
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,45 +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
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
return wrap('createFileSync', resolveSymlinks, path, flag, mode, cred);
|
|
147
|
-
case ActionType.THROW:
|
|
148
|
-
throw ErrnoError.With('ENOENT', path, '_open');
|
|
149
|
-
default:
|
|
150
|
-
throw new ErrnoError(Errno.EINVAL, 'Invalid FileFlag object.');
|
|
151
|
-
}
|
|
152
|
-
} catch (_) {
|
|
153
|
-
const ex = _ as ErrnoError;
|
|
154
|
-
ex.stack += '\n<original>\n';
|
|
155
|
-
ex.stack += (original as Error).stack;
|
|
156
|
-
throw ex;
|
|
129
|
+
|
|
130
|
+
path = resolveSymlinks && existsSync(path) ? realpathSync(path) : path;
|
|
131
|
+
const { fs, path: resolved } = resolveMount(path);
|
|
132
|
+
|
|
133
|
+
if (!fs.existsSync(resolved, cred)) {
|
|
134
|
+
switch (pathNotExistsAction(flag)) {
|
|
135
|
+
case ActionType.CREATE:
|
|
136
|
+
// Ensure parent exists.
|
|
137
|
+
const parentStats: Stats = fs.statSync(dirname(resolved), cred);
|
|
138
|
+
if (!parentStats.isDirectory()) {
|
|
139
|
+
throw ErrnoError.With('ENOTDIR', dirname(path), '_open');
|
|
140
|
+
}
|
|
141
|
+
return fs.createFileSync(resolved, flag, mode, cred);
|
|
142
|
+
case ActionType.THROW:
|
|
143
|
+
throw ErrnoError.With('ENOENT', path, '_open');
|
|
144
|
+
default:
|
|
145
|
+
throw new ErrnoError(Errno.EINVAL, 'Invalid FileFlag object.');
|
|
157
146
|
}
|
|
158
147
|
}
|
|
148
|
+
|
|
149
|
+
const stats: Stats = fs.statSync(resolved, cred);
|
|
150
|
+
|
|
159
151
|
if (!stats.hasAccess(mode, cred)) {
|
|
160
152
|
throw ErrnoError.With('EACCES', path, '_open');
|
|
161
153
|
}
|
|
@@ -166,16 +158,16 @@ function _openSync(_path: fs.PathLike, _flag: fs.OpenMode, _mode?: fs.Mode | nul
|
|
|
166
158
|
throw ErrnoError.With('EEXIST', path, '_open');
|
|
167
159
|
case ActionType.TRUNCATE:
|
|
168
160
|
// Delete file.
|
|
169
|
-
|
|
161
|
+
fs.unlinkSync(resolved, cred);
|
|
170
162
|
/*
|
|
171
163
|
Create file. Use the same mode as the old file.
|
|
172
164
|
Node itself modifies the ctime when this occurs, so this action
|
|
173
165
|
will preserve that behavior if the underlying file system
|
|
174
166
|
supports those properties.
|
|
175
167
|
*/
|
|
176
|
-
return
|
|
168
|
+
return fs.createFileSync(resolved, flag, stats.mode, cred);
|
|
177
169
|
case ActionType.NOP:
|
|
178
|
-
return
|
|
170
|
+
return fs.openFileSync(resolved, flag, cred);
|
|
179
171
|
default:
|
|
180
172
|
throw new ErrnoError(Errno.EINVAL, 'Invalid FileFlag object.');
|
|
181
173
|
}
|
|
@@ -474,7 +466,13 @@ futimesSync satisfies typeof fs.futimesSync;
|
|
|
474
466
|
* @param path
|
|
475
467
|
*/
|
|
476
468
|
export function rmdirSync(path: fs.PathLike): void {
|
|
477
|
-
|
|
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
|
+
}
|
|
478
476
|
}
|
|
479
477
|
rmdirSync satisfies typeof fs.rmdirSync;
|
|
480
478
|
|
|
@@ -488,9 +486,15 @@ export function mkdirSync(path: fs.PathLike, options: fs.MakeDirectoryOptions &
|
|
|
488
486
|
export function mkdirSync(path: fs.PathLike, options?: fs.Mode | (fs.MakeDirectoryOptions & { recursive?: false }) | null): void;
|
|
489
487
|
export function mkdirSync(path: fs.PathLike, options?: fs.Mode | fs.MakeDirectoryOptions | null): string | undefined;
|
|
490
488
|
export function mkdirSync(path: fs.PathLike, options?: fs.Mode | fs.MakeDirectoryOptions | null): string | undefined | void {
|
|
491
|
-
const mode: fs.Mode
|
|
489
|
+
const mode: fs.Mode = normalizeMode(typeof options == 'number' || typeof options == 'string' ? options : options?.mode, 0o777);
|
|
492
490
|
const recursive = typeof options == 'object' && options?.recursive;
|
|
493
|
-
|
|
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
|
+
}
|
|
494
498
|
}
|
|
495
499
|
mkdirSync satisfies typeof fs.mkdirSync;
|
|
496
500
|
|
|
@@ -507,7 +511,13 @@ export function readdirSync(
|
|
|
507
511
|
options?: { recursive?: boolean; encoding?: BufferEncoding | 'buffer' | null; withFileTypes?: boolean } | BufferEncoding | 'buffer' | null
|
|
508
512
|
): string[] | Dirent[] | Buffer[] {
|
|
509
513
|
path = normalizePath(path);
|
|
510
|
-
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
|
+
}
|
|
511
521
|
for (const mount of mounts.keys()) {
|
|
512
522
|
if (!mount.startsWith(path)) {
|
|
513
523
|
continue;
|
|
@@ -541,8 +551,14 @@ readdirSync satisfies typeof fs.readdirSync;
|
|
|
541
551
|
* @param newpath
|
|
542
552
|
*/
|
|
543
553
|
export function linkSync(existing: fs.PathLike, newpath: fs.PathLike): void {
|
|
554
|
+
existing = normalizePath(existing);
|
|
544
555
|
newpath = normalizePath(newpath);
|
|
545
|
-
|
|
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
|
+
}
|
|
546
562
|
}
|
|
547
563
|
linkSync satisfies typeof fs.linkSync;
|
|
548
564
|
|
|
@@ -883,9 +899,11 @@ cpSync satisfies typeof fs.cpSync;
|
|
|
883
899
|
* @param path A path to an existing file or directory on the file system to be queried.
|
|
884
900
|
* @param callback
|
|
885
901
|
*/
|
|
886
|
-
export function statfsSync(path: fs.PathLike, options?: fs.StatFsOptions & { bigint?: false }): StatsFs;
|
|
887
|
-
export function statfsSync(path: fs.PathLike, options: fs.StatFsOptions & { bigint: true }): BigIntStatsFs;
|
|
888
|
-
export function statfsSync(path: fs.PathLike, options?: fs.StatFsOptions): StatsFs | BigIntStatsFs;
|
|
889
|
-
export function statfsSync(path: fs.PathLike, options?: fs.StatFsOptions): StatsFs | BigIntStatsFs {
|
|
890
|
-
|
|
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);
|
|
891
909
|
}
|
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!
|
|
@@ -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,7 +535,7 @@ 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.');
|
|
@@ -566,11 +559,8 @@ export class PreloadFile<FS extends FileSystem> extends File {
|
|
|
566
559
|
this._buffer.set(slice, position);
|
|
567
560
|
const bytesWritten = slice.byteLength;
|
|
568
561
|
this.stats.mtimeMs = Date.now();
|
|
569
|
-
if (isSynchronous(this.flag)) {
|
|
570
|
-
this.syncSync();
|
|
571
|
-
return bytesWritten;
|
|
572
|
-
}
|
|
573
562
|
this.position = position + bytesWritten;
|
|
563
|
+
this.syncSync();
|
|
574
564
|
return bytesWritten;
|
|
575
565
|
}
|
|
576
566
|
|
|
@@ -609,6 +599,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
|
|
|
609
599
|
if (!isReadable(this.flag)) {
|
|
610
600
|
throw new ErrnoError(Errno.EPERM, 'File not opened with a readable mode.');
|
|
611
601
|
}
|
|
602
|
+
this.dirty = true;
|
|
612
603
|
position ??= this.position;
|
|
613
604
|
let end = position + length;
|
|
614
605
|
if (end > this.stats.size) {
|
|
@@ -617,6 +608,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
|
|
|
617
608
|
this.stats.atimeMs = Date.now();
|
|
618
609
|
this._position = end;
|
|
619
610
|
const bytesRead = end - position;
|
|
611
|
+
this.syncSync();
|
|
620
612
|
if (bytesRead == 0) {
|
|
621
613
|
// No copy/read. Return immediatly for better performance
|
|
622
614
|
return bytesRead;
|
|
@@ -638,7 +630,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
|
|
|
638
630
|
* @param mode
|
|
639
631
|
*/
|
|
640
632
|
public chmodSync(mode: number): void {
|
|
641
|
-
this.
|
|
633
|
+
this.dirty = true;
|
|
642
634
|
this.stats.chmod(mode);
|
|
643
635
|
this.syncSync();
|
|
644
636
|
}
|
|
@@ -658,7 +650,7 @@ export class PreloadFile<FS extends FileSystem> extends File {
|
|
|
658
650
|
* @param gid
|
|
659
651
|
*/
|
|
660
652
|
public chownSync(uid: number, gid: number): void {
|
|
661
|
-
this.
|
|
653
|
+
this.dirty = true;
|
|
662
654
|
this.stats.chown(uid, gid);
|
|
663
655
|
this.syncSync();
|
|
664
656
|
}
|
|
@@ -668,31 +660,20 @@ export class PreloadFile<FS extends FileSystem> extends File {
|
|
|
668
660
|
}
|
|
669
661
|
|
|
670
662
|
public utimesSync(atime: Date, mtime: Date): void {
|
|
671
|
-
this.
|
|
663
|
+
this.dirty = true;
|
|
672
664
|
this.stats.atime = atime;
|
|
673
665
|
this.stats.mtime = mtime;
|
|
674
666
|
this.syncSync();
|
|
675
667
|
}
|
|
676
668
|
|
|
677
|
-
protected isDirty(): boolean {
|
|
678
|
-
return this._dirty;
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
/**
|
|
682
|
-
* Resets the dirty bit. Should only be called after a sync has completed successfully.
|
|
683
|
-
*/
|
|
684
|
-
protected resetDirty() {
|
|
685
|
-
this._dirty = false;
|
|
686
|
-
}
|
|
687
|
-
|
|
688
669
|
public _setType(type: FileType): Promise<void> {
|
|
689
|
-
this.
|
|
670
|
+
this.dirty = true;
|
|
690
671
|
this.stats.mode = (this.stats.mode & ~S_IFMT) | type;
|
|
691
672
|
return this.sync();
|
|
692
673
|
}
|
|
693
674
|
|
|
694
675
|
public _setTypeSync(type: FileType): void {
|
|
695
|
-
this.
|
|
676
|
+
this.dirty = true;
|
|
696
677
|
this.stats.mode = (this.stats.mode & ~S_IFMT) | type;
|
|
697
678
|
this.syncSync();
|
|
698
679
|
}
|
package/src/filesystem.ts
CHANGED
|
@@ -44,6 +44,27 @@ export interface FileSystemMetadata {
|
|
|
44
44
|
* @default false
|
|
45
45
|
*/
|
|
46
46
|
noAsyncCache: boolean;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The optimal block size to use with the file system
|
|
50
|
+
* @default 4096
|
|
51
|
+
*/
|
|
52
|
+
blockSize?: number;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Total number of (file) nodes available
|
|
56
|
+
*/
|
|
57
|
+
totalNodes?: number;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Number of free (file) nodes available
|
|
61
|
+
*/
|
|
62
|
+
freeNodes?: number;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The type of the FS
|
|
66
|
+
*/
|
|
67
|
+
type?: number;
|
|
47
68
|
}
|
|
48
69
|
|
|
49
70
|
/**
|
|
@@ -57,6 +78,12 @@ export interface FileSystemMetadata {
|
|
|
57
78
|
* - All arguments are present. Any optional arguments at the Node API level have been passed in with their default values.
|
|
58
79
|
*/
|
|
59
80
|
export abstract class FileSystem {
|
|
81
|
+
/**
|
|
82
|
+
* Numeric type, used for statfs
|
|
83
|
+
* @internal @protected
|
|
84
|
+
*/
|
|
85
|
+
_type?: number;
|
|
86
|
+
|
|
60
87
|
/**
|
|
61
88
|
* Get metadata about the current file system
|
|
62
89
|
*/
|
|
@@ -68,11 +95,11 @@ export abstract class FileSystem {
|
|
|
68
95
|
freeSpace: 0,
|
|
69
96
|
noResizableBuffers: false,
|
|
70
97
|
noAsyncCache: false,
|
|
98
|
+
type: this._type,
|
|
71
99
|
};
|
|
72
100
|
}
|
|
73
101
|
|
|
74
|
-
|
|
75
|
-
public constructor(options?: object) {}
|
|
102
|
+
public constructor() {}
|
|
76
103
|
|
|
77
104
|
public async ready(): Promise<void> {}
|
|
78
105
|
|