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 defineLazyProperties, 91} = require('internal/util'); 92const { 93 constants: { 94 kIoMaxLength, 95 kMaxUserId, 96 }, 97 copyObject, 98 Dirent, 99 emitRecursiveRmdirWarning, 100 getDirent, 101 getDirents, 102 getOptions, 103 getValidatedFd, 104 getValidatedPath, 105 getValidMode, 106 handleErrorFromBinding, 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 CHAR_FORWARD_SLASH, 130 CHAR_BACKWARD_SLASH, 131} = require('internal/constants'); 132const { 133 isUint32, 134 parseFileMode, 135 validateBoolean, 136 validateBuffer, 137 validateEncoding, 138 validateFunction, 139 validateInteger, 140 validateObject, 141} = require('internal/validators'); 142 143let truncateWarn = true; 144let fs; 145 146// Lazy loaded 147let cpFn; 148let cpSyncFn; 149let promises = null; 150let ReadStream; 151let WriteStream; 152let rimraf; 153let rimrafSync; 154let kResistStopPropagation; 155 156// These have to be separate because of how graceful-fs happens to do it's 157// monkeypatching. 158let FileReadStream; 159let FileWriteStream; 160 161const isWindows = process.platform === 'win32'; 162const isOSX = process.platform === 'darwin'; 163 164 165const showStringCoercionDeprecation = deprecate( 166 () => {}, 167 'Implicit coercion of objects with own toString property is deprecated.', 168 'DEP0162', 169); 170function showTruncateDeprecation() { 171 if (truncateWarn) { 172 process.emitWarning( 173 'Using fs.truncate with a file descriptor is deprecated. Please use ' + 174 'fs.ftruncate with a file descriptor instead.', 175 'DeprecationWarning', 'DEP0081'); 176 truncateWarn = false; 177 } 178} 179 180function maybeCallback(cb) { 181 validateFunction(cb, 'cb'); 182 183 return cb; 184} 185 186// Ensure that callbacks run in the global context. Only use this function 187// for callbacks that are passed to the binding layer, callbacks that are 188// invoked from JS already run in the proper scope. 189function makeCallback(cb) { 190 validateFunction(cb, 'cb'); 191 192 return (...args) => ReflectApply(cb, this, args); 193} 194 195// Special case of `makeCallback()` that is specific to async `*stat()` calls as 196// an optimization, since the data passed back to the callback needs to be 197// transformed anyway. 198function makeStatsCallback(cb) { 199 validateFunction(cb, 'cb'); 200 201 return (err, stats) => { 202 if (err) return cb(err); 203 cb(err, getStatsFromBinding(stats)); 204 }; 205} 206 207const isFd = isUint32; 208 209function isFileType(stats, fileType) { 210 // Use stats array directly to avoid creating an fs.Stats instance just for 211 // our internal use. 212 let mode = stats[1]; 213 if (typeof mode === 'bigint') 214 mode = Number(mode); 215 return (mode & S_IFMT) === fileType; 216} 217 218/** 219 * Tests a user's permissions for the file or directory 220 * specified by `path`. 221 * @param {string | Buffer | URL} path 222 * @param {number} [mode] 223 * @param {(err?: Error) => any} callback 224 * @returns {void} 225 */ 226function access(path, mode, callback) { 227 if (typeof mode === 'function') { 228 callback = mode; 229 mode = F_OK; 230 } 231 232 path = getValidatedPath(path); 233 mode = getValidMode(mode, 'access'); 234 callback = makeCallback(callback); 235 236 const req = new FSReqCallback(); 237 req.oncomplete = callback; 238 binding.access(pathModule.toNamespacedPath(path), mode, req); 239} 240 241/** 242 * Synchronously tests a user's permissions for the file or 243 * directory specified by `path`. 244 * @param {string | Buffer | URL} path 245 * @param {number} [mode] 246 * @returns {void} 247 */ 248function accessSync(path, mode) { 249 path = getValidatedPath(path); 250 mode = getValidMode(mode, 'access'); 251 252 const ctx = { path }; 253 binding.access(pathModule.toNamespacedPath(path), mode, undefined, ctx); 254 handleErrorFromBinding(ctx); 255} 256 257/** 258 * Tests whether or not the given path exists. 259 * @param {string | Buffer | URL} path 260 * @param {(exists?: boolean) => any} callback 261 * @returns {void} 262 */ 263function exists(path, callback) { 264 maybeCallback(callback); 265 266 function suppressedCallback(err) { 267 callback(err ? false : true); 268 } 269 270 try { 271 fs.access(path, F_OK, suppressedCallback); 272 } catch { 273 return callback(false); 274 } 275} 276 277ObjectDefineProperty(exists, kCustomPromisifiedSymbol, { 278 __proto__: null, 279 value: function exists(path) { // eslint-disable-line func-name-matching 280 return new Promise((resolve) => fs.exists(path, resolve)); 281 }, 282}); 283 284// fs.existsSync never throws, it only returns true or false. 285// Since fs.existsSync never throws, users have established 286// the expectation that passing invalid arguments to it, even like 287// fs.existsSync(), would only get a false in return, so we cannot signal 288// validation errors to users properly out of compatibility concerns. 289// TODO(joyeecheung): deprecate the never-throw-on-invalid-arguments behavior 290/** 291 * Synchronously tests whether or not the given path exists. 292 * @param {string | Buffer | URL} path 293 * @returns {boolean} 294 */ 295function existsSync(path) { 296 try { 297 path = getValidatedPath(path); 298 } catch { 299 return false; 300 } 301 const ctx = { path }; 302 const nPath = pathModule.toNamespacedPath(path); 303 binding.access(nPath, F_OK, undefined, ctx); 304 305 // In case of an invalid symlink, `binding.access()` on win32 306 // will **not** return an error and is therefore not enough. 307 // Double check with `binding.stat()`. 308 if (isWindows && ctx.errno === undefined) { 309 binding.stat(nPath, false, undefined, ctx); 310 } 311 312 return ctx.errno === undefined; 313} 314 315function readFileAfterOpen(err, fd) { 316 const context = this.context; 317 318 if (err) { 319 context.callback(err); 320 return; 321 } 322 323 context.fd = fd; 324 325 const req = new FSReqCallback(); 326 req.oncomplete = readFileAfterStat; 327 req.context = context; 328 binding.fstat(fd, false, req); 329} 330 331function readFileAfterStat(err, stats) { 332 const context = this.context; 333 334 if (err) 335 return context.close(err); 336 337 // TODO(BridgeAR): Check if allocating a smaller chunk is better performance 338 // wise, similar to the promise based version (less peak memory and chunked 339 // stringify operations vs multiple C++/JS boundary crossings). 340 const size = context.size = isFileType(stats, S_IFREG) ? stats[8] : 0; 341 342 if (size > kIoMaxLength) { 343 err = new ERR_FS_FILE_TOO_LARGE(size); 344 return context.close(err); 345 } 346 347 try { 348 if (size === 0) { 349 // TODO(BridgeAR): If an encoding is set, use the StringDecoder to concat 350 // the result and reuse the buffer instead of allocating a new one. 351 context.buffers = []; 352 } else { 353 context.buffer = Buffer.allocUnsafeSlow(size); 354 } 355 } catch (err) { 356 return context.close(err); 357 } 358 context.read(); 359} 360 361function checkAborted(signal, callback) { 362 if (signal?.aborted) { 363 callback(new AbortError(undefined, { cause: signal?.reason })); 364 return true; 365 } 366 return false; 367} 368 369/** 370 * Asynchronously reads the entire contents of a file. 371 * @param {string | Buffer | URL | number} path 372 * @param {{ 373 * encoding?: string | null; 374 * flag?: string; 375 * signal?: AbortSignal; 376 * } | string} [options] 377 * @param {( 378 * err?: Error, 379 * data?: string | Buffer 380 * ) => any} callback 381 * @returns {void} 382 */ 383function readFile(path, options, callback) { 384 callback = maybeCallback(callback || options); 385 options = getOptions(options, { flag: 'r' }); 386 const ReadFileContext = require('internal/fs/read_file_context'); 387 const context = new ReadFileContext(callback, options.encoding); 388 context.isUserFd = isFd(path); // File descriptor ownership 389 390 if (options.signal) { 391 context.signal = options.signal; 392 } 393 if (context.isUserFd) { 394 process.nextTick(function tick(context) { 395 ReflectApply(readFileAfterOpen, { context }, [null, path]); 396 }, context); 397 return; 398 } 399 400 if (checkAborted(options.signal, callback)) 401 return; 402 403 const flagsNumber = stringToFlags(options.flag, 'options.flag'); 404 path = getValidatedPath(path); 405 406 const req = new FSReqCallback(); 407 req.context = context; 408 req.oncomplete = readFileAfterOpen; 409 binding.open(pathModule.toNamespacedPath(path), 410 flagsNumber, 411 0o666, 412 req); 413} 414 415function tryStatSync(fd, isUserFd) { 416 const ctx = {}; 417 const stats = binding.fstat(fd, false, undefined, ctx); 418 if (ctx.errno !== undefined && !isUserFd) { 419 fs.closeSync(fd); 420 throw uvException(ctx); 421 } 422 return stats; 423} 424 425function tryCreateBuffer(size, fd, isUserFd) { 426 let threw = true; 427 let buffer; 428 try { 429 if (size > kIoMaxLength) { 430 throw new ERR_FS_FILE_TOO_LARGE(size); 431 } 432 buffer = Buffer.allocUnsafe(size); 433 threw = false; 434 } finally { 435 if (threw && !isUserFd) fs.closeSync(fd); 436 } 437 return buffer; 438} 439 440function tryReadSync(fd, isUserFd, buffer, pos, len) { 441 let threw = true; 442 let bytesRead; 443 try { 444 bytesRead = fs.readSync(fd, buffer, pos, len); 445 threw = false; 446 } finally { 447 if (threw && !isUserFd) fs.closeSync(fd); 448 } 449 return bytesRead; 450} 451 452/** 453 * Synchronously reads the entire contents of a file. 454 * @param {string | Buffer | URL | number} path 455 * @param {{ 456 * encoding?: string | null; 457 * flag?: string; 458 * }} [options] 459 * @returns {string | Buffer} 460 */ 461function readFileSync(path, options) { 462 options = getOptions(options, { flag: 'r' }); 463 const isUserFd = isFd(path); // File descriptor ownership 464 const fd = isUserFd ? path : fs.openSync(path, options.flag, 0o666); 465 466 const stats = tryStatSync(fd, isUserFd); 467 const size = isFileType(stats, S_IFREG) ? stats[8] : 0; 468 let pos = 0; 469 let buffer; // Single buffer with file data 470 let buffers; // List for when size is unknown 471 472 if (size === 0) { 473 buffers = []; 474 } else { 475 buffer = tryCreateBuffer(size, fd, isUserFd); 476 } 477 478 let bytesRead; 479 480 if (size !== 0) { 481 do { 482 bytesRead = tryReadSync(fd, isUserFd, buffer, pos, size - pos); 483 pos += bytesRead; 484 } while (bytesRead !== 0 && pos < size); 485 } else { 486 do { 487 // The kernel lies about many files. 488 // Go ahead and try to read some bytes. 489 buffer = Buffer.allocUnsafe(8192); 490 bytesRead = tryReadSync(fd, isUserFd, buffer, 0, 8192); 491 if (bytesRead !== 0) { 492 ArrayPrototypePush(buffers, buffer.slice(0, bytesRead)); 493 } 494 pos += bytesRead; 495 } while (bytesRead !== 0); 496 } 497 498 if (!isUserFd) 499 fs.closeSync(fd); 500 501 if (size === 0) { 502 // Data was collected into the buffers list. 503 buffer = Buffer.concat(buffers, pos); 504 } else if (pos < size) { 505 buffer = buffer.slice(0, pos); 506 } 507 508 if (options.encoding) buffer = buffer.toString(options.encoding); 509 return buffer; 510} 511 512function defaultCloseCallback(err) { 513 if (err != null) throw err; 514} 515 516/** 517 * Closes the file descriptor. 518 * @param {number} fd 519 * @param {(err?: Error) => any} [callback] 520 * @returns {void} 521 */ 522function close(fd, callback = defaultCloseCallback) { 523 fd = getValidatedFd(fd); 524 if (callback !== defaultCloseCallback) 525 callback = makeCallback(callback); 526 527 const req = new FSReqCallback(); 528 req.oncomplete = callback; 529 binding.close(fd, req); 530} 531 532/** 533 * Synchronously closes the file descriptor. 534 * @param {number} fd 535 * @returns {void} 536 */ 537function closeSync(fd) { 538 fd = getValidatedFd(fd); 539 540 const ctx = {}; 541 binding.close(fd, undefined, ctx); 542 handleErrorFromBinding(ctx); 543} 544 545/** 546 * Asynchronously opens a file. 547 * @param {string | Buffer | URL} path 548 * @param {string | number} [flags] 549 * @param {string | number} [mode] 550 * @param {( 551 * err?: Error, 552 * fd?: number 553 * ) => any} callback 554 * @returns {void} 555 */ 556function open(path, flags, mode, callback) { 557 path = getValidatedPath(path); 558 if (arguments.length < 3) { 559 callback = flags; 560 flags = 'r'; 561 mode = 0o666; 562 } else if (typeof mode === 'function') { 563 callback = mode; 564 mode = 0o666; 565 } else { 566 mode = parseFileMode(mode, 'mode', 0o666); 567 } 568 const flagsNumber = stringToFlags(flags); 569 callback = makeCallback(callback); 570 571 const req = new FSReqCallback(); 572 req.oncomplete = callback; 573 574 binding.open(pathModule.toNamespacedPath(path), 575 flagsNumber, 576 mode, 577 req); 578} 579 580/** 581 * Synchronously opens a file. 582 * @param {string | Buffer | URL} path 583 * @param {string | number} [flags] 584 * @param {string | number} [mode] 585 * @returns {number} 586 */ 587function openSync(path, flags, mode) { 588 path = getValidatedPath(path); 589 const flagsNumber = stringToFlags(flags); 590 mode = parseFileMode(mode, 'mode', 0o666); 591 592 const ctx = { path }; 593 const result = binding.open(pathModule.toNamespacedPath(path), 594 flagsNumber, mode, 595 undefined, ctx); 596 handleErrorFromBinding(ctx); 597 return result; 598} 599 600/** 601 * Reads file from the specified `fd` (file descriptor). 602 * @param {number} fd 603 * @param {Buffer | TypedArray | DataView} buffer 604 * @param {number} offsetOrOptions 605 * @param {number} length 606 * @param {number | bigint | null} position 607 * @param {( 608 * err?: Error, 609 * bytesRead?: number, 610 * buffer?: Buffer 611 * ) => any} callback 612 * @returns {void} 613 */ 614function read(fd, buffer, offsetOrOptions, length, position, callback) { 615 fd = getValidatedFd(fd); 616 617 let offset = offsetOrOptions; 618 let params = null; 619 if (arguments.length <= 4) { 620 if (arguments.length === 4) { 621 // This is fs.read(fd, buffer, options, callback) 622 validateObject(offsetOrOptions, 'options', { nullable: true }); 623 callback = length; 624 params = offsetOrOptions; 625 } else if (arguments.length === 3) { 626 // This is fs.read(fd, bufferOrParams, callback) 627 if (!isArrayBufferView(buffer)) { 628 // This is fs.read(fd, params, callback) 629 params = buffer; 630 ({ buffer = Buffer.alloc(16384) } = params ?? kEmptyObject); 631 } 632 callback = offsetOrOptions; 633 } else { 634 // This is fs.read(fd, callback) 635 callback = buffer; 636 buffer = Buffer.alloc(16384); 637 } 638 639 ({ 640 offset = 0, 641 length = buffer.byteLength - offset, 642 position = null, 643 } = params ?? kEmptyObject); 644 } 645 646 validateBuffer(buffer); 647 callback = maybeCallback(callback); 648 649 if (offset == null) { 650 offset = 0; 651 } else { 652 validateInteger(offset, 'offset', 0); 653 } 654 655 length |= 0; 656 657 if (length === 0) { 658 return process.nextTick(function tick() { 659 callback(null, 0, buffer); 660 }); 661 } 662 663 if (buffer.byteLength === 0) { 664 throw new ERR_INVALID_ARG_VALUE('buffer', buffer, 665 'is empty and cannot be written'); 666 } 667 668 validateOffsetLengthRead(offset, length, buffer.byteLength); 669 670 if (position == null) 671 position = -1; 672 673 validatePosition(position, 'position'); 674 675 function wrapper(err, bytesRead) { 676 // Retain a reference to buffer so that it can't be GC'ed too soon. 677 callback(err, bytesRead || 0, buffer); 678 } 679 680 const req = new FSReqCallback(); 681 req.oncomplete = wrapper; 682 683 binding.read(fd, buffer, offset, length, position, req); 684} 685 686ObjectDefineProperty(read, kCustomPromisifyArgsSymbol, 687 { __proto__: null, value: ['bytesRead', 'buffer'], enumerable: false }); 688 689/** 690 * Synchronously reads the file from the 691 * specified `fd` (file descriptor). 692 * @param {number} fd 693 * @param {Buffer | TypedArray | DataView} buffer 694 * @param {{ 695 * offset?: number; 696 * length?: number; 697 * position?: number | bigint | null; 698 * }} [offset] 699 * @returns {number} 700 */ 701function readSync(fd, buffer, offset, length, position) { 702 fd = getValidatedFd(fd); 703 704 validateBuffer(buffer); 705 706 if (arguments.length <= 3) { 707 // Assume fs.readSync(fd, buffer, options) 708 const options = offset || kEmptyObject; 709 710 ({ 711 offset = 0, 712 length = buffer.byteLength - offset, 713 position = null, 714 } = options); 715 } 716 717 if (offset == null) { 718 offset = 0; 719 } else { 720 validateInteger(offset, 'offset', 0); 721 } 722 723 length |= 0; 724 725 if (length === 0) { 726 return 0; 727 } 728 729 if (buffer.byteLength === 0) { 730 throw new ERR_INVALID_ARG_VALUE('buffer', buffer, 731 'is empty and cannot be written'); 732 } 733 734 validateOffsetLengthRead(offset, length, buffer.byteLength); 735 736 if (position == null) 737 position = -1; 738 739 validatePosition(position, 'position'); 740 741 const ctx = {}; 742 const result = binding.read(fd, buffer, offset, length, position, 743 undefined, ctx); 744 handleErrorFromBinding(ctx); 745 return result; 746} 747 748/** 749 * Reads file from the specified `fd` (file descriptor) 750 * and writes to an array of `ArrayBufferView`s. 751 * @param {number} fd 752 * @param {ArrayBufferView[]} buffers 753 * @param {number | null} [position] 754 * @param {( 755 * err?: Error, 756 * bytesRead?: number, 757 * buffers?: ArrayBufferView[]; 758 * ) => any} callback 759 * @returns {void} 760 */ 761function readv(fd, buffers, position, callback) { 762 function wrapper(err, read) { 763 callback(err, read || 0, buffers); 764 } 765 766 fd = getValidatedFd(fd); 767 validateBufferArray(buffers); 768 callback = maybeCallback(callback || position); 769 770 const req = new FSReqCallback(); 771 req.oncomplete = wrapper; 772 773 if (typeof position !== 'number') 774 position = null; 775 776 return binding.readBuffers(fd, buffers, position, req); 777} 778 779ObjectDefineProperty(readv, kCustomPromisifyArgsSymbol, 780 { __proto__: null, value: ['bytesRead', 'buffers'], enumerable: false }); 781 782/** 783 * Synchronously reads file from the 784 * specified `fd` (file descriptor) and writes to an array 785 * of `ArrayBufferView`s. 786 * @param {number} fd 787 * @param {ArrayBufferView[]} buffers 788 * @param {number | null} [position] 789 * @returns {number} 790 */ 791function readvSync(fd, buffers, position) { 792 fd = getValidatedFd(fd); 793 validateBufferArray(buffers); 794 795 const ctx = {}; 796 797 if (typeof position !== 'number') 798 position = null; 799 800 const result = binding.readBuffers(fd, buffers, position, undefined, ctx); 801 handleErrorFromBinding(ctx); 802 return result; 803} 804 805/** 806 * Writes `buffer` to the specified `fd` (file descriptor). 807 * @param {number} fd 808 * @param {Buffer | TypedArray | DataView | string | object} buffer 809 * @param {number | object} [offsetOrOptions] 810 * @param {number} [length] 811 * @param {number | null} [position] 812 * @param {( 813 * err?: Error, 814 * bytesWritten?: number; 815 * buffer?: Buffer | TypedArray | DataView 816 * ) => any} callback 817 * @returns {void} 818 */ 819function write(fd, buffer, offsetOrOptions, length, position, callback) { 820 function wrapper(err, written) { 821 // Retain a reference to buffer so that it can't be GC'ed too soon. 822 callback(err, written || 0, buffer); 823 } 824 825 fd = getValidatedFd(fd); 826 827 let offset = offsetOrOptions; 828 if (isArrayBufferView(buffer)) { 829 callback = maybeCallback(callback || position || length || offset); 830 831 if (typeof offset === 'object') { 832 ({ 833 offset = 0, 834 length = buffer.byteLength - offset, 835 position = null, 836 } = offsetOrOptions ?? kEmptyObject); 837 } 838 839 if (offset == null || typeof offset === 'function') { 840 offset = 0; 841 } else { 842 validateInteger(offset, 'offset', 0); 843 } 844 if (typeof length !== 'number') 845 length = buffer.byteLength - offset; 846 if (typeof position !== 'number') 847 position = null; 848 validateOffsetLengthWrite(offset, length, buffer.byteLength); 849 850 const req = new FSReqCallback(); 851 req.oncomplete = wrapper; 852 return binding.writeBuffer(fd, buffer, offset, length, position, req); 853 } 854 855 validateStringAfterArrayBufferView(buffer, 'buffer'); 856 if (typeof buffer !== 'string') { 857 showStringCoercionDeprecation(); 858 } 859 860 if (typeof position !== 'function') { 861 if (typeof offset === 'function') { 862 position = offset; 863 offset = null; 864 } else { 865 position = length; 866 } 867 length = 'utf8'; 868 } 869 870 const str = String(buffer); 871 validateEncoding(str, length); 872 callback = maybeCallback(position); 873 874 const req = new FSReqCallback(); 875 req.oncomplete = wrapper; 876 return binding.writeString(fd, str, offset, length, req); 877} 878 879ObjectDefineProperty(write, kCustomPromisifyArgsSymbol, 880 { __proto__: null, value: ['bytesWritten', 'buffer'], enumerable: false }); 881 882/** 883 * Synchronously writes `buffer` to the 884 * specified `fd` (file descriptor). 885 * @param {number} fd 886 * @param {Buffer | TypedArray | DataView | string} buffer 887 * @param {{ 888 * offset?: number; 889 * length?: number; 890 * position?: number | null; 891 * }} [offsetOrOptions] 892 * @returns {number} 893 */ 894function writeSync(fd, buffer, offsetOrOptions, length, position) { 895 fd = getValidatedFd(fd); 896 const ctx = {}; 897 let result; 898 899 let offset = offsetOrOptions; 900 if (isArrayBufferView(buffer)) { 901 if (typeof offset === 'object') { 902 ({ 903 offset = 0, 904 length = buffer.byteLength - offset, 905 position = null, 906 } = offsetOrOptions ?? kEmptyObject); 907 } 908 if (position === undefined) 909 position = null; 910 if (offset == null) { 911 offset = 0; 912 } else { 913 validateInteger(offset, 'offset', 0); 914 } 915 if (typeof length !== 'number') 916 length = buffer.byteLength - offset; 917 validateOffsetLengthWrite(offset, length, buffer.byteLength); 918 result = binding.writeBuffer(fd, buffer, offset, length, position, 919 undefined, ctx); 920 } else { 921 validatePrimitiveStringAfterArrayBufferView(buffer, 'buffer'); 922 validateEncoding(buffer, length); 923 924 if (offset === undefined) 925 offset = null; 926 result = binding.writeString(fd, buffer, offset, length, 927 undefined, ctx); 928 } 929 handleErrorFromBinding(ctx); 930 return result; 931} 932 933/** 934 * Writes an array of `ArrayBufferView`s to the 935 * specified `fd` (file descriptor). 936 * @param {number} fd 937 * @param {ArrayBufferView[]} buffers 938 * @param {number | null} [position] 939 * @param {( 940 * err?: Error, 941 * bytesWritten?: number, 942 * buffers?: ArrayBufferView[] 943 * ) => any} callback 944 * @returns {void} 945 */ 946function writev(fd, buffers, position, callback) { 947 function wrapper(err, written) { 948 callback(err, written || 0, buffers); 949 } 950 951 fd = getValidatedFd(fd); 952 validateBufferArray(buffers); 953 callback = maybeCallback(callback || position); 954 955 if (buffers.length === 0) { 956 process.nextTick(callback, null, 0, buffers); 957 return; 958 } 959 960 const req = new FSReqCallback(); 961 req.oncomplete = wrapper; 962 963 if (typeof position !== 'number') 964 position = null; 965 966 return binding.writeBuffers(fd, buffers, position, req); 967} 968 969ObjectDefineProperty(writev, kCustomPromisifyArgsSymbol, { 970 __proto__: null, 971 value: ['bytesWritten', 'buffer'], 972 enumerable: false, 973}); 974 975/** 976 * Synchronously writes an array of `ArrayBufferView`s 977 * to the specified `fd` (file descriptor). 978 * @param {number} fd 979 * @param {ArrayBufferView[]} buffers 980 * @param {number | null} [position] 981 * @returns {number} 982 */ 983function writevSync(fd, buffers, position) { 984 fd = getValidatedFd(fd); 985 validateBufferArray(buffers); 986 987 if (buffers.length === 0) { 988 return 0; 989 } 990 991 const ctx = {}; 992 993 if (typeof position !== 'number') 994 position = null; 995 996 const result = binding.writeBuffers(fd, buffers, position, undefined, ctx); 997 998 handleErrorFromBinding(ctx); 999 return result; 1000} 1001 1002/** 1003 * Asynchronously renames file at `oldPath` to 1004 * the pathname provided as `newPath`. 1005 * @param {string | Buffer | URL} oldPath 1006 * @param {string | Buffer | URL} newPath 1007 * @param {(err?: Error) => any} callback 1008 * @returns {void} 1009 */ 1010function rename(oldPath, newPath, callback) { 1011 callback = makeCallback(callback); 1012 oldPath = getValidatedPath(oldPath, 'oldPath'); 1013 newPath = getValidatedPath(newPath, 'newPath'); 1014 const req = new FSReqCallback(); 1015 req.oncomplete = callback; 1016 binding.rename(pathModule.toNamespacedPath(oldPath), 1017 pathModule.toNamespacedPath(newPath), 1018 req); 1019} 1020 1021 1022/** 1023 * Synchronously renames file at `oldPath` to 1024 * the pathname provided as `newPath`. 1025 * @param {string | Buffer | URL} oldPath 1026 * @param {string | Buffer | URL} newPath 1027 * @returns {void} 1028 */ 1029function renameSync(oldPath, newPath) { 1030 oldPath = getValidatedPath(oldPath, 'oldPath'); 1031 newPath = getValidatedPath(newPath, 'newPath'); 1032 const ctx = { path: oldPath, dest: newPath }; 1033 binding.rename(pathModule.toNamespacedPath(oldPath), 1034 pathModule.toNamespacedPath(newPath), undefined, ctx); 1035 handleErrorFromBinding(ctx); 1036} 1037 1038/** 1039 * Truncates the file. 1040 * @param {string | Buffer | URL} path 1041 * @param {number} [len] 1042 * @param {(err?: Error) => any} callback 1043 * @returns {void} 1044 */ 1045function truncate(path, len, callback) { 1046 if (typeof path === 'number') { 1047 showTruncateDeprecation(); 1048 return fs.ftruncate(path, len, callback); 1049 } 1050 if (typeof len === 'function') { 1051 callback = len; 1052 len = 0; 1053 } else if (len === undefined) { 1054 len = 0; 1055 } 1056 1057 validateInteger(len, 'len'); 1058 len = MathMax(0, len); 1059 callback = maybeCallback(callback); 1060 fs.open(path, 'r+', (er, fd) => { 1061 if (er) return callback(er); 1062 const req = new FSReqCallback(); 1063 req.oncomplete = function oncomplete(er) { 1064 fs.close(fd, (er2) => { 1065 callback(aggregateTwoErrors(er2, er)); 1066 }); 1067 }; 1068 binding.ftruncate(fd, len, req); 1069 }); 1070} 1071 1072/** 1073 * Synchronously truncates the file. 1074 * @param {string | Buffer | URL} path 1075 * @param {number} [len] 1076 * @returns {void} 1077 */ 1078function truncateSync(path, len) { 1079 if (typeof path === 'number') { 1080 // legacy 1081 showTruncateDeprecation(); 1082 return fs.ftruncateSync(path, len); 1083 } 1084 if (len === undefined) { 1085 len = 0; 1086 } 1087 // Allow error to be thrown, but still close fd. 1088 const fd = fs.openSync(path, 'r+'); 1089 let ret; 1090 1091 try { 1092 ret = fs.ftruncateSync(fd, len); 1093 } finally { 1094 fs.closeSync(fd); 1095 } 1096 return ret; 1097} 1098 1099/** 1100 * Truncates the file descriptor. 1101 * @param {number} fd 1102 * @param {number} [len] 1103 * @param {(err?: Error) => any} callback 1104 * @returns {void} 1105 */ 1106function ftruncate(fd, len = 0, callback) { 1107 if (typeof len === 'function') { 1108 callback = len; 1109 len = 0; 1110 } 1111 fd = getValidatedFd(fd); 1112 validateInteger(len, 'len'); 1113 len = MathMax(0, len); 1114 callback = makeCallback(callback); 1115 1116 const req = new FSReqCallback(); 1117 req.oncomplete = callback; 1118 binding.ftruncate(fd, len, req); 1119} 1120 1121/** 1122 * Synchronously truncates the file descriptor. 1123 * @param {number} fd 1124 * @param {number} [len] 1125 * @returns {void} 1126 */ 1127function ftruncateSync(fd, len = 0) { 1128 fd = getValidatedFd(fd); 1129 validateInteger(len, 'len'); 1130 len = MathMax(0, len); 1131 const ctx = {}; 1132 binding.ftruncate(fd, len, undefined, ctx); 1133 handleErrorFromBinding(ctx); 1134} 1135 1136function lazyLoadCp() { 1137 if (cpFn === undefined) { 1138 ({ cpFn } = require('internal/fs/cp/cp')); 1139 cpFn = require('util').callbackify(cpFn); 1140 ({ cpSyncFn } = require('internal/fs/cp/cp-sync')); 1141 } 1142} 1143 1144function lazyLoadRimraf() { 1145 if (rimraf === undefined) 1146 ({ rimraf, rimrafSync } = require('internal/fs/rimraf')); 1147} 1148 1149/** 1150 * Asynchronously removes a directory. 1151 * @param {string | Buffer | URL} path 1152 * @param {{ 1153 * maxRetries?: number; 1154 * recursive?: boolean; 1155 * retryDelay?: number; 1156 * }} [options] 1157 * @param {(err?: Error) => any} callback 1158 * @returns {void} 1159 */ 1160function rmdir(path, options, callback) { 1161 if (typeof options === 'function') { 1162 callback = options; 1163 options = undefined; 1164 } 1165 1166 callback = makeCallback(callback); 1167 path = pathModule.toNamespacedPath(getValidatedPath(path)); 1168 1169 if (options?.recursive) { 1170 emitRecursiveRmdirWarning(); 1171 validateRmOptions( 1172 path, 1173 { ...options, force: false }, 1174 true, 1175 (err, options) => { 1176 if (err === false) { 1177 const req = new FSReqCallback(); 1178 req.oncomplete = callback; 1179 return binding.rmdir(path, req); 1180 } 1181 if (err) { 1182 return callback(err); 1183 } 1184 1185 lazyLoadRimraf(); 1186 rimraf(path, options, callback); 1187 }); 1188 } else { 1189 validateRmdirOptions(options); 1190 const req = new FSReqCallback(); 1191 req.oncomplete = callback; 1192 return binding.rmdir(path, req); 1193 } 1194} 1195 1196/** 1197 * Synchronously removes a directory. 1198 * @param {string | Buffer | URL} path 1199 * @param {{ 1200 * maxRetries?: number; 1201 * recursive?: boolean; 1202 * retryDelay?: number; 1203 * }} [options] 1204 * @returns {void} 1205 */ 1206function rmdirSync(path, options) { 1207 path = getValidatedPath(path); 1208 1209 if (options?.recursive) { 1210 emitRecursiveRmdirWarning(); 1211 options = validateRmOptionsSync(path, { ...options, force: false }, true); 1212 if (options !== false) { 1213 lazyLoadRimraf(); 1214 return rimrafSync(pathModule.toNamespacedPath(path), options); 1215 } 1216 } else { 1217 validateRmdirOptions(options); 1218 } 1219 1220 const ctx = { path }; 1221 binding.rmdir(pathModule.toNamespacedPath(path), undefined, ctx); 1222 return handleErrorFromBinding(ctx); 1223} 1224 1225/** 1226 * Asynchronously removes files and 1227 * directories (modeled on the standard POSIX `rm` utility). 1228 * @param {string | Buffer | URL} path 1229 * @param {{ 1230 * force?: boolean; 1231 * maxRetries?: number; 1232 * recursive?: boolean; 1233 * retryDelay?: number; 1234 * }} [options] 1235 * @param {(err?: Error) => any} callback 1236 * @returns {void} 1237 */ 1238function rm(path, options, callback) { 1239 if (typeof options === 'function') { 1240 callback = options; 1241 options = undefined; 1242 } 1243 path = getValidatedPath(path); 1244 1245 validateRmOptions(path, options, false, (err, options) => { 1246 if (err) { 1247 return callback(err); 1248 } 1249 lazyLoadRimraf(); 1250 return rimraf(pathModule.toNamespacedPath(path), options, callback); 1251 }); 1252} 1253 1254/** 1255 * Synchronously removes files and 1256 * directories (modeled on the standard POSIX `rm` utility). 1257 * @param {string | Buffer | URL} path 1258 * @param {{ 1259 * force?: boolean; 1260 * maxRetries?: number; 1261 * recursive?: boolean; 1262 * retryDelay?: number; 1263 * }} [options] 1264 * @returns {void} 1265 */ 1266function rmSync(path, options) { 1267 path = getValidatedPath(path); 1268 options = validateRmOptionsSync(path, options, false); 1269 1270 lazyLoadRimraf(); 1271 return rimrafSync(pathModule.toNamespacedPath(path), options); 1272} 1273 1274/** 1275 * Forces all currently queued I/O operations associated 1276 * with the file to the operating system's synchronized 1277 * I/O completion state. 1278 * @param {number} fd 1279 * @param {(err?: Error) => any} callback 1280 * @returns {void} 1281 */ 1282function fdatasync(fd, callback) { 1283 fd = getValidatedFd(fd); 1284 const req = new FSReqCallback(); 1285 req.oncomplete = makeCallback(callback); 1286 binding.fdatasync(fd, req); 1287} 1288 1289/** 1290 * Synchronously forces all currently queued I/O operations 1291 * associated with the file to the operating 1292 * system's synchronized I/O completion state. 1293 * @param {number} fd 1294 * @returns {void} 1295 */ 1296function fdatasyncSync(fd) { 1297 fd = getValidatedFd(fd); 1298 const ctx = {}; 1299 binding.fdatasync(fd, undefined, ctx); 1300 handleErrorFromBinding(ctx); 1301} 1302 1303/** 1304 * Requests for all data for the open file descriptor 1305 * to be flushed to the storage device. 1306 * @param {number} fd 1307 * @param {(err?: Error) => any} callback 1308 * @returns {void} 1309 */ 1310function fsync(fd, callback) { 1311 fd = getValidatedFd(fd); 1312 const req = new FSReqCallback(); 1313 req.oncomplete = makeCallback(callback); 1314 binding.fsync(fd, req); 1315} 1316 1317/** 1318 * Synchronously requests for all data for the open 1319 * file descriptor to be flushed to the storage device. 1320 * @param {number} fd 1321 * @returns {void} 1322 */ 1323function fsyncSync(fd) { 1324 fd = getValidatedFd(fd); 1325 const ctx = {}; 1326 binding.fsync(fd, undefined, ctx); 1327 handleErrorFromBinding(ctx); 1328} 1329 1330/** 1331 * Asynchronously creates a directory. 1332 * @param {string | Buffer | URL} path 1333 * @param {{ 1334 * recursive?: boolean; 1335 * mode?: string | number; 1336 * } | number} [options] 1337 * @param {(err?: Error) => any} callback 1338 * @returns {void} 1339 */ 1340function mkdir(path, options, callback) { 1341 let mode = 0o777; 1342 let recursive = false; 1343 if (typeof options === 'function') { 1344 callback = options; 1345 } else if (typeof options === 'number' || typeof options === 'string') { 1346 mode = options; 1347 } else if (options) { 1348 if (options.recursive !== undefined) 1349 recursive = options.recursive; 1350 if (options.mode !== undefined) 1351 mode = options.mode; 1352 } 1353 callback = makeCallback(callback); 1354 path = getValidatedPath(path); 1355 1356 validateBoolean(recursive, 'options.recursive'); 1357 1358 const req = new FSReqCallback(); 1359 req.oncomplete = callback; 1360 binding.mkdir(pathModule.toNamespacedPath(path), 1361 parseFileMode(mode, 'mode'), recursive, req); 1362} 1363 1364/** 1365 * Synchronously creates a directory. 1366 * @param {string | Buffer | URL} path 1367 * @param {{ 1368 * recursive?: boolean; 1369 * mode?: string | number; 1370 * } | number} [options] 1371 * @returns {string | void} 1372 */ 1373function mkdirSync(path, options) { 1374 let mode = 0o777; 1375 let recursive = false; 1376 if (typeof options === 'number' || typeof options === 'string') { 1377 mode = options; 1378 } else if (options) { 1379 if (options.recursive !== undefined) 1380 recursive = options.recursive; 1381 if (options.mode !== undefined) 1382 mode = options.mode; 1383 } 1384 path = getValidatedPath(path); 1385 validateBoolean(recursive, 'options.recursive'); 1386 1387 const ctx = { path }; 1388 const result = binding.mkdir(pathModule.toNamespacedPath(path), 1389 parseFileMode(mode, 'mode'), recursive, 1390 undefined, ctx); 1391 handleErrorFromBinding(ctx); 1392 if (recursive) { 1393 return result; 1394 } 1395} 1396 1397/** 1398 * An iterative algorithm for reading the entire contents of the `basePath` directory. 1399 * This function does not validate `basePath` as a directory. It is passed directly to 1400 * `binding.readdir`. 1401 * @param {string} basePath 1402 * @param {{ encoding: string, withFileTypes: boolean }} options 1403 * @returns {string[] | Dirent[]} 1404 */ 1405function readdirSyncRecursive(basePath, options) { 1406 const withFileTypes = Boolean(options.withFileTypes); 1407 const encoding = options.encoding; 1408 1409 const readdirResults = []; 1410 const pathsQueue = [basePath]; 1411 1412 const ctx = { path: basePath }; 1413 function read(path) { 1414 ctx.path = path; 1415 const readdirResult = binding.readdir( 1416 pathModule.toNamespacedPath(path), 1417 encoding, 1418 withFileTypes, 1419 undefined, 1420 ctx, 1421 ); 1422 handleErrorFromBinding(ctx); 1423 1424 if (withFileTypes) { 1425 // Calling `readdir` with `withFileTypes=true`, the result is an array of arrays. 1426 // The first array is the names, and the second array is the types. 1427 // They are guaranteed to be the same length; hence, setting `length` to the length 1428 // of the first array within the result. 1429 const length = readdirResult[0].length; 1430 for (let i = 0; i < length; i++) { 1431 const dirent = getDirent(path, readdirResult[0][i], readdirResult[1][i]); 1432 ArrayPrototypePush(readdirResults, dirent); 1433 if (dirent.isDirectory()) { 1434 ArrayPrototypePush(pathsQueue, pathModule.join(dirent.path, dirent.name)); 1435 } 1436 } 1437 } else { 1438 for (let i = 0; i < readdirResult.length; i++) { 1439 const resultPath = pathModule.join(path, readdirResult[i]); 1440 const relativeResultPath = pathModule.relative(basePath, resultPath); 1441 const stat = binding.internalModuleStat(resultPath); 1442 ArrayPrototypePush(readdirResults, relativeResultPath); 1443 // 1 indicates directory 1444 if (stat === 1) { 1445 ArrayPrototypePush(pathsQueue, resultPath); 1446 } 1447 } 1448 } 1449 } 1450 1451 for (let i = 0; i < pathsQueue.length; i++) { 1452 read(pathsQueue[i]); 1453 } 1454 1455 return readdirResults; 1456} 1457 1458/** 1459 * Reads the contents of a directory. 1460 * @param {string | Buffer | URL} path 1461 * @param {string | { 1462 * encoding?: string; 1463 * withFileTypes?: boolean; 1464 * }} [options] 1465 * @param {( 1466 * err?: Error, 1467 * files?: string[] | Buffer[] | Direct[]; 1468 * ) => any} callback 1469 * @returns {void} 1470 */ 1471function readdir(path, options, callback) { 1472 callback = makeCallback(typeof options === 'function' ? options : callback); 1473 options = getOptions(options); 1474 path = getValidatedPath(path); 1475 if (options.recursive != null) { 1476 validateBoolean(options.recursive, 'options.recursive'); 1477 } 1478 1479 if (options.recursive) { 1480 callback(null, readdirSyncRecursive(path, options)); 1481 return; 1482 } 1483 1484 const req = new FSReqCallback(); 1485 if (!options.withFileTypes) { 1486 req.oncomplete = callback; 1487 } else { 1488 req.oncomplete = (err, result) => { 1489 if (err) { 1490 callback(err); 1491 return; 1492 } 1493 getDirents(path, result, callback); 1494 }; 1495 } 1496 binding.readdir(pathModule.toNamespacedPath(path), options.encoding, 1497 !!options.withFileTypes, req); 1498} 1499 1500/** 1501 * Synchronously reads the contents of a directory. 1502 * @param {string | Buffer | URL} path 1503 * @param {string | { 1504 * encoding?: string; 1505 * withFileTypes?: boolean; 1506 * recursive?: boolean; 1507 * }} [options] 1508 * @returns {string | Buffer[] | Dirent[]} 1509 */ 1510function readdirSync(path, options) { 1511 options = getOptions(options); 1512 path = getValidatedPath(path); 1513 if (options.recursive != null) { 1514 validateBoolean(options.recursive, 'options.recursive'); 1515 } 1516 1517 if (options.recursive) { 1518 return readdirSyncRecursive(path, options); 1519 } 1520 1521 const ctx = { path }; 1522 const result = binding.readdir(pathModule.toNamespacedPath(path), 1523 options.encoding, !!options.withFileTypes, 1524 undefined, ctx); 1525 handleErrorFromBinding(ctx); 1526 return options.withFileTypes ? getDirents(path, result) : result; 1527} 1528 1529/** 1530 * Invokes the callback with the `fs.Stats` 1531 * for the file descriptor. 1532 * @param {number} fd 1533 * @param {{ bigint?: boolean; }} [options] 1534 * @param {( 1535 * err?: Error, 1536 * stats?: Stats 1537 * ) => any} callback 1538 * @returns {void} 1539 */ 1540function fstat(fd, options = { bigint: false }, callback) { 1541 if (typeof options === 'function') { 1542 callback = options; 1543 options = kEmptyObject; 1544 } 1545 fd = getValidatedFd(fd); 1546 callback = makeStatsCallback(callback); 1547 1548 const req = new FSReqCallback(options.bigint); 1549 req.oncomplete = callback; 1550 binding.fstat(fd, options.bigint, req); 1551} 1552 1553/** 1554 * Retrieves the `fs.Stats` for the symbolic link 1555 * referred to by the `path`. 1556 * @param {string | Buffer | URL} path 1557 * @param {{ bigint?: boolean; }} [options] 1558 * @param {( 1559 * err?: Error, 1560 * stats?: Stats 1561 * ) => any} callback 1562 * @returns {void} 1563 */ 1564function lstat(path, options = { bigint: false }, callback) { 1565 if (typeof options === 'function') { 1566 callback = options; 1567 options = kEmptyObject; 1568 } 1569 callback = makeStatsCallback(callback); 1570 path = getValidatedPath(path); 1571 1572 const req = new FSReqCallback(options.bigint); 1573 req.oncomplete = callback; 1574 binding.lstat(pathModule.toNamespacedPath(path), options.bigint, req); 1575} 1576 1577/** 1578 * Asynchronously gets the stats of a file. 1579 * @param {string | Buffer | URL} path 1580 * @param {{ bigint?: boolean; }} [options] 1581 * @param {( 1582 * err?: Error, 1583 * stats?: Stats 1584 * ) => any} callback 1585 * @returns {void} 1586 */ 1587function stat(path, options = { bigint: false }, callback) { 1588 if (typeof options === 'function') { 1589 callback = options; 1590 options = kEmptyObject; 1591 } 1592 callback = makeStatsCallback(callback); 1593 path = getValidatedPath(path); 1594 1595 const req = new FSReqCallback(options.bigint); 1596 req.oncomplete = callback; 1597 binding.stat(pathModule.toNamespacedPath(path), options.bigint, req); 1598} 1599 1600function statfs(path, options = { bigint: false }, callback) { 1601 if (typeof options === 'function') { 1602 callback = options; 1603 options = kEmptyObject; 1604 } 1605 callback = maybeCallback(callback); 1606 path = getValidatedPath(path); 1607 const req = new FSReqCallback(options.bigint); 1608 req.oncomplete = (err, stats) => { 1609 if (err) { 1610 return callback(err); 1611 } 1612 1613 callback(err, getStatFsFromBinding(stats)); 1614 }; 1615 binding.statfs(pathModule.toNamespacedPath(path), options.bigint, req); 1616} 1617 1618function hasNoEntryError(ctx) { 1619 if (ctx.errno) { 1620 const uvErr = uvErrmapGet(ctx.errno); 1621 return uvErr?.[0] === 'ENOENT'; 1622 } 1623 1624 if (ctx.error) { 1625 return ctx.error.code === 'ENOENT'; 1626 } 1627 1628 return false; 1629} 1630 1631/** 1632 * Synchronously retrieves the `fs.Stats` for 1633 * the file descriptor. 1634 * @param {number} fd 1635 * @param {{ 1636 * bigint?: boolean; 1637 * }} [options] 1638 * @returns {Stats} 1639 */ 1640function fstatSync(fd, options = { bigint: false }) { 1641 fd = getValidatedFd(fd); 1642 const ctx = { fd }; 1643 const stats = binding.fstat(fd, options.bigint, undefined, ctx); 1644 handleErrorFromBinding(ctx); 1645 return getStatsFromBinding(stats); 1646} 1647 1648/** 1649 * Synchronously retrieves the `fs.Stats` for 1650 * the symbolic link referred to by the `path`. 1651 * @param {string | Buffer | URL} path 1652 * @param {{ 1653 * bigint?: boolean; 1654 * throwIfNoEntry?: boolean; 1655 * }} [options] 1656 * @returns {Stats} 1657 */ 1658function lstatSync(path, options = { bigint: false, throwIfNoEntry: true }) { 1659 path = getValidatedPath(path); 1660 const ctx = { path }; 1661 const stats = binding.lstat(pathModule.toNamespacedPath(path), 1662 options.bigint, undefined, ctx); 1663 if (options.throwIfNoEntry === false && hasNoEntryError(ctx)) { 1664 return undefined; 1665 } 1666 handleErrorFromBinding(ctx); 1667 return getStatsFromBinding(stats); 1668} 1669 1670/** 1671 * Synchronously retrieves the `fs.Stats` 1672 * for the `path`. 1673 * @param {string | Buffer | URL} path 1674 * @param {{ 1675 * bigint?: boolean; 1676 * throwIfNoEntry?: boolean; 1677 * }} [options] 1678 * @returns {Stats} 1679 */ 1680function statSync(path, options = { bigint: false, throwIfNoEntry: true }) { 1681 path = getValidatedPath(path); 1682 const ctx = { path }; 1683 const stats = binding.stat(pathModule.toNamespacedPath(path), 1684 options.bigint, undefined, ctx); 1685 if (options.throwIfNoEntry === false && hasNoEntryError(ctx)) { 1686 return undefined; 1687 } 1688 handleErrorFromBinding(ctx); 1689 return getStatsFromBinding(stats); 1690} 1691 1692function statfsSync(path, options = { bigint: false }) { 1693 path = getValidatedPath(path); 1694 const ctx = { path }; 1695 const stats = binding.statfs(pathModule.toNamespacedPath(path), 1696 options.bigint, undefined, ctx); 1697 handleErrorFromBinding(ctx); 1698 return getStatFsFromBinding(stats); 1699} 1700 1701/** 1702 * Reads the contents of a symbolic link 1703 * referred to by `path`. 1704 * @param {string | Buffer | URL} path 1705 * @param {{ encoding?: string; } | string} [options] 1706 * @param {( 1707 * err?: Error, 1708 * linkString?: string | Buffer 1709 * ) => any} callback 1710 * @returns {void} 1711 */ 1712function readlink(path, options, callback) { 1713 callback = makeCallback(typeof options === 'function' ? options : callback); 1714 options = getOptions(options); 1715 path = getValidatedPath(path, 'oldPath'); 1716 const req = new FSReqCallback(); 1717 req.oncomplete = callback; 1718 binding.readlink(pathModule.toNamespacedPath(path), options.encoding, req); 1719} 1720 1721/** 1722 * Synchronously reads the contents of a symbolic link 1723 * referred to by `path`. 1724 * @param {string | Buffer | URL} path 1725 * @param {{ encoding?: string; } | string} [options] 1726 * @returns {string | Buffer} 1727 */ 1728function readlinkSync(path, options) { 1729 options = getOptions(options); 1730 path = getValidatedPath(path, 'oldPath'); 1731 const ctx = { path }; 1732 const result = binding.readlink(pathModule.toNamespacedPath(path), 1733 options.encoding, undefined, ctx); 1734 handleErrorFromBinding(ctx); 1735 return result; 1736} 1737 1738/** 1739 * Creates the link called `path` pointing to `target`. 1740 * @param {string | Buffer | URL} target 1741 * @param {string | Buffer | URL} path 1742 * @param {string | null} [type_] 1743 * @param {(err?: Error) => any} callback_ 1744 * @returns {void} 1745 */ 1746function symlink(target, path, type_, callback_) { 1747 const type = (typeof type_ === 'string' ? type_ : null); 1748 const callback = makeCallback(arguments[arguments.length - 1]); 1749 1750 target = getValidatedPath(target, 'target'); 1751 path = getValidatedPath(path); 1752 1753 if (isWindows && type === null) { 1754 let absoluteTarget; 1755 try { 1756 // Symlinks targets can be relative to the newly created path. 1757 // Calculate absolute file name of the symlink target, and check 1758 // if it is a directory. Ignore resolve error to keep symlink 1759 // errors consistent between platforms if invalid path is 1760 // provided. 1761 absoluteTarget = pathModule.resolve(path, '..', target); 1762 } catch { 1763 // Continue regardless of error. 1764 } 1765 if (absoluteTarget !== undefined) { 1766 stat(absoluteTarget, (err, stat) => { 1767 const resolvedType = !err && stat.isDirectory() ? 'dir' : 'file'; 1768 const resolvedFlags = stringToSymlinkType(resolvedType); 1769 const destination = preprocessSymlinkDestination(target, 1770 resolvedType, 1771 path); 1772 1773 const req = new FSReqCallback(); 1774 req.oncomplete = callback; 1775 binding.symlink(destination, 1776 pathModule.toNamespacedPath(path), resolvedFlags, req); 1777 }); 1778 return; 1779 } 1780 } 1781 1782 const destination = preprocessSymlinkDestination(target, type, path); 1783 1784 const flags = stringToSymlinkType(type); 1785 const req = new FSReqCallback(); 1786 req.oncomplete = callback; 1787 binding.symlink(destination, pathModule.toNamespacedPath(path), flags, req); 1788} 1789 1790/** 1791 * Synchronously creates the link called `path` 1792 * pointing to `target`. 1793 * @param {string | Buffer | URL} target 1794 * @param {string | Buffer | URL} path 1795 * @param {string | null} [type] 1796 * @returns {void} 1797 */ 1798function symlinkSync(target, path, type) { 1799 type = (typeof type === 'string' ? type : null); 1800 if (isWindows && type === null) { 1801 const absoluteTarget = pathModule.resolve(`${path}`, '..', `${target}`); 1802 if (statSync(absoluteTarget, { throwIfNoEntry: false })?.isDirectory()) { 1803 type = 'dir'; 1804 } 1805 } 1806 target = getValidatedPath(target, 'target'); 1807 path = getValidatedPath(path); 1808 const flags = stringToSymlinkType(type); 1809 1810 const ctx = { path: target, dest: path }; 1811 binding.symlink(preprocessSymlinkDestination(target, type, path), 1812 pathModule.toNamespacedPath(path), flags, undefined, ctx); 1813 1814 handleErrorFromBinding(ctx); 1815} 1816 1817/** 1818 * Creates a new link from the `existingPath` 1819 * to the `newPath`. 1820 * @param {string | Buffer | URL} existingPath 1821 * @param {string | Buffer | URL} newPath 1822 * @param {(err?: Error) => any} callback 1823 * @returns {void} 1824 */ 1825function link(existingPath, newPath, callback) { 1826 callback = makeCallback(callback); 1827 1828 existingPath = getValidatedPath(existingPath, 'existingPath'); 1829 newPath = getValidatedPath(newPath, 'newPath'); 1830 1831 const req = new FSReqCallback(); 1832 req.oncomplete = callback; 1833 1834 binding.link(pathModule.toNamespacedPath(existingPath), 1835 pathModule.toNamespacedPath(newPath), 1836 req); 1837} 1838 1839/** 1840 * Synchronously creates a new link from the `existingPath` 1841 * to the `newPath`. 1842 * @param {string | Buffer | URL} existingPath 1843 * @param {string | Buffer | URL} newPath 1844 * @returns {void} 1845 */ 1846function linkSync(existingPath, newPath) { 1847 existingPath = getValidatedPath(existingPath, 'existingPath'); 1848 newPath = getValidatedPath(newPath, 'newPath'); 1849 1850 const ctx = { path: existingPath, dest: newPath }; 1851 const result = binding.link(pathModule.toNamespacedPath(existingPath), 1852 pathModule.toNamespacedPath(newPath), 1853 undefined, ctx); 1854 handleErrorFromBinding(ctx); 1855 return result; 1856} 1857 1858/** 1859 * Asynchronously removes a file or symbolic link. 1860 * @param {string | Buffer | URL} path 1861 * @param {(err?: Error) => any} callback 1862 * @returns {void} 1863 */ 1864function unlink(path, callback) { 1865 callback = makeCallback(callback); 1866 path = getValidatedPath(path); 1867 const req = new FSReqCallback(); 1868 req.oncomplete = callback; 1869 binding.unlink(pathModule.toNamespacedPath(path), req); 1870} 1871 1872/** 1873 * Synchronously removes a file or symbolic link. 1874 * @param {string | Buffer | URL} path 1875 * @returns {void} 1876 */ 1877function unlinkSync(path) { 1878 path = getValidatedPath(path); 1879 const ctx = { path }; 1880 binding.unlink(pathModule.toNamespacedPath(path), undefined, ctx); 1881 handleErrorFromBinding(ctx); 1882} 1883 1884/** 1885 * Sets the permissions on the file. 1886 * @param {number} fd 1887 * @param {string | number} mode 1888 * @param {(err?: Error) => any} callback 1889 * @returns {void} 1890 */ 1891function fchmod(fd, mode, callback) { 1892 fd = getValidatedFd(fd); 1893 mode = parseFileMode(mode, 'mode'); 1894 callback = makeCallback(callback); 1895 1896 const req = new FSReqCallback(); 1897 req.oncomplete = callback; 1898 binding.fchmod(fd, mode, req); 1899} 1900 1901/** 1902 * Synchronously sets the permissions on the file. 1903 * @param {number} fd 1904 * @param {string | number} mode 1905 * @returns {void} 1906 */ 1907function fchmodSync(fd, mode) { 1908 fd = getValidatedFd(fd); 1909 mode = parseFileMode(mode, 'mode'); 1910 const ctx = {}; 1911 binding.fchmod(fd, mode, undefined, ctx); 1912 handleErrorFromBinding(ctx); 1913} 1914 1915/** 1916 * Changes the permissions on a symbolic link. 1917 * @param {string | Buffer | URL} path 1918 * @param {number} mode 1919 * @param {(err?: Error) => any} callback 1920 * @returns {void} 1921 */ 1922function lchmod(path, mode, callback) { 1923 callback = maybeCallback(callback); 1924 mode = parseFileMode(mode, 'mode'); 1925 fs.open(path, O_WRONLY | O_SYMLINK, (err, fd) => { 1926 if (err) { 1927 callback(err); 1928 return; 1929 } 1930 // Prefer to return the chmod error, if one occurs, 1931 // but still try to close, and report closing errors if they occur. 1932 fs.fchmod(fd, mode, (err) => { 1933 fs.close(fd, (err2) => { 1934 callback(aggregateTwoErrors(err2, err)); 1935 }); 1936 }); 1937 }); 1938} 1939 1940/** 1941 * Synchronously changes the permissions on a symbolic link. 1942 * @param {string | Buffer | URL} path 1943 * @param {number} mode 1944 * @returns {void} 1945 */ 1946function lchmodSync(path, mode) { 1947 const fd = fs.openSync(path, O_WRONLY | O_SYMLINK); 1948 1949 // Prefer to return the chmod error, if one occurs, 1950 // but still try to close, and report closing errors if they occur. 1951 let ret; 1952 try { 1953 ret = fs.fchmodSync(fd, mode); 1954 } finally { 1955 fs.closeSync(fd); 1956 } 1957 return ret; 1958} 1959 1960/** 1961 * Asynchronously changes the permissions of a file. 1962 * @param {string | Buffer | URL} path 1963 * @param {string | number} mode 1964 * @param {(err?: Error) => any} callback 1965 * @returns {void} 1966 */ 1967function chmod(path, mode, callback) { 1968 path = getValidatedPath(path); 1969 mode = parseFileMode(mode, 'mode'); 1970 callback = makeCallback(callback); 1971 1972 const req = new FSReqCallback(); 1973 req.oncomplete = callback; 1974 binding.chmod(pathModule.toNamespacedPath(path), mode, req); 1975} 1976 1977/** 1978 * Synchronously changes the permissions of a file. 1979 * @param {string | Buffer | URL} path 1980 * @param {string | number} mode 1981 * @returns {void} 1982 */ 1983function chmodSync(path, mode) { 1984 path = getValidatedPath(path); 1985 mode = parseFileMode(mode, 'mode'); 1986 1987 const ctx = { path }; 1988 binding.chmod(pathModule.toNamespacedPath(path), mode, undefined, ctx); 1989 handleErrorFromBinding(ctx); 1990} 1991 1992/** 1993 * Sets the owner of the symbolic link. 1994 * @param {string | Buffer | URL} path 1995 * @param {number} uid 1996 * @param {number} gid 1997 * @param {(err?: Error) => any} callback 1998 * @returns {void} 1999 */ 2000function lchown(path, uid, gid, callback) { 2001 callback = makeCallback(callback); 2002 path = getValidatedPath(path); 2003 validateInteger(uid, 'uid', -1, kMaxUserId); 2004 validateInteger(gid, 'gid', -1, kMaxUserId); 2005 const req = new FSReqCallback(); 2006 req.oncomplete = callback; 2007 binding.lchown(pathModule.toNamespacedPath(path), uid, gid, req); 2008} 2009 2010/** 2011 * Synchronously sets the owner of the symbolic link. 2012 * @param {string | Buffer | URL} path 2013 * @param {number} uid 2014 * @param {number} gid 2015 * @returns {void} 2016 */ 2017function lchownSync(path, uid, gid) { 2018 path = getValidatedPath(path); 2019 validateInteger(uid, 'uid', -1, kMaxUserId); 2020 validateInteger(gid, 'gid', -1, kMaxUserId); 2021 const ctx = { path }; 2022 binding.lchown(pathModule.toNamespacedPath(path), uid, gid, undefined, ctx); 2023 handleErrorFromBinding(ctx); 2024} 2025 2026/** 2027 * Sets the owner of the file. 2028 * @param {number} fd 2029 * @param {number} uid 2030 * @param {number} gid 2031 * @param {(err?: Error) => any} callback 2032 * @returns {void} 2033 */ 2034function fchown(fd, uid, gid, callback) { 2035 fd = getValidatedFd(fd); 2036 validateInteger(uid, 'uid', -1, kMaxUserId); 2037 validateInteger(gid, 'gid', -1, kMaxUserId); 2038 callback = makeCallback(callback); 2039 2040 const req = new FSReqCallback(); 2041 req.oncomplete = callback; 2042 binding.fchown(fd, uid, gid, req); 2043} 2044 2045/** 2046 * Synchronously sets the owner of the file. 2047 * @param {number} fd 2048 * @param {number} uid 2049 * @param {number} gid 2050 * @returns {void} 2051 */ 2052function fchownSync(fd, uid, gid) { 2053 fd = getValidatedFd(fd); 2054 validateInteger(uid, 'uid', -1, kMaxUserId); 2055 validateInteger(gid, 'gid', -1, kMaxUserId); 2056 2057 const ctx = {}; 2058 binding.fchown(fd, uid, gid, undefined, ctx); 2059 handleErrorFromBinding(ctx); 2060} 2061 2062/** 2063 * Asynchronously changes the owner and group 2064 * of a file. 2065 * @param {string | Buffer | URL} path 2066 * @param {number} uid 2067 * @param {number} gid 2068 * @param {(err?: Error) => any} callback 2069 * @returns {void} 2070 */ 2071function chown(path, uid, gid, callback) { 2072 callback = makeCallback(callback); 2073 path = getValidatedPath(path); 2074 validateInteger(uid, 'uid', -1, kMaxUserId); 2075 validateInteger(gid, 'gid', -1, kMaxUserId); 2076 2077 const req = new FSReqCallback(); 2078 req.oncomplete = callback; 2079 binding.chown(pathModule.toNamespacedPath(path), uid, gid, req); 2080} 2081 2082/** 2083 * Synchronously changes the owner and group 2084 * of a file. 2085 * @param {string | Buffer | URL} path 2086 * @param {number} uid 2087 * @param {number} gid 2088 * @returns {void} 2089 */ 2090function chownSync(path, uid, gid) { 2091 path = getValidatedPath(path); 2092 validateInteger(uid, 'uid', -1, kMaxUserId); 2093 validateInteger(gid, 'gid', -1, kMaxUserId); 2094 const ctx = { path }; 2095 binding.chown(pathModule.toNamespacedPath(path), uid, gid, undefined, ctx); 2096 handleErrorFromBinding(ctx); 2097} 2098 2099/** 2100 * Changes the file system timestamps of the object 2101 * referenced by `path`. 2102 * @param {string | Buffer | URL} path 2103 * @param {number | string | Date} atime 2104 * @param {number | string | Date} mtime 2105 * @param {(err?: Error) => any} callback 2106 * @returns {void} 2107 */ 2108function utimes(path, atime, mtime, callback) { 2109 callback = makeCallback(callback); 2110 path = getValidatedPath(path); 2111 2112 const req = new FSReqCallback(); 2113 req.oncomplete = callback; 2114 binding.utimes(pathModule.toNamespacedPath(path), 2115 toUnixTimestamp(atime), 2116 toUnixTimestamp(mtime), 2117 req); 2118} 2119 2120/** 2121 * Synchronously changes the file system timestamps 2122 * of the object referenced by `path`. 2123 * @param {string | Buffer | URL} path 2124 * @param {number | string | Date} atime 2125 * @param {number | string | Date} mtime 2126 * @returns {void} 2127 */ 2128function utimesSync(path, atime, mtime) { 2129 path = getValidatedPath(path); 2130 const ctx = { path }; 2131 binding.utimes(pathModule.toNamespacedPath(path), 2132 toUnixTimestamp(atime), toUnixTimestamp(mtime), 2133 undefined, ctx); 2134 handleErrorFromBinding(ctx); 2135} 2136 2137/** 2138 * Changes the file system timestamps of the object 2139 * referenced by the supplied `fd` (file descriptor). 2140 * @param {number} fd 2141 * @param {number | string | Date} atime 2142 * @param {number | string | Date} mtime 2143 * @param {(err?: Error) => any} callback 2144 * @returns {void} 2145 */ 2146function futimes(fd, atime, mtime, callback) { 2147 fd = getValidatedFd(fd); 2148 atime = toUnixTimestamp(atime, 'atime'); 2149 mtime = toUnixTimestamp(mtime, 'mtime'); 2150 callback = makeCallback(callback); 2151 2152 const req = new FSReqCallback(); 2153 req.oncomplete = callback; 2154 binding.futimes(fd, atime, mtime, req); 2155} 2156 2157/** 2158 * Synchronously changes the file system timestamps 2159 * of the object referenced by the 2160 * supplied `fd` (file descriptor). 2161 * @param {number} fd 2162 * @param {number | string | Date} atime 2163 * @param {number | string | Date} mtime 2164 * @returns {void} 2165 */ 2166function futimesSync(fd, atime, mtime) { 2167 fd = getValidatedFd(fd); 2168 atime = toUnixTimestamp(atime, 'atime'); 2169 mtime = toUnixTimestamp(mtime, 'mtime'); 2170 const ctx = {}; 2171 binding.futimes(fd, atime, mtime, undefined, ctx); 2172 handleErrorFromBinding(ctx); 2173} 2174 2175/** 2176 * Changes the access and modification times of 2177 * a file in the same way as `fs.utimes()`. 2178 * @param {string | Buffer | URL} path 2179 * @param {number | string | Date} atime 2180 * @param {number | string | Date} mtime 2181 * @param {(err?: Error) => any} callback 2182 * @returns {void} 2183 */ 2184function lutimes(path, atime, mtime, callback) { 2185 callback = makeCallback(callback); 2186 path = getValidatedPath(path); 2187 2188 const req = new FSReqCallback(); 2189 req.oncomplete = callback; 2190 binding.lutimes(pathModule.toNamespacedPath(path), 2191 toUnixTimestamp(atime), 2192 toUnixTimestamp(mtime), 2193 req); 2194} 2195 2196/** 2197 * Synchronously changes the access and modification 2198 * times of a file in the same way as `fs.utimesSync()`. 2199 * @param {string | Buffer | URL} path 2200 * @param {number | string | Date} atime 2201 * @param {number | string | Date} mtime 2202 * @returns {void} 2203 */ 2204function lutimesSync(path, atime, mtime) { 2205 path = getValidatedPath(path); 2206 const ctx = { path }; 2207 binding.lutimes(pathModule.toNamespacedPath(path), 2208 toUnixTimestamp(atime), 2209 toUnixTimestamp(mtime), 2210 undefined, ctx); 2211 handleErrorFromBinding(ctx); 2212} 2213 2214function writeAll(fd, isUserFd, buffer, offset, length, signal, callback) { 2215 if (signal?.aborted) { 2216 const abortError = new AbortError(undefined, { cause: signal?.reason }); 2217 if (isUserFd) { 2218 callback(abortError); 2219 } else { 2220 fs.close(fd, (err) => { 2221 callback(aggregateTwoErrors(err, abortError)); 2222 }); 2223 } 2224 return; 2225 } 2226 // write(fd, buffer, offset, length, position, callback) 2227 fs.write(fd, buffer, offset, length, null, (writeErr, written) => { 2228 if (writeErr) { 2229 if (isUserFd) { 2230 callback(writeErr); 2231 } else { 2232 fs.close(fd, (err) => { 2233 callback(aggregateTwoErrors(err, writeErr)); 2234 }); 2235 } 2236 } else if (written === length) { 2237 if (isUserFd) { 2238 callback(null); 2239 } else { 2240 fs.close(fd, callback); 2241 } 2242 } else { 2243 offset += written; 2244 length -= written; 2245 writeAll(fd, isUserFd, buffer, offset, length, signal, callback); 2246 } 2247 }); 2248} 2249 2250/** 2251 * Asynchronously writes data to the file. 2252 * @param {string | Buffer | URL | number} path 2253 * @param {string | Buffer | TypedArray | DataView | object} data 2254 * @param {{ 2255 * encoding?: string | null; 2256 * mode?: number; 2257 * flag?: string; 2258 * signal?: AbortSignal; 2259 * } | string} [options] 2260 * @param {(err?: Error) => any} callback 2261 * @returns {void} 2262 */ 2263function writeFile(path, data, options, callback) { 2264 callback = maybeCallback(callback || options); 2265 options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'w' }); 2266 const flag = options.flag || 'w'; 2267 2268 if (!isArrayBufferView(data)) { 2269 validateStringAfterArrayBufferView(data, 'data'); 2270 if (typeof data !== 'string') { 2271 showStringCoercionDeprecation(); 2272 } 2273 data = Buffer.from(String(data), options.encoding || 'utf8'); 2274 } 2275 2276 if (isFd(path)) { 2277 const isUserFd = true; 2278 const signal = options.signal; 2279 writeAll(path, isUserFd, data, 0, data.byteLength, signal, callback); 2280 return; 2281 } 2282 2283 if (checkAborted(options.signal, callback)) 2284 return; 2285 2286 fs.open(path, flag, options.mode, (openErr, fd) => { 2287 if (openErr) { 2288 callback(openErr); 2289 } else { 2290 const isUserFd = false; 2291 const signal = options.signal; 2292 writeAll(fd, isUserFd, data, 0, data.byteLength, signal, callback); 2293 } 2294 }); 2295} 2296 2297/** 2298 * Synchronously writes data to the file. 2299 * @param {string | Buffer | URL | number} path 2300 * @param {string | Buffer | TypedArray | DataView | object} data 2301 * @param {{ 2302 * encoding?: string | null; 2303 * mode?: number; 2304 * flag?: string; 2305 * } | string} [options] 2306 * @returns {void} 2307 */ 2308function writeFileSync(path, data, options) { 2309 options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'w' }); 2310 2311 if (!isArrayBufferView(data)) { 2312 validateStringAfterArrayBufferView(data, 'data'); 2313 if (typeof data !== 'string') { 2314 showStringCoercionDeprecation(); 2315 } 2316 data = Buffer.from(String(data), options.encoding || 'utf8'); 2317 } 2318 2319 const flag = options.flag || 'w'; 2320 2321 const isUserFd = isFd(path); // File descriptor ownership 2322 const fd = isUserFd ? path : fs.openSync(path, flag, options.mode); 2323 2324 let offset = 0; 2325 let length = data.byteLength; 2326 try { 2327 while (length > 0) { 2328 const written = fs.writeSync(fd, data, offset, length); 2329 offset += written; 2330 length -= written; 2331 } 2332 } finally { 2333 if (!isUserFd) fs.closeSync(fd); 2334 } 2335} 2336 2337/** 2338 * Asynchronously appends data to a file. 2339 * @param {string | Buffer | URL | number} path 2340 * @param {string | Buffer} data 2341 * @param {{ 2342 * encoding?: string | null; 2343 * mode?: number; 2344 * flag?: string; 2345 * } | string} [options] 2346 * @param {(err?: Error) => any} callback 2347 * @returns {void} 2348 */ 2349function appendFile(path, data, options, callback) { 2350 callback = maybeCallback(callback || options); 2351 options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'a' }); 2352 2353 // Don't make changes directly on options object 2354 options = copyObject(options); 2355 2356 // Force append behavior when using a supplied file descriptor 2357 if (!options.flag || isFd(path)) 2358 options.flag = 'a'; 2359 2360 fs.writeFile(path, data, options, callback); 2361} 2362 2363/** 2364 * Synchronously appends data to a file. 2365 * @param {string | Buffer | URL | number} path 2366 * @param {string | Buffer} data 2367 * @param {{ 2368 * encoding?: string | null; 2369 * mode?: number; 2370 * flag?: string; 2371 * } | string} [options] 2372 * @returns {void} 2373 */ 2374function appendFileSync(path, data, options) { 2375 options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'a' }); 2376 2377 // Don't make changes directly on options object 2378 options = copyObject(options); 2379 2380 // Force append behavior when using a supplied file descriptor 2381 if (!options.flag || isFd(path)) 2382 options.flag = 'a'; 2383 2384 fs.writeFileSync(path, data, options); 2385} 2386 2387/** 2388 * Watches for the changes on `filename`. 2389 * @param {string | Buffer | URL} filename 2390 * @param {string | { 2391 * persistent?: boolean; 2392 * recursive?: boolean; 2393 * encoding?: string; 2394 * signal?: AbortSignal; 2395 * }} [options] 2396 * @param {( 2397 * eventType?: string, 2398 * filename?: string | Buffer 2399 * ) => any} [listener] 2400 * @returns {watchers.FSWatcher} 2401 */ 2402function watch(filename, options, listener) { 2403 if (typeof options === 'function') { 2404 listener = options; 2405 } 2406 options = getOptions(options); 2407 2408 // Don't make changes directly on options object 2409 options = copyObject(options); 2410 2411 if (options.persistent === undefined) options.persistent = true; 2412 if (options.recursive === undefined) options.recursive = false; 2413 if (options.recursive && !(isOSX || isWindows)) 2414 throw new ERR_FEATURE_UNAVAILABLE_ON_PLATFORM('watch recursively'); 2415 2416 const watchers = require('internal/fs/watchers'); 2417 const watcher = new watchers.FSWatcher(); 2418 watcher[watchers.kFSWatchStart](filename, 2419 options.persistent, 2420 options.recursive, 2421 options.encoding); 2422 if (listener) { 2423 watcher.addListener('change', listener); 2424 } 2425 if (options.signal) { 2426 if (options.signal.aborted) { 2427 process.nextTick(() => watcher.close()); 2428 } else { 2429 const listener = () => watcher.close(); 2430 kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; 2431 options.signal.addEventListener('abort', listener, { __proto__: null, [kResistStopPropagation]: true }); 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 const watchers = require('internal/fs/watchers'); 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 const watchers = require('internal/fs/watchers'); 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 | Buffer | URL} 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 prefix = getValidatedPath(prefix, 'prefix'); 2896 warnOnNonPortableTemplate(prefix); 2897 2898 let path; 2899 if (typeof prefix === 'string') { 2900 path = `${prefix}XXXXXX`; 2901 } else { 2902 path = Buffer.concat([prefix, Buffer.from('XXXXXX')]); 2903 } 2904 2905 const req = new FSReqCallback(); 2906 req.oncomplete = callback; 2907 binding.mkdtemp(path, options.encoding, req); 2908} 2909 2910/** 2911 * Synchronously creates a unique temporary directory. 2912 * @param {string | Buffer | URL} prefix 2913 * @param {string | { encoding?: string; }} [options] 2914 * @returns {string} 2915 */ 2916function mkdtempSync(prefix, options) { 2917 options = getOptions(options); 2918 2919 prefix = getValidatedPath(prefix, 'prefix'); 2920 warnOnNonPortableTemplate(prefix); 2921 2922 let path; 2923 if (typeof prefix === 'string') { 2924 path = `${prefix}XXXXXX`; 2925 } else { 2926 path = Buffer.concat([prefix, Buffer.from('XXXXXX')]); 2927 } 2928 2929 const ctx = { path }; 2930 const result = binding.mkdtemp(path, options.encoding, 2931 undefined, ctx); 2932 handleErrorFromBinding(ctx); 2933 return result; 2934} 2935 2936/** 2937 * Asynchronously copies `src` to `dest`. By 2938 * default, `dest` is overwritten if it already exists. 2939 * @param {string | Buffer | URL} src 2940 * @param {string | Buffer | URL} dest 2941 * @param {number} [mode] 2942 * @param {() => any} callback 2943 * @returns {void} 2944 */ 2945function copyFile(src, dest, mode, callback) { 2946 if (typeof mode === 'function') { 2947 callback = mode; 2948 mode = 0; 2949 } 2950 2951 src = getValidatedPath(src, 'src'); 2952 dest = getValidatedPath(dest, 'dest'); 2953 2954 src = pathModule._makeLong(src); 2955 dest = pathModule._makeLong(dest); 2956 mode = getValidMode(mode, 'copyFile'); 2957 callback = makeCallback(callback); 2958 2959 const req = new FSReqCallback(); 2960 req.oncomplete = callback; 2961 binding.copyFile(src, dest, mode, req); 2962} 2963 2964/** 2965 * Synchronously copies `src` to `dest`. By 2966 * default, `dest` is overwritten if it already exists. 2967 * @param {string | Buffer | URL} src 2968 * @param {string | Buffer | URL} dest 2969 * @param {number} [mode] 2970 * @returns {void} 2971 */ 2972function copyFileSync(src, dest, mode) { 2973 src = getValidatedPath(src, 'src'); 2974 dest = getValidatedPath(dest, 'dest'); 2975 2976 const ctx = { path: src, dest }; // non-prefixed 2977 2978 src = pathModule._makeLong(src); 2979 dest = pathModule._makeLong(dest); 2980 mode = getValidMode(mode, 'copyFile'); 2981 binding.copyFile(src, dest, mode, undefined, ctx); 2982 handleErrorFromBinding(ctx); 2983} 2984 2985/** 2986 * Asynchronously copies `src` to `dest`. `src` can be a file, directory, or 2987 * symlink. The contents of directories will be copied recursively. 2988 * @param {string | URL} src 2989 * @param {string | URL} dest 2990 * @param {object} [options] 2991 * @param {() => any} callback 2992 * @returns {void} 2993 */ 2994function cp(src, dest, options, callback) { 2995 if (typeof options === 'function') { 2996 callback = options; 2997 options = undefined; 2998 } 2999 callback = makeCallback(callback); 3000 options = validateCpOptions(options); 3001 src = pathModule.toNamespacedPath(getValidatedPath(src, 'src')); 3002 dest = pathModule.toNamespacedPath(getValidatedPath(dest, 'dest')); 3003 lazyLoadCp(); 3004 cpFn(src, dest, options, callback); 3005} 3006 3007/** 3008 * Synchronously copies `src` to `dest`. `src` can be a file, directory, or 3009 * symlink. The contents of directories will be copied recursively. 3010 * @param {string | URL} src 3011 * @param {string | URL} dest 3012 * @param {object} [options] 3013 * @returns {void} 3014 */ 3015function cpSync(src, dest, options) { 3016 options = validateCpOptions(options); 3017 src = pathModule.toNamespacedPath(getValidatedPath(src, 'src')); 3018 dest = pathModule.toNamespacedPath(getValidatedPath(dest, 'dest')); 3019 lazyLoadCp(); 3020 cpSyncFn(src, dest, options); 3021} 3022 3023function lazyLoadStreams() { 3024 if (!ReadStream) { 3025 ({ ReadStream, WriteStream } = require('internal/fs/streams')); 3026 FileReadStream = ReadStream; 3027 FileWriteStream = WriteStream; 3028 } 3029} 3030 3031/** 3032 * Creates a readable stream with a default `highWaterMark` 3033 * of 64 KiB. 3034 * @param {string | Buffer | URL} path 3035 * @param {string | { 3036 * flags?: string; 3037 * encoding?: string; 3038 * fd?: number | FileHandle; 3039 * mode?: number; 3040 * autoClose?: boolean; 3041 * emitClose?: boolean; 3042 * start: number; 3043 * end?: number; 3044 * highWaterMark?: number; 3045 * fs?: object | null; 3046 * }} [options] 3047 * @returns {ReadStream} 3048 */ 3049function createReadStream(path, options) { 3050 lazyLoadStreams(); 3051 return new ReadStream(path, options); 3052} 3053 3054/** 3055 * Creates a write stream. 3056 * @param {string | Buffer | URL} path 3057 * @param {string | { 3058 * flags?: string; 3059 * encoding?: string; 3060 * fd?: number | FileHandle; 3061 * mode?: number; 3062 * autoClose?: boolean; 3063 * emitClose?: boolean; 3064 * start: number; 3065 * fs?: object | null; 3066 * }} [options] 3067 * @returns {WriteStream} 3068 */ 3069function createWriteStream(path, options) { 3070 lazyLoadStreams(); 3071 return new WriteStream(path, options); 3072} 3073 3074module.exports = fs = { 3075 appendFile, 3076 appendFileSync, 3077 access, 3078 accessSync, 3079 chown, 3080 chownSync, 3081 chmod, 3082 chmodSync, 3083 close, 3084 closeSync, 3085 copyFile, 3086 copyFileSync, 3087 cp, 3088 cpSync, 3089 createReadStream, 3090 createWriteStream, 3091 exists, 3092 existsSync, 3093 fchown, 3094 fchownSync, 3095 fchmod, 3096 fchmodSync, 3097 fdatasync, 3098 fdatasyncSync, 3099 fstat, 3100 fstatSync, 3101 fsync, 3102 fsyncSync, 3103 ftruncate, 3104 ftruncateSync, 3105 futimes, 3106 futimesSync, 3107 lchown, 3108 lchownSync, 3109 lchmod: constants.O_SYMLINK !== undefined ? lchmod : undefined, 3110 lchmodSync: constants.O_SYMLINK !== undefined ? lchmodSync : undefined, 3111 link, 3112 linkSync, 3113 lstat, 3114 lstatSync, 3115 lutimes, 3116 lutimesSync, 3117 mkdir, 3118 mkdirSync, 3119 mkdtemp, 3120 mkdtempSync, 3121 open, 3122 openSync, 3123 readdir, 3124 readdirSync, 3125 read, 3126 readSync, 3127 readv, 3128 readvSync, 3129 readFile, 3130 readFileSync, 3131 readlink, 3132 readlinkSync, 3133 realpath, 3134 realpathSync, 3135 rename, 3136 renameSync, 3137 rm, 3138 rmSync, 3139 rmdir, 3140 rmdirSync, 3141 stat, 3142 statfs, 3143 statSync, 3144 statfsSync, 3145 symlink, 3146 symlinkSync, 3147 truncate, 3148 truncateSync, 3149 unwatchFile, 3150 unlink, 3151 unlinkSync, 3152 utimes, 3153 utimesSync, 3154 watch, 3155 watchFile, 3156 writeFile, 3157 writeFileSync, 3158 write, 3159 writeSync, 3160 writev, 3161 writevSync, 3162 Dirent, 3163 Stats, 3164 3165 get ReadStream() { 3166 lazyLoadStreams(); 3167 return ReadStream; 3168 }, 3169 3170 set ReadStream(val) { 3171 ReadStream = val; 3172 }, 3173 3174 get WriteStream() { 3175 lazyLoadStreams(); 3176 return WriteStream; 3177 }, 3178 3179 set WriteStream(val) { 3180 WriteStream = val; 3181 }, 3182 3183 // Legacy names... these have to be separate because of how graceful-fs 3184 // (and possibly other) modules monkey patch the values. 3185 get FileReadStream() { 3186 lazyLoadStreams(); 3187 return FileReadStream; 3188 }, 3189 3190 set FileReadStream(val) { 3191 FileReadStream = val; 3192 }, 3193 3194 get FileWriteStream() { 3195 lazyLoadStreams(); 3196 return FileWriteStream; 3197 }, 3198 3199 set FileWriteStream(val) { 3200 FileWriteStream = val; 3201 }, 3202 3203 // For tests 3204 _toUnixTimestamp: toUnixTimestamp, 3205}; 3206 3207defineLazyProperties( 3208 fs, 3209 'internal/fs/dir', 3210 ['Dir', 'opendir', 'opendirSync'], 3211); 3212 3213ObjectDefineProperties(fs, { 3214 F_OK: { __proto__: null, enumerable: true, value: F_OK || 0 }, 3215 R_OK: { __proto__: null, enumerable: true, value: R_OK || 0 }, 3216 W_OK: { __proto__: null, enumerable: true, value: W_OK || 0 }, 3217 X_OK: { __proto__: null, enumerable: true, value: X_OK || 0 }, 3218 constants: { 3219 __proto__: null, 3220 configurable: false, 3221 enumerable: true, 3222 value: constants, 3223 }, 3224 promises: { 3225 __proto__: null, 3226 configurable: true, 3227 enumerable: true, 3228 get() { 3229 promises ??= require('internal/fs/promises').exports; 3230 return promises; 3231 }, 3232 }, 3233}); 3234