@zenfs/core 1.1.6 → 1.2.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/dist/backends/file_index.js +0 -3
- package/dist/backends/overlay.js +0 -8
- package/dist/backends/store/fs.js +4 -17
- package/dist/config.d.ts +14 -0
- package/dist/config.js +4 -0
- package/dist/devices.js +0 -12
- package/dist/emulation/cache.d.ts +21 -0
- package/dist/emulation/cache.js +36 -0
- package/dist/emulation/promises.d.ts +9 -14
- package/dist/emulation/promises.js +71 -48
- package/dist/emulation/shared.d.ts +22 -0
- package/dist/emulation/shared.js +6 -0
- package/dist/emulation/sync.d.ts +11 -20
- package/dist/emulation/sync.js +44 -23
- package/package.json +4 -2
- package/scripts/test.js +14 -1
- package/src/backends/backend.ts +160 -0
- package/src/backends/fetch.ts +180 -0
- package/src/backends/file_index.ts +206 -0
- package/src/backends/memory.ts +50 -0
- package/src/backends/overlay.ts +560 -0
- package/src/backends/port/fs.ts +335 -0
- package/src/backends/port/readme.md +54 -0
- package/src/backends/port/rpc.ts +167 -0
- package/src/backends/readme.md +3 -0
- package/src/backends/store/fs.ts +700 -0
- package/src/backends/store/readme.md +9 -0
- package/src/backends/store/simple.ts +146 -0
- package/src/backends/store/store.ts +173 -0
- package/src/config.ts +173 -0
- package/src/credentials.ts +31 -0
- package/src/devices.ts +459 -0
- package/src/emulation/async.ts +834 -0
- package/src/emulation/cache.ts +44 -0
- package/src/emulation/constants.ts +182 -0
- package/src/emulation/dir.ts +138 -0
- package/src/emulation/index.ts +8 -0
- package/src/emulation/path.ts +440 -0
- package/src/emulation/promises.ts +1133 -0
- package/src/emulation/shared.ts +160 -0
- package/src/emulation/streams.ts +34 -0
- package/src/emulation/sync.ts +867 -0
- package/src/emulation/watchers.ts +193 -0
- package/src/error.ts +307 -0
- package/src/file.ts +661 -0
- package/src/filesystem.ts +174 -0
- package/src/index.ts +25 -0
- package/src/inode.ts +132 -0
- package/src/mixins/async.ts +208 -0
- package/src/mixins/index.ts +5 -0
- package/src/mixins/mutexed.ts +257 -0
- package/src/mixins/readonly.ts +96 -0
- package/src/mixins/shared.ts +25 -0
- package/src/mixins/sync.ts +58 -0
- package/src/polyfills.ts +21 -0
- package/src/stats.ts +363 -0
- package/src/utils.ts +288 -0
- package/tests/fs/readdir.test.ts +3 -3
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// Utilities and shared data
|
|
2
|
+
|
|
3
|
+
import type { BigIntStatsFs, StatsFs } from 'node:fs';
|
|
4
|
+
import { InMemory } from '../backends/memory.js';
|
|
5
|
+
import { Errno, ErrnoError } from '../error.js';
|
|
6
|
+
import type { File } from '../file.js';
|
|
7
|
+
import type { FileSystem } from '../filesystem.js';
|
|
8
|
+
import { normalizePath } from '../utils.js';
|
|
9
|
+
import { resolve, type AbsolutePath } from './path.js';
|
|
10
|
+
import { size_max } from './constants.js';
|
|
11
|
+
|
|
12
|
+
// descriptors
|
|
13
|
+
export const fdMap: Map<number, File> = new Map();
|
|
14
|
+
let nextFd = 100;
|
|
15
|
+
export function file2fd(file: File): number {
|
|
16
|
+
const fd = nextFd++;
|
|
17
|
+
fdMap.set(fd, file);
|
|
18
|
+
return fd;
|
|
19
|
+
}
|
|
20
|
+
export function fd2file(fd: number): File {
|
|
21
|
+
if (!fdMap.has(fd)) {
|
|
22
|
+
throw new ErrnoError(Errno.EBADF);
|
|
23
|
+
}
|
|
24
|
+
return fdMap.get(fd)!;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type MountObject = Record<AbsolutePath, FileSystem>;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The map of mount points
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
33
|
+
export const mounts: Map<string, FileSystem> = new Map();
|
|
34
|
+
|
|
35
|
+
// Set a default root.
|
|
36
|
+
mount('/', InMemory.create({ name: 'root' }));
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Mounts the file system at `mountPoint`.
|
|
40
|
+
*/
|
|
41
|
+
export function mount(mountPoint: string, fs: FileSystem): void {
|
|
42
|
+
if (mountPoint[0] !== '/') {
|
|
43
|
+
mountPoint = '/' + mountPoint;
|
|
44
|
+
}
|
|
45
|
+
mountPoint = resolve(mountPoint);
|
|
46
|
+
if (mounts.has(mountPoint)) {
|
|
47
|
+
throw new ErrnoError(Errno.EINVAL, 'Mount point ' + mountPoint + ' is already in use.');
|
|
48
|
+
}
|
|
49
|
+
mounts.set(mountPoint, fs);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Unmounts the file system at `mountPoint`.
|
|
54
|
+
*/
|
|
55
|
+
export function umount(mountPoint: string): void {
|
|
56
|
+
if (mountPoint[0] !== '/') {
|
|
57
|
+
mountPoint = `/${mountPoint}`;
|
|
58
|
+
}
|
|
59
|
+
mountPoint = resolve(mountPoint);
|
|
60
|
+
if (!mounts.has(mountPoint)) {
|
|
61
|
+
throw new ErrnoError(Errno.EINVAL, 'Mount point ' + mountPoint + ' is already unmounted.');
|
|
62
|
+
}
|
|
63
|
+
mounts.delete(mountPoint);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Gets the internal FileSystem for the path, then returns it along with the path relative to the FS' root
|
|
68
|
+
*/
|
|
69
|
+
export function resolveMount(path: string): { fs: FileSystem; path: string; mountPoint: string } {
|
|
70
|
+
path = normalizePath(path);
|
|
71
|
+
// Maybe do something for devices here
|
|
72
|
+
const sortedMounts = [...mounts].sort((a, b) => (a[0].length > b[0].length ? -1 : 1)); // descending order of the string length
|
|
73
|
+
for (const [mountPoint, fs] of sortedMounts) {
|
|
74
|
+
// We know path is normalized, so it would be a substring of the mount point.
|
|
75
|
+
if (mountPoint.length <= path.length && path.startsWith(mountPoint)) {
|
|
76
|
+
path = path.slice(mountPoint.length > 1 ? mountPoint.length : 0); // Resolve the path relative to the mount point
|
|
77
|
+
if (path === '') {
|
|
78
|
+
path = '/';
|
|
79
|
+
}
|
|
80
|
+
return { fs, path, mountPoint };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
throw new ErrnoError(Errno.EIO, 'ZenFS not initialized with a file system');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Reverse maps the paths in text from the mounted FileSystem to the global path
|
|
89
|
+
* @hidden
|
|
90
|
+
*/
|
|
91
|
+
export function fixPaths(text: string, paths: Record<string, string>): string {
|
|
92
|
+
for (const [from, to] of Object.entries(paths)) {
|
|
93
|
+
text = text?.replaceAll(from, to);
|
|
94
|
+
}
|
|
95
|
+
return text;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Fix paths in error stacks
|
|
100
|
+
* @hidden
|
|
101
|
+
*/
|
|
102
|
+
export function fixError<E extends ErrnoError>(e: E, paths: Record<string, string>): E {
|
|
103
|
+
if (typeof e.stack == 'string') {
|
|
104
|
+
e.stack = fixPaths(e.stack, paths);
|
|
105
|
+
}
|
|
106
|
+
e.message = fixPaths(e.message, paths);
|
|
107
|
+
return e;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function mountObject(mounts: MountObject): void {
|
|
111
|
+
if ('/' in mounts) {
|
|
112
|
+
umount('/');
|
|
113
|
+
}
|
|
114
|
+
for (const [point, fs] of Object.entries(mounts)) {
|
|
115
|
+
mount(point, fs);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* @hidden
|
|
121
|
+
*/
|
|
122
|
+
export function _statfs<const T extends boolean>(fs: FileSystem, bigint?: T): T extends true ? BigIntStatsFs : StatsFs {
|
|
123
|
+
const md = fs.metadata();
|
|
124
|
+
const bs = md.blockSize || 4096;
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
type: (bigint ? BigInt : Number)(md.type),
|
|
128
|
+
bsize: (bigint ? BigInt : Number)(bs),
|
|
129
|
+
ffree: (bigint ? BigInt : Number)(md.freeNodes || size_max),
|
|
130
|
+
files: (bigint ? BigInt : Number)(md.totalNodes || size_max),
|
|
131
|
+
bavail: (bigint ? BigInt : Number)(md.freeSpace / bs),
|
|
132
|
+
bfree: (bigint ? BigInt : Number)(md.freeSpace / bs),
|
|
133
|
+
blocks: (bigint ? BigInt : Number)(md.totalSpace / bs),
|
|
134
|
+
} as T extends true ? BigIntStatsFs : StatsFs;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export const config = {
|
|
138
|
+
/**
|
|
139
|
+
* Whether to perform access checks
|
|
140
|
+
*/
|
|
141
|
+
checkAccess: true,
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Options used for caching, among other things.
|
|
146
|
+
* @internal *UNSTABLE*
|
|
147
|
+
*/
|
|
148
|
+
export interface InternalOptions {
|
|
149
|
+
/**
|
|
150
|
+
* If true, then this readdir was called from another function.
|
|
151
|
+
* In this case, don't clear the cache when done.
|
|
152
|
+
* @internal *UNSTABLE*
|
|
153
|
+
*/
|
|
154
|
+
_isIndirect?: boolean;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface ReaddirOptions extends InternalOptions {
|
|
158
|
+
withFileTypes?: boolean;
|
|
159
|
+
recursive?: boolean;
|
|
160
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type * as Node from 'node:fs';
|
|
2
|
+
import { Readable, Writable } from 'readable-stream';
|
|
3
|
+
import type { Callback } from '../utils.js';
|
|
4
|
+
import { ErrnoError, Errno } from '../error.js';
|
|
5
|
+
|
|
6
|
+
export class ReadStream extends Readable implements Node.ReadStream {
|
|
7
|
+
close(callback: Callback = () => null): void {
|
|
8
|
+
try {
|
|
9
|
+
super.destroy();
|
|
10
|
+
super.emit('close');
|
|
11
|
+
callback();
|
|
12
|
+
} catch (err) {
|
|
13
|
+
callback(new ErrnoError(Errno.EIO, (err as Error).toString()));
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
declare bytesRead: number;
|
|
17
|
+
declare path: string | Buffer;
|
|
18
|
+
declare pending: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class WriteStream extends Writable implements Node.WriteStream {
|
|
22
|
+
close(callback: Callback = () => null): void {
|
|
23
|
+
try {
|
|
24
|
+
super.destroy();
|
|
25
|
+
super.emit('close');
|
|
26
|
+
callback();
|
|
27
|
+
} catch (err) {
|
|
28
|
+
callback(new ErrnoError(Errno.EIO, (err as Error).toString()));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
declare bytesWritten: number;
|
|
32
|
+
declare path: string | Buffer;
|
|
33
|
+
declare pending: boolean;
|
|
34
|
+
}
|