Skip to content

Commit 5df105d

Browse files
committed
fs: fix process crash in fs.promises.writeFile
This commit fixes an issue where the process would crash if the input stream emitted an error while the file was being opened. Fixes: #58742
1 parent 1523d66 commit 5df105d

File tree

2 files changed

+45
-1
lines changed

2 files changed

+45
-1
lines changed

lib/internal/fs/promises.js

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1240,7 +1240,35 @@ async function writeFile(path, data, options) {
12401240

12411241
checkAborted(options.signal);
12421242

1243-
const fd = await open(path, flag, options.mode);
1243+
1244+
let fd;
1245+
if (isCustomIterable(data) && typeof data.on === 'function') {
1246+
fd = await new Promise((resolve, reject) => {
1247+
let isRejected = false;
1248+
const onStreamError = (err) => {
1249+
isRejected = true;
1250+
reject(err);
1251+
};
1252+
data.on('error', onStreamError);
1253+
open(path, flag, options.mode).then((fd) => {
1254+
data.removeListener('error', onStreamError);
1255+
if (isRejected) {
1256+
// If the stream emitted an error while opening the file, close the file.
1257+
// Ignore any errors from closing the file since the promise is already
1258+
// rejected with the stream error.
1259+
fd.close().then(undefined, () => {});
1260+
} else {
1261+
resolve(fd);
1262+
}
1263+
}, (err) => {
1264+
data.removeListener('error', onStreamError);
1265+
reject(err);
1266+
});
1267+
});
1268+
} else {
1269+
fd = await open(path, flag, options.mode);
1270+
}
1271+
12441272
let writeOp = writeFileHandle(fd, data, options.signal, options.encoding);
12451273

12461274
if (flush) {

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,21 @@ async function doReadWithEncoding() {
161161
assert.deepStrictEqual(data, syncData);
162162
}
163163

164+
async function doWriteStreamWithError() {
165+
const s1 = new Readable({
166+
read() {}
167+
});
168+
169+
process.nextTick(() => {
170+
s1.emit('error', new Error('Boom'));
171+
});
172+
173+
await assert.rejects(
174+
fsPromises.writeFile(otherDest, s1),
175+
{ message: 'Boom' }
176+
);
177+
}
178+
164179
(async () => {
165180
await doWrite();
166181
await doWriteWithCancel();
@@ -169,6 +184,7 @@ async function doReadWithEncoding() {
169184
await doReadWithEncoding();
170185
await doWriteStream();
171186
await doWriteStreamWithCancel();
187+
await doWriteStreamWithError();
172188
await doWriteIterable();
173189
await doWriteInvalidIterable();
174190
await doWriteIterableWithEncoding();

0 commit comments

Comments
 (0)