Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 4cecbe1

Browse filesBrowse files
juanarboladuh95
authored andcommitted
fs: add throwIfNoEntry option for fs.stat and fs.promises.stat
Fixes: #61116 Signed-off-by: Juan José Arboleda <soyjuanarbol@gmail.com> PR-URL: #61178 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
1 parent 7d63a2d commit 4cecbe1
Copy full SHA for 4cecbe1

6 files changed

+64-8Lines changed: 64 additions & 8 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎doc/api/fs.md‎

Copy file name to clipboardExpand all lines: doc/api/fs.md
+6Lines changed: 6 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -1719,6 +1719,9 @@ changes:
17191719
* `options` {Object}
17201720
* `bigint` {boolean} Whether the numeric values in the returned
17211721
{fs.Stats} object should be `bigint`. **Default:** `false`.
1722+
* `throwIfNoEntry` {boolean} Whether an exception will be thrown
1723+
if no file system entry exists, rather than returning `undefined`.
1724+
**Default:** `true`.
17221725
* Returns: {Promise} Fulfills with the {fs.Stats} object for the
17231726
given `path`.
17241727
@@ -4436,6 +4439,9 @@ changes:
44364439
* `options` {Object}
44374440
* `bigint` {boolean} Whether the numeric values in the returned
44384441
{fs.Stats} object should be `bigint`. **Default:** `false`.
4442+
* `throwIfNoEntry` {boolean} Whether an exception will be thrown
4443+
if no file system entry exists, rather than returning `undefined`.
4444+
**Default:** `true`.
44394445
* `callback` {Function}
44404446
* `err` {Error}
44414447
* `stats` {fs.Stats}
Collapse file

‎lib/fs.js‎

