2017-01-03 13:16:48 -08:00
|
|
|
// Copyright Joyent, Inc. and other Node contributors.
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
// copy of this software and associated documentation files (the
|
|
|
|
// "Software"), to deal in the Software without restriction, including
|
|
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
|
|
// persons to whom the Software is furnished to do so, subject to the
|
|
|
|
// following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included
|
|
|
|
// in all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
|
|
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
|
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
|
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
|
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
2015-01-10 23:12:37 +03:00
|
|
|
// Maintainers, keep in mind that ES1-style octal literals (`0666`) are not
|
|
|
|
// allowed in strict mode. Use ES6-style octal literals instead (`0o666`).
|
2011-11-04 13:10:07 +01:00
|
|
|
|
2014-11-22 16:59:48 +01:00
|
|
|
'use strict';
|
|
|
|
|
2019-11-22 18:04:46 +01:00
|
|
|
const {
|
2020-11-19 23:20:26 +01:00
|
|
|
ArrayPrototypePush,
|
|
|
|
BigIntPrototypeToString,
|
2019-11-22 18:04:46 +01:00
|
|
|
MathMax,
|
2020-06-18 18:49:59 +03:00
|
|
|
Number,
|
2019-11-22 18:04:46 +01:00
|
|
|
ObjectDefineProperties,
|
|
|
|
ObjectDefineProperty,
|
2019-12-13 16:46:35 +01:00
|
|
|
Promise,
|
2022-12-17 13:58:26 -08:00
|
|
|
PromiseResolve,
|
2020-11-19 23:20:26 +01:00
|
|
|
ReflectApply,
|
|
|
|
SafeMap,
|
2022-06-30 16:30:53 +08:00
|
|
|
SafeSet,
|
2020-11-19 23:20:26 +01:00
|
|
|
StringPrototypeCharCodeAt,
|
|
|
|
StringPrototypeIndexOf,
|
|
|
|
StringPrototypeSlice,
|
2019-11-22 18:04:46 +01:00
|
|
|
} = primordials;
|
2019-03-31 13:30:12 +02:00
|
|
|
|
2018-10-15 01:41:32 +02:00
|
|
|
const { fs: constants } = internalBinding('constants');
|
2018-05-14 16:36:37 -07:00
|
|
|
const {
|
|
|
|
S_IFIFO,
|
|
|
|
S_IFLNK,
|
|
|
|
S_IFMT,
|
|
|
|
S_IFREG,
|
|
|
|
S_IFSOCK,
|
|
|
|
F_OK,
|
|
|
|
R_OK,
|
|
|
|
W_OK,
|
|
|
|
X_OK,
|
|
|
|
O_WRONLY,
|
2023-02-20 01:58:32 +01:00
|
|
|
O_SYMLINK,
|
2018-05-14 16:36:37 -07:00
|
|
|
} = constants;
|
2018-05-15 12:34:49 -07:00
|
|
|
|
2015-01-21 11:36:59 -05:00
|
|
|
const pathModule = require('path');
|
2018-08-06 15:25:59 +05:30
|
|
|
const { isArrayBufferView } = require('internal/util/types');
|
2021-02-08 22:13:37 +08:00
|
|
|
|
|
|
|
// We need to get the statValues from the binding at the callsite since
|
|
|
|
// it's re-initialized after deserialization.
|
|
|
|
|
2018-08-23 23:29:40 +09:00
|
|
|
const binding = internalBinding('fs');
|
2022-12-17 13:58:26 -08:00
|
|
|
|
|
|
|
const { createBlobFromFilePath } = require('internal/blob');
|
|
|
|
|
2020-01-18 10:55:31 +01:00
|
|
|
const { Buffer } = require('buffer');
|
2018-02-27 14:55:32 +01:00
|
|
|
const {
|
2021-03-04 17:46:40 +01:00
|
|
|
aggregateTwoErrors,
|
2019-03-18 02:29:39 +01:00
|
|
|
codes: {
|
|
|
|
ERR_FS_FILE_TOO_LARGE,
|
|
|
|
ERR_INVALID_ARG_VALUE,
|
|
|
|
},
|
2021-03-11 07:59:53 -08:00
|
|
|
AbortError,
|
lib: add throws option to fs.f/l/statSync
For consumers that aren't interested in *why* a `statSync` call failed,
allocating and throwing an exception is an unnecessary expense. This PR
adds an option that will cause it to return `undefined` in such cases
instead.
As a motivating example, the JavaScript & TypeScript language service
shared between Visual Studio and Visual Studio Code is stuck with
synchronous file IO for architectural and backward-compatibility
reasons. It frequently needs to speculatively check for the existence
of files and directories that may not exist (and cares about file vs
directory, so `existsSync` is insufficient), but ignores file system
entries it can't access, regardless of the reason.
Benchmarking the language service is difficult because it's so hard to
get good coverage of both code bases and user behaviors, but, as a
representative metric, we measured batch compilation of a few hundred
popular projects (by star count) from GitHub and found that, on average,
we saved about 1-2% of total compilation time. We speculate that the
savings could be even more significant in interactive (language service
or watch mode) scenarios, where the same (non-existent) files need to be
polled over and over again. It's not a huge improvement, but it's a
very small change and it will affect a lot of users (and CI runs).
For reference, our measurements were against `v12.x` (3637a061a at the
time) on an Ubuntu Server desktop with an SSD.
PR-URL: https://github.com/nodejs/node/pull/33716
Reviewed-By: Denys Otrishko <shishugi@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
2020-06-03 01:18:58 +00:00
|
|
|
uvErrmapGet,
|
2023-02-20 01:58:32 +01:00
|
|
|
uvException,
|
2019-03-18 02:29:39 +01:00
|
|
|
} = require('internal/errors');
|
2018-05-15 12:34:49 -07:00
|
|
|
|
2021-02-08 22:13:37 +08:00
|
|
|
const { FSReqCallback } = binding;
|
2018-08-24 18:13:32 +02:00
|
|
|
const { toPathIfFileURL } = require('internal/url');
|
2022-05-21 17:52:23 +08:00
|
|
|
const {
|
|
|
|
customPromisifyArgs: kCustomPromisifyArgsSymbol,
|
|
|
|
kEmptyObject,
|
|
|
|
promisify: {
|
|
|
|
custom: kCustomPromisifiedSymbol,
|
|
|
|
},
|
2022-08-05 10:01:32 +02:00
|
|
|
SideEffectFreeRegExpPrototypeExec,
|
2022-12-09 23:37:35 +01:00
|
|
|
defineLazyProperties,
|
2022-05-21 17:52:23 +08:00
|
|
|
} = require('internal/util');
|
2017-10-07 22:50:42 +08:00
|
|
|
const {
|
2021-04-03 21:14:32 +05:30
|
|
|
constants: {
|
|
|
|
kIoMaxLength,
|
|
|
|
kMaxUserId,
|
|
|
|
},
|
2018-02-14 09:57:42 +01:00
|
|
|
copyObject,
|
2018-07-27 19:29:32 -07:00
|
|
|
Dirent,
|
2021-02-08 12:24:06 +01:00
|
|
|
emitRecursiveRmdirWarning,
|
2018-07-27 19:29:32 -07:00
|
|
|
getDirents,
|
2018-02-14 09:57:42 +01:00
|
|
|
getOptions,
|
2021-01-29 19:31:52 +05:30
|
|
|
getValidatedFd,
|
2019-05-12 20:30:29 +08:00
|
|
|
getValidatedPath,
|
2019-04-02 01:21:36 +02:00
|
|
|
getValidMode,
|
2019-08-27 17:14:27 -07:00
|
|
|
handleErrorFromBinding,
|
2018-02-14 09:57:42 +01:00
|
|
|
nullCheck,
|
|
|
|
preprocessSymlinkDestination,
|
|
|
|
Stats,
|
2023-01-29 12:43:20 -05:00
|
|
|
getStatFsFromBinding,
|
2018-03-31 04:02:57 +08:00
|
|
|
getStatsFromBinding,
|
2018-05-14 16:36:37 -07:00
|
|
|
realpathCacheKey,
|
2018-02-14 09:57:42 +01:00
|
|
|
stringToFlags,
|
|
|
|
stringToSymlinkType,
|
|
|
|
toUnixTimestamp,
|
2019-08-17 15:03:46 -04:00
|
|
|
validateBufferArray,
|
2021-08-08 13:48:01 -07:00
|
|
|
validateCpOptions,
|
2018-02-14 09:57:42 +01:00
|
|
|
validateOffsetLengthRead,
|
|
|
|
validateOffsetLengthWrite,
|
2019-03-29 09:17:55 -04:00
|
|
|
validatePath,
|
2021-01-24 19:43:05 +05:30
|
|
|
validatePosition,
|
2020-10-03 20:20:28 -06:00
|
|
|
validateRmOptions,
|
|
|
|
validateRmOptionsSync,
|
2019-08-16 13:17:21 -04:00
|
|
|
validateRmdirOptions,
|
2019-12-19 19:00:45 +01:00
|
|
|
validateStringAfterArrayBufferView,
|
2023-02-20 01:58:32 +01:00
|
|
|
warnOnNonPortableTemplate,
|
2018-12-21 16:07:22 +08:00
|
|
|
} = require('internal/fs/utils');
|
2018-02-13 14:49:53 +03:00
|
|
|
const {
|
|
|
|
CHAR_FORWARD_SLASH,
|
|
|
|
CHAR_BACKWARD_SLASH,
|
|
|
|
} = require('internal/constants');
|
2018-04-15 11:16:50 +02:00
|
|
|
const {
|
|
|
|
isUint32,
|
2019-04-02 01:21:36 +02:00
|
|
|
parseFileMode,
|
2021-01-18 19:39:25 +08:00
|
|
|
validateBoolean,
|
2019-03-20 13:15:48 +01:00
|
|
|
validateBuffer,
|
2021-04-09 21:39:43 -04:00
|
|
|
validateEncoding,
|
2021-01-24 15:46:24 +08:00
|
|
|
validateFunction,
|
2019-08-17 11:50:43 -04:00
|
|
|
validateInteger,
|
2022-05-03 02:01:27 +08:00
|
|
|
validateObject,
|
2021-06-14 03:37:54 +04:30
|
|
|
validateString,
|
2018-04-15 11:16:50 +02:00
|
|
|
} = require('internal/validators');
|
2010-03-11 14:32:10 -08:00
|
|
|
|
2018-05-15 12:34:49 -07:00
|
|
|
let truncateWarn = true;
|
|
|
|
let fs;
|
2018-05-03 14:40:48 -04:00
|
|
|
|
2018-05-15 12:34:49 -07:00
|
|
|
// Lazy loaded
|
2021-08-08 13:48:01 -07:00
|
|
|
let cpFn;
|
|
|
|
let cpSyncFn;
|
2018-12-02 12:08:26 -05:00
|
|
|
let promises = null;
|
2018-05-15 12:34:49 -07:00
|
|
|
let ReadStream;
|
|
|
|
let WriteStream;
|
2019-08-16 13:17:21 -04:00
|
|
|
let rimraf;
|
|
|
|
let rimrafSync;
|
2018-03-03 00:28:05 +08:00
|
|
|
|
2018-05-15 12:34:49 -07:00
|
|
|
// These have to be separate because of how graceful-fs happens to do it's
|
|
|
|
// monkeypatching.
|
|
|
|
let FileReadStream;
|
|
|
|
let FileWriteStream;
|
2010-05-24 15:47:40 -07:00
|
|
|
|
2015-01-21 11:36:59 -05:00
|
|
|
const isWindows = process.platform === 'win32';
|
2019-10-12 12:23:07 +03:00
|
|
|
const isOSX = process.platform === 'darwin';
|
2012-05-22 16:02:10 -07:00
|
|
|
|
2017-10-06 11:06:35 -07:00
|
|
|
function showTruncateDeprecation() {
|
|
|
|
if (truncateWarn) {
|
|
|
|
process.emitWarning(
|
|
|
|
'Using fs.truncate with a file descriptor is deprecated. Please use ' +
|
|
|
|
'fs.ftruncate with a file descriptor instead.',
|
|
|
|
'DeprecationWarning', 'DEP0081');
|
|
|
|
truncateWarn = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-22 16:38:36 -07:00
|
|
|
function maybeCallback(cb) {
|
2022-01-24 19:39:16 +03:30
|
|
|
validateFunction(cb, 'cb');
|
2018-02-09 00:54:31 +01:00
|
|
|
|
2020-12-23 19:22:00 +08:00
|
|
|
return cb;
|
2016-07-22 16:38:36 -07:00
|
|
|
}
|
|
|
|
|
2012-12-04 03:17:52 +01:00
|
|
|
// Ensure that callbacks run in the global context. Only use this function
|
|
|
|
// for callbacks that are passed to the binding layer, callbacks that are
|
|
|
|
// invoked from JS already run in the proper scope.
|
|
|
|
function makeCallback(cb) {
|
2022-01-24 19:39:16 +03:30
|
|
|
validateFunction(cb, 'cb');
|
2015-02-18 12:55:13 -05:00
|
|
|
|
2020-12-29 20:21:27 +01:00
|
|
|
return (...args) => ReflectApply(cb, this, args);
|
2012-12-04 03:17:52 +01:00
|
|
|
}
|
|
|
|
|
2017-03-11 19:41:20 -05:00
|
|
|
// Special case of `makeCallback()` that is specific to async `*stat()` calls as
|
|
|
|
// an optimization, since the data passed back to the callback needs to be
|
|
|
|
// transformed anyway.
|
|
|
|
function makeStatsCallback(cb) {
|
2022-01-24 19:39:16 +03:30
|
|
|
validateFunction(cb, 'cb');
|
2017-03-11 19:41:20 -05:00
|
|
|
|
2018-11-24 16:34:14 +09:00
|
|
|
return (err, stats) => {
|
2017-03-11 19:41:20 -05:00
|
|
|
if (err) return cb(err);
|
2018-03-31 04:02:57 +08:00
|
|
|
cb(err, getStatsFromBinding(stats));
|
2017-03-11 19:41:20 -05:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-04-26 13:22:14 +02:00
|
|
|
const isFd = isUint32;
|
2016-07-22 16:37:54 -07:00
|
|
|
|
2018-04-07 16:57:22 +08:00
|
|
|
function isFileType(stats, fileType) {
|
2018-02-11 21:29:19 +03:00
|
|
|
// Use stats array directly to avoid creating an fs.Stats instance just for
|
|
|
|
// our internal use.
|
2020-06-18 18:49:59 +03:00
|
|
|
let mode = stats[1];
|
|
|
|
if (typeof mode === 'bigint')
|
|
|
|
mode = Number(mode);
|
|
|
|
return (mode & S_IFMT) === fileType;
|
2018-02-11 21:29:19 +03:00
|
|
|
}
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Tests a user's permissions for the file or directory
|
|
|
|
* specified by `path`.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {number} [mode]
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function access(path, mode, callback) {
|
2014-12-15 10:44:46 -05:00
|
|
|
if (typeof mode === 'function') {
|
2016-07-22 16:38:36 -07:00
|
|
|
callback = mode;
|
2018-05-14 16:36:37 -07:00
|
|
|
mode = F_OK;
|
2014-12-15 10:44:46 -05:00
|
|
|
}
|
|
|
|
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2019-04-02 01:21:36 +02:00
|
|
|
mode = getValidMode(mode, 'access');
|
2020-10-03 22:44:20 +02:00
|
|
|
callback = makeCallback(callback);
|
|
|
|
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2020-10-03 22:44:20 +02:00
|
|
|
req.oncomplete = callback;
|
2017-08-20 22:44:47 -07:00
|
|
|
binding.access(pathModule.toNamespacedPath(path), mode, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2014-12-15 10:44:46 -05:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously tests a user's permissions for the file or
|
|
|
|
* directory specified by `path`.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {number} [mode]
|
2021-12-04 19:59:24 -08:00
|
|
|
* @returns {void}
|
2021-04-20 10:32:24 +04:30
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function accessSync(path, mode) {
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2019-04-02 01:21:36 +02:00
|
|
|
mode = getValidMode(mode, 'access');
|
2014-12-15 10:44:46 -05:00
|
|
|
|
2017-11-27 13:08:05 +09:00
|
|
|
const ctx = { path };
|
2017-11-21 04:47:57 +08:00
|
|
|
binding.access(pathModule.toNamespacedPath(path), mode, undefined, ctx);
|
2018-02-08 22:24:08 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2014-12-15 10:44:46 -05:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Tests whether or not the given path exists.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {(exists?: boolean) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function exists(path, callback) {
|
2018-02-09 00:54:31 +01:00
|
|
|
maybeCallback(callback);
|
2018-01-23 10:23:46 +08:00
|
|
|
|
|
|
|
function suppressedCallback(err) {
|
|
|
|
callback(err ? false : true);
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
2018-05-14 16:36:37 -07:00
|
|
|
fs.access(path, F_OK, suppressedCallback);
|
2018-11-04 09:52:28 -05:00
|
|
|
} catch {
|
2018-01-23 10:23:46 +08:00
|
|
|
return callback(false);
|
|
|
|
}
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2012-01-21 02:37:57 +01:00
|
|
|
|
2022-05-21 17:52:23 +08:00
|
|
|
ObjectDefineProperty(exists, kCustomPromisifiedSymbol, {
|
2022-06-03 10:23:58 +02:00
|
|
|
__proto__: null,
|
2022-05-27 00:04:09 +08:00
|
|
|
value: function exists(path) { // eslint-disable-line func-name-matching
|
2018-05-19 00:25:07 +02:00
|
|
|
return new Promise((resolve) => fs.exists(path, resolve));
|
2022-05-27 00:04:09 +08:00
|
|
|
},
|
2017-05-30 14:34:27 -07:00
|
|
|
});
|
|
|
|
|
2018-01-23 10:23:46 +08:00
|
|
|
// fs.existsSync never throws, it only returns true or false.
|
|
|
|
// Since fs.existsSync never throws, users have established
|
|
|
|
// the expectation that passing invalid arguments to it, even like
|
|
|
|
// fs.existsSync(), would only get a false in return, so we cannot signal
|
|
|
|
// validation errors to users properly out of compatibility concerns.
|
|
|
|
// TODO(joyeecheung): deprecate the never-throw-on-invalid-arguments behavior
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously tests whether or not the given path exists.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function existsSync(path) {
|
2012-01-21 02:37:57 +01:00
|
|
|
try {
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2018-11-04 09:52:28 -05:00
|
|
|
} catch {
|
2012-01-21 02:37:57 +01:00
|
|
|
return false;
|
|
|
|
}
|
2018-11-01 18:04:57 +08:00
|
|
|
const ctx = { path };
|
2019-11-22 14:01:21 +08:00
|
|
|
const nPath = pathModule.toNamespacedPath(path);
|
|
|
|
binding.access(nPath, F_OK, undefined, ctx);
|
|
|
|
|
|
|
|
// In case of an invalid symlink, `binding.access()` on win32
|
|
|
|
// will **not** return an error and is therefore not enough.
|
|
|
|
// Double check with `binding.stat()`.
|
|
|
|
if (isWindows && ctx.errno === undefined) {
|
|
|
|
binding.stat(nPath, false, undefined, ctx);
|
|
|
|
}
|
|
|
|
|
2018-11-01 18:04:57 +08:00
|
|
|
return ctx.errno === undefined;
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2015-02-03 22:07:02 +03:00
|
|
|
|
|
|
|
function readFileAfterOpen(err, fd) {
|
2018-05-15 12:34:49 -07:00
|
|
|
const context = this.context;
|
2015-02-03 22:07:02 +03:00
|
|
|
|
|
|
|
if (err) {
|
2015-06-03 03:41:04 +05:30
|
|
|
context.callback(err);
|
2015-02-03 22:07:02 +03:00
|
|
|
return;
|
2012-05-15 17:35:42 -07:00
|
|
|
}
|
|
|
|
|
2015-02-03 22:07:02 +03:00
|
|
|
context.fd = fd;
|
2012-06-11 14:49:31 -07:00
|
|
|
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2015-02-03 22:07:02 +03:00
|
|
|
req.oncomplete = readFileAfterStat;
|
|
|
|
req.context = context;
|
2018-04-07 17:01:06 +08:00
|
|
|
binding.fstat(fd, false, req);
|
2015-02-03 22:07:02 +03:00
|
|
|
}
|
|
|
|
|
2018-04-07 16:57:22 +08:00
|
|
|
function readFileAfterStat(err, stats) {
|
2018-05-15 12:34:49 -07:00
|
|
|
const context = this.context;
|
2015-02-03 22:07:02 +03:00
|
|
|
|
|
|
|
if (err)
|
|
|
|
return context.close(err);
|
|
|
|
|
2022-10-06 19:03:56 +02:00
|
|
|
// TODO(BridgeAR): Check if allocating a smaller chunk is better performance
|
|
|
|
// wise, similar to the promise based version (less peak memory and chunked
|
|
|
|
// stringify operations vs multiple C++/JS boundary crossings).
|
2018-05-15 12:34:49 -07:00
|
|
|
const size = context.size = isFileType(stats, S_IFREG) ? stats[8] : 0;
|
2015-02-03 22:07:02 +03:00
|
|
|
|
2020-01-18 10:55:31 +01:00
|
|
|
if (size > kIoMaxLength) {
|
2018-03-15 14:22:36 +01:00
|
|
|
err = new ERR_FS_FILE_TOO_LARGE(size);
|
2015-02-03 22:07:02 +03:00
|
|
|
return context.close(err);
|
|
|
|
}
|
|
|
|
|
2017-10-15 13:18:09 +02:00
|
|
|
try {
|
2019-04-03 02:58:31 +02:00
|
|
|
if (size === 0) {
|
2022-10-06 19:03:56 +02:00
|
|
|
// TODO(BridgeAR): If an encoding is set, use the StringDecoder to concat
|
|
|
|
// the result and reuse the buffer instead of allocating a new one.
|
2019-04-03 02:58:31 +02:00
|
|
|
context.buffers = [];
|
|
|
|
} else {
|
|
|
|
context.buffer = Buffer.allocUnsafeSlow(size);
|
|
|
|
}
|
2017-10-15 13:18:09 +02:00
|
|
|
} catch (err) {
|
|
|
|
return context.close(err);
|
|
|
|
}
|
2015-02-03 22:07:02 +03:00
|
|
|
context.read();
|
|
|
|
}
|
|
|
|
|
2021-03-11 07:59:53 -08:00
|
|
|
function checkAborted(signal, callback) {
|
|
|
|
if (signal?.aborted) {
|
2021-11-28 12:53:43 -08:00
|
|
|
callback(new AbortError(undefined, { cause: signal?.reason }));
|
2021-03-11 07:59:53 -08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Asynchronously reads the entire contents of a file.
|
|
|
|
* @param {string | Buffer | URL | number} path
|
|
|
|
* @param {{
|
|
|
|
* encoding?: string | null;
|
|
|
|
* flag?: string;
|
|
|
|
* signal?: AbortSignal;
|
|
|
|
* } | string} [options]
|
|
|
|
* @param {(
|
|
|
|
* err?: Error,
|
|
|
|
* data?: string | Buffer
|
|
|
|
* ) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function readFile(path, options, callback) {
|
|
|
|
callback = maybeCallback(callback || options);
|
|
|
|
options = getOptions(options, { flag: 'r' });
|
2022-12-09 23:37:35 +01:00
|
|
|
const ReadFileContext = require('internal/fs/read_file_context');
|
2018-05-15 12:34:49 -07:00
|
|
|
const context = new ReadFileContext(callback, options.encoding);
|
2019-03-22 03:44:26 +01:00
|
|
|
context.isUserFd = isFd(path); // File descriptor ownership
|
2015-02-03 22:07:02 +03:00
|
|
|
|
2020-11-01 18:22:20 +02:00
|
|
|
if (options.signal) {
|
|
|
|
context.signal = options.signal;
|
|
|
|
}
|
2018-05-15 12:34:49 -07:00
|
|
|
if (context.isUserFd) {
|
2020-10-03 22:44:20 +02:00
|
|
|
process.nextTick(function tick(context) {
|
2020-11-19 23:20:26 +01:00
|
|
|
ReflectApply(readFileAfterOpen, { context }, [null, path]);
|
2020-10-03 22:44:20 +02:00
|
|
|
}, context);
|
2018-05-15 12:34:49 -07:00
|
|
|
return;
|
2015-10-22 06:58:26 -05:00
|
|
|
}
|
2017-10-15 13:18:09 +02:00
|
|
|
|
2021-03-11 07:59:53 -08:00
|
|
|
if (checkAborted(options.signal, callback))
|
2021-02-16 20:08:58 +02:00
|
|
|
return;
|
|
|
|
|
2021-02-22 12:03:32 -08:00
|
|
|
const flagsNumber = stringToFlags(options.flag, 'options.flag');
|
2020-10-03 22:44:20 +02:00
|
|
|
path = getValidatedPath(path);
|
|
|
|
|
|
|
|
const req = new FSReqCallback();
|
|
|
|
req.context = context;
|
|
|
|
req.oncomplete = readFileAfterOpen;
|
2018-05-15 12:34:49 -07:00
|
|
|
binding.open(pathModule.toNamespacedPath(path),
|
2019-04-02 01:21:36 +02:00
|
|
|
flagsNumber,
|
2018-05-15 12:34:49 -07:00
|
|
|
0o666,
|
|
|
|
req);
|
2015-10-22 06:58:26 -05:00
|
|
|
}
|
2010-03-15 10:41:58 -07:00
|
|
|
|
2016-04-07 10:04:47 -04:00
|
|
|
function tryStatSync(fd, isUserFd) {
|
2017-12-28 23:16:33 +08:00
|
|
|
const ctx = {};
|
2018-04-07 17:01:06 +08:00
|
|
|
const stats = binding.fstat(fd, false, undefined, ctx);
|
2017-12-28 23:16:33 +08:00
|
|
|
if (ctx.errno !== undefined && !isUserFd) {
|
|
|
|
fs.closeSync(fd);
|
2019-03-18 02:29:39 +01:00
|
|
|
throw uvException(ctx);
|
2016-04-07 10:04:47 -04:00
|
|
|
}
|
2018-04-07 16:57:22 +08:00
|
|
|
return stats;
|
2016-04-07 10:04:47 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
function tryCreateBuffer(size, fd, isUserFd) {
|
2018-05-15 12:34:49 -07:00
|
|
|
let threw = true;
|
|
|
|
let buffer;
|
2016-04-07 10:04:47 -04:00
|
|
|
try {
|
2020-01-18 10:55:31 +01:00
|
|
|
if (size > kIoMaxLength) {
|
2018-03-15 14:22:36 +01:00
|
|
|
throw new ERR_FS_FILE_TOO_LARGE(size);
|
|
|
|
}
|
2016-04-07 10:04:47 -04:00
|
|
|
buffer = Buffer.allocUnsafe(size);
|
|
|
|
threw = false;
|
|
|
|
} finally {
|
|
|
|
if (threw && !isUserFd) fs.closeSync(fd);
|
|
|
|
}
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2017-01-15 00:44:19 +05:30
|
|
|
function tryReadSync(fd, isUserFd, buffer, pos, len) {
|
2018-05-15 12:34:49 -07:00
|
|
|
let threw = true;
|
|
|
|
let bytesRead;
|
2016-04-07 10:04:47 -04:00
|
|
|
try {
|
2017-01-15 00:44:19 +05:30
|
|
|
bytesRead = fs.readSync(fd, buffer, pos, len);
|
2016-04-07 10:04:47 -04:00
|
|
|
threw = false;
|
|
|
|
} finally {
|
|
|
|
if (threw && !isUserFd) fs.closeSync(fd);
|
|
|
|
}
|
|
|
|
return bytesRead;
|
|
|
|
}
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously reads the entire contents of a file.
|
|
|
|
* @param {string | Buffer | URL | number} path
|
|
|
|
* @param {{
|
|
|
|
* encoding?: string | null;
|
|
|
|
* flag?: string;
|
|
|
|
* }} [options]
|
|
|
|
* @returns {string | Buffer}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function readFileSync(path, options) {
|
2016-06-26 00:03:05 +05:30
|
|
|
options = getOptions(options, { flag: 'r' });
|
2019-03-22 03:44:26 +01:00
|
|
|
const isUserFd = isFd(path); // File descriptor ownership
|
2018-10-23 22:26:57 +02:00
|
|
|
const fd = isUserFd ? path : fs.openSync(path, options.flag, 0o666);
|
2010-09-22 17:58:08 -07:00
|
|
|
|
2018-04-07 16:57:22 +08:00
|
|
|
const stats = tryStatSync(fd, isUserFd);
|
2018-05-15 12:34:49 -07:00
|
|
|
const size = isFileType(stats, S_IFREG) ? stats[8] : 0;
|
|
|
|
let pos = 0;
|
2019-03-22 03:44:26 +01:00
|
|
|
let buffer; // Single buffer with file data
|
|
|
|
let buffers; // List for when size is unknown
|
2012-06-11 14:49:31 -07:00
|
|
|
|
2012-05-15 17:35:42 -07:00
|
|
|
if (size === 0) {
|
2012-06-11 14:49:31 -07:00
|
|
|
buffers = [];
|
|
|
|
} else {
|
2016-04-07 10:04:47 -04:00
|
|
|
buffer = tryCreateBuffer(size, fd, isUserFd);
|
2012-05-03 01:03:08 +02:00
|
|
|
}
|
2010-03-15 10:41:58 -07:00
|
|
|
|
2018-05-15 12:34:49 -07:00
|
|
|
let bytesRead;
|
2015-06-03 03:41:04 +05:30
|
|
|
|
2016-04-07 10:04:47 -04:00
|
|
|
if (size !== 0) {
|
|
|
|
do {
|
2017-01-15 00:44:19 +05:30
|
|
|
bytesRead = tryReadSync(fd, isUserFd, buffer, pos, size - pos);
|
2016-04-07 10:04:47 -04:00
|
|
|
pos += bytesRead;
|
|
|
|
} while (bytesRead !== 0 && pos < size);
|
|
|
|
} else {
|
|
|
|
do {
|
2019-03-07 01:03:53 +01:00
|
|
|
// The kernel lies about many files.
|
2016-04-07 10:04:47 -04:00
|
|
|
// Go ahead and try to read some bytes.
|
|
|
|
buffer = Buffer.allocUnsafe(8192);
|
2017-01-15 00:44:19 +05:30
|
|
|
bytesRead = tryReadSync(fd, isUserFd, buffer, 0, 8192);
|
2016-04-07 10:04:47 -04:00
|
|
|
if (bytesRead !== 0) {
|
2020-11-19 23:20:26 +01:00
|
|
|
ArrayPrototypePush(buffers, buffer.slice(0, bytesRead));
|
2012-06-11 14:49:31 -07:00
|
|
|
}
|
2016-04-07 10:04:47 -04:00
|
|
|
pos += bytesRead;
|
|
|
|
} while (bytesRead !== 0);
|
2010-05-29 13:38:00 -07:00
|
|
|
}
|
2010-09-22 17:58:08 -07:00
|
|
|
|
2015-10-03 02:06:42 +02:00
|
|
|
if (!isUserFd)
|
|
|
|
fs.closeSync(fd);
|
2012-05-15 17:35:42 -07:00
|
|
|
|
2012-06-11 14:49:31 -07:00
|
|
|
if (size === 0) {
|
2019-01-21 01:22:27 +01:00
|
|
|
// Data was collected into the buffers list.
|
2012-06-11 14:49:31 -07:00
|
|
|
buffer = Buffer.concat(buffers, pos);
|
2012-06-12 16:04:56 +02:00
|
|
|
} else if (pos < size) {
|
|
|
|
buffer = buffer.slice(0, pos);
|
2012-06-11 14:49:31 -07:00
|
|
|
}
|
|
|
|
|
2016-06-26 00:03:05 +05:30
|
|
|
if (options.encoding) buffer = buffer.toString(options.encoding);
|
2010-09-22 17:58:08 -07:00
|
|
|
return buffer;
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-02-01 11:55:12 -08:00
|
|
|
function defaultCloseCallback(err) {
|
|
|
|
if (err != null) throw err;
|
|
|
|
}
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Closes the file descriptor.
|
|
|
|
* @param {number} fd
|
|
|
|
* @param {(err?: Error) => any} [callback]
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2021-02-01 11:55:12 -08:00
|
|
|
function close(fd, callback = defaultCloseCallback) {
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2021-02-01 11:55:12 -08:00
|
|
|
if (callback !== defaultCloseCallback)
|
|
|
|
callback = makeCallback(callback);
|
2020-10-03 22:44:20 +02:00
|
|
|
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2020-10-03 22:44:20 +02:00
|
|
|
req.oncomplete = callback;
|
2016-07-22 16:37:54 -07:00
|
|
|
binding.close(fd, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously closes the file descriptor.
|
|
|
|
* @param {number} fd
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function closeSync(fd) {
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2017-11-26 12:44:20 -08:00
|
|
|
|
2017-11-29 12:52:16 +08:00
|
|
|
const ctx = {};
|
|
|
|
binding.close(fd, undefined, ctx);
|
2018-02-08 22:24:08 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Asynchronously opens a file.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {string | number} [flags]
|
|
|
|
* @param {string | number} [mode]
|
|
|
|
* @param {(
|
|
|
|
* err?: Error,
|
|
|
|
* fd?: number
|
|
|
|
* ) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function open(path, flags, mode, callback) {
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2018-10-23 22:26:57 +02:00
|
|
|
if (arguments.length < 3) {
|
|
|
|
callback = flags;
|
|
|
|
flags = 'r';
|
2018-05-09 22:44:44 +08:00
|
|
|
mode = 0o666;
|
2018-11-06 11:17:26 -08:00
|
|
|
} else if (typeof mode === 'function') {
|
2018-10-23 22:26:57 +02:00
|
|
|
callback = mode;
|
|
|
|
mode = 0o666;
|
2019-04-02 01:21:36 +02:00
|
|
|
} else {
|
|
|
|
mode = parseFileMode(mode, 'mode', 0o666);
|
2018-10-23 22:26:57 +02:00
|
|
|
}
|
|
|
|
const flagsNumber = stringToFlags(flags);
|
|
|
|
callback = makeCallback(callback);
|
2017-12-13 14:24:34 -08:00
|
|
|
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
|
|
|
|
2017-08-20 22:44:47 -07:00
|
|
|
binding.open(pathModule.toNamespacedPath(path),
|
2018-05-09 22:44:44 +08:00
|
|
|
flagsNumber,
|
2012-02-18 15:01:35 -08:00
|
|
|
mode,
|
2014-12-09 05:29:47 +01:00
|
|
|
req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously opens a file.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {string | number} [flags]
|
|
|
|
* @param {string | number} [mode]
|
|
|
|
* @returns {number}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function openSync(path, flags, mode) {
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2019-04-02 01:21:36 +02:00
|
|
|
const flagsNumber = stringToFlags(flags);
|
|
|
|
mode = parseFileMode(mode, 'mode', 0o666);
|
2017-12-13 14:24:34 -08:00
|
|
|
|
2018-02-14 11:08:52 -08:00
|
|
|
const ctx = { path };
|
|
|
|
const result = binding.open(pathModule.toNamespacedPath(path),
|
2018-05-09 22:44:44 +08:00
|
|
|
flagsNumber, mode,
|
2018-02-14 11:08:52 -08:00
|
|
|
undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
|
|
|
return result;
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2022-12-17 13:58:26 -08:00
|
|
|
/**
|
|
|
|
* @param {string | Buffer | URL } path
|
|
|
|
* @returns {Promise<Blob>}
|
|
|
|
*/
|
|
|
|
function openAsBlob(path, options = kEmptyObject) {
|
|
|
|
validateObject(options, 'options');
|
|
|
|
const type = options.type || '';
|
|
|
|
validateString(type, 'options.type');
|
|
|
|
// The underlying implementation here returns the Blob synchronously for now.
|
|
|
|
// To give ourselves flexibility to maybe return the Blob asynchronously,
|
|
|
|
// this API returns a Promise.
|
|
|
|
return PromiseResolve(createBlobFromFilePath(getValidatedPath(path), { type }));
|
|
|
|
}
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Reads file from the specified `fd` (file descriptor).
|
|
|
|
* @param {number} fd
|
|
|
|
* @param {Buffer | TypedArray | DataView} buffer
|
2022-05-03 02:01:27 +08:00
|
|
|
* @param {number} offsetOrOptions
|
2021-04-20 10:32:24 +04:30
|
|
|
* @param {number} length
|
2022-05-03 01:40:30 +08:00
|
|
|
* @param {number | bigint | null} position
|
2021-04-20 10:32:24 +04:30
|
|
|
* @param {(
|
|
|
|
* err?: Error,
|
|
|
|
* bytesRead?: number,
|
|
|
|
* buffer?: Buffer
|
|
|
|
* ) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2022-05-03 02:01:27 +08:00
|
|
|
function read(fd, buffer, offsetOrOptions, length, position, callback) {
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2020-01-16 09:46:28 -05:00
|
|
|
|
2022-05-03 02:01:27 +08:00
|
|
|
let offset = offsetOrOptions;
|
|
|
|
let params = null;
|
|
|
|
if (arguments.length <= 4) {
|
|
|
|
if (arguments.length === 4) {
|
|
|
|
// This is fs.read(fd, buffer, options, callback)
|
|
|
|
validateObject(offsetOrOptions, 'options', { nullable: true });
|
|
|
|
callback = length;
|
|
|
|
params = offsetOrOptions;
|
|
|
|
} else if (arguments.length === 3) {
|
|
|
|
// This is fs.read(fd, bufferOrParams, callback)
|
|
|
|
if (!isArrayBufferView(buffer)) {
|
|
|
|
// This is fs.read(fd, params, callback)
|
|
|
|
params = buffer;
|
2022-05-21 17:52:23 +08:00
|
|
|
({ buffer = Buffer.alloc(16384) } = params ?? kEmptyObject);
|
2022-05-03 02:01:27 +08:00
|
|
|
}
|
|
|
|
callback = offsetOrOptions;
|
|
|
|
} else {
|
2020-01-16 09:46:28 -05:00
|
|
|
// This is fs.read(fd, callback)
|
|
|
|
callback = buffer;
|
2022-05-03 02:01:27 +08:00
|
|
|
buffer = Buffer.alloc(16384);
|
2020-01-16 09:46:28 -05:00
|
|
|
}
|
|
|
|
|
2022-04-18 19:54:40 +08:00
|
|
|
if (params !== undefined) {
|
|
|
|
validateObject(params, 'options', { nullable: true });
|
|
|
|
}
|
2020-03-25 16:36:35 +08:00
|
|
|
({
|
|
|
|
offset = 0,
|
2022-09-28 17:44:39 +09:00
|
|
|
length = buffer?.byteLength - offset,
|
2022-04-04 19:07:50 +08:00
|
|
|
position = null,
|
2022-05-21 17:52:23 +08:00
|
|
|
} = params ?? kEmptyObject);
|
2020-01-16 09:46:28 -05:00
|
|
|
}
|
|
|
|
|
2017-12-13 19:54:09 -05:00
|
|
|
validateBuffer(buffer);
|
2018-08-06 01:17:25 +02:00
|
|
|
callback = maybeCallback(callback);
|
2017-11-26 20:51:01 -08:00
|
|
|
|
2019-03-18 11:27:13 -07:00
|
|
|
if (offset == null) {
|
|
|
|
offset = 0;
|
|
|
|
} else {
|
2021-04-26 10:58:41 -07:00
|
|
|
validateInteger(offset, 'offset', 0);
|
2019-03-18 11:27:13 -07:00
|
|
|
}
|
|
|
|
|
2017-11-26 20:51:01 -08:00
|
|
|
length |= 0;
|
|
|
|
|
2016-01-06 17:39:03 +01:00
|
|
|
if (length === 0) {
|
2018-04-30 02:08:20 -05:00
|
|
|
return process.nextTick(function tick() {
|
2018-08-06 01:17:25 +02:00
|
|
|
callback(null, 0, buffer);
|
2016-01-06 17:39:03 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-08-06 15:25:59 +05:30
|
|
|
if (buffer.byteLength === 0) {
|
2018-06-11 19:14:52 +05:30
|
|
|
throw new ERR_INVALID_ARG_VALUE('buffer', buffer,
|
|
|
|
'is empty and cannot be written');
|
|
|
|
}
|
|
|
|
|
2018-08-06 15:25:59 +05:30
|
|
|
validateOffsetLengthRead(offset, length, buffer.byteLength);
|
2017-11-26 20:51:01 -08:00
|
|
|
|
2020-11-20 19:25:41 +05:30
|
|
|
if (position == null)
|
2017-11-26 20:51:01 -08:00
|
|
|
position = -1;
|
|
|
|
|
2021-01-24 19:43:05 +05:30
|
|
|
validatePosition(position, 'position');
|
2020-11-20 19:25:41 +05:30
|
|
|
|
2011-03-23 12:29:49 +01:00
|
|
|
function wrapper(err, bytesRead) {
|
|
|
|
// Retain a reference to buffer so that it can't be GC'ed too soon.
|
2018-08-06 01:17:25 +02:00
|
|
|
callback(err, bytesRead || 0, buffer);
|
2011-03-23 12:29:49 +01:00
|
|
|
}
|
|
|
|
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = wrapper;
|
|
|
|
|
|
|
|
binding.read(fd, buffer, offset, length, position, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2022-05-21 17:52:23 +08:00
|
|
|
ObjectDefineProperty(read, kCustomPromisifyArgsSymbol,
|
2022-06-03 10:23:58 +02:00
|
|
|
{ __proto__: null, value: ['bytesRead', 'buffer'], enumerable: false });
|
2017-04-16 21:19:36 +02:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously reads the file from the
|
|
|
|
* specified `fd` (file descriptor).
|
|
|
|
* @param {number} fd
|
|
|
|
* @param {Buffer | TypedArray | DataView} buffer
|
|
|
|
* @param {{
|
|
|
|
* offset?: number;
|
|
|
|
* length?: number;
|
2022-05-03 01:40:30 +08:00
|
|
|
* position?: number | bigint | null;
|
2022-04-19 14:19:55 +08:00
|
|
|
* }} [offsetOrOptions]
|
2021-04-20 10:32:24 +04:30
|
|
|
* @returns {number}
|
|
|
|
*/
|
2022-04-19 14:19:55 +08:00
|
|
|
function readSync(fd, buffer, offsetOrOptions, length, position) {
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2020-03-24 11:23:33 -04:00
|
|
|
|
2021-04-10 17:20:30 +02:00
|
|
|
validateBuffer(buffer);
|
|
|
|
|
2022-04-19 14:19:55 +08:00
|
|
|
let offset = offsetOrOptions;
|
|
|
|
if (arguments.length <= 3 || typeof offsetOrOptions === 'object') {
|
|
|
|
if (offsetOrOptions !== undefined) {
|
|
|
|
validateObject(offsetOrOptions, 'options', { nullable: true });
|
|
|
|
}
|
2020-03-24 11:23:33 -04:00
|
|
|
|
2022-02-27 20:56:09 +08:00
|
|
|
({
|
|
|
|
offset = 0,
|
|
|
|
length = buffer.byteLength - offset,
|
2022-04-04 19:07:50 +08:00
|
|
|
position = null,
|
2022-04-19 14:19:55 +08:00
|
|
|
} = offsetOrOptions ?? kEmptyObject);
|
2020-03-24 11:23:33 -04:00
|
|
|
}
|
|
|
|
|
2022-04-19 14:19:55 +08:00
|
|
|
if (offset === undefined) {
|
2019-03-18 11:27:13 -07:00
|
|
|
offset = 0;
|
|
|
|
} else {
|
2021-04-26 10:58:41 -07:00
|
|
|
validateInteger(offset, 'offset', 0);
|
2019-03-18 11:27:13 -07:00
|
|
|
}
|
|
|
|
|
2017-11-26 20:51:01 -08:00
|
|
|
length |= 0;
|
|
|
|
|
2016-01-06 17:39:03 +01:00
|
|
|
if (length === 0) {
|
2017-01-10 14:26:23 +02:00
|
|
|
return 0;
|
2010-05-20 18:13:22 -04:00
|
|
|
}
|
|
|
|
|
2018-08-06 15:25:59 +05:30
|
|
|
if (buffer.byteLength === 0) {
|
2018-06-11 19:14:52 +05:30
|
|
|
throw new ERR_INVALID_ARG_VALUE('buffer', buffer,
|
|
|
|
'is empty and cannot be written');
|
|
|
|
}
|
|
|
|
|
2018-08-06 15:25:59 +05:30
|
|
|
validateOffsetLengthRead(offset, length, buffer.byteLength);
|
2017-11-26 20:51:01 -08:00
|
|
|
|
2020-11-20 19:25:41 +05:30
|
|
|
if (position == null)
|
2017-11-26 20:51:01 -08:00
|
|
|
position = -1;
|
|
|
|
|
2021-01-24 19:43:05 +05:30
|
|
|
validatePosition(position, 'position');
|
2020-11-20 19:25:41 +05:30
|
|
|
|
2018-02-28 01:21:19 +08:00
|
|
|
const ctx = {};
|
|
|
|
const result = binding.read(fd, buffer, offset, length, position,
|
|
|
|
undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
|
|
|
return result;
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Reads file from the specified `fd` (file descriptor)
|
|
|
|
* and writes to an array of `ArrayBufferView`s.
|
|
|
|
* @param {number} fd
|
|
|
|
* @param {ArrayBufferView[]} buffers
|
2022-05-03 01:40:30 +08:00
|
|
|
* @param {number | null} [position]
|
2021-04-20 10:32:24 +04:30
|
|
|
* @param {(
|
|
|
|
* err?: Error,
|
|
|
|
* bytesRead?: number,
|
|
|
|
* buffers?: ArrayBufferView[];
|
|
|
|
* ) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2020-03-17 00:50:27 +11:00
|
|
|
function readv(fd, buffers, position, callback) {
|
|
|
|
function wrapper(err, read) {
|
|
|
|
callback(err, read || 0, buffers);
|
|
|
|
}
|
|
|
|
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2020-03-17 00:50:27 +11:00
|
|
|
validateBufferArray(buffers);
|
2020-10-03 22:44:20 +02:00
|
|
|
callback = maybeCallback(callback || position);
|
2020-03-17 00:50:27 +11:00
|
|
|
|
|
|
|
const req = new FSReqCallback();
|
|
|
|
req.oncomplete = wrapper;
|
|
|
|
|
|
|
|
if (typeof position !== 'number')
|
|
|
|
position = null;
|
|
|
|
|
|
|
|
return binding.readBuffers(fd, buffers, position, req);
|
|
|
|
}
|
|
|
|
|
2022-05-21 17:52:23 +08:00
|
|
|
ObjectDefineProperty(readv, kCustomPromisifyArgsSymbol,
|
2022-06-03 10:23:58 +02:00
|
|
|
{ __proto__: null, value: ['bytesRead', 'buffers'], enumerable: false });
|
2020-05-27 12:55:15 -04:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously reads file from the
|
|
|
|
* specified `fd` (file descriptor) and writes to an array
|
|
|
|
* of `ArrayBufferView`s.
|
|
|
|
* @param {number} fd
|
|
|
|
* @param {ArrayBufferView[]} buffers
|
2022-05-03 01:40:30 +08:00
|
|
|
* @param {number | null} [position]
|
2021-04-20 10:32:24 +04:30
|
|
|
* @returns {number}
|
|
|
|
*/
|
2020-03-17 00:50:27 +11:00
|
|
|
function readvSync(fd, buffers, position) {
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2020-03-17 00:50:27 +11:00
|
|
|
validateBufferArray(buffers);
|
|
|
|
|
|
|
|
const ctx = {};
|
|
|
|
|
|
|
|
if (typeof position !== 'number')
|
|
|
|
position = null;
|
|
|
|
|
|
|
|
const result = binding.readBuffers(fd, buffers, position, undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Writes `buffer` to the specified `fd` (file descriptor).
|
|
|
|
* @param {number} fd
|
2022-09-12 18:29:43 +09:00
|
|
|
* @param {Buffer | TypedArray | DataView | string} buffer
|
2022-04-04 19:07:50 +08:00
|
|
|
* @param {number | object} [offsetOrOptions]
|
2021-04-20 10:32:24 +04:30
|
|
|
* @param {number} [length]
|
2022-05-03 01:40:30 +08:00
|
|
|
* @param {number | null} [position]
|
2021-04-20 10:32:24 +04:30
|
|
|
* @param {(
|
|
|
|
* err?: Error,
|
|
|
|
* bytesWritten?: number;
|
|
|
|
* buffer?: Buffer | TypedArray | DataView
|
|
|
|
* ) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2022-04-04 19:07:50 +08:00
|
|
|
function write(fd, buffer, offsetOrOptions, length, position, callback) {
|
2015-09-18 17:36:57 +09:00
|
|
|
function wrapper(err, written) {
|
2014-12-09 05:29:47 +01:00
|
|
|
// Retain a reference to buffer so that it can't be GC'ed too soon.
|
|
|
|
callback(err, written || 0, buffer);
|
|
|
|
}
|
|
|
|
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2017-12-13 14:24:34 -08:00
|
|
|
|
2022-04-04 19:07:50 +08:00
|
|
|
let offset = offsetOrOptions;
|
2018-08-06 15:25:59 +05:30
|
|
|
if (isArrayBufferView(buffer)) {
|
2016-07-23 22:43:41 +02:00
|
|
|
callback = maybeCallback(callback || position || length || offset);
|
2022-04-04 19:07:50 +08:00
|
|
|
|
|
|
|
if (typeof offset === 'object') {
|
|
|
|
({
|
|
|
|
offset = 0,
|
|
|
|
length = buffer.byteLength - offset,
|
|
|
|
position = null,
|
2022-05-21 17:52:23 +08:00
|
|
|
} = offsetOrOptions ?? kEmptyObject);
|
2022-04-04 19:07:50 +08:00
|
|
|
}
|
|
|
|
|
2019-03-27 15:23:59 -07:00
|
|
|
if (offset == null || typeof offset === 'function') {
|
2016-07-23 22:43:41 +02:00
|
|
|
offset = 0;
|
2019-03-27 15:23:59 -07:00
|
|
|
} else {
|
2021-04-26 10:58:41 -07:00
|
|
|
validateInteger(offset, 'offset', 0);
|
2019-03-27 15:23:59 -07:00
|
|
|
}
|
2017-12-13 14:24:34 -08:00
|
|
|
if (typeof length !== 'number')
|
2021-04-10 17:20:30 +02:00
|
|
|
length = buffer.byteLength - offset;
|
2017-12-13 14:24:34 -08:00
|
|
|
if (typeof position !== 'number')
|
2013-07-02 00:27:26 -07:00
|
|
|
position = null;
|
2017-12-22 18:33:31 -05:00
|
|
|
validateOffsetLengthWrite(offset, length, buffer.byteLength);
|
2019-12-19 19:00:45 +01:00
|
|
|
|
|
|
|
const req = new FSReqCallback();
|
|
|
|
req.oncomplete = wrapper;
|
2014-12-09 05:29:47 +01:00
|
|
|
return binding.writeBuffer(fd, buffer, offset, length, position, req);
|
2010-05-19 14:17:50 -04:00
|
|
|
}
|
2010-08-24 23:46:37 -04:00
|
|
|
|
2019-12-19 19:00:45 +01:00
|
|
|
validateStringAfterArrayBufferView(buffer, 'buffer');
|
|
|
|
|
2015-01-28 20:05:53 -05:00
|
|
|
if (typeof position !== 'function') {
|
|
|
|
if (typeof offset === 'function') {
|
2013-07-02 00:27:26 -07:00
|
|
|
position = offset;
|
|
|
|
offset = null;
|
|
|
|
} else {
|
|
|
|
position = length;
|
2010-08-24 23:46:37 -04:00
|
|
|
}
|
2013-07-02 00:27:26 -07:00
|
|
|
length = 'utf8';
|
2010-08-24 23:46:37 -04:00
|
|
|
}
|
2021-04-09 21:39:43 -04:00
|
|
|
|
2022-09-12 18:29:43 +09:00
|
|
|
const str = buffer;
|
2021-04-09 21:39:43 -04:00
|
|
|
validateEncoding(str, length);
|
2016-07-22 16:38:36 -07:00
|
|
|
callback = maybeCallback(position);
|
2019-12-19 19:00:45 +01:00
|
|
|
|
|
|
|
const req = new FSReqCallback();
|
|
|
|
req.oncomplete = wrapper;
|
2021-04-09 21:39:43 -04:00
|
|
|
return binding.writeString(fd, str, offset, length, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2022-05-21 17:52:23 +08:00
|
|
|
ObjectDefineProperty(write, kCustomPromisifyArgsSymbol,
|
2022-06-03 10:23:58 +02:00
|
|
|
{ __proto__: null, value: ['bytesWritten', 'buffer'], enumerable: false });
|
2017-04-16 21:19:36 +02:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously writes `buffer` to the
|
|
|
|
* specified `fd` (file descriptor).
|
|
|
|
* @param {number} fd
|
2022-04-04 18:57:59 +08:00
|
|
|
* @param {Buffer | TypedArray | DataView | string} buffer
|
2022-04-04 19:07:50 +08:00
|
|
|
* @param {{
|
|
|
|
* offset?: number;
|
|
|
|
* length?: number;
|
|
|
|
* position?: number | null;
|
|
|
|
* }} [offsetOrOptions]
|
2021-04-20 10:32:24 +04:30
|
|
|
* @returns {number}
|
|
|
|
*/
|
2022-04-04 19:07:50 +08:00
|
|
|
function writeSync(fd, buffer, offsetOrOptions, length, position) {
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2018-02-28 02:17:12 +08:00
|
|
|
const ctx = {};
|
|
|
|
let result;
|
2022-04-04 19:07:50 +08:00
|
|
|
|
|
|
|
let offset = offsetOrOptions;
|
2018-08-06 15:25:59 +05:30
|
|
|
if (isArrayBufferView(buffer)) {
|
2022-04-04 19:07:50 +08:00
|
|
|
if (typeof offset === 'object') {
|
|
|
|
({
|
|
|
|
offset = 0,
|
|
|
|
length = buffer.byteLength - offset,
|
2022-05-18 01:37:03 +08:00
|
|
|
position = null,
|
2022-05-21 17:52:23 +08:00
|
|
|
} = offsetOrOptions ?? kEmptyObject);
|
2022-04-04 19:07:50 +08:00
|
|
|
}
|
2015-01-28 20:05:53 -05:00
|
|
|
if (position === undefined)
|
2013-07-02 00:27:26 -07:00
|
|
|
position = null;
|
2019-03-27 15:23:59 -07:00
|
|
|
if (offset == null) {
|
2016-07-23 22:43:41 +02:00
|
|
|
offset = 0;
|
2019-03-27 15:23:59 -07:00
|
|
|
} else {
|
2021-04-26 10:58:41 -07:00
|
|
|
validateInteger(offset, 'offset', 0);
|
2019-03-27 15:23:59 -07:00
|
|
|
}
|
2016-07-23 22:43:41 +02:00
|
|
|
if (typeof length !== 'number')
|
2018-08-06 15:25:59 +05:30
|
|
|
length = buffer.byteLength - offset;
|
2017-12-22 18:33:31 -05:00
|
|
|
validateOffsetLengthWrite(offset, length, buffer.byteLength);
|
2018-02-28 02:17:12 +08:00
|
|
|
result = binding.writeBuffer(fd, buffer, offset, length, position,
|
|
|
|
undefined, ctx);
|
|
|
|
} else {
|
2022-09-12 18:29:43 +09:00
|
|
|
validateStringAfterArrayBufferView(buffer, 'buffer');
|
2021-04-09 21:39:43 -04:00
|
|
|
validateEncoding(buffer, length);
|
2019-12-19 19:00:45 +01:00
|
|
|
|
2018-02-28 02:17:12 +08:00
|
|
|
if (offset === undefined)
|
|
|
|
offset = null;
|
|
|
|
result = binding.writeString(fd, buffer, offset, length,
|
|
|
|
undefined, ctx);
|
2010-05-19 14:17:50 -04:00
|
|
|
}
|
2018-02-28 02:17:12 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
|
|
|
return result;
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Writes an array of `ArrayBufferView`s to the
|
|
|
|
* specified `fd` (file descriptor).
|
|
|
|
* @param {number} fd
|
|
|
|
* @param {ArrayBufferView[]} buffers
|
2022-05-03 01:40:30 +08:00
|
|
|
* @param {number | null} [position]
|
2021-04-20 10:32:24 +04:30
|
|
|
* @param {(
|
|
|
|
* err?: Error,
|
|
|
|
* bytesWritten?: number,
|
|
|
|
* buffers?: ArrayBufferView[]
|
|
|
|
* ) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2019-02-04 17:18:39 +01:00
|
|
|
function writev(fd, buffers, position, callback) {
|
|
|
|
function wrapper(err, written) {
|
|
|
|
callback(err, written || 0, buffers);
|
|
|
|
}
|
|
|
|
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2019-08-17 15:03:46 -04:00
|
|
|
validateBufferArray(buffers);
|
2020-10-03 22:44:20 +02:00
|
|
|
callback = maybeCallback(callback || position);
|
2019-02-04 17:18:39 +01:00
|
|
|
|
2022-02-11 12:32:10 +02:00
|
|
|
if (buffers.length === 0) {
|
|
|
|
process.nextTick(callback, null, 0, buffers);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-02-04 17:18:39 +01:00
|
|
|
const req = new FSReqCallback();
|
|
|
|
req.oncomplete = wrapper;
|
|
|
|
|
|
|
|
if (typeof position !== 'number')
|
|
|
|
position = null;
|
|
|
|
|
|
|
|
return binding.writeBuffers(fd, buffers, position, req);
|
|
|
|
}
|
|
|
|
|
2022-05-21 17:52:23 +08:00
|
|
|
ObjectDefineProperty(writev, kCustomPromisifyArgsSymbol, {
|
2022-06-03 10:23:58 +02:00
|
|
|
__proto__: null,
|
2019-02-04 17:18:39 +01:00
|
|
|
value: ['bytesWritten', 'buffer'],
|
2023-02-20 01:58:32 +01:00
|
|
|
enumerable: false,
|
2019-02-04 17:18:39 +01:00
|
|
|
});
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously writes an array of `ArrayBufferView`s
|
|
|
|
* to the specified `fd` (file descriptor).
|
|
|
|
* @param {number} fd
|
|
|
|
* @param {ArrayBufferView[]} buffers
|
2022-05-03 01:40:30 +08:00
|
|
|
* @param {number | null} [position]
|
2021-04-20 10:32:24 +04:30
|
|
|
* @returns {number}
|
|
|
|
*/
|
2019-02-04 17:18:39 +01:00
|
|
|
function writevSync(fd, buffers, position) {
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2019-08-17 15:03:46 -04:00
|
|
|
validateBufferArray(buffers);
|
2019-02-04 17:18:39 +01:00
|
|
|
|
2022-02-11 12:32:10 +02:00
|
|
|
if (buffers.length === 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-08-17 15:03:46 -04:00
|
|
|
const ctx = {};
|
2019-02-04 17:18:39 +01:00
|
|
|
|
|
|
|
if (typeof position !== 'number')
|
|
|
|
position = null;
|
|
|
|
|
|
|
|
const result = binding.writeBuffers(fd, buffers, position, undefined, ctx);
|
|
|
|
|
|
|
|
handleErrorFromBinding(ctx);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Asynchronously renames file at `oldPath` to
|
|
|
|
* the pathname provided as `newPath`.
|
|
|
|
* @param {string | Buffer | URL} oldPath
|
|
|
|
* @param {string | Buffer | URL} newPath
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function rename(oldPath, newPath, callback) {
|
2016-07-22 16:38:36 -07:00
|
|
|
callback = makeCallback(callback);
|
2019-05-12 20:30:29 +08:00
|
|
|
oldPath = getValidatedPath(oldPath, 'oldPath');
|
|
|
|
newPath = getValidatedPath(newPath, 'newPath');
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
2017-08-20 22:44:47 -07:00
|
|
|
binding.rename(pathModule.toNamespacedPath(oldPath),
|
|
|
|
pathModule.toNamespacedPath(newPath),
|
2014-12-09 05:29:47 +01:00
|
|
|
req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
|
|
|
|
/**
|
|
|
|
* Synchronously renames file at `oldPath` to
|
|
|
|
* the pathname provided as `newPath`.
|
|
|
|
* @param {string | Buffer | URL} oldPath
|
|
|
|
* @param {string | Buffer | URL} newPath
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function renameSync(oldPath, newPath) {
|
2019-05-12 20:30:29 +08:00
|
|
|
oldPath = getValidatedPath(oldPath, 'oldPath');
|
|
|
|
newPath = getValidatedPath(newPath, 'newPath');
|
2018-01-24 09:03:45 +08:00
|
|
|
const ctx = { path: oldPath, dest: newPath };
|
|
|
|
binding.rename(pathModule.toNamespacedPath(oldPath),
|
|
|
|
pathModule.toNamespacedPath(newPath), undefined, ctx);
|
2018-02-08 22:24:08 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Truncates the file.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {number} [len]
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function truncate(path, len, callback) {
|
2016-07-22 16:37:54 -07:00
|
|
|
if (typeof path === 'number') {
|
2017-10-06 11:06:35 -07:00
|
|
|
showTruncateDeprecation();
|
2015-02-07 19:27:20 +01:00
|
|
|
return fs.ftruncate(path, len, callback);
|
2016-07-22 16:37:54 -07:00
|
|
|
}
|
2016-07-22 16:38:36 -07:00
|
|
|
if (typeof len === 'function') {
|
|
|
|
callback = len;
|
|
|
|
len = 0;
|
|
|
|
} else if (len === undefined) {
|
2012-08-04 12:39:11 -07:00
|
|
|
len = 0;
|
|
|
|
}
|
2014-12-09 05:29:47 +01:00
|
|
|
|
2019-08-17 11:50:43 -04:00
|
|
|
validateInteger(len, 'len');
|
2021-02-22 13:19:14 -08:00
|
|
|
len = MathMax(0, len);
|
2016-07-22 16:38:36 -07:00
|
|
|
callback = maybeCallback(callback);
|
2018-11-24 16:34:14 +09:00
|
|
|
fs.open(path, 'r+', (er, fd) => {
|
2012-08-04 12:39:11 -07:00
|
|
|
if (er) return callback(er);
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2016-10-15 15:02:43 -07:00
|
|
|
req.oncomplete = function oncomplete(er) {
|
2018-11-24 16:34:14 +09:00
|
|
|
fs.close(fd, (er2) => {
|
2021-03-04 17:46:40 +01:00
|
|
|
callback(aggregateTwoErrors(er2, er));
|
2012-08-04 12:39:11 -07:00
|
|
|
});
|
2014-12-09 05:29:47 +01:00
|
|
|
};
|
|
|
|
binding.ftruncate(fd, len, req);
|
2012-08-04 12:39:11 -07:00
|
|
|
});
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously truncates the file.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {number} [len]
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function truncateSync(path, len) {
|
2016-07-22 16:37:54 -07:00
|
|
|
if (typeof path === 'number') {
|
|
|
|
// legacy
|
2017-10-06 11:06:35 -07:00
|
|
|
showTruncateDeprecation();
|
2012-08-08 23:07:18 +02:00
|
|
|
return fs.ftruncateSync(path, len);
|
2016-07-22 16:37:54 -07:00
|
|
|
}
|
|
|
|
if (len === undefined) {
|
2012-08-04 12:39:11 -07:00
|
|
|
len = 0;
|
|
|
|
}
|
2019-01-21 01:22:27 +01:00
|
|
|
// Allow error to be thrown, but still close fd.
|
2018-05-15 12:34:49 -07:00
|
|
|
const fd = fs.openSync(path, 'r+');
|
|
|
|
let ret;
|
2015-06-03 03:41:04 +05:30
|
|
|
|
2012-08-04 12:39:11 -07:00
|
|
|
try {
|
2015-06-03 03:41:04 +05:30
|
|
|
ret = fs.ftruncateSync(fd, len);
|
2012-08-04 12:39:11 -07:00
|
|
|
} finally {
|
|
|
|
fs.closeSync(fd);
|
|
|
|
}
|
|
|
|
return ret;
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2012-08-04 12:39:11 -07:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Truncates the file descriptor.
|
|
|
|
* @param {number} fd
|
|
|
|
* @param {number} [len]
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function ftruncate(fd, len = 0, callback) {
|
2016-07-22 16:38:36 -07:00
|
|
|
if (typeof len === 'function') {
|
|
|
|
callback = len;
|
|
|
|
len = 0;
|
2012-08-04 12:39:11 -07:00
|
|
|
}
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2019-08-17 11:50:43 -04:00
|
|
|
validateInteger(len, 'len');
|
2019-11-22 18:04:46 +01:00
|
|
|
len = MathMax(0, len);
|
2020-10-03 22:44:20 +02:00
|
|
|
callback = makeCallback(callback);
|
|
|
|
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2020-10-03 22:44:20 +02:00
|
|
|
req.oncomplete = callback;
|
2014-12-09 05:29:47 +01:00
|
|
|
binding.ftruncate(fd, len, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2012-08-04 12:39:11 -07:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously truncates the file descriptor.
|
|
|
|
* @param {number} fd
|
|
|
|
* @param {number} [len]
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function ftruncateSync(fd, len = 0) {
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2019-08-17 11:50:43 -04:00
|
|
|
validateInteger(len, 'len');
|
2019-11-22 18:04:46 +01:00
|
|
|
len = MathMax(0, len);
|
2018-01-24 09:20:30 +08:00
|
|
|
const ctx = {};
|
|
|
|
binding.ftruncate(fd, len, undefined, ctx);
|
2018-02-08 22:24:08 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-08-08 13:48:01 -07:00
|
|
|
function lazyLoadCp() {
|
|
|
|
if (cpFn === undefined) {
|
|
|
|
({ cpFn } = require('internal/fs/cp/cp'));
|
|
|
|
cpFn = require('util').callbackify(cpFn);
|
|
|
|
({ cpSyncFn } = require('internal/fs/cp/cp-sync'));
|
|
|
|
}
|
|
|
|
}
|
2019-08-16 13:17:21 -04:00
|
|
|
|
|
|
|
function lazyLoadRimraf() {
|
|
|
|
if (rimraf === undefined)
|
|
|
|
({ rimraf, rimrafSync } = require('internal/fs/rimraf'));
|
|
|
|
}
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Asynchronously removes a directory.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {{
|
|
|
|
* maxRetries?: number;
|
|
|
|
* recursive?: boolean;
|
|
|
|
* retryDelay?: number;
|
|
|
|
* }} [options]
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2019-08-16 13:17:21 -04:00
|
|
|
function rmdir(path, options, callback) {
|
|
|
|
if (typeof options === 'function') {
|
|
|
|
callback = options;
|
|
|
|
options = undefined;
|
|
|
|
}
|
|
|
|
|
2018-02-09 16:31:26 +01:00
|
|
|
callback = makeCallback(callback);
|
2019-08-16 13:17:21 -04:00
|
|
|
path = pathModule.toNamespacedPath(getValidatedPath(path));
|
|
|
|
|
2020-12-15 19:24:10 +08:00
|
|
|
if (options?.recursive) {
|
2021-02-08 12:24:06 +01:00
|
|
|
emitRecursiveRmdirWarning();
|
2020-10-30 07:50:22 -07:00
|
|
|
validateRmOptions(
|
2020-10-08 15:21:56 -06:00
|
|
|
path,
|
2021-02-03 20:18:50 +01:00
|
|
|
{ ...options, force: false },
|
2020-10-08 15:21:56 -06:00
|
|
|
true,
|
|
|
|
(err, options) => {
|
2021-02-03 20:18:50 +01:00
|
|
|
if (err === false) {
|
|
|
|
const req = new FSReqCallback();
|
|
|
|
req.oncomplete = callback;
|
|
|
|
return binding.rmdir(path, req);
|
|
|
|
}
|
2020-10-08 15:21:56 -06:00
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
lazyLoadRimraf();
|
2021-02-03 20:18:50 +01:00
|
|
|
rimraf(path, options, callback);
|
2020-10-08 15:21:56 -06:00
|
|
|
});
|
2020-10-03 20:20:28 -06:00
|
|
|
} else {
|
2020-10-08 21:32:56 -04:00
|
|
|
validateRmdirOptions(options);
|
2020-10-03 20:20:28 -06:00
|
|
|
const req = new FSReqCallback();
|
|
|
|
req.oncomplete = callback;
|
|
|
|
return binding.rmdir(path, req);
|
|
|
|
}
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously removes a directory.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {{
|
|
|
|
* maxRetries?: number;
|
|
|
|
* recursive?: boolean;
|
|
|
|
* retryDelay?: number;
|
|
|
|
* }} [options]
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2019-08-16 13:17:21 -04:00
|
|
|
function rmdirSync(path, options) {
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2019-08-16 13:17:21 -04:00
|
|
|
|
2020-12-15 19:24:10 +08:00
|
|
|
if (options?.recursive) {
|
2021-02-08 12:24:06 +01:00
|
|
|
emitRecursiveRmdirWarning();
|
2021-02-03 20:18:50 +01:00
|
|
|
options = validateRmOptionsSync(path, { ...options, force: false }, true);
|
|
|
|
if (options !== false) {
|
|
|
|
lazyLoadRimraf();
|
|
|
|
return rimrafSync(pathModule.toNamespacedPath(path), options);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
validateRmdirOptions(options);
|
2019-08-16 13:17:21 -04:00
|
|
|
}
|
|
|
|
|
2018-02-03 21:39:43 +08:00
|
|
|
const ctx = { path };
|
|
|
|
binding.rmdir(pathModule.toNamespacedPath(path), undefined, ctx);
|
2020-10-03 20:20:28 -06:00
|
|
|
return handleErrorFromBinding(ctx);
|
|
|
|
}
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Asynchronously removes files and
|
|
|
|
* directories (modeled on the standard POSIX `rm` utility).
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {{
|
|
|
|
* force?: boolean;
|
|
|
|
* maxRetries?: number;
|
|
|
|
* recursive?: boolean;
|
|
|
|
* retryDelay?: number;
|
|
|
|
* }} [options]
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2020-10-03 20:20:28 -06:00
|
|
|
function rm(path, options, callback) {
|
|
|
|
if (typeof options === 'function') {
|
|
|
|
callback = options;
|
|
|
|
options = undefined;
|
|
|
|
}
|
2021-12-13 15:45:09 +01:00
|
|
|
path = getValidatedPath(path);
|
2020-10-03 20:20:28 -06:00
|
|
|
|
2020-10-08 15:21:56 -06:00
|
|
|
validateRmOptions(path, options, false, (err, options) => {
|
2020-10-03 20:20:28 -06:00
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
|
|
|
lazyLoadRimraf();
|
|
|
|
return rimraf(pathModule.toNamespacedPath(path), options, callback);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously removes files and
|
|
|
|
* directories (modeled on the standard POSIX `rm` utility).
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {{
|
|
|
|
* force?: boolean;
|
|
|
|
* maxRetries?: number;
|
|
|
|
* recursive?: boolean;
|
|
|
|
* retryDelay?: number;
|
|
|
|
* }} [options]
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2020-10-03 20:20:28 -06:00
|
|
|
function rmSync(path, options) {
|
2021-12-13 15:45:09 +01:00
|
|
|
path = getValidatedPath(path);
|
2020-10-08 15:21:56 -06:00
|
|
|
options = validateRmOptionsSync(path, options, false);
|
2020-10-03 20:20:28 -06:00
|
|
|
|
|
|
|
lazyLoadRimraf();
|
|
|
|
return rimrafSync(pathModule.toNamespacedPath(path), options);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Forces all currently queued I/O operations associated
|
|
|
|
* with the file to the operating system's synchronized
|
|
|
|
* I/O completion state.
|
|
|
|
* @param {number} fd
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function fdatasync(fd, callback) {
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = makeCallback(callback);
|
2016-07-22 16:37:54 -07:00
|
|
|
binding.fdatasync(fd, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-22 07:25:24 +00:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously forces all currently queued I/O operations
|
|
|
|
* associated with the file to the operating
|
|
|
|
* system's synchronized I/O completion state.
|
|
|
|
* @param {number} fd
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function fdatasyncSync(fd) {
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2018-01-24 09:37:52 +08:00
|
|
|
const ctx = {};
|
|
|
|
binding.fdatasync(fd, undefined, ctx);
|
2018-02-08 22:24:08 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-22 07:25:24 +00:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Requests for all data for the open file descriptor
|
|
|
|
* to be flushed to the storage device.
|
|
|
|
* @param {number} fd
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function fsync(fd, callback) {
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2016-07-22 16:38:36 -07:00
|
|
|
req.oncomplete = makeCallback(callback);
|
2016-07-22 16:37:54 -07:00
|
|
|
binding.fsync(fd, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-22 07:25:24 +00:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously requests for all data for the open
|
|
|
|
* file descriptor to be flushed to the storage device.
|
|
|
|
* @param {number} fd
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function fsyncSync(fd) {
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2018-01-24 18:39:35 +08:00
|
|
|
const ctx = {};
|
|
|
|
binding.fsync(fd, undefined, ctx);
|
2018-02-08 22:24:08 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-22 07:25:24 +00:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Asynchronously creates a directory.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {{
|
|
|
|
* recursive?: boolean;
|
|
|
|
* mode?: string | number;
|
|
|
|
* } | number} [options]
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-08-09 16:52:41 -07:00
|
|
|
function mkdir(path, options, callback) {
|
2019-04-02 01:21:36 +02:00
|
|
|
let mode = 0o777;
|
|
|
|
let recursive = false;
|
2018-08-09 16:52:41 -07:00
|
|
|
if (typeof options === 'function') {
|
|
|
|
callback = options;
|
|
|
|
} else if (typeof options === 'number' || typeof options === 'string') {
|
2019-04-02 01:21:36 +02:00
|
|
|
mode = options;
|
|
|
|
} else if (options) {
|
|
|
|
if (options.recursive !== undefined)
|
|
|
|
recursive = options.recursive;
|
|
|
|
if (options.mode !== undefined)
|
|
|
|
mode = options.mode;
|
2018-08-09 16:52:41 -07:00
|
|
|
}
|
|
|
|
callback = makeCallback(callback);
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2018-05-09 22:44:44 +08:00
|
|
|
|
2021-01-18 19:39:25 +08:00
|
|
|
validateBoolean(recursive, 'options.recursive');
|
2017-12-13 14:24:34 -08:00
|
|
|
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
2018-08-09 16:52:41 -07:00
|
|
|
binding.mkdir(pathModule.toNamespacedPath(path),
|
2019-04-02 01:21:36 +02:00
|
|
|
parseFileMode(mode, 'mode'), recursive, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously creates a directory.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {{
|
|
|
|
* recursive?: boolean;
|
|
|
|
* mode?: string | number;
|
|
|
|
* } | number} [options]
|
|
|
|
* @returns {string | void}
|
|
|
|
*/
|
2018-08-09 16:52:41 -07:00
|
|
|
function mkdirSync(path, options) {
|
2019-04-02 01:21:36 +02:00
|
|
|
let mode = 0o777;
|
|
|
|
let recursive = false;
|
2018-08-09 16:52:41 -07:00
|
|
|
if (typeof options === 'number' || typeof options === 'string') {
|
2019-04-02 01:21:36 +02:00
|
|
|
mode = options;
|
|
|
|
} else if (options) {
|
|
|
|
if (options.recursive !== undefined)
|
|
|
|
recursive = options.recursive;
|
|
|
|
if (options.mode !== undefined)
|
|
|
|
mode = options.mode;
|
2018-08-09 16:52:41 -07:00
|
|
|
}
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2021-01-18 19:39:25 +08:00
|
|
|
validateBoolean(recursive, 'options.recursive');
|
2018-08-09 16:52:41 -07:00
|
|
|
|
2018-02-03 21:49:32 +08:00
|
|
|
const ctx = { path };
|
2020-01-28 23:06:44 -08:00
|
|
|
const result = binding.mkdir(pathModule.toNamespacedPath(path),
|
|
|
|
parseFileMode(mode, 'mode'), recursive,
|
|
|
|
undefined, ctx);
|
2018-02-03 21:49:32 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
2020-01-28 23:06:44 -08:00
|
|
|
if (recursive) {
|
|
|
|
return result;
|
|
|
|
}
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Reads the contents of a directory.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {string | {
|
|
|
|
* encoding?: string;
|
|
|
|
* withFileTypes?: boolean;
|
|
|
|
* }} [options]
|
|
|
|
* @param {(
|
|
|
|
* err?: Error,
|
|
|
|
* files?: string[] | Buffer[] | Direct[];
|
|
|
|
* ) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function readdir(path, options, callback) {
|
2016-06-26 00:03:05 +05:30
|
|
|
callback = makeCallback(typeof options === 'function' ? options : callback);
|
2022-05-21 17:52:23 +08:00
|
|
|
options = getOptions(options);
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2017-12-13 14:24:34 -08:00
|
|
|
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2018-07-27 19:29:32 -07:00
|
|
|
if (!options.withFileTypes) {
|
|
|
|
req.oncomplete = callback;
|
|
|
|
} else {
|
|
|
|
req.oncomplete = (err, result) => {
|
|
|
|
if (err) {
|
|
|
|
callback(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
getDirents(path, result, callback);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
binding.readdir(pathModule.toNamespacedPath(path), options.encoding,
|
|
|
|
!!options.withFileTypes, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously reads the contents of a directory.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {string | {
|
|
|
|
* encoding?: string;
|
|
|
|
* withFileTypes?: boolean;
|
|
|
|
* }} [options]
|
|
|
|
* @returns {string | Buffer[] | Dirent[]}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function readdirSync(path, options) {
|
2022-05-21 17:52:23 +08:00
|
|
|
options = getOptions(options);
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2018-02-03 22:45:30 +08:00
|
|
|
const ctx = { path };
|
|
|
|
const result = binding.readdir(pathModule.toNamespacedPath(path),
|
2018-07-27 19:29:32 -07:00
|
|
|
options.encoding, !!options.withFileTypes,
|
|
|
|
undefined, ctx);
|
2018-02-03 22:45:30 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
2018-07-27 19:29:32 -07:00
|
|
|
return options.withFileTypes ? getDirents(path, result) : result;
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Invokes the callback with the `fs.Stats`
|
|
|
|
* for the file descriptor.
|
|
|
|
* @param {number} fd
|
|
|
|
* @param {{ bigint?: boolean; }} [options]
|
|
|
|
* @param {(
|
|
|
|
* err?: Error,
|
|
|
|
* stats?: Stats
|
|
|
|
* ) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2019-08-14 00:15:10 -05:00
|
|
|
function fstat(fd, options = { bigint: false }, callback) {
|
2018-11-06 11:17:26 -08:00
|
|
|
if (typeof options === 'function') {
|
2018-04-07 17:01:06 +08:00
|
|
|
callback = options;
|
2022-05-21 17:52:23 +08:00
|
|
|
options = kEmptyObject;
|
2018-04-07 17:01:06 +08:00
|
|
|
}
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2020-10-03 22:44:20 +02:00
|
|
|
callback = makeStatsCallback(callback);
|
|
|
|
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback(options.bigint);
|
2020-10-03 22:44:20 +02:00
|
|
|
req.oncomplete = callback;
|
2018-04-07 17:01:06 +08:00
|
|
|
binding.fstat(fd, options.bigint, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-05-12 22:35:33 +02:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Retrieves the `fs.Stats` for the symbolic link
|
|
|
|
* referred to by the `path`.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {{ bigint?: boolean; }} [options]
|
|
|
|
* @param {(
|
|
|
|
* err?: Error,
|
|
|
|
* stats?: Stats
|
|
|
|
* ) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2019-08-14 00:15:10 -05:00
|
|
|
function lstat(path, options = { bigint: false }, callback) {
|
2018-11-06 11:17:26 -08:00
|
|
|
if (typeof options === 'function') {
|
2018-04-07 17:01:06 +08:00
|
|
|
callback = options;
|
2022-05-21 17:52:23 +08:00
|
|
|
options = kEmptyObject;
|
2018-04-07 17:01:06 +08:00
|
|
|
}
|
2017-03-11 19:41:20 -05:00
|
|
|
callback = makeStatsCallback(callback);
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2020-10-03 22:44:20 +02:00
|
|
|
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback(options.bigint);
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
2018-04-07 17:01:06 +08:00
|
|
|
binding.lstat(pathModule.toNamespacedPath(path), options.bigint, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Asynchronously gets the stats of a file.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {{ bigint?: boolean; }} [options]
|
|
|
|
* @param {(
|
|
|
|
* err?: Error,
|
|
|
|
* stats?: Stats
|
|
|
|
* ) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2019-08-14 00:15:10 -05:00
|
|
|
function stat(path, options = { bigint: false }, callback) {
|
2018-11-06 11:17:26 -08:00
|
|
|
if (typeof options === 'function') {
|
2018-04-07 17:01:06 +08:00
|
|
|
callback = options;
|
2022-05-21 17:52:23 +08:00
|
|
|
options = kEmptyObject;
|
2018-04-07 17:01:06 +08:00
|
|
|
}
|
2017-03-11 19:41:20 -05:00
|
|
|
callback = makeStatsCallback(callback);
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2020-10-03 22:44:20 +02:00
|
|
|
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback(options.bigint);
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
2018-04-07 17:01:06 +08:00
|
|
|
binding.stat(pathModule.toNamespacedPath(path), options.bigint, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2023-01-29 12:43:20 -05:00
|
|
|
function statfs(path, options = { bigint: false }, callback) {
|
|
|
|
if (typeof options === 'function') {
|
|
|
|
callback = options;
|
|
|
|
options = kEmptyObject;
|
|
|
|
}
|
|
|
|
callback = maybeCallback(callback);
|
|
|
|
path = getValidatedPath(path);
|
|
|
|
const req = new FSReqCallback(options.bigint);
|
|
|
|
req.oncomplete = (err, stats) => {
|
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
callback(err, getStatFsFromBinding(stats));
|
|
|
|
};
|
|
|
|
binding.statfs(pathModule.toNamespacedPath(path), options.bigint, req);
|
|
|
|
}
|
|
|
|
|
lib: add throws option to fs.f/l/statSync
For consumers that aren't interested in *why* a `statSync` call failed,
allocating and throwing an exception is an unnecessary expense. This PR
adds an option that will cause it to return `undefined` in such cases
instead.
As a motivating example, the JavaScript & TypeScript language service
shared between Visual Studio and Visual Studio Code is stuck with
synchronous file IO for architectural and backward-compatibility
reasons. It frequently needs to speculatively check for the existence
of files and directories that may not exist (and cares about file vs
directory, so `existsSync` is insufficient), but ignores file system
entries it can't access, regardless of the reason.
Benchmarking the language service is difficult because it's so hard to
get good coverage of both code bases and user behaviors, but, as a
representative metric, we measured batch compilation of a few hundred
popular projects (by star count) from GitHub and found that, on average,
we saved about 1-2% of total compilation time. We speculate that the
savings could be even more significant in interactive (language service
or watch mode) scenarios, where the same (non-existent) files need to be
polled over and over again. It's not a huge improvement, but it's a
very small change and it will affect a lot of users (and CI runs).
For reference, our measurements were against `v12.x` (3637a061a at the
time) on an Ubuntu Server desktop with an SSD.
PR-URL: https://github.com/nodejs/node/pull/33716
Reviewed-By: Denys Otrishko <shishugi@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
2020-06-03 01:18:58 +00:00
|
|
|
function hasNoEntryError(ctx) {
|
|
|
|
if (ctx.errno) {
|
|
|
|
const uvErr = uvErrmapGet(ctx.errno);
|
2020-12-15 19:24:10 +08:00
|
|
|
return uvErr?.[0] === 'ENOENT';
|
lib: add throws option to fs.f/l/statSync
For consumers that aren't interested in *why* a `statSync` call failed,
allocating and throwing an exception is an unnecessary expense. This PR
adds an option that will cause it to return `undefined` in such cases
instead.
As a motivating example, the JavaScript & TypeScript language service
shared between Visual Studio and Visual Studio Code is stuck with
synchronous file IO for architectural and backward-compatibility
reasons. It frequently needs to speculatively check for the existence
of files and directories that may not exist (and cares about file vs
directory, so `existsSync` is insufficient), but ignores file system
entries it can't access, regardless of the reason.
Benchmarking the language service is difficult because it's so hard to
get good coverage of both code bases and user behaviors, but, as a
representative metric, we measured batch compilation of a few hundred
popular projects (by star count) from GitHub and found that, on average,
we saved about 1-2% of total compilation time. We speculate that the
savings could be even more significant in interactive (language service
or watch mode) scenarios, where the same (non-existent) files need to be
polled over and over again. It's not a huge improvement, but it's a
very small change and it will affect a lot of users (and CI runs).
For reference, our measurements were against `v12.x` (3637a061a at the
time) on an Ubuntu Server desktop with an SSD.
PR-URL: https://github.com/nodejs/node/pull/33716
Reviewed-By: Denys Otrishko <shishugi@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
2020-06-03 01:18:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx.error) {
|
|
|
|
return ctx.error.code === 'ENOENT';
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously retrieves the `fs.Stats` for
|
|
|
|
* the file descriptor.
|
|
|
|
* @param {number} fd
|
|
|
|
* @param {{
|
|
|
|
* bigint?: boolean;
|
|
|
|
* }} [options]
|
|
|
|
* @returns {Stats}
|
|
|
|
*/
|
2022-09-15 02:16:01 +09:00
|
|
|
function fstatSync(fd, options = { bigint: false }) {
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2017-12-28 23:16:33 +08:00
|
|
|
const ctx = { fd };
|
2018-04-07 17:01:06 +08:00
|
|
|
const stats = binding.fstat(fd, options.bigint, undefined, ctx);
|
2018-02-08 22:24:08 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
2018-04-07 16:57:22 +08:00
|
|
|
return getStatsFromBinding(stats);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-05-12 22:35:33 +02:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously retrieves the `fs.Stats` for
|
|
|
|
* the symbolic link referred to by the `path`.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {{
|
|
|
|
* bigint?: boolean;
|
|
|
|
* throwIfNoEntry?: boolean;
|
|
|
|
* }} [options]
|
|
|
|
* @returns {Stats}
|
|
|
|
*/
|
lib: add throws option to fs.f/l/statSync
For consumers that aren't interested in *why* a `statSync` call failed,
allocating and throwing an exception is an unnecessary expense. This PR
adds an option that will cause it to return `undefined` in such cases
instead.
As a motivating example, the JavaScript & TypeScript language service
shared between Visual Studio and Visual Studio Code is stuck with
synchronous file IO for architectural and backward-compatibility
reasons. It frequently needs to speculatively check for the existence
of files and directories that may not exist (and cares about file vs
directory, so `existsSync` is insufficient), but ignores file system
entries it can't access, regardless of the reason.
Benchmarking the language service is difficult because it's so hard to
get good coverage of both code bases and user behaviors, but, as a
representative metric, we measured batch compilation of a few hundred
popular projects (by star count) from GitHub and found that, on average,
we saved about 1-2% of total compilation time. We speculate that the
savings could be even more significant in interactive (language service
or watch mode) scenarios, where the same (non-existent) files need to be
polled over and over again. It's not a huge improvement, but it's a
very small change and it will affect a lot of users (and CI runs).
For reference, our measurements were against `v12.x` (3637a061a at the
time) on an Ubuntu Server desktop with an SSD.
PR-URL: https://github.com/nodejs/node/pull/33716
Reviewed-By: Denys Otrishko <shishugi@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
2020-06-03 01:18:58 +00:00
|
|
|
function lstatSync(path, options = { bigint: false, throwIfNoEntry: true }) {
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2017-12-28 14:51:05 +08:00
|
|
|
const ctx = { path };
|
2018-04-07 16:57:22 +08:00
|
|
|
const stats = binding.lstat(pathModule.toNamespacedPath(path),
|
2018-04-07 17:01:06 +08:00
|
|
|
options.bigint, undefined, ctx);
|
lib: add throws option to fs.f/l/statSync
For consumers that aren't interested in *why* a `statSync` call failed,
allocating and throwing an exception is an unnecessary expense. This PR
adds an option that will cause it to return `undefined` in such cases
instead.
As a motivating example, the JavaScript & TypeScript language service
shared between Visual Studio and Visual Studio Code is stuck with
synchronous file IO for architectural and backward-compatibility
reasons. It frequently needs to speculatively check for the existence
of files and directories that may not exist (and cares about file vs
directory, so `existsSync` is insufficient), but ignores file system
entries it can't access, regardless of the reason.
Benchmarking the language service is difficult because it's so hard to
get good coverage of both code bases and user behaviors, but, as a
representative metric, we measured batch compilation of a few hundred
popular projects (by star count) from GitHub and found that, on average,
we saved about 1-2% of total compilation time. We speculate that the
savings could be even more significant in interactive (language service
or watch mode) scenarios, where the same (non-existent) files need to be
polled over and over again. It's not a huge improvement, but it's a
very small change and it will affect a lot of users (and CI runs).
For reference, our measurements were against `v12.x` (3637a061a at the
time) on an Ubuntu Server desktop with an SSD.
PR-URL: https://github.com/nodejs/node/pull/33716
Reviewed-By: Denys Otrishko <shishugi@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
2020-06-03 01:18:58 +00:00
|
|
|
if (options.throwIfNoEntry === false && hasNoEntryError(ctx)) {
|
|
|
|
return undefined;
|
|
|
|
}
|
2018-02-08 22:24:08 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
2018-04-07 16:57:22 +08:00
|
|
|
return getStatsFromBinding(stats);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously retrieves the `fs.Stats`
|
|
|
|
* for the `path`.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {{
|
|
|
|
* bigint?: boolean;
|
|
|
|
* throwIfNoEntry?: boolean;
|
|
|
|
* }} [options]
|
|
|
|
* @returns {Stats}
|
|
|
|
*/
|
lib: add throws option to fs.f/l/statSync
For consumers that aren't interested in *why* a `statSync` call failed,
allocating and throwing an exception is an unnecessary expense. This PR
adds an option that will cause it to return `undefined` in such cases
instead.
As a motivating example, the JavaScript & TypeScript language service
shared between Visual Studio and Visual Studio Code is stuck with
synchronous file IO for architectural and backward-compatibility
reasons. It frequently needs to speculatively check for the existence
of files and directories that may not exist (and cares about file vs
directory, so `existsSync` is insufficient), but ignores file system
entries it can't access, regardless of the reason.
Benchmarking the language service is difficult because it's so hard to
get good coverage of both code bases and user behaviors, but, as a
representative metric, we measured batch compilation of a few hundred
popular projects (by star count) from GitHub and found that, on average,
we saved about 1-2% of total compilation time. We speculate that the
savings could be even more significant in interactive (language service
or watch mode) scenarios, where the same (non-existent) files need to be
polled over and over again. It's not a huge improvement, but it's a
very small change and it will affect a lot of users (and CI runs).
For reference, our measurements were against `v12.x` (3637a061a at the
time) on an Ubuntu Server desktop with an SSD.
PR-URL: https://github.com/nodejs/node/pull/33716
Reviewed-By: Denys Otrishko <shishugi@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
2020-06-03 01:18:58 +00:00
|
|
|
function statSync(path, options = { bigint: false, throwIfNoEntry: true }) {
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2017-12-28 04:01:45 +08:00
|
|
|
const ctx = { path };
|
2018-04-07 16:57:22 +08:00
|
|
|
const stats = binding.stat(pathModule.toNamespacedPath(path),
|
2018-04-07 17:01:06 +08:00
|
|
|
options.bigint, undefined, ctx);
|
lib: add throws option to fs.f/l/statSync
For consumers that aren't interested in *why* a `statSync` call failed,
allocating and throwing an exception is an unnecessary expense. This PR
adds an option that will cause it to return `undefined` in such cases
instead.
As a motivating example, the JavaScript & TypeScript language service
shared between Visual Studio and Visual Studio Code is stuck with
synchronous file IO for architectural and backward-compatibility
reasons. It frequently needs to speculatively check for the existence
of files and directories that may not exist (and cares about file vs
directory, so `existsSync` is insufficient), but ignores file system
entries it can't access, regardless of the reason.
Benchmarking the language service is difficult because it's so hard to
get good coverage of both code bases and user behaviors, but, as a
representative metric, we measured batch compilation of a few hundred
popular projects (by star count) from GitHub and found that, on average,
we saved about 1-2% of total compilation time. We speculate that the
savings could be even more significant in interactive (language service
or watch mode) scenarios, where the same (non-existent) files need to be
polled over and over again. It's not a huge improvement, but it's a
very small change and it will affect a lot of users (and CI runs).
For reference, our measurements were against `v12.x` (3637a061a at the
time) on an Ubuntu Server desktop with an SSD.
PR-URL: https://github.com/nodejs/node/pull/33716
Reviewed-By: Denys Otrishko <shishugi@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
2020-06-03 01:18:58 +00:00
|
|
|
if (options.throwIfNoEntry === false && hasNoEntryError(ctx)) {
|
|
|
|
return undefined;
|
|
|
|
}
|
2018-02-08 22:24:08 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
2018-04-07 16:57:22 +08:00
|
|
|
return getStatsFromBinding(stats);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2023-01-29 12:43:20 -05:00
|
|
|
function statfsSync(path, options = { bigint: false }) {
|
|
|
|
path = getValidatedPath(path);
|
|
|
|
const ctx = { path };
|
|
|
|
const stats = binding.statfs(pathModule.toNamespacedPath(path),
|
|
|
|
options.bigint, undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
|
|
|
return getStatFsFromBinding(stats);
|
|
|
|
}
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Reads the contents of a symbolic link
|
|
|
|
* referred to by `path`.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {{ encoding?: string; } | string} [options]
|
|
|
|
* @param {(
|
|
|
|
* err?: Error,
|
|
|
|
* linkString?: string | Buffer
|
|
|
|
* ) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function readlink(path, options, callback) {
|
2016-06-26 00:03:05 +05:30
|
|
|
callback = makeCallback(typeof options === 'function' ? options : callback);
|
2022-05-21 17:52:23 +08:00
|
|
|
options = getOptions(options);
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path, 'oldPath');
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
2017-08-20 22:44:47 -07:00
|
|
|
binding.readlink(pathModule.toNamespacedPath(path), options.encoding, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously reads the contents of a symbolic link
|
|
|
|
* referred to by `path`.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {{ encoding?: string; } | string} [options]
|
|
|
|
* @returns {string | Buffer}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function readlinkSync(path, options) {
|
2022-05-21 17:52:23 +08:00
|
|
|
options = getOptions(options);
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path, 'oldPath');
|
2018-01-24 07:51:08 +08:00
|
|
|
const ctx = { path };
|
|
|
|
const result = binding.readlink(pathModule.toNamespacedPath(path),
|
|
|
|
options.encoding, undefined, ctx);
|
2018-02-08 22:24:08 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
2018-01-24 07:51:08 +08:00
|
|
|
return result;
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Creates the link called `path` pointing to `target`.
|
|
|
|
* @param {string | Buffer | URL} target
|
|
|
|
* @param {string | Buffer | URL} path
|
2022-05-03 01:40:30 +08:00
|
|
|
* @param {string | null} [type_]
|
2021-04-20 10:32:24 +04:30
|
|
|
* @param {(err?: Error) => any} callback_
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function symlink(target, path, type_, callback_) {
|
|
|
|
const type = (typeof type_ === 'string' ? type_ : null);
|
|
|
|
const callback = makeCallback(arguments[arguments.length - 1]);
|
2012-05-22 16:02:10 -07:00
|
|
|
|
2019-05-12 20:30:29 +08:00
|
|
|
target = getValidatedPath(target, 'target');
|
|
|
|
path = getValidatedPath(path);
|
2014-12-09 05:29:47 +01:00
|
|
|
|
2018-10-18 02:42:14 +02:00
|
|
|
if (isWindows && type === null) {
|
|
|
|
let absoluteTarget;
|
|
|
|
try {
|
|
|
|
// Symlinks targets can be relative to the newly created path.
|
|
|
|
// Calculate absolute file name of the symlink target, and check
|
|
|
|
// if it is a directory. Ignore resolve error to keep symlink
|
|
|
|
// errors consistent between platforms if invalid path is
|
|
|
|
// provided.
|
|
|
|
absoluteTarget = pathModule.resolve(path, '..', target);
|
2022-02-02 21:57:11 -08:00
|
|
|
} catch {
|
|
|
|
// Continue regardless of error.
|
|
|
|
}
|
2018-10-18 02:42:14 +02:00
|
|
|
if (absoluteTarget !== undefined) {
|
|
|
|
stat(absoluteTarget, (err, stat) => {
|
|
|
|
const resolvedType = !err && stat.isDirectory() ? 'dir' : 'file';
|
|
|
|
const resolvedFlags = stringToSymlinkType(resolvedType);
|
2020-10-03 22:44:20 +02:00
|
|
|
const destination = preprocessSymlinkDestination(target,
|
|
|
|
resolvedType,
|
|
|
|
path);
|
|
|
|
|
|
|
|
const req = new FSReqCallback();
|
|
|
|
req.oncomplete = callback;
|
|
|
|
binding.symlink(destination,
|
2018-10-18 02:42:14 +02:00
|
|
|
pathModule.toNamespacedPath(path), resolvedFlags, req);
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-03 22:44:20 +02:00
|
|
|
const destination = preprocessSymlinkDestination(target, type, path);
|
|
|
|
|
2018-10-18 02:42:14 +02:00
|
|
|
const flags = stringToSymlinkType(type);
|
2020-10-03 22:44:20 +02:00
|
|
|
const req = new FSReqCallback();
|
|
|
|
req.oncomplete = callback;
|
|
|
|
binding.symlink(destination, pathModule.toNamespacedPath(path), flags, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously creates the link called `path`
|
|
|
|
* pointing to `target`.
|
|
|
|
* @param {string | Buffer | URL} target
|
|
|
|
* @param {string | Buffer | URL} path
|
2022-05-03 01:40:30 +08:00
|
|
|
* @param {string | null} [type]
|
2021-04-20 10:32:24 +04:30
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function symlinkSync(target, path, type) {
|
2015-01-28 20:05:53 -05:00
|
|
|
type = (typeof type === 'string' ? type : null);
|
2018-10-18 02:42:14 +02:00
|
|
|
if (isWindows && type === null) {
|
2021-01-17 12:48:58 +01:00
|
|
|
const absoluteTarget = pathModule.resolve(`${path}`, '..', `${target}`);
|
|
|
|
if (statSync(absoluteTarget, { throwIfNoEntry: false })?.isDirectory()) {
|
|
|
|
type = 'dir';
|
|
|
|
}
|
2018-10-18 02:42:14 +02:00
|
|
|
}
|
2019-05-12 20:30:29 +08:00
|
|
|
target = getValidatedPath(target, 'target');
|
|
|
|
path = getValidatedPath(path);
|
2017-12-13 14:24:34 -08:00
|
|
|
const flags = stringToSymlinkType(type);
|
2018-01-24 06:53:47 +08:00
|
|
|
|
|
|
|
const ctx = { path: target, dest: path };
|
|
|
|
binding.symlink(preprocessSymlinkDestination(target, type, path),
|
|
|
|
pathModule.toNamespacedPath(path), flags, undefined, ctx);
|
|
|
|
|
2018-02-08 22:24:08 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Creates a new link from the `existingPath`
|
|
|
|
* to the `newPath`.
|
|
|
|
* @param {string | Buffer | URL} existingPath
|
|
|
|
* @param {string | Buffer | URL} newPath
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function link(existingPath, newPath, callback) {
|
2016-07-22 16:38:36 -07:00
|
|
|
callback = makeCallback(callback);
|
2017-01-11 07:02:40 -08:00
|
|
|
|
2019-05-12 20:30:29 +08:00
|
|
|
existingPath = getValidatedPath(existingPath, 'existingPath');
|
|
|
|
newPath = getValidatedPath(newPath, 'newPath');
|
2017-12-13 14:24:34 -08:00
|
|
|
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
|
|
|
|
2017-08-20 22:44:47 -07:00
|
|
|
binding.link(pathModule.toNamespacedPath(existingPath),
|
|
|
|
pathModule.toNamespacedPath(newPath),
|
2014-12-09 05:29:47 +01:00
|
|
|
req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously creates a new link from the `existingPath`
|
|
|
|
* to the `newPath`.
|
|
|
|
* @param {string | Buffer | URL} existingPath
|
|
|
|
* @param {string | Buffer | URL} newPath
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function linkSync(existingPath, newPath) {
|
2019-05-12 20:30:29 +08:00
|
|
|
existingPath = getValidatedPath(existingPath, 'existingPath');
|
|
|
|
newPath = getValidatedPath(newPath, 'newPath');
|
2018-01-24 07:03:11 +08:00
|
|
|
|
|
|
|
const ctx = { path: existingPath, dest: newPath };
|
|
|
|
const result = binding.link(pathModule.toNamespacedPath(existingPath),
|
|
|
|
pathModule.toNamespacedPath(newPath),
|
|
|
|
undefined, ctx);
|
2018-02-08 22:24:08 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
2018-01-24 07:03:11 +08:00
|
|
|
return result;
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Asynchronously removes a file or symbolic link.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function unlink(path, callback) {
|
2016-07-22 16:38:36 -07:00
|
|
|
callback = makeCallback(callback);
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
2017-08-20 22:44:47 -07:00
|
|
|
binding.unlink(pathModule.toNamespacedPath(path), req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously removes a file or symbolic link.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function unlinkSync(path) {
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2018-01-24 22:18:37 +08:00
|
|
|
const ctx = { path };
|
|
|
|
binding.unlink(pathModule.toNamespacedPath(path), undefined, ctx);
|
2018-02-08 22:24:08 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Sets the permissions on the file.
|
|
|
|
* @param {number} fd
|
|
|
|
* @param {string | number} mode
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function fchmod(fd, mode, callback) {
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2019-04-02 01:21:36 +02:00
|
|
|
mode = parseFileMode(mode, 'mode');
|
2018-05-09 22:44:44 +08:00
|
|
|
callback = makeCallback(callback);
|
2017-11-26 12:44:20 -08:00
|
|
|
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2018-05-09 22:44:44 +08:00
|
|
|
req.oncomplete = callback;
|
2017-11-26 12:44:20 -08:00
|
|
|
binding.fchmod(fd, mode, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2011-03-29 15:31:41 -07:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously sets the permissions on the file.
|
|
|
|
* @param {number} fd
|
|
|
|
* @param {string | number} mode
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function fchmodSync(fd, mode) {
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2019-04-02 01:21:36 +02:00
|
|
|
mode = parseFileMode(mode, 'mode');
|
2018-02-28 01:33:31 +08:00
|
|
|
const ctx = {};
|
|
|
|
binding.fchmod(fd, mode, undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2011-03-29 15:31:41 -07:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Changes the permissions on a symbolic link.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {number} mode
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function lchmod(path, mode, callback) {
|
|
|
|
callback = maybeCallback(callback);
|
2021-02-22 12:03:32 -08:00
|
|
|
mode = parseFileMode(mode, 'mode');
|
2018-11-24 16:34:14 +09:00
|
|
|
fs.open(path, O_WRONLY | O_SYMLINK, (err, fd) => {
|
2018-05-15 12:34:49 -07:00
|
|
|
if (err) {
|
|
|
|
callback(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Prefer to return the chmod error, if one occurs,
|
|
|
|
// but still try to close, and report closing errors if they occur.
|
2018-11-24 16:34:14 +09:00
|
|
|
fs.fchmod(fd, mode, (err) => {
|
|
|
|
fs.close(fd, (err2) => {
|
2021-03-04 17:46:40 +01:00
|
|
|
callback(aggregateTwoErrors(err2, err));
|
2011-11-22 13:10:57 -08:00
|
|
|
});
|
2011-03-29 16:34:05 -07:00
|
|
|
});
|
2018-05-15 12:34:49 -07:00
|
|
|
});
|
|
|
|
}
|
2011-03-29 16:34:05 -07:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously changes the permissions on a symbolic link.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {number} mode
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function lchmodSync(path, mode) {
|
|
|
|
const fd = fs.openSync(path, O_WRONLY | O_SYMLINK);
|
2011-11-22 13:10:57 -08:00
|
|
|
|
2018-05-15 12:34:49 -07:00
|
|
|
// Prefer to return the chmod error, if one occurs,
|
|
|
|
// but still try to close, and report closing errors if they occur.
|
|
|
|
let ret;
|
|
|
|
try {
|
|
|
|
ret = fs.fchmodSync(fd, mode);
|
|
|
|
} finally {
|
|
|
|
fs.closeSync(fd);
|
|
|
|
}
|
|
|
|
return ret;
|
2011-03-29 16:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Asynchronously changes the permissions of a file.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {string | number} mode
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function chmod(path, mode, callback) {
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2019-04-02 01:21:36 +02:00
|
|
|
mode = parseFileMode(mode, 'mode');
|
2018-05-09 22:44:44 +08:00
|
|
|
callback = makeCallback(callback);
|
2017-12-13 14:24:34 -08:00
|
|
|
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
2017-12-13 14:24:34 -08:00
|
|
|
binding.chmod(pathModule.toNamespacedPath(path), mode, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously changes the permissions of a file.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {string | number} mode
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function chmodSync(path, mode) {
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2019-04-02 01:21:36 +02:00
|
|
|
mode = parseFileMode(mode, 'mode');
|
2018-05-09 22:44:44 +08:00
|
|
|
|
2018-02-19 17:09:41 +08:00
|
|
|
const ctx = { path };
|
|
|
|
binding.chmod(pathModule.toNamespacedPath(path), mode, undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Sets the owner of the symbolic link.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {number} uid
|
|
|
|
* @param {number} gid
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function lchown(path, uid, gid, callback) {
|
2018-06-23 16:26:29 -04:00
|
|
|
callback = makeCallback(callback);
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2020-02-09 23:13:41 +08:00
|
|
|
validateInteger(uid, 'uid', -1, kMaxUserId);
|
|
|
|
validateInteger(gid, 'gid', -1, kMaxUserId);
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2018-06-23 16:26:29 -04:00
|
|
|
req.oncomplete = callback;
|
|
|
|
binding.lchown(pathModule.toNamespacedPath(path), uid, gid, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2011-03-29 16:34:05 -07:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously sets the owner of the symbolic link.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {number} uid
|
|
|
|
* @param {number} gid
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function lchownSync(path, uid, gid) {
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2020-02-09 23:13:41 +08:00
|
|
|
validateInteger(uid, 'uid', -1, kMaxUserId);
|
|
|
|
validateInteger(gid, 'gid', -1, kMaxUserId);
|
2018-06-23 16:26:29 -04:00
|
|
|
const ctx = { path };
|
|
|
|
binding.lchown(pathModule.toNamespacedPath(path), uid, gid, undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
2011-03-29 16:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Sets the owner of the file.
|
|
|
|
* @param {number} fd
|
|
|
|
* @param {number} uid
|
|
|
|
* @param {number} gid
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function fchown(fd, uid, gid, callback) {
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2020-02-09 23:13:41 +08:00
|
|
|
validateInteger(uid, 'uid', -1, kMaxUserId);
|
|
|
|
validateInteger(gid, 'gid', -1, kMaxUserId);
|
2020-10-03 22:44:20 +02:00
|
|
|
callback = makeCallback(callback);
|
2017-11-26 16:53:33 -08:00
|
|
|
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2020-10-03 22:44:20 +02:00
|
|
|
req.oncomplete = callback;
|
2016-07-22 16:37:54 -07:00
|
|
|
binding.fchown(fd, uid, gid, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2011-03-29 15:31:41 -07:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously sets the owner of the file.
|
|
|
|
* @param {number} fd
|
|
|
|
* @param {number} uid
|
|
|
|
* @param {number} gid
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function fchownSync(fd, uid, gid) {
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2020-02-09 23:13:41 +08:00
|
|
|
validateInteger(uid, 'uid', -1, kMaxUserId);
|
|
|
|
validateInteger(gid, 'gid', -1, kMaxUserId);
|
2017-11-26 16:53:33 -08:00
|
|
|
|
2018-02-28 01:45:17 +08:00
|
|
|
const ctx = {};
|
|
|
|
binding.fchown(fd, uid, gid, undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2011-03-29 15:31:41 -07:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Asynchronously changes the owner and group
|
|
|
|
* of a file.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {number} uid
|
|
|
|
* @param {number} gid
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function chown(path, uid, gid, callback) {
|
2016-07-22 16:38:36 -07:00
|
|
|
callback = makeCallback(callback);
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2020-02-09 23:13:41 +08:00
|
|
|
validateInteger(uid, 'uid', -1, kMaxUserId);
|
|
|
|
validateInteger(gid, 'gid', -1, kMaxUserId);
|
2017-12-13 14:24:34 -08:00
|
|
|
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
2017-08-20 22:44:47 -07:00
|
|
|
binding.chown(pathModule.toNamespacedPath(path), uid, gid, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-05-27 03:49:01 +10:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously changes the owner and group
|
|
|
|
* of a file.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {number} uid
|
|
|
|
* @param {number} gid
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function chownSync(path, uid, gid) {
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2020-02-09 23:13:41 +08:00
|
|
|
validateInteger(uid, 'uid', -1, kMaxUserId);
|
|
|
|
validateInteger(gid, 'gid', -1, kMaxUserId);
|
2018-02-20 03:35:39 +08:00
|
|
|
const ctx = { path };
|
|
|
|
binding.chown(pathModule.toNamespacedPath(path), uid, gid, undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-10-29 12:38:13 +02:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Changes the file system timestamps of the object
|
|
|
|
* referenced by `path`.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {number | string | Date} atime
|
|
|
|
* @param {number | string | Date} mtime
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function utimes(path, atime, mtime, callback) {
|
2016-07-22 16:38:36 -07:00
|
|
|
callback = makeCallback(callback);
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2017-12-13 14:24:34 -08:00
|
|
|
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
2017-08-20 22:44:47 -07:00
|
|
|
binding.utimes(pathModule.toNamespacedPath(path),
|
2012-06-06 21:33:29 +02:00
|
|
|
toUnixTimestamp(atime),
|
|
|
|
toUnixTimestamp(mtime),
|
2014-12-09 05:29:47 +01:00
|
|
|
req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-10-29 12:38:13 +02:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously changes the file system timestamps
|
|
|
|
* of the object referenced by `path`.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {number | string | Date} atime
|
|
|
|
* @param {number | string | Date} mtime
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function utimesSync(path, atime, mtime) {
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2018-02-20 04:23:47 +08:00
|
|
|
const ctx = { path };
|
2017-12-13 14:24:34 -08:00
|
|
|
binding.utimes(pathModule.toNamespacedPath(path),
|
2018-02-20 04:23:47 +08:00
|
|
|
toUnixTimestamp(atime), toUnixTimestamp(mtime),
|
|
|
|
undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-10-29 12:38:13 +02:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Changes the file system timestamps of the object
|
|
|
|
* referenced by the supplied `fd` (file descriptor).
|
|
|
|
* @param {number} fd
|
|
|
|
* @param {number | string | Date} atime
|
|
|
|
* @param {number | string | Date} mtime
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function futimes(fd, atime, mtime, callback) {
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2017-11-26 17:05:26 -08:00
|
|
|
atime = toUnixTimestamp(atime, 'atime');
|
|
|
|
mtime = toUnixTimestamp(mtime, 'mtime');
|
2020-10-03 22:44:20 +02:00
|
|
|
callback = makeCallback(callback);
|
|
|
|
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2020-10-03 22:44:20 +02:00
|
|
|
req.oncomplete = callback;
|
2014-12-09 05:29:47 +01:00
|
|
|
binding.futimes(fd, atime, mtime, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-10-29 12:38:13 +02:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously changes the file system timestamps
|
|
|
|
* of the object referenced by the
|
|
|
|
* supplied `fd` (file descriptor).
|
|
|
|
* @param {number} fd
|
|
|
|
* @param {number | string | Date} atime
|
|
|
|
* @param {number | string | Date} mtime
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function futimesSync(fd, atime, mtime) {
|
2021-01-29 19:31:52 +05:30
|
|
|
fd = getValidatedFd(fd);
|
2017-11-26 17:05:26 -08:00
|
|
|
atime = toUnixTimestamp(atime, 'atime');
|
|
|
|
mtime = toUnixTimestamp(mtime, 'mtime');
|
2018-02-28 02:25:02 +08:00
|
|
|
const ctx = {};
|
|
|
|
binding.futimes(fd, atime, mtime, undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-10-29 12:38:13 +02:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Changes the access and modification times of
|
|
|
|
* a file in the same way as `fs.utimes()`.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {number | string | Date} atime
|
|
|
|
* @param {number | string | Date} mtime
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2020-05-14 11:54:00 +02:00
|
|
|
function lutimes(path, atime, mtime, callback) {
|
|
|
|
callback = makeCallback(callback);
|
|
|
|
path = getValidatedPath(path);
|
|
|
|
|
|
|
|
const req = new FSReqCallback();
|
|
|
|
req.oncomplete = callback;
|
|
|
|
binding.lutimes(pathModule.toNamespacedPath(path),
|
|
|
|
toUnixTimestamp(atime),
|
|
|
|
toUnixTimestamp(mtime),
|
|
|
|
req);
|
|
|
|
}
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously changes the access and modification
|
|
|
|
* times of a file in the same way as `fs.utimesSync()`.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {number | string | Date} atime
|
|
|
|
* @param {number | string | Date} mtime
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2020-05-14 11:54:00 +02:00
|
|
|
function lutimesSync(path, atime, mtime) {
|
|
|
|
path = getValidatedPath(path);
|
|
|
|
const ctx = { path };
|
|
|
|
binding.lutimes(pathModule.toNamespacedPath(path),
|
|
|
|
toUnixTimestamp(atime),
|
|
|
|
toUnixTimestamp(mtime),
|
|
|
|
undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
|
|
|
}
|
|
|
|
|
2020-11-06 13:44:40 +02:00
|
|
|
function writeAll(fd, isUserFd, buffer, offset, length, signal, callback) {
|
|
|
|
if (signal?.aborted) {
|
2021-11-28 12:53:43 -08:00
|
|
|
const abortError = new AbortError(undefined, { cause: signal?.reason });
|
2021-02-16 20:08:58 +02:00
|
|
|
if (isUserFd) {
|
2021-03-04 17:46:40 +01:00
|
|
|
callback(abortError);
|
2021-02-16 20:08:58 +02:00
|
|
|
} else {
|
2021-03-04 17:46:40 +01:00
|
|
|
fs.close(fd, (err) => {
|
|
|
|
callback(aggregateTwoErrors(err, abortError));
|
2021-02-16 20:08:58 +02:00
|
|
|
});
|
|
|
|
}
|
2020-11-06 13:44:40 +02:00
|
|
|
return;
|
|
|
|
}
|
2010-11-13 20:12:47 -08:00
|
|
|
// write(fd, buffer, offset, length, position, callback)
|
2020-02-28 13:40:30 +01:00
|
|
|
fs.write(fd, buffer, offset, length, null, (writeErr, written) => {
|
2010-03-01 10:14:49 -08:00
|
|
|
if (writeErr) {
|
2015-10-03 02:06:42 +02:00
|
|
|
if (isUserFd) {
|
2016-01-21 17:35:10 +02:00
|
|
|
callback(writeErr);
|
2015-10-03 02:06:42 +02:00
|
|
|
} else {
|
2021-03-04 17:46:40 +01:00
|
|
|
fs.close(fd, (err) => {
|
|
|
|
callback(aggregateTwoErrors(err, writeErr));
|
2015-10-03 02:06:42 +02:00
|
|
|
});
|
|
|
|
}
|
2017-10-16 18:37:14 -04:00
|
|
|
} else if (written === length) {
|
|
|
|
if (isUserFd) {
|
|
|
|
callback(null);
|
2010-03-01 10:14:49 -08:00
|
|
|
} else {
|
2017-10-16 18:37:14 -04:00
|
|
|
fs.close(fd, callback);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
offset += written;
|
|
|
|
length -= written;
|
2020-11-06 13:44:40 +02:00
|
|
|
writeAll(fd, isUserFd, buffer, offset, length, signal, callback);
|
2010-03-01 10:14:49 -08:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Asynchronously writes data to the file.
|
|
|
|
* @param {string | Buffer | URL | number} path
|
2022-09-12 18:29:43 +09:00
|
|
|
* @param {string | Buffer | TypedArray | DataView} data
|
2021-04-20 10:32:24 +04:30
|
|
|
* @param {{
|
|
|
|
* encoding?: string | null;
|
|
|
|
* mode?: number;
|
|
|
|
* flag?: string;
|
|
|
|
* signal?: AbortSignal;
|
|
|
|
* } | string} [options]
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function writeFile(path, data, options, callback) {
|
2017-04-24 02:20:45 -04:00
|
|
|
callback = maybeCallback(callback || options);
|
2016-06-26 00:03:05 +05:30
|
|
|
options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'w' });
|
|
|
|
const flag = options.flag || 'w';
|
2015-10-03 02:06:42 +02:00
|
|
|
|
2019-12-19 19:00:45 +01:00
|
|
|
if (!isArrayBufferView(data)) {
|
|
|
|
validateStringAfterArrayBufferView(data, 'data');
|
2022-09-12 18:29:43 +09:00
|
|
|
data = Buffer.from(data, options.encoding || 'utf8');
|
2019-12-19 19:00:45 +01:00
|
|
|
}
|
|
|
|
|
2016-07-22 16:37:54 -07:00
|
|
|
if (isFd(path)) {
|
2019-12-19 19:00:45 +01:00
|
|
|
const isUserFd = true;
|
2020-11-06 13:44:40 +02:00
|
|
|
const signal = options.signal;
|
|
|
|
writeAll(path, isUserFd, data, 0, data.byteLength, signal, callback);
|
2015-10-03 02:06:42 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-03-11 07:59:53 -08:00
|
|
|
if (checkAborted(options.signal, callback))
|
2020-11-06 13:44:40 +02:00
|
|
|
return;
|
2021-03-11 07:59:53 -08:00
|
|
|
|
2018-11-24 16:34:14 +09:00
|
|
|
fs.open(path, flag, options.mode, (openErr, fd) => {
|
2010-03-01 10:14:49 -08:00
|
|
|
if (openErr) {
|
2016-01-21 17:35:10 +02:00
|
|
|
callback(openErr);
|
2010-03-01 10:14:49 -08:00
|
|
|
} else {
|
2019-12-19 19:00:45 +01:00
|
|
|
const isUserFd = false;
|
2020-11-06 13:44:40 +02:00
|
|
|
const signal = options.signal;
|
|
|
|
writeAll(fd, isUserFd, data, 0, data.byteLength, signal, callback);
|
2010-03-01 10:14:49 -08:00
|
|
|
}
|
|
|
|
});
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously writes data to the file.
|
|
|
|
* @param {string | Buffer | URL | number} path
|
2022-09-12 18:29:43 +09:00
|
|
|
* @param {string | Buffer | TypedArray | DataView} data
|
2021-04-20 10:32:24 +04:30
|
|
|
* @param {{
|
|
|
|
* encoding?: string | null;
|
|
|
|
* mode?: number;
|
|
|
|
* flag?: string;
|
|
|
|
* } | string} [options]
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function writeFileSync(path, data, options) {
|
2016-06-26 00:03:05 +05:30
|
|
|
options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'w' });
|
2019-12-19 19:00:45 +01:00
|
|
|
|
|
|
|
if (!isArrayBufferView(data)) {
|
|
|
|
validateStringAfterArrayBufferView(data, 'data');
|
2022-09-12 18:29:43 +09:00
|
|
|
data = Buffer.from(data, options.encoding || 'utf8');
|
2019-12-19 19:00:45 +01:00
|
|
|
}
|
|
|
|
|
2016-06-26 00:03:05 +05:30
|
|
|
const flag = options.flag || 'w';
|
2013-03-01 09:10:26 -08:00
|
|
|
|
2019-03-22 03:44:26 +01:00
|
|
|
const isUserFd = isFd(path); // File descriptor ownership
|
2018-05-15 12:34:49 -07:00
|
|
|
const fd = isUserFd ? path : fs.openSync(path, flag, options.mode);
|
2015-10-03 02:06:42 +02:00
|
|
|
|
2018-05-15 12:34:49 -07:00
|
|
|
let offset = 0;
|
2018-08-06 15:25:59 +05:30
|
|
|
let length = data.byteLength;
|
2012-05-03 01:03:08 +02:00
|
|
|
try {
|
2015-03-05 01:03:34 +01:00
|
|
|
while (length > 0) {
|
2020-02-28 13:40:30 +01:00
|
|
|
const written = fs.writeSync(fd, data, offset, length);
|
2015-03-05 01:03:34 +01:00
|
|
|
offset += written;
|
|
|
|
length -= written;
|
2012-05-03 01:03:08 +02:00
|
|
|
}
|
|
|
|
} finally {
|
2015-10-03 02:06:42 +02:00
|
|
|
if (!isUserFd) fs.closeSync(fd);
|
2010-03-01 10:14:49 -08:00
|
|
|
}
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:14:49 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Asynchronously appends data to a file.
|
|
|
|
* @param {string | Buffer | URL | number} path
|
|
|
|
* @param {string | Buffer} data
|
|
|
|
* @param {{
|
|
|
|
* encoding?: string | null;
|
|
|
|
* mode?: number;
|
|
|
|
* flag?: string;
|
|
|
|
* } | string} [options]
|
|
|
|
* @param {(err?: Error) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function appendFile(path, data, options, callback) {
|
2017-02-28 16:13:49 +02:00
|
|
|
callback = maybeCallback(callback || options);
|
2016-06-26 00:03:05 +05:30
|
|
|
options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'a' });
|
2011-11-02 16:06:16 -02:00
|
|
|
|
2016-10-09 19:37:59 +05:30
|
|
|
// Don't make changes directly on options object
|
|
|
|
options = copyObject(options);
|
2015-10-03 02:06:42 +02:00
|
|
|
|
2018-12-10 13:27:32 +01:00
|
|
|
// Force append behavior when using a supplied file descriptor
|
2016-10-09 19:37:59 +05:30
|
|
|
if (!options.flag || isFd(path))
|
2015-10-03 02:06:42 +02:00
|
|
|
options.flag = 'a';
|
|
|
|
|
2013-03-01 09:10:26 -08:00
|
|
|
fs.writeFile(path, data, options, callback);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2011-11-02 16:06:16 -02:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously appends data to a file.
|
|
|
|
* @param {string | Buffer | URL | number} path
|
|
|
|
* @param {string | Buffer} data
|
|
|
|
* @param {{
|
|
|
|
* encoding?: string | null;
|
|
|
|
* mode?: number;
|
|
|
|
* flag?: string;
|
|
|
|
* } | string} [options]
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function appendFileSync(path, data, options) {
|
2016-06-26 00:03:05 +05:30
|
|
|
options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'a' });
|
2015-10-03 02:06:42 +02:00
|
|
|
|
2016-10-09 19:37:59 +05:30
|
|
|
// Don't make changes directly on options object
|
|
|
|
options = copyObject(options);
|
2011-11-02 16:06:16 -02:00
|
|
|
|
2018-12-10 13:27:32 +01:00
|
|
|
// Force append behavior when using a supplied file descriptor
|
2016-10-09 19:37:59 +05:30
|
|
|
if (!options.flag || isFd(path))
|
2015-10-03 02:06:42 +02:00
|
|
|
options.flag = 'a';
|
|
|
|
|
2013-03-01 09:10:26 -08:00
|
|
|
fs.writeFileSync(path, data, options);
|
2018-04-09 15:00:18 -04:00
|
|
|
}
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Watches for the changes on `filename`.
|
|
|
|
* @param {string | Buffer | URL} filename
|
|
|
|
* @param {string | {
|
|
|
|
* persistent?: boolean;
|
|
|
|
* recursive?: boolean;
|
|
|
|
* encoding?: string;
|
|
|
|
* signal?: AbortSignal;
|
|
|
|
* }} [options]
|
|
|
|
* @param {(
|
|
|
|
* eventType?: string,
|
|
|
|
* filename?: string | Buffer
|
|
|
|
* ) => any} [listener]
|
|
|
|
* @returns {watchers.FSWatcher}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function watch(filename, options, listener) {
|
fs: Buffer and encoding enhancements to fs API
This makes several changes:
1. Allow path/filename to be passed in as a Buffer on fs methods
2. Add `options.encoding` to fs.readdir, fs.readdirSync, fs.readlink,
fs.readlinkSync and fs.watch.
3. Documentation updates
For 1... it's now possible to do:
```js
fs.open(Buffer('/fs/foo/bar'), 'w+', (err, fd) => { });
```
For 2...
```js
fs.readdir('/fs/foo/bar', {encoding:'hex'}, (err,list) => { });
fs.readdir('/fs/foo/bar', {encoding:'buffer'}, (err, list) => { });
```
encoding can also be passed as a string
```js
fs.readdir('/fs/foo/bar', 'hex', (err,list) => { });
```
The default encoding is set to UTF8 so this addresses the
discrepency that existed previously between fs.readdir and
fs.watch handling filenames differently.
Fixes: https://github.com/nodejs/node/issues/2088
Refs: https://github.com/nodejs/node/issues/3519
PR-URL: https://github.com/nodejs/node/pull/5616
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
2016-03-08 20:58:45 -08:00
|
|
|
if (typeof options === 'function') {
|
|
|
|
listener = options;
|
2011-09-22 16:18:08 -07:00
|
|
|
}
|
2022-05-21 17:52:23 +08:00
|
|
|
options = getOptions(options);
|
2011-09-22 16:18:08 -07:00
|
|
|
|
2016-10-09 19:37:59 +05:30
|
|
|
// Don't make changes directly on options object
|
|
|
|
options = copyObject(options);
|
|
|
|
|
2015-01-28 20:05:53 -05:00
|
|
|
if (options.persistent === undefined) options.persistent = true;
|
|
|
|
if (options.recursive === undefined) options.recursive = false;
|
2022-10-31 19:15:45 -04:00
|
|
|
|
|
|
|
let watcher;
|
2022-12-09 23:37:35 +01:00
|
|
|
const watchers = require('internal/fs/watchers');
|
2022-11-01 14:32:36 -04:00
|
|
|
// TODO(anonrig): Remove non-native watcher when/if libuv supports recursive.
|
2022-10-31 19:15:45 -04:00
|
|
|
// As of November 2022, libuv does not support recursive file watch on all platforms,
|
|
|
|
// e.g. Linux due to the limitations of inotify.
|
|
|
|
if (options.recursive && !isOSX && !isWindows) {
|
2022-12-09 23:37:35 +01:00
|
|
|
const nonNativeWatcher = require('internal/fs/recursive_watch');
|
2022-10-31 19:15:45 -04:00
|
|
|
watcher = new nonNativeWatcher.FSWatcher(options);
|
|
|
|
watcher[watchers.kFSWatchStart](filename);
|
|
|
|
} else {
|
|
|
|
watcher = new watchers.FSWatcher();
|
|
|
|
watcher[watchers.kFSWatchStart](filename,
|
|
|
|
options.persistent,
|
|
|
|
options.recursive,
|
|
|
|
options.encoding);
|
|
|
|
}
|
2011-09-22 16:18:08 -07:00
|
|
|
|
2012-05-19 23:05:43 +02:00
|
|
|
if (listener) {
|
|
|
|
watcher.addListener('change', listener);
|
|
|
|
}
|
2021-02-02 19:30:43 +02:00
|
|
|
if (options.signal) {
|
|
|
|
if (options.signal.aborted) {
|
|
|
|
process.nextTick(() => watcher.close());
|
|
|
|
} else {
|
|
|
|
const listener = () => watcher.close();
|
|
|
|
options.signal.addEventListener('abort', listener);
|
|
|
|
watcher.once('close', () => {
|
|
|
|
options.signal.removeEventListener('abort', listener);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2012-05-19 23:05:43 +02:00
|
|
|
|
2011-09-22 16:18:08 -07:00
|
|
|
return watcher;
|
2011-07-19 01:23:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-19 23:20:26 +01:00
|
|
|
const statWatchers = new SafeMap();
|
2011-07-19 01:23:50 -07:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Watches for changes on `filename`.
|
|
|
|
* @param {string | Buffer | URL} filename
|
|
|
|
* @param {{
|
|
|
|
* bigint?: boolean;
|
|
|
|
* persistent?: boolean;
|
|
|
|
* interval?: number;
|
|
|
|
* }} [options]
|
|
|
|
* @param {(
|
|
|
|
* current?: Stats,
|
|
|
|
* previous?: Stats
|
|
|
|
* ) => any} listener
|
|
|
|
* @returns {watchers.StatWatcher}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function watchFile(filename, options, listener) {
|
2019-05-12 20:30:29 +08:00
|
|
|
filename = getValidatedPath(filename);
|
2014-02-06 08:29:58 +02:00
|
|
|
filename = pathModule.resolve(filename);
|
2018-05-15 12:34:49 -07:00
|
|
|
let stat;
|
2010-03-01 10:42:37 -08:00
|
|
|
|
2018-12-18 03:15:57 +01:00
|
|
|
if (options === null || typeof options !== 'object') {
|
|
|
|
listener = options;
|
|
|
|
options = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
options = {
|
2012-06-21 15:03:21 +02:00
|
|
|
// Poll interval in milliseconds. 5007 is what libev used to use. It's
|
|
|
|
// a little on the slow side but let's stick with it for now to keep
|
|
|
|
// behavioral changes to a minimum.
|
|
|
|
interval: 5007,
|
2018-12-18 03:15:57 +01:00
|
|
|
persistent: true,
|
2023-02-20 01:58:32 +01:00
|
|
|
...options,
|
2012-06-21 15:03:21 +02:00
|
|
|
};
|
|
|
|
|
2021-01-24 15:46:24 +08:00
|
|
|
validateFunction(listener, 'listener');
|
2016-07-22 16:38:36 -07:00
|
|
|
|
2015-06-02 22:32:15 +05:30
|
|
|
stat = statWatchers.get(filename);
|
2022-12-09 23:37:35 +01:00
|
|
|
const watchers = require('internal/fs/watchers');
|
2015-06-02 22:32:15 +05:30
|
|
|
if (stat === undefined) {
|
2018-04-07 17:01:06 +08:00
|
|
|
stat = new watchers.StatWatcher(options.bigint);
|
2019-10-14 11:57:24 -04:00
|
|
|
stat[watchers.kFSStatWatcherStart](filename,
|
|
|
|
options.persistent, options.interval);
|
2015-06-02 22:32:15 +05:30
|
|
|
statWatchers.set(filename, stat);
|
2020-04-29 02:00:35 +08:00
|
|
|
} else {
|
|
|
|
stat[watchers.kFSStatWatcherAddOrCleanRef]('add');
|
2010-03-01 10:42:37 -08:00
|
|
|
}
|
2015-06-02 22:32:15 +05:30
|
|
|
|
2010-12-01 17:43:30 -08:00
|
|
|
stat.addListener('change', listener);
|
2010-03-01 10:42:37 -08:00
|
|
|
return stat;
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:42:37 -08:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Stops watching for changes on `filename`.
|
|
|
|
* @param {string | Buffer | URL} filename
|
|
|
|
* @param {() => any} [listener]
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function unwatchFile(filename, listener) {
|
2019-05-12 20:30:29 +08:00
|
|
|
filename = getValidatedPath(filename);
|
2014-02-06 08:29:58 +02:00
|
|
|
filename = pathModule.resolve(filename);
|
2018-05-15 12:34:49 -07:00
|
|
|
const stat = statWatchers.get(filename);
|
2012-07-08 16:31:07 +02:00
|
|
|
|
2015-06-02 22:32:15 +05:30
|
|
|
if (stat === undefined) return;
|
2022-12-09 23:37:35 +01:00
|
|
|
const watchers = require('internal/fs/watchers');
|
2015-01-28 20:05:53 -05:00
|
|
|
if (typeof listener === 'function') {
|
2020-04-29 02:00:35 +08:00
|
|
|
const beforeListenerCount = stat.listenerCount('change');
|
2012-07-08 16:31:07 +02:00
|
|
|
stat.removeListener('change', listener);
|
2020-04-29 02:00:35 +08:00
|
|
|
if (stat.listenerCount('change') < beforeListenerCount)
|
|
|
|
stat[watchers.kFSStatWatcherAddOrCleanRef]('clean');
|
2012-07-08 16:31:07 +02:00
|
|
|
} else {
|
|
|
|
stat.removeAllListeners('change');
|
2020-04-29 02:00:35 +08:00
|
|
|
stat[watchers.kFSStatWatcherAddOrCleanRef]('cleanAll');
|
2012-07-08 16:31:07 +02:00
|
|
|
}
|
|
|
|
|
2015-08-12 00:01:50 +05:30
|
|
|
if (stat.listenerCount('change') === 0) {
|
2010-03-01 10:42:37 -08:00
|
|
|
stat.stop();
|
2015-06-02 22:32:15 +05:30
|
|
|
statWatchers.delete(filename);
|
2010-03-01 10:42:37 -08:00
|
|
|
}
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-03-01 10:42:37 -08:00
|
|
|
|
2010-09-09 18:49:28 -07:00
|
|
|
|
2018-05-15 12:34:49 -07:00
|
|
|
let splitRoot;
|
2017-03-11 23:59:37 -05:00
|
|
|
if (isWindows) {
|
|
|
|
// Regex to find the device root on Windows (e.g. 'c:\\'), including trailing
|
|
|
|
// slash.
|
|
|
|
const splitRootRe = /^(?:[a-zA-Z]:|[\\/]{2}[^\\/]+[\\/][^\\/]+)?[\\/]*/;
|
|
|
|
splitRoot = function splitRoot(str) {
|
2022-08-05 10:01:32 +02:00
|
|
|
return SideEffectFreeRegExpPrototypeExec(splitRootRe, str)[0];
|
2017-03-11 23:59:37 -05:00
|
|
|
};
|
|
|
|
} else {
|
|
|
|
splitRoot = function splitRoot(str) {
|
2019-11-06 18:30:30 +03:00
|
|
|
for (let i = 0; i < str.length; ++i) {
|
2020-11-19 23:20:26 +01:00
|
|
|
if (StringPrototypeCharCodeAt(str, i) !== CHAR_FORWARD_SLASH)
|
|
|
|
return StringPrototypeSlice(str, 0, i);
|
2017-03-11 23:59:37 -05:00
|
|
|
}
|
|
|
|
return str;
|
|
|
|
};
|
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
|
2017-01-18 11:50:33 +08:00
|
|
|
function encodeRealpathResult(result, options) {
|
|
|
|
if (!options || !options.encoding || options.encoding === 'utf8')
|
2016-07-27 00:18:35 +02:00
|
|
|
return result;
|
|
|
|
const asBuffer = Buffer.from(result);
|
|
|
|
if (options.encoding === 'buffer') {
|
|
|
|
return asBuffer;
|
|
|
|
}
|
2020-04-08 18:58:03 +02:00
|
|
|
return asBuffer.toString(options.encoding);
|
2016-07-27 00:18:35 +02:00
|
|
|
}
|
|
|
|
|
2017-01-13 05:09:52 -05:00
|
|
|
// Finds the next portion of a (partial) path, up to the next path delimiter
|
2018-05-15 12:34:49 -07:00
|
|
|
let nextPart;
|
2017-01-13 05:09:52 -05:00
|
|
|
if (isWindows) {
|
|
|
|
nextPart = function nextPart(p, i) {
|
|
|
|
for (; i < p.length; ++i) {
|
2020-11-19 23:20:26 +01:00
|
|
|
const ch = StringPrototypeCharCodeAt(p, i);
|
2018-02-13 14:49:53 +03:00
|
|
|
|
|
|
|
// Check for a separator character
|
|
|
|
if (ch === CHAR_BACKWARD_SLASH || ch === CHAR_FORWARD_SLASH)
|
2017-01-13 05:09:52 -05:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
} else {
|
2020-11-19 23:20:26 +01:00
|
|
|
nextPart = function nextPart(p, i) {
|
|
|
|
return StringPrototypeIndexOf(p, '/', i);
|
|
|
|
};
|
2017-01-13 05:09:52 -05:00
|
|
|
}
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Returns the resolved pathname.
|
|
|
|
* @param {string | Buffer | URL} p
|
|
|
|
* @param {string | { encoding?: string | null; }} [options]
|
|
|
|
* @returns {string | Buffer}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function realpathSync(p, options) {
|
2022-05-21 17:52:23 +08:00
|
|
|
options = getOptions(options);
|
2018-08-24 18:13:32 +02:00
|
|
|
p = toPathIfFileURL(p);
|
2017-03-11 23:59:37 -05:00
|
|
|
if (typeof p !== 'string') {
|
2018-01-23 10:23:46 +08:00
|
|
|
p += '';
|
2017-03-11 23:59:37 -05:00
|
|
|
}
|
2018-01-23 10:23:46 +08:00
|
|
|
validatePath(p);
|
2016-07-27 00:18:35 +02:00
|
|
|
p = pathModule.resolve(p);
|
|
|
|
|
2018-05-14 16:36:37 -07:00
|
|
|
const cache = options[realpathCacheKey];
|
2020-12-15 19:24:10 +08:00
|
|
|
const maybeCachedResult = cache?.get(p);
|
2016-08-14 18:41:28 +02:00
|
|
|
if (maybeCachedResult) {
|
|
|
|
return maybeCachedResult;
|
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
|
2022-06-30 16:30:53 +08:00
|
|
|
const seenLinks = new SafeMap();
|
|
|
|
const knownHard = new SafeSet();
|
2017-01-13 05:07:18 -05:00
|
|
|
const original = p;
|
|
|
|
|
2019-03-07 01:03:53 +01:00
|
|
|
// Current character position in p
|
2018-05-15 12:34:49 -07:00
|
|
|
let pos;
|
2018-12-10 13:27:32 +01:00
|
|
|
// The partial path so far, including a trailing slash if any
|
2018-05-15 12:34:49 -07:00
|
|
|
let current;
|
2018-12-03 17:15:45 +01:00
|
|
|
// The partial path without a trailing slash (except when pointing at a root)
|
2018-05-15 12:34:49 -07:00
|
|
|
let base;
|
2018-12-10 13:27:32 +01:00
|
|
|
// The partial path scanned in the previous round, with slash
|
2018-05-15 12:34:49 -07:00
|
|
|
let previous;
|
2016-07-27 00:18:35 +02:00
|
|
|
|
2017-01-13 05:04:18 -05:00
|
|
|
// Skip over roots
|
2017-03-11 23:59:37 -05:00
|
|
|
current = base = splitRoot(p);
|
|
|
|
pos = current.length;
|
2016-07-27 00:18:35 +02:00
|
|
|
|
2017-01-13 05:04:18 -05:00
|
|
|
// On windows, check that the root exists. On unix there is no need.
|
2020-09-29 13:06:43 +08:00
|
|
|
if (isWindows) {
|
2017-12-28 14:51:05 +08:00
|
|
|
const ctx = { path: base };
|
2018-04-07 17:01:06 +08:00
|
|
|
binding.lstat(pathModule.toNamespacedPath(base), false, undefined, ctx);
|
2018-02-08 22:24:08 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
2022-06-30 16:30:53 +08:00
|
|
|
knownHard.add(base);
|
2016-07-27 00:18:35 +02:00
|
|
|
}
|
|
|
|
|
2018-12-03 17:15:45 +01:00
|
|
|
// Walk down the path, swapping out linked path parts for their real
|
2016-07-27 00:18:35 +02:00
|
|
|
// values
|
|
|
|
// NB: p.length changes.
|
|
|
|
while (pos < p.length) {
|
|
|
|
// find the next part
|
2018-05-15 12:34:49 -07:00
|
|
|
const result = nextPart(p, pos);
|
2016-07-27 00:18:35 +02:00
|
|
|
previous = current;
|
2017-01-13 05:09:52 -05:00
|
|
|
if (result === -1) {
|
2020-11-19 23:20:26 +01:00
|
|
|
const last = StringPrototypeSlice(p, pos);
|
2017-01-13 05:09:52 -05:00
|
|
|
current += last;
|
|
|
|
base = previous + last;
|
|
|
|
pos = p.length;
|
|
|
|
} else {
|
2020-11-19 23:20:26 +01:00
|
|
|
current += StringPrototypeSlice(p, pos, result + 1);
|
|
|
|
base = previous + StringPrototypeSlice(p, pos, result);
|
2017-01-13 05:09:52 -05:00
|
|
|
pos = result + 1;
|
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
|
2019-01-21 01:22:27 +01:00
|
|
|
// Continue if not a symlink, break if a pipe/socket
|
2022-06-30 16:30:53 +08:00
|
|
|
if (knownHard.has(base) || cache?.get(base) === base) {
|
2021-02-08 22:13:37 +08:00
|
|
|
if (isFileType(binding.statValues, S_IFIFO) ||
|
|
|
|
isFileType(binding.statValues, S_IFSOCK)) {
|
2017-05-15 03:27:54 +04:30
|
|
|
break;
|
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-05-15 12:34:49 -07:00
|
|
|
let resolvedLink;
|
2020-12-15 19:24:10 +08:00
|
|
|
const maybeCachedResolved = cache?.get(base);
|
2016-08-14 18:41:28 +02:00
|
|
|
if (maybeCachedResolved) {
|
|
|
|
resolvedLink = maybeCachedResolved;
|
|
|
|
} else {
|
2017-03-11 19:41:20 -05:00
|
|
|
// Use stats array directly to avoid creating an fs.Stats instance just
|
|
|
|
// for our internal use.
|
|
|
|
|
2018-05-15 12:34:49 -07:00
|
|
|
const baseLong = pathModule.toNamespacedPath(base);
|
2017-12-28 14:51:05 +08:00
|
|
|
const ctx = { path: base };
|
2020-06-18 18:49:59 +03:00
|
|
|
const stats = binding.lstat(baseLong, true, undefined, ctx);
|
2018-02-08 22:24:08 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
2017-03-11 19:41:20 -05:00
|
|
|
|
2018-04-07 16:57:22 +08:00
|
|
|
if (!isFileType(stats, S_IFLNK)) {
|
2022-06-30 16:30:53 +08:00
|
|
|
knownHard.add(base);
|
2020-12-15 19:24:10 +08:00
|
|
|
cache?.set(base, base);
|
2016-08-14 18:41:28 +02:00
|
|
|
continue;
|
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
|
2019-03-07 01:03:53 +01:00
|
|
|
// Read the link if it wasn't read before
|
2016-08-14 18:41:28 +02:00
|
|
|
// dev/ino always return 0 on windows, so skip the check.
|
2018-05-15 12:34:49 -07:00
|
|
|
let linkTarget = null;
|
|
|
|
let id;
|
2016-08-14 18:41:28 +02:00
|
|
|
if (!isWindows) {
|
2020-11-19 23:20:26 +01:00
|
|
|
const dev = BigIntPrototypeToString(stats[0], 32);
|
|
|
|
const ino = BigIntPrototypeToString(stats[7], 32);
|
2017-03-11 19:41:20 -05:00
|
|
|
id = `${dev}:${ino}`;
|
2022-06-30 16:30:53 +08:00
|
|
|
if (seenLinks.has(id)) {
|
|
|
|
linkTarget = seenLinks.get(id);
|
2016-08-14 18:41:28 +02:00
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
}
|
2016-08-14 18:41:28 +02:00
|
|
|
if (linkTarget === null) {
|
2017-12-28 04:01:45 +08:00
|
|
|
const ctx = { path: base };
|
2018-04-07 17:01:06 +08:00
|
|
|
binding.stat(baseLong, false, undefined, ctx);
|
2018-02-08 22:24:08 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
2018-01-24 07:51:08 +08:00
|
|
|
linkTarget = binding.readlink(baseLong, undefined, undefined, ctx);
|
2018-02-08 22:24:08 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
2016-08-14 18:41:28 +02:00
|
|
|
}
|
|
|
|
resolvedLink = pathModule.resolve(previous, linkTarget);
|
2016-07-27 00:18:35 +02:00
|
|
|
|
2022-02-11 21:02:12 +08:00
|
|
|
cache?.set(base, resolvedLink);
|
2022-06-30 16:30:53 +08:00
|
|
|
if (!isWindows) seenLinks.set(id, linkTarget);
|
2016-08-14 18:41:28 +02:00
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
|
2019-03-07 01:03:53 +01:00
|
|
|
// Resolve the link, then start over
|
2020-11-19 23:20:26 +01:00
|
|
|
p = pathModule.resolve(resolvedLink, StringPrototypeSlice(p, pos));
|
2017-01-13 05:04:18 -05:00
|
|
|
|
|
|
|
// Skip over roots
|
2017-03-11 23:59:37 -05:00
|
|
|
current = base = splitRoot(p);
|
|
|
|
pos = current.length;
|
2017-01-13 05:04:18 -05:00
|
|
|
|
|
|
|
// On windows, check that the root exists. On unix there is no need.
|
2022-06-30 16:30:53 +08:00
|
|
|
if (isWindows && !knownHard.has(base)) {
|
2017-12-28 14:51:05 +08:00
|
|
|
const ctx = { path: base };
|
2018-04-07 17:01:06 +08:00
|
|
|
binding.lstat(pathModule.toNamespacedPath(base), false, undefined, ctx);
|
2018-02-08 22:24:08 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
2022-06-30 16:30:53 +08:00
|
|
|
knownHard.add(base);
|
2017-01-13 05:04:18 -05:00
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
}
|
|
|
|
|
2020-12-15 19:24:10 +08:00
|
|
|
cache?.set(original, p);
|
2016-07-27 00:18:35 +02:00
|
|
|
return encodeRealpathResult(p, options);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-09-09 18:49:28 -07:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Returns the resolved pathname.
|
2021-12-21 09:53:57 -08:00
|
|
|
* @param {string | Buffer | URL} path
|
2021-04-20 10:32:24 +04:30
|
|
|
* @param {string | { encoding?: string; }} [options]
|
|
|
|
* @returns {string | Buffer}
|
|
|
|
*/
|
2018-11-24 16:34:14 +09:00
|
|
|
realpathSync.native = (path, options) => {
|
2022-05-21 17:52:23 +08:00
|
|
|
options = getOptions(options);
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2018-02-03 22:22:05 +08:00
|
|
|
const ctx = { path };
|
2022-09-13 13:48:53 +02:00
|
|
|
const result = binding.realpath(pathModule.toNamespacedPath(path), options.encoding, undefined, ctx);
|
2018-02-03 22:22:05 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
|
|
|
return result;
|
2017-10-05 13:10:03 +02:00
|
|
|
};
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Asynchronously computes the canonical pathname by
|
|
|
|
* resolving `.`, `..` and symbolic links.
|
|
|
|
* @param {string | Buffer | URL} p
|
|
|
|
* @param {string | { encoding?: string; }} [options]
|
|
|
|
* @param {(
|
|
|
|
* err?: Error,
|
|
|
|
* resolvedPath?: string | Buffer
|
|
|
|
* ) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function realpath(p, options, callback) {
|
2018-12-21 16:03:50 +08:00
|
|
|
callback = typeof options === 'function' ? options : maybeCallback(callback);
|
2022-05-21 17:52:23 +08:00
|
|
|
options = getOptions(options);
|
2018-08-24 18:13:32 +02:00
|
|
|
p = toPathIfFileURL(p);
|
2019-05-26 17:38:13 +03:00
|
|
|
|
2017-03-11 23:59:37 -05:00
|
|
|
if (typeof p !== 'string') {
|
2018-01-23 10:23:46 +08:00
|
|
|
p += '';
|
2017-03-11 23:59:37 -05:00
|
|
|
}
|
2018-01-23 10:23:46 +08:00
|
|
|
validatePath(p);
|
2016-07-27 00:18:35 +02:00
|
|
|
p = pathModule.resolve(p);
|
|
|
|
|
2022-06-30 16:30:53 +08:00
|
|
|
const seenLinks = new SafeMap();
|
|
|
|
const knownHard = new SafeSet();
|
2016-07-27 00:18:35 +02:00
|
|
|
|
2019-03-07 01:03:53 +01:00
|
|
|
// Current character position in p
|
2018-05-15 12:34:49 -07:00
|
|
|
let pos;
|
2018-12-10 13:27:32 +01:00
|
|
|
// The partial path so far, including a trailing slash if any
|
2018-05-15 12:34:49 -07:00
|
|
|
let current;
|
2018-12-03 17:15:45 +01:00
|
|
|
// The partial path without a trailing slash (except when pointing at a root)
|
2018-05-15 12:34:49 -07:00
|
|
|
let base;
|
2018-12-10 13:27:32 +01:00
|
|
|
// The partial path scanned in the previous round, with slash
|
2018-05-15 12:34:49 -07:00
|
|
|
let previous;
|
2016-07-27 00:18:35 +02:00
|
|
|
|
2017-03-11 23:59:37 -05:00
|
|
|
current = base = splitRoot(p);
|
|
|
|
pos = current.length;
|
2016-07-27 00:18:35 +02:00
|
|
|
|
2017-01-13 05:04:18 -05:00
|
|
|
// On windows, check that the root exists. On unix there is no need.
|
2022-06-30 16:30:53 +08:00
|
|
|
if (isWindows && !knownHard.has(base)) {
|
2018-11-24 16:34:14 +09:00
|
|
|
fs.lstat(base, (err, stats) => {
|
2017-01-13 05:04:18 -05:00
|
|
|
if (err) return callback(err);
|
2022-06-30 16:30:53 +08:00
|
|
|
knownHard.add(base);
|
2017-01-13 05:04:18 -05:00
|
|
|
LOOP();
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
process.nextTick(LOOP);
|
2016-07-27 00:18:35 +02:00
|
|
|
}
|
|
|
|
|
2018-12-03 17:15:45 +01:00
|
|
|
// Walk down the path, swapping out linked path parts for their real
|
2016-07-27 00:18:35 +02:00
|
|
|
// values
|
|
|
|
function LOOP() {
|
2019-03-07 01:03:53 +01:00
|
|
|
// Stop if scanned past end of path
|
2016-07-27 00:18:35 +02:00
|
|
|
if (pos >= p.length) {
|
|
|
|
return callback(null, encodeRealpathResult(p, options));
|
|
|
|
}
|
|
|
|
|
|
|
|
// find the next part
|
2018-05-15 12:34:49 -07:00
|
|
|
const result = nextPart(p, pos);
|
2016-07-27 00:18:35 +02:00
|
|
|
previous = current;
|
2017-01-13 05:09:52 -05:00
|
|
|
if (result === -1) {
|
2020-11-19 23:20:26 +01:00
|
|
|
const last = StringPrototypeSlice(p, pos);
|
2017-01-13 05:09:52 -05:00
|
|
|
current += last;
|
|
|
|
base = previous + last;
|
|
|
|
pos = p.length;
|
|
|
|
} else {
|
2020-11-19 23:20:26 +01:00
|
|
|
current += StringPrototypeSlice(p, pos, result + 1);
|
|
|
|
base = previous + StringPrototypeSlice(p, pos, result);
|
2017-01-13 05:09:52 -05:00
|
|
|
pos = result + 1;
|
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
|
2019-01-21 01:22:27 +01:00
|
|
|
// Continue if not a symlink, break if a pipe/socket
|
2022-06-30 16:30:53 +08:00
|
|
|
if (knownHard.has(base)) {
|
2021-02-08 22:13:37 +08:00
|
|
|
if (isFileType(binding.statValues, S_IFIFO) ||
|
|
|
|
isFileType(binding.statValues, S_IFSOCK)) {
|
2017-05-15 03:27:54 +04:30
|
|
|
return callback(null, encodeRealpathResult(p, options));
|
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
return process.nextTick(LOOP);
|
|
|
|
}
|
|
|
|
|
2020-06-18 18:49:59 +03:00
|
|
|
return fs.lstat(base, { bigint: true }, gotStat);
|
2016-07-27 00:18:35 +02:00
|
|
|
}
|
|
|
|
|
2018-04-07 16:57:22 +08:00
|
|
|
function gotStat(err, stats) {
|
2016-07-27 00:18:35 +02:00
|
|
|
if (err) return callback(err);
|
|
|
|
|
2019-01-21 01:22:27 +01:00
|
|
|
// If not a symlink, skip to the next path part
|
2018-04-07 16:57:22 +08:00
|
|
|
if (!stats.isSymbolicLink()) {
|
2022-06-30 16:30:53 +08:00
|
|
|
knownHard.add(base);
|
2016-07-27 00:18:35 +02:00
|
|
|
return process.nextTick(LOOP);
|
|
|
|
}
|
|
|
|
|
2019-03-07 01:03:53 +01:00
|
|
|
// Stat & read the link if not read before.
|
|
|
|
// Call `gotTarget()` as soon as the link target is known.
|
|
|
|
// `dev`/`ino` always return 0 on windows, so skip the check.
|
2016-08-14 18:41:28 +02:00
|
|
|
let id;
|
2016-07-27 00:18:35 +02:00
|
|
|
if (!isWindows) {
|
2020-11-19 23:20:26 +01:00
|
|
|
const dev = BigIntPrototypeToString(stats.dev, 32);
|
|
|
|
const ino = BigIntPrototypeToString(stats.ino, 32);
|
2017-03-11 19:41:20 -05:00
|
|
|
id = `${dev}:${ino}`;
|
2022-06-30 16:30:53 +08:00
|
|
|
if (seenLinks.has(id)) {
|
|
|
|
return gotTarget(null, seenLinks.get(id));
|
2016-07-27 00:18:35 +02:00
|
|
|
}
|
|
|
|
}
|
2018-11-24 16:34:14 +09:00
|
|
|
fs.stat(base, (err) => {
|
2016-07-27 00:18:35 +02:00
|
|
|
if (err) return callback(err);
|
|
|
|
|
2018-11-24 16:34:14 +09:00
|
|
|
fs.readlink(base, (err, target) => {
|
2022-06-30 16:30:53 +08:00
|
|
|
if (!isWindows) seenLinks.set(id, target);
|
2016-07-27 00:18:35 +02:00
|
|
|
gotTarget(err, target);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-09-29 13:06:43 +08:00
|
|
|
function gotTarget(err, target) {
|
2016-07-27 00:18:35 +02:00
|
|
|
if (err) return callback(err);
|
|
|
|
|
2018-05-15 12:34:49 -07:00
|
|
|
gotResolvedLink(pathModule.resolve(previous, target));
|
2016-07-27 00:18:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function gotResolvedLink(resolvedLink) {
|
2019-03-07 01:03:53 +01:00
|
|
|
// Resolve the link, then start over
|
2020-11-19 23:20:26 +01:00
|
|
|
p = pathModule.resolve(resolvedLink, StringPrototypeSlice(p, pos));
|
2017-03-11 23:59:37 -05:00
|
|
|
current = base = splitRoot(p);
|
|
|
|
pos = current.length;
|
2017-01-13 05:04:18 -05:00
|
|
|
|
|
|
|
// On windows, check that the root exists. On unix there is no need.
|
2022-06-30 16:30:53 +08:00
|
|
|
if (isWindows && !knownHard.has(base)) {
|
2018-11-24 16:34:14 +09:00
|
|
|
fs.lstat(base, (err) => {
|
2017-01-13 05:04:18 -05:00
|
|
|
if (err) return callback(err);
|
2022-06-30 16:30:53 +08:00
|
|
|
knownHard.add(base);
|
2017-01-13 05:04:18 -05:00
|
|
|
LOOP();
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
process.nextTick(LOOP);
|
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
}
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2010-05-24 15:47:40 -07:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Asynchronously computes the canonical pathname by
|
|
|
|
* resolving `.`, `..` and symbolic links.
|
2021-12-21 09:53:57 -08:00
|
|
|
* @param {string | Buffer | URL} path
|
2021-04-20 10:32:24 +04:30
|
|
|
* @param {string | { encoding?: string; }} [options]
|
|
|
|
* @param {(
|
|
|
|
* err?: Error,
|
|
|
|
* resolvedPath?: string | Buffer
|
|
|
|
* ) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-11-24 16:34:14 +09:00
|
|
|
realpath.native = (path, options, callback) => {
|
2018-02-09 16:31:26 +01:00
|
|
|
callback = makeCallback(callback || options);
|
2022-05-21 17:52:23 +08:00
|
|
|
options = getOptions(options);
|
2019-05-12 20:30:29 +08:00
|
|
|
path = getValidatedPath(path);
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2017-10-05 13:10:03 +02:00
|
|
|
req.oncomplete = callback;
|
2022-09-13 13:48:53 +02:00
|
|
|
return binding.realpath(pathModule.toNamespacedPath(path), options.encoding, req);
|
2017-10-05 13:10:03 +02:00
|
|
|
};
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Creates a unique temporary directory.
|
|
|
|
* @param {string} prefix
|
|
|
|
* @param {string | { encoding?: string; }} [options]
|
|
|
|
* @param {(
|
|
|
|
* err?: Error,
|
|
|
|
* directory?: string
|
|
|
|
* ) => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function mkdtemp(prefix, options, callback) {
|
2016-06-26 00:03:05 +05:30
|
|
|
callback = makeCallback(typeof options === 'function' ? options : callback);
|
2022-05-21 17:52:23 +08:00
|
|
|
options = getOptions(options);
|
2021-06-14 03:37:54 +04:30
|
|
|
|
|
|
|
validateString(prefix, 'prefix');
|
2018-01-23 10:23:46 +08:00
|
|
|
nullCheck(prefix, 'prefix');
|
2019-03-29 09:17:55 -04:00
|
|
|
warnOnNonPortableTemplate(prefix);
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2016-05-18 17:47:07 +05:30
|
|
|
req.oncomplete = callback;
|
2017-11-10 18:17:17 +05:30
|
|
|
binding.mkdtemp(`${prefix}XXXXXX`, options.encoding, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2016-05-18 17:47:07 +05:30
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously creates a unique temporary directory.
|
|
|
|
* @param {string} prefix
|
|
|
|
* @param {string | { encoding?: string; }} [options]
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function mkdtempSync(prefix, options) {
|
2022-05-21 17:52:23 +08:00
|
|
|
options = getOptions(options);
|
2021-06-14 03:37:54 +04:30
|
|
|
|
|
|
|
validateString(prefix, 'prefix');
|
2018-01-23 10:23:46 +08:00
|
|
|
nullCheck(prefix, 'prefix');
|
2019-03-29 09:17:55 -04:00
|
|
|
warnOnNonPortableTemplate(prefix);
|
2018-02-20 04:54:19 +08:00
|
|
|
const path = `${prefix}XXXXXX`;
|
|
|
|
const ctx = { path };
|
|
|
|
const result = binding.mkdtemp(path, options.encoding,
|
|
|
|
undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
|
|
|
return result;
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2017-09-06 12:54:29 -04:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Asynchronously copies `src` to `dest`. By
|
|
|
|
* default, `dest` is overwritten if it already exists.
|
|
|
|
* @param {string | Buffer | URL} src
|
|
|
|
* @param {string | Buffer | URL} dest
|
|
|
|
* @param {number} [mode]
|
|
|
|
* @param {() => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2019-04-02 01:21:36 +02:00
|
|
|
function copyFile(src, dest, mode, callback) {
|
|
|
|
if (typeof mode === 'function') {
|
|
|
|
callback = mode;
|
|
|
|
mode = 0;
|
2017-09-06 12:54:29 -04:00
|
|
|
}
|
|
|
|
|
2019-05-12 20:30:29 +08:00
|
|
|
src = getValidatedPath(src, 'src');
|
|
|
|
dest = getValidatedPath(dest, 'dest');
|
2017-12-13 14:24:34 -08:00
|
|
|
|
2017-09-06 12:54:29 -04:00
|
|
|
src = pathModule._makeLong(src);
|
|
|
|
dest = pathModule._makeLong(dest);
|
2019-04-02 01:21:36 +02:00
|
|
|
mode = getValidMode(mode, 'copyFile');
|
2020-10-03 22:44:20 +02:00
|
|
|
callback = makeCallback(callback);
|
|
|
|
|
2018-07-25 11:35:10 -04:00
|
|
|
const req = new FSReqCallback();
|
2020-10-03 22:44:20 +02:00
|
|
|
req.oncomplete = callback;
|
2019-04-02 01:21:36 +02:00
|
|
|
binding.copyFile(src, dest, mode, req);
|
2018-05-15 12:34:49 -07:00
|
|
|
}
|
2017-09-06 12:54:29 -04:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Synchronously copies `src` to `dest`. By
|
|
|
|
* default, `dest` is overwritten if it already exists.
|
|
|
|
* @param {string | Buffer | URL} src
|
|
|
|
* @param {string | Buffer | URL} dest
|
|
|
|
* @param {number} [mode]
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2019-04-02 01:21:36 +02:00
|
|
|
function copyFileSync(src, dest, mode) {
|
2019-05-12 20:30:29 +08:00
|
|
|
src = getValidatedPath(src, 'src');
|
|
|
|
dest = getValidatedPath(dest, 'dest');
|
2017-12-13 14:24:34 -08:00
|
|
|
|
2018-02-16 13:25:21 +08:00
|
|
|
const ctx = { path: src, dest }; // non-prefixed
|
|
|
|
|
2017-09-06 12:54:29 -04:00
|
|
|
src = pathModule._makeLong(src);
|
|
|
|
dest = pathModule._makeLong(dest);
|
2019-04-02 01:21:36 +02:00
|
|
|
mode = getValidMode(mode, 'copyFile');
|
|
|
|
binding.copyFile(src, dest, mode, undefined, ctx);
|
2018-02-16 13:25:21 +08:00
|
|
|
handleErrorFromBinding(ctx);
|
2010-03-02 03:01:44 +01:00
|
|
|
}
|
2010-03-02 23:12:52 +01:00
|
|
|
|
2021-08-08 13:48:01 -07:00
|
|
|
/**
|
|
|
|
* Asynchronously copies `src` to `dest`. `src` can be a file, directory, or
|
|
|
|
* symlink. The contents of directories will be copied recursively.
|
|
|
|
* @param {string | URL} src
|
|
|
|
* @param {string | URL} dest
|
2021-11-28 22:48:00 -08:00
|
|
|
* @param {object} [options]
|
2021-08-08 13:48:01 -07:00
|
|
|
* @param {() => any} callback
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
function cp(src, dest, options, callback) {
|
|
|
|
if (typeof options === 'function') {
|
|
|
|
callback = options;
|
|
|
|
options = undefined;
|
|
|
|
}
|
|
|
|
callback = makeCallback(callback);
|
|
|
|
options = validateCpOptions(options);
|
|
|
|
src = pathModule.toNamespacedPath(getValidatedPath(src, 'src'));
|
|
|
|
dest = pathModule.toNamespacedPath(getValidatedPath(dest, 'dest'));
|
|
|
|
lazyLoadCp();
|
|
|
|
cpFn(src, dest, options, callback);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Synchronously copies `src` to `dest`. `src` can be a file, directory, or
|
|
|
|
* symlink. The contents of directories will be copied recursively.
|
|
|
|
* @param {string | URL} src
|
|
|
|
* @param {string | URL} dest
|
2021-11-28 22:48:00 -08:00
|
|
|
* @param {object} [options]
|
2021-08-08 13:48:01 -07:00
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
function cpSync(src, dest, options) {
|
|
|
|
options = validateCpOptions(options);
|
|
|
|
src = pathModule.toNamespacedPath(getValidatedPath(src, 'src'));
|
|
|
|
dest = pathModule.toNamespacedPath(getValidatedPath(dest, 'dest'));
|
|
|
|
lazyLoadCp();
|
|
|
|
cpSyncFn(src, dest, options);
|
|
|
|
}
|
|
|
|
|
2018-05-15 12:34:49 -07:00
|
|
|
function lazyLoadStreams() {
|
|
|
|
if (!ReadStream) {
|
|
|
|
({ ReadStream, WriteStream } = require('internal/fs/streams'));
|
2021-01-06 19:53:27 +01:00
|
|
|
FileReadStream = ReadStream;
|
|
|
|
FileWriteStream = WriteStream;
|
2018-04-09 23:02:08 +05:30
|
|
|
}
|
2012-10-04 17:44:48 -07:00
|
|
|
}
|
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Creates a readable stream with a default `highWaterMark`
|
2022-04-20 00:46:37 +02:00
|
|
|
* of 64 KiB.
|
2021-04-20 10:32:24 +04:30
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {string | {
|
|
|
|
* flags?: string;
|
|
|
|
* encoding?: string;
|
|
|
|
* fd?: number | FileHandle;
|
|
|
|
* mode?: number;
|
|
|
|
* autoClose?: boolean;
|
|
|
|
* emitClose?: boolean;
|
|
|
|
* start: number;
|
|
|
|
* end?: number;
|
|
|
|
* highWaterMark?: number;
|
2022-03-26 20:48:11 -07:00
|
|
|
* fs?: object | null;
|
2021-04-20 10:32:24 +04:30
|
|
|
* }} [options]
|
|
|
|
* @returns {ReadStream}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function createReadStream(path, options) {
|
|
|
|
lazyLoadStreams();
|
|
|
|
return new ReadStream(path, options);
|
2017-06-05 16:46:55 +02:00
|
|
|
}
|
2010-03-03 12:39:41 +01:00
|
|
|
|
2021-04-20 10:32:24 +04:30
|
|
|
/**
|
|
|
|
* Creates a write stream.
|
|
|
|
* @param {string | Buffer | URL} path
|
|
|
|
* @param {string | {
|
|
|
|
* flags?: string;
|
|
|
|
* encoding?: string;
|
|
|
|
* fd?: number | FileHandle;
|
|
|
|
* mode?: number;
|
|
|
|
* autoClose?: boolean;
|
|
|
|
* emitClose?: boolean;
|
|
|
|
* start: number;
|
2022-03-26 20:48:11 -07:00
|
|
|
* fs?: object | null;
|
2021-04-20 10:32:24 +04:30
|
|
|
* }} [options]
|
|
|
|
* @returns {WriteStream}
|
|
|
|
*/
|
2018-05-15 12:34:49 -07:00
|
|
|
function createWriteStream(path, options) {
|
|
|
|
lazyLoadStreams();
|
2010-04-27 18:51:41 -07:00
|
|
|
return new WriteStream(path, options);
|
2012-10-04 17:44:48 -07:00
|
|
|
}
|
2010-03-02 23:12:52 +01:00
|
|
|
|
2018-05-15 12:34:49 -07:00
|
|
|
module.exports = fs = {
|
|
|
|
appendFile,
|
|
|
|
appendFileSync,
|
|
|
|
access,
|
|
|
|
accessSync,
|
|
|
|
chown,
|
|
|
|
chownSync,
|
|
|
|
chmod,
|
|
|
|
chmodSync,
|
|
|
|
close,
|
|
|
|
closeSync,
|
|
|
|
copyFile,
|
|
|
|
copyFileSync,
|
2021-08-08 13:48:01 -07:00
|
|
|
cp,
|
|
|
|
cpSync,
|
2018-05-15 12:34:49 -07:00
|
|
|
createReadStream,
|
|
|
|
createWriteStream,
|
|
|
|
exists,
|
|
|
|
existsSync,
|
|
|
|
fchown,
|
|
|
|
fchownSync,
|
|
|
|
fchmod,
|
|
|
|
fchmodSync,
|
|
|
|
fdatasync,
|
|
|
|
fdatasyncSync,
|
|
|
|
fstat,
|
|
|
|
fstatSync,
|
|
|
|
fsync,
|
|
|
|
fsyncSync,
|
|
|
|
ftruncate,
|
|
|
|
ftruncateSync,
|
|
|
|
futimes,
|
|
|
|
futimesSync,
|
2018-06-23 16:26:29 -04:00
|
|
|
lchown,
|
|
|
|
lchownSync,
|
2018-05-15 12:34:49 -07:00
|
|
|
lchmod: constants.O_SYMLINK !== undefined ? lchmod : undefined,
|
|
|
|
lchmodSync: constants.O_SYMLINK !== undefined ? lchmodSync : undefined,
|
|
|
|
link,
|
|
|
|
linkSync,
|
|
|
|
lstat,
|
|
|
|
lstatSync,
|
2020-05-14 11:54:00 +02:00
|
|
|
lutimes,
|
|
|
|
lutimesSync,
|
2018-05-15 12:34:49 -07:00
|
|
|
mkdir,
|
|
|
|
mkdirSync,
|
|
|
|
mkdtemp,
|
|
|
|
mkdtempSync,
|
|
|
|
open,
|
|
|
|
openSync,
|
2022-12-17 13:58:26 -08:00
|
|
|
openAsBlob,
|
2018-05-15 12:34:49 -07:00
|
|
|
readdir,
|
|
|
|
readdirSync,
|
|
|
|
read,
|
|
|
|
readSync,
|
2020-03-17 00:50:27 +11:00
|
|
|
readv,
|
|
|
|
readvSync,
|
2018-05-15 12:34:49 -07:00
|
|
|
readFile,
|
|
|
|
readFileSync,
|
|
|
|
readlink,
|
|
|
|
readlinkSync,
|
|
|
|
realpath,
|
|
|
|
realpathSync,
|
|
|
|
rename,
|
|
|
|
renameSync,
|
2020-10-03 20:20:28 -06:00
|
|
|
rm,
|
|
|
|
rmSync,
|
2018-05-15 12:34:49 -07:00
|
|
|
rmdir,
|
|
|
|
rmdirSync,
|
|
|
|
stat,
|
2023-01-29 12:43:20 -05:00
|
|
|
statfs,
|
2018-05-15 12:34:49 -07:00
|
|
|
statSync,
|
2023-01-29 12:43:20 -05:00
|
|
|
statfsSync,
|
2018-05-15 12:34:49 -07:00
|
|
|
symlink,
|
|
|
|
symlinkSync,
|
|
|
|
truncate,
|
|
|
|
truncateSync,
|
|
|
|
unwatchFile,
|
|
|
|
unlink,
|
|
|
|
unlinkSync,
|
|
|
|
utimes,
|
|
|
|
utimesSync,
|
|
|
|
watch,
|
|
|
|
watchFile,
|
|
|
|
writeFile,
|
|
|
|
writeFileSync,
|
|
|
|
write,
|
|
|
|
writeSync,
|
2019-02-04 17:18:39 +01:00
|
|
|
writev,
|
|
|
|
writevSync,
|
2018-07-27 19:29:32 -07:00
|
|
|
Dirent,
|
2018-05-15 12:34:49 -07:00
|
|
|
Stats,
|
2010-04-08 10:37:10 -07:00
|
|
|
|
2018-05-15 12:34:49 -07:00
|
|
|
get ReadStream() {
|
|
|
|
lazyLoadStreams();
|
|
|
|
return ReadStream;
|
|
|
|
},
|
2015-07-28 14:59:35 +09:00
|
|
|
|
2018-05-15 12:34:49 -07:00
|
|
|
set ReadStream(val) {
|
|
|
|
ReadStream = val;
|
|
|
|
},
|
2015-07-28 14:59:35 +09:00
|
|
|
|
2018-05-15 12:34:49 -07:00
|
|
|
get WriteStream() {
|
|
|
|
lazyLoadStreams();
|
|
|
|
return WriteStream;
|
|
|
|
},
|
2015-07-28 14:59:35 +09:00
|
|
|
|
2018-05-15 12:34:49 -07:00
|
|
|
set WriteStream(val) {
|
|
|
|
WriteStream = val;
|
|
|
|
},
|
2015-07-28 14:59:35 +09:00
|
|
|
|
2018-05-15 12:34:49 -07:00
|
|
|
// Legacy names... these have to be separate because of how graceful-fs
|
|
|
|
// (and possibly other) modules monkey patch the values.
|
|
|
|
get FileReadStream() {
|
|
|
|
lazyLoadStreams();
|
|
|
|
return FileReadStream;
|
|
|
|
},
|
2015-07-28 14:59:35 +09:00
|
|
|
|
2018-05-15 12:34:49 -07:00
|
|
|
set FileReadStream(val) {
|
|
|
|
FileReadStream = val;
|
|
|
|
},
|
2015-07-28 14:59:35 +09:00
|
|
|
|
2018-05-15 12:34:49 -07:00
|
|
|
get FileWriteStream() {
|
|
|
|
lazyLoadStreams();
|
|
|
|
return FileWriteStream;
|
|
|
|
},
|
2015-07-28 14:59:35 +09:00
|
|
|
|
2018-05-15 12:34:49 -07:00
|
|
|
set FileWriteStream(val) {
|
|
|
|
FileWriteStream = val;
|
|
|
|
},
|
2015-07-28 14:59:35 +09:00
|
|
|
|
2018-05-15 12:34:49 -07:00
|
|
|
// For tests
|
2023-02-20 01:58:32 +01:00
|
|
|
_toUnixTimestamp: toUnixTimestamp,
|
2015-07-28 14:59:35 +09:00
|
|
|
};
|
|
|
|
|
2022-12-09 23:37:35 +01:00
|
|
|
defineLazyProperties(
|
|
|
|
fs,
|
|
|
|
'internal/fs/dir',
|
2023-02-14 18:45:16 +01:00
|
|
|
['Dir', 'opendir', 'opendirSync'],
|
2022-12-09 23:37:35 +01:00
|
|
|
);
|
|
|
|
|
2019-11-22 18:04:46 +01:00
|
|
|
ObjectDefineProperties(fs, {
|
2022-06-03 10:23:58 +02:00
|
|
|
F_OK: { __proto__: null, enumerable: true, value: F_OK || 0 },
|
|
|
|
R_OK: { __proto__: null, enumerable: true, value: R_OK || 0 },
|
|
|
|
W_OK: { __proto__: null, enumerable: true, value: W_OK || 0 },
|
|
|
|
X_OK: { __proto__: null, enumerable: true, value: X_OK || 0 },
|
2018-05-15 12:34:49 -07:00
|
|
|
constants: {
|
2022-06-03 10:23:58 +02:00
|
|
|
__proto__: null,
|
2018-05-15 12:34:49 -07:00
|
|
|
configurable: false,
|
|
|
|
enumerable: true,
|
2023-02-20 01:58:32 +01:00
|
|
|
value: constants,
|
2018-05-15 12:34:49 -07:00
|
|
|
},
|
|
|
|
promises: {
|
2022-06-03 10:23:58 +02:00
|
|
|
__proto__: null,
|
2018-05-15 12:34:49 -07:00
|
|
|
configurable: true,
|
2019-03-11 10:19:47 +00:00
|
|
|
enumerable: true,
|
2018-05-15 12:34:49 -07:00
|
|
|
get() {
|
2022-02-11 21:02:12 +08:00
|
|
|
promises ??= require('internal/fs/promises').exports;
|
2018-05-15 12:34:49 -07:00
|
|
|
return promises;
|
2023-02-20 01:58:32 +01:00
|
|
|
},
|
|
|
|
},
|
2018-05-15 12:34:49 -07:00
|
|
|
});
|