1// Copyright Joyent, Inc. and other Node contributors. 2// 3// Permission is hereby granted, free of charge, to any person obtaining a 4// copy of this software and associated documentation files (the 5// "Software"), to deal in the Software without restriction, including 6// without limitation the rights to use, copy, modify, merge, publish, 7// distribute, sublicense, and/or sell copies of the Software, and to permit 8// persons to whom the Software is furnished to do so, subject to the 9// following conditions: 10// 11// The above copyright notice and this permission notice shall be included 12// in all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20// USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22// Maintainers, keep in mind that ES1-style octal literals (`0666`) are not 23// allowed in strict mode. Use ES6-style octal literals instead (`0o666`). 24 25'use strict'; 26 27const { 28 ArrayPrototypePush, 29 BigIntPrototypeToString, 30 Boolean, 31 MathMax, 32 Number, 33 ObjectDefineProperties, 34 ObjectDefineProperty, 35 Promise, 36 ReflectApply, 37 SafeMap, 38 SafeSet, 39 String, 40 StringPrototypeCharCodeAt, 41 StringPrototypeIndexOf, 42 StringPrototypeSlice, 43} = primordials; 44 45const { fs: constants } = internalBinding('constants'); 46const { 47 S_IFIFO, 48 S_IFLNK, 49 S_IFMT, 50 S_IFREG, 51 S_IFSOCK, 52 F_OK, 53 R_OK, 54 W_OK, 55 X_OK, 56 O_WRONLY, 57 O_SYMLINK, 58} = constants; 59 60const pathModule = require('path'); 61const { isArrayBufferView } = require('internal/util/types'); 62 63// We need to get the statValues from the binding at the callsite since 64// it's re-initialized after deserialization. 65 66const binding = internalBinding('fs'); 67const { Buffer } = require('buffer'); 68const { 69 aggregateTwoErrors, 70 codes: { 71 ERR_FS_FILE_TOO_LARGE, 72 ERR_INVALID_ARG_VALUE, 73 ERR_FEATURE_UNAVAILABLE_ON_PLATFORM, 74 }, 75 AbortError, 76 uvErrmapGet, 77 uvException, 78} = require('internal/errors'); 79 80const { FSReqCallback } = binding; 81const { toPathIfFileURL } = require('internal/url'); 82const { 83 customPromisifyArgs: kCustomPromisifyArgsSymbol, 84 deprecate, 85 kEmptyObject, 86 promisify: { 87 custom: kCustomPromisifiedSymbol, 88 }, 89 SideEffectFreeRegExpPrototypeExec, 90} = require('internal/util'); 91const { 92 constants: { 93 kIoMaxLength, 94 kMaxUserId, 95 }, 96 copyObject, 97 Dirent, 98 emitRecursiveRmdirWarning, 99 getDirent, 100 getDirents, 101 getOptions, 102 getValidatedFd, 103 getValidatedPath, 104 getValidMode, 105 handleErrorFromBinding, 106 nullCheck, 107 preprocessSymlinkDestination, 108 Stats, 109 getStatFsFromBinding, 110 getStatsFromBinding, 111 realpathCacheKey, 112 stringToFlags, 113 stringToSymlinkType, 114 toUnixTimestamp, 115 validateBufferArray, 116 validateCpOptions, 117 validateOffsetLengthRead, 118 validateOffsetLengthWrite, 119 validatePath, 120 validatePosition, 121 validateRmOptions, 122 validateRmOptionsSync, 123 validateRmdirOptions, 124 validateStringAfterArrayBufferView, 125 validatePrimitiveStringAfterArrayBufferView, 126 warnOnNonPortableTemplate, 127} = require('internal/fs/utils'); 128const { 129 Dir, 130 opendir, 131 opendirSync, 132} = require('internal/fs/dir'); 133const { 134 CHAR_FORWARD_SLASH, 135 CHAR_BACKWARD_SLASH, 136} = require('internal/constants'); 137const { 138 isUint32, 139 parseFileMode, 140 validateBoolean, 141 validateBuffer, 142 validateEncoding, 143 validateFunction, 144 validateInteger, 145 validateObject, 146 validateString, 147} = require('internal/validators'); 148 149const watchers = require('internal/fs/watchers'); 150const ReadFileContext = require('internal/fs/read_file_context'); 151 152let truncateWarn = true; 153let fs; 154 155// Lazy loaded 156let cpFn; 157let cpSyncFn; 158let promises = null; 159let ReadStream; 160let WriteStream; 161let rimraf; 162let rimrafSync; 163 164// These have to be separate because of how graceful-fs happens to do it's 165// monkeypatching. 166let FileReadStream; 167let FileWriteStream; 168 169const isWindows = process.platform === 'win32'; 170const isOSX = process.platform === 'darwin'; 171 172 173const showStringCoercionDeprecation = deprecate( 174 () => {}, 175 'Implicit coercion of objects with own toString property is deprecated.', 176 'DEP0162', 177); 178function showTruncateDeprecation() { 179 if (truncateWarn) { 180 process.emitWarning( 181 'Using fs.truncate with a file descriptor is deprecated. Please use ' + 182 'fs.ftruncate with a file descriptor instead.', 183 'DeprecationWarning', 'DEP0081'); 184 truncateWarn = false; 185 } 186} 187 188function maybeCallback(cb) { 189 validateFunction(cb, 'cb'); 190 191 return cb; 192} 193 194// Ensure that callbacks run in the global context. Only use this function 195// for callbacks that are passed to the binding layer, callbacks that are 196// invoked from JS already run in the proper scope. 197function makeCallback(cb) { 198 validateFunction(cb, 'cb'); 199 200 return (...args) => ReflectApply(cb, this, args); 201} 202 203// Special case of `makeCallback()` that is specific to async `*stat()` calls as 204// an optimization, since the data passed back to the callback needs to be 205// transformed anyway. 206function makeStatsCallback(cb) { 207 validateFunction(cb, 'cb'); 208 209 return (err, stats) => { 210 if (err) return cb(err); 211 cb(err, getStatsFromBinding(stats)); 212 }; 213} 214 215const isFd = isUint32; 216 217function isFileType(stats, fileType) { 218 // Use stats array directly to avoid creating an fs.Stats instance just for 219 // our internal use. 220 let mode = stats[1]; 221 if (typeof mode === 'bigint') 222 mode = Number(mode); 223 return (mode & S_IFMT) === fileType; 224} 225 226/** 227 * Tests a user's permissions for the file or directory 228 * specified by `path`. 229 * @param {string | Buffer | URL} path 230 * @param {number} [mode] 231 * @param {(err?: Error) => any} callback 232 * @returns {void} 233 */ 234function access(path, mode, callback) { 235 if (typeof mode === 'function') { 236 callback = mode; 237 mode = F_OK; 238 } 239 240 path = getValidatedPath(path); 241 mode = getValidMode(mode, 'access'); 242 callback = makeCallback(callback); 243 244 const req = new FSReqCallback(); 245 req.oncomplete = callback; 246 binding.access(pathModule.toNamespacedPath(path), mode, req); 247} 248 249/** 250 * Synchronously tests a user's permissions for the file or 251 * directory specified by `path`. 252 * @param {string | Buffer | URL} path 253 * @param {number} [mode] 254 * @returns {void} 255 */ 256function accessSync(path, mode) { 257 path = getValidatedPath(path); 258 mode = getValidMode(mode, 'access'); 259 260 const ctx = { path }; 261 binding.access(pathModule.toNamespacedPath(path), mode, undefined, ctx); 262 handleErrorFromBinding(ctx); 263} 264 265/** 266 * Tests whether or not the given path exists. 267 * @param {string | Buffer | URL} path 268 * @param {(exists?: boolean) => any} callback 269 * @returns {void} 270 */ 271function exists(path, callback) { 272 maybeCallback(callback); 273 274 function suppressedCallback(err) { 275 callback(err ? false : true); 276 } 277 278 try { 279 fs.access(path, F_OK, suppressedCallback); 280 } catch { 281 return callback(false); 282 } 283} 284 285ObjectDefineProperty(exists, kCustomPromisifiedSymbol, { 286 __proto__: null, 287 value: function exists(path) { // eslint-disable-line func-name-matching 288 return new Promise((resolve) => fs.exists(path, resolve)); 289 }, 290}); 291 292// fs.existsSync never throws, it only returns true or false. 293// Since fs.existsSync never throws, users have established 294// the expectation that passing invalid arguments to it, even like 295// fs.existsSync(), would only get a false in return, so we cannot signal 296// validation errors to users properly out of compatibility concerns. 297// TODO(joyeecheung): deprecate the never-throw-on-invalid-arguments behavior 298/** 299 * Synchronously tests whether or not the given path exists. 300 * @param {string | Buffer | URL} path 301 * @returns {boolean} 302 */ 303function existsSync(path) { 304 try { 305 path = getValidatedPath(path); 306 } catch { 307 return false; 308 } 309 const ctx = { path }; 310 const nPath = pathModule.toNamespacedPath(path); 311 binding.access(nPath, F_OK, undefined, ctx); 312 313 // In case of an invalid symlink, `binding.access()` on win32 314 // will **not** return an error and is therefore not enough. 315 // Double check with `binding.stat()`. 316 if (isWindows && ctx.errno === undefined) { 317 binding.stat(nPath, false, undefined, ctx); 318 } 319 320 return ctx.errno === undefined; 321} 322 323function readFileAfterOpen(err, fd) { 324 const context = this.context; 325 326 if (err) { 327 context.callback(err); 328 return; 329 } 330 331 context.fd = fd; 332 333 const req = new FSReqCallback(); 334 req.oncomplete = readFileAfterStat; 335 req.context = context; 336 binding.fstat(fd, false, req); 337} 338 339function readFileAfterStat(err, stats) { 340 const context = this.context; 341 342 if (err) 343 return context.close(err); 344 345 // TODO(BridgeAR): Check if allocating a smaller chunk is better performance 346 // wise, similar to the promise based version (less peak memory and chunked 347 // stringify operations vs multiple C++/JS boundary crossings). 348 const size = context.size = isFileType(stats, S_IFREG) ? stats[8] : 0; 349 350 if (size > kIoMaxLength) { 351 err = new ERR_FS_FILE_TOO_LARGE(size); 352 return context.close(err); 353 } 354 355 try { 356 if (size === 0) { 357 // TODO(BridgeAR): If an encoding is set, use the StringDecoder to concat 358 // the result and reuse the buffer instead of allocating a new one. 359 context.buffers = []; 360 } else { 361 context.buffer = Buffer.allocUnsafeSlow(size); 362 } 363 } catch (err) { 364 return context.close(err); 365 } 366 context.read(); 367} 368 369function checkAborted(signal, callback) { 370 if (signal?.aborted) { 371 callback(new AbortError(undefined, { cause: signal?.reason })); 372 return true; 373 } 374 return false; 375} 376 377/** 378 * Asynchronously reads the entire contents of a file. 379 * @param {string | Buffer | URL | number} path 380 * @param {{ 381 * encoding?: string | null; 382 * flag?: string; 383 * signal?: AbortSignal; 384 * } | string} [options] 385 * @param {( 386 * err?: Error, 387 * data?: string | Buffer 388 * ) => any} callback 389 * @returns {void} 390 */ 391function readFile(path, options, callback) { 392 callback = maybeCallback(callback || options); 393 options = getOptions(options, { flag: 'r' }); 394 const context = new ReadFileContext(callback, options.encoding); 395 context.isUserFd = isFd(path); // File descriptor ownership 396 397 if (options.signal) { 398 context.signal = options.signal; 399 } 400 if (context.isUserFd) { 401 process.nextTick(function tick(context) { 402 ReflectApply(readFileAfterOpen, { context }, [null, path]); 403 }, context); 404 return; 405 } 406 407 if (checkAborted(options.signal, callback)) 408 return; 409 410 const flagsNumber = stringToFlags(options.flag, 'options.flag'); 411 path = getValidatedPath(path); 412 413 const req = new FSReqCallback(); 414 req.context = context; 415 req.oncomplete = readFileAfterOpen; 416 binding.open(pathModule.toNamespacedPath(path), 417 flagsNumber, 418 0o666, 419 req); 420} 421 422function tryStatSync(fd, isUserFd) { 423 const ctx = {}; 424 const stats = binding.fstat(fd, false, undefined, ctx); 425 if (ctx.errno !== undefined && !isUserFd) { 426 fs.closeSync(fd); 427 throw uvException(ctx); 428 } 429 return stats; 430} 431 432function tryCreateBuffer(size, fd, isUserFd) { 433 let threw = true; 434 let buffer; 435 try { 436 if (size > kIoMaxLength) { 437 throw new ERR_FS_FILE_TOO_LARGE(size); 438 } 439 buffer = Buffer.allocUnsafe(size); 440 threw = false; 441 } finally { 442 if (threw && !isUserFd) fs.closeSync(fd); 443 } 444 return buffer; 445} 446 447function tryReadSync(fd, isUserFd, buffer, pos, len) { 448 let threw = true; 449 let bytesRead; 450 try { 451 bytesRead = fs.readSync(fd, buffer, pos, len); 452 threw = false; 453 } finally { 454 if (threw && !isUserFd) fs.closeSync(fd); 455 } 456 return bytesRead; 457} 458 459/** 460 * Synchronously reads the entire contents of a file. 461 * @param {string | Buffer | URL | number} path 462 * @param {{ 463 * encoding?: string | null; 464 * flag?: string; 465 * }} [options] 466 * @returns {string | Buffer} 467 */ 468function readFileSync(path, options) { 469 options = getOptions(options, { flag: 'r' }); 470 const isUserFd = isFd(path); // File descriptor ownership 471 const fd = isUserFd ? path : fs.openSync(path, options.flag, 0o666); 472 473 const stats = tryStatSync(fd, isUserFd); 474 const size = isFileType(stats, S_IFREG) ? stats[8] : 0; 475 let pos = 0; 476 let buffer; // Single buffer with file data 477 let buffers; // List for when size is unknown 478 479 if (size === 0) { 480 buffers = []; 481 } else { 482 buffer = tryCreateBuffer(size, fd, isUserFd); 483 } 484 485 let bytesRead; 486 487 if (size !== 0) { 488 do { 489 bytesRead = tryReadSync(fd, isUserFd, buffer, pos, size - pos); 490 pos += bytesRead; 491 } while (bytesRead !== 0 && pos < size); 492 } else { 493 do { 494 // The kernel lies about many files. 495 // Go ahead and try to read some bytes. 496 buffer = Buffer.allocUnsafe(8192); 497 bytesRead = tryReadSync(fd, isUserFd, buffer, 0, 8192); 498 if (bytesRead !== 0) { 499 ArrayPrototypePush(buffers, buffer.slice(0, bytesRead)); 500 } 501 pos += bytesRead; 502 } while (bytesRead !== 0); 503 } 504 505 if (!isUserFd) 506 fs.closeSync(fd); 507 508 if (size === 0) { 509 // Data was collected into the buffers list. 510 buffer = Buffer.concat(buffers, pos); 511 } else if (pos < size) { 512 buffer = buffer.slice(0, pos); 513 } 514 515 if (options.encoding) buffer = buffer.toString(options.encoding); 516 return buffer; 517} 518 519function defaultCloseCallback(err) { 520 if (err != null) throw err; 521} 522 523/** 524 * Closes the file descriptor. 525 * @param {number} fd 526 * @param {(err?: Error) => any} [callback] 527 * @returns {void} 528 */ 529function close(fd, callback = defaultCloseCallback) { 530 fd = getValidatedFd(fd); 531 if (callback !== defaultCloseCallback) 532 callback = makeCallback(callback); 533 534 const req = new FSReqCallback(); 535 req.oncomplete = callback; 536 binding.close(fd, req); 537} 538 539/** 540 * Synchronously closes the file descriptor. 541 * @param {number} fd 542 * @returns {void} 543 */ 544function closeSync(fd) { 545 fd = getValidatedFd(fd); 546 547 const ctx = {}; 548 binding.close(fd, undefined, ctx); 549 handleErrorFromBinding(ctx); 550} 551 552/** 553 * Asynchronously opens a file. 554 * @param {string | Buffer | URL} path 555 * @param {string | number} [flags] 556 * @param {string | number} [mode] 557 * @param {( 558 * err?: Error, 559 * fd?: number 560 * ) => any} callback 561 * @returns {void} 562 */ 563function open(path, flags, mode, callback) { 564 path = getValidatedPath(path); 565 if (arguments.length < 3) { 566 callback = flags; 567 flags = 'r'; 568 mode = 0o666; 569 } else if (typeof mode === 'function') { 570 callback = mode; 571 mode = 0o666; 572 } else { 573 mode = parseFileMode(mode, 'mode', 0o666); 574 } 575 const flagsNumber = stringToFlags(flags); 576 callback = makeCallback(callback); 577 578 const req = new FSReqCallback(); 579 req.oncomplete = callback; 580 581 binding.open(pathModule.toNamespacedPath(path), 582 flagsNumber, 583 mode, 584 req); 585} 586 587/** 588 * Synchronously opens a file. 589 * @param {string | Buffer | URL} path 590 * @param {string | number} [flags] 591 * @param {string | number} [mode] 592 * @returns {number} 593 */ 594function openSync(path, flags, mode) { 595 path = getValidatedPath(path); 596 const flagsNumber = stringToFlags(flags); 597 mode = parseFileMode(mode, 'mode', 0o666); 598 599 const ctx = { path }; 600 const result = binding.open(pathModule.toNamespacedPath(path), 601 flagsNumber, mode, 602 undefined, ctx); 603 handleErrorFromBinding(ctx); 604 return result; 605} 606 607/** 608 * Reads file from the specified `fd` (file descriptor). 609 * @param {number} fd 610 * @param {Buffer | TypedArray | DataView} buffer 611 * @param {number} offsetOrOptions 612 * @param {number} length 613 * @param {number | bigint | null} position 614 * @param {( 615 * err?: Error, 616 * bytesRead?: number, 617 * buffer?: Buffer 618 * ) => any} callback 619 * @returns {void} 620 */ 621function read(fd, buffer, offsetOrOptions, length, position, callback) { 622 fd = getValidatedFd(fd); 623 624 let offset = offsetOrOptions; 625 let params = null; 626 if (arguments.length <= 4) { 627 if (arguments.length === 4) { 628 // This is fs.read(fd, buffer, options, callback) 629 validateObject(offsetOrOptions, 'options', { nullable: true }); 630 callback = length; 631 params = offsetOrOptions; 632 } else if (arguments.length === 3) { 633 // This is fs.read(fd, bufferOrParams, callback) 634 if (!isArrayBufferView(buffer)) { 635 // This is fs.read(fd, params, callback) 636 params = buffer; 637 ({ buffer = Buffer.alloc(16384) } = params ?? kEmptyObject); 638 } 639 callback = offsetOrOptions; 640 } else { 641 // This is fs.read(fd, callback) 642 callback = buffer; 643 buffer = Buffer.alloc(16384); 644 } 645 646 ({ 647 offset = 0, 648 length = buffer.byteLength - offset, 649 position = null, 650 } = params ?? kEmptyObject); 651 } 652 653 validateBuffer(buffer); 654 callback = maybeCallback(callback); 655 656 if (offset == null) { 657 offset = 0; 658 } else { 659 validateInteger(offset, 'offset', 0); 660 } 661 662 length |= 0; 663 664 if (length === 0) { 665 return process.nextTick(function tick() { 666 callback(null, 0, buffer); 667 }); 668 } 669 670 if (buffer.byteLength === 0) { 671 throw new ERR_INVALID_ARG_VALUE('buffer', buffer, 672 'is empty and cannot be written'); 673 } 674 675 validateOffsetLengthRead(offset, length, buffer.byteLength); 676 677 if (position == null) 678 position = -1; 679 680 validatePosition(position, 'position'); 681 682 function wrapper(err, bytesRead) { 683 // Retain a reference to buffer so that it can't be GC'ed too soon. 684 callback(err, bytesRead || 0, buffer); 685 } 686 687 const req = new FSReqCallback(); 688 req.oncomplete = wrapper; 689 690 binding.read(fd, buffer, offset, length, position, req); 691} 692 693ObjectDefineProperty(read, kCustomPromisifyArgsSymbol, 694 { __proto__: null, value: ['bytesRead', 'buffer'], enumerable: false }); 695 696/** 697 * Synchronously reads the file from the 698 * specified `fd` (file descriptor). 699 * @param {number} fd 700 * @param {Buffer | TypedArray | DataView} buffer 701 * @param {{ 702 * offset?: number; 703 * length?: number; 704 * position?: number | bigint | null; 705 * }} [offset] 706 * @returns {number} 707 */ 708function readSync(fd, buffer, offset, length, position) { 709 fd = getValidatedFd(fd); 710 711 validateBuffer(buffer); 712 713 if (arguments.length <= 3) { 714 // Assume fs.readSync(fd, buffer, options) 715 const options = offset || kEmptyObject; 716 717 ({ 718 offset = 0, 719 length = buffer.byteLength - offset, 720 position = null, 721 } = options); 722 } 723 724 if (offset == null) { 725 offset = 0; 726 } else { 727 validateInteger(offset, 'offset', 0); 728 } 729 730 length |= 0; 731 732 if (length === 0) { 733 return 0; 734 } 735 736 if (buffer.byteLength === 0) { 737 throw new ERR_INVALID_ARG_VALUE('buffer', buffer, 738 'is empty and cannot be written'); 739 } 740 741 validateOffsetLengthRead(offset, length, buffer.byteLength); 742 743 if (position == null) 744 position = -1; 745 746 validatePosition(position, 'position'); 747 748 const ctx = {}; 749 const result = binding.read(fd, buffer, offset, length, position, 750 undefined, ctx); 751 handleErrorFromBinding(ctx); 752 return result; 753} 754 755/** 756 * Reads file from the specified `fd` (file descriptor) 757 * and writes to an array of `ArrayBufferView`s. 758 * @param {number} fd 759 * @param {ArrayBufferView[]} buffers 760 * @param {number | null} [position] 761 * @param {( 762 * err?: Error, 763 * bytesRead?: number, 764 * buffers?: ArrayBufferView[]; 765 * ) => any} callback 766 * @returns {void} 767 */ 768function readv(fd, buffers, position, callback) { 769 function wrapper(err, read) { 770 callback(err, read || 0, buffers); 771 } 772 773 fd = getValidatedFd(fd); 774 validateBufferArray(buffers); 775 callback = maybeCallback(callback || position); 776 777 const req = new FSReqCallback(); 778 req.oncomplete = wrapper; 779 780 if (typeof position !== 'number') 781 position = null; 782 783 return binding.readBuffers(fd, buffers, position, req); 784} 785 786ObjectDefineProperty(readv, kCustomPromisifyArgsSymbol, 787 { __proto__: null, value: ['bytesRead', 'buffers'], enumerable: false }); 788 789/** 790 * Synchronously reads file from the 791 * specified `fd` (file descriptor) and writes to an array 792 * of `ArrayBufferView`s. 793 * @param {number} fd 794 * @param {ArrayBufferView[]} buffers 795 * @param {number | null} [position] 796 * @returns {number} 797 */ 798function readvSync(fd, buffers, position) { 799 fd = getValidatedFd(fd); 800 validateBufferArray(buffers); 801 802 const ctx = {}; 803 804 if (typeof position !== 'number') 805 position = null; 806 807 const result = binding.readBuffers(fd, buffers, position, undefined, ctx); 808 handleErrorFromBinding(ctx); 809 return result; 810} 811 812/** 813 * Writes `buffer` to the specified `fd` (file descriptor). 814 * @param {number} fd 815 * @param {Buffer | TypedArray | DataView | string | object} buffer 816 * @param {number | object} [offsetOrOptions] 817 * @param {number} [length] 818 * @param {number | null} [position] 819 * @param {( 820 * err?: Error, 821 * bytesWritten?: number; 822 * buffer?: Buffer | TypedArray | DataView 823 * ) => any} callback 824 * @returns {void} 825 */ 826function write(fd, buffer, offsetOrOptions, length, position, callback) { 827 function wrapper(err, written) { 828 // Retain a reference to buffer so that it can't be GC'ed too soon. 829 callback(err, written || 0, buffer); 830 } 831 832 fd = getValidatedFd(fd); 833 834 let offset = offsetOrOptions; 835 if (isArrayBufferView(buffer)) { 836 callback = maybeCallback(callback || position || length || offset); 837 838 if (typeof offset === 'object') { 839 ({ 840 offset = 0, 841 length = buffer.byteLength - offset, 842 position = null, 843 } = offsetOrOptions ?? kEmptyObject); 844 } 845 846 if (offset == null || typeof offset === 'function') { 847 offset = 0; 848 } else { 849 validateInteger(offset, 'offset', 0); 850 } 851 if (typeof length !== 'number') 852 length = buffer.byteLength - offset; 853 if (typeof position !== 'number') 854 position = null; 855 validateOffsetLengthWrite(offset, length, buffer.byteLength); 856 857 const req = new FSReqCallback(); 858 req.oncomplete = wrapper; 859 return binding.writeBuffer(fd, buffer, offset, length, position, req); 860 } 861 862 validateStringAfterArrayBufferView(buffer, 'buffer'); 863 if (typeof buffer !== 'string') { 864 showStringCoercionDeprecation(); 865 } 866 867 if (typeof position !== 'function') { 868 if (typeof offset === 'function') { 869 position = offset; 870 offset = null; 871 } else { 872 position = length; 873 } 874 length = 'utf8'; 875 } 876 877 const str = String(buffer); 878 validateEncoding(str, length); 879 callback = maybeCallback(position); 880 881 const req = new FSReqCallback(); 882 req.oncomplete = wrapper; 883 return binding.writeString(fd, str, offset, length, req); 884} 885 886ObjectDefineProperty(write, kCustomPromisifyArgsSymbol, 887 { __proto__: null, value: ['bytesWritten', 'buffer'], enumerable: false }); 888 889/** 890 * Synchronously writes `buffer` to the 891 * specified `fd` (file descriptor). 892 * @param {number} fd 893 * @param {Buffer | TypedArray | DataView | string} buffer 894 * @param {{ 895 * offset?: number; 896 * length?: number; 897 * position?: number | null; 898 * }} [offsetOrOptions] 899 * @returns {number} 900 */ 901function writeSync(fd, buffer, offsetOrOptions, length, position) { 902 fd = getValidatedFd(fd); 903 const ctx = {}; 904 let result; 905 906 let offset = offsetOrOptions; 907 if (isArrayBufferView(buffer)) { 908 if (typeof offset === 'object') { 909 ({ 910 offset = 0, 911 length = buffer.byteLength - offset, 912 position = null, 913 } = offsetOrOptions ?? kEmptyObject); 914 } 915 if (position === undefined) 916 position = null; 917 if (offset == null) { 918 offset = 0; 919 } else { 920 validateInteger(offset, 'offset', 0); 921 } 922 if (typeof length !== 'number') 923 length = buffer.byteLength - offset; 924 validateOffsetLengthWrite(offset, length, buffer.byteLength); 925 result = binding.writeBuffer(fd, buffer, offset, length, position, 926 undefined, ctx); 927 } else { 928 validatePrimitiveStringAfterArrayBufferView(buffer, 'buffer'); 929 validateEncoding(buffer, length); 930 931 if (offset === undefined) 932 offset = null; 933 result = binding.writeString(fd, buffer, offset, length, 934 undefined, ctx); 935 } 936 handleErrorFromBinding(ctx); 937 return result; 938} 939 940/** 941 * Writes an array of `ArrayBufferView`s to the 942 * specified `fd` (file descriptor). 943 * @param {number} fd 944 * @param {ArrayBufferView[]} buffers 945 * @param {number | null} [position] 946 * @param {( 947 * err?: Error, 948 * bytesWritten?: number, 949 * buffers?: ArrayBufferView[] 950 * ) => any} callback 951 * @returns {void} 952 */ 953function writev(fd, buffers, position, callback) { 954 function wrapper(err, written) { 955 callback(err, written || 0, buffers); 956 } 957 958 fd = getValidatedFd(fd); 959 validateBufferArray(buffers); 960 callback = maybeCallback(callback || position); 961 962 if (buffers.length === 0) { 963 process.nextTick(callback, null, 0, buffers); 964 return; 965 } 966 967 const req = new FSReqCallback(); 968 req.oncomplete = wrapper; 969 970 if (typeof position !== 'number') 971 position = null; 972 973 return binding.writeBuffers(fd, buffers, position, req); 974} 975 976ObjectDefineProperty(writev, kCustomPromisifyArgsSymbol, { 977 __proto__: null, 978 value: ['bytesWritten', 'buffer'], 979 enumerable: false, 980}); 981 982/** 983 * Synchronously writes an array of `ArrayBufferView`s 984 * to the specified `fd` (file descriptor). 985 * @param {number} fd 986 * @param {ArrayBufferView[]} buffers 987 * @param {number | null} [position] 988 * @returns {number} 989 */ 990function writevSync(fd, buffers, position) { 991 fd = getValidatedFd(fd); 992 validateBufferArray(buffers); 993 994 if (buffers.length === 0) { 995 return 0; 996 } 997 998 const ctx = {}; 999 1000 if (typeof position !== 'number') 1001 position = null; 1002 1003 const result = binding.writeBuffers(fd, buffers, position, undefined, ctx); 1004 1005 handleErrorFromBinding(ctx); 1006 return result; 1007} 1008 1009/** 1010 * Asynchronously renames file at `oldPath` to 1011 * the pathname provided as `newPath`. 1012 * @param {string | Buffer | URL} oldPath 1013 * @param {string | Buffer | URL} newPath 1014 * @param {(err?: Error) => any} callback 1015 * @returns {void} 1016 */ 1017function rename(oldPath, newPath, callback) { 1018 callback = makeCallback(callback); 1019 oldPath = getValidatedPath(oldPath, 'oldPath'); 1020 newPath = getValidatedPath(newPath, 'newPath'); 1021 const req = new FSReqCallback(); 1022 req.oncomplete = callback; 1023 binding.rename(pathModule.toNamespacedPath(oldPath), 1024 pathModule.toNamespacedPath(newPath), 1025 req); 1026} 1027 1028 1029/** 1030 * Synchronously renames file at `oldPath` to 1031 * the pathname provided as `newPath`. 1032 * @param {string | Buffer | URL} oldPath 1033 * @param {string | Buffer | URL} newPath 1034 * @returns {void} 1035 */ 1036function renameSync(oldPath, newPath) { 1037 oldPath = getValidatedPath(oldPath, 'oldPath'); 1038 newPath = getValidatedPath(newPath, 'newPath'); 1039 const ctx = { path: oldPath, dest: newPath }; 1040 binding.rename(pathModule.toNamespacedPath(oldPath), 1041 pathModule.toNamespacedPath(newPath), undefined, ctx); 1042 handleErrorFromBinding(ctx); 1043} 1044 1045/** 1046 * Truncates the file. 1047 * @param {string | Buffer | URL} path 1048 * @param {number} [len] 1049 * @param {(err?: Error) => any} callback 1050 * @returns {void} 1051 */ 1052function truncate(path, len, callback) { 1053 if (typeof path === 'number') { 1054 showTruncateDeprecation(); 1055 return fs.ftruncate(path, len, callback); 1056 } 1057 if (typeof len === 'function') { 1058 callback = len; 1059 len = 0; 1060 } else if (len === undefined) { 1061 len = 0; 1062 } 1063 1064 validateInteger(len, 'len'); 1065 len = MathMax(0, len); 1066 callback = maybeCallback(callback); 1067 fs.open(path, 'r+', (er, fd) => { 1068 if (er) return callback(er); 1069 const req = new FSReqCallback(); 1070 req.oncomplete = function oncomplete(er) { 1071 fs.close(fd, (er2) => { 1072 callback(aggregateTwoErrors(er2, er)); 1073 }); 1074 }; 1075 binding.ftruncate(fd, len, req); 1076 }); 1077} 1078 1079/** 1080 * Synchronously truncates the file. 1081 * @param {string | Buffer | URL} path 1082 * @param {number} [len] 1083 * @returns {void} 1084 */ 1085function truncateSync(path, len) { 1086 if (typeof path === 'number') { 1087 // legacy 1088 showTruncateDeprecation(); 1089 return fs.ftruncateSync(path, len); 1090 } 1091 if (len === undefined) { 1092 len = 0; 1093 } 1094 // Allow error to be thrown, but still close fd. 1095 const fd = fs.openSync(path, 'r+'); 1096 let ret; 1097 1098 try { 1099 ret = fs.ftruncateSync(fd, len); 1100 } finally { 1101 fs.closeSync(fd); 1102 } 1103 return ret; 1104} 1105 1106/** 1107 * Truncates the file descriptor. 1108 * @param {number} fd 1109 * @param {number} [len] 1110 * @param {(err?: Error) => any} callback 1111 * @returns {void} 1112 */ 1113function ftruncate(fd, len = 0, callback) { 1114 if (typeof len === 'function') { 1115 callback = len; 1116 len = 0; 1117 } 1118 fd = getValidatedFd(fd); 1119 validateInteger(len, 'len'); 1120 len = MathMax(0, len); 1121 callback = makeCallback(callback); 1122 1123 const req = new FSReqCallback(); 1124 req.oncomplete = callback; 1125 binding.ftruncate(fd, len, req); 1126} 1127 1128/** 1129 * Synchronously truncates the file descriptor. 1130 * @param {number} fd 1131 * @param {number} [len] 1132 * @returns {void} 1133 */ 1134function ftruncateSync(fd, len = 0) { 1135 fd = getValidatedFd(fd); 1136 validateInteger(len, 'len'); 1137 len = MathMax(0, len); 1138 const ctx = {}; 1139 binding.ftruncate(fd, len, undefined, ctx); 1140 handleErrorFromBinding(ctx); 1141} 1142 1143function lazyLoadCp() { 1144 if (cpFn === undefined) { 1145 ({ cpFn } = require('internal/fs/cp/cp')); 1146 cpFn = require('util').callbackify(cpFn); 1147 ({ cpSyncFn } = require('internal/fs/cp/cp-sync')); 1148 } 1149} 1150 1151function lazyLoadRimraf() { 1152 if (rimraf === undefined) 1153 ({ rimraf, rimrafSync } = require('internal/fs/rimraf')); 1154} 1155 1156/** 1157 * Asynchronously removes a directory. 1158 * @param {string | Buffer | URL} path 1159 * @param {{ 1160 * maxRetries?: number; 1161 * recursive?: boolean; 1162 * retryDelay?: number; 1163 * }} [options] 1164 * @param {(err?: Error) => any} callback 1165 * @returns {void} 1166 */ 1167function rmdir(path, options, callback) { 1168 if (typeof options === 'function') { 1169 callback = options; 1170 options = undefined; 1171 } 1172 1173 callback = makeCallback(callback); 1174 path = pathModule.toNamespacedPath(getValidatedPath(path)); 1175 1176 if (options?.recursive) { 1177 emitRecursiveRmdirWarning(); 1178 validateRmOptions( 1179 path, 1180 { ...options, force: false }, 1181 true, 1182 (err, options) => { 1183 if (err === false) { 1184 const req = new FSReqCallback(); 1185 req.oncomplete = callback; 1186 return binding.rmdir(path, req); 1187 } 1188 if (err) { 1189 return callback(err); 1190 } 1191 1192 lazyLoadRimraf(); 1193 rimraf(path, options, callback); 1194 }); 1195 } else { 1196 validateRmdirOptions(options); 1197 const req = new FSReqCallback(); 1198 req.oncomplete = callback; 1199 return binding.rmdir(path, req); 1200 } 1201} 1202 1203/** 1204 * Synchronously removes a directory. 1205 * @param {string | Buffer | URL} path 1206 * @param {{ 1207 * maxRetries?: number; 1208 * recursive?: boolean; 1209 * retryDelay?: number; 1210 * }} [options] 1211 * @returns {void} 1212 */ 1213function rmdirSync(path, options) { 1214 path = getValidatedPath(path); 1215 1216 if (options?.recursive) { 1217 emitRecursiveRmdirWarning(); 1218 options = validateRmOptionsSync(path, { ...options, force: false }, true); 1219 if (options !== false) { 1220 lazyLoadRimraf(); 1221 return rimrafSync(pathModule.toNamespacedPath(path), options); 1222 } 1223 } else { 1224 validateRmdirOptions(options); 1225 } 1226 1227 const ctx = { path }; 1228 binding.rmdir(pathModule.toNamespacedPath(path), undefined, ctx); 1229 return handleErrorFromBinding(ctx); 1230} 1231 1232/** 1233 * Asynchronously removes files and 1234 * directories (modeled on the standard POSIX `rm` utility). 1235 * @param {string | Buffer | URL} path 1236 * @param {{ 1237 * force?: boolean; 1238 * maxRetries?: number; 1239 * recursive?: boolean; 1240 * retryDelay?: number; 1241 * }} [options] 1242 * @param {(err?: Error) => any} callback 1243 * @returns {void} 1244 */ 1245function rm(path, options, callback) { 1246 if (typeof options === 'function') { 1247 callback = options; 1248 options = undefined; 1249 } 1250 path = getValidatedPath(path); 1251 1252 validateRmOptions(path, options, false, (err, options) => { 1253 if (err) { 1254 return callback(err); 1255 } 1256 lazyLoadRimraf(); 1257 return rimraf(pathModule.toNamespacedPath(path), options, callback); 1258 }); 1259} 1260 1261/** 1262 * Synchronously removes files and 1263 * directories (modeled on the standard POSIX `rm` utility). 1264 * @param {string | Buffer | URL} path 1265 * @param {{ 1266 * force?: boolean; 1267 * maxRetries?: number; 1268 * recursive?: boolean; 1269 * retryDelay?: number; 1270 * }} [options] 1271 * @returns {void} 1272 */ 1273function rmSync(path, options) { 1274 path = getValidatedPath(path); 1275 options = validateRmOptionsSync(path, options, false); 1276 1277 lazyLoadRimraf(); 1278 return rimrafSync(pathModule.toNamespacedPath(path), options); 1279} 1280 1281/** 1282 * Forces all currently queued I/O operations associated 1283 * with the file to the operating system's synchronized 1284 * I/O completion state. 1285 * @param {number} fd 1286 * @param {(err?: Error) => any} callback 1287 * @returns {void} 1288 */ 1289function fdatasync(fd, callback) { 1290 fd = getValidatedFd(fd); 1291 const req = new FSReqCallback(); 1292 req.oncomplete = makeCallback(callback); 1293 binding.fdatasync(fd, req); 1294} 1295 1296/** 1297 * Synchronously forces all currently queued I/O operations 1298 * associated with the file to the operating 1299 * system's synchronized I/O completion state. 1300 * @param {number} fd 1301 * @returns {void} 1302 */ 1303function fdatasyncSync(fd) { 1304 fd = getValidatedFd(fd); 1305 const ctx = {}; 1306 binding.fdatasync(fd, undefined, ctx); 1307 handleErrorFromBinding(ctx); 1308} 1309 1310/** 1311 * Requests for all data for the open file descriptor 1312 * to be flushed to the storage device. 1313 * @param {number} fd 1314 * @param {(err?: Error) => any} callback 1315 * @returns {void} 1316 */ 1317function fsync(fd, callback) { 1318 fd = getValidatedFd(fd); 1319 const req = new FSReqCallback(); 1320 req.oncomplete = makeCallback(callback); 1321 binding.fsync(fd, req); 1322} 1323 1324/** 1325 * Synchronously requests for all data for the open 1326 * file descriptor to be flushed to the storage device. 1327 * @param {number} fd 1328 * @returns {void} 1329 */ 1330function fsyncSync(fd) { 1331 fd = getValidatedFd(fd); 1332 const ctx = {}; 1333 binding.fsync(fd, undefined, ctx); 1334 handleErrorFromBinding(ctx); 1335} 1336 1337/** 1338 * Asynchronously creates a directory. 1339 * @param {string | Buffer | URL} path 1340 * @param {{ 1341 * recursive?: boolean; 1342 * mode?: string | number; 1343 * } | number} [options] 1344 * @param {(err?: Error) => any} callback 1345 * @returns {void} 1346 */ 1347function mkdir(path, options, callback) { 1348 let mode = 0o777; 1349 let recursive = false; 1350 if (typeof options === 'function') { 1351 callback = options; 1352 } else if (typeof options === 'number' || typeof options === 'string') { 1353 mode = options; 1354 } else if (options) { 1355 if (options.recursive !== undefined) 1356 recursive = options.recursive; 1357 if (options.mode !== undefined) 1358 mode = options.mode; 1359 } 1360 callback = makeCallback(callback); 1361 path = getValidatedPath(path); 1362 1363 validateBoolean(recursive, 'options.recursive'); 1364 1365 const req = new FSReqCallback(); 1366 req.oncomplete = callback; 1367 binding.mkdir(pathModule.toNamespacedPath(path), 1368 parseFileMode(mode, 'mode'), recursive, req); 1369} 1370 1371/** 1372 * Synchronously creates a directory. 1373 * @param {string | Buffer | URL} path 1374 * @param {{ 1375 * recursive?: boolean; 1376 * mode?: string | number; 1377 * } | number} [options] 1378 * @returns {string | void} 1379 */ 1380function mkdirSync(path, options) { 1381 let mode = 0o777; 1382 let recursive = false; 1383 if (typeof options === 'number' || typeof options === 'string') { 1384 mode = options; 1385 } else if (options) { 1386 if (options.recursive !== undefined) 1387 recursive = options.recursive; 1388 if (options.mode !== undefined) 1389 mode = options.mode; 1390 } 1391 path = getValidatedPath(path); 1392 validateBoolean(recursive, 'options.recursive'); 1393 1394 const ctx = { path }; 1395 const result = binding.mkdir(pathModule.toNamespacedPath(path), 1396 parseFileMode(mode, 'mode'), recursive, 1397 undefined, ctx); 1398 handleErrorFromBinding(ctx); 1399 if (recursive) { 1400 return result; 1401 } 1402} 1403 1404/** 1405 * An iterative algorithm for reading the entire contents of the `basePath` directory. 1406 * This function does not validate `basePath` as a directory. It is passed directly to 1407 * `binding.readdir` after a `nullCheck`. 1408 * @param {string} basePath 1409 * @param {{ encoding: string, withFileTypes: boolean }} options 1410 * @returns {string[] | Dirent[]} 1411 */ 1412function readdirSyncRecursive(basePath, options) { 1413 nullCheck(basePath, 'path', true); 1414 1415 const withFileTypes = Boolean(options.withFileTypes); 1416 const encoding = options.encoding; 1417 1418 const readdirResults = []; 1419 const pathsQueue = [basePath]; 1420 1421 const ctx = { path: basePath }; 1422 function read(path) { 1423 ctx.path = path; 1424 const readdirResult = binding.readdir( 1425 pathModule.toNamespacedPath(path), 1426 encoding, 1427 withFileTypes, 1428 undefined, 1429 ctx, 1430 ); 1431 handleErrorFromBinding(ctx); 1432 1433 for (let i = 0; i < readdirResult.length; i++) { 1434 if (withFileTypes) { 1435 const dirent = getDirent(path, readdirResult[0][i], readdirResult[1][i]); 1436 ArrayPrototypePush(readdirResults, dirent); 1437 if (dirent.isDirectory()) { 1438 ArrayPrototypePush(pathsQueue, pathModule.join(dirent.path, dirent.name)); 1439 } 1440 } else { 1441 const resultPath = pathModule.join(path, readdirResult[i]); 1442 const relativeResultPath = pathModule.relative(basePath, resultPath); 1443 const stat = binding.internalModuleStat(resultPath); 1444 ArrayPrototypePush(readdirResults, relativeResultPath); 1445 // 1 indicates directory 1446 if (stat === 1) { 1447 ArrayPrototypePush(pathsQueue, resultPath); 1448 } 1449 } 1450 } 1451 } 1452 1453 for (let i = 0; i < pathsQueue.length; i++) { 1454 read(pathsQueue[i]); 1455 } 1456 1457 return readdirResults; 1458} 1459 1460/** 1461 * Reads the contents of a directory. 1462 * @param {string | Buffer | URL} path 1463 * @param {string | { 1464 * encoding?: string; 1465 * withFileTypes?: boolean; 1466 * }} [options] 1467 * @param {( 1468 * err?: Error, 1469 * files?: string[] | Buffer[] | Direct[]; 1470 * ) => any} callback 1471 * @returns {void} 1472 */ 1473function readdir(path, options, callback) { 1474 callback = makeCallback(typeof options === 'function' ? options : callback); 1475 options = getOptions(options); 1476 path = getValidatedPath(path); 1477 if (options.recursive != null) { 1478 validateBoolean(options.recursive, 'options.recursive'); 1479 } 1480 1481 if (options.recursive) { 1482 callback(null, readdirSyncRecursive(path, options)); 1483 return; 1484 } 1485 1486 const req = new FSReqCallback(); 1487 if (!options.withFileTypes) { 1488 req.oncomplete = callback; 1489 } else { 1490 req.oncomplete = (err, result) => { 1491 if (err) { 1492 callback(err); 1493 return; 1494 } 1495 getDirents(path, result, callback); 1496 }; 1497 } 1498 binding.readdir(pathModule.toNamespacedPath(path), options.encoding, 1499 !!options.withFileTypes, req); 1500} 1501 1502/** 1503 * Synchronously reads the contents of a directory. 1504 * @param {string | Buffer | URL} path 1505 * @param {string | { 1506 * encoding?: string; 1507 * withFileTypes?: boolean; 1508 * recursive?: boolean; 1509 * }} [options] 1510 * @returns {string | Buffer[] | Dirent[]} 1511 */ 1512function readdirSync(path, options) { 1513 options = getOptions(options); 1514 path = getValidatedPath(path); 1515 if (options.recursive != null) { 1516 validateBoolean(options.recursive, 'options.recursive'); 1517 } 1518 1519 if (options.recursive) { 1520 return readdirSyncRecursive(path, options); 1521 } 1522 1523 const ctx = { path }; 1524 const result = binding.readdir(pathModule.toNamespacedPath(path), 1525 options.encoding, !!options.withFileTypes, 1526 undefined, ctx); 1527 handleErrorFromBinding(ctx); 1528 return options.withFileTypes ? getDirents(path, result) : result; 1529} 1530 1531/** 1532 * Invokes the callback with the `fs.Stats` 1533 * for the file descriptor. 1534 * @param {number} fd 1535 * @param {{ bigint?: boolean; }} [options] 1536 * @param {( 1537 * err?: Error, 1538 * stats?: Stats 1539 * ) => any} callback 1540 * @returns {void} 1541 */ 1542function fstat(fd, options = { bigint: false }, callback) { 1543 if (typeof options === 'function') { 1544 callback = options; 1545 options = kEmptyObject; 1546 } 1547 fd = getValidatedFd(fd); 1548 callback = makeStatsCallback(callback); 1549 1550 const req = new FSReqCallback(options.bigint); 1551 req.oncomplete = callback; 1552 binding.fstat(fd, options.bigint, req); 1553} 1554 1555/** 1556 * Retrieves the `fs.Stats` for the symbolic link 1557 * referred to by the `path`. 1558 * @param {string | Buffer | URL} path 1559 * @param {{ bigint?: boolean; }} [options] 1560 * @param {( 1561 * err?: Error, 1562 * stats?: Stats 1563 * ) => any} callback 1564 * @returns {void} 1565 */ 1566function lstat(path, options = { bigint: false }, callback) { 1567 if (typeof options === 'function') { 1568 callback = options; 1569 options = kEmptyObject; 1570 } 1571 callback = makeStatsCallback(callback); 1572 path = getValidatedPath(path); 1573 1574 const req = new FSReqCallback(options.bigint); 1575 req.oncomplete = callback; 1576 binding.lstat(pathModule.toNamespacedPath(path), options.bigint, req); 1577} 1578 1579/** 1580 * Asynchronously gets the stats of a file. 1581 * @param {string | Buffer | URL} path 1582 * @param {{ bigint?: boolean; }} [options] 1583 * @param {( 1584 * err?: Error, 1585 * stats?: Stats 1586 * ) => any} callback 1587 * @returns {void} 1588 */ 1589function stat(path, options = { bigint: false }, callback) { 1590 if (typeof options === 'function') { 1591 callback = options; 1592 options = kEmptyObject; 1593 } 1594 callback = makeStatsCallback(callback); 1595 path = getValidatedPath(path); 1596 1597 const req = new FSReqCallback(options.bigint); 1598 req.oncomplete = callback; 1599 binding.stat(pathModule.toNamespacedPath(path), options.bigint, req); 1600} 1601 1602function statfs(path, options = { bigint: false }, callback) { 1603 if (typeof options === 'function') { 1604 callback = options; 1605 options = kEmptyObject; 1606 } 1607 callback = maybeCallback(callback); 1608 path = getValidatedPath(path); 1609 const req = new FSReqCallback(options.bigint); 1610 req.oncomplete = (err, stats) => { 1611 if (err) { 1612 return callback(err); 1613 } 1614 1615 callback(err, getStatFsFromBinding(stats)); 1616 }; 1617 binding.statfs(pathModule.toNamespacedPath(path), options.bigint, req); 1618} 1619 1620function hasNoEntryError(ctx) { 1621 if (ctx.errno) { 1622 const uvErr = uvErrmapGet(ctx.errno); 1623 return uvErr?.[0] === 'ENOENT'; 1624 } 1625 1626 if (ctx.error) { 1627 return ctx.error.code === 'ENOENT'; 1628 } 1629 1630 return false; 1631} 1632 1633/** 1634 * Synchronously retrieves the `fs.Stats` for 1635 * the file descriptor. 1636 * @param {number} fd 1637 * @param {{ 1638 * bigint?: boolean; 1639 * }} [options] 1640 * @returns {Stats} 1641 */ 1642function fstatSync(fd, options = { bigint: false }) { 1643 fd = getValidatedFd(fd); 1644 const ctx = { fd }; 1645 const stats = binding.fstat(fd, options.bigint, undefined, ctx); 1646 handleErrorFromBinding(ctx); 1647 return getStatsFromBinding(stats); 1648} 1649 1650/** 1651 * Synchronously retrieves the `fs.Stats` for 1652 * the symbolic link referred to by the `path`. 1653 * @param {string | Buffer | URL} path 1654 * @param {{ 1655 * bigint?: boolean; 1656 * throwIfNoEntry?: boolean; 1657 * }} [options] 1658 * @returns {Stats} 1659 */ 1660function lstatSync(path, options = { bigint: false, throwIfNoEntry: true }) { 1661 path = getValidatedPath(path); 1662 const ctx = { path }; 1663 const stats = binding.lstat(pathModule.toNamespacedPath(path), 1664 options.bigint, undefined, ctx); 1665 if (options.throwIfNoEntry === false && hasNoEntryError(ctx)) { 1666 return undefined; 1667 } 1668 handleErrorFromBinding(ctx); 1669 return getStatsFromBinding(stats); 1670} 1671 1672/** 1673 * Synchronously retrieves the `fs.Stats` 1674 * for the `path`. 1675 * @param {string | Buffer | URL} path 1676 * @param {{ 1677 * bigint?: boolean; 1678 * throwIfNoEntry?: boolean; 1679 * }} [options] 1680 * @returns {Stats} 1681 */ 1682function statSync(path, options = { bigint: false, throwIfNoEntry: true }) { 1683 path = getValidatedPath(path); 1684 const ctx = { path }; 1685 const stats = binding.stat(pathModule.toNamespacedPath(path), 1686 options.bigint, undefined, ctx); 1687 if (options.throwIfNoEntry === false && hasNoEntryError(ctx)) { 1688 return undefined; 1689 } 1690 handleErrorFromBinding(ctx); 1691 return getStatsFromBinding(stats); 1692} 1693 1694function statfsSync(path, options = { bigint: false }) { 1695 path = getValidatedPath(path); 1696 const ctx = { path }; 1697 const stats = binding.statfs(pathModule.toNamespacedPath(path), 1698 options.bigint, undefined, ctx); 1699 handleErrorFromBinding(ctx); 1700 return getStatFsFromBinding(stats); 1701} 1702 1703/** 1704 * Reads the contents of a symbolic link 1705 * referred to by `path`. 1706 * @param {string | Buffer | URL} path 1707 * @param {{ encoding?: string; } | string} [options] 1708 * @param {( 1709 * err?: Error, 1710 * linkString?: string | Buffer 1711 * ) => any} callback 1712 * @returns {void} 1713 */ 1714function readlink(path, options, callback) { 1715 callback = makeCallback(typeof options === 'function' ? options : callback); 1716 options = getOptions(options); 1717 path = getValidatedPath(path, 'oldPath'); 1718 const req = new FSReqCallback(); 1719 req.oncomplete = callback; 1720 binding.readlink(pathModule.toNamespacedPath(path), options.encoding, req); 1721} 1722 1723/** 1724 * Synchronously reads the contents of a symbolic link 1725 * referred to by `path`. 1726 * @param {string | Buffer | URL} path 1727 * @param {{ encoding?: string; } | string} [options] 1728 * @returns {string | Buffer} 1729 */ 1730function readlinkSync(path, options) { 1731 options = getOptions(options); 1732 path = getValidatedPath(path, 'oldPath'); 1733 const ctx = { path }; 1734 const result = binding.readlink(pathModule.toNamespacedPath(path), 1735 options.encoding, undefined, ctx); 1736 handleErrorFromBinding(ctx); 1737 return result; 1738} 1739 1740/** 1741 * Creates the link called `path` pointing to `target`. 1742 * @param {string | Buffer | URL} target 1743 * @param {string | Buffer | URL} path 1744 * @param {string | null} [type_] 1745 * @param {(err?: Error) => any} callback_ 1746 * @returns {void} 1747 */ 1748function symlink(target, path, type_, callback_) { 1749 const type = (typeof type_ === 'string' ? type_ : null); 1750 const callback = makeCallback(arguments[arguments.length - 1]); 1751 1752 target = getValidatedPath(target, 'target'); 1753 path = getValidatedPath(path); 1754 1755 if (isWindows && type === null) { 1756 let absoluteTarget; 1757 try { 1758 // Symlinks targets can be relative to the newly created path. 1759 // Calculate absolute file name of the symlink target, and check 1760 // if it is a directory. Ignore resolve error to keep symlink 1761 // errors consistent between platforms if invalid path is 1762 // provided. 1763 absoluteTarget = pathModule.resolve(path, '..', target); 1764 } catch { 1765 // Continue regardless of error. 1766 } 1767 if (absoluteTarget !== undefined) { 1768 stat(absoluteTarget, (err, stat) => { 1769 const resolvedType = !err && stat.isDirectory() ? 'dir' : 'file'; 1770 const resolvedFlags = stringToSymlinkType(resolvedType); 1771 const destination = preprocessSymlinkDestination(target, 1772 resolvedType, 1773 path); 1774 1775 const req = new FSReqCallback(); 1776 req.oncomplete = callback; 1777 binding.symlink(destination, 1778 pathModule.toNamespacedPath(path), resolvedFlags, req); 1779 }); 1780 return; 1781 } 1782 } 1783 1784 const destination = preprocessSymlinkDestination(target, type, path); 1785 1786 const flags = stringToSymlinkType(type); 1787 const req = new FSReqCallback(); 1788 req.oncomplete = callback; 1789 binding.symlink(destination, pathModule.toNamespacedPath(path), flags, req); 1790} 1791 1792/** 1793 * Synchronously creates the link called `path` 1794 * pointing to `target`. 1795 * @param {string | Buffer | URL} target 1796 * @param {string | Buffer | URL} path 1797 * @param {string | null} [type] 1798 * @returns {void} 1799 */ 1800function symlinkSync(target, path, type) { 1801 type = (typeof type === 'string' ? type : null); 1802 if (isWindows && type === null) { 1803 const absoluteTarget = pathModule.resolve(`${path}`, '..', `${target}`); 1804 if (statSync(absoluteTarget, { throwIfNoEntry: false })?.isDirectory()) { 1805 type = 'dir'; 1806 } 1807 } 1808 target = getValidatedPath(target, 'target'); 1809 path = getValidatedPath(path); 1810 const flags = stringToSymlinkType(type); 1811 1812 const ctx = { path: target, dest: path }; 1813 binding.symlink(preprocessSymlinkDestination(target, type, path), 1814 pathModule.toNamespacedPath(path), flags, undefined, ctx); 1815 1816 handleErrorFromBinding(ctx); 1817} 1818 1819/** 1820 * Creates a new link from the `existingPath` 1821 * to the `newPath`. 1822 * @param {string | Buffer | URL} existingPath 1823 * @param {string | Buffer | URL} newPath 1824 * @param {(err?: Error) => any} callback 1825 * @returns {void} 1826 */ 1827function link(existingPath, newPath, callback) { 1828 callback = makeCallback(callback); 1829 1830 existingPath = getValidatedPath(existingPath, 'existingPath'); 1831 newPath = getValidatedPath(newPath, 'newPath'); 1832 1833 const req = new FSReqCallback(); 1834 req.oncomplete = callback; 1835 1836 binding.link(pathModule.toNamespacedPath(existingPath), 1837 pathModule.toNamespacedPath(newPath), 1838 req); 1839} 1840 1841/** 1842 * Synchronously creates a new link from the `existingPath` 1843 * to the `newPath`. 1844 * @param {string | Buffer | URL} existingPath 1845 * @param {string | Buffer | URL} newPath 1846 * @returns {void} 1847 */ 1848function linkSync(existingPath, newPath) { 1849 existingPath = getValidatedPath(existingPath, 'existingPath'); 1850 newPath = getValidatedPath(newPath, 'newPath'); 1851 1852 const ctx = { path: existingPath, dest: newPath }; 1853 const result = binding.link(pathModule.toNamespacedPath(existingPath), 1854 pathModule.toNamespacedPath(newPath), 1855 undefined, ctx); 1856 handleErrorFromBinding(ctx); 1857 return result; 1858} 1859 1860/** 1861 * Asynchronously removes a file or symbolic link. 1862 * @param {string | Buffer | URL} path 1863 * @param {(err?: Error) => any} callback 1864 * @returns {void} 1865 */ 1866function unlink(path, callback) { 1867 callback = makeCallback(callback); 1868 path = getValidatedPath(path); 1869 const req = new FSReqCallback(); 1870 req.oncomplete = callback; 1871 binding.unlink(pathModule.toNamespacedPath(path), req); 1872} 1873 1874/** 1875 * Synchronously removes a file or symbolic link. 1876 * @param {string | Buffer | URL} path 1877 * @returns {void} 1878 */ 1879function unlinkSync(path) { 1880 path = getValidatedPath(path); 1881 const ctx = { path }; 1882 binding.unlink(pathModule.toNamespacedPath(path), undefined, ctx); 1883 handleErrorFromBinding(ctx); 1884} 1885 1886/** 1887 * Sets the permissions on the file. 1888 * @param {number} fd 1889 * @param {string | number} mode 1890 * @param {(err?: Error) => any} callback 1891 * @returns {void} 1892 */ 1893function fchmod(fd, mode, callback) { 1894 fd = getValidatedFd(fd); 1895 mode = parseFileMode(mode, 'mode'); 1896 callback = makeCallback(callback); 1897 1898 const req = new FSReqCallback(); 1899 req.oncomplete = callback; 1900 binding.fchmod(fd, mode, req); 1901} 1902 1903/** 1904 * Synchronously sets the permissions on the file. 1905 * @param {number} fd 1906 * @param {string | number} mode 1907 * @returns {void} 1908 */ 1909function fchmodSync(fd, mode) { 1910 fd = getValidatedFd(fd); 1911 mode = parseFileMode(mode, 'mode'); 1912 const ctx = {}; 1913 binding.fchmod(fd, mode, undefined, ctx); 1914 handleErrorFromBinding(ctx); 1915} 1916 1917/** 1918 * Changes the permissions on a symbolic link. 1919 * @param {string | Buffer | URL} path 1920 * @param {number} mode 1921 * @param {(err?: Error) => any} callback 1922 * @returns {void} 1923 */ 1924function lchmod(path, mode, callback) { 1925 callback = maybeCallback(callback); 1926 mode = parseFileMode(mode, 'mode'); 1927 fs.open(path, O_WRONLY | O_SYMLINK, (err, fd) => { 1928 if (err) { 1929 callback(err); 1930 return; 1931 } 1932 // Prefer to return the chmod error, if one occurs, 1933 // but still try to close, and report closing errors if they occur. 1934 fs.fchmod(fd, mode, (err) => { 1935 fs.close(fd, (err2) => { 1936 callback(aggregateTwoErrors(err2, err)); 1937 }); 1938 }); 1939 }); 1940} 1941 1942/** 1943 * Synchronously changes the permissions on a symbolic link. 1944 * @param {string | Buffer | URL} path 1945 * @param {number} mode 1946 * @returns {void} 1947 */ 1948function lchmodSync(path, mode) { 1949 const fd = fs.openSync(path, O_WRONLY | O_SYMLINK); 1950 1951 // Prefer to return the chmod error, if one occurs, 1952 // but still try to close, and report closing errors if they occur. 1953 let ret; 1954 try { 1955 ret = fs.fchmodSync(fd, mode); 1956 } finally { 1957 fs.closeSync(fd); 1958 } 1959 return ret; 1960} 1961 1962/** 1963 * Asynchronously changes the permissions of a file. 1964 * @param {string | Buffer | URL} path 1965 * @param {string | number} mode 1966 * @param {(err?: Error) => any} callback 1967 * @returns {void} 1968 */ 1969function chmod(path, mode, callback) { 1970 path = getValidatedPath(path); 1971 mode = parseFileMode(mode, 'mode'); 1972 callback = makeCallback(callback); 1973 1974 const req = new FSReqCallback(); 1975 req.oncomplete = callback; 1976 binding.chmod(pathModule.toNamespacedPath(path), mode, req); 1977} 1978 1979/** 1980 * Synchronously changes the permissions of a file. 1981 * @param {string | Buffer | URL} path 1982 * @param {string | number} mode 1983 * @returns {void} 1984 */ 1985function chmodSync(path, mode) { 1986 path = getValidatedPath(path); 1987 mode = parseFileMode(mode, 'mode'); 1988 1989 const ctx = { path }; 1990 binding.chmod(pathModule.toNamespacedPath(path), mode, undefined, ctx); 1991 handleErrorFromBinding(ctx); 1992} 1993 1994/** 1995 * Sets the owner of the symbolic link. 1996 * @param {string | Buffer | URL} path 1997 * @param {number} uid 1998 * @param {number} gid 1999 * @param {(err?: Error) => any} callback 2000 * @returns {void} 2001 */ 2002function lchown(path, uid, gid, callback) { 2003 callback = makeCallback(callback); 2004 path = getValidatedPath(path); 2005 validateInteger(uid, 'uid', -1, kMaxUserId); 2006 validateInteger(gid, 'gid', -1, kMaxUserId); 2007 const req = new FSReqCallback(); 2008 req.oncomplete = callback; 2009 binding.lchown(pathModule.toNamespacedPath(path), uid, gid, req); 2010} 2011 2012/** 2013 * Synchronously sets the owner of the symbolic link. 2014 * @param {string | Buffer | URL} path 2015 * @param {number} uid 2016 * @param {number} gid 2017 * @returns {void} 2018 */ 2019function lchownSync(path, uid, gid) { 2020 path = getValidatedPath(path); 2021 validateInteger(uid, 'uid', -1, kMaxUserId); 2022 validateInteger(gid, 'gid', -1, kMaxUserId); 2023 const ctx = { path }; 2024 binding.lchown(pathModule.toNamespacedPath(path), uid, gid, undefined, ctx); 2025 handleErrorFromBinding(ctx); 2026} 2027 2028/** 2029 * Sets the owner of the file. 2030 * @param {number} fd 2031 * @param {number} uid 2032 * @param {number} gid 2033 * @param {(err?: Error) => any} callback 2034 * @returns {void} 2035 */ 2036function fchown(fd, uid, gid, callback) { 2037 fd = getValidatedFd(fd); 2038 validateInteger(uid, 'uid', -1, kMaxUserId); 2039 validateInteger(gid, 'gid', -1, kMaxUserId); 2040 callback = makeCallback(callback); 2041 2042 const req = new FSReqCallback(); 2043 req.oncomplete = callback; 2044 binding.fchown(fd, uid, gid, req); 2045} 2046 2047/** 2048 * Synchronously sets the owner of the file. 2049 * @param {number} fd 2050 * @param {number} uid 2051 * @param {number} gid 2052 * @returns {void} 2053 */ 2054function fchownSync(fd, uid, gid) { 2055 fd = getValidatedFd(fd); 2056 validateInteger(uid, 'uid', -1, kMaxUserId); 2057 validateInteger(gid, 'gid', -1, kMaxUserId); 2058 2059 const ctx = {}; 2060 binding.fchown(fd, uid, gid, undefined, ctx); 2061 handleErrorFromBinding(ctx); 2062} 2063 2064/** 2065 * Asynchronously changes the owner and group 2066 * of a file. 2067 * @param {string | Buffer | URL} path 2068 * @param {number} uid 2069 * @param {number} gid 2070 * @param {(err?: Error) => any} callback 2071 * @returns {void} 2072 */ 2073function chown(path, uid, gid, callback) { 2074 callback = makeCallback(callback); 2075 path = getValidatedPath(path); 2076 validateInteger(uid, 'uid', -1, kMaxUserId); 2077 validateInteger(gid, 'gid', -1, kMaxUserId); 2078 2079 const req = new FSReqCallback(); 2080 req.oncomplete = callback; 2081 binding.chown(pathModule.toNamespacedPath(path), uid, gid, req); 2082} 2083 2084/** 2085 * Synchronously changes the owner and group 2086 * of a file. 2087 * @param {string | Buffer | URL} path 2088 * @param {number} uid 2089 * @param {number} gid 2090 * @returns {void} 2091 */ 2092function chownSync(path, uid, gid) { 2093 path = getValidatedPath(path); 2094 validateInteger(uid, 'uid', -1, kMaxUserId); 2095 validateInteger(gid, 'gid', -1, kMaxUserId); 2096 const ctx = { path }; 2097 binding.chown(pathModule.toNamespacedPath(path), uid, gid, undefined, ctx); 2098 handleErrorFromBinding(ctx); 2099} 2100 2101/** 2102 * Changes the file system timestamps of the object 2103 * referenced by `path`. 2104 * @param {string | Buffer | URL} path 2105 * @param {number | string | Date} atime 2106 * @param {number | string | Date} mtime 2107 * @param {(err?: Error) => any} callback 2108 * @returns {void} 2109 */ 2110function utimes(path, atime, mtime, callback) { 2111 callback = makeCallback(callback); 2112 path = getValidatedPath(path); 2113 2114 const req = new FSReqCallback(); 2115 req.oncomplete = callback; 2116 binding.utimes(pathModule.toNamespacedPath(path), 2117 toUnixTimestamp(atime), 2118 toUnixTimestamp(mtime), 2119 req); 2120} 2121 2122/** 2123 * Synchronously changes the file system timestamps 2124 * of the object referenced by `path`. 2125 * @param {string | Buffer | URL} path 2126 * @param {number | string | Date} atime 2127 * @param {number | string | Date} mtime 2128 * @returns {void} 2129 */ 2130function utimesSync(path, atime, mtime) { 2131 path = getValidatedPath(path); 2132 const ctx = { path }; 2133 binding.utimes(pathModule.toNamespacedPath(path), 2134 toUnixTimestamp(atime), toUnixTimestamp(mtime), 2135 undefined, ctx); 2136 handleErrorFromBinding(ctx); 2137} 2138 2139/** 2140 * Changes the file system timestamps of the object 2141 * referenced by the supplied `fd` (file descriptor). 2142 * @param {number} fd 2143 * @param {number | string | Date} atime 2144 * @param {number | string | Date} mtime 2145 * @param {(err?: Error) => any} callback 2146 * @returns {void} 2147 */ 2148function futimes(fd, atime, mtime, callback) { 2149 fd = getValidatedFd(fd); 2150 atime = toUnixTimestamp(atime, 'atime'); 2151 mtime = toUnixTimestamp(mtime, 'mtime'); 2152 callback = makeCallback(callback); 2153 2154 const req = new FSReqCallback(); 2155 req.oncomplete = callback; 2156 binding.futimes(fd, atime, mtime, req); 2157} 2158 2159/** 2160 * Synchronously changes the file system timestamps 2161 * of the object referenced by the 2162 * supplied `fd` (file descriptor). 2163 * @param {number} fd 2164 * @param {number | string | Date} atime 2165 * @param {number | string | Date} mtime 2166 * @returns {void} 2167 */ 2168function futimesSync(fd, atime, mtime) { 2169 fd = getValidatedFd(fd); 2170 atime = toUnixTimestamp(atime, 'atime'); 2171 mtime = toUnixTimestamp(mtime, 'mtime'); 2172 const ctx = {}; 2173 binding.futimes(fd, atime, mtime, undefined, ctx); 2174 handleErrorFromBinding(ctx); 2175} 2176 2177/** 2178 * Changes the access and modification times of 2179 * a file in the same way as `fs.utimes()`. 2180 * @param {string | Buffer | URL} path 2181 * @param {number | string | Date} atime 2182 * @param {number | string | Date} mtime 2183 * @param {(err?: Error) => any} callback 2184 * @returns {void} 2185 */ 2186function lutimes(path, atime, mtime, callback) { 2187 callback = makeCallback(callback); 2188 path = getValidatedPath(path); 2189 2190 const req = new FSReqCallback(); 2191 req.oncomplete = callback; 2192 binding.lutimes(pathModule.toNamespacedPath(path), 2193 toUnixTimestamp(atime), 2194 toUnixTimestamp(mtime), 2195 req); 2196} 2197 2198/** 2199 * Synchronously changes the access and modification 2200 * times of a file in the same way as `fs.utimesSync()`. 2201 * @param {string | Buffer | URL} path 2202 * @param {number | string | Date} atime 2203 * @param {number | string | Date} mtime 2204 * @returns {void} 2205 */ 2206function lutimesSync(path, atime, mtime) { 2207 path = getValidatedPath(path); 2208 const ctx = { path }; 2209 binding.lutimes(pathModule.toNamespacedPath(path), 2210 toUnixTimestamp(atime), 2211 toUnixTimestamp(mtime), 2212 undefined, ctx); 2213 handleErrorFromBinding(ctx); 2214} 2215 2216function writeAll(fd, isUserFd, buffer, offset, length, signal, callback) { 2217 if (signal?.aborted) { 2218 const abortError = new AbortError(undefined, { cause: signal?.reason }); 2219 if (isUserFd) { 2220 callback(abortError); 2221 } else { 2222 fs.close(fd, (err) => { 2223 callback(aggregateTwoErrors(err, abortError)); 2224 }); 2225 } 2226 return; 2227 } 2228 // write(fd, buffer, offset, length, position, callback) 2229 fs.write(fd, buffer, offset, length, null, (writeErr, written) => { 2230 if (writeErr) { 2231 if (isUserFd) { 2232 callback(writeErr); 2233 } else { 2234 fs.close(fd, (err) => { 2235 callback(aggregateTwoErrors(err, writeErr)); 2236 }); 2237 } 2238 } else if (written === length) { 2239 if (isUserFd) { 2240 callback(null); 2241 } else { 2242 fs.close(fd, callback); 2243 } 2244 } else { 2245 offset += written; 2246 length -= written; 2247 writeAll(fd, isUserFd, buffer, offset, length, signal, callback); 2248 } 2249 }); 2250} 2251 2252/** 2253 * Asynchronously writes data to the file. 2254 * @param {string | Buffer | URL | number} path 2255 * @param {string | Buffer | TypedArray | DataView | object} data 2256 * @param {{ 2257 * encoding?: string | null; 2258 * mode?: number; 2259 * flag?: string; 2260 * signal?: AbortSignal; 2261 * } | string} [options] 2262 * @param {(err?: Error) => any} callback 2263 * @returns {void} 2264 */ 2265function writeFile(path, data, options, callback) { 2266 callback = maybeCallback(callback || options); 2267 options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'w' }); 2268 const flag = options.flag || 'w'; 2269 2270 if (!isArrayBufferView(data)) { 2271 validateStringAfterArrayBufferView(data, 'data'); 2272 if (typeof data !== 'string') { 2273 showStringCoercionDeprecation(); 2274 } 2275 data = Buffer.from(String(data), options.encoding || 'utf8'); 2276 } 2277 2278 if (isFd(path)) { 2279 const isUserFd = true; 2280 const signal = options.signal; 2281 writeAll(path, isUserFd, data, 0, data.byteLength, signal, callback); 2282 return; 2283 } 2284 2285 if (checkAborted(options.signal, callback)) 2286 return; 2287 2288 fs.open(path, flag, options.mode, (openErr, fd) => { 2289 if (openErr) { 2290 callback(openErr); 2291 } else { 2292 const isUserFd = false; 2293 const signal = options.signal; 2294 writeAll(fd, isUserFd, data, 0, data.byteLength, signal, callback); 2295 } 2296 }); 2297} 2298 2299/** 2300 * Synchronously writes data to the file. 2301 * @param {string | Buffer | URL | number} path 2302 * @param {string | Buffer | TypedArray | DataView | object} data 2303 * @param {{ 2304 * encoding?: string | null; 2305 * mode?: number; 2306 * flag?: string; 2307 * } | string} [options] 2308 * @returns {void} 2309 */ 2310function writeFileSync(path, data, options) { 2311 options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'w' }); 2312 2313 if (!isArrayBufferView(data)) { 2314 validateStringAfterArrayBufferView(data, 'data'); 2315 if (typeof data !== 'string') { 2316 showStringCoercionDeprecation(); 2317 } 2318 data = Buffer.from(String(data), options.encoding || 'utf8'); 2319 } 2320 2321 const flag = options.flag || 'w'; 2322 2323 const isUserFd = isFd(path); // File descriptor ownership 2324 const fd = isUserFd ? path : fs.openSync(path, flag, options.mode); 2325 2326 let offset = 0; 2327 let length = data.byteLength; 2328 try { 2329 while (length > 0) { 2330 const written = fs.writeSync(fd, data, offset, length); 2331 offset += written; 2332 length -= written; 2333 } 2334 } finally { 2335 if (!isUserFd) fs.closeSync(fd); 2336 } 2337} 2338 2339/** 2340 * Asynchronously appends data to a file. 2341 * @param {string | Buffer | URL | number} path 2342 * @param {string | Buffer} data 2343 * @param {{ 2344 * encoding?: string | null; 2345 * mode?: number; 2346 * flag?: string; 2347 * } | string} [options] 2348 * @param {(err?: Error) => any} callback 2349 * @returns {void} 2350 */ 2351function appendFile(path, data, options, callback) { 2352 callback = maybeCallback(callback || options); 2353 options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'a' }); 2354 2355 // Don't make changes directly on options object 2356 options = copyObject(options); 2357 2358 // Force append behavior when using a supplied file descriptor 2359 if (!options.flag || isFd(path)) 2360 options.flag = 'a'; 2361 2362 fs.writeFile(path, data, options, callback); 2363} 2364 2365/** 2366 * Synchronously appends data to a file. 2367 * @param {string | Buffer | URL | number} path 2368 * @param {string | Buffer} data 2369 * @param {{ 2370 * encoding?: string | null; 2371 * mode?: number; 2372 * flag?: string; 2373 * } | string} [options] 2374 * @returns {void} 2375 */ 2376function appendFileSync(path, data, options) { 2377 options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'a' }); 2378 2379 // Don't make changes directly on options object 2380 options = copyObject(options); 2381 2382 // Force append behavior when using a supplied file descriptor 2383 if (!options.flag || isFd(path)) 2384 options.flag = 'a'; 2385 2386 fs.writeFileSync(path, data, options); 2387} 2388 2389/** 2390 * Watches for the changes on `filename`. 2391 * @param {string | Buffer | URL} filename 2392 * @param {string | { 2393 * persistent?: boolean; 2394 * recursive?: boolean; 2395 * encoding?: string; 2396 * signal?: AbortSignal; 2397 * }} [options] 2398 * @param {( 2399 * eventType?: string, 2400 * filename?: string | Buffer 2401 * ) => any} [listener] 2402 * @returns {watchers.FSWatcher} 2403 */ 2404function watch(filename, options, listener) { 2405 if (typeof options === 'function') { 2406 listener = options; 2407 } 2408 options = getOptions(options); 2409 2410 // Don't make changes directly on options object 2411 options = copyObject(options); 2412 2413 if (options.persistent === undefined) options.persistent = true; 2414 if (options.recursive === undefined) options.recursive = false; 2415 if (options.recursive && !(isOSX || isWindows)) 2416 throw new ERR_FEATURE_UNAVAILABLE_ON_PLATFORM('watch recursively'); 2417 const watcher = new watchers.FSWatcher(); 2418 watcher[watchers.kFSWatchStart](filename, 2419 options.persistent, 2420 options.recursive, 2421 options.encoding); 2422 2423 if (listener) { 2424 watcher.addListener('change', listener); 2425 } 2426 if (options.signal) { 2427 if (options.signal.aborted) { 2428 process.nextTick(() => watcher.close()); 2429 } else { 2430 const listener = () => watcher.close(); 2431 options.signal.addEventListener('abort', listener); 2432 watcher.once('close', () => { 2433 options.signal.removeEventListener('abort', listener); 2434 }); 2435 } 2436 } 2437 2438 return watcher; 2439} 2440 2441 2442const statWatchers = new SafeMap(); 2443 2444/** 2445 * Watches for changes on `filename`. 2446 * @param {string | Buffer | URL} filename 2447 * @param {{ 2448 * bigint?: boolean; 2449 * persistent?: boolean; 2450 * interval?: number; 2451 * }} [options] 2452 * @param {( 2453 * current?: Stats, 2454 * previous?: Stats 2455 * ) => any} listener 2456 * @returns {watchers.StatWatcher} 2457 */ 2458function watchFile(filename, options, listener) { 2459 filename = getValidatedPath(filename); 2460 filename = pathModule.resolve(filename); 2461 let stat; 2462 2463 if (options === null || typeof options !== 'object') { 2464 listener = options; 2465 options = null; 2466 } 2467 2468 options = { 2469 // Poll interval in milliseconds. 5007 is what libev used to use. It's 2470 // a little on the slow side but let's stick with it for now to keep 2471 // behavioral changes to a minimum. 2472 interval: 5007, 2473 persistent: true, 2474 ...options, 2475 }; 2476 2477 validateFunction(listener, 'listener'); 2478 2479 stat = statWatchers.get(filename); 2480 2481 if (stat === undefined) { 2482 stat = new watchers.StatWatcher(options.bigint); 2483 stat[watchers.kFSStatWatcherStart](filename, 2484 options.persistent, options.interval); 2485 statWatchers.set(filename, stat); 2486 } else { 2487 stat[watchers.kFSStatWatcherAddOrCleanRef]('add'); 2488 } 2489 2490 stat.addListener('change', listener); 2491 return stat; 2492} 2493 2494/** 2495 * Stops watching for changes on `filename`. 2496 * @param {string | Buffer | URL} filename 2497 * @param {() => any} [listener] 2498 * @returns {void} 2499 */ 2500function unwatchFile(filename, listener) { 2501 filename = getValidatedPath(filename); 2502 filename = pathModule.resolve(filename); 2503 const stat = statWatchers.get(filename); 2504 2505 if (stat === undefined) return; 2506 2507 if (typeof listener === 'function') { 2508 const beforeListenerCount = stat.listenerCount('change'); 2509 stat.removeListener('change', listener); 2510 if (stat.listenerCount('change') < beforeListenerCount) 2511 stat[watchers.kFSStatWatcherAddOrCleanRef]('clean'); 2512 } else { 2513 stat.removeAllListeners('change'); 2514 stat[watchers.kFSStatWatcherAddOrCleanRef]('cleanAll'); 2515 } 2516 2517 if (stat.listenerCount('change') === 0) { 2518 stat.stop(); 2519 statWatchers.delete(filename); 2520 } 2521} 2522 2523 2524let splitRoot; 2525if (isWindows) { 2526 // Regex to find the device root on Windows (e.g. 'c:\\'), including trailing 2527 // slash. 2528 const splitRootRe = /^(?:[a-zA-Z]:|[\\/]{2}[^\\/]+[\\/][^\\/]+)?[\\/]*/; 2529 splitRoot = function splitRoot(str) { 2530 return SideEffectFreeRegExpPrototypeExec(splitRootRe, str)[0]; 2531 }; 2532} else { 2533 splitRoot = function splitRoot(str) { 2534 for (let i = 0; i < str.length; ++i) { 2535 if (StringPrototypeCharCodeAt(str, i) !== CHAR_FORWARD_SLASH) 2536 return StringPrototypeSlice(str, 0, i); 2537 } 2538 return str; 2539 }; 2540} 2541 2542function encodeRealpathResult(result, options) { 2543 if (!options || !options.encoding || options.encoding === 'utf8') 2544 return result; 2545 const asBuffer = Buffer.from(result); 2546 if (options.encoding === 'buffer') { 2547 return asBuffer; 2548 } 2549 return asBuffer.toString(options.encoding); 2550} 2551 2552// Finds the next portion of a (partial) path, up to the next path delimiter 2553let nextPart; 2554if (isWindows) { 2555 nextPart = function nextPart(p, i) { 2556 for (; i < p.length; ++i) { 2557 const ch = StringPrototypeCharCodeAt(p, i); 2558 2559 // Check for a separator character 2560 if (ch === CHAR_BACKWARD_SLASH || ch === CHAR_FORWARD_SLASH) 2561 return i; 2562 } 2563 return -1; 2564 }; 2565} else { 2566 nextPart = function nextPart(p, i) { 2567 return StringPrototypeIndexOf(p, '/', i); 2568 }; 2569} 2570 2571/** 2572 * Returns the resolved pathname. 2573 * @param {string | Buffer | URL} p 2574 * @param {string | { encoding?: string | null; }} [options] 2575 * @returns {string | Buffer} 2576 */ 2577function realpathSync(p, options) { 2578 options = getOptions(options); 2579 p = toPathIfFileURL(p); 2580 if (typeof p !== 'string') { 2581 p += ''; 2582 } 2583 validatePath(p); 2584 p = pathModule.resolve(p); 2585 2586 const cache = options[realpathCacheKey]; 2587 const maybeCachedResult = cache?.get(p); 2588 if (maybeCachedResult) { 2589 return maybeCachedResult; 2590 } 2591 2592 const seenLinks = new SafeMap(); 2593 const knownHard = new SafeSet(); 2594 const original = p; 2595 2596 // Current character position in p 2597 let pos; 2598 // The partial path so far, including a trailing slash if any 2599 let current; 2600 // The partial path without a trailing slash (except when pointing at a root) 2601 let base; 2602 // The partial path scanned in the previous round, with slash 2603 let previous; 2604 2605 // Skip over roots 2606 current = base = splitRoot(p); 2607 pos = current.length; 2608 2609 // On windows, check that the root exists. On unix there is no need. 2610 if (isWindows) { 2611 const ctx = { path: base }; 2612 binding.lstat(pathModule.toNamespacedPath(base), false, undefined, ctx); 2613 handleErrorFromBinding(ctx); 2614 knownHard.add(base); 2615 } 2616 2617 // Walk down the path, swapping out linked path parts for their real 2618 // values 2619 // NB: p.length changes. 2620 while (pos < p.length) { 2621 // find the next part 2622 const result = nextPart(p, pos); 2623 previous = current; 2624 if (result === -1) { 2625 const last = StringPrototypeSlice(p, pos); 2626 current += last; 2627 base = previous + last; 2628 pos = p.length; 2629 } else { 2630 current += StringPrototypeSlice(p, pos, result + 1); 2631 base = previous + StringPrototypeSlice(p, pos, result); 2632 pos = result + 1; 2633 } 2634 2635 // Continue if not a symlink, break if a pipe/socket 2636 if (knownHard.has(base) || cache?.get(base) === base) { 2637 if (isFileType(binding.statValues, S_IFIFO) || 2638 isFileType(binding.statValues, S_IFSOCK)) { 2639 break; 2640 } 2641 continue; 2642 } 2643 2644 let resolvedLink; 2645 const maybeCachedResolved = cache?.get(base); 2646 if (maybeCachedResolved) { 2647 resolvedLink = maybeCachedResolved; 2648 } else { 2649 // Use stats array directly to avoid creating an fs.Stats instance just 2650 // for our internal use. 2651 2652 const baseLong = pathModule.toNamespacedPath(base); 2653 const ctx = { path: base }; 2654 const stats = binding.lstat(baseLong, true, undefined, ctx); 2655 handleErrorFromBinding(ctx); 2656 2657 if (!isFileType(stats, S_IFLNK)) { 2658 knownHard.add(base); 2659 cache?.set(base, base); 2660 continue; 2661 } 2662 2663 // Read the link if it wasn't read before 2664 // dev/ino always return 0 on windows, so skip the check. 2665 let linkTarget = null; 2666 let id; 2667 if (!isWindows) { 2668 const dev = BigIntPrototypeToString(stats[0], 32); 2669 const ino = BigIntPrototypeToString(stats[7], 32); 2670 id = `${dev}:${ino}`; 2671 if (seenLinks.has(id)) { 2672 linkTarget = seenLinks.get(id); 2673 } 2674 } 2675 if (linkTarget === null) { 2676 const ctx = { path: base }; 2677 binding.stat(baseLong, false, undefined, ctx); 2678 handleErrorFromBinding(ctx); 2679 linkTarget = binding.readlink(baseLong, undefined, undefined, ctx); 2680 handleErrorFromBinding(ctx); 2681 } 2682 resolvedLink = pathModule.resolve(previous, linkTarget); 2683 2684 cache?.set(base, resolvedLink); 2685 if (!isWindows) seenLinks.set(id, linkTarget); 2686 } 2687 2688 // Resolve the link, then start over 2689 p = pathModule.resolve(resolvedLink, StringPrototypeSlice(p, pos)); 2690 2691 // Skip over roots 2692 current = base = splitRoot(p); 2693 pos = current.length; 2694 2695 // On windows, check that the root exists. On unix there is no need. 2696 if (isWindows && !knownHard.has(base)) { 2697 const ctx = { path: base }; 2698 binding.lstat(pathModule.toNamespacedPath(base), false, undefined, ctx); 2699 handleErrorFromBinding(ctx); 2700 knownHard.add(base); 2701 } 2702 } 2703 2704 cache?.set(original, p); 2705 return encodeRealpathResult(p, options); 2706} 2707 2708/** 2709 * Returns the resolved pathname. 2710 * @param {string | Buffer | URL} path 2711 * @param {string | { encoding?: string; }} [options] 2712 * @returns {string | Buffer} 2713 */ 2714realpathSync.native = (path, options) => { 2715 options = getOptions(options); 2716 path = getValidatedPath(path); 2717 const ctx = { path }; 2718 const result = binding.realpath(pathModule.toNamespacedPath(path), options.encoding, undefined, ctx); 2719 handleErrorFromBinding(ctx); 2720 return result; 2721}; 2722 2723/** 2724 * Asynchronously computes the canonical pathname by 2725 * resolving `.`, `..` and symbolic links. 2726 * @param {string | Buffer | URL} p 2727 * @param {string | { encoding?: string; }} [options] 2728 * @param {( 2729 * err?: Error, 2730 * resolvedPath?: string | Buffer 2731 * ) => any} callback 2732 * @returns {void} 2733 */ 2734function realpath(p, options, callback) { 2735 callback = typeof options === 'function' ? options : maybeCallback(callback); 2736 options = getOptions(options); 2737 p = toPathIfFileURL(p); 2738 2739 if (typeof p !== 'string') { 2740 p += ''; 2741 } 2742 validatePath(p); 2743 p = pathModule.resolve(p); 2744 2745 const seenLinks = new SafeMap(); 2746 const knownHard = new SafeSet(); 2747 2748 // Current character position in p 2749 let pos; 2750 // The partial path so far, including a trailing slash if any 2751 let current; 2752 // The partial path without a trailing slash (except when pointing at a root) 2753 let base; 2754 // The partial path scanned in the previous round, with slash 2755 let previous; 2756 2757 current = base = splitRoot(p); 2758 pos = current.length; 2759 2760 // On windows, check that the root exists. On unix there is no need. 2761 if (isWindows && !knownHard.has(base)) { 2762 fs.lstat(base, (err, stats) => { 2763 if (err) return callback(err); 2764 knownHard.add(base); 2765 LOOP(); 2766 }); 2767 } else { 2768 process.nextTick(LOOP); 2769 } 2770 2771 // Walk down the path, swapping out linked path parts for their real 2772 // values 2773 function LOOP() { 2774 // Stop if scanned past end of path 2775 if (pos >= p.length) { 2776 return callback(null, encodeRealpathResult(p, options)); 2777 } 2778 2779 // find the next part 2780 const result = nextPart(p, pos); 2781 previous = current; 2782 if (result === -1) { 2783 const last = StringPrototypeSlice(p, pos); 2784 current += last; 2785 base = previous + last; 2786 pos = p.length; 2787 } else { 2788 current += StringPrototypeSlice(p, pos, result + 1); 2789 base = previous + StringPrototypeSlice(p, pos, result); 2790 pos = result + 1; 2791 } 2792 2793 // Continue if not a symlink, break if a pipe/socket 2794 if (knownHard.has(base)) { 2795 if (isFileType(binding.statValues, S_IFIFO) || 2796 isFileType(binding.statValues, S_IFSOCK)) { 2797 return callback(null, encodeRealpathResult(p, options)); 2798 } 2799 return process.nextTick(LOOP); 2800 } 2801 2802 return fs.lstat(base, { bigint: true }, gotStat); 2803 } 2804 2805 function gotStat(err, stats) { 2806 if (err) return callback(err); 2807 2808 // If not a symlink, skip to the next path part 2809 if (!stats.isSymbolicLink()) { 2810 knownHard.add(base); 2811 return process.nextTick(LOOP); 2812 } 2813 2814 // Stat & read the link if not read before. 2815 // Call `gotTarget()` as soon as the link target is known. 2816 // `dev`/`ino` always return 0 on windows, so skip the check. 2817 let id; 2818 if (!isWindows) { 2819 const dev = BigIntPrototypeToString(stats.dev, 32); 2820 const ino = BigIntPrototypeToString(stats.ino, 32); 2821 id = `${dev}:${ino}`; 2822 if (seenLinks.has(id)) { 2823 return gotTarget(null, seenLinks.get(id)); 2824 } 2825 } 2826 fs.stat(base, (err) => { 2827 if (err) return callback(err); 2828 2829 fs.readlink(base, (err, target) => { 2830 if (!isWindows) seenLinks.set(id, target); 2831 gotTarget(err, target); 2832 }); 2833 }); 2834 } 2835 2836 function gotTarget(err, target) { 2837 if (err) return callback(err); 2838 2839 gotResolvedLink(pathModule.resolve(previous, target)); 2840 } 2841 2842 function gotResolvedLink(resolvedLink) { 2843 // Resolve the link, then start over 2844 p = pathModule.resolve(resolvedLink, StringPrototypeSlice(p, pos)); 2845 current = base = splitRoot(p); 2846 pos = current.length; 2847 2848 // On windows, check that the root exists. On unix there is no need. 2849 if (isWindows && !knownHard.has(base)) { 2850 fs.lstat(base, (err) => { 2851 if (err) return callback(err); 2852 knownHard.add(base); 2853 LOOP(); 2854 }); 2855 } else { 2856 process.nextTick(LOOP); 2857 } 2858 } 2859} 2860 2861/** 2862 * Asynchronously computes the canonical pathname by 2863 * resolving `.`, `..` and symbolic links. 2864 * @param {string | Buffer | URL} path 2865 * @param {string | { encoding?: string; }} [options] 2866 * @param {( 2867 * err?: Error, 2868 * resolvedPath?: string | Buffer 2869 * ) => any} callback 2870 * @returns {void} 2871 */ 2872realpath.native = (path, options, callback) => { 2873 callback = makeCallback(callback || options); 2874 options = getOptions(options); 2875 path = getValidatedPath(path); 2876 const req = new FSReqCallback(); 2877 req.oncomplete = callback; 2878 return binding.realpath(pathModule.toNamespacedPath(path), options.encoding, req); 2879}; 2880 2881/** 2882 * Creates a unique temporary directory. 2883 * @param {string} prefix 2884 * @param {string | { encoding?: string; }} [options] 2885 * @param {( 2886 * err?: Error, 2887 * directory?: string 2888 * ) => any} callback 2889 * @returns {void} 2890 */ 2891function mkdtemp(prefix, options, callback) { 2892 callback = makeCallback(typeof options === 'function' ? options : callback); 2893 options = getOptions(options); 2894 2895 validateString(prefix, 'prefix'); 2896 nullCheck(prefix, 'prefix'); 2897 warnOnNonPortableTemplate(prefix); 2898 const req = new FSReqCallback(); 2899 req.oncomplete = callback; 2900 binding.mkdtemp(`${prefix}XXXXXX`, options.encoding, req); 2901} 2902 2903/** 2904 * Synchronously creates a unique temporary directory. 2905 * @param {string} prefix 2906 * @param {string | { encoding?: string; }} [options] 2907 * @returns {string} 2908 */ 2909function mkdtempSync(prefix, options) { 2910 options = getOptions(options); 2911 2912 validateString(prefix, 'prefix'); 2913 nullCheck(prefix, 'prefix'); 2914 warnOnNonPortableTemplate(prefix); 2915 const path = `${prefix}XXXXXX`; 2916 const ctx = { path }; 2917 const result = binding.mkdtemp(path, options.encoding, 2918 undefined, ctx); 2919 handleErrorFromBinding(ctx); 2920 return result; 2921} 2922 2923/** 2924 * Asynchronously copies `src` to `dest`. By 2925 * default, `dest` is overwritten if it already exists. 2926 * @param {string | Buffer | URL} src 2927 * @param {string | Buffer | URL} dest 2928 * @param {number} [mode] 2929 * @param {() => any} callback 2930 * @returns {void} 2931 */ 2932function copyFile(src, dest, mode, callback) { 2933 if (typeof mode === 'function') { 2934 callback = mode; 2935 mode = 0; 2936 } 2937 2938 src = getValidatedPath(src, 'src'); 2939 dest = getValidatedPath(dest, 'dest'); 2940 2941 src = pathModule._makeLong(src); 2942 dest = pathModule._makeLong(dest); 2943 mode = getValidMode(mode, 'copyFile'); 2944 callback = makeCallback(callback); 2945 2946 const req = new FSReqCallback(); 2947 req.oncomplete = callback; 2948 binding.copyFile(src, dest, mode, req); 2949} 2950 2951/** 2952 * Synchronously copies `src` to `dest`. By 2953 * default, `dest` is overwritten if it already exists. 2954 * @param {string | Buffer | URL} src 2955 * @param {string | Buffer | URL} dest 2956 * @param {number} [mode] 2957 * @returns {void} 2958 */ 2959function copyFileSync(src, dest, mode) { 2960 src = getValidatedPath(src, 'src'); 2961 dest = getValidatedPath(dest, 'dest'); 2962 2963 const ctx = { path: src, dest }; // non-prefixed 2964 2965 src = pathModule._makeLong(src); 2966 dest = pathModule._makeLong(dest); 2967 mode = getValidMode(mode, 'copyFile'); 2968 binding.copyFile(src, dest, mode, undefined, ctx); 2969 handleErrorFromBinding(ctx); 2970} 2971 2972/** 2973 * Asynchronously copies `src` to `dest`. `src` can be a file, directory, or 2974 * symlink. The contents of directories will be copied recursively. 2975 * @param {string | URL} src 2976 * @param {string | URL} dest 2977 * @param {object} [options] 2978 * @param {() => any} callback 2979 * @returns {void} 2980 */ 2981function cp(src, dest, options, callback) { 2982 if (typeof options === 'function') { 2983 callback = options; 2984 options = undefined; 2985 } 2986 callback = makeCallback(callback); 2987 options = validateCpOptions(options); 2988 src = pathModule.toNamespacedPath(getValidatedPath(src, 'src')); 2989 dest = pathModule.toNamespacedPath(getValidatedPath(dest, 'dest')); 2990 lazyLoadCp(); 2991 cpFn(src, dest, options, callback); 2992} 2993 2994/** 2995 * Synchronously copies `src` to `dest`. `src` can be a file, directory, or 2996 * symlink. The contents of directories will be copied recursively. 2997 * @param {string | URL} src 2998 * @param {string | URL} dest 2999 * @param {object} [options] 3000 * @returns {void} 3001 */ 3002function cpSync(src, dest, options) { 3003 options = validateCpOptions(options); 3004 src = pathModule.toNamespacedPath(getValidatedPath(src, 'src')); 3005 dest = pathModule.toNamespacedPath(getValidatedPath(dest, 'dest')); 3006 lazyLoadCp(); 3007 cpSyncFn(src, dest, options); 3008} 3009 3010function lazyLoadStreams() { 3011 if (!ReadStream) { 3012 ({ ReadStream, WriteStream } = require('internal/fs/streams')); 3013 FileReadStream = ReadStream; 3014 FileWriteStream = WriteStream; 3015 } 3016} 3017 3018/** 3019 * Creates a readable stream with a default `highWaterMark` 3020 * of 64 KiB. 3021 * @param {string | Buffer | URL} path 3022 * @param {string | { 3023 * flags?: string; 3024 * encoding?: string; 3025 * fd?: number | FileHandle; 3026 * mode?: number; 3027 * autoClose?: boolean; 3028 * emitClose?: boolean; 3029 * start: number; 3030 * end?: number; 3031 * highWaterMark?: number; 3032 * fs?: object | null; 3033 * }} [options] 3034 * @returns {ReadStream} 3035 */ 3036function createReadStream(path, options) { 3037 lazyLoadStreams(); 3038 return new ReadStream(path, options); 3039} 3040 3041/** 3042 * Creates a write stream. 3043 * @param {string | Buffer | URL} path 3044 * @param {string | { 3045 * flags?: string; 3046 * encoding?: string; 3047 * fd?: number | FileHandle; 3048 * mode?: number; 3049 * autoClose?: boolean; 3050 * emitClose?: boolean; 3051 * start: number; 3052 * fs?: object | null; 3053 * }} [options] 3054 * @returns {WriteStream} 3055 */ 3056function createWriteStream(path, options) { 3057 lazyLoadStreams(); 3058 return new WriteStream(path, options); 3059} 3060 3061module.exports = fs = { 3062 appendFile, 3063 appendFileSync, 3064 access, 3065 accessSync, 3066 chown, 3067 chownSync, 3068 chmod, 3069 chmodSync, 3070 close, 3071 closeSync, 3072 copyFile, 3073 copyFileSync, 3074 cp, 3075 cpSync, 3076 createReadStream, 3077 createWriteStream, 3078 exists, 3079 existsSync, 3080 fchown, 3081 fchownSync, 3082 fchmod, 3083 fchmodSync, 3084 fdatasync, 3085 fdatasyncSync, 3086 fstat, 3087 fstatSync, 3088 fsync, 3089 fsyncSync, 3090 ftruncate, 3091 ftruncateSync, 3092 futimes, 3093 futimesSync, 3094 lchown, 3095 lchownSync, 3096 lchmod: constants.O_SYMLINK !== undefined ? lchmod : undefined, 3097 lchmodSync: constants.O_SYMLINK !== undefined ? lchmodSync : undefined, 3098 link, 3099 linkSync, 3100 lstat, 3101 lstatSync, 3102 lutimes, 3103 lutimesSync, 3104 mkdir, 3105 mkdirSync, 3106 mkdtemp, 3107 mkdtempSync, 3108 open, 3109 openSync, 3110 opendir, 3111 opendirSync, 3112 readdir, 3113 readdirSync, 3114 read, 3115 readSync, 3116 readv, 3117 readvSync, 3118 readFile, 3119 readFileSync, 3120 readlink, 3121 readlinkSync, 3122 realpath, 3123 realpathSync, 3124 rename, 3125 renameSync, 3126 rm, 3127 rmSync, 3128 rmdir, 3129 rmdirSync, 3130 stat, 3131 statfs, 3132 statSync, 3133 statfsSync, 3134 symlink, 3135 symlinkSync, 3136 truncate, 3137 truncateSync, 3138 unwatchFile, 3139 unlink, 3140 unlinkSync, 3141 utimes, 3142 utimesSync, 3143 watch, 3144 watchFile, 3145 writeFile, 3146 writeFileSync, 3147 write, 3148 writeSync, 3149 writev, 3150 writevSync, 3151 Dir, 3152 Dirent, 3153 Stats, 3154 3155 get ReadStream() { 3156 lazyLoadStreams(); 3157 return ReadStream; 3158 }, 3159 3160 set ReadStream(val) { 3161 ReadStream = val; 3162 }, 3163 3164 get WriteStream() { 3165 lazyLoadStreams(); 3166 return WriteStream; 3167 }, 3168 3169 set WriteStream(val) { 3170 WriteStream = val; 3171 }, 3172 3173 // Legacy names... these have to be separate because of how graceful-fs 3174 // (and possibly other) modules monkey patch the values. 3175 get FileReadStream() { 3176 lazyLoadStreams(); 3177 return FileReadStream; 3178 }, 3179 3180 set FileReadStream(val) { 3181 FileReadStream = val; 3182 }, 3183 3184 get FileWriteStream() { 3185 lazyLoadStreams(); 3186 return FileWriteStream; 3187 }, 3188 3189 set FileWriteStream(val) { 3190 FileWriteStream = val; 3191 }, 3192 3193 // For tests 3194 _toUnixTimestamp: toUnixTimestamp, 3195}; 3196 3197ObjectDefineProperties(fs, { 3198 F_OK: { __proto__: null, enumerable: true, value: F_OK || 0 }, 3199 R_OK: { __proto__: null, enumerable: true, value: R_OK || 0 }, 3200 W_OK: { __proto__: null, enumerable: true, value: W_OK || 0 }, 3201 X_OK: { __proto__: null, enumerable: true, value: X_OK || 0 }, 3202 constants: { 3203 __proto__: null, 3204 configurable: false, 3205 enumerable: true, 3206 value: constants, 3207 }, 3208 promises: { 3209 __proto__: null, 3210 configurable: true, 3211 enumerable: true, 3212 get() { 3213 promises ??= require('internal/fs/promises').exports; 3214 return promises; 3215 }, 3216 }, 3217}); 3218