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 f4a3edc

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 6834ca1 commit f4a3edc
Copy full SHA for f4a3edc

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
@@ -1720,6 +1720,9 @@ changes:
17201720
* `options` {Object}
17211721
* `bigint` {boolean} Whether the numeric values in the returned
17221722
{fs.Stats} object should be `bigint`. **Default:** `false`.
1723+
* `throwIfNoEntry` {boolean} Whether an exception will be thrown
1724+
if no file system entry exists, rather than returning `undefined`.
1725+
**Default:** `true`.
17231726
* Returns: {Promise} Fulfills with the {fs.Stats} object for the
17241727
given `path`.
17251728
@@ -4432,6 +4435,9 @@ changes:
44324435
* `options` {Object}
44334436
* `bigint` {boolean} Whether the numeric values in the returned
44344437
{fs.Stats} object should be `bigint`. **Default:** `false`.
4438+
* `throwIfNoEntry` {boolean} Whether an exception will be thrown
4439+
if no file system entry exists, rather than returning `undefined`.
4440+
**Default:** `true`.
44354441
* `callback` {Function}
44364442
* `err` {Error}
44374443
* `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
@@ -193,6 +193,7 @@ function makeStatsCallback(cb) {
193193

194194
return (err, stats) => {
195195
if (err) return cb(err);
196+
if (stats === undefined && err === null) return cb(null, undefined);
196197
cb(err, getStatsFromBinding(stats));
197198
};
198199
}
@@ -1637,7 +1638,7 @@ function lstat(path, options = { bigint: false }, callback) {
16371638
* ) => any} callback
16381639
* @returns {void}
16391640
*/
1640-
function stat(path, options = { bigint: false }, callback) {
1641+
function stat(path, options = { bigint: false, throwIfNoEntry: true }, callback) {
16411642
if (typeof options === 'function') {
16421643
callback = options;
16431644
options = kEmptyObject;
@@ -1646,7 +1647,7 @@ function stat(path, options = { bigint: false }, callback) {
16461647

16471648
const req = new FSReqCallback(options.bigint);
16481649
req.oncomplete = callback;
1649-
binding.stat(getValidatedPath(path), options.bigint, req);
1650+
binding.stat(getValidatedPath(path), options.bigint, req, options.throwIfNoEntry);
16501651
}
16511652

16521653
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
@@ -1034,12 +1034,16 @@ async function lstat(path, options = { bigint: false }) {
10341034
return getStatsFromBinding(result);
10351035
}
10361036

1037-
async function stat(path, options = { bigint: false }) {
1037+
async function stat(path, options = { bigint: false, throwIfNoEntry: true }) {
10381038
const result = await PromisePrototypeThen(
1039-
binding.stat(getValidatedPath(path), options.bigint, kUsePromises),
1039+
binding.stat(getValidatedPath(path), options.bigint, kUsePromises, options.throwIfNoEntry),
10401040
undefined,
10411041
handleErrorFromBinding,
10421042
);
1043+
1044+
// Binding will resolve undefined if UV_ENOENT or UV_ENOTDIR and throwIfNoEntry is false
1045+
if (!options.throwIfNoEntry && result === undefined) return undefined;
1046+
10431047
return getStatsFromBinding(result);
10441048
}
10451049

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
@@ -801,6 +801,22 @@ void AfterStat(uv_fs_t* req) {
801801
}
802802
}
803803

804+
void AfterStatNoThrowIfNoEntry(uv_fs_t* req) {
805+
FSReqBase* req_wrap = FSReqBase::from_req(req);
806+
FSReqAfterScope after(req_wrap, req);
807+
808+
FS_ASYNC_TRACE_END1(
809+
req->fs_type, req_wrap, "result", static_cast<int>(req->result))
810+
if (req->result == UV_ENOENT || req->result == UV_ENOTDIR) {
811+
req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
812+
return;
813+
}
814+
815+
if (after.Proceed()) {
816+
req_wrap->ResolveStat(&req->statbuf);
817+
}
818+
}
819+
804820
void AfterStatFs(uv_fs_t* req) {
805821
FSReqBase* req_wrap = FSReqBase::from_req(req);
806822
FSReqAfterScope after(req_wrap, req);
@@ -1096,7 +1112,9 @@ static void Stat(const FunctionCallbackInfo<Value>& args) {
10961112
ToNamespacedPath(env, &path);
10971113

10981114
bool use_bigint = args[1]->IsTrue();
1099-
if (!args[2]->IsUndefined()) { // stat(path, use_bigint, req)
1115+
if (!args[2]->IsUndefined()) { // stat(path, use_bigint, req,
1116+
// do_not_throw_if_no_entry)
1117+
bool do_not_throw_if_no_entry = args[3]->IsFalse();
11001118
FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint);
11011119
CHECK_NOT_NULL(req_wrap_async);
11021120
ASYNC_THROW_IF_INSUFFICIENT_PERMISSIONS(
@@ -1106,8 +1124,25 @@ static void Stat(const FunctionCallbackInfo<Value>& args) {
11061124
path.ToStringView());
11071125
FS_ASYNC_TRACE_BEGIN1(
11081126
UV_FS_STAT, req_wrap_async, "path", TRACE_STR_COPY(*path))
1109-
AsyncCall(env, req_wrap_async, args, "stat", UTF8, AfterStat,
1110-
uv_fs_stat, *path);
1127+
if (do_not_throw_if_no_entry) {
1128+
AsyncCall(env,
1129+
req_wrap_async,
1130+
args,
1131+
"stat",
1132+
UTF8,
1133+
AfterStatNoThrowIfNoEntry,
1134+
uv_fs_stat,
1135+
*path);
1136+
} else {
1137+
AsyncCall(env,
1138+
req_wrap_async,
1139+
args,
1140+
"stat",
1141+
UTF8,
1142+
AfterStat,
1143+
uv_fs_stat,
1144+
*path);
1145+
}
11111146
} else { // stat(path, use_bigint, undefined, do_not_throw_if_no_entry)
11121147
THROW_IF_INSUFFICIENT_PERMISSIONS(
11131148
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.