Copy file name to clipboardExpand all lines: lib/fs.js
+3-2Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ function makeStatsCallback(cb) {
188188

189189
return (err, stats) => {
190190
if (err) return cb(err);
191+
if (stats === undefined && err === null) return cb(null, undefined);
191192
cb(err, getStatsFromBinding(stats));
192193
};
193194
}
@@ -1621,7 +1622,7 @@ function lstat(path, options = { bigint: false }, callback) {
16211622
* ) => any} callback
16221623
* @returns {void}
16231624
*/
1624-
function stat(path, options = { bigint: false }, callback) {
1625+
function stat(path, options = { bigint: false, throwIfNoEntry: true }, callback) {
16251626
if (typeof options === 'function') {
16261627
callback = options;
16271628
options = kEmptyObject;
@@ -1630,7 +1631,7 @@ function stat(path, options = { bigint: false }, callback) {
16301631

16311632
const req = new FSReqCallback(options.bigint);
16321633
req.oncomplete = callback;
1633-
binding.stat(getValidatedPath(path), options.bigint, req);
1634+
binding.stat(getValidatedPath(path), options.bigint, req, options.throwIfNoEntry);
16341635
}
16351636

16361637
function statfs(path, options = { bigint: false }, callback) {
Collapse file

‎lib/internal/fs/promises.js‎

Copy file name to clipboardExpand all lines: lib/internal/fs/promises.js
+6-2Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,12 +1026,16 @@ async function lstat(path, options = { bigint: false }) {
10261026
return getStatsFromBinding(result);
10271027
}
10281028

1029-
async function stat(path, options = { bigint: false }) {
1029+
async function stat(path, options = { bigint: false, throwIfNoEntry: true }) {
10301030
const result = await PromisePrototypeThen(
1031-
binding.stat(getValidatedPath(path), options.bigint, kUsePromises),
1031+
binding.stat(getValidatedPath(path), options.bigint, kUsePromises, options.throwIfNoEntry),
10321032
undefined,
10331033
handleErrorFromBinding,
10341034
);
1035+
1036+
// Binding will resolve undefined if UV_ENOENT or UV_ENOTDIR and throwIfNoEntry is false
1037+
if (!options.throwIfNoEntry && result === undefined) return undefined;
1038+
10351039
return getStatsFromBinding(result);
10361040
}
10371041

Collapse file

‎src/node_file.cc‎

Copy file name to clipboardExpand all lines: src/node_file.cc
+38-3Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,22 @@ void AfterStat(uv_fs_t* req) {
810810
}
811811
}
812812

813+
void AfterStatNoThrowIfNoEntry(uv_fs_t* req) {
814+
FSReqBase* req_wrap = FSReqBase::from_req(req);
815+
FSReqAfterScope after(req_wrap, req);
816+
817+
FS_ASYNC_TRACE_END1(
818+
req->fs_type, req_wrap, "result", static_cast<int>(req->result))
819+
if (req->result == UV_ENOENT || req->result == UV_ENOTDIR) {
820+
req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
821+
return;
822+
}
823+
824+
if (after.Proceed()) {
825+
req_wrap->ResolveStat(&req->statbuf);
826+
}
827+
}
828+
813829
void AfterStatFs(uv_fs_t* req) {
814830
FSReqBase* req_wrap = FSReqBase::from_req(req);
815831
FSReqAfterScope after(req_wrap, req);
@@ -1105,7 +1121,9 @@ static void Stat(const FunctionCallbackInfo<Value>& args) {
11051121
ToNamespacedPath(env, &path);
11061122

11071123
bool use_bigint = args[1]->IsTrue();
1108-
if (!args[2]->IsUndefined()) { // stat(path, use_bigint, req)
1124+
if (!args[2]->IsUndefined()) { // stat(path, use_bigint, req,
1125+
// do_not_throw_if_no_entry)
1126+
bool do_not_throw_if_no_entry = args[3]->IsFalse();
11091127
FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
11101128
CHECK_NOT_NULL(req_wrap_async);
11111129
ASYNC_THROW_IF_INSUFFICIENT_PERMISSIONS(
@@ -1115,8 +1133,25 @@ static void Stat(const FunctionCallbackInfo<Value>& args) {
11151133
path.ToStringView());
11161134
FS_ASYNC_TRACE_BEGIN1(
11171135
UV_FS_STAT, req_wrap_async, "path", TRACE_STR_COPY(*path))
1118-
AsyncCall(env, req_wrap_async, args, "stat", UTF8, AfterStat,
1119-
uv_fs_stat, *path);
1136+
if (do_not_throw_if_no_entry) {
1137+
AsyncCall(env,
1138+
req_wrap_async,
1139+
args,
1140+
"stat",
1141+
UTF8,
1142+
AfterStatNoThrowIfNoEntry,
1143+
uv_fs_stat,
1144+
*path);
1145+
} else {
1146+
AsyncCall(env,
1147+
req_wrap_async,
1148+
args,
1149+
"stat",
1150+
UTF8,
1151+
AfterStat,
1152+
uv_fs_stat,
1153+
*path);
1154+
}
11201155
} else { // stat(path, use_bigint, undefined, do_not_throw_if_no_entry)
11211156
THROW_IF_INSUFFICIENT_PERMISSIONS(
11221157
env, permission::PermissionScope::kFileSystemRead, path.ToStringView());
Collapse file

‎test/parallel/test-fs-promises.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-fs-promises.js
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,12 @@ async function executeOnHandle(dest, func) {
152152
}));
153153
}
154154

155+
// File stats throwIfNoEntry: false
156+
{
157+
const stats = await stat('meow.js', { throwIfNoEntry: false });
158+
assert.strictEqual(stats, undefined);
159+
}
160+
155161
// File system stats
156162
{
157163
const statFs = await statfs(dest);
Collapse file

‎test/parallel/test-fs-stat.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-fs-stat.js
+5-1Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,5 +224,9 @@ fs.lstat(__filename, undefined, common.mustCall());
224224

225225
{
226226
// Test that the throwIfNoEntry option works and returns undefined
227-
assert.ok(!(fs.statSync('./wont_exists', { throwIfNoEntry: false })));
227+
const opts = { throwIfNoEntry: false };
228+
assert.ok(!(fs.statSync('./wont_exists', opts)));
229+
fs.stat('./wont_exists', opts, common.mustSucceed((err, stats) => {
230+
assert.strictEqual(stats, undefined);
231+
}));
228232
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.