@zenfs/core 2.4.1 → 2.4.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/COPYING.md +18 -0
- package/{readme.md → README.md} +16 -74
- package/dist/backends/fetch.js +1 -1
- package/dist/backends/memory.js +1 -1
- package/dist/backends/passthrough.d.ts +1 -2
- package/dist/backends/single_buffer.js +1 -1
- package/dist/backends/store/fs.js +4 -4
- package/dist/config.js +15 -15
- package/dist/context.js +3 -2
- package/dist/index.d.ts +9 -3
- package/dist/index.js +9 -4
- package/dist/internal/contexts.d.ts +5 -4
- package/dist/internal/devices.js +1 -1
- package/dist/internal/error.d.ts +11 -2
- package/dist/internal/error.js +38 -2
- package/dist/internal/file_index.js +1 -1
- package/dist/internal/index.d.ts +1 -0
- package/dist/internal/index.js +2 -1
- package/dist/internal/index_fs.js +1 -1
- package/dist/internal/inode.d.ts +51 -2
- package/dist/internal/inode.js +18 -2
- package/dist/mixins/shared.js +1 -1
- package/dist/node/async.d.ts +278 -0
- package/dist/node/async.js +518 -0
- package/dist/node/compat.d.ts +4 -0
- package/dist/node/compat.js +6 -0
- package/dist/node/dir.d.ts +78 -0
- package/dist/node/dir.js +150 -0
- package/dist/node/index.d.ts +8 -0
- package/dist/node/index.js +8 -0
- package/dist/{vfs → node}/promises.d.ts +10 -66
- package/dist/{vfs → node}/promises.js +141 -478
- package/dist/{vfs → node}/stats.d.ts +0 -4
- package/dist/{vfs → node}/stats.js +1 -16
- package/dist/{vfs → node}/streams.js +2 -2
- package/dist/node/sync.d.ts +252 -0
- package/dist/node/sync.js +682 -0
- package/dist/node/types.d.ts +21 -0
- package/dist/utils.d.ts +1 -7
- package/dist/utils.js +0 -6
- package/dist/vfs/acl.js +1 -1
- package/dist/vfs/async.d.ts +22 -278
- package/dist/vfs/async.js +212 -501
- package/dist/vfs/dir.d.ts +5 -82
- package/dist/vfs/dir.js +5 -233
- package/dist/vfs/file.d.ts +52 -13
- package/dist/vfs/file.js +167 -25
- package/dist/vfs/flags.js +1 -1
- package/dist/vfs/index.d.ts +2 -5
- package/dist/vfs/index.js +2 -5
- package/dist/vfs/shared.d.ts +25 -1
- package/dist/vfs/shared.js +6 -4
- package/dist/vfs/sync.d.ts +17 -245
- package/dist/vfs/sync.js +129 -773
- package/dist/vfs/watchers.d.ts +1 -1
- package/dist/vfs/watchers.js +2 -2
- package/dist/vfs/xattr.js +1 -1
- package/eslint.shared.js +1 -0
- package/package.json +7 -5
- package/scripts/make-index.js +5 -29
- package/scripts/test.js +59 -51
- package/tests/backend/fetch.test.ts +2 -2
- package/tests/backend/port.test.ts +2 -3
- package/tests/backend/single-buffer.test.ts +1 -1
- package/tests/common/casefold.test.ts +1 -1
- package/tests/common/context.test.ts +11 -4
- package/tests/common/devices.test.ts +3 -3
- package/tests/common/handle.test.ts +4 -3
- package/tests/common/inode.test.ts +2 -2
- package/tests/common/mounts.test.ts +1 -3
- package/tests/common/mutex.test.ts +1 -3
- package/tests/common/path.test.ts +2 -2
- package/tests/common/readline.test.ts +1 -1
- package/tests/common.ts +5 -4
- package/tests/fetch/fetch.ts +1 -1
- package/tests/fs/dir.test.ts +3 -43
- package/tests/fs/directory.test.ts +4 -4
- package/tests/fs/errors.test.ts +2 -2
- package/tests/fs/links.test.ts +1 -1
- package/tests/fs/permissions.test.ts +3 -3
- package/tests/fs/read.test.ts +1 -1
- package/tests/fs/scaling.test.ts +1 -1
- package/tests/fs/stat.test.ts +1 -2
- package/tests/fs/times.test.ts +1 -1
- package/tests/fs/watch.test.ts +3 -2
- package/tests/setup/context.ts +1 -2
- package/tests/setup/cow.ts +1 -1
- package/tests/setup/index.ts +2 -2
- package/tests/setup/port.ts +1 -1
- package/tests/setup/single-buffer.ts +1 -1
- package/tests/setup.ts +4 -3
- package/dist/vfs/types.d.ts +0 -24
- package/tests/assignment.ts +0 -21
- /package/dist/{vfs/constants.d.ts → constants.d.ts} +0 -0
- /package/dist/{vfs/constants.js → constants.js} +0 -0
- /package/dist/{readline.d.ts → node/readline.d.ts} +0 -0
- /package/dist/{readline.js → node/readline.js} +0 -0
- /package/dist/{vfs → node}/streams.d.ts +0 -0
- /package/dist/{vfs → node}/types.js +0 -0
package/COPYING.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
_This document is supplemental to the license._
|
|
2
|
+
|
|
3
|
+
**This is a very easy requirement, please respect it.**
|
|
4
|
+
Feel free to reach out if you have any concerns regarding licensing.
|
|
5
|
+
|
|
6
|
+
If you convey copies of ZenFS (including in bundles), you must meet section 4 and 5 of the license. This includes at a minimum:
|
|
7
|
+
|
|
8
|
+
- disclosure that ZenFS is in use
|
|
9
|
+
- linking to the GitHub or npm pages
|
|
10
|
+
- referencing the license and copyright.
|
|
11
|
+
|
|
12
|
+
For example, in a list of libraries you could have:
|
|
13
|
+
|
|
14
|
+
> - [ZenFS](https://github.com/zen-fs/core), LGPL-3.0-or-later, Copyright © James Prevett and other ZenFS contributors
|
|
15
|
+
|
|
16
|
+
<br />
|
|
17
|
+
|
|
18
|
+
Before v2.4.0, ZenFS was licensed under the MIT. This still means you need to include the copyright notice and license.
|
package/{readme.md → README.md}
RENAMED
|
@@ -19,7 +19,12 @@ ZenFS supports a number of other backends.
|
|
|
19
19
|
Many are provided as separate packages under `@zenfs`.
|
|
20
20
|
More backends can be defined by separate libraries by extending the `FileSystem` class and providing a `Backend` object.
|
|
21
21
|
|
|
22
|
-
You can find all of the packages available over on [NPM](https://www.npmjs.com/org/zenfs).
|
|
22
|
+
You can find all of the packages available over on [NPM](https://www.npmjs.com/org/zenfs). Below is a list of the backends included with some of them:
|
|
23
|
+
|
|
24
|
+
- @zenfs/archives: `Zip`, `Iso`
|
|
25
|
+
- @zenfs/cloud: `Dropbox`, `GoogleDrive`, `S3Bucket`
|
|
26
|
+
- @zenfs/dom: `WebAccess` (Web [File System Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_API)/OPFS), `IndexedDB`, `WebStorage` (`localStorage`/`sessionStorage`), `XML` (DOM elements)
|
|
27
|
+
- @zenfs/emscripten: `Emscripten` and a plugin for Emscripten's file system API
|
|
23
28
|
|
|
24
29
|
As an added bonus, all ZenFS backends support synchronous operations.
|
|
25
30
|
Additionally, all of the backends included with the core are cross-platform.
|
|
@@ -34,7 +39,7 @@ npm install @zenfs/core
|
|
|
34
39
|
|
|
35
40
|
If you're using ZenFS, especially for big projects, please consider supporting the project.
|
|
36
41
|
Thousands of hours have been dedicated to its development.
|
|
37
|
-
Your
|
|
42
|
+
Your financial support would go a long way toward improving ZenFS and its community.
|
|
38
43
|
|
|
39
44
|
## Usage
|
|
40
45
|
|
|
@@ -69,8 +74,8 @@ await configure({
|
|
|
69
74
|
'/mnt/zip': { backend: Zip, data: await res.arrayBuffer() },
|
|
70
75
|
'/tmp': InMemory,
|
|
71
76
|
'/home': IndexedDB,
|
|
72
|
-
}
|
|
73
|
-
};
|
|
77
|
+
},
|
|
78
|
+
});
|
|
74
79
|
```
|
|
75
80
|
|
|
76
81
|
Note that while you aren't required to use absolute paths for the keys of `mounts`, it is a good practice to do so.
|
|
@@ -140,7 +145,7 @@ await configure({
|
|
|
140
145
|
},
|
|
141
146
|
});
|
|
142
147
|
|
|
143
|
-
fs.mkdirSync('/mnt');
|
|
148
|
+
fs.mkdirSync('/mnt/zip', { recursive: true });
|
|
144
149
|
|
|
145
150
|
const res = await fetch('mydata.zip');
|
|
146
151
|
const zipfs = await resolveMountConfig({ backend: Zip, data: await res.arrayBuffer() });
|
|
@@ -156,82 +161,19 @@ fs.umount('/mnt/zip'); // finished using the zip
|
|
|
156
161
|
|
|
157
162
|
### Devices and device files
|
|
158
163
|
|
|
159
|
-
ZenFS includes support for device files. These are designed to follow Linux's device file behavior, for consistency and ease of use.
|
|
160
|
-
|
|
161
|
-
```ts
|
|
162
|
-
await configure({
|
|
163
|
-
mounts: {
|
|
164
|
-
/* ... */
|
|
165
|
-
},
|
|
166
|
-
addDevices: true,
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
fs.writeFileSync('/dev/null', 'Some data to be discarded');
|
|
170
|
-
|
|
171
|
-
const randomData = new Uint8Array(100);
|
|
172
|
-
|
|
173
|
-
const random = fs.openSync('/dev/random', 'r');
|
|
174
|
-
fs.readSync(random, randomData);
|
|
175
|
-
fs.closeSync(random);
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
You can create your own devices by implementing a `DeviceDriver`. For example, the null device looks similar to this:
|
|
179
|
-
|
|
180
|
-
```ts
|
|
181
|
-
const customNullDevice = {
|
|
182
|
-
name: 'custom_null',
|
|
183
|
-
// only 1 can exist per DeviceFS
|
|
184
|
-
singleton: true,
|
|
185
|
-
// optional if false
|
|
186
|
-
isBuffered: false,
|
|
187
|
-
read() {
|
|
188
|
-
return 0;
|
|
189
|
-
},
|
|
190
|
-
write() {
|
|
191
|
-
return 0;
|
|
192
|
-
},
|
|
193
|
-
};
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
Note the actual implementation's write is slightly more complicated since it adds to the file position. You can find more information on the docs.
|
|
197
|
-
|
|
198
|
-
Finally, if you'd like to use your custom device with the file system:
|
|
164
|
+
ZenFS includes support for device files. These are designed to follow Linux's device file behavior, for consistency and ease of use. Check out the [Devices and Device Drivers](https://zenfs.dev/core/documents/Devices_and_Device_Drivers) documentation for more information.
|
|
199
165
|
|
|
200
|
-
|
|
201
|
-
import { addDevice, fs } from '@zenfs/core';
|
|
202
|
-
|
|
203
|
-
addDevice(customNullDevice);
|
|
204
|
-
|
|
205
|
-
fs.writeFileSync('/dev/custom', 'This gets discarded.');
|
|
206
|
-
```
|
|
166
|
+
## Bundling
|
|
207
167
|
|
|
208
|
-
|
|
168
|
+
ZenFS exports a drop-in for Node's `fs` module, so you can use it for your bundler of preference using the default export.
|
|
209
169
|
|
|
210
|
-
|
|
170
|
+
> [!IMPORTANT]
|
|
171
|
+
> See [COPYING.md](./COPYING.md)
|
|
211
172
|
|
|
212
173
|
## Sponsors
|
|
213
174
|
|
|
214
|
-
A huge thank you to [
|
|
215
|
-
|
|
216
|
-
## Building
|
|
217
|
-
|
|
218
|
-
- Make sure you have Node and NPM installed. You must have Node v22 or newer.
|
|
219
|
-
- Install dependencies with `npm install`
|
|
220
|
-
- Build using `npx tsc` or `npm run build`
|
|
221
|
-
- You can find the built code in `dist`.
|
|
175
|
+
A huge thank you to [deco.cx](https://github.com/deco-cx) for sponsoring ZenFS and helping to make this possible.
|
|
222
176
|
|
|
223
177
|
## Contact and Support
|
|
224
178
|
|
|
225
179
|
You can reach out [on Discord](https://zenfs.dev/discord) or by emailing jp@zenfs.dev
|
|
226
|
-
|
|
227
|
-
### Testing
|
|
228
|
-
|
|
229
|
-
Run unit tests with:
|
|
230
|
-
|
|
231
|
-
- `npm test` to run all tests using the default configuration
|
|
232
|
-
- `npx zenfs-test -abc` to run the common tests and run the full FS suite against all included backends
|
|
233
|
-
- You can also run this command to test your own backends, the `--auto` (`-a`) flag will automatically detect any setup scripts matching `tests/setup/*` or `tests/setup-*.ts`. If you do, you'll need to include the `c8` dependency for coverage.
|
|
234
|
-
|
|
235
|
-
### BrowserFS Fork
|
|
236
|
-
|
|
237
|
-
ZenFS is a fork of [BrowserFS](https://github.com/jvilk/BrowserFS). If you are using ZenFS in a research paper, you may want to [cite BrowserFS](https://github.com/jvilk/BrowserFS#citing).
|
package/dist/backends/fetch.js
CHANGED
|
@@ -6,7 +6,7 @@ import * as requests from 'utilium/requests.js';
|
|
|
6
6
|
import { Index } from '../internal/file_index.js';
|
|
7
7
|
import { IndexFS } from '../internal/index_fs.js';
|
|
8
8
|
import { normalizePath } from '../utils.js';
|
|
9
|
-
import { S_IFREG } from '../
|
|
9
|
+
import { S_IFREG } from '../constants.js';
|
|
10
10
|
/** Parse and throw */
|
|
11
11
|
function parseError(error) {
|
|
12
12
|
if (!('tag' in error))
|
package/dist/backends/memory.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import type * as fs from 'node:fs';
|
|
2
1
|
import type { CreationOptions, UsageInfo } from '../internal/filesystem.js';
|
|
3
2
|
import { FileSystem } from '../internal/filesystem.js';
|
|
4
3
|
import { type InodeLike } from '../internal/inode.js';
|
|
5
|
-
|
|
4
|
+
import type { NodeFS } from '../node/types.js';
|
|
6
5
|
/**
|
|
7
6
|
* Passthrough backend options
|
|
8
7
|
* @category Backends and Configuration
|
|
@@ -87,7 +87,7 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
87
87
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
88
88
|
import { withErrno } from 'kerium';
|
|
89
89
|
import { alert, crit, err, warn } from 'kerium/log';
|
|
90
|
-
import { array, offsetof,
|
|
90
|
+
import { array, offsetof, sizeof } from 'memium';
|
|
91
91
|
import { $from, field, struct, types as t } from 'memium/decorators';
|
|
92
92
|
import { BufferView } from 'utilium/buffer.js';
|
|
93
93
|
import { crc32c } from 'utilium/checksum.js';
|
|
@@ -58,10 +58,10 @@ import { _throw, canary, encodeUTF8 } from 'utilium';
|
|
|
58
58
|
import { extendBuffer } from 'utilium/buffer.js';
|
|
59
59
|
import { Index } from '../../internal/file_index.js';
|
|
60
60
|
import { FileSystem } from '../../internal/filesystem.js';
|
|
61
|
-
import { Inode, isDirectory, rootIno } from '../../internal/inode.js';
|
|
61
|
+
import { Inode, isDirectory, isFile, rootIno } from '../../internal/inode.js';
|
|
62
62
|
import { basename, dirname, join, parse, relative } from '../../path.js';
|
|
63
63
|
import { decodeDirListing, encodeDirListing } from '../../utils.js';
|
|
64
|
-
import { S_IFDIR, S_IFREG, size_max } from '../../
|
|
64
|
+
import { S_IFDIR, S_IFREG, size_max } from '../../constants.js';
|
|
65
65
|
import { WrappedTransaction } from './store.js';
|
|
66
66
|
/**
|
|
67
67
|
* A file system which uses a `Store`
|
|
@@ -304,7 +304,7 @@ export class StoreFS extends FileSystem {
|
|
|
304
304
|
: decodeDirListing((await tx.get(newDirNode.data)) ?? _throw(withErrno('ENODATA')));
|
|
305
305
|
if (newDirList[_new.base]) {
|
|
306
306
|
const existing = new Inode((await tx.get(newDirList[_new.base])) ?? _throw(withErrno('ENOENT')));
|
|
307
|
-
if (!
|
|
307
|
+
if (!isFile(existing))
|
|
308
308
|
throw withErrno('EISDIR');
|
|
309
309
|
await tx.remove(existing.data);
|
|
310
310
|
await tx.remove(newDirList[_new.base]);
|
|
@@ -353,7 +353,7 @@ export class StoreFS extends FileSystem {
|
|
|
353
353
|
const newDirList = sameParent ? oldDirList : decodeDirListing(tx.getSync(newDirNode.data) ?? _throw(withErrno('ENODATA')));
|
|
354
354
|
if (newDirList[_new.base]) {
|
|
355
355
|
const existing = new Inode(tx.getSync(newDirList[_new.base]) ?? _throw(withErrno('ENOENT')));
|
|
356
|
-
if (!
|
|
356
|
+
if (!isFile(existing))
|
|
357
357
|
throw withErrno('EISDIR');
|
|
358
358
|
tx.removeSync(existing.data);
|
|
359
359
|
tx.removeSync(newDirList[_new.base]);
|
package/dist/config.js
CHANGED
|
@@ -4,9 +4,9 @@ import { defaultContext } from './internal/contexts.js';
|
|
|
4
4
|
import { createCredentials } from './internal/credentials.js';
|
|
5
5
|
import { DeviceFS } from './internal/devices.js';
|
|
6
6
|
import { FileSystem } from './internal/filesystem.js';
|
|
7
|
+
import { exists, mkdir, stat } from './node/promises.js';
|
|
7
8
|
import { _setAccessChecks } from './vfs/config.js';
|
|
8
|
-
import
|
|
9
|
-
import { mounts } from './vfs/shared.js';
|
|
9
|
+
import { mount, mounts, umount } from './vfs/shared.js';
|
|
10
10
|
/**
|
|
11
11
|
* Update the configuration of a file system.
|
|
12
12
|
* @category Backends and Configuration
|
|
@@ -69,8 +69,8 @@ export async function configureSingle(configuration) {
|
|
|
69
69
|
throw new TypeError('Invalid single mount point configuration');
|
|
70
70
|
}
|
|
71
71
|
const resolved = await resolveMountConfig(configuration);
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
umount('/');
|
|
73
|
+
mount('/', resolved);
|
|
74
74
|
}
|
|
75
75
|
/**
|
|
76
76
|
* Like `fs.mount`, but it also creates missing directories.
|
|
@@ -78,19 +78,19 @@ export async function configureSingle(configuration) {
|
|
|
78
78
|
* This is implemented as a separate function to avoid a circular dependency between vfs/shared.ts and other vfs layer files.
|
|
79
79
|
* @internal
|
|
80
80
|
*/
|
|
81
|
-
async function
|
|
81
|
+
async function mountWithMkdir(path, fs) {
|
|
82
82
|
if (path == '/') {
|
|
83
|
-
|
|
83
|
+
mount(path, fs);
|
|
84
84
|
return;
|
|
85
85
|
}
|
|
86
|
-
const stats = await
|
|
86
|
+
const stats = await stat(path).catch(() => null);
|
|
87
87
|
if (!stats) {
|
|
88
|
-
await
|
|
88
|
+
await mkdir(path, { recursive: true });
|
|
89
89
|
}
|
|
90
90
|
else if (!stats.isDirectory()) {
|
|
91
91
|
throw withErrno('ENOTDIR', 'Missing directory at mount point: ' + path);
|
|
92
92
|
}
|
|
93
|
-
|
|
93
|
+
mount(path, fs);
|
|
94
94
|
}
|
|
95
95
|
/**
|
|
96
96
|
* @category Backends and Configuration
|
|
@@ -124,8 +124,8 @@ export async function configure(configuration) {
|
|
|
124
124
|
mountConfig.caseFold ??= configuration.caseFold;
|
|
125
125
|
}
|
|
126
126
|
if (point == '/')
|
|
127
|
-
|
|
128
|
-
await
|
|
127
|
+
umount('/');
|
|
128
|
+
await mountWithMkdir(point, await resolveMountConfig(mountConfig));
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
for (const fs of mounts.values()) {
|
|
@@ -135,17 +135,17 @@ export async function configure(configuration) {
|
|
|
135
135
|
const devfs = new DeviceFS();
|
|
136
136
|
devfs.addDefaults();
|
|
137
137
|
await devfs.ready();
|
|
138
|
-
await
|
|
138
|
+
await mountWithMkdir('/dev', devfs);
|
|
139
139
|
}
|
|
140
140
|
if (configuration.defaultDirectories) {
|
|
141
141
|
for (const dir of _defaultDirectories) {
|
|
142
|
-
if (await
|
|
143
|
-
const stats = await
|
|
142
|
+
if (await exists(dir)) {
|
|
143
|
+
const stats = await stat(dir);
|
|
144
144
|
if (!stats.isDirectory())
|
|
145
145
|
log.warn('Default directory exists but is not a directory: ' + dir);
|
|
146
146
|
}
|
|
147
147
|
else
|
|
148
|
-
await
|
|
148
|
+
await mkdir(dir);
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
151
|
}
|
package/dist/context.js
CHANGED
|
@@ -3,7 +3,8 @@ import { bindFunctions } from 'utilium';
|
|
|
3
3
|
import { defaultContext } from './internal/contexts.js';
|
|
4
4
|
import { createCredentials } from './internal/credentials.js';
|
|
5
5
|
import * as path from './path.js';
|
|
6
|
-
import * as fs from './
|
|
6
|
+
import * as fs from './node/index.js';
|
|
7
|
+
import * as xattr from './vfs/xattr.js';
|
|
7
8
|
// 0 is reserved for the global/default context
|
|
8
9
|
let _nextId = 1;
|
|
9
10
|
/**
|
|
@@ -33,7 +34,7 @@ export function bindContext({ root = this?.root || '/', pwd = this?.pwd || '/',
|
|
|
33
34
|
fs: {
|
|
34
35
|
...bindFunctions(fs, ctx),
|
|
35
36
|
promises: bindFunctions(fs.promises, ctx),
|
|
36
|
-
xattr: bindFunctions(
|
|
37
|
+
xattr: bindFunctions(xattr, ctx),
|
|
37
38
|
},
|
|
38
39
|
path: bindFunctions(path, ctx),
|
|
39
40
|
bind: (init) => {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* @zenfs/core — https://npmjs.com/package/@zenfs/core
|
|
3
|
+
* Copyright © James Prevett and other ZenFS contributors.
|
|
4
|
+
* SPDX-License-Identifier: LGPL-3.0-or-later
|
|
5
|
+
*/
|
|
1
6
|
export * from './backends/index.js';
|
|
2
7
|
export * from './config.js';
|
|
3
8
|
export * from './context.js';
|
|
4
9
|
export * from './internal/index.js';
|
|
5
10
|
export * from './mixins/index.js';
|
|
6
|
-
export * from './vfs/stats.js';
|
|
7
11
|
export * from './utils.js';
|
|
8
12
|
export { mounts } from './vfs/shared.js';
|
|
9
|
-
|
|
13
|
+
import * as fs from './node/compat.js';
|
|
14
|
+
/** @primaryExport */
|
|
10
15
|
export { fs };
|
|
11
|
-
import * as fs from './vfs/index.js';
|
|
12
16
|
export default fs;
|
|
17
|
+
export * from './node/compat.js';
|
|
18
|
+
export * as vfs from './vfs/index.js';
|
package/dist/index.js
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
/*!
|
|
2
|
+
* @zenfs/core — https://npmjs.com/package/@zenfs/core
|
|
3
|
+
* Copyright © James Prevett and other ZenFS contributors.
|
|
4
|
+
* SPDX-License-Identifier: LGPL-3.0-or-later
|
|
5
|
+
*/
|
|
2
6
|
export * from './backends/index.js';
|
|
3
7
|
export * from './config.js';
|
|
4
8
|
export * from './context.js';
|
|
5
9
|
export * from './internal/index.js';
|
|
6
10
|
export * from './mixins/index.js';
|
|
7
|
-
export * from './vfs/stats.js';
|
|
8
11
|
export * from './utils.js';
|
|
9
12
|
export { mounts } from './vfs/shared.js';
|
|
10
|
-
|
|
13
|
+
import * as fs from './node/compat.js';
|
|
14
|
+
/** @primaryExport */
|
|
11
15
|
export { fs };
|
|
12
|
-
import * as fs from './vfs/index.js';
|
|
13
16
|
export default fs;
|
|
17
|
+
export * from './node/compat.js';
|
|
18
|
+
export * as vfs from './vfs/index.js';
|
|
14
19
|
import $pkg from '../package.json' with { type: 'json' };
|
|
15
20
|
globalThis.__zenfs__ = Object.assign(Object.create(fs), { _version: $pkg.version });
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { Bound } from 'utilium';
|
|
2
|
+
import type * as fs from '../node/index.js';
|
|
2
3
|
import type * as path from '../path.js';
|
|
3
|
-
import type {
|
|
4
|
-
import type * as
|
|
4
|
+
import type { Handle } from '../vfs/file.js';
|
|
5
|
+
import type * as xattr from '../vfs/xattr.js';
|
|
5
6
|
import type { Credentials, CredentialsInit } from './credentials.js';
|
|
6
7
|
/**
|
|
7
8
|
* A context used for FS operations
|
|
@@ -21,7 +22,7 @@ export interface FSContext {
|
|
|
21
22
|
/** The credentials of the context, used for access checks */
|
|
22
23
|
readonly credentials: Credentials;
|
|
23
24
|
/** A map of open file descriptors to their handles */
|
|
24
|
-
descriptors: Map<number,
|
|
25
|
+
descriptors: Map<number, Handle>;
|
|
25
26
|
/** The parent context, if any. */
|
|
26
27
|
parent: V_Context;
|
|
27
28
|
/** The child contexts */
|
|
@@ -38,7 +39,7 @@ export type V_Context = void | null | (Partial<FSContext> & object);
|
|
|
38
39
|
export interface BoundContext extends FSContext {
|
|
39
40
|
fs: Bound<typeof fs, FSContext> & {
|
|
40
41
|
promises: Bound<typeof fs.promises, FSContext>;
|
|
41
|
-
xattr: Bound<typeof
|
|
42
|
+
xattr: Bound<typeof xattr, FSContext>;
|
|
42
43
|
};
|
|
43
44
|
/** Path functions, bound to the context */
|
|
44
45
|
path: Bound<typeof path, FSContext>;
|
package/dist/internal/devices.js
CHANGED
|
@@ -8,7 +8,7 @@ import { decodeUTF8, omit } from 'utilium';
|
|
|
8
8
|
import { InMemoryStore } from '../backends/memory.js';
|
|
9
9
|
import { StoreFS } from '../backends/store/fs.js';
|
|
10
10
|
import { basename, dirname } from '../path.js';
|
|
11
|
-
import { S_IFCHR } from '../
|
|
11
|
+
import { S_IFCHR } from '../constants.js';
|
|
12
12
|
import { Inode } from './inode.js';
|
|
13
13
|
/**
|
|
14
14
|
* A temporary file system that manages and interfaces with devices
|
package/dist/internal/error.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Exception, type ExceptionJSON } from 'kerium';
|
|
1
|
+
import { Exception, type ExceptionExtra, type ExceptionJSON } from 'kerium';
|
|
2
|
+
import type { FileSystem } from './filesystem.js';
|
|
2
3
|
/**
|
|
3
4
|
* @deprecated Use {@link ExceptionJSON} instead
|
|
4
5
|
* @category Internals
|
|
@@ -15,4 +16,12 @@ export declare const ErrnoError: typeof Exception;
|
|
|
15
16
|
*/
|
|
16
17
|
export type ErrnoError = Exception;
|
|
17
18
|
export declare function withPath<E extends Exception>(e: E, path: string): E;
|
|
18
|
-
|
|
19
|
+
/**
|
|
20
|
+
* @internal @hidden
|
|
21
|
+
*/
|
|
22
|
+
export declare function wrap<const FS, const Prop extends keyof FS & string>(fs: FS, prop: Prop, path: string | ExceptionExtra, dest?: string): FS[Prop];
|
|
23
|
+
/**
|
|
24
|
+
* @internal
|
|
25
|
+
* Wraps an `fs` so that thrown errors aren't empty
|
|
26
|
+
*/
|
|
27
|
+
export declare function withExceptionContext<const FS extends FileSystem>(fs: FS, context: ExceptionExtra): FS;
|
package/dist/internal/error.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
|
-
import { Exception, setUVMessage } from 'kerium';
|
|
2
|
+
import { Errno, Exception, setUVMessage, UV } from 'kerium';
|
|
3
3
|
/**
|
|
4
4
|
* @deprecated Use {@link Exception} instead
|
|
5
5
|
* @category Internals
|
|
@@ -9,7 +9,11 @@ export function withPath(e, path) {
|
|
|
9
9
|
e.path = path;
|
|
10
10
|
return e;
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* @internal @hidden
|
|
14
|
+
*/
|
|
12
15
|
export function wrap(fs, prop, path, dest) {
|
|
16
|
+
const extra = typeof path === 'string' ? { path, dest, syscall: prop.endsWith('Sync') ? prop.slice(0, -4) : prop } : path;
|
|
13
17
|
const fn = fs[prop];
|
|
14
18
|
if (typeof fn !== 'function')
|
|
15
19
|
throw new TypeError(`${prop} is not a function`);
|
|
@@ -18,7 +22,39 @@ export function wrap(fs, prop, path, dest) {
|
|
|
18
22
|
return fn.call(fs, ...args);
|
|
19
23
|
}
|
|
20
24
|
catch (e) {
|
|
21
|
-
throw setUVMessage(Object.assign(e,
|
|
25
|
+
throw setUVMessage(Object.assign(e, extra));
|
|
22
26
|
}
|
|
23
27
|
};
|
|
24
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* @internal
|
|
31
|
+
* Wraps an `fs` so that thrown errors aren't empty
|
|
32
|
+
*/
|
|
33
|
+
export function withExceptionContext(fs, context) {
|
|
34
|
+
return new Proxy(fs, {
|
|
35
|
+
get(target, prop) {
|
|
36
|
+
const value = Reflect.get(target, prop);
|
|
37
|
+
if (typeof value != 'function')
|
|
38
|
+
return value;
|
|
39
|
+
return function __withContext(...args) {
|
|
40
|
+
try {
|
|
41
|
+
const result = value.apply(target, args);
|
|
42
|
+
if (!(result instanceof Promise))
|
|
43
|
+
return result;
|
|
44
|
+
return result.catch((e) => {
|
|
45
|
+
if ('code' in e)
|
|
46
|
+
throw setUVMessage(Object.assign(e, context));
|
|
47
|
+
if (e in Errno) {
|
|
48
|
+
const ex = UV(e, context);
|
|
49
|
+
Error.captureStackTrace(ex, __withContext);
|
|
50
|
+
}
|
|
51
|
+
throw e;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
throw setUVMessage(Object.assign(e, context));
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
}
|
|
@@ -4,7 +4,7 @@ import { withErrno } from 'kerium';
|
|
|
4
4
|
import { sizeof } from 'memium';
|
|
5
5
|
import { isJSON, randomInt } from 'utilium';
|
|
6
6
|
import { basename, dirname } from '../path.js';
|
|
7
|
-
import { S_IFDIR, S_IFMT, size_max } from '../
|
|
7
|
+
import { S_IFDIR, S_IFMT, size_max } from '../constants.js';
|
|
8
8
|
import { Inode } from './inode.js';
|
|
9
9
|
export const version = 1;
|
|
10
10
|
/**
|
package/dist/internal/index.d.ts
CHANGED
package/dist/internal/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
|
-
export { log } from 'kerium'; // DO NOT USE
|
|
2
|
+
export { log } from 'kerium'; // DO NOT USE @todo [BREAKING] Remove this
|
|
3
|
+
export * from './contexts.js';
|
|
3
4
|
export * from './credentials.js';
|
|
4
5
|
export * from './devices.js';
|
|
5
6
|
export * from './error.js';
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { withErrno } from 'kerium';
|
|
4
4
|
import { _throw } from 'utilium';
|
|
5
5
|
import { dirname, join, relative } from '../path.js';
|
|
6
|
-
import { S_IFDIR, S_IFMT, S_IFREG, S_ISGID, S_ISUID } from '../
|
|
6
|
+
import { S_IFDIR, S_IFMT, S_IFREG, S_ISGID, S_ISUID } from '../constants.js';
|
|
7
7
|
import { Index } from './file_index.js';
|
|
8
8
|
import { FileSystem } from './filesystem.js';
|
|
9
9
|
import { Inode } from './inode.js';
|
package/dist/internal/inode.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BufferView } from 'utilium/buffer.js';
|
|
2
|
-
import { Stats
|
|
2
|
+
import { Stats } from '../node/stats.js';
|
|
3
3
|
import { type V_Context } from './contexts.js';
|
|
4
4
|
/**
|
|
5
5
|
* Root inode
|
|
@@ -36,7 +36,51 @@ export interface InodeFields {
|
|
|
36
36
|
* @category Internals
|
|
37
37
|
* @internal
|
|
38
38
|
*/
|
|
39
|
-
export interface InodeLike extends
|
|
39
|
+
export interface InodeLike<T extends number | bigint = number> extends InodeFields {
|
|
40
|
+
/**
|
|
41
|
+
* Size of the item in bytes.
|
|
42
|
+
* For directories/symlinks, this is normally the size of the struct that represents the item.
|
|
43
|
+
*/
|
|
44
|
+
size: T;
|
|
45
|
+
/**
|
|
46
|
+
* Unix-style file mode (e.g. 0o644) that includes the item type
|
|
47
|
+
*/
|
|
48
|
+
mode: T;
|
|
49
|
+
/**
|
|
50
|
+
* Time of last access, since epoch
|
|
51
|
+
*/
|
|
52
|
+
atimeMs: T;
|
|
53
|
+
/**
|
|
54
|
+
* Time of last modification, since epoch
|
|
55
|
+
*/
|
|
56
|
+
mtimeMs: T;
|
|
57
|
+
/**
|
|
58
|
+
* Time of last time file status was changed, since epoch
|
|
59
|
+
*/
|
|
60
|
+
ctimeMs: T;
|
|
61
|
+
/**
|
|
62
|
+
* Time of file creation, since epoch
|
|
63
|
+
*/
|
|
64
|
+
birthtimeMs: T;
|
|
65
|
+
/**
|
|
66
|
+
* The id of the user that owns the file
|
|
67
|
+
*/
|
|
68
|
+
uid: T;
|
|
69
|
+
/**
|
|
70
|
+
* The id of the group that owns the file
|
|
71
|
+
*/
|
|
72
|
+
gid: T;
|
|
73
|
+
/**
|
|
74
|
+
* Inode number
|
|
75
|
+
*/
|
|
76
|
+
ino: T;
|
|
77
|
+
/**
|
|
78
|
+
* Number of hard links
|
|
79
|
+
*/
|
|
80
|
+
nlink: T;
|
|
81
|
+
/**
|
|
82
|
+
* Extended attributes
|
|
83
|
+
*/
|
|
40
84
|
attributes?: Attributes;
|
|
41
85
|
}
|
|
42
86
|
/**
|
|
@@ -153,6 +197,7 @@ export declare class Inode extends Inode_base implements InodeLike {
|
|
|
153
197
|
toJSON(): InodeLike;
|
|
154
198
|
/**
|
|
155
199
|
* Handy function that converts the Inode to a Node Stats object.
|
|
200
|
+
* @deprecated Use `new Stats(inode)` instead.
|
|
156
201
|
*/
|
|
157
202
|
toStats(): Stats;
|
|
158
203
|
/**
|
|
@@ -194,4 +239,8 @@ export declare function isFIFO(metadata: {
|
|
|
194
239
|
* @internal
|
|
195
240
|
*/
|
|
196
241
|
export declare function hasAccess($: V_Context, inode: Pick<InodeLike, 'mode' | 'uid' | 'gid'>, access: number): boolean;
|
|
242
|
+
/**
|
|
243
|
+
* @hidden @internal
|
|
244
|
+
*/
|
|
245
|
+
export declare function _chown(stats: Partial<InodeLike>, uid: number, gid: number): boolean;
|
|
197
246
|
export {};
|
package/dist/internal/inode.js
CHANGED
|
@@ -39,8 +39,8 @@ import { sizeof } from 'memium';
|
|
|
39
39
|
import { $from, field, struct, types as t } from 'memium/decorators';
|
|
40
40
|
import { decodeUTF8, encodeUTF8, pick } from 'utilium';
|
|
41
41
|
import { BufferView } from 'utilium/buffer.js';
|
|
42
|
-
import
|
|
43
|
-
import
|
|
42
|
+
import { Stats } from '../node/stats.js';
|
|
43
|
+
import * as c from '../constants.js';
|
|
44
44
|
import { defaultContext } from './contexts.js';
|
|
45
45
|
/**
|
|
46
46
|
* Root inode
|
|
@@ -549,6 +549,7 @@ let Inode = (() => {
|
|
|
549
549
|
}
|
|
550
550
|
/**
|
|
551
551
|
* Handy function that converts the Inode to a Node Stats object.
|
|
552
|
+
* @deprecated Use `new Stats(inode)` instead.
|
|
552
553
|
*/
|
|
553
554
|
toStats() {
|
|
554
555
|
return new Stats(this);
|
|
@@ -647,3 +648,18 @@ export function hasAccess($, inode, access) {
|
|
|
647
648
|
perm |= c.X_OK;
|
|
648
649
|
return (perm & access) === access;
|
|
649
650
|
}
|
|
651
|
+
/**
|
|
652
|
+
* @hidden @internal
|
|
653
|
+
*/
|
|
654
|
+
export function _chown(stats, uid, gid) {
|
|
655
|
+
let valid = true;
|
|
656
|
+
if (!isNaN(uid) && uid >= 0 && uid < c.size_max)
|
|
657
|
+
stats.uid = uid;
|
|
658
|
+
else
|
|
659
|
+
valid = false;
|
|
660
|
+
if (!isNaN(gid) && gid >= 0 && gid < c.size_max)
|
|
661
|
+
stats.gid = gid;
|
|
662
|
+
else
|
|
663
|
+
valid = false;
|
|
664
|
+
return valid;
|
|
665
|
+
}
|
package/dist/mixins/shared.js
CHANGED