@zenfs/core 1.3.6 → 1.4.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/memory.d.ts +4 -4
- package/dist/backends/memory.js +4 -4
- package/dist/backends/overlay.d.ts +5 -2
- package/dist/backends/overlay.js +7 -10
- package/dist/backends/port/fs.js +1 -4
- package/dist/config.js +4 -8
- package/dist/context.d.ts +32 -0
- package/dist/context.js +23 -0
- package/dist/credentials.d.ts +5 -5
- package/dist/credentials.js +10 -6
- package/dist/emulation/async.d.ts +90 -89
- package/dist/emulation/async.js +76 -75
- package/dist/emulation/dir.d.ts +3 -1
- package/dist/emulation/dir.js +6 -7
- package/dist/emulation/index.d.ts +1 -1
- package/dist/emulation/index.js +1 -1
- package/dist/emulation/promises.d.ts +50 -48
- package/dist/emulation/promises.js +78 -77
- package/dist/emulation/shared.d.ts +35 -8
- package/dist/emulation/shared.js +37 -11
- package/dist/emulation/sync.d.ts +63 -62
- package/dist/emulation/sync.js +72 -73
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/stats.d.ts +2 -1
- package/dist/stats.js +5 -4
- package/package.json +3 -5
- package/scripts/test.js +78 -17
- package/tests/assignment.ts +1 -1
- package/tests/common/context.test.ts +19 -0
- package/tests/{devices.test.ts → common/devices.test.ts} +3 -3
- package/tests/{handle.test.ts → common/handle.test.ts} +1 -1
- package/tests/common/mounts.test.ts +36 -0
- package/tests/{mutex.test.ts → common/mutex.test.ts} +3 -3
- package/tests/common/path.test.ts +34 -0
- package/tests/common.ts +4 -3
- package/tests/fs/dir.test.ts +11 -11
- package/tests/fs/directory.test.ts +17 -17
- package/tests/fs/errors.test.ts +29 -39
- package/tests/fs/watch.test.ts +2 -2
- package/tests/setup/context.ts +9 -0
- package/tests/setup/cow+fetch.ts +1 -1
- package/tests/setup/memory.ts +1 -1
- package/tests/{setup/common.ts → setup.ts} +6 -5
- package/src/backends/backend.ts +0 -161
- package/src/backends/fetch.ts +0 -180
- package/src/backends/file_index.ts +0 -206
- package/src/backends/memory.ts +0 -45
- package/src/backends/overlay.ts +0 -560
- package/src/backends/port/fs.ts +0 -329
- package/src/backends/port/readme.md +0 -54
- package/src/backends/port/rpc.ts +0 -167
- package/src/backends/readme.md +0 -3
- package/src/backends/store/fs.ts +0 -667
- package/src/backends/store/readme.md +0 -9
- package/src/backends/store/simple.ts +0 -154
- package/src/backends/store/store.ts +0 -189
- package/src/config.ts +0 -227
- package/src/credentials.ts +0 -49
- package/src/devices.ts +0 -521
- package/src/emulation/async.ts +0 -834
- package/src/emulation/cache.ts +0 -86
- package/src/emulation/config.ts +0 -21
- package/src/emulation/constants.ts +0 -182
- package/src/emulation/dir.ts +0 -138
- package/src/emulation/index.ts +0 -8
- package/src/emulation/path.ts +0 -440
- package/src/emulation/promises.ts +0 -1140
- package/src/emulation/shared.ts +0 -172
- package/src/emulation/streams.ts +0 -34
- package/src/emulation/sync.ts +0 -863
- package/src/emulation/watchers.ts +0 -194
- package/src/error.ts +0 -307
- package/src/file.ts +0 -631
- package/src/filesystem.ts +0 -174
- package/src/index.ts +0 -35
- package/src/inode.ts +0 -128
- package/src/mixins/async.ts +0 -230
- package/src/mixins/index.ts +0 -5
- package/src/mixins/mutexed.ts +0 -257
- package/src/mixins/readonly.ts +0 -96
- package/src/mixins/shared.ts +0 -25
- package/src/mixins/sync.ts +0 -58
- package/src/polyfills.ts +0 -21
- package/src/stats.ts +0 -405
- package/src/utils.ts +0 -276
- package/tests/mounts.test.ts +0 -18
- package/tests/path.test.ts +0 -34
|
@@ -1,1140 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-redundant-type-constituents */
|
|
2
|
-
import { Buffer } from 'buffer';
|
|
3
|
-
import type * as fs from 'node:fs';
|
|
4
|
-
import type * as promises from 'node:fs/promises';
|
|
5
|
-
import type { Stream } from 'node:stream';
|
|
6
|
-
import type { ReadableStreamController, ReadableStream as TReadableStream } from 'node:stream/web';
|
|
7
|
-
import type { Interface as ReadlineInterface } from 'readline';
|
|
8
|
-
import { Errno, ErrnoError } from '../error.js';
|
|
9
|
-
import type { File } from '../file.js';
|
|
10
|
-
import { flagToMode, isAppendable, isExclusive, isReadable, isTruncating, isWriteable, parseFlag } from '../file.js';
|
|
11
|
-
import type { FileContents } from '../filesystem.js';
|
|
12
|
-
import '../polyfills.js';
|
|
13
|
-
import { BigIntStats, type Stats } from '../stats.js';
|
|
14
|
-
import { decodeUTF8, normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '../utils.js';
|
|
15
|
-
import * as cache from './cache.js';
|
|
16
|
-
import { config } from './config.js';
|
|
17
|
-
import * as constants from './constants.js';
|
|
18
|
-
import { Dir, Dirent } from './dir.js';
|
|
19
|
-
import { dirname, join, parse, resolve } from './path.js';
|
|
20
|
-
import { _statfs, fd2file, fdMap, file2fd, fixError, resolveMount, type InternalOptions, type ReaddirOptions } from './shared.js';
|
|
21
|
-
import { ReadStream, WriteStream } from './streams.js';
|
|
22
|
-
import { FSWatcher, emitChange } from './watchers.js';
|
|
23
|
-
export * as constants from './constants.js';
|
|
24
|
-
|
|
25
|
-
export class FileHandle implements promises.FileHandle {
|
|
26
|
-
/**
|
|
27
|
-
* The file descriptor for this file handle.
|
|
28
|
-
*/
|
|
29
|
-
public readonly fd: number;
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* @internal
|
|
33
|
-
* The file for this file handle
|
|
34
|
-
*/
|
|
35
|
-
public readonly file: File;
|
|
36
|
-
|
|
37
|
-
public constructor(fdOrFile: number | File) {
|
|
38
|
-
const isFile = typeof fdOrFile != 'number';
|
|
39
|
-
this.fd = isFile ? file2fd(fdOrFile) : fdOrFile;
|
|
40
|
-
this.file = isFile ? fdOrFile : fd2file(fdOrFile);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Asynchronous fchown(2) - Change ownership of a file.
|
|
45
|
-
*/
|
|
46
|
-
public async chown(uid: number, gid: number): Promise<void> {
|
|
47
|
-
await this.file.chown(uid, gid);
|
|
48
|
-
emitChange('change', this.file.path);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Asynchronous fchmod(2) - Change permissions of a file.
|
|
53
|
-
* @param mode A file mode. If a string is passed, it is parsed as an octal integer.
|
|
54
|
-
*/
|
|
55
|
-
public async chmod(mode: fs.Mode): Promise<void> {
|
|
56
|
-
const numMode = normalizeMode(mode, -1);
|
|
57
|
-
if (numMode < 0) {
|
|
58
|
-
throw new ErrnoError(Errno.EINVAL, 'Invalid mode.');
|
|
59
|
-
}
|
|
60
|
-
await this.file.chmod(numMode);
|
|
61
|
-
emitChange('change', this.file.path);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Asynchronous fdatasync(2) - synchronize a file's in-core state with storage device.
|
|
66
|
-
*/
|
|
67
|
-
public datasync(): Promise<void> {
|
|
68
|
-
return this.file.datasync();
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Asynchronous fsync(2) - synchronize a file's in-core state with the underlying storage device.
|
|
73
|
-
*/
|
|
74
|
-
public sync(): Promise<void> {
|
|
75
|
-
return this.file.sync();
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Asynchronous ftruncate(2) - Truncate a file to a specified length.
|
|
80
|
-
* @param length If not specified, defaults to `0`.
|
|
81
|
-
*/
|
|
82
|
-
public async truncate(length?: number | null): Promise<void> {
|
|
83
|
-
length ||= 0;
|
|
84
|
-
if (length < 0) {
|
|
85
|
-
throw new ErrnoError(Errno.EINVAL);
|
|
86
|
-
}
|
|
87
|
-
await this.file.truncate(length);
|
|
88
|
-
emitChange('change', this.file.path);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Asynchronously change file timestamps of the file.
|
|
93
|
-
* @param atime The last access time. If a string is provided, it will be coerced to number.
|
|
94
|
-
* @param mtime The last modified time. If a string is provided, it will be coerced to number.
|
|
95
|
-
*/
|
|
96
|
-
public async utimes(atime: string | number | Date, mtime: string | number | Date): Promise<void> {
|
|
97
|
-
await this.file.utimes(normalizeTime(atime), normalizeTime(mtime));
|
|
98
|
-
emitChange('change', this.file.path);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Asynchronously append data to a file, creating the file if it does not exist. The underlying file will _not_ be closed automatically.
|
|
103
|
-
* The `FileHandle` must have been opened for appending.
|
|
104
|
-
* @param data The data to write. If something other than a `Buffer` or `Uint8Array` is provided, the value is coerced to a string.
|
|
105
|
-
* @param _options Either the encoding for the file, or an object optionally specifying the encoding, file mode, and flag.
|
|
106
|
-
* - `encoding` defaults to `'utf8'`.
|
|
107
|
-
* - `mode` defaults to `0o666`.
|
|
108
|
-
* - `flag` defaults to `'a'`.
|
|
109
|
-
*/
|
|
110
|
-
public async appendFile(data: string | Uint8Array, _options: (fs.ObjectEncodingOptions & promises.FlagAndOpenMode) | BufferEncoding = {}): Promise<void> {
|
|
111
|
-
const options = normalizeOptions(_options, 'utf8', 'a', 0o644);
|
|
112
|
-
const flag = parseFlag(options.flag);
|
|
113
|
-
if (!isAppendable(flag)) {
|
|
114
|
-
throw new ErrnoError(Errno.EINVAL, 'Flag passed to appendFile must allow for appending.');
|
|
115
|
-
}
|
|
116
|
-
if (typeof data != 'string' && !options.encoding) {
|
|
117
|
-
throw new ErrnoError(Errno.EINVAL, 'Encoding not specified');
|
|
118
|
-
}
|
|
119
|
-
const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding!) : data;
|
|
120
|
-
await this.file.write(encodedData, 0, encodedData.length);
|
|
121
|
-
emitChange('change', this.file.path);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Asynchronously reads data from the file.
|
|
126
|
-
* The `FileHandle` must have been opened for reading.
|
|
127
|
-
* @param buffer The buffer that the data will be written to.
|
|
128
|
-
* @param offset The offset in the buffer at which to start writing.
|
|
129
|
-
* @param length The number of bytes to read.
|
|
130
|
-
* @param position The offset from the beginning of the file from which data should be read. If `null`, data will be read from the current position.
|
|
131
|
-
*/
|
|
132
|
-
public read<TBuffer extends NodeJS.ArrayBufferView>(buffer: TBuffer, offset?: number, length?: number, position?: number | null): Promise<promises.FileReadResult<TBuffer>> {
|
|
133
|
-
if (isNaN(+position!)) {
|
|
134
|
-
position = this.file.position;
|
|
135
|
-
}
|
|
136
|
-
return this.file.read(buffer, offset, length, position!);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Asynchronously reads the entire contents of a file. The underlying file will _not_ be closed automatically.
|
|
141
|
-
* The `FileHandle` must have been opened for reading.
|
|
142
|
-
* @param _options An object that may contain an optional flag.
|
|
143
|
-
* If a flag is not provided, it defaults to `'r'`.
|
|
144
|
-
*/
|
|
145
|
-
public async readFile(_options?: { flag?: fs.OpenMode }): Promise<Buffer>;
|
|
146
|
-
public async readFile(_options: (fs.ObjectEncodingOptions & promises.FlagAndOpenMode) | BufferEncoding): Promise<string>;
|
|
147
|
-
public async readFile(_options?: (fs.ObjectEncodingOptions & promises.FlagAndOpenMode) | BufferEncoding): Promise<string | Buffer> {
|
|
148
|
-
const options = normalizeOptions(_options, null, 'r', 0o444);
|
|
149
|
-
const flag = parseFlag(options.flag);
|
|
150
|
-
if (!isReadable(flag)) {
|
|
151
|
-
throw new ErrnoError(Errno.EINVAL, 'Flag passed must allow for reading.');
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const { size } = await this.stat();
|
|
155
|
-
const { buffer: data } = await this.file.read(new Uint8Array(size), 0, size, 0);
|
|
156
|
-
const buffer = Buffer.from(data);
|
|
157
|
-
return options.encoding ? buffer.toString(options.encoding) : buffer;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Returns a `ReadableStream` that may be used to read the files data.
|
|
162
|
-
*
|
|
163
|
-
* An error will be thrown if this method is called more than once or is called after the `FileHandle` is closed or closing.
|
|
164
|
-
*
|
|
165
|
-
* While the `ReadableStream` will read the file to completion,
|
|
166
|
-
* it will not close the `FileHandle` automatically.
|
|
167
|
-
* User code must still call the `fileHandle.close()` method.
|
|
168
|
-
*
|
|
169
|
-
* @since v17.0.0
|
|
170
|
-
* @experimental
|
|
171
|
-
*/
|
|
172
|
-
public readableWebStream(options: promises.ReadableWebStreamOptions = {}): TReadableStream<Uint8Array> {
|
|
173
|
-
// Note: using an arrow function to preserve `this`
|
|
174
|
-
const start = async (controller: ReadableStreamController<Uint8Array>) => {
|
|
175
|
-
try {
|
|
176
|
-
const chunkSize = 64 * 1024,
|
|
177
|
-
maxChunks = 1e7;
|
|
178
|
-
let i = 0,
|
|
179
|
-
position = 0,
|
|
180
|
-
bytesRead = NaN;
|
|
181
|
-
|
|
182
|
-
while (bytesRead > 0) {
|
|
183
|
-
const result = await this.read(new Uint8Array(chunkSize), 0, chunkSize, position);
|
|
184
|
-
if (!result.bytesRead) {
|
|
185
|
-
controller.close();
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
controller.enqueue(result.buffer.slice(0, result.bytesRead));
|
|
189
|
-
position += result.bytesRead;
|
|
190
|
-
if (++i >= maxChunks) {
|
|
191
|
-
throw new ErrnoError(Errno.EFBIG, 'Too many iterations on readable stream', this.file.path, 'FileHandle.readableWebStream');
|
|
192
|
-
}
|
|
193
|
-
bytesRead = result.bytesRead;
|
|
194
|
-
}
|
|
195
|
-
} catch (e) {
|
|
196
|
-
controller.error(e);
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
const _gt = globalThis;
|
|
201
|
-
if (!('ReadableStream' in _gt)) {
|
|
202
|
-
throw new ErrnoError(Errno.ENOSYS, 'ReadableStream is missing on globalThis');
|
|
203
|
-
}
|
|
204
|
-
return new (_gt as { ReadableStream: new (...args: unknown[]) => TReadableStream<Uint8Array> }).ReadableStream({ start, type: options.type });
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* @todo Implement
|
|
209
|
-
*/
|
|
210
|
-
public readLines(options?: promises.CreateReadStreamOptions): ReadlineInterface {
|
|
211
|
-
throw ErrnoError.With('ENOSYS', this.file.path, 'FileHandle.readLines');
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
public [Symbol.asyncDispose](): Promise<void> {
|
|
215
|
-
return this.close();
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Asynchronous fstat(2) - Get file status.
|
|
220
|
-
*/
|
|
221
|
-
public async stat(opts: fs.BigIntOptions): Promise<BigIntStats>;
|
|
222
|
-
public async stat(opts?: fs.StatOptions & { bigint?: false }): Promise<Stats>;
|
|
223
|
-
public async stat(opts?: fs.StatOptions): Promise<Stats | BigIntStats> {
|
|
224
|
-
const stats = await this.file.stat();
|
|
225
|
-
if (config.checkAccess && !stats.hasAccess(constants.R_OK)) {
|
|
226
|
-
throw ErrnoError.With('EACCES', this.file.path, 'stat');
|
|
227
|
-
}
|
|
228
|
-
return opts?.bigint ? new BigIntStats(stats) : stats;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Asynchronously writes `string` to the file.
|
|
233
|
-
* The `FileHandle` must have been opened for writing.
|
|
234
|
-
* It is unsafe to call `write()` multiple times on the same file without waiting for the `Promise`
|
|
235
|
-
* to be resolved (or rejected). For this scenario, `fs.createWriteStream` is strongly recommended.
|
|
236
|
-
*/
|
|
237
|
-
public async write(
|
|
238
|
-
data: FileContents,
|
|
239
|
-
posOrOff?: number | null,
|
|
240
|
-
lenOrEnc?: BufferEncoding | number,
|
|
241
|
-
position?: number | null
|
|
242
|
-
): Promise<{ bytesWritten: number; buffer: FileContents }>;
|
|
243
|
-
public async write<TBuffer extends Uint8Array>(buffer: TBuffer, offset?: number, length?: number, position?: number): Promise<{ bytesWritten: number; buffer: TBuffer }>;
|
|
244
|
-
public async write(data: string, position?: number, encoding?: BufferEncoding): Promise<{ bytesWritten: number; buffer: string }>;
|
|
245
|
-
public async write(
|
|
246
|
-
data: FileContents,
|
|
247
|
-
posOrOff?: number,
|
|
248
|
-
lenOrEnc?: BufferEncoding | number,
|
|
249
|
-
position?: number | null
|
|
250
|
-
): Promise<{ bytesWritten: number; buffer: FileContents }> {
|
|
251
|
-
let buffer: Uint8Array, offset: number | null | undefined, length: number;
|
|
252
|
-
if (typeof data === 'string') {
|
|
253
|
-
// Signature 1: (fd, string, [position?, [encoding?]])
|
|
254
|
-
position = typeof posOrOff === 'number' ? posOrOff : null;
|
|
255
|
-
const encoding = typeof lenOrEnc === 'string' ? lenOrEnc : ('utf8' as BufferEncoding);
|
|
256
|
-
offset = 0;
|
|
257
|
-
buffer = Buffer.from(data, encoding);
|
|
258
|
-
length = buffer.length;
|
|
259
|
-
} else {
|
|
260
|
-
// Signature 2: (fd, buffer, offset, length, position?)
|
|
261
|
-
buffer = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
262
|
-
offset = posOrOff;
|
|
263
|
-
length = lenOrEnc as number;
|
|
264
|
-
position = typeof position === 'number' ? position : null;
|
|
265
|
-
}
|
|
266
|
-
position ??= this.file.position;
|
|
267
|
-
const bytesWritten = await this.file.write(buffer, offset, length, position);
|
|
268
|
-
emitChange('change', this.file.path);
|
|
269
|
-
return { buffer, bytesWritten };
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
* Asynchronously writes data to a file, replacing the file if it already exists. The underlying file will _not_ be closed automatically.
|
|
274
|
-
* The `FileHandle` must have been opened for writing.
|
|
275
|
-
* It is unsafe to call `writeFile()` multiple times on the same file without waiting for the `Promise` to be resolved (or rejected).
|
|
276
|
-
* @param data The data to write. If something other than a `Buffer` or `Uint8Array` is provided, the value is coerced to a string.
|
|
277
|
-
* @param _options Either the encoding for the file, or an object optionally specifying the encoding, file mode, and flag.
|
|
278
|
-
* - `encoding` defaults to `'utf8'`.
|
|
279
|
-
* - `mode` defaults to `0o666`.
|
|
280
|
-
* - `flag` defaults to `'w'`.
|
|
281
|
-
*/
|
|
282
|
-
public async writeFile(data: string | Uint8Array, _options: fs.WriteFileOptions = {}): Promise<void> {
|
|
283
|
-
const options = normalizeOptions(_options, 'utf8', 'w', 0o644);
|
|
284
|
-
const flag = parseFlag(options.flag);
|
|
285
|
-
if (!isWriteable(flag)) {
|
|
286
|
-
throw new ErrnoError(Errno.EINVAL, 'Flag passed must allow for writing.');
|
|
287
|
-
}
|
|
288
|
-
if (typeof data != 'string' && !options.encoding) {
|
|
289
|
-
throw new ErrnoError(Errno.EINVAL, 'Encoding not specified');
|
|
290
|
-
}
|
|
291
|
-
const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding!) : data;
|
|
292
|
-
await this.file.write(encodedData, 0, encodedData.length, 0);
|
|
293
|
-
emitChange('change', this.file.path);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* Asynchronous close(2) - close a `FileHandle`.
|
|
298
|
-
*/
|
|
299
|
-
public async close(): Promise<void> {
|
|
300
|
-
await this.file.close();
|
|
301
|
-
fdMap.delete(this.fd);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
* Asynchronous `writev`. Writes from multiple buffers.
|
|
306
|
-
* @param buffers An array of Uint8Array buffers.
|
|
307
|
-
* @param position The position in the file where to begin writing.
|
|
308
|
-
* @returns The number of bytes written.
|
|
309
|
-
*/
|
|
310
|
-
public async writev(buffers: Uint8Array[], position?: number): Promise<fs.WriteVResult> {
|
|
311
|
-
let bytesWritten = 0;
|
|
312
|
-
|
|
313
|
-
for (const buffer of buffers) {
|
|
314
|
-
bytesWritten += (await this.write(buffer, 0, buffer.length, position! + bytesWritten)).bytesWritten;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
return { bytesWritten, buffers };
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* Asynchronous `readv`. Reads into multiple buffers.
|
|
322
|
-
* @param buffers An array of Uint8Array buffers.
|
|
323
|
-
* @param position The position in the file where to begin reading.
|
|
324
|
-
* @returns The number of bytes read.
|
|
325
|
-
*/
|
|
326
|
-
public async readv(buffers: NodeJS.ArrayBufferView[], position?: number): Promise<fs.ReadVResult> {
|
|
327
|
-
let bytesRead = 0;
|
|
328
|
-
|
|
329
|
-
for (const buffer of buffers) {
|
|
330
|
-
bytesRead += (await this.read(buffer, 0, buffer.byteLength, position! + bytesRead)).bytesRead;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
return { bytesRead, buffers };
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Creates a stream for reading from the file.
|
|
338
|
-
* @param options Options for the readable stream
|
|
339
|
-
*/
|
|
340
|
-
public createReadStream(options?: promises.CreateReadStreamOptions): ReadStream {
|
|
341
|
-
const stream = new ReadStream({
|
|
342
|
-
highWaterMark: options?.highWaterMark || 64 * 1024,
|
|
343
|
-
encoding: options!.encoding!,
|
|
344
|
-
|
|
345
|
-
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
346
|
-
read: async (size: number) => {
|
|
347
|
-
try {
|
|
348
|
-
const result = await this.read(new Uint8Array(size), 0, size, this.file.position);
|
|
349
|
-
stream.push(!result.bytesRead ? null : result.buffer.slice(0, result.bytesRead)); // Push data or null for EOF
|
|
350
|
-
this.file.position += result.bytesRead;
|
|
351
|
-
} catch (error) {
|
|
352
|
-
stream.destroy(error as Error);
|
|
353
|
-
}
|
|
354
|
-
},
|
|
355
|
-
});
|
|
356
|
-
|
|
357
|
-
stream.path = this.file.path;
|
|
358
|
-
return stream;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
/**
|
|
362
|
-
* Creates a stream for writing to the file.
|
|
363
|
-
* @param options Options for the writeable stream.
|
|
364
|
-
*/
|
|
365
|
-
public createWriteStream(options?: promises.CreateWriteStreamOptions): WriteStream {
|
|
366
|
-
const streamOptions = {
|
|
367
|
-
highWaterMark: options?.highWaterMark,
|
|
368
|
-
encoding: options?.encoding,
|
|
369
|
-
|
|
370
|
-
write: async (chunk: Uint8Array, encoding: BufferEncoding, callback: (error?: Error | null) => void) => {
|
|
371
|
-
try {
|
|
372
|
-
const { bytesWritten } = await this.write(chunk, null, encoding);
|
|
373
|
-
callback(bytesWritten == chunk.length ? null : new Error('Failed to write full chunk'));
|
|
374
|
-
} catch (error) {
|
|
375
|
-
callback(error as Error);
|
|
376
|
-
}
|
|
377
|
-
},
|
|
378
|
-
};
|
|
379
|
-
|
|
380
|
-
const stream = new WriteStream(streamOptions);
|
|
381
|
-
stream.path = this.file.path;
|
|
382
|
-
return stream;
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
export async function rename(oldPath: fs.PathLike, newPath: fs.PathLike): Promise<void> {
|
|
387
|
-
oldPath = normalizePath(oldPath);
|
|
388
|
-
newPath = normalizePath(newPath);
|
|
389
|
-
const src = resolveMount(oldPath);
|
|
390
|
-
const dst = resolveMount(newPath);
|
|
391
|
-
if (config.checkAccess && !(await stat(dirname(oldPath))).hasAccess(constants.W_OK)) {
|
|
392
|
-
throw ErrnoError.With('EACCES', oldPath, 'rename');
|
|
393
|
-
}
|
|
394
|
-
try {
|
|
395
|
-
if (src.mountPoint == dst.mountPoint) {
|
|
396
|
-
await src.fs.rename(src.path, dst.path);
|
|
397
|
-
emitChange('rename', oldPath.toString());
|
|
398
|
-
emitChange('change', newPath.toString());
|
|
399
|
-
return;
|
|
400
|
-
}
|
|
401
|
-
await writeFile(newPath, await readFile(oldPath));
|
|
402
|
-
await unlink(oldPath);
|
|
403
|
-
emitChange('rename', oldPath.toString());
|
|
404
|
-
} catch (e) {
|
|
405
|
-
throw fixError(e as ErrnoError, { [src.path]: oldPath, [dst.path]: newPath });
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
rename satisfies typeof promises.rename;
|
|
409
|
-
|
|
410
|
-
/**
|
|
411
|
-
* Test whether or not `path` exists by checking with the file system.
|
|
412
|
-
*/
|
|
413
|
-
export async function exists(path: fs.PathLike): Promise<boolean> {
|
|
414
|
-
try {
|
|
415
|
-
const { fs, path: resolved } = resolveMount(await realpath(path));
|
|
416
|
-
return await fs.exists(resolved);
|
|
417
|
-
} catch (e) {
|
|
418
|
-
if (e instanceof ErrnoError && e.code == 'ENOENT') {
|
|
419
|
-
return false;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
throw e;
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
export async function stat(path: fs.PathLike, options: fs.BigIntOptions): Promise<BigIntStats>;
|
|
427
|
-
export async function stat(path: fs.PathLike, options?: { bigint?: false }): Promise<Stats>;
|
|
428
|
-
export async function stat(path: fs.PathLike, options?: fs.StatOptions): Promise<Stats | BigIntStats>;
|
|
429
|
-
export async function stat(path: fs.PathLike, options?: fs.StatOptions): Promise<Stats | BigIntStats> {
|
|
430
|
-
path = normalizePath(path);
|
|
431
|
-
const { fs, path: resolved } = resolveMount(await realpath(path));
|
|
432
|
-
try {
|
|
433
|
-
const stats = await fs.stat(resolved);
|
|
434
|
-
if (config.checkAccess && !stats.hasAccess(constants.R_OK)) {
|
|
435
|
-
throw ErrnoError.With('EACCES', resolved, 'stat');
|
|
436
|
-
}
|
|
437
|
-
return options?.bigint ? new BigIntStats(stats) : stats;
|
|
438
|
-
} catch (e) {
|
|
439
|
-
throw fixError(e as ErrnoError, { [resolved]: path });
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
stat satisfies typeof promises.stat;
|
|
443
|
-
|
|
444
|
-
/**
|
|
445
|
-
* `lstat`.
|
|
446
|
-
* `lstat()` is identical to `stat()`, except that if path is a symbolic link,
|
|
447
|
-
* then the link itself is stat-ed, not the file that it refers to.
|
|
448
|
-
*/
|
|
449
|
-
export async function lstat(path: fs.PathLike, options?: { bigint?: boolean }): Promise<Stats>;
|
|
450
|
-
export async function lstat(path: fs.PathLike, options: { bigint: true }): Promise<BigIntStats>;
|
|
451
|
-
export async function lstat(path: fs.PathLike, options?: fs.StatOptions): Promise<Stats | BigIntStats> {
|
|
452
|
-
path = normalizePath(path);
|
|
453
|
-
const { fs, path: resolved } = resolveMount(path);
|
|
454
|
-
try {
|
|
455
|
-
const stats = await fs.stat(resolved);
|
|
456
|
-
return options?.bigint ? new BigIntStats(stats) : stats;
|
|
457
|
-
} catch (e) {
|
|
458
|
-
throw fixError(e as ErrnoError, { [resolved]: path });
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
lstat satisfies typeof promises.lstat;
|
|
462
|
-
|
|
463
|
-
// FILE-ONLY METHODS
|
|
464
|
-
|
|
465
|
-
export async function truncate(path: fs.PathLike, len: number = 0): Promise<void> {
|
|
466
|
-
await using handle = await open(path, 'r+');
|
|
467
|
-
await handle.truncate(len);
|
|
468
|
-
}
|
|
469
|
-
truncate satisfies typeof promises.truncate;
|
|
470
|
-
|
|
471
|
-
export async function unlink(path: fs.PathLike): Promise<void> {
|
|
472
|
-
path = normalizePath(path);
|
|
473
|
-
const { fs, path: resolved } = resolveMount(path);
|
|
474
|
-
try {
|
|
475
|
-
if (config.checkAccess && !(await (cache.stats.getAsync(path) || fs.stat(resolved))).hasAccess(constants.W_OK)) {
|
|
476
|
-
throw ErrnoError.With('EACCES', resolved, 'unlink');
|
|
477
|
-
}
|
|
478
|
-
await fs.unlink(resolved);
|
|
479
|
-
emitChange('rename', path.toString());
|
|
480
|
-
} catch (e) {
|
|
481
|
-
throw fixError(e as ErrnoError, { [resolved]: path });
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
unlink satisfies typeof promises.unlink;
|
|
485
|
-
|
|
486
|
-
/**
|
|
487
|
-
* Opens a file. This helper handles the complexity of file flags.
|
|
488
|
-
* @internal
|
|
489
|
-
*/
|
|
490
|
-
async function _open(path: fs.PathLike, _flag: fs.OpenMode, _mode: fs.Mode = 0o644, resolveSymlinks: boolean): Promise<FileHandle> {
|
|
491
|
-
path = normalizePath(path);
|
|
492
|
-
const mode = normalizeMode(_mode, 0o644),
|
|
493
|
-
flag = parseFlag(_flag);
|
|
494
|
-
|
|
495
|
-
path = resolveSymlinks ? await realpath(path) : path;
|
|
496
|
-
const { fs, path: resolved } = resolveMount(path);
|
|
497
|
-
|
|
498
|
-
const stats = await fs.stat(resolved).catch(() => null);
|
|
499
|
-
|
|
500
|
-
if (!stats) {
|
|
501
|
-
if ((!isWriteable(flag) && !isAppendable(flag)) || flag == 'r+') {
|
|
502
|
-
throw ErrnoError.With('ENOENT', path, '_open');
|
|
503
|
-
}
|
|
504
|
-
// Create the file
|
|
505
|
-
const parentStats: Stats = await fs.stat(dirname(resolved));
|
|
506
|
-
if (config.checkAccess && !parentStats.hasAccess(constants.W_OK)) {
|
|
507
|
-
throw ErrnoError.With('EACCES', dirname(path), '_open');
|
|
508
|
-
}
|
|
509
|
-
if (!parentStats.isDirectory()) {
|
|
510
|
-
throw ErrnoError.With('ENOTDIR', dirname(path), '_open');
|
|
511
|
-
}
|
|
512
|
-
return new FileHandle(await fs.createFile(resolved, flag, mode));
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
if (config.checkAccess && !stats.hasAccess(flagToMode(flag))) {
|
|
516
|
-
throw ErrnoError.With('EACCES', path, '_open');
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
if (isExclusive(flag)) {
|
|
520
|
-
throw ErrnoError.With('EEXIST', path, '_open');
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
const handle = new FileHandle(await fs.openFile(resolved, flag));
|
|
524
|
-
|
|
525
|
-
/*
|
|
526
|
-
In a previous implementation, we deleted the file and
|
|
527
|
-
re-created it. However, this created a race condition if another
|
|
528
|
-
asynchronous request was trying to read the file, as the file
|
|
529
|
-
would not exist for a small period of time.
|
|
530
|
-
*/
|
|
531
|
-
if (isTruncating(flag)) {
|
|
532
|
-
await handle.truncate(0);
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
return handle;
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
/**
|
|
539
|
-
* Asynchronous file open.
|
|
540
|
-
* @see http://www.manpagez.com/man/2/open/
|
|
541
|
-
* @param flag Handles the complexity of the various file modes. See its API for more details.
|
|
542
|
-
* @param mode Mode to use to open the file. Can be ignored if the filesystem doesn't support permissions.
|
|
543
|
-
*/
|
|
544
|
-
export async function open(path: fs.PathLike, flag: fs.OpenMode = 'r', mode: fs.Mode = 0o644): Promise<FileHandle> {
|
|
545
|
-
return await _open(path, flag, mode, true);
|
|
546
|
-
}
|
|
547
|
-
open satisfies typeof promises.open;
|
|
548
|
-
|
|
549
|
-
/**
|
|
550
|
-
* Asynchronously reads the entire contents of a file.
|
|
551
|
-
* @option encoding The string encoding for the file contents. Defaults to `null`.
|
|
552
|
-
* @option flag Defaults to `'r'`.
|
|
553
|
-
* @returns the file data
|
|
554
|
-
*/
|
|
555
|
-
export async function readFile(path: fs.PathLike | promises.FileHandle, options?: { encoding?: null; flag?: fs.OpenMode } | null): Promise<Buffer>;
|
|
556
|
-
export async function readFile(path: fs.PathLike | promises.FileHandle, options: { encoding: BufferEncoding; flag?: fs.OpenMode } | BufferEncoding): Promise<string>;
|
|
557
|
-
export async function readFile(
|
|
558
|
-
path: fs.PathLike | promises.FileHandle,
|
|
559
|
-
options?: (fs.ObjectEncodingOptions & { flag?: fs.OpenMode }) | BufferEncoding | null
|
|
560
|
-
): Promise<string | Buffer>;
|
|
561
|
-
export async function readFile(
|
|
562
|
-
path: fs.PathLike | promises.FileHandle,
|
|
563
|
-
_options?: (fs.ObjectEncodingOptions & { flag?: fs.OpenMode }) | BufferEncoding | null
|
|
564
|
-
): Promise<Buffer | string> {
|
|
565
|
-
const options = normalizeOptions(_options, null, 'r', 0o644);
|
|
566
|
-
await using handle: FileHandle | promises.FileHandle = typeof path == 'object' && 'fd' in path ? path : await open(path as string, options.flag, options.mode);
|
|
567
|
-
return await handle.readFile(options);
|
|
568
|
-
}
|
|
569
|
-
readFile satisfies typeof promises.readFile;
|
|
570
|
-
|
|
571
|
-
/**
|
|
572
|
-
* Asynchronously writes data to a file, replacing the file if it already exists.
|
|
573
|
-
*
|
|
574
|
-
* The encoding option is ignored if data is a buffer.
|
|
575
|
-
* @option encoding Defaults to `'utf8'`.
|
|
576
|
-
* @option mode Defaults to `0644`.
|
|
577
|
-
* @option flag Defaults to `'w'`.
|
|
578
|
-
*/
|
|
579
|
-
export async function writeFile(
|
|
580
|
-
path: fs.PathLike | promises.FileHandle,
|
|
581
|
-
data: FileContents | Stream | Iterable<string | ArrayBufferView> | AsyncIterable<string | ArrayBufferView>,
|
|
582
|
-
_options?: (fs.ObjectEncodingOptions & { mode?: fs.Mode; flag?: fs.OpenMode; flush?: boolean }) | BufferEncoding | null
|
|
583
|
-
): Promise<void> {
|
|
584
|
-
const options = normalizeOptions(_options, 'utf8', 'w+', 0o644);
|
|
585
|
-
await using handle = path instanceof FileHandle ? path : await open((path as fs.PathLike).toString(), options.flag, options.mode);
|
|
586
|
-
|
|
587
|
-
const _data = typeof data == 'string' ? data : data;
|
|
588
|
-
if (typeof _data != 'string' && !(_data instanceof Uint8Array)) {
|
|
589
|
-
throw new ErrnoError(Errno.EINVAL, 'Iterables and streams not supported', handle.file.path, 'writeFile');
|
|
590
|
-
}
|
|
591
|
-
await handle.writeFile(_data, options);
|
|
592
|
-
}
|
|
593
|
-
writeFile satisfies typeof promises.writeFile;
|
|
594
|
-
|
|
595
|
-
/**
|
|
596
|
-
* Asynchronously append data to a file, creating the file if it not yet exists.
|
|
597
|
-
* @option encoding Defaults to `'utf8'`.
|
|
598
|
-
* @option mode Defaults to `0644`.
|
|
599
|
-
* @option flag Defaults to `'a'`.
|
|
600
|
-
*/
|
|
601
|
-
export async function appendFile(
|
|
602
|
-
path: fs.PathLike | promises.FileHandle,
|
|
603
|
-
data: FileContents,
|
|
604
|
-
_options?: BufferEncoding | (fs.EncodingOption & { mode?: fs.Mode; flag?: fs.OpenMode }) | null
|
|
605
|
-
): Promise<void> {
|
|
606
|
-
const options = normalizeOptions(_options, 'utf8', 'a', 0o644);
|
|
607
|
-
const flag = parseFlag(options.flag);
|
|
608
|
-
if (!isAppendable(flag)) {
|
|
609
|
-
throw new ErrnoError(Errno.EINVAL, 'Flag passed to appendFile must allow for appending.');
|
|
610
|
-
}
|
|
611
|
-
if (typeof data != 'string' && !options.encoding) {
|
|
612
|
-
throw new ErrnoError(Errno.EINVAL, 'Encoding not specified');
|
|
613
|
-
}
|
|
614
|
-
const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding!) : new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
615
|
-
await using handle: FileHandle | promises.FileHandle = typeof path == 'object' && 'fd' in path ? path : await open(path as string, options.flag, options.mode);
|
|
616
|
-
|
|
617
|
-
await handle.appendFile(encodedData, options);
|
|
618
|
-
}
|
|
619
|
-
appendFile satisfies typeof promises.appendFile;
|
|
620
|
-
|
|
621
|
-
// DIRECTORY-ONLY METHODS
|
|
622
|
-
|
|
623
|
-
export async function rmdir(path: fs.PathLike): Promise<void> {
|
|
624
|
-
path = await realpath(path);
|
|
625
|
-
const { fs, path: resolved } = resolveMount(path);
|
|
626
|
-
try {
|
|
627
|
-
const stats = await (cache.stats.getAsync(path) || fs.stat(resolved));
|
|
628
|
-
if (!stats) {
|
|
629
|
-
throw ErrnoError.With('ENOENT', path, 'rmdir');
|
|
630
|
-
}
|
|
631
|
-
if (!stats.isDirectory()) {
|
|
632
|
-
throw ErrnoError.With('ENOTDIR', resolved, 'rmdir');
|
|
633
|
-
}
|
|
634
|
-
if (config.checkAccess && !stats.hasAccess(constants.W_OK)) {
|
|
635
|
-
throw ErrnoError.With('EACCES', resolved, 'rmdir');
|
|
636
|
-
}
|
|
637
|
-
await fs.rmdir(resolved);
|
|
638
|
-
emitChange('rename', path.toString());
|
|
639
|
-
} catch (e) {
|
|
640
|
-
throw fixError(e as ErrnoError, { [resolved]: path });
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
rmdir satisfies typeof promises.rmdir;
|
|
644
|
-
|
|
645
|
-
/**
|
|
646
|
-
* Asynchronous mkdir(2) - create a directory.
|
|
647
|
-
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
|
648
|
-
* @param options Either the file mode, or an object optionally specifying the file mode and whether parent folders
|
|
649
|
-
* should be created. If a string is passed, it is parsed as an octal integer. If not specified, defaults to `0o777`.
|
|
650
|
-
*/
|
|
651
|
-
export async function mkdir(path: fs.PathLike, options: fs.MakeDirectoryOptions & { recursive: true }): Promise<string | undefined>;
|
|
652
|
-
export async function mkdir(path: fs.PathLike, options?: fs.Mode | (fs.MakeDirectoryOptions & { recursive?: false | undefined }) | null): Promise<void>;
|
|
653
|
-
export async function mkdir(path: fs.PathLike, options?: fs.Mode | fs.MakeDirectoryOptions | null): Promise<string | undefined>;
|
|
654
|
-
export async function mkdir(path: fs.PathLike, options?: fs.Mode | fs.MakeDirectoryOptions | null): Promise<string | undefined | void> {
|
|
655
|
-
options = typeof options === 'object' ? options : { mode: options };
|
|
656
|
-
const mode = normalizeMode(options?.mode, 0o777);
|
|
657
|
-
|
|
658
|
-
path = await realpath(path);
|
|
659
|
-
const { fs, path: resolved } = resolveMount(path);
|
|
660
|
-
const errorPaths: Record<string, string> = { [resolved]: path };
|
|
661
|
-
|
|
662
|
-
try {
|
|
663
|
-
if (!options?.recursive) {
|
|
664
|
-
if (config.checkAccess && !(await fs.stat(dirname(resolved))).hasAccess(constants.W_OK)) {
|
|
665
|
-
throw ErrnoError.With('EACCES', dirname(resolved), 'mkdir');
|
|
666
|
-
}
|
|
667
|
-
await fs.mkdir(resolved, mode);
|
|
668
|
-
emitChange('rename', path.toString());
|
|
669
|
-
return;
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
const dirs: string[] = [];
|
|
673
|
-
for (let dir = resolved, origDir = path; !(await fs.exists(dir)); dir = dirname(dir), origDir = dirname(origDir)) {
|
|
674
|
-
dirs.unshift(dir);
|
|
675
|
-
errorPaths[dir] = origDir;
|
|
676
|
-
}
|
|
677
|
-
for (const dir of dirs) {
|
|
678
|
-
if (config.checkAccess && !(await fs.stat(dirname(dir))).hasAccess(constants.W_OK)) {
|
|
679
|
-
throw ErrnoError.With('EACCES', dirname(dir), 'mkdir');
|
|
680
|
-
}
|
|
681
|
-
await fs.mkdir(dir, mode);
|
|
682
|
-
emitChange('rename', dir);
|
|
683
|
-
}
|
|
684
|
-
return dirs[0];
|
|
685
|
-
} catch (e) {
|
|
686
|
-
throw fixError(e as ErrnoError, errorPaths);
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
mkdir satisfies typeof promises.mkdir;
|
|
690
|
-
|
|
691
|
-
/**
|
|
692
|
-
* Asynchronous readdir(3) - read a directory.
|
|
693
|
-
*
|
|
694
|
-
* Note: The order of entries is not guaranteed
|
|
695
|
-
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
|
696
|
-
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. If not provided, `'utf8'`.
|
|
697
|
-
*/
|
|
698
|
-
export async function readdir(path: fs.PathLike, options?: (fs.ObjectEncodingOptions & ReaddirOptions & { withFileTypes?: false }) | BufferEncoding | null): Promise<string[]>;
|
|
699
|
-
export async function readdir(path: fs.PathLike, options: fs.BufferEncodingOption & ReaddirOptions & { withFileTypes?: false }): Promise<Buffer[]>;
|
|
700
|
-
export async function readdir(
|
|
701
|
-
path: fs.PathLike,
|
|
702
|
-
options?: (fs.ObjectEncodingOptions & ReaddirOptions & { withFileTypes?: false }) | BufferEncoding | null
|
|
703
|
-
): Promise<string[] | Buffer[]>;
|
|
704
|
-
export async function readdir(path: fs.PathLike, options: fs.ObjectEncodingOptions & ReaddirOptions & { withFileTypes: true }): Promise<Dirent[]>;
|
|
705
|
-
export async function readdir(
|
|
706
|
-
path: fs.PathLike,
|
|
707
|
-
options?: (ReaddirOptions & (fs.ObjectEncodingOptions | fs.BufferEncodingOption)) | BufferEncoding | null
|
|
708
|
-
): Promise<string[] | Dirent[] | Buffer[]>;
|
|
709
|
-
export async function readdir(
|
|
710
|
-
path: fs.PathLike,
|
|
711
|
-
options?: (ReaddirOptions & (fs.ObjectEncodingOptions | fs.BufferEncodingOption)) | BufferEncoding | null
|
|
712
|
-
): Promise<string[] | Dirent[] | Buffer[]> {
|
|
713
|
-
options = typeof options === 'object' ? options : { encoding: options };
|
|
714
|
-
path = await realpath(path);
|
|
715
|
-
|
|
716
|
-
const handleError = (e: ErrnoError) => {
|
|
717
|
-
throw fixError(e, { [resolved]: path });
|
|
718
|
-
};
|
|
719
|
-
|
|
720
|
-
const { fs, path: resolved } = resolveMount(path);
|
|
721
|
-
|
|
722
|
-
const _stats = cache.stats.getAsync(path) || fs.stat(resolved).catch(handleError);
|
|
723
|
-
cache.stats.setAsync(path, _stats);
|
|
724
|
-
const stats = await _stats;
|
|
725
|
-
|
|
726
|
-
if (!stats) {
|
|
727
|
-
throw ErrnoError.With('ENOENT', path, 'readdir');
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
if (config.checkAccess && !stats.hasAccess(constants.R_OK)) {
|
|
731
|
-
throw ErrnoError.With('EACCES', path, 'readdir');
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
if (!stats.isDirectory()) {
|
|
735
|
-
throw ErrnoError.With('ENOTDIR', path, 'readdir');
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
const entries = await fs.readdir(resolved).catch(handleError);
|
|
739
|
-
|
|
740
|
-
const values: (string | Dirent | Buffer)[] = [];
|
|
741
|
-
const addEntry = async (entry: string) => {
|
|
742
|
-
let entryStats: Stats | undefined;
|
|
743
|
-
if (options?.recursive || options?.withFileTypes) {
|
|
744
|
-
const _entryStats = cache.stats.getAsync(join(path, entry)) || fs.stat(join(resolved, entry)).catch(handleError);
|
|
745
|
-
cache.stats.setAsync(join(path, entry), _entryStats);
|
|
746
|
-
entryStats = await _entryStats;
|
|
747
|
-
}
|
|
748
|
-
if (options?.withFileTypes) {
|
|
749
|
-
values.push(new Dirent(entry, entryStats!));
|
|
750
|
-
} else if (options?.encoding == 'buffer') {
|
|
751
|
-
values.push(Buffer.from(entry));
|
|
752
|
-
} else {
|
|
753
|
-
values.push(entry);
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
if (!options?.recursive || !entryStats?.isDirectory()) return;
|
|
757
|
-
|
|
758
|
-
for (const subEntry of await readdir(join(path, entry), { ...options, _isIndirect: true })) {
|
|
759
|
-
if (subEntry instanceof Dirent) {
|
|
760
|
-
subEntry.path = join(entry, subEntry.path);
|
|
761
|
-
values.push(subEntry);
|
|
762
|
-
} else if (Buffer.isBuffer(subEntry)) {
|
|
763
|
-
// Convert Buffer to string, prefix with the full path
|
|
764
|
-
values.push(Buffer.from(join(entry, decodeUTF8(subEntry))));
|
|
765
|
-
} else {
|
|
766
|
-
values.push(join(entry, subEntry));
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
};
|
|
770
|
-
await Promise.all(entries.map(addEntry));
|
|
771
|
-
if (!options?._isIndirect) {
|
|
772
|
-
cache.stats.clear();
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
return values as string[] | Dirent[];
|
|
776
|
-
}
|
|
777
|
-
readdir satisfies typeof promises.readdir;
|
|
778
|
-
|
|
779
|
-
export async function link(targetPath: fs.PathLike, linkPath: fs.PathLike): Promise<void> {
|
|
780
|
-
targetPath = normalizePath(targetPath);
|
|
781
|
-
linkPath = normalizePath(linkPath);
|
|
782
|
-
|
|
783
|
-
const { fs, path } = resolveMount(targetPath);
|
|
784
|
-
const link = resolveMount(linkPath);
|
|
785
|
-
|
|
786
|
-
if (fs != link.fs) {
|
|
787
|
-
throw ErrnoError.With('EXDEV', linkPath, 'link');
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
try {
|
|
791
|
-
if (config.checkAccess && !(await fs.stat(dirname(targetPath))).hasAccess(constants.R_OK)) {
|
|
792
|
-
throw ErrnoError.With('EACCES', dirname(path), 'link');
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
if (config.checkAccess && !(await stat(dirname(linkPath))).hasAccess(constants.W_OK)) {
|
|
796
|
-
throw ErrnoError.With('EACCES', dirname(linkPath), 'link');
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
if (config.checkAccess && !(await fs.stat(path)).hasAccess(constants.R_OK)) {
|
|
800
|
-
throw ErrnoError.With('EACCES', path, 'link');
|
|
801
|
-
}
|
|
802
|
-
return await fs.link(path, link.path);
|
|
803
|
-
} catch (e) {
|
|
804
|
-
throw fixError(e as ErrnoError, { [link.path]: linkPath, [path]: targetPath });
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
link satisfies typeof promises.link;
|
|
808
|
-
|
|
809
|
-
/**
|
|
810
|
-
* `symlink`.
|
|
811
|
-
* @param target target path
|
|
812
|
-
* @param path link path
|
|
813
|
-
* @param type can be either `'dir'` or `'file'` (default is `'file'`)
|
|
814
|
-
*/
|
|
815
|
-
export async function symlink(target: fs.PathLike, path: fs.PathLike, type: fs.symlink.Type | string | null = 'file'): Promise<void> {
|
|
816
|
-
if (!['file', 'dir', 'junction'].includes(type!)) {
|
|
817
|
-
throw new ErrnoError(Errno.EINVAL, 'Invalid symlink type: ' + type);
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
if (await exists(path)) {
|
|
821
|
-
throw ErrnoError.With('EEXIST', path.toString(), 'symlink');
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
await using handle = await _open(path, 'w+', 0o644, false);
|
|
825
|
-
await handle.writeFile(target.toString());
|
|
826
|
-
await handle.file.chmod(constants.S_IFLNK);
|
|
827
|
-
}
|
|
828
|
-
symlink satisfies typeof promises.symlink;
|
|
829
|
-
|
|
830
|
-
export async function readlink(path: fs.PathLike, options: fs.BufferEncodingOption): Promise<Buffer>;
|
|
831
|
-
export async function readlink(path: fs.PathLike, options?: fs.EncodingOption | null): Promise<string>;
|
|
832
|
-
export async function readlink(path: fs.PathLike, options?: fs.BufferEncodingOption | fs.EncodingOption | string | null): Promise<string | Buffer>;
|
|
833
|
-
export async function readlink(path: fs.PathLike, options?: fs.BufferEncodingOption | fs.EncodingOption | string | null): Promise<string | Buffer> {
|
|
834
|
-
await using handle = await _open(normalizePath(path), 'r', 0o644, false);
|
|
835
|
-
const value = await handle.readFile();
|
|
836
|
-
const encoding = typeof options == 'object' ? options?.encoding : options;
|
|
837
|
-
return encoding == 'buffer' ? value : value.toString(encoding! as BufferEncoding);
|
|
838
|
-
}
|
|
839
|
-
readlink satisfies typeof promises.readlink;
|
|
840
|
-
|
|
841
|
-
// PROPERTY OPERATIONS
|
|
842
|
-
|
|
843
|
-
export async function chown(path: fs.PathLike, uid: number, gid: number): Promise<void> {
|
|
844
|
-
await using handle = await open(path, 'r+');
|
|
845
|
-
await handle.chown(uid, gid);
|
|
846
|
-
}
|
|
847
|
-
chown satisfies typeof promises.chown;
|
|
848
|
-
|
|
849
|
-
export async function lchown(path: fs.PathLike, uid: number, gid: number): Promise<void> {
|
|
850
|
-
await using handle: FileHandle = await _open(path, 'r+', 0o644, false);
|
|
851
|
-
await handle.chown(uid, gid);
|
|
852
|
-
}
|
|
853
|
-
lchown satisfies typeof promises.lchown;
|
|
854
|
-
|
|
855
|
-
export async function chmod(path: fs.PathLike, mode: fs.Mode): Promise<void> {
|
|
856
|
-
await using handle = await open(path, 'r+');
|
|
857
|
-
await handle.chmod(mode);
|
|
858
|
-
}
|
|
859
|
-
chmod satisfies typeof promises.chmod;
|
|
860
|
-
|
|
861
|
-
export async function lchmod(path: fs.PathLike, mode: fs.Mode): Promise<void> {
|
|
862
|
-
await using handle: FileHandle = await _open(path, 'r+', 0o644, false);
|
|
863
|
-
await handle.chmod(mode);
|
|
864
|
-
}
|
|
865
|
-
lchmod satisfies typeof promises.lchmod;
|
|
866
|
-
|
|
867
|
-
/**
|
|
868
|
-
* Change file timestamps of the file referenced by the supplied path.
|
|
869
|
-
*/
|
|
870
|
-
export async function utimes(path: fs.PathLike, atime: string | number | Date, mtime: string | number | Date): Promise<void> {
|
|
871
|
-
await using handle = await open(path, 'r+');
|
|
872
|
-
await handle.utimes(atime, mtime);
|
|
873
|
-
}
|
|
874
|
-
utimes satisfies typeof promises.utimes;
|
|
875
|
-
|
|
876
|
-
/**
|
|
877
|
-
* Change file timestamps of the file referenced by the supplied path.
|
|
878
|
-
*/
|
|
879
|
-
export async function lutimes(path: fs.PathLike, atime: fs.TimeLike, mtime: fs.TimeLike): Promise<void> {
|
|
880
|
-
await using handle: FileHandle = await _open(path, 'r+', 0o644, false);
|
|
881
|
-
await handle.utimes(new Date(atime), new Date(mtime));
|
|
882
|
-
}
|
|
883
|
-
lutimes satisfies typeof promises.lutimes;
|
|
884
|
-
|
|
885
|
-
/**
|
|
886
|
-
* Asynchronous realpath(3) - return the canonicalized absolute pathname.
|
|
887
|
-
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
|
|
888
|
-
* @param options The encoding (or an object specifying the encoding), used as the encoding of the result. Defaults to `'utf8'`.
|
|
889
|
-
* @todo handle options
|
|
890
|
-
*/
|
|
891
|
-
export async function realpath(path: fs.PathLike, options: fs.BufferEncodingOption): Promise<Buffer>;
|
|
892
|
-
export async function realpath(path: fs.PathLike, options?: fs.EncodingOption | BufferEncoding): Promise<string>;
|
|
893
|
-
export async function realpath(path: fs.PathLike, options?: fs.EncodingOption | BufferEncoding | fs.BufferEncodingOption): Promise<string | Buffer> {
|
|
894
|
-
path = normalizePath(path);
|
|
895
|
-
if (cache.paths.hasAsync(path)) return cache.paths.getAsync(path)!;
|
|
896
|
-
const { base, dir } = parse(path);
|
|
897
|
-
const realDir = dir == '/' ? '/' : await (cache.paths.getAsync(dir) || realpath(dir));
|
|
898
|
-
const lpath = join(realDir, base);
|
|
899
|
-
const { fs, path: resolvedPath } = resolveMount(lpath);
|
|
900
|
-
|
|
901
|
-
try {
|
|
902
|
-
const _stats = cache.stats.getAsync(lpath) || fs.stat(resolvedPath);
|
|
903
|
-
cache.stats.setAsync(lpath, _stats);
|
|
904
|
-
if (!(await _stats).isSymbolicLink()) {
|
|
905
|
-
cache.paths.set(path, lpath);
|
|
906
|
-
return lpath;
|
|
907
|
-
}
|
|
908
|
-
|
|
909
|
-
const target = resolve(realDir, await readlink(lpath));
|
|
910
|
-
|
|
911
|
-
const real = cache.paths.getAsync(target) || realpath(target);
|
|
912
|
-
cache.paths.setAsync(path, real);
|
|
913
|
-
return await real;
|
|
914
|
-
} catch (e) {
|
|
915
|
-
if ((e as ErrnoError).code == 'ENOENT') {
|
|
916
|
-
return path;
|
|
917
|
-
}
|
|
918
|
-
throw fixError(e as ErrnoError, { [resolvedPath]: lpath });
|
|
919
|
-
}
|
|
920
|
-
}
|
|
921
|
-
realpath satisfies typeof promises.realpath;
|
|
922
|
-
|
|
923
|
-
export function watch(filename: fs.PathLike, options?: fs.WatchOptions | BufferEncoding): AsyncIterable<promises.FileChangeInfo<string>>;
|
|
924
|
-
export function watch(filename: fs.PathLike, options: fs.WatchOptions | fs.BufferEncodingOption): AsyncIterable<promises.FileChangeInfo<Buffer>>;
|
|
925
|
-
export function watch(filename: fs.PathLike, options?: fs.WatchOptions | string): AsyncIterable<promises.FileChangeInfo<string>> | AsyncIterable<promises.FileChangeInfo<Buffer>>;
|
|
926
|
-
export function watch<T extends string | Buffer>(filename: fs.PathLike, options: fs.WatchOptions | string = {}): AsyncIterable<promises.FileChangeInfo<T>> {
|
|
927
|
-
return {
|
|
928
|
-
[Symbol.asyncIterator](): AsyncIterator<promises.FileChangeInfo<T>> {
|
|
929
|
-
const watcher = new FSWatcher<T>(filename.toString(), typeof options !== 'string' ? options : { encoding: options as BufferEncoding | 'buffer' });
|
|
930
|
-
|
|
931
|
-
// A queue to hold change events, since we need to resolve them in the async iterator
|
|
932
|
-
const eventQueue: ((value: IteratorResult<promises.FileChangeInfo<T>>) => void)[] = [];
|
|
933
|
-
|
|
934
|
-
watcher.on('change', (eventType: promises.FileChangeInfo<T>['eventType'], filename: T) => {
|
|
935
|
-
eventQueue.shift()?.({ value: { eventType, filename }, done: false });
|
|
936
|
-
});
|
|
937
|
-
|
|
938
|
-
function cleanup() {
|
|
939
|
-
watcher.close();
|
|
940
|
-
for (const resolve of eventQueue) {
|
|
941
|
-
resolve({ value: null, done: true });
|
|
942
|
-
}
|
|
943
|
-
eventQueue.length = 0; // Clear the queue
|
|
944
|
-
return Promise.resolve({ value: null, done: true as const });
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
return {
|
|
948
|
-
async next() {
|
|
949
|
-
const { promise, resolve } = Promise.withResolvers<IteratorResult<promises.FileChangeInfo<T>>>();
|
|
950
|
-
eventQueue.push(resolve);
|
|
951
|
-
return promise;
|
|
952
|
-
},
|
|
953
|
-
return: cleanup,
|
|
954
|
-
throw: cleanup,
|
|
955
|
-
};
|
|
956
|
-
},
|
|
957
|
-
};
|
|
958
|
-
}
|
|
959
|
-
watch satisfies typeof promises.watch;
|
|
960
|
-
|
|
961
|
-
export async function access(path: fs.PathLike, mode: number = constants.F_OK): Promise<void> {
|
|
962
|
-
if (!config.checkAccess) return;
|
|
963
|
-
const stats = await stat(path);
|
|
964
|
-
if (!stats.hasAccess(mode)) {
|
|
965
|
-
throw new ErrnoError(Errno.EACCES);
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
access satisfies typeof promises.access;
|
|
969
|
-
|
|
970
|
-
/**
|
|
971
|
-
* Asynchronous `rm`. Removes files or directories (recursively).
|
|
972
|
-
* @param path The path to the file or directory to remove.
|
|
973
|
-
*/
|
|
974
|
-
export async function rm(path: fs.PathLike, options?: fs.RmOptions & InternalOptions) {
|
|
975
|
-
path = normalizePath(path);
|
|
976
|
-
|
|
977
|
-
const stats = await (cache.stats.getAsync(path) ||
|
|
978
|
-
stat(path).catch((error: ErrnoError) => {
|
|
979
|
-
if (error.code == 'ENOENT' && options?.force) return undefined;
|
|
980
|
-
throw error;
|
|
981
|
-
}));
|
|
982
|
-
|
|
983
|
-
if (!stats) {
|
|
984
|
-
return;
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
cache.stats.set(path, stats);
|
|
988
|
-
|
|
989
|
-
switch (stats.mode & constants.S_IFMT) {
|
|
990
|
-
case constants.S_IFDIR:
|
|
991
|
-
if (options?.recursive) {
|
|
992
|
-
for (const entry of await readdir(path, { _isIndirect: true })) {
|
|
993
|
-
await rm(join(path, entry), { ...options, _isIndirect: true });
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
|
|
997
|
-
await rmdir(path);
|
|
998
|
-
break;
|
|
999
|
-
case constants.S_IFREG:
|
|
1000
|
-
case constants.S_IFLNK:
|
|
1001
|
-
case constants.S_IFBLK:
|
|
1002
|
-
case constants.S_IFCHR:
|
|
1003
|
-
await unlink(path);
|
|
1004
|
-
break;
|
|
1005
|
-
case constants.S_IFIFO:
|
|
1006
|
-
case constants.S_IFSOCK:
|
|
1007
|
-
default:
|
|
1008
|
-
cache.stats.clear();
|
|
1009
|
-
throw new ErrnoError(Errno.EPERM, 'File type not supported', path, 'rm');
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
if (!options?._isIndirect) {
|
|
1013
|
-
cache.stats.clear();
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
rm satisfies typeof promises.rm;
|
|
1017
|
-
|
|
1018
|
-
/**
|
|
1019
|
-
* Asynchronous `mkdtemp`. Creates a unique temporary directory.
|
|
1020
|
-
* @param prefix The directory prefix.
|
|
1021
|
-
* @param options The encoding (or an object including `encoding`).
|
|
1022
|
-
* @returns The path to the created temporary directory, encoded as a string or buffer.
|
|
1023
|
-
*/
|
|
1024
|
-
export async function mkdtemp(prefix: string, options?: fs.EncodingOption): Promise<string>;
|
|
1025
|
-
export async function mkdtemp(prefix: string, options?: fs.BufferEncodingOption): Promise<Buffer>;
|
|
1026
|
-
export async function mkdtemp(prefix: string, options?: fs.EncodingOption | fs.BufferEncodingOption): Promise<string | Buffer> {
|
|
1027
|
-
const encoding = typeof options === 'object' ? options?.encoding : options || 'utf8';
|
|
1028
|
-
const fsName = `${prefix}${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
1029
|
-
const resolvedPath = '/tmp/' + fsName;
|
|
1030
|
-
|
|
1031
|
-
await mkdir(resolvedPath);
|
|
1032
|
-
|
|
1033
|
-
return encoding == 'buffer' ? Buffer.from(resolvedPath) : resolvedPath;
|
|
1034
|
-
}
|
|
1035
|
-
mkdtemp satisfies typeof promises.mkdtemp;
|
|
1036
|
-
|
|
1037
|
-
/**
|
|
1038
|
-
* Asynchronous `copyFile`. Copies a file.
|
|
1039
|
-
* @param src The source file.
|
|
1040
|
-
* @param dest The destination file.
|
|
1041
|
-
* @param mode Optional flags for the copy operation. Currently supports these flags:
|
|
1042
|
-
* * `fs.constants.COPYFILE_EXCL`: If the destination file already exists, the operation fails.
|
|
1043
|
-
*/
|
|
1044
|
-
export async function copyFile(src: fs.PathLike, dest: fs.PathLike, mode?: number): Promise<void> {
|
|
1045
|
-
src = normalizePath(src);
|
|
1046
|
-
dest = normalizePath(dest);
|
|
1047
|
-
|
|
1048
|
-
if (mode && mode & constants.COPYFILE_EXCL && (await exists(dest))) {
|
|
1049
|
-
throw new ErrnoError(Errno.EEXIST, 'Destination file already exists.', dest, 'copyFile');
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
await writeFile(dest, await readFile(src));
|
|
1053
|
-
emitChange('rename', dest.toString());
|
|
1054
|
-
}
|
|
1055
|
-
copyFile satisfies typeof promises.copyFile;
|
|
1056
|
-
|
|
1057
|
-
/**
|
|
1058
|
-
* Asynchronous `opendir`. Opens a directory.
|
|
1059
|
-
* @param path The path to the directory.
|
|
1060
|
-
* @param options Options for opening the directory.
|
|
1061
|
-
* @returns A `Dir` object representing the opened directory.
|
|
1062
|
-
* @todo Use options
|
|
1063
|
-
*/
|
|
1064
|
-
export function opendir(path: fs.PathLike, options?: fs.OpenDirOptions): Promise<Dir> {
|
|
1065
|
-
path = normalizePath(path);
|
|
1066
|
-
return Promise.resolve(new Dir(path));
|
|
1067
|
-
}
|
|
1068
|
-
opendir satisfies typeof promises.opendir;
|
|
1069
|
-
|
|
1070
|
-
/**
|
|
1071
|
-
* Asynchronous `cp`. Recursively copies a file or directory.
|
|
1072
|
-
* @param source The source file or directory.
|
|
1073
|
-
* @param destination The destination file or directory.
|
|
1074
|
-
* @param opts Options for the copy operation. Currently supports these options from Node.js 'fs.await cp':
|
|
1075
|
-
* * `dereference`: Dereference symbolic links.
|
|
1076
|
-
* * `errorOnExist`: Throw an error if the destination file or directory already exists.
|
|
1077
|
-
* * `filter`: A function that takes a source and destination path and returns a boolean, indicating whether to copy `source` element.
|
|
1078
|
-
* * `force`: Overwrite the destination if it exists, and overwrite existing readonly destination files.
|
|
1079
|
-
* * `preserveTimestamps`: Preserve file timestamps.
|
|
1080
|
-
* * `recursive`: If `true`, copies directories recursively.
|
|
1081
|
-
*/
|
|
1082
|
-
export async function cp(source: fs.PathLike, destination: fs.PathLike, opts?: fs.CopyOptions): Promise<void> {
|
|
1083
|
-
source = normalizePath(source);
|
|
1084
|
-
destination = normalizePath(destination);
|
|
1085
|
-
|
|
1086
|
-
const srcStats = await lstat(source); // Use lstat to follow symlinks if not dereferencing
|
|
1087
|
-
|
|
1088
|
-
if (opts?.errorOnExist && (await exists(destination))) {
|
|
1089
|
-
throw new ErrnoError(Errno.EEXIST, 'Destination file or directory already exists.', destination, 'cp');
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
|
-
switch (srcStats.mode & constants.S_IFMT) {
|
|
1093
|
-
case constants.S_IFDIR: {
|
|
1094
|
-
if (!opts?.recursive) {
|
|
1095
|
-
throw new ErrnoError(Errno.EISDIR, source + ' is a directory (not copied)', source, 'cp');
|
|
1096
|
-
}
|
|
1097
|
-
const [entries] = await Promise.all(
|
|
1098
|
-
[readdir(source, { withFileTypes: true }), mkdir(destination, { recursive: true })] // Ensure the destination directory exists
|
|
1099
|
-
);
|
|
1100
|
-
|
|
1101
|
-
const _cp = async (dirent: Dirent) => {
|
|
1102
|
-
if (opts.filter && !opts.filter(join(source, dirent.name), join(destination, dirent.name))) {
|
|
1103
|
-
return; // Skip if the filter returns false
|
|
1104
|
-
}
|
|
1105
|
-
await cp(join(source, dirent.name), join(destination, dirent.name), opts);
|
|
1106
|
-
};
|
|
1107
|
-
await Promise.all(entries.map(_cp));
|
|
1108
|
-
break;
|
|
1109
|
-
}
|
|
1110
|
-
case constants.S_IFREG:
|
|
1111
|
-
case constants.S_IFLNK:
|
|
1112
|
-
await copyFile(source, destination);
|
|
1113
|
-
break;
|
|
1114
|
-
case constants.S_IFBLK:
|
|
1115
|
-
case constants.S_IFCHR:
|
|
1116
|
-
case constants.S_IFIFO:
|
|
1117
|
-
case constants.S_IFSOCK:
|
|
1118
|
-
default:
|
|
1119
|
-
throw new ErrnoError(Errno.EPERM, 'File type not supported', source, 'rm');
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
// Optionally preserve timestamps
|
|
1123
|
-
if (opts?.preserveTimestamps) {
|
|
1124
|
-
await utimes(destination, srcStats.atime, srcStats.mtime);
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1127
|
-
cp satisfies typeof promises.cp;
|
|
1128
|
-
|
|
1129
|
-
/**
|
|
1130
|
-
* @since Node v18.15.0
|
|
1131
|
-
* @returns Fulfills with an {fs.StatFs} for the file system.
|
|
1132
|
-
*/
|
|
1133
|
-
export async function statfs(path: fs.PathLike, opts?: fs.StatFsOptions & { bigint?: false }): Promise<fs.StatsFs>;
|
|
1134
|
-
export async function statfs(path: fs.PathLike, opts: fs.StatFsOptions & { bigint: true }): Promise<fs.BigIntStatsFs>;
|
|
1135
|
-
export async function statfs(path: fs.PathLike, opts?: fs.StatFsOptions): Promise<fs.StatsFs | fs.BigIntStatsFs>;
|
|
1136
|
-
export function statfs(path: fs.PathLike, opts?: fs.StatFsOptions): Promise<fs.StatsFs | fs.BigIntStatsFs> {
|
|
1137
|
-
path = normalizePath(path);
|
|
1138
|
-
const { fs } = resolveMount(path);
|
|
1139
|
-
return Promise.resolve(_statfs(fs, opts?.bigint));
|
|
1140
|
-
}
|