Skip to content

Commit a76fa60

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 b57778f commit a76fa60

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
@@ -144,6 +144,31 @@ function copyObject(source) {
144144
return target;
145145
}
146146

147+
const bufferSep = Buffer.from(pathModule.sep);
148+
149+
function join(path, name) {
150+
if ((typeof path === 'string' || isUint8Array(path)) &&
151+
name === undefined) {
152+
return path;
153+
}
154+
155+
if (typeof path === 'string' && isUint8Array(name)) {
156+
const pathBuffer = Buffer.from(pathModule.join(path, pathModule.sep));
157+
return Buffer.concat([pathBuffer, name]);
158+
}
159+
160+
if (typeof path === 'string' && typeof name === 'string') {
161+
return pathModule.join(path, name);
162+
}
163+
164+
if (isUint8Array(path) && isUint8Array(name)) {
165+
return Buffer.concat([path, bufferSep, name]);
166+
}
167+
168+
throw new ERR_INVALID_ARG_TYPE(
169+
'path', ['string', 'Buffer'], path);
170+
}
171+
147172
function getDirents(path, [names, types], callback) {
148173
let i;
149174
if (typeof callback === 'function') {
@@ -156,7 +181,14 @@ function getDirents(path, [names, types], callback) {
156181
const name = names[i];
157182
const idx = i;
158183
toFinish++;
159-
lazyLoadFs().lstat(pathModule.join(path, name), (err, stats) => {
184+
let filepath;
185+
try {
186+
filepath = join(path, name);
187+
} catch (err) {
188+
callback(err);
189+
return;
190+
}
191+
lazyLoadFs().lstat(filepath, (err, stats) => {
160192
if (err) {
161193
callback(err);
162194
return;
@@ -185,7 +217,14 @@ function getDirents(path, [names, types], callback) {
185217
function getDirent(path, name, type, callback) {
186218
if (typeof callback === 'function') {
187219
if (type === UV_DIRENT_UNKNOWN) {
188-
lazyLoadFs().lstat(pathModule.join(path, name), (err, stats) => {
220+
let filepath;
221+
try {
222+
filepath = join(path, name);
223+
} catch (err) {
224+
callback(err);
225+
return;
226+
}
227+
lazyLoadFs().lstat(filepath, (err, stats) => {
189228
if (err) {
190229
callback(err);
191230
return;
@@ -196,7 +235,7 @@ function getDirent(path, name, type, callback) {
196235
callback(null, new Dirent(name, type));
197236
}
198237
} else if (type === UV_DIRENT_UNKNOWN) {
199-
const stats = lazyLoadFs().lstatSync(pathModule.join(path, name));
238+
const stats = lazyLoadFs().lstatSync(join(path, name));
200239
return new DirentFromStats(name, stats);
201240
} else {
202241
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)