mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 18:25:13 +08:00
fs: add throwIfNoEntry option for fs.stat and fs.promises.stat
Fixes: https://github.com/nodejs/node/issues/61116 Signed-off-by: Juan José Arboleda <soyjuanarbol@gmail.com> PR-URL: https://github.com/nodejs/node/pull/61178 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
This commit is contained in:
1 parent
cff8bfd865
commit
31bf4fb6e5
6 files changed
+64
-8
No files matched your search
@@ -1719,6 +1719,9 @@ changes:
|
||||
* `options` {Object}
|
||||
* `bigint` {boolean} Whether the numeric values in the returned
|
||||
{fs.Stats} object should be `bigint`. **Default:** `false`.
|
||||
* `throwIfNoEntry` {boolean} Whether an exception will be thrown
|
||||
if no file system entry exists, rather than returning `undefined`.
|
||||
**Default:** `true`.
|
||||
* Returns: {Promise} Fulfills with the {fs.Stats} object for the
|
||||
given `path`.
|
||||
|
||||
@@ -4436,6 +4439,9 @@ changes:
|
||||
* `options` {Object}
|
||||
* `bigint` {boolean} Whether the numeric values in the returned
|
||||
{fs.Stats} object should be `bigint`. **Default:** `false`.
|
||||
* `throwIfNoEntry` {boolean} Whether an exception will be thrown
|
||||
if no file system entry exists, rather than returning `undefined`.
|
||||
**Default:** `true`.
|
||||
* `callback` {Function}
|
||||
* `err` {Error}
|
||||
* `stats` {fs.Stats}
|
||||
|
||||
@@ -188,6 +188,7 @@ function makeStatsCallback(cb) {
|
||||
|
||||
return (err, stats) => {
|
||||
if (err) return cb(err);
|
||||
if (stats === undefined && err === null) return cb(null, undefined);
|
||||
cb(err, getStatsFromBinding(stats));
|
||||
};
|
||||
}
|
||||
@@ -1621,7 +1622,7 @@ function lstat(path, options = { bigint: false }, callback) {
|
||||
* ) => any} callback
|
||||
* @returns {void}
|
||||
*/
|
||||
function stat(path, options = { bigint: false }, callback) {
|
||||
function stat(path, options = { bigint: false, throwIfNoEntry: true }, callback) {
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = kEmptyObject;
|
||||
@@ -1630,7 +1631,7 @@ function stat(path, options = { bigint: false }, callback) {
|
||||
|
||||
const req = new FSReqCallback(options.bigint);
|
||||
req.oncomplete = callback;
|
||||
binding.stat(getValidatedPath(path), options.bigint, req);
|
||||
binding.stat(getValidatedPath(path), options.bigint, req, options.throwIfNoEntry);
|
||||
}
|
||||
|
||||
function statfs(path, options = { bigint: false }, callback) {
|
||||
|
||||
@@ -1026,12 +1026,16 @@ async function lstat(path, options = { bigint: false }) {
|
||||
return getStatsFromBinding(result);
|
||||
}
|
||||
|
||||
async function stat(path, options = { bigint: false }) {
|
||||
async function stat(path, options = { bigint: false, throwIfNoEntry: true }) {
|
||||
const result = await PromisePrototypeThen(
|
||||
binding.stat(getValidatedPath(path), options.bigint, kUsePromises),
|
||||
binding.stat(getValidatedPath(path), options.bigint, kUsePromises, options.throwIfNoEntry),
|
||||
undefined,
|
||||
handleErrorFromBinding,
|
||||
);
|
||||
|
||||
// Binding will resolve undefined if UV_ENOENT or UV_ENOTDIR and throwIfNoEntry is false
|
||||
if (!options.throwIfNoEntry && result === undefined) return undefined;
|
||||
|
||||
return getStatsFromBinding(result);
|
||||
}
|
||||
|
||||
|
||||
+38
-3
@@ -810,6 +810,22 @@ void AfterStat(uv_fs_t* req) {
|
||||
}
|
||||
}
|
||||
|
||||
void AfterStatNoThrowIfNoEntry(uv_fs_t* req) {
|
||||
FSReqBase* req_wrap = FSReqBase::from_req(req);
|
||||
FSReqAfterScope after(req_wrap, req);
|
||||
|
||||
FS_ASYNC_TRACE_END1(
|
||||
req->fs_type, req_wrap, "result", static_cast<int>(req->result))
|
||||
if (req->result == UV_ENOENT || req->result == UV_ENOTDIR) {
|
||||
req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (after.Proceed()) {
|
||||
req_wrap->ResolveStat(&req->statbuf);
|
||||
}
|
||||
}
|
||||
|
||||
void AfterStatFs(uv_fs_t* req) {
|
||||
FSReqBase* req_wrap = FSReqBase::from_req(req);
|
||||
FSReqAfterScope after(req_wrap, req);
|
||||
@@ -1105,7 +1121,9 @@ static void Stat(const FunctionCallbackInfo<Value>& args) {
|
||||
ToNamespacedPath(env, &path);
|
||||
|
||||
bool use_bigint = args[1]->IsTrue();
|
||||
if (!args[2]->IsUndefined()) { // stat(path, use_bigint, req)
|
||||
if (!args[2]->IsUndefined()) { // stat(path, use_bigint, req,
|
||||
// do_not_throw_if_no_entry)
|
||||
bool do_not_throw_if_no_entry = args[3]->IsFalse();
|
||||
FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
|
||||
CHECK_NOT_NULL(req_wrap_async);
|
||||
ASYNC_THROW_IF_INSUFFICIENT_PERMISSIONS(
|
||||
@@ -1115,8 +1133,25 @@ static void Stat(const FunctionCallbackInfo<Value>& args) {
|
||||
path.ToStringView());
|
||||
FS_ASYNC_TRACE_BEGIN1(
|
||||
UV_FS_STAT, req_wrap_async, "path", TRACE_STR_COPY(*path))
|
||||
AsyncCall(env, req_wrap_async, args, "stat", UTF8, AfterStat,
|
||||
uv_fs_stat, *path);
|
||||
if (do_not_throw_if_no_entry) {
|
||||
AsyncCall(env,
|
||||
req_wrap_async,
|
||||
args,
|
||||
"stat",
|
||||
UTF8,
|
||||
AfterStatNoThrowIfNoEntry,
|
||||
uv_fs_stat,
|
||||
*path);
|
||||
} else {
|
||||
AsyncCall(env,
|
||||
req_wrap_async,
|
||||
args,
|
||||
"stat",
|
||||
UTF8,
|
||||
AfterStat,
|
||||
uv_fs_stat,
|
||||
*path);
|
||||
}
|
||||
} else { // stat(path, use_bigint, undefined, do_not_throw_if_no_entry)
|
||||
THROW_IF_INSUFFICIENT_PERMISSIONS(
|
||||
env, permission::PermissionScope::kFileSystemRead, path.ToStringView());
|
||||
|
||||
@@ -152,6 +152,12 @@ async function executeOnHandle(dest, func) {
|
||||
}));
|
||||
}
|
||||
|
||||
// File stats throwIfNoEntry: false
|
||||
{
|
||||
const stats = await stat('meow.js', { throwIfNoEntry: false });
|
||||
assert.strictEqual(stats, undefined);
|
||||
}
|
||||
|
||||
// File system stats
|
||||
{
|
||||
const statFs = await statfs(dest);
|
||||
|
||||
@@ -224,5 +224,9 @@ fs.lstat(__filename, undefined, common.mustCall());
|
||||
|
||||
{
|
||||
// Test that the throwIfNoEntry option works and returns undefined
|
||||
assert.ok(!(fs.statSync('./wont_exists', { throwIfNoEntry: false })));
|
||||
const opts = { throwIfNoEntry: false };
|
||||
assert.ok(!(fs.statSync('./wont_exists', opts)));
|
||||
fs.stat('./wont_exists', opts, common.mustSucceed((err, stats) => {
|
||||
assert.strictEqual(stats, undefined);
|
||||
}));
|
||||
}
|
||||
Reference in new issue
Block a user