Skip to content

Commit 63ecd7c

Browse files
committed
fix: end a zip directory entry through flow control, not a timer
The directory placeholder emitted 'end' from a setImmediate, so the event fired whether or not the consumer had finished with the entry. A listener that creates the directory asynchronously would therefore be handed the next entry, a file inside that directory, before the directory existed, and the write failed with ENOENT. That is the intermittent "ENOENT ... /xxx/bar.txt" seen in test/zip/uncompress_stream.test.js on loaded CI runners. Reproduces every time by delaying the mkdir in the entry handler. Push EOF instead, so 'end' arrives only once the consumer reads or resumes the entry and the ordering no longer depends on timing.
1 parent 35ab10c commit 63ecd7c

1 file changed

Lines changed: 5 additions & 1 deletion

File tree

‎lib/zip/uncompress_stream.js‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,11 @@ class ZipUncompressStream extends UncompressBaseStream {
125125
const placeholder = new stream.Readable({ read() {} });
126126
debug('directory, header: %j', header);
127127
this.emit('entry', header, placeholder, next);
128-
setImmediate(() => placeholder.emit('end'));
128+
// Push EOF rather than emitting 'end' on a timer: a fabricated event fires
129+
// whether or not the consumer has finished with the entry, so a listener
130+
// that creates the directory asynchronously would see the next entry, a
131+
// file inside that directory, arrive before the directory exists.
132+
placeholder.push(null);
129133
}
130134
})
131135
.on('end', () => this._finalCallback())

0 commit comments

Comments
 (0)