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