@zenfs/core 0.9.2 → 0.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backends/Index.d.ts +3 -0
- package/dist/browser.min.js +3 -3
- package/dist/browser.min.js.map +3 -3
- package/dist/filesystem.d.ts +1 -1
- package/dist/filesystem.js +6 -6
- package/package.json +2 -9
- package/src/ApiError.ts +310 -0
- package/src/backends/AsyncStore.ts +635 -0
- package/src/backends/InMemory.ts +56 -0
- package/src/backends/Index.ts +500 -0
- package/src/backends/Locked.ts +181 -0
- package/src/backends/Overlay.ts +591 -0
- package/src/backends/SyncStore.ts +589 -0
- package/src/backends/backend.ts +152 -0
- package/src/config.ts +101 -0
- package/src/cred.ts +21 -0
- package/src/emulation/async.ts +910 -0
- package/src/emulation/constants.ts +176 -0
- package/src/emulation/dir.ts +139 -0
- package/src/emulation/index.ts +8 -0
- package/src/emulation/path.ts +468 -0
- package/src/emulation/promises.ts +1071 -0
- package/src/emulation/shared.ts +128 -0
- package/src/emulation/streams.ts +33 -0
- package/src/emulation/sync.ts +898 -0
- package/src/file.ts +721 -0
- package/src/filesystem.ts +544 -0
- package/src/index.ts +21 -0
- package/src/inode.ts +229 -0
- package/src/mutex.ts +52 -0
- package/src/stats.ts +385 -0
- package/src/utils.ts +287 -0
|
@@ -0,0 +1,898 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
import type * as Node from 'fs';
|
|
3
|
+
import type { BufferEncodingOption, EncodingOption, ReadSyncOptions, StatOptions, symlink } from 'fs';
|
|
4
|
+
import { ApiError, ErrorCode } from '../ApiError.js';
|
|
5
|
+
import { ActionType, File, isAppendable, isReadable, isWriteable, parseFlag, pathExistsAction, pathNotExistsAction } from '../file.js';
|
|
6
|
+
import { FileContents, FileSystem } from '../filesystem.js';
|
|
7
|
+
import { BigIntStats, FileType, type BigIntStatsFs, type Stats, type StatsFs } from '../stats.js';
|
|
8
|
+
import { normalizeMode, normalizeOptions, normalizePath, normalizeTime } from '../utils.js';
|
|
9
|
+
import { COPYFILE_EXCL, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLNK, S_IFMT, S_IFREG, S_IFSOCK } from './constants.js';
|
|
10
|
+
import { Dir, Dirent } from './dir.js';
|
|
11
|
+
import { dirname, join, parse } from './path.js';
|
|
12
|
+
import { PathLike, cred, fd2file, fdMap, fixError, getFdForFile, mounts, resolveMount } from './shared.js';
|
|
13
|
+
|
|
14
|
+
type FileSystemMethod = {
|
|
15
|
+
[K in keyof FileSystem]: FileSystem[K] extends (...args) => unknown
|
|
16
|
+
? (name: K, resolveSymlinks: boolean, ...args: Parameters<FileSystem[K]>) => ReturnType<FileSystem[K]>
|
|
17
|
+
: never;
|
|
18
|
+
}[keyof FileSystem]; // https://stackoverflow.com/a/76335220/17637456
|
|
19
|
+
|
|
20
|
+
function doOp<M extends FileSystemMethod, RT extends ReturnType<M>>(...[name, resolveSymlinks, path, ...args]: Parameters<M>): RT {
|
|
21
|
+
path = normalizePath(path);
|
|
22
|
+
const { fs, path: resolvedPath } = resolveMount(resolveSymlinks && existsSync(path) ? realpathSync(path) : path);
|
|
23
|
+
try {
|
|
24
|
+
// @ts-expect-error 2556 (since ...args is not correctly picked up as being a tuple)
|
|
25
|
+
return fs[name](resolvedPath, ...args) as RT;
|
|
26
|
+
} catch (e) {
|
|
27
|
+
throw fixError(e, { [resolvedPath]: path });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Synchronous rename.
|
|
33
|
+
* @param oldPath
|
|
34
|
+
* @param newPath
|
|
35
|
+
*/
|
|
36
|
+
export function renameSync(oldPath: PathLike, newPath: PathLike): void {
|
|
37
|
+
oldPath = normalizePath(oldPath);
|
|
38
|
+
newPath = normalizePath(newPath);
|
|
39
|
+
const _old = resolveMount(oldPath);
|
|
40
|
+
const _new = resolveMount(newPath);
|
|
41
|
+
const paths = { [_old.path]: oldPath, [_new.path]: newPath };
|
|
42
|
+
try {
|
|
43
|
+
if (_old === _new) {
|
|
44
|
+
return _old.fs.renameSync(_old.path, _new.path, cred);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
writeFileSync(newPath, readFileSync(oldPath));
|
|
48
|
+
unlinkSync(oldPath);
|
|
49
|
+
} catch (e) {
|
|
50
|
+
throw fixError(e, paths);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
renameSync satisfies typeof Node.renameSync;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Test whether or not the given path exists by checking with the file system.
|
|
57
|
+
* @param path
|
|
58
|
+
*/
|
|
59
|
+
export function existsSync(path: PathLike): boolean {
|
|
60
|
+
path = normalizePath(path);
|
|
61
|
+
try {
|
|
62
|
+
const { fs, path: resolvedPath } = resolveMount(realpathSync(path));
|
|
63
|
+
return fs.existsSync(resolvedPath, cred);
|
|
64
|
+
} catch (e) {
|
|
65
|
+
if ((e as ApiError).errno == ErrorCode.ENOENT) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
throw e;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
existsSync satisfies typeof Node.existsSync;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Synchronous `stat`.
|
|
76
|
+
* @param path
|
|
77
|
+
* @returns Stats
|
|
78
|
+
*/
|
|
79
|
+
export function statSync(path: PathLike, options?: { bigint?: false }): Stats;
|
|
80
|
+
export function statSync(path: PathLike, options: { bigint: true }): BigIntStats;
|
|
81
|
+
export function statSync(path: PathLike, options?: StatOptions): Stats | BigIntStats {
|
|
82
|
+
const stats: Stats = doOp('statSync', true, path, cred);
|
|
83
|
+
return options?.bigint ? new BigIntStats(stats) : stats;
|
|
84
|
+
}
|
|
85
|
+
statSync satisfies typeof Node.statSync;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Synchronous `lstat`.
|
|
89
|
+
* `lstat()` is identical to `stat()`, except that if path is a symbolic link,
|
|
90
|
+
* then the link itself is stat-ed, not the file that it refers to.
|
|
91
|
+
* @param path
|
|
92
|
+
*/
|
|
93
|
+
export function lstatSync(path: PathLike, options?: { bigint?: false }): Stats;
|
|
94
|
+
export function lstatSync(path: PathLike, options: { bigint: true }): BigIntStats;
|
|
95
|
+
export function lstatSync(path: PathLike, options?: StatOptions): Stats | BigIntStats {
|
|
96
|
+
const stats: Stats = doOp('statSync', false, path, cred);
|
|
97
|
+
return options?.bigint ? new BigIntStats(stats) : stats;
|
|
98
|
+
}
|
|
99
|
+
lstatSync satisfies typeof Node.lstatSync;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Synchronous `truncate`.
|
|
103
|
+
* @param path
|
|
104
|
+
* @param len
|
|
105
|
+
*/
|
|
106
|
+
export function truncateSync(path: PathLike, len: number = 0): void {
|
|
107
|
+
const fd = openSync(path, 'r+');
|
|
108
|
+
try {
|
|
109
|
+
ftruncateSync(fd, len);
|
|
110
|
+
} finally {
|
|
111
|
+
closeSync(fd);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
truncateSync satisfies typeof Node.truncateSync;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Synchronous `unlink`.
|
|
118
|
+
* @param path
|
|
119
|
+
*/
|
|
120
|
+
export function unlinkSync(path: PathLike): void {
|
|
121
|
+
return doOp('unlinkSync', false, path, cred);
|
|
122
|
+
}
|
|
123
|
+
unlinkSync satisfies typeof Node.unlinkSync;
|
|
124
|
+
|
|
125
|
+
function _openSync(_path: PathLike, _flag: string, _mode: Node.Mode, resolveSymlinks: boolean): File {
|
|
126
|
+
const path = normalizePath(_path),
|
|
127
|
+
mode = normalizeMode(_mode, 0o644),
|
|
128
|
+
flag = parseFlag(_flag);
|
|
129
|
+
// Check if the path exists, and is a file.
|
|
130
|
+
let stats: Stats;
|
|
131
|
+
try {
|
|
132
|
+
stats = doOp('statSync', resolveSymlinks, path, cred);
|
|
133
|
+
} catch (e) {
|
|
134
|
+
// File does not exist.
|
|
135
|
+
switch (pathNotExistsAction(flag)) {
|
|
136
|
+
case ActionType.CREATE:
|
|
137
|
+
// Ensure parent exists.
|
|
138
|
+
const parentStats: Stats = doOp('statSync', resolveSymlinks, dirname(path), cred);
|
|
139
|
+
if (!parentStats.isDirectory()) {
|
|
140
|
+
throw ApiError.With('ENOTDIR', dirname(path), '_open');
|
|
141
|
+
}
|
|
142
|
+
return doOp('createFileSync', resolveSymlinks, path, flag, mode, cred);
|
|
143
|
+
case ActionType.THROW:
|
|
144
|
+
throw ApiError.With('ENOENT', path, '_open');
|
|
145
|
+
default:
|
|
146
|
+
throw new ApiError(ErrorCode.EINVAL, 'Invalid FileFlag object.');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (!stats.hasAccess(mode, cred)) {
|
|
150
|
+
throw ApiError.With('EACCES', path, '_open');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// File exists.
|
|
154
|
+
switch (pathExistsAction(flag)) {
|
|
155
|
+
case ActionType.THROW:
|
|
156
|
+
throw ApiError.With('EEXIST', path, '_open');
|
|
157
|
+
case ActionType.TRUNCATE:
|
|
158
|
+
// Delete file.
|
|
159
|
+
doOp('unlinkSync', resolveSymlinks, path, cred);
|
|
160
|
+
/*
|
|
161
|
+
Create file. Use the same mode as the old file.
|
|
162
|
+
Node itself modifies the ctime when this occurs, so this action
|
|
163
|
+
will preserve that behavior if the underlying file system
|
|
164
|
+
supports those properties.
|
|
165
|
+
*/
|
|
166
|
+
return doOp('createFileSync', resolveSymlinks, path, flag, stats.mode, cred);
|
|
167
|
+
case ActionType.NOP:
|
|
168
|
+
return doOp('openFileSync', resolveSymlinks, path, flag, cred);
|
|
169
|
+
default:
|
|
170
|
+
throw new ApiError(ErrorCode.EINVAL, 'Invalid FileFlag object.');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Synchronous file open.
|
|
176
|
+
* @see http://www.manpagez.com/man/2/open/
|
|
177
|
+
* @param flags Handles the complexity of the various file
|
|
178
|
+
* modes. See its API for more details.
|
|
179
|
+
* @param mode Mode to use to open the file. Can be ignored if the
|
|
180
|
+
* filesystem doesn't support permissions.
|
|
181
|
+
*/
|
|
182
|
+
export function openSync(path: PathLike, flag: string, mode?: Node.Mode): number {
|
|
183
|
+
return getFdForFile(_openSync(path, flag, mode, true));
|
|
184
|
+
}
|
|
185
|
+
openSync satisfies typeof Node.openSync;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Opens a file or symlink
|
|
189
|
+
* @internal
|
|
190
|
+
*/
|
|
191
|
+
export function lopenSync(path: PathLike, flag: string, mode?: Node.Mode): number {
|
|
192
|
+
return getFdForFile(_openSync(path, flag, mode, false));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Synchronously reads the entire contents of a file.
|
|
197
|
+
*/
|
|
198
|
+
function _readFileSync(fname: string, flag: string, resolveSymlinks: boolean): Uint8Array {
|
|
199
|
+
// Get file.
|
|
200
|
+
const file = _openSync(fname, flag, 0o644, resolveSymlinks);
|
|
201
|
+
try {
|
|
202
|
+
const stat = file.statSync();
|
|
203
|
+
// Allocate buffer.
|
|
204
|
+
const data = new Uint8Array(stat.size);
|
|
205
|
+
file.readSync(data, 0, stat.size, 0);
|
|
206
|
+
file.closeSync();
|
|
207
|
+
return data;
|
|
208
|
+
} finally {
|
|
209
|
+
file.closeSync();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Synchronously reads the entire contents of a file.
|
|
215
|
+
* @param filename
|
|
216
|
+
* @param options
|
|
217
|
+
* @option options encoding The string encoding for the file contents. Defaults to `null`.
|
|
218
|
+
* @option options flag Defaults to `'r'`.
|
|
219
|
+
* @returns file contents
|
|
220
|
+
*/
|
|
221
|
+
export function readFileSync(filename: string, options?: { flag?: string }): Buffer;
|
|
222
|
+
export function readFileSync(filename: string, options: (Node.EncodingOption & { flag?: string }) | BufferEncoding): string;
|
|
223
|
+
export function readFileSync(filename: string, arg2: Node.WriteFileOptions = {}): FileContents {
|
|
224
|
+
const options = normalizeOptions(arg2, null, 'r', 0o644);
|
|
225
|
+
const flag = parseFlag(options.flag);
|
|
226
|
+
if (!isReadable(flag)) {
|
|
227
|
+
throw new ApiError(ErrorCode.EINVAL, 'Flag passed to readFile must allow for reading.');
|
|
228
|
+
}
|
|
229
|
+
const data: Buffer = Buffer.from(_readFileSync(filename, options.flag, true));
|
|
230
|
+
return options.encoding ? data.toString(options.encoding) : data;
|
|
231
|
+
}
|
|
232
|
+
readFileSync satisfies typeof Node.readFileSync;
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Synchronously writes data to a file, replacing the file
|
|
236
|
+
* if it already exists.
|
|
237
|
+
*
|
|
238
|
+
* The encoding option is ignored if data is a buffer.
|
|
239
|
+
*/
|
|
240
|
+
function _writeFileSync(fname: string, data: Uint8Array, flag: string, mode: number, resolveSymlinks: boolean): void {
|
|
241
|
+
const file = _openSync(fname, flag, mode, resolveSymlinks);
|
|
242
|
+
try {
|
|
243
|
+
file.writeSync(data, 0, data.length, 0);
|
|
244
|
+
} finally {
|
|
245
|
+
file.closeSync();
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Synchronously writes data to a file, replacing the file if it already
|
|
251
|
+
* exists.
|
|
252
|
+
*
|
|
253
|
+
* The encoding option is ignored if data is a buffer.
|
|
254
|
+
* @param filename
|
|
255
|
+
* @param data
|
|
256
|
+
* @param options
|
|
257
|
+
* @option options encoding Defaults to `'utf8'`.
|
|
258
|
+
* @option options mode Defaults to `0644`.
|
|
259
|
+
* @option options flag Defaults to `'w'`.
|
|
260
|
+
*/
|
|
261
|
+
export function writeFileSync(filename: string, data: FileContents, options?: Node.WriteFileOptions): void;
|
|
262
|
+
export function writeFileSync(filename: string, data: FileContents, encoding?: BufferEncoding): void;
|
|
263
|
+
export function writeFileSync(filename: string, data: FileContents, _options?: Node.WriteFileOptions | BufferEncoding): void {
|
|
264
|
+
const options = normalizeOptions(_options, 'utf8', 'w+', 0o644);
|
|
265
|
+
const flag = parseFlag(options.flag);
|
|
266
|
+
if (!isWriteable(flag)) {
|
|
267
|
+
throw new ApiError(ErrorCode.EINVAL, 'Flag passed to writeFile must allow for writing.');
|
|
268
|
+
}
|
|
269
|
+
if (typeof data != 'string' && !options.encoding) {
|
|
270
|
+
throw new ApiError(ErrorCode.EINVAL, 'Encoding not specified');
|
|
271
|
+
}
|
|
272
|
+
const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding) : data;
|
|
273
|
+
if (encodedData === undefined) {
|
|
274
|
+
throw new ApiError(ErrorCode.EINVAL, 'Data not specified');
|
|
275
|
+
}
|
|
276
|
+
_writeFileSync(filename, encodedData, options.flag, options.mode, true);
|
|
277
|
+
}
|
|
278
|
+
writeFileSync satisfies typeof Node.writeFileSync;
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Synchronously append data to a file, creating the file if
|
|
282
|
+
* it not yet exists.
|
|
283
|
+
*/
|
|
284
|
+
function _appendFileSync(fname: string, data: Uint8Array, flag: string, mode: number, resolveSymlinks: boolean): void {
|
|
285
|
+
const file = _openSync(fname, flag, mode, resolveSymlinks);
|
|
286
|
+
try {
|
|
287
|
+
file.writeSync(data, 0, data.length, null);
|
|
288
|
+
} finally {
|
|
289
|
+
file.closeSync();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Asynchronously append data to a file, creating the file if it not yet
|
|
295
|
+
* exists.
|
|
296
|
+
*
|
|
297
|
+
* @param filename
|
|
298
|
+
* @param data
|
|
299
|
+
* @param options
|
|
300
|
+
* @option options encoding Defaults to `'utf8'`.
|
|
301
|
+
* @option options mode Defaults to `0644`.
|
|
302
|
+
* @option options flag Defaults to `'a'`.
|
|
303
|
+
*/
|
|
304
|
+
export function appendFileSync(filename: string, data: FileContents, _options?: Node.WriteFileOptions): void {
|
|
305
|
+
const options = normalizeOptions(_options, 'utf8', 'a', 0o644);
|
|
306
|
+
const flag = parseFlag(options.flag);
|
|
307
|
+
if (!isAppendable(flag)) {
|
|
308
|
+
throw new ApiError(ErrorCode.EINVAL, 'Flag passed to appendFile must allow for appending.');
|
|
309
|
+
}
|
|
310
|
+
if (typeof data != 'string' && !options.encoding) {
|
|
311
|
+
throw new ApiError(ErrorCode.EINVAL, 'Encoding not specified');
|
|
312
|
+
}
|
|
313
|
+
const encodedData = typeof data == 'string' ? Buffer.from(data, options.encoding) : data;
|
|
314
|
+
_appendFileSync(filename, encodedData, options.flag, options.mode, true);
|
|
315
|
+
}
|
|
316
|
+
appendFileSync satisfies typeof Node.appendFileSync;
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Synchronous `fstat`.
|
|
320
|
+
* `fstat()` is identical to `stat()`, except that the file to be stat-ed is
|
|
321
|
+
* specified by the file descriptor `fd`.
|
|
322
|
+
* @param fd
|
|
323
|
+
*/
|
|
324
|
+
export function fstatSync(fd: number, options?: { bigint?: false }): Stats;
|
|
325
|
+
export function fstatSync(fd: number, options: { bigint: true }): BigIntStats;
|
|
326
|
+
export function fstatSync(fd: number, options?: StatOptions): Stats | BigIntStats {
|
|
327
|
+
const stats: Stats = fd2file(fd).statSync();
|
|
328
|
+
return options?.bigint ? new BigIntStats(stats) : stats;
|
|
329
|
+
}
|
|
330
|
+
fstatSync satisfies typeof Node.fstatSync;
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Synchronous close.
|
|
334
|
+
* @param fd
|
|
335
|
+
*/
|
|
336
|
+
export function closeSync(fd: number): void {
|
|
337
|
+
fd2file(fd).closeSync();
|
|
338
|
+
fdMap.delete(fd);
|
|
339
|
+
}
|
|
340
|
+
closeSync satisfies typeof Node.closeSync;
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Synchronous ftruncate.
|
|
344
|
+
* @param fd
|
|
345
|
+
* @param len
|
|
346
|
+
*/
|
|
347
|
+
export function ftruncateSync(fd: number, len: number = 0): void {
|
|
348
|
+
if (len < 0) {
|
|
349
|
+
throw new ApiError(ErrorCode.EINVAL);
|
|
350
|
+
}
|
|
351
|
+
fd2file(fd).truncateSync(len);
|
|
352
|
+
}
|
|
353
|
+
ftruncateSync satisfies typeof Node.ftruncateSync;
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Synchronous fsync.
|
|
357
|
+
* @param fd
|
|
358
|
+
*/
|
|
359
|
+
export function fsyncSync(fd: number): void {
|
|
360
|
+
fd2file(fd).syncSync();
|
|
361
|
+
}
|
|
362
|
+
fsyncSync satisfies typeof Node.fsyncSync;
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Synchronous fdatasync.
|
|
366
|
+
* @param fd
|
|
367
|
+
*/
|
|
368
|
+
export function fdatasyncSync(fd: number): void {
|
|
369
|
+
fd2file(fd).datasyncSync();
|
|
370
|
+
}
|
|
371
|
+
fdatasyncSync satisfies typeof Node.fdatasyncSync;
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Write buffer to the file specified by `fd`.
|
|
375
|
+
* Note that it is unsafe to use fs.write multiple times on the same file
|
|
376
|
+
* without waiting for it to return.
|
|
377
|
+
* @param fd
|
|
378
|
+
* @param data Uint8Array containing the data to write to
|
|
379
|
+
* the file.
|
|
380
|
+
* @param offset Offset in the buffer to start reading data from.
|
|
381
|
+
* @param length The amount of bytes to write to the file.
|
|
382
|
+
* @param position Offset from the beginning of the file where this
|
|
383
|
+
* data should be written. If position is null, the data will be written at
|
|
384
|
+
* the current position.
|
|
385
|
+
*/
|
|
386
|
+
export function writeSync(fd: number, data: Uint8Array, offset: number, length: number, position?: number): number;
|
|
387
|
+
export function writeSync(fd: number, data: string, position?: number, encoding?: BufferEncoding): number;
|
|
388
|
+
export function writeSync(fd: number, data: FileContents, posOrOff?: number, lenOrEnc?: BufferEncoding | number, pos?: number): number {
|
|
389
|
+
let buffer: Uint8Array,
|
|
390
|
+
offset: number = 0,
|
|
391
|
+
length: number,
|
|
392
|
+
position: number;
|
|
393
|
+
if (typeof data === 'string') {
|
|
394
|
+
// Signature 1: (fd, string, [position?, [encoding?]])
|
|
395
|
+
position = typeof posOrOff === 'number' ? posOrOff : null;
|
|
396
|
+
const encoding = <BufferEncoding>(typeof lenOrEnc === 'string' ? lenOrEnc : 'utf8');
|
|
397
|
+
offset = 0;
|
|
398
|
+
buffer = Buffer.from(data, encoding);
|
|
399
|
+
length = buffer.length;
|
|
400
|
+
} else {
|
|
401
|
+
// Signature 2: (fd, buffer, offset, length, position?)
|
|
402
|
+
buffer = data;
|
|
403
|
+
offset = posOrOff;
|
|
404
|
+
length = lenOrEnc as number;
|
|
405
|
+
position = typeof pos === 'number' ? pos : null;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const file = fd2file(fd);
|
|
409
|
+
if (position === undefined || position === null) {
|
|
410
|
+
position = file.position!;
|
|
411
|
+
}
|
|
412
|
+
return file.writeSync(buffer, offset, length, position);
|
|
413
|
+
}
|
|
414
|
+
writeSync satisfies typeof Node.writeSync;
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Read data from the file specified by `fd`.
|
|
418
|
+
* @param fd
|
|
419
|
+
* @param buffer The buffer that the data will be
|
|
420
|
+
* written to.
|
|
421
|
+
* @param offset The offset within the buffer where writing will
|
|
422
|
+
* start.
|
|
423
|
+
* @param length An integer specifying the number of bytes to read.
|
|
424
|
+
* @param position An integer specifying where to begin reading from
|
|
425
|
+
* in the file. If position is null, data will be read from the current file
|
|
426
|
+
* position.
|
|
427
|
+
*/
|
|
428
|
+
export function readSync(fd: number, buffer: Uint8Array, opts?: ReadSyncOptions): number;
|
|
429
|
+
export function readSync(fd: number, buffer: Uint8Array, offset: number, length: number, position?: number): number;
|
|
430
|
+
export function readSync(fd: number, buffer: Uint8Array, opts?: ReadSyncOptions | number, length?: number, position?: number | bigint): number {
|
|
431
|
+
const file = fd2file(fd);
|
|
432
|
+
const offset = typeof opts == 'object' ? opts.offset : opts;
|
|
433
|
+
if (typeof opts == 'object') {
|
|
434
|
+
length = opts.length;
|
|
435
|
+
position = opts.position;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
position = Number(position);
|
|
439
|
+
if (isNaN(position)) {
|
|
440
|
+
position = file.position!;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return file.readSync(buffer, offset, length, position);
|
|
444
|
+
}
|
|
445
|
+
readSync satisfies typeof Node.readSync;
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Synchronous `fchown`.
|
|
449
|
+
* @param fd
|
|
450
|
+
* @param uid
|
|
451
|
+
* @param gid
|
|
452
|
+
*/
|
|
453
|
+
export function fchownSync(fd: number, uid: number, gid: number): void {
|
|
454
|
+
fd2file(fd).chownSync(uid, gid);
|
|
455
|
+
}
|
|
456
|
+
fchownSync satisfies typeof Node.fchownSync;
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Synchronous `fchmod`.
|
|
460
|
+
* @param fd
|
|
461
|
+
* @param mode
|
|
462
|
+
*/
|
|
463
|
+
export function fchmodSync(fd: number, mode: number | string): void {
|
|
464
|
+
const numMode = normalizeMode(mode, -1);
|
|
465
|
+
if (numMode < 0) {
|
|
466
|
+
throw new ApiError(ErrorCode.EINVAL, `Invalid mode.`);
|
|
467
|
+
}
|
|
468
|
+
fd2file(fd).chmodSync(numMode);
|
|
469
|
+
}
|
|
470
|
+
fchmodSync satisfies typeof Node.fchmodSync;
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Change the file timestamps of a file referenced by the supplied file
|
|
474
|
+
* descriptor.
|
|
475
|
+
* @param fd
|
|
476
|
+
* @param atime
|
|
477
|
+
* @param mtime
|
|
478
|
+
*/
|
|
479
|
+
export function futimesSync(fd: number, atime: string | number | Date, mtime: string | number | Date): void {
|
|
480
|
+
fd2file(fd).utimesSync(normalizeTime(atime), normalizeTime(mtime));
|
|
481
|
+
}
|
|
482
|
+
futimesSync satisfies typeof Node.futimesSync;
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Synchronous `rmdir`.
|
|
486
|
+
* @param path
|
|
487
|
+
*/
|
|
488
|
+
export function rmdirSync(path: PathLike): void {
|
|
489
|
+
return doOp('rmdirSync', true, path, cred);
|
|
490
|
+
}
|
|
491
|
+
rmdirSync satisfies typeof Node.rmdirSync;
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Synchronous `mkdir`.
|
|
495
|
+
* @param path
|
|
496
|
+
* @param mode defaults to o777
|
|
497
|
+
* @todo Implement recursion
|
|
498
|
+
*/
|
|
499
|
+
export function mkdirSync(path: PathLike, options: Node.MakeDirectoryOptions & { recursive: true }): string;
|
|
500
|
+
export function mkdirSync(path: PathLike, options?: Node.Mode | (Node.MakeDirectoryOptions & { recursive?: false })): void;
|
|
501
|
+
export function mkdirSync(path: PathLike, options?: Node.Mode | Node.MakeDirectoryOptions): string | void {
|
|
502
|
+
const mode: Node.Mode = typeof options == 'number' || typeof options == 'string' ? options : options?.mode;
|
|
503
|
+
const recursive = typeof options == 'object' && options?.recursive;
|
|
504
|
+
doOp('mkdirSync', true, path, normalizeMode(mode, 0o777), cred);
|
|
505
|
+
}
|
|
506
|
+
mkdirSync satisfies typeof Node.mkdirSync;
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Synchronous `readdir`. Reads the contents of a directory.
|
|
510
|
+
* @param path
|
|
511
|
+
*/
|
|
512
|
+
export function readdirSync(path: PathLike, options?: { encoding?: BufferEncoding; withFileTypes?: false } | BufferEncoding): string[];
|
|
513
|
+
export function readdirSync(path: PathLike, options: { encoding: 'buffer'; withFileTypes?: false } | 'buffer'): Buffer[];
|
|
514
|
+
export function readdirSync(path: PathLike, options: { withFileTypes: true }): Dirent[];
|
|
515
|
+
export function readdirSync(path: PathLike, options?: { encoding?: BufferEncoding | 'buffer'; withFileTypes?: boolean } | string): string[] | Dirent[] | Buffer[] {
|
|
516
|
+
path = normalizePath(path);
|
|
517
|
+
const entries: string[] = doOp('readdirSync', true, path, cred);
|
|
518
|
+
for (const mount of mounts.keys()) {
|
|
519
|
+
if (!mount.startsWith(path)) {
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
const entry = mount.slice(path.length);
|
|
523
|
+
if (entry.includes('/') || entry.length == 0) {
|
|
524
|
+
// ignore FSs mounted in subdirectories and any FS mounted to `path`.
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
527
|
+
entries.push(entry);
|
|
528
|
+
}
|
|
529
|
+
return <string[] | Dirent[] | Buffer[]>entries.map((entry: string): string | Dirent | Buffer => {
|
|
530
|
+
if (typeof options == 'object' && options?.withFileTypes) {
|
|
531
|
+
return new Dirent(entry, statSync(join(path, entry)));
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
if (options == 'buffer' || (typeof options == 'object' && options.encoding == 'buffer')) {
|
|
535
|
+
return Buffer.from(entry);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
return entry;
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
readdirSync satisfies typeof Node.readdirSync;
|
|
542
|
+
|
|
543
|
+
// SYMLINK METHODS
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Synchronous `link`.
|
|
547
|
+
* @param existing
|
|
548
|
+
* @param newpath
|
|
549
|
+
*/
|
|
550
|
+
export function linkSync(existing: PathLike, newpath: PathLike): void {
|
|
551
|
+
newpath = normalizePath(newpath);
|
|
552
|
+
return doOp('linkSync', false, existing, newpath, cred);
|
|
553
|
+
}
|
|
554
|
+
linkSync satisfies typeof Node.linkSync;
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* Synchronous `symlink`.
|
|
558
|
+
* @param target target path
|
|
559
|
+
* @param path link path
|
|
560
|
+
* @param type can be either `'dir'` or `'file'` (default is `'file'`)
|
|
561
|
+
*/
|
|
562
|
+
export function symlinkSync(target: PathLike, path: PathLike, type: symlink.Type = 'file'): void {
|
|
563
|
+
if (!['file', 'dir', 'junction'].includes(type)) {
|
|
564
|
+
throw new ApiError(ErrorCode.EINVAL, 'Invalid type: ' + type);
|
|
565
|
+
}
|
|
566
|
+
if (existsSync(path)) {
|
|
567
|
+
throw ApiError.With('EEXIST', path, 'symlink');
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
writeFileSync(path, target);
|
|
571
|
+
const file = _openSync(path, 'r+', 0o644, false);
|
|
572
|
+
file._setTypeSync(FileType.SYMLINK);
|
|
573
|
+
}
|
|
574
|
+
symlinkSync satisfies typeof Node.symlinkSync;
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Synchronous readlink.
|
|
578
|
+
* @param path
|
|
579
|
+
*/
|
|
580
|
+
export function readlinkSync(path: PathLike, options?: BufferEncodingOption): Buffer;
|
|
581
|
+
export function readlinkSync(path: PathLike, options: EncodingOption | BufferEncoding): string;
|
|
582
|
+
export function readlinkSync(path: PathLike, options?: EncodingOption | BufferEncoding | BufferEncodingOption): Buffer | string {
|
|
583
|
+
const value: Buffer = Buffer.from(_readFileSync(path, 'r', false));
|
|
584
|
+
const encoding: BufferEncoding | 'buffer' = typeof options == 'object' ? options.encoding : options;
|
|
585
|
+
if (encoding == 'buffer') {
|
|
586
|
+
return value;
|
|
587
|
+
}
|
|
588
|
+
return value.toString(encoding);
|
|
589
|
+
}
|
|
590
|
+
readlinkSync satisfies typeof Node.readlinkSync;
|
|
591
|
+
|
|
592
|
+
// PROPERTY OPERATIONS
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Synchronous `chown`.
|
|
596
|
+
* @param path
|
|
597
|
+
* @param uid
|
|
598
|
+
* @param gid
|
|
599
|
+
*/
|
|
600
|
+
export function chownSync(path: PathLike, uid: number, gid: number): void {
|
|
601
|
+
const fd = openSync(path, 'r+');
|
|
602
|
+
fchownSync(fd, uid, gid);
|
|
603
|
+
closeSync(fd);
|
|
604
|
+
}
|
|
605
|
+
chownSync satisfies typeof Node.chownSync;
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* Synchronous `lchown`.
|
|
609
|
+
* @param path
|
|
610
|
+
* @param uid
|
|
611
|
+
* @param gid
|
|
612
|
+
*/
|
|
613
|
+
export function lchownSync(path: PathLike, uid: number, gid: number): void {
|
|
614
|
+
const fd = lopenSync(path, 'r+');
|
|
615
|
+
fchownSync(fd, uid, gid);
|
|
616
|
+
closeSync(fd);
|
|
617
|
+
}
|
|
618
|
+
lchownSync satisfies typeof Node.lchownSync;
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* Synchronous `chmod`.
|
|
622
|
+
* @param path
|
|
623
|
+
* @param mode
|
|
624
|
+
*/
|
|
625
|
+
export function chmodSync(path: PathLike, mode: Node.Mode): void {
|
|
626
|
+
const fd = openSync(path, 'r+');
|
|
627
|
+
fchmodSync(fd, mode);
|
|
628
|
+
closeSync(fd);
|
|
629
|
+
}
|
|
630
|
+
chmodSync satisfies typeof Node.chmodSync;
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Synchronous `lchmod`.
|
|
634
|
+
* @param path
|
|
635
|
+
* @param mode
|
|
636
|
+
*/
|
|
637
|
+
export function lchmodSync(path: PathLike, mode: number | string): void {
|
|
638
|
+
const fd = lopenSync(path, 'r+');
|
|
639
|
+
fchmodSync(fd, mode);
|
|
640
|
+
closeSync(fd);
|
|
641
|
+
}
|
|
642
|
+
lchmodSync satisfies typeof Node.lchmodSync;
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* Change file timestamps of the file referenced by the supplied path.
|
|
646
|
+
* @param path
|
|
647
|
+
* @param atime
|
|
648
|
+
* @param mtime
|
|
649
|
+
*/
|
|
650
|
+
export function utimesSync(path: PathLike, atime: string | number | Date, mtime: string | number | Date): void {
|
|
651
|
+
const fd = openSync(path, 'r+');
|
|
652
|
+
futimesSync(fd, atime, mtime);
|
|
653
|
+
closeSync(fd);
|
|
654
|
+
}
|
|
655
|
+
utimesSync satisfies typeof Node.utimesSync;
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Change file timestamps of the file referenced by the supplied path.
|
|
659
|
+
* @param path
|
|
660
|
+
* @param atime
|
|
661
|
+
* @param mtime
|
|
662
|
+
*/
|
|
663
|
+
export function lutimesSync(path: PathLike, atime: string | number | Date, mtime: string | number | Date): void {
|
|
664
|
+
const fd = lopenSync(path, 'r+');
|
|
665
|
+
futimesSync(fd, atime, mtime);
|
|
666
|
+
closeSync(fd);
|
|
667
|
+
}
|
|
668
|
+
lutimesSync satisfies typeof Node.lutimesSync;
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Synchronous `realpath`.
|
|
672
|
+
* @param path
|
|
673
|
+
* @param cache An object literal of mapped paths that can be used to
|
|
674
|
+
* force a specific path resolution or avoid additional `fs.stat` calls for
|
|
675
|
+
* known real paths.
|
|
676
|
+
* @returns the real path
|
|
677
|
+
*/
|
|
678
|
+
export function realpathSync(path: PathLike, options: BufferEncodingOption): Buffer;
|
|
679
|
+
export function realpathSync(path: PathLike, options?: EncodingOption): string;
|
|
680
|
+
export function realpathSync(path: PathLike, options?: EncodingOption | BufferEncodingOption): string | Buffer {
|
|
681
|
+
path = normalizePath(path);
|
|
682
|
+
const { base, dir } = parse(path);
|
|
683
|
+
const lpath = join(dir == '/' ? '/' : realpathSync(dir), base);
|
|
684
|
+
const { fs, path: resolvedPath, mountPoint } = resolveMount(lpath);
|
|
685
|
+
|
|
686
|
+
try {
|
|
687
|
+
const stats = fs.statSync(resolvedPath, cred);
|
|
688
|
+
if (!stats.isSymbolicLink()) {
|
|
689
|
+
return lpath;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
return realpathSync(mountPoint + readlinkSync(lpath));
|
|
693
|
+
} catch (e) {
|
|
694
|
+
throw fixError(e, { [resolvedPath]: lpath });
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
realpathSync satisfies Omit<typeof Node.realpathSync, 'native'>;
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Synchronous `access`.
|
|
701
|
+
* @param path
|
|
702
|
+
* @param mode
|
|
703
|
+
*/
|
|
704
|
+
export function accessSync(path: PathLike, mode: number = 0o600): void {
|
|
705
|
+
const stats = statSync(path);
|
|
706
|
+
if (!stats.hasAccess(mode, cred)) {
|
|
707
|
+
throw new ApiError(ErrorCode.EACCES);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
accessSync satisfies typeof Node.accessSync;
|
|
711
|
+
|
|
712
|
+
/**
|
|
713
|
+
* Synchronous `rm`. Removes files or directories (recursively).
|
|
714
|
+
* @param path The path to the file or directory to remove.
|
|
715
|
+
*/
|
|
716
|
+
export function rmSync(path: PathLike, options?: Node.RmOptions): void {
|
|
717
|
+
path = normalizePath(path);
|
|
718
|
+
|
|
719
|
+
const stats = statSync(path);
|
|
720
|
+
|
|
721
|
+
switch (stats.mode & S_IFMT) {
|
|
722
|
+
case S_IFDIR:
|
|
723
|
+
if (options?.recursive) {
|
|
724
|
+
for (const entry of readdirSync(path)) {
|
|
725
|
+
rmSync(join(path, entry));
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
rmdirSync(path);
|
|
730
|
+
return;
|
|
731
|
+
case S_IFREG:
|
|
732
|
+
case S_IFLNK:
|
|
733
|
+
unlinkSync(path);
|
|
734
|
+
return;
|
|
735
|
+
case S_IFBLK:
|
|
736
|
+
case S_IFCHR:
|
|
737
|
+
case S_IFIFO:
|
|
738
|
+
case S_IFSOCK:
|
|
739
|
+
default:
|
|
740
|
+
throw new ApiError(ErrorCode.EPERM, 'File type not supported', path, 'rm');
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
rmSync satisfies typeof Node.rmSync;
|
|
744
|
+
|
|
745
|
+
/**
|
|
746
|
+
* Synchronous `mkdtemp`. Creates a unique temporary directory.
|
|
747
|
+
* @param prefix The directory prefix.
|
|
748
|
+
* @param options The encoding (or an object including `encoding`).
|
|
749
|
+
* @returns The path to the created temporary directory, encoded as a string or buffer.
|
|
750
|
+
*/
|
|
751
|
+
export function mkdtempSync(prefix: string, options: BufferEncodingOption): Buffer;
|
|
752
|
+
export function mkdtempSync(prefix: string, options?: EncodingOption): string;
|
|
753
|
+
export function mkdtempSync(prefix: string, options?: EncodingOption | BufferEncodingOption): string | Buffer {
|
|
754
|
+
const encoding = typeof options === 'object' ? options.encoding : options || 'utf8';
|
|
755
|
+
const fsName = `${prefix}${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
756
|
+
const resolvedPath = '/tmp/' + fsName;
|
|
757
|
+
|
|
758
|
+
mkdirSync(resolvedPath);
|
|
759
|
+
|
|
760
|
+
return encoding == 'buffer' ? Buffer.from(resolvedPath) : resolvedPath;
|
|
761
|
+
}
|
|
762
|
+
mkdtempSync satisfies typeof Node.mkdtempSync;
|
|
763
|
+
|
|
764
|
+
/**
|
|
765
|
+
* Synchronous `copyFile`. Copies a file.
|
|
766
|
+
* @param src The source file.
|
|
767
|
+
* @param dest The destination file.
|
|
768
|
+
* @param flags Optional flags for the copy operation. Currently supports these flags:
|
|
769
|
+
* * `fs.constants.COPYFILE_EXCL`: If the destination file already exists, the operation fails.
|
|
770
|
+
*/
|
|
771
|
+
export function copyFileSync(src: PathLike, dest: PathLike, flags?: number): void {
|
|
772
|
+
src = normalizePath(src);
|
|
773
|
+
dest = normalizePath(dest);
|
|
774
|
+
|
|
775
|
+
if (flags && flags & COPYFILE_EXCL && existsSync(dest)) {
|
|
776
|
+
throw new ApiError(ErrorCode.EEXIST, 'Destination file already exists.', dest, 'copyFile');
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
writeFileSync(dest, readFileSync(src));
|
|
780
|
+
}
|
|
781
|
+
copyFileSync satisfies typeof Node.copyFileSync;
|
|
782
|
+
|
|
783
|
+
/**
|
|
784
|
+
* Synchronous `readv`. Reads from a file descriptor into multiple buffers.
|
|
785
|
+
* @param fd The file descriptor.
|
|
786
|
+
* @param buffers An array of Uint8Array buffers.
|
|
787
|
+
* @param position The position in the file where to begin reading.
|
|
788
|
+
* @returns The number of bytes read.
|
|
789
|
+
*/
|
|
790
|
+
export function readvSync(fd: number, buffers: readonly Uint8Array[], position?: number): number {
|
|
791
|
+
const file = fd2file(fd);
|
|
792
|
+
let bytesRead = 0;
|
|
793
|
+
|
|
794
|
+
for (const buffer of buffers) {
|
|
795
|
+
bytesRead += file.readSync(buffer, 0, buffer.length, position + bytesRead);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
return bytesRead;
|
|
799
|
+
}
|
|
800
|
+
readvSync satisfies typeof Node.readvSync;
|
|
801
|
+
|
|
802
|
+
/**
|
|
803
|
+
* Synchronous `writev`. Writes from multiple buffers into a file descriptor.
|
|
804
|
+
* @param fd The file descriptor.
|
|
805
|
+
* @param buffers An array of Uint8Array buffers.
|
|
806
|
+
* @param position The position in the file where to begin writing.
|
|
807
|
+
* @returns The number of bytes written.
|
|
808
|
+
*/
|
|
809
|
+
export function writevSync(fd: number, buffers: readonly Uint8Array[], position?: number): number {
|
|
810
|
+
const file = fd2file(fd);
|
|
811
|
+
let bytesWritten = 0;
|
|
812
|
+
|
|
813
|
+
for (const buffer of buffers) {
|
|
814
|
+
bytesWritten += file.writeSync(buffer, 0, buffer.length, position + bytesWritten);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
return bytesWritten;
|
|
818
|
+
}
|
|
819
|
+
writevSync satisfies typeof Node.writevSync;
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* Synchronous `opendir`. Opens a directory.
|
|
823
|
+
* @param path The path to the directory.
|
|
824
|
+
* @param options Options for opening the directory.
|
|
825
|
+
* @returns A `Dir` object representing the opened directory.
|
|
826
|
+
*/
|
|
827
|
+
export function opendirSync(path: PathLike, options?: Node.OpenDirOptions): Dir {
|
|
828
|
+
path = normalizePath(path);
|
|
829
|
+
return new Dir(path); // Re-use existing `Dir` class
|
|
830
|
+
}
|
|
831
|
+
opendirSync satisfies typeof Node.opendirSync;
|
|
832
|
+
|
|
833
|
+
/**
|
|
834
|
+
* Synchronous `cp`. Recursively copies a file or directory.
|
|
835
|
+
* @param source The source file or directory.
|
|
836
|
+
* @param destination The destination file or directory.
|
|
837
|
+
* @param opts Options for the copy operation. Currently supports these options from Node.js 'fs.cpSync':
|
|
838
|
+
* * `dereference`: Dereference symbolic links.
|
|
839
|
+
* * `errorOnExist`: Throw an error if the destination file or directory already exists.
|
|
840
|
+
* * `filter`: A function that takes a source and destination path and returns a boolean, indicating whether to copy the given source element.
|
|
841
|
+
* * `force`: Overwrite the destination if it exists, and overwrite existing readonly destination files.
|
|
842
|
+
* * `preserveTimestamps`: Preserve file timestamps.
|
|
843
|
+
* * `recursive`: If `true`, copies directories recursively.
|
|
844
|
+
*/
|
|
845
|
+
export function cpSync(source: PathLike, destination: PathLike, opts?: Node.CopySyncOptions): void {
|
|
846
|
+
source = normalizePath(source);
|
|
847
|
+
destination = normalizePath(destination);
|
|
848
|
+
|
|
849
|
+
const srcStats = lstatSync(source); // Use lstat to follow symlinks if not dereferencing
|
|
850
|
+
|
|
851
|
+
if (opts?.errorOnExist && existsSync(destination)) {
|
|
852
|
+
throw new ApiError(ErrorCode.EEXIST, 'Destination file or directory already exists.', destination, 'cp');
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
switch (srcStats.mode & S_IFMT) {
|
|
856
|
+
case S_IFDIR:
|
|
857
|
+
if (!opts?.recursive) {
|
|
858
|
+
throw new ApiError(ErrorCode.EISDIR, source + ' is a directory (not copied)', source, 'cp');
|
|
859
|
+
}
|
|
860
|
+
mkdirSync(destination, { recursive: true }); // Ensure the destination directory exists
|
|
861
|
+
for (const dirent of readdirSync(source, { withFileTypes: true })) {
|
|
862
|
+
if (opts.filter && !opts.filter(join(source, dirent.name), join(destination, dirent.name))) {
|
|
863
|
+
continue; // Skip if the filter returns false
|
|
864
|
+
}
|
|
865
|
+
cpSync(join(source, dirent.name), join(destination, dirent.name), opts);
|
|
866
|
+
}
|
|
867
|
+
break;
|
|
868
|
+
case S_IFREG:
|
|
869
|
+
case S_IFLNK:
|
|
870
|
+
copyFileSync(source, destination);
|
|
871
|
+
break;
|
|
872
|
+
case S_IFBLK:
|
|
873
|
+
case S_IFCHR:
|
|
874
|
+
case S_IFIFO:
|
|
875
|
+
case S_IFSOCK:
|
|
876
|
+
default:
|
|
877
|
+
throw new ApiError(ErrorCode.EPERM, 'File type not supported', source, 'rm');
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// Optionally preserve timestamps
|
|
881
|
+
if (opts?.preserveTimestamps) {
|
|
882
|
+
utimesSync(destination, srcStats.atime, srcStats.mtime);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
cpSync satisfies typeof Node.cpSync;
|
|
886
|
+
|
|
887
|
+
/**
|
|
888
|
+
* Synchronous statfs(2). Returns information about the mounted file system which contains path.
|
|
889
|
+
* In case of an error, the err.code will be one of Common System Errors.
|
|
890
|
+
* @param path A path to an existing file or directory on the file system to be queried.
|
|
891
|
+
* @param callback
|
|
892
|
+
*/
|
|
893
|
+
export function statfsSync(path: PathLike, options?: Node.StatFsOptions & { bigint?: false }): StatsFs;
|
|
894
|
+
export function statfsSync(path: PathLike, options: Node.StatFsOptions & { bigint: true }): BigIntStatsFs;
|
|
895
|
+
export function statfsSync(path: PathLike, options?: Node.StatFsOptions): StatsFs | BigIntStatsFs;
|
|
896
|
+
export function statfsSync(path: PathLike, options?: Node.StatFsOptions): StatsFs | BigIntStatsFs {
|
|
897
|
+
throw ApiError.With('ENOSYS', path, 'statfs');
|
|
898
|
+
}
|