Skip to content

Commit db3fc6d

Browse files
lux01ruyadorno
authored andcommitted
fs: fix readdir and opendir recursive with unknown file types
If the libuv operations invoked by `readdir`/`opendir` return `uv_dirent_t` values where the `type` is `UV_DIRENT_UNKNOWN` then a further `lstat` is issued to fully construct the `Dirent` values. In the recursive versions of these functions, the `path` parameter was incorrectly assumed to be the path to the entry when it should be the path to the directory containing the entry. Fixes #49499. PR-URL: #49603 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
1 parent ed7c6d1 commit db3fc6d

File tree

4 files changed

+26
-19
lines changed

4 files changed

+26
-19
lines changed

lib/internal/fs/dir.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ class Dir {
152152
ArrayPrototypePush(
153153
this[kDirBufferedEntries],
154154
getDirent(
155-
pathModule.join(path, result[i]),
155+
path,
156156
result[i],
157157
result[i + 1],
158158
),
@@ -161,9 +161,10 @@ class Dir {
161161
}
162162

163163
readSyncRecursive(dirent) {
164-
const ctx = { path: dirent.path };
164+
const path = pathModule.join(dirent.path, dirent.name);
165+
const ctx = { path };
165166
const handle = dirBinding.opendir(
166-
pathModule.toNamespacedPath(dirent.path),
167+
pathModule.toNamespacedPath(path),
167168
this[kDirOptions].encoding,
168169
undefined,
169170
ctx,
@@ -177,7 +178,7 @@ class Dir {
177178
);
178179

179180
if (result) {
180-
this.processReadResult(dirent.path, result);
181+
this.processReadResult(path, result);
181182
}
182183

183184
handle.close(undefined, ctx);

lib/internal/fs/utils.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ function join(path, name) {
234234
}
235235

236236
if (typeof path === 'string' && typeof name === 'string') {
237-
return pathModule.basename(path) === name ? path : pathModule.join(path, name);
237+
return pathModule.join(path, name);
238238
}
239239

240240
if (isUint8Array(path) && isUint8Array(name)) {

test/sequential/test-fs-opendir-recursive.js

+10-7
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const tmpdir = require('../common/tmpdir');
1010
const testDir = tmpdir.path;
1111

1212
const fileStructure = [
13-
[ 'a', [ 'foo', 'bar' ] ],
13+
[ 'a', [ 'a', 'foo', 'bar' ] ],
1414
[ 'b', [ 'foo', 'bar' ] ],
1515
[ 'c', [ 'foo', 'bar' ] ],
1616
[ 'd', [ 'foo', 'bar' ] ],
@@ -91,7 +91,7 @@ fs.symlinkSync(symlinkTargetFile, pathModule.join(symlinksRootPath, 'symlink-src
9191
fs.symlinkSync(symlinkTargetDir, pathModule.join(symlinksRootPath, 'symlink-src-dir'));
9292

9393
const expected = [
94-
'a', 'a/bar', 'a/foo', 'aa', 'aa/bar', 'aa/foo',
94+
'a', 'a/a', 'a/bar', 'a/foo', 'aa', 'aa/bar', 'aa/foo',
9595
'abc', 'abc/def', 'abc/def/bar', 'abc/def/foo', 'abc/ghi', 'abc/ghi/bar', 'abc/ghi/foo',
9696
'b', 'b/bar', 'b/foo', 'bb', 'bb/bar', 'bb/foo',
9797
'c', 'c/bar', 'c/foo', 'cc', 'cc/bar', 'cc/foo',
@@ -128,15 +128,18 @@ for (let i = 0; i < expected.length; i++) {
128128
}
129129

130130
function getDirentPath(dirent) {
131-
return pathModule.relative(testDir, dirent.path);
131+
return pathModule.relative(testDir, pathModule.join(dirent.path, dirent.name));
132132
}
133133

134134
function assertDirents(dirents) {
135135
dirents.sort((a, b) => (getDirentPath(a) < getDirentPath(b) ? -1 : 1));
136-
for (const [i, dirent] of dirents.entries()) {
137-
assert(dirent instanceof fs.Dirent);
138-
assert.strictEqual(getDirentPath(dirent), expected[i]);
139-
}
136+
assert.deepStrictEqual(
137+
dirents.map((dirent) => {
138+
assert(dirent instanceof fs.Dirent);
139+
return getDirentPath(dirent);
140+
}),
141+
expected
142+
);
140143
}
141144

142145
function processDirSync(dir) {

test/sequential/test-fs-readdir-recursive.js

+10-7
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const tmpdir = require('../common/tmpdir');
99
const readdirDir = tmpdir.path;
1010

1111
const fileStructure = [
12-
[ 'a', [ 'foo', 'bar' ] ],
12+
[ 'a', [ 'a', 'foo', 'bar' ] ],
1313
[ 'b', [ 'foo', 'bar' ] ],
1414
[ 'c', [ 'foo', 'bar' ] ],
1515
[ 'd', [ 'foo', 'bar' ] ],
@@ -90,7 +90,7 @@ fs.symlinkSync(symlinkTargetFile, pathModule.join(symlinksRootPath, 'symlink-src
9090
fs.symlinkSync(symlinkTargetDir, pathModule.join(symlinksRootPath, 'symlink-src-dir'));
9191

9292
const expected = [
93-
'a', 'a/bar', 'a/foo', 'aa', 'aa/bar', 'aa/foo',
93+
'a', 'a/a', 'a/bar', 'a/foo', 'aa', 'aa/bar', 'aa/foo',
9494
'abc', 'abc/def', 'abc/def/bar', 'abc/def/foo', 'abc/ghi', 'abc/ghi/bar', 'abc/ghi/foo',
9595
'b', 'b/bar', 'b/foo', 'bb', 'bb/bar', 'bb/foo',
9696
'c', 'c/bar', 'c/foo', 'cc', 'cc/bar', 'cc/foo',
@@ -133,11 +133,14 @@ function getDirentPath(dirent) {
133133
function assertDirents(dirents) {
134134
assert.strictEqual(dirents.length, expected.length);
135135
dirents.sort((a, b) => (getDirentPath(a) < getDirentPath(b) ? -1 : 1));
136-
for (const [i, dirent] of dirents.entries()) {
137-
assert(dirent instanceof fs.Dirent);
138-
assert.notStrictEqual(dirent.name, undefined);
139-
assert.strictEqual(getDirentPath(dirent), expected[i]);
140-
}
136+
assert.deepStrictEqual(
137+
dirents.map((dirent) => {
138+
assert(dirent instanceof fs.Dirent);
139+
assert.notStrictEqual(dirent.name, undefined);
140+
return getDirentPath(dirent);
141+
}),
142+
expected
143+
);
141144
}
142145

143146
// readdirSync

0 commit comments

Comments
 (0)