Skip to content

Commit 95cbfce

Browse files
shackijjcodebytere
authored andcommitted
fs: fix readdir failure when libuv returns UV_DIRENT_UNKNOWN
Fixes: #33348 PR-URL: #33395 Refs: #33348 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 4ae4073 commit 95cbfce

File tree

3 files changed

+182
-3
lines changed

3 files changed

+182
-3
lines changed

lib/internal/fs/utils.js

+42-3
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,31 @@ function copyObject(source) {
173173
return target;
174174
}
175175

176+
const bufferSep = Buffer.from(pathModule.sep);
177+
178+
function join(path, name) {
179+
if ((typeof path === 'string' || isUint8Array(path)) &&
180+
name === undefined) {
181+
return path;
182+
}
183+
184+
if (typeof path === 'string' && isUint8Array(name)) {
185+
const pathBuffer = Buffer.from(pathModule.join(path, pathModule.sep));
186+
return Buffer.concat([pathBuffer, name]);
187+
}
188+
189+
if (typeof path === 'string' && typeof name === 'string') {
190+
return pathModule.join(path, name);
191+
}
192+
193+
if (isUint8Array(path) && isUint8Array(name)) {
194+
return Buffer.concat([path, bufferSep, name]);
195+
}
196+
197+
throw new ERR_INVALID_ARG_TYPE(
198+
'path', ['string', 'Buffer'], path);
199+
}
200+
176201
function getDirents(path, [names, types], callback) {
177202
let i;
178203
if (typeof callback === 'function') {
@@ -185,7 +210,14 @@ function getDirents(path, [names, types], callback) {
185210
const name = names[i];
186211
const idx = i;
187212
toFinish++;
188-
lazyLoadFs().lstat(pathModule.join(path, name), (err, stats) => {
213+
let filepath;
214+
try {
215+
filepath = join(path, name);
216+
} catch (err) {
217+
callback(err);
218+
return;
219+
}
220+
lazyLoadFs().lstat(filepath, (err, stats) => {
189221
if (err) {
190222
callback(err);
191223
return;
@@ -214,7 +246,14 @@ function getDirents(path, [names, types], callback) {
214246
function getDirent(path, name, type, callback) {
215247
if (typeof callback === 'function') {
216248
if (type === UV_DIRENT_UNKNOWN) {
217-
lazyLoadFs().lstat(pathModule.join(path, name), (err, stats) => {
249+
let filepath;
250+
try {
251+
filepath = join(path, name);
252+
} catch (err) {
253+
callback(err);
254+
return;
255+
}
256+
lazyLoadFs().lstat(filepath, (err, stats) => {
218257
if (err) {
219258
callback(err);
220259
return;
@@ -225,7 +264,7 @@ function getDirent(path, name, type, callback) {
225264
callback(null, new Dirent(name, type));
226265
}
227266
} else if (type === UV_DIRENT_UNKNOWN) {
228-
const stats = lazyLoadFs().lstatSync(pathModule.join(path, name));
267+
const stats = lazyLoadFs().lstatSync(join(path, name));
229268
return new DirentFromStats(name, stats);
230269
} else {
231270
return new Dirent(name, type);
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
'use strict';
2+
const common = require('../common');
3+
const fs = require('fs');
4+
5+
if (!common.isOSX) {
6+
common.skip('this tests works only on MacOS');
7+
}
8+
9+
const assert = require('assert');
10+
11+
fs.readdir(
12+
Buffer.from('/dev'),
13+
{ withFileTypes: true, encoding: 'buffer' },
14+
common.mustCall((e, d) => {
15+
assert.strictEqual(e, null);
16+
})
17+
);
+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// Flags: --expose-internals
2+
'use strict';
3+
4+
const common = require('../common');
5+
const { getDirents, getDirent } = require('internal/fs/utils');
6+
const assert = require('assert');
7+
const { internalBinding } = require('internal/test/binding');
8+
const { UV_DIRENT_UNKNOWN } = internalBinding('constants').fs;
9+
const fs = require('fs');
10+
const path = require('path');
11+
12+
const tmpdir = require('../common/tmpdir');
13+
const filename = 'foo';
14+
15+
{
16+
// setup
17+
tmpdir.refresh();
18+
fs.writeFileSync(path.join(tmpdir.path, filename), '');
19+
}
20+
// getDirents
21+
{
22+
// string + string
23+
getDirents(
24+
tmpdir.path,
25+
[[filename], [UV_DIRENT_UNKNOWN]],
26+
common.mustCall((err, names) => {
27+
assert.strictEqual(err, null);
28+
assert.strictEqual(names.length, 1);
29+
},
30+
));
31+
}
32+
{
33+
// string + Buffer
34+
getDirents(
35+
tmpdir.path,
36+
[[Buffer.from(filename)], [UV_DIRENT_UNKNOWN]],
37+
common.mustCall((err, names) => {
38+
assert.strictEqual(err, null);
39+
assert.strictEqual(names.length, 1);
40+
},
41+
));
42+
}
43+
{
44+
// Buffer + Buffer
45+
getDirents(
46+
Buffer.from(tmpdir.path),
47+
[[Buffer.from(filename)], [UV_DIRENT_UNKNOWN]],
48+
common.mustCall((err, names) => {
49+
assert.strictEqual(err, null);
50+
assert.strictEqual(names.length, 1);
51+
},
52+
));
53+
}
54+
{
55+
// wrong combination
56+
getDirents(
57+
42,
58+
[[Buffer.from(filename)], [UV_DIRENT_UNKNOWN]],
59+
common.mustCall((err) => {
60+
assert.strictEqual(
61+
err.message,
62+
[
63+
'The "path" argument must be of type string or an ' +
64+
'instance of Buffer. Received type number (42)'
65+
].join(''));
66+
},
67+
));
68+
}
69+
// getDirent
70+
{
71+
// string + string
72+
getDirent(
73+
tmpdir.path,
74+
filename,
75+
UV_DIRENT_UNKNOWN,
76+
common.mustCall((err, dirent) => {
77+
assert.strictEqual(err, null);
78+
assert.strictEqual(dirent.name, filename);
79+
},
80+
));
81+
}
82+
{
83+
// string + Buffer
84+
const filenameBuffer = Buffer.from(filename);
85+
getDirent(
86+
tmpdir.path,
87+
filenameBuffer,
88+
UV_DIRENT_UNKNOWN,
89+
common.mustCall((err, dirent) => {
90+
assert.strictEqual(err, null);
91+
assert.strictEqual(dirent.name, filenameBuffer);
92+
},
93+
));
94+
}
95+
{
96+
// Buffer + Buffer
97+
const filenameBuffer = Buffer.from(filename);
98+
getDirent(
99+
Buffer.from(tmpdir.path),
100+
filenameBuffer,
101+
UV_DIRENT_UNKNOWN,
102+
common.mustCall((err, dirent) => {
103+
assert.strictEqual(err, null);
104+
assert.strictEqual(dirent.name, filenameBuffer);
105+
},
106+
));
107+
}
108+
{
109+
// wrong combination
110+
getDirent(
111+
42,
112+
Buffer.from(filename),
113+
UV_DIRENT_UNKNOWN,
114+
common.mustCall((err) => {
115+
assert.strictEqual(
116+
err.message,
117+
[
118+
'The "path" argument must be of type string or an ' +
119+
'instance of Buffer. Received type number (42)'
120+
].join(''));
121+
},
122+
));
123+
}

0 commit comments

Comments
 (0)