@@ -7,10 +7,12 @@ const {
7
7
NumberIsSafeInteger,
8
8
ObjectDefineProperty,
9
9
ObjectSetPrototypeOf,
10
+ Symbol,
10
11
} = primordials ;
11
12
12
13
const {
13
- ERR_OUT_OF_RANGE
14
+ ERR_OUT_OF_RANGE ,
15
+ ERR_STREAM_DESTROYED
14
16
} = require ( 'internal/errors' ) . codes ;
15
17
const internalUtil = require ( 'internal/util' ) ;
16
18
const { validateNumber } = require ( 'internal/validators' ) ;
@@ -22,6 +24,8 @@ const {
22
24
} = require ( 'internal/fs/utils' ) ;
23
25
const { Readable, Writable } = require ( 'stream' ) ;
24
26
const { toPathIfFileURL } = require ( 'internal/url' ) ;
27
+ const kIoDone = Symbol ( 'kIoDone' ) ;
28
+ const kIsPerformingIO = Symbol ( 'kIsPerformingIO' ) ;
25
29
26
30
const kMinPoolSpace = 128 ;
27
31
@@ -86,6 +90,7 @@ function ReadStream(path, options) {
86
90
this . pos = undefined ;
87
91
this . bytesRead = 0 ;
88
92
this . closed = false ;
93
+ this [ kIsPerformingIO ] = false ;
89
94
90
95
if ( this . start !== undefined ) {
91
96
checkPosition ( this . start , 'start' ) ;
@@ -155,6 +160,8 @@ ReadStream.prototype._read = function(n) {
155
160
} ) ;
156
161
}
157
162
163
+ if ( this . destroyed ) return ;
164
+
158
165
if ( ! pool || pool . length - pool . used < kMinPoolSpace ) {
159
166
// Discard the old pool.
160
167
allocNewPool ( this . readableHighWaterMark ) ;
@@ -178,7 +185,12 @@ ReadStream.prototype._read = function(n) {
178
185
return this . push ( null ) ;
179
186
180
187
// the actual read.
188
+ this [ kIsPerformingIO ] = true ;
181
189
fs . read ( this . fd , pool , pool . used , toRead , this . pos , ( er , bytesRead ) => {
190
+ this [ kIsPerformingIO ] = false ;
191
+ // Tell ._destroy() that it's safe to close the fd now.
192
+ if ( this . destroyed ) return this . emit ( kIoDone , er ) ;
193
+
182
194
if ( er ) {
183
195
if ( this . autoClose ) {
184
196
this . destroy ( ) ;
@@ -224,8 +236,12 @@ ReadStream.prototype._destroy = function(err, cb) {
224
236
return ;
225
237
}
226
238
239
+ if ( this [ kIsPerformingIO ] ) {
240
+ this . once ( kIoDone , ( er ) => closeFsStream ( this , cb , err || er ) ) ;
241
+ return ;
242
+ }
243
+
227
244
closeFsStream ( this , cb , err ) ;
228
- this . fd = null ;
229
245
} ;
230
246
231
247
function closeFsStream ( stream , cb , err ) {
@@ -236,6 +252,8 @@ function closeFsStream(stream, cb, err) {
236
252
if ( ! er )
237
253
stream . emit ( 'close' ) ;
238
254
} ) ;
255
+
256
+ stream . fd = null ;
239
257
}
240
258
241
259
ReadStream . prototype . close = function ( cb ) {
@@ -274,6 +292,7 @@ function WriteStream(path, options) {
274
292
this . pos = undefined ;
275
293
this . bytesWritten = 0 ;
276
294
this . closed = false ;
295
+ this [ kIsPerformingIO ] = false ;
277
296
278
297
if ( this . start !== undefined ) {
279
298
checkPosition ( this . start , 'start' ) ;
@@ -339,7 +358,17 @@ WriteStream.prototype._write = function(data, encoding, cb) {
339
358
} ) ;
340
359
}
341
360
361
+ if ( this . destroyed ) return cb ( new ERR_STREAM_DESTROYED ( 'write' ) ) ;
362
+
363
+ this [ kIsPerformingIO ] = true ;
342
364
fs . write ( this . fd , data , 0 , data . length , this . pos , ( er , bytes ) => {
365
+ this [ kIsPerformingIO ] = false ;
366
+ // Tell ._destroy() that it's safe to close the fd now.
367
+ if ( this . destroyed ) {
368
+ cb ( er ) ;
369
+ return this . emit ( kIoDone , er ) ;
370
+ }
371
+
343
372
if ( er ) {
344
373
if ( this . autoClose ) {
345
374
this . destroy ( ) ;
@@ -362,7 +391,8 @@ WriteStream.prototype._writev = function(data, cb) {
362
391
} ) ;
363
392
}
364
393
365
- const self = this ;
394
+ if ( this . destroyed ) return cb ( new ERR_STREAM_DESTROYED ( 'write' ) ) ;
395
+
366
396
const len = data . length ;
367
397
const chunks = new Array ( len ) ;
368
398
let size = 0 ;
@@ -374,12 +404,22 @@ WriteStream.prototype._writev = function(data, cb) {
374
404
size += chunk . length ;
375
405
}
376
406
377
- fs . writev ( this . fd , chunks , this . pos , function ( er , bytes ) {
407
+ this [ kIsPerformingIO ] = true ;
408
+ fs . writev ( this . fd , chunks , this . pos , ( er , bytes ) => {
409
+ this [ kIsPerformingIO ] = false ;
410
+ // Tell ._destroy() that it's safe to close the fd now.
411
+ if ( this . destroyed ) {
412
+ cb ( er ) ;
413
+ return this . emit ( kIoDone , er ) ;
414
+ }
415
+
378
416
if ( er ) {
379
- self . destroy ( ) ;
417
+ if ( this . autoClose ) {
418
+ this . destroy ( ) ;
419
+ }
380
420
return cb ( er ) ;
381
421
}
382
- self . bytesWritten += bytes ;
422
+ this . bytesWritten += bytes ;
383
423
cb ( ) ;
384
424
} ) ;
385
425
0 commit comments