@zenfs/core 1.11.4 → 2.1.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/backend.d.ts +19 -15
- package/dist/backends/backend.js +36 -19
- package/dist/backends/cow.d.ts +20 -30
- package/dist/backends/cow.js +83 -192
- package/dist/backends/fetch.d.ts +1 -0
- package/dist/backends/fetch.js +30 -30
- package/dist/backends/index.d.ts +1 -1
- package/dist/backends/index.js +1 -1
- package/dist/backends/memory.d.ts +5 -7
- package/dist/backends/memory.js +2 -3
- package/dist/backends/passthrough.d.ts +19 -23
- package/dist/backends/passthrough.js +98 -288
- package/dist/backends/port.d.ts +220 -0
- package/dist/backends/port.js +328 -0
- package/dist/backends/single_buffer.d.ts +59 -47
- package/dist/backends/single_buffer.js +468 -219
- package/dist/backends/store/fs.d.ts +25 -35
- package/dist/backends/store/fs.js +276 -315
- package/dist/backends/store/store.d.ts +10 -15
- package/dist/backends/store/store.js +11 -10
- package/dist/config.d.ts +3 -12
- package/dist/config.js +17 -19
- package/dist/context.d.ts +8 -21
- package/dist/context.js +33 -10
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/internal/contexts.d.ts +63 -0
- package/dist/internal/contexts.js +15 -0
- package/dist/internal/credentials.d.ts +2 -11
- package/dist/internal/credentials.js +0 -19
- package/dist/internal/devices.d.ts +18 -80
- package/dist/internal/devices.js +103 -316
- package/dist/internal/error.d.ts +9 -204
- package/dist/internal/error.js +19 -288
- package/dist/internal/file_index.d.ts +1 -1
- package/dist/internal/file_index.js +11 -11
- package/dist/internal/filesystem.d.ts +51 -94
- package/dist/internal/filesystem.js +21 -20
- package/dist/internal/index.d.ts +1 -2
- package/dist/internal/index.js +1 -2
- package/dist/internal/index_fs.d.ts +12 -30
- package/dist/internal/index_fs.js +37 -69
- package/dist/internal/inode.d.ts +140 -24
- package/dist/internal/inode.js +515 -66
- package/dist/mixins/async.js +52 -112
- package/dist/mixins/mutexed.d.ts +19 -18
- package/dist/mixins/mutexed.js +62 -64
- package/dist/mixins/readonly.d.ts +7 -6
- package/dist/mixins/readonly.js +24 -18
- package/dist/mixins/sync.js +8 -8
- package/dist/{vfs/path.d.ts → path.d.ts} +3 -4
- package/dist/{vfs/path.js → path.js} +6 -9
- package/dist/polyfills.js +1 -1
- package/dist/readline.d.ts +134 -0
- package/dist/readline.js +623 -0
- package/dist/utils.d.ts +9 -37
- package/dist/utils.js +17 -85
- package/dist/vfs/acl.d.ts +42 -0
- package/dist/vfs/acl.js +268 -0
- package/dist/vfs/async.d.ts +9 -23
- package/dist/vfs/async.js +25 -27
- package/dist/vfs/config.d.ts +6 -18
- package/dist/vfs/config.js +8 -18
- package/dist/vfs/dir.d.ts +3 -3
- package/dist/vfs/dir.js +12 -12
- package/dist/vfs/file.d.ts +106 -0
- package/dist/vfs/file.js +244 -0
- package/dist/vfs/flags.d.ts +19 -0
- package/dist/vfs/flags.js +62 -0
- package/dist/vfs/index.d.ts +4 -10
- package/dist/vfs/index.js +4 -13
- package/dist/vfs/ioctl.d.ts +88 -0
- package/dist/vfs/ioctl.js +409 -0
- package/dist/vfs/promises.d.ts +81 -19
- package/dist/vfs/promises.js +404 -288
- package/dist/vfs/shared.d.ts +7 -37
- package/dist/vfs/shared.js +29 -85
- package/dist/{stats.d.ts → vfs/stats.d.ts} +14 -28
- package/dist/{stats.js → vfs/stats.js} +11 -66
- package/dist/vfs/streams.d.ts +1 -0
- package/dist/vfs/streams.js +32 -27
- package/dist/vfs/sync.d.ts +3 -3
- package/dist/vfs/sync.js +263 -260
- package/dist/vfs/watchers.d.ts +2 -2
- package/dist/vfs/watchers.js +12 -12
- package/dist/vfs/xattr.d.ts +116 -0
- package/dist/vfs/xattr.js +201 -0
- package/package.json +5 -3
- package/readme.md +1 -1
- package/scripts/test.js +2 -2
- package/tests/assignment.ts +1 -1
- package/tests/backend/config.worker.js +4 -1
- package/tests/backend/fetch.test.ts +3 -0
- package/tests/backend/port.test.ts +19 -33
- package/tests/backend/remote.worker.js +4 -1
- package/tests/backend/single-buffer.test.ts +53 -0
- package/tests/backend/single-buffer.worker.js +30 -0
- package/tests/common/context.test.ts +3 -3
- package/tests/common/handle.test.ts +17 -12
- package/tests/common/mutex.test.ts +9 -9
- package/tests/common/path.test.ts +1 -1
- package/tests/common/readline.test.ts +104 -0
- package/tests/common.ts +4 -19
- package/tests/fetch/fetch.ts +2 -2
- package/tests/fs/append.test.ts +4 -4
- package/tests/fs/directory.test.ts +25 -25
- package/tests/fs/errors.test.ts +15 -19
- package/tests/fs/links.test.ts +4 -3
- package/tests/fs/open.test.ts +4 -21
- package/tests/fs/permissions.test.ts +14 -18
- package/tests/fs/read.test.ts +10 -9
- package/tests/fs/readFile.test.ts +10 -26
- package/tests/fs/rename.test.ts +4 -9
- package/tests/fs/stat.test.ts +8 -8
- package/tests/fs/streams.test.ts +2 -11
- package/tests/fs/times.test.ts +7 -7
- package/tests/fs/truncate.test.ts +8 -36
- package/tests/fs/watch.test.ts +10 -10
- package/tests/fs/write.test.ts +77 -13
- package/tests/fs/xattr.test.ts +85 -0
- package/tests/logs.js +22 -0
- package/tests/setup/context.ts +1 -1
- package/tests/setup/index.ts +3 -3
- package/tests/setup/port.ts +7 -1
- package/dist/backends/port/fs.d.ts +0 -84
- package/dist/backends/port/fs.js +0 -151
- package/dist/backends/port/rpc.d.ts +0 -77
- package/dist/backends/port/rpc.js +0 -100
- package/dist/backends/store/simple.d.ts +0 -20
- package/dist/backends/store/simple.js +0 -13
- package/dist/internal/file.d.ts +0 -359
- package/dist/internal/file.js +0 -751
- package/dist/internal/log.d.ts +0 -133
- package/dist/internal/log.js +0 -218
- package/tests/fs/writeFile.test.ts +0 -70
package/dist/vfs/async.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { Buffer } from 'buffer';
|
|
2
|
-
import {
|
|
3
|
-
import { BigIntStats } from '../stats.js';
|
|
2
|
+
import { UV, withErrno } from 'kerium';
|
|
4
3
|
import { normalizeMode, normalizePath } from '../utils.js';
|
|
5
4
|
import { R_OK } from './constants.js';
|
|
6
5
|
import * as promises from './promises.js';
|
|
7
|
-
import {
|
|
6
|
+
import { BigIntStats } from './stats.js';
|
|
8
7
|
import { ReadStream, WriteStream } from './streams.js';
|
|
9
8
|
import { FSWatcher, StatWatcher } from './watchers.js';
|
|
10
9
|
const nop = () => { };
|
|
@@ -31,7 +30,7 @@ rename;
|
|
|
31
30
|
/**
|
|
32
31
|
* Test whether or not `path` exists by checking with the file system.
|
|
33
32
|
* Then call the callback argument with either true or false.
|
|
34
|
-
*
|
|
33
|
+
* According to Node.js: deprecated Use {@link stat} or {@link access} instead.
|
|
35
34
|
*/
|
|
36
35
|
export function exists(path, cb = nop) {
|
|
37
36
|
promises.exists
|
|
@@ -108,39 +107,39 @@ export function appendFile(filename, data, cbEncOpts, cb = nop) {
|
|
|
108
107
|
appendFile;
|
|
109
108
|
export function fstat(fd, options, cb = nop) {
|
|
110
109
|
cb = typeof options == 'function' ? options : cb;
|
|
111
|
-
|
|
110
|
+
new promises.FileHandle(this, fd)
|
|
112
111
|
.stat()
|
|
113
112
|
.then(stats => cb(undefined, typeof options == 'object' && (options === null || options === void 0 ? void 0 : options.bigint) ? new BigIntStats(stats) : stats))
|
|
114
113
|
.catch(cb);
|
|
115
114
|
}
|
|
116
115
|
fstat;
|
|
117
116
|
export function close(fd, cb = nop) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
117
|
+
new promises.FileHandle(this, fd)
|
|
118
|
+
.close()
|
|
119
|
+
.then(() => cb())
|
|
120
|
+
.catch(cb);
|
|
121
121
|
}
|
|
122
122
|
close;
|
|
123
123
|
export function ftruncate(fd, lenOrCB, cb = nop) {
|
|
124
124
|
const length = typeof lenOrCB === 'number' ? lenOrCB : 0;
|
|
125
125
|
cb = typeof lenOrCB === 'function' ? lenOrCB : cb;
|
|
126
|
-
const file =
|
|
127
|
-
if (length < 0)
|
|
128
|
-
throw
|
|
129
|
-
}
|
|
126
|
+
const file = new promises.FileHandle(this, fd);
|
|
127
|
+
if (length < 0)
|
|
128
|
+
throw withErrno('EINVAL');
|
|
130
129
|
file.truncate(length)
|
|
131
130
|
.then(() => cb())
|
|
132
131
|
.catch(cb);
|
|
133
132
|
}
|
|
134
133
|
ftruncate;
|
|
135
134
|
export function fsync(fd, cb = nop) {
|
|
136
|
-
|
|
135
|
+
new promises.FileHandle(this, fd)
|
|
137
136
|
.sync()
|
|
138
137
|
.then(() => cb())
|
|
139
138
|
.catch(cb);
|
|
140
139
|
}
|
|
141
140
|
fsync;
|
|
142
141
|
export function fdatasync(fd, cb = nop) {
|
|
143
|
-
|
|
142
|
+
new promises.FileHandle(this, fd)
|
|
144
143
|
.datasync()
|
|
145
144
|
.then(() => cb())
|
|
146
145
|
.catch(cb);
|
|
@@ -148,7 +147,7 @@ export function fdatasync(fd, cb = nop) {
|
|
|
148
147
|
fdatasync;
|
|
149
148
|
export function write(fd, data, cbPosOff, cbLenEnc, cbPosEnc, cb = nop) {
|
|
150
149
|
let buffer, offset, length, position, encoding;
|
|
151
|
-
const handle = new promises.FileHandle(
|
|
150
|
+
const handle = new promises.FileHandle(this, fd);
|
|
152
151
|
if (typeof data === 'string') {
|
|
153
152
|
// Signature 1: (fd, string, [position?, [encoding?]], cb?)
|
|
154
153
|
encoding = 'utf8';
|
|
@@ -166,7 +165,7 @@ export function write(fd, data, cbPosOff, cbLenEnc, cbPosEnc, cb = nop) {
|
|
|
166
165
|
default:
|
|
167
166
|
// ...try to find the callback and get out of here!
|
|
168
167
|
cb = (typeof cbLenEnc === 'function' ? cbLenEnc : typeof cbPosEnc === 'function' ? cbPosEnc : cb);
|
|
169
|
-
cb(
|
|
168
|
+
cb(withErrno('EINVAL'));
|
|
170
169
|
return;
|
|
171
170
|
}
|
|
172
171
|
buffer = Buffer.from(data);
|
|
@@ -202,21 +201,21 @@ write;
|
|
|
202
201
|
* @param cb The number is the number of bytes read
|
|
203
202
|
*/
|
|
204
203
|
export function read(fd, buffer, offset, length, position, cb = nop) {
|
|
205
|
-
new promises.FileHandle(
|
|
204
|
+
new promises.FileHandle(this, fd)
|
|
206
205
|
.read(buffer, offset, length, position)
|
|
207
206
|
.then(({ bytesRead, buffer }) => cb(undefined, bytesRead, buffer))
|
|
208
207
|
.catch(cb);
|
|
209
208
|
}
|
|
210
209
|
read;
|
|
211
210
|
export function fchown(fd, uid, gid, cb = nop) {
|
|
212
|
-
new promises.FileHandle(
|
|
211
|
+
new promises.FileHandle(this, fd)
|
|
213
212
|
.chown(uid, gid)
|
|
214
213
|
.then(() => cb())
|
|
215
214
|
.catch(cb);
|
|
216
215
|
}
|
|
217
216
|
fchown;
|
|
218
217
|
export function fchmod(fd, mode, cb) {
|
|
219
|
-
new promises.FileHandle(
|
|
218
|
+
new promises.FileHandle(this, fd)
|
|
220
219
|
.chmod(mode)
|
|
221
220
|
.then(() => cb())
|
|
222
221
|
.catch(cb);
|
|
@@ -226,7 +225,7 @@ fchmod;
|
|
|
226
225
|
* Change the file timestamps of a file referenced by the supplied file descriptor.
|
|
227
226
|
*/
|
|
228
227
|
export function futimes(fd, atime, mtime, cb = nop) {
|
|
229
|
-
new promises.FileHandle(
|
|
228
|
+
new promises.FileHandle(this, fd)
|
|
230
229
|
.utimes(atime, mtime)
|
|
231
230
|
.then(() => cb())
|
|
232
231
|
.catch(cb);
|
|
@@ -350,14 +349,13 @@ export function access(path, cbMode, cb = nop) {
|
|
|
350
349
|
access;
|
|
351
350
|
const statWatchers = new Map();
|
|
352
351
|
export function watchFile(path, options, listener) {
|
|
353
|
-
const normalizedPath = normalizePath(path
|
|
352
|
+
const normalizedPath = normalizePath(path);
|
|
354
353
|
const opts = typeof options != 'function' ? options : {};
|
|
355
354
|
if (typeof options == 'function') {
|
|
356
355
|
listener = options;
|
|
357
356
|
}
|
|
358
|
-
if (!listener)
|
|
359
|
-
throw
|
|
360
|
-
}
|
|
357
|
+
if (!listener)
|
|
358
|
+
throw UV('EINVAL', 'watch', path.toString());
|
|
361
359
|
if (statWatchers.has(normalizedPath)) {
|
|
362
360
|
const entry = statWatchers.get(normalizedPath);
|
|
363
361
|
if (entry) {
|
|
@@ -388,7 +386,7 @@ watchFile;
|
|
|
388
386
|
* @param listener Optional listener to remove.
|
|
389
387
|
*/
|
|
390
388
|
export function unwatchFile(path, listener = nop) {
|
|
391
|
-
const normalizedPath = normalizePath(path
|
|
389
|
+
const normalizedPath = normalizePath(path);
|
|
392
390
|
const entry = statWatchers.get(normalizedPath);
|
|
393
391
|
if (entry) {
|
|
394
392
|
if (listener && listener !== nop) {
|
|
@@ -465,7 +463,7 @@ export function copyFile(src, dest, flags, callback = nop) {
|
|
|
465
463
|
copyFile;
|
|
466
464
|
export function readv(fd, buffers, position, cb = nop) {
|
|
467
465
|
cb = typeof position === 'function' ? position : cb;
|
|
468
|
-
new promises.FileHandle(
|
|
466
|
+
new promises.FileHandle(this, fd)
|
|
469
467
|
.readv(buffers, typeof position === 'function' ? undefined : position)
|
|
470
468
|
.then(({ buffers, bytesRead }) => cb(undefined, bytesRead, buffers))
|
|
471
469
|
.catch(cb);
|
|
@@ -473,7 +471,7 @@ export function readv(fd, buffers, position, cb = nop) {
|
|
|
473
471
|
readv;
|
|
474
472
|
export function writev(fd, buffers, position, cb = nop) {
|
|
475
473
|
cb = typeof position === 'function' ? position : cb;
|
|
476
|
-
new promises.FileHandle(
|
|
474
|
+
new promises.FileHandle(this, fd)
|
|
477
475
|
.writev(buffers, typeof position === 'function' ? undefined : position)
|
|
478
476
|
.then(({ buffers, bytesWritten }) => cb(undefined, bytesWritten, buffers))
|
|
479
477
|
.catch(cb);
|
package/dist/vfs/config.d.ts
CHANGED
|
@@ -1,18 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* Whether to mark a file as dirty after updating its `atime` when read from
|
|
8
|
-
*/
|
|
9
|
-
updateOnRead: boolean;
|
|
10
|
-
/**
|
|
11
|
-
* Whether to immediately sync when files are changed
|
|
12
|
-
*/
|
|
13
|
-
syncImmediately: boolean;
|
|
14
|
-
/**
|
|
15
|
-
* If a file's buffer is not large enough to store content when writing and the buffer can't be resized, reuse the buffer passed to write()
|
|
16
|
-
*/
|
|
17
|
-
unsafeBufferReplace: boolean;
|
|
18
|
-
};
|
|
1
|
+
/** Whether to perform access checks */
|
|
2
|
+
export declare let checkAccess: boolean;
|
|
3
|
+
/**
|
|
4
|
+
* @internal @hidden
|
|
5
|
+
*/
|
|
6
|
+
export declare function _setAccessChecks(value: boolean): void;
|
package/dist/vfs/config.js
CHANGED
|
@@ -1,18 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
updateOnRead: true,
|
|
10
|
-
/**
|
|
11
|
-
* Whether to immediately sync when files are changed
|
|
12
|
-
*/
|
|
13
|
-
syncImmediately: true,
|
|
14
|
-
/**
|
|
15
|
-
* If a file's buffer is not large enough to store content when writing and the buffer can't be resized, reuse the buffer passed to write()
|
|
16
|
-
*/
|
|
17
|
-
unsafeBufferReplace: false,
|
|
18
|
-
};
|
|
1
|
+
/** Whether to perform access checks */
|
|
2
|
+
export let checkAccess = true;
|
|
3
|
+
/**
|
|
4
|
+
* @internal @hidden
|
|
5
|
+
*/
|
|
6
|
+
export function _setAccessChecks(value) {
|
|
7
|
+
checkAccess = value;
|
|
8
|
+
}
|
package/dist/vfs/dir.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { Dir as _Dir, Dirent as _Dirent } from 'node:fs';
|
|
2
2
|
import type { V_Context } from '../context.js';
|
|
3
|
-
import type {
|
|
3
|
+
import type { InodeLike } from '../internal/inode.js';
|
|
4
4
|
import type { Callback } from '../utils.js';
|
|
5
5
|
export declare class Dirent implements _Dirent {
|
|
6
6
|
path: string;
|
|
7
|
-
protected stats:
|
|
7
|
+
protected stats: InodeLike;
|
|
8
8
|
get name(): string;
|
|
9
|
-
constructor(path: string, stats:
|
|
9
|
+
constructor(path: string, stats: InodeLike);
|
|
10
10
|
get parentPath(): string;
|
|
11
11
|
isFile(): boolean;
|
|
12
12
|
isDirectory(): boolean;
|
package/dist/vfs/dir.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { withErrno } from 'kerium';
|
|
2
|
+
import { isBlockDevice, isCharacterDevice, isDirectory, isFIFO, isFile, isSocket, isSymbolicLink } from '../internal/inode.js';
|
|
3
|
+
import { basename } from '../path.js';
|
|
3
4
|
import { readdir } from './promises.js';
|
|
4
5
|
import { readdirSync } from './sync.js';
|
|
5
6
|
export class Dirent {
|
|
@@ -14,25 +15,25 @@ export class Dirent {
|
|
|
14
15
|
return this.path;
|
|
15
16
|
}
|
|
16
17
|
isFile() {
|
|
17
|
-
return this.stats
|
|
18
|
+
return isFile(this.stats);
|
|
18
19
|
}
|
|
19
20
|
isDirectory() {
|
|
20
|
-
return this.stats
|
|
21
|
+
return isDirectory(this.stats);
|
|
21
22
|
}
|
|
22
23
|
isBlockDevice() {
|
|
23
|
-
return this.stats
|
|
24
|
+
return isBlockDevice(this.stats);
|
|
24
25
|
}
|
|
25
26
|
isCharacterDevice() {
|
|
26
|
-
return this.stats
|
|
27
|
+
return isCharacterDevice(this.stats);
|
|
27
28
|
}
|
|
28
29
|
isSymbolicLink() {
|
|
29
|
-
return this.stats
|
|
30
|
+
return isSymbolicLink(this.stats);
|
|
30
31
|
}
|
|
31
32
|
isFIFO() {
|
|
32
|
-
return this.stats
|
|
33
|
+
return isFIFO(this.stats);
|
|
33
34
|
}
|
|
34
35
|
isSocket() {
|
|
35
|
-
return this.stats
|
|
36
|
+
return isSocket(this.stats);
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
39
|
/**
|
|
@@ -40,9 +41,8 @@ export class Dirent {
|
|
|
40
41
|
*/
|
|
41
42
|
export class Dir {
|
|
42
43
|
checkClosed() {
|
|
43
|
-
if (this.closed)
|
|
44
|
-
throw
|
|
45
|
-
}
|
|
44
|
+
if (this.closed)
|
|
45
|
+
throw withErrno('EBADF', 'Can not use closed Dir');
|
|
46
46
|
}
|
|
47
47
|
constructor(path, context) {
|
|
48
48
|
this.path = path;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { V_Context } from '../context.js';
|
|
2
|
+
import type { FileSystem, StreamOptions } from '../internal/filesystem.js';
|
|
3
|
+
import { type InodeLike } from '../internal/inode.js';
|
|
4
|
+
import '../polyfills.js';
|
|
5
|
+
/** @hidden */
|
|
6
|
+
export interface FileReadResult<T extends ArrayBufferView> {
|
|
7
|
+
bytesRead: number;
|
|
8
|
+
buffer: T;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
export declare class SyncHandle {
|
|
14
|
+
readonly context: V_Context;
|
|
15
|
+
readonly path: string;
|
|
16
|
+
readonly fs: FileSystem;
|
|
17
|
+
readonly internalPath: string;
|
|
18
|
+
readonly flag: number;
|
|
19
|
+
readonly inode: InodeLike;
|
|
20
|
+
protected _buffer?: Uint8Array;
|
|
21
|
+
/**
|
|
22
|
+
* Current position
|
|
23
|
+
*/
|
|
24
|
+
protected _position: number;
|
|
25
|
+
/**
|
|
26
|
+
* Get the current file position.
|
|
27
|
+
*
|
|
28
|
+
* We emulate the following bug mentioned in the Node documentation:
|
|
29
|
+
*
|
|
30
|
+
* On Linux, positional writes don't work when the file is opened in append mode.
|
|
31
|
+
* The kernel ignores the position argument and always appends the data to the end of the file.
|
|
32
|
+
* @returns The current file position.
|
|
33
|
+
*/
|
|
34
|
+
get position(): number;
|
|
35
|
+
set position(value: number);
|
|
36
|
+
/**
|
|
37
|
+
* Whether the file has changes which have not been written to the FS
|
|
38
|
+
*/
|
|
39
|
+
protected dirty: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Whether the file is open or closed
|
|
42
|
+
*/
|
|
43
|
+
protected closed: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Creates a file with `path` and, optionally, the given contents.
|
|
46
|
+
* Note that, if contents is specified, it will be mutated by the file.
|
|
47
|
+
*/
|
|
48
|
+
constructor(context: V_Context, path: string, fs: FileSystem, internalPath: string, flag: number, inode: InodeLike);
|
|
49
|
+
[Symbol.dispose](): void;
|
|
50
|
+
private get _isSync();
|
|
51
|
+
sync(): void;
|
|
52
|
+
/**
|
|
53
|
+
* Default implementation maps to `syncSync`.
|
|
54
|
+
*/
|
|
55
|
+
datasync(): void;
|
|
56
|
+
close(): void;
|
|
57
|
+
/**
|
|
58
|
+
* Cleans up. This will *not* sync the file data to the FS
|
|
59
|
+
*/
|
|
60
|
+
protected dispose(force?: boolean): void;
|
|
61
|
+
stat(): InodeLike;
|
|
62
|
+
truncate(length: number): void;
|
|
63
|
+
/**
|
|
64
|
+
* Write buffer to the file.
|
|
65
|
+
* @param buffer Uint8Array containing the data to write to the file.
|
|
66
|
+
* @param offset Offset in the buffer to start reading data from.
|
|
67
|
+
* @param length The amount of bytes to write to the file.
|
|
68
|
+
* @param position Offset from the beginning of the file where this data should be written.
|
|
69
|
+
* If position is null, the data will be written at the current position.
|
|
70
|
+
* @returns bytes written
|
|
71
|
+
*/
|
|
72
|
+
write(buffer: Uint8Array, offset?: number, length?: number, position?: number): number;
|
|
73
|
+
/**
|
|
74
|
+
* Read data from the file.
|
|
75
|
+
* @param buffer The buffer that the data will be written to.
|
|
76
|
+
* @param offset The offset within the buffer where writing will start.
|
|
77
|
+
* @param length An integer specifying the number of bytes to read.
|
|
78
|
+
* @param position An integer specifying where to begin reading from in the file.
|
|
79
|
+
* If position is null, data will be read from the current file position.
|
|
80
|
+
* @returns number of bytes written
|
|
81
|
+
*/
|
|
82
|
+
read(buffer: ArrayBufferView, offset?: number, length?: number, position?: number): number;
|
|
83
|
+
chmod(mode: number): void;
|
|
84
|
+
chown(uid: number, gid: number): void;
|
|
85
|
+
/**
|
|
86
|
+
* Change the file timestamps of the file.
|
|
87
|
+
*/
|
|
88
|
+
utimes(atime: number, mtime: number): void;
|
|
89
|
+
/**
|
|
90
|
+
* Create a stream for reading the file.
|
|
91
|
+
*/
|
|
92
|
+
streamRead(options: StreamOptions): ReadableStream;
|
|
93
|
+
/**
|
|
94
|
+
* Create a stream for writing the file.
|
|
95
|
+
*/
|
|
96
|
+
streamWrite(options: StreamOptions): WritableStream;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* @internal @hidden
|
|
100
|
+
*/
|
|
101
|
+
export declare function toFD(file: SyncHandle): number;
|
|
102
|
+
/**
|
|
103
|
+
* @internal @hidden
|
|
104
|
+
*/
|
|
105
|
+
export declare function fromFD($: V_Context, fd: number): SyncHandle;
|
|
106
|
+
export declare function deleteFD($: V_Context, fd: number): boolean;
|
package/dist/vfs/file.js
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { UV, withErrno } from 'kerium';
|
|
2
|
+
import { defaultContext } from '../internal/contexts.js';
|
|
3
|
+
import { InodeFlags, isBlockDevice, isCharacterDevice } from '../internal/inode.js';
|
|
4
|
+
import '../polyfills.js';
|
|
5
|
+
import * as c from './constants.js';
|
|
6
|
+
import { _chown } from './stats.js';
|
|
7
|
+
/**
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export class SyncHandle {
|
|
11
|
+
/**
|
|
12
|
+
* Get the current file position.
|
|
13
|
+
*
|
|
14
|
+
* We emulate the following bug mentioned in the Node documentation:
|
|
15
|
+
*
|
|
16
|
+
* On Linux, positional writes don't work when the file is opened in append mode.
|
|
17
|
+
* The kernel ignores the position argument and always appends the data to the end of the file.
|
|
18
|
+
* @returns The current file position.
|
|
19
|
+
*/
|
|
20
|
+
get position() {
|
|
21
|
+
return this.flag & c.O_APPEND ? this.inode.size : this._position;
|
|
22
|
+
}
|
|
23
|
+
set position(value) {
|
|
24
|
+
this._position = value;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Creates a file with `path` and, optionally, the given contents.
|
|
28
|
+
* Note that, if contents is specified, it will be mutated by the file.
|
|
29
|
+
*/
|
|
30
|
+
constructor(context, path, fs, internalPath, flag, inode) {
|
|
31
|
+
this.context = context;
|
|
32
|
+
this.path = path;
|
|
33
|
+
this.fs = fs;
|
|
34
|
+
this.internalPath = internalPath;
|
|
35
|
+
this.flag = flag;
|
|
36
|
+
this.inode = inode;
|
|
37
|
+
/**
|
|
38
|
+
* Current position
|
|
39
|
+
*/
|
|
40
|
+
this._position = 0;
|
|
41
|
+
/**
|
|
42
|
+
* Whether the file has changes which have not been written to the FS
|
|
43
|
+
*/
|
|
44
|
+
this.dirty = false;
|
|
45
|
+
/**
|
|
46
|
+
* Whether the file is open or closed
|
|
47
|
+
*/
|
|
48
|
+
this.closed = false;
|
|
49
|
+
}
|
|
50
|
+
[Symbol.dispose]() {
|
|
51
|
+
this.close();
|
|
52
|
+
}
|
|
53
|
+
get _isSync() {
|
|
54
|
+
return !!(this.flag & c.O_SYNC || this.inode.flags & InodeFlags.Sync || this.fs.attributes.has('sync'));
|
|
55
|
+
}
|
|
56
|
+
sync() {
|
|
57
|
+
if (this.closed)
|
|
58
|
+
throw UV('EBADF', 'sync', this.path);
|
|
59
|
+
if (!this.dirty)
|
|
60
|
+
return;
|
|
61
|
+
if (!this.fs.attributes.has('no_write'))
|
|
62
|
+
this.fs.touchSync(this.internalPath, this.inode);
|
|
63
|
+
this.dirty = false;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Default implementation maps to `syncSync`.
|
|
67
|
+
*/
|
|
68
|
+
datasync() {
|
|
69
|
+
return this.sync();
|
|
70
|
+
}
|
|
71
|
+
close() {
|
|
72
|
+
if (this.closed)
|
|
73
|
+
throw UV('EBADF', 'close', this.path);
|
|
74
|
+
this.sync();
|
|
75
|
+
this.dispose();
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Cleans up. This will *not* sync the file data to the FS
|
|
79
|
+
*/
|
|
80
|
+
dispose(force) {
|
|
81
|
+
if (this.closed)
|
|
82
|
+
throw UV('EBADF', 'close', this.path);
|
|
83
|
+
if (this.dirty && !force)
|
|
84
|
+
throw UV('EBUSY', 'close', this.path);
|
|
85
|
+
this.closed = true;
|
|
86
|
+
}
|
|
87
|
+
stat() {
|
|
88
|
+
if (this.closed)
|
|
89
|
+
throw UV('EBADF', 'stat', this.path);
|
|
90
|
+
return this.inode;
|
|
91
|
+
}
|
|
92
|
+
truncate(length) {
|
|
93
|
+
if (length < 0)
|
|
94
|
+
throw UV('EINVAL', 'truncate', this.path);
|
|
95
|
+
if (this.closed)
|
|
96
|
+
throw UV('EBADF', 'truncate', this.path);
|
|
97
|
+
if (!(this.flag & c.O_WRONLY || this.flag & c.O_RDWR))
|
|
98
|
+
throw UV('EBADF', 'truncate', this.path);
|
|
99
|
+
if (this.fs.attributes.has('readonly'))
|
|
100
|
+
throw UV('EROFS', 'truncate', this.path);
|
|
101
|
+
if (this.inode.flags & InodeFlags.Immutable)
|
|
102
|
+
throw UV('EPERM', 'truncate', this.path);
|
|
103
|
+
this.dirty = true;
|
|
104
|
+
this.inode.mtimeMs = Date.now();
|
|
105
|
+
this.inode.size = length;
|
|
106
|
+
this.inode.ctimeMs = Date.now();
|
|
107
|
+
if (this._isSync)
|
|
108
|
+
this.sync();
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Write buffer to the file.
|
|
112
|
+
* @param buffer Uint8Array containing the data to write to the file.
|
|
113
|
+
* @param offset Offset in the buffer to start reading data from.
|
|
114
|
+
* @param length The amount of bytes to write to the file.
|
|
115
|
+
* @param position Offset from the beginning of the file where this data should be written.
|
|
116
|
+
* If position is null, the data will be written at the current position.
|
|
117
|
+
* @returns bytes written
|
|
118
|
+
*/
|
|
119
|
+
write(buffer, offset = 0, length = buffer.byteLength - offset, position = this.position) {
|
|
120
|
+
if (this.closed)
|
|
121
|
+
throw UV('EBADF', 'write', this.path);
|
|
122
|
+
if (!(this.flag & c.O_WRONLY || this.flag & c.O_RDWR))
|
|
123
|
+
throw UV('EBADF', 'write', this.path);
|
|
124
|
+
if (this.fs.attributes.has('readonly'))
|
|
125
|
+
throw UV('EROFS', 'write', this.path);
|
|
126
|
+
if (this.inode.flags & InodeFlags.Immutable)
|
|
127
|
+
throw UV('EPERM', 'write', this.path);
|
|
128
|
+
this.dirty = true;
|
|
129
|
+
const end = position + length;
|
|
130
|
+
const slice = buffer.subarray(offset, offset + length);
|
|
131
|
+
if (!isCharacterDevice(this.inode) && !isBlockDevice(this.inode) && end > this.inode.size)
|
|
132
|
+
this.inode.size = end;
|
|
133
|
+
this.inode.mtimeMs = Date.now();
|
|
134
|
+
this.inode.ctimeMs = Date.now();
|
|
135
|
+
this._position = position + slice.byteLength;
|
|
136
|
+
this.fs.writeSync(this.internalPath, slice, position);
|
|
137
|
+
if (this._isSync)
|
|
138
|
+
this.sync();
|
|
139
|
+
return slice.byteLength;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Read data from the file.
|
|
143
|
+
* @param buffer The buffer that the data will be written to.
|
|
144
|
+
* @param offset The offset within the buffer where writing will start.
|
|
145
|
+
* @param length An integer specifying the number of bytes to read.
|
|
146
|
+
* @param position An integer specifying where to begin reading from in the file.
|
|
147
|
+
* If position is null, data will be read from the current file position.
|
|
148
|
+
* @returns number of bytes written
|
|
149
|
+
*/
|
|
150
|
+
read(buffer, offset = 0, length = buffer.byteLength - offset, position = this.position) {
|
|
151
|
+
if (this.closed)
|
|
152
|
+
throw UV('EBADF', 'read', this.path);
|
|
153
|
+
if (this.flag & c.O_WRONLY)
|
|
154
|
+
throw UV('EBADF', 'read', this.path);
|
|
155
|
+
if (!(this.inode.flags & InodeFlags.NoAtime) && !this.fs.attributes.has('no_atime')) {
|
|
156
|
+
this.dirty = true;
|
|
157
|
+
this.inode.atimeMs = Date.now();
|
|
158
|
+
}
|
|
159
|
+
let end = position + length;
|
|
160
|
+
if (!isCharacterDevice(this.inode) && !isBlockDevice(this.inode) && end > this.inode.size) {
|
|
161
|
+
end = position + Math.max(this.inode.size - position, 0);
|
|
162
|
+
}
|
|
163
|
+
this._position = end;
|
|
164
|
+
const uint8 = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
165
|
+
this.fs.readSync(this.internalPath, uint8.subarray(offset, offset + length), position, end);
|
|
166
|
+
if (this._isSync)
|
|
167
|
+
this.sync();
|
|
168
|
+
return end - position;
|
|
169
|
+
}
|
|
170
|
+
chmod(mode) {
|
|
171
|
+
if (this.closed)
|
|
172
|
+
throw UV('EBADF', 'chmod', this.path);
|
|
173
|
+
this.dirty = true;
|
|
174
|
+
this.inode.mode = (this.inode.mode & (mode > c.S_IFMT ? ~c.S_IFMT : c.S_IFMT)) | mode;
|
|
175
|
+
if (this._isSync || mode > c.S_IFMT)
|
|
176
|
+
this.sync();
|
|
177
|
+
}
|
|
178
|
+
chown(uid, gid) {
|
|
179
|
+
if (this.closed)
|
|
180
|
+
throw UV('EBADF', 'chmod', this.path);
|
|
181
|
+
this.dirty = true;
|
|
182
|
+
_chown(this.inode, uid, gid);
|
|
183
|
+
if (this._isSync)
|
|
184
|
+
this.sync();
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Change the file timestamps of the file.
|
|
188
|
+
*/
|
|
189
|
+
utimes(atime, mtime) {
|
|
190
|
+
if (this.closed)
|
|
191
|
+
throw UV('EBADF', 'utimes', this.path);
|
|
192
|
+
this.dirty = true;
|
|
193
|
+
this.inode.atimeMs = atime;
|
|
194
|
+
this.inode.mtimeMs = mtime;
|
|
195
|
+
if (this._isSync)
|
|
196
|
+
this.sync();
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Create a stream for reading the file.
|
|
200
|
+
*/
|
|
201
|
+
streamRead(options) {
|
|
202
|
+
if (this.closed)
|
|
203
|
+
throw UV('EBADF', 'streamRead', this.path);
|
|
204
|
+
return this.fs.streamRead(this.internalPath, options);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Create a stream for writing the file.
|
|
208
|
+
*/
|
|
209
|
+
streamWrite(options) {
|
|
210
|
+
if (this.closed)
|
|
211
|
+
throw UV('EBADF', 'write', this.path);
|
|
212
|
+
if (this.inode.flags & InodeFlags.Immutable)
|
|
213
|
+
throw UV('EPERM', 'write', this.path);
|
|
214
|
+
if (this.fs.attributes.has('readonly'))
|
|
215
|
+
throw UV('EROFS', 'write', this.path);
|
|
216
|
+
return this.fs.streamWrite(this.internalPath, options);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// descriptors
|
|
220
|
+
/**
|
|
221
|
+
* @internal @hidden
|
|
222
|
+
*/
|
|
223
|
+
export function toFD(file) {
|
|
224
|
+
var _a, _b;
|
|
225
|
+
const map = (_b = (_a = file.context) === null || _a === void 0 ? void 0 : _a.descriptors) !== null && _b !== void 0 ? _b : defaultContext.descriptors;
|
|
226
|
+
const fd = Math.max(map.size ? Math.max(...map.keys()) + 1 : 0, 4);
|
|
227
|
+
map.set(fd, file);
|
|
228
|
+
return fd;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* @internal @hidden
|
|
232
|
+
*/
|
|
233
|
+
export function fromFD($, fd) {
|
|
234
|
+
var _a;
|
|
235
|
+
const map = (_a = $ === null || $ === void 0 ? void 0 : $.descriptors) !== null && _a !== void 0 ? _a : defaultContext.descriptors;
|
|
236
|
+
const value = map.get(fd);
|
|
237
|
+
if (!value)
|
|
238
|
+
throw withErrno('EBADF');
|
|
239
|
+
return value;
|
|
240
|
+
}
|
|
241
|
+
export function deleteFD($, fd) {
|
|
242
|
+
var _a;
|
|
243
|
+
return ((_a = $ === null || $ === void 0 ? void 0 : $.descriptors) !== null && _a !== void 0 ? _a : defaultContext.descriptors).delete(fd);
|
|
244
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const pattern: RegExp;
|
|
2
|
+
/**
|
|
3
|
+
* @internal @hidden
|
|
4
|
+
*/
|
|
5
|
+
export declare function parse(flag: string | number): number;
|
|
6
|
+
/**
|
|
7
|
+
* @internal @hidden
|
|
8
|
+
*/
|
|
9
|
+
export declare function toString(flag: number): string;
|
|
10
|
+
/**
|
|
11
|
+
* @internal @hidden
|
|
12
|
+
*/
|
|
13
|
+
export declare function toNumber(flag: string): number;
|
|
14
|
+
/**
|
|
15
|
+
* Parses a flag as a mode (W_OK, R_OK, and/or X_OK)
|
|
16
|
+
* @param flag the flag to parse
|
|
17
|
+
* @internal @hidden
|
|
18
|
+
*/
|
|
19
|
+
export declare function toMode(flag: number): number;
|