@@ -13,8 +13,10 @@ const {
13
13
14
14
const {
15
15
ERR_INVALID_ARG_TYPE ,
16
- ERR_OUT_OF_RANGE ,
17
16
ERR_METHOD_NOT_IMPLEMENTED ,
17
+ ERR_OUT_OF_RANGE ,
18
+ ERR_STREAM_DESTROYED ,
19
+ ERR_SYSTEM_ERROR ,
18
20
} = require ( 'internal/errors' ) . codes ;
19
21
const {
20
22
deprecate,
@@ -392,22 +394,75 @@ WriteStream.prototype.open = openWriteFs;
392
394
393
395
WriteStream . prototype . _construct = _construct ;
394
396
397
+ function writeAll ( data , size , pos , cb , retries = 0 ) {
398
+ this [ kFs ] . write ( this . fd , data , 0 , size , pos , ( er , bytesWritten , buffer ) => {
399
+ // No data currently available and operation should be retried later.
400
+ if ( er ?. code === 'EAGAIN' ) {
401
+ er = null ;
402
+ bytesWritten = 0 ;
403
+ }
404
+
405
+ if ( this . destroyed || er ) {
406
+ return cb ( er || new ERR_STREAM_DESTROYED ( 'write' ) ) ;
407
+ }
408
+
409
+ this . bytesWritten += bytesWritten ;
410
+
411
+ retries = bytesWritten ? 0 : retries + 1 ;
412
+ size -= bytesWritten ;
413
+ pos += bytesWritten ;
414
+
415
+ // Try writing non-zero number of bytes up to 5 times.
416
+ if ( retries > 5 ) {
417
+ cb ( new ERR_SYSTEM_ERROR ( 'write failed' ) ) ;
418
+ } else if ( size ) {
419
+ writeAll . call ( this , buffer . slice ( bytesWritten ) , size , pos , cb , retries ) ;
420
+ } else {
421
+ cb ( ) ;
422
+ }
423
+ } ) ;
424
+ }
425
+
426
+ function writevAll ( chunks , size , pos , cb , retries = 0 ) {
427
+ this [ kFs ] . writev ( this . fd , chunks , this . pos , ( er , bytesWritten , buffers ) => {
428
+ // No data currently available and operation should be retried later.
429
+ if ( er ?. code === 'EAGAIN' ) {
430
+ er = null ;
431
+ bytesWritten = 0 ;
432
+ }
433
+
434
+ if ( this . destroyed || er ) {
435
+ return cb ( er || new ERR_STREAM_DESTROYED ( 'writev' ) ) ;
436
+ }
437
+
438
+ this . bytesWritten += bytesWritten ;
439
+
440
+ retries = bytesWritten ? 0 : retries + 1 ;
441
+ size -= bytesWritten ;
442
+ pos += bytesWritten ;
443
+
444
+ // Try writing non-zero number of bytes up to 5 times.
445
+ if ( retries > 5 ) {
446
+ cb ( new ERR_SYSTEM_ERROR ( 'writev failed' ) ) ;
447
+ } else if ( size ) {
448
+ writevAll . call ( this , [ Buffer . concat ( buffers ) . slice ( bytesWritten ) ] , size , pos , cb , retries ) ;
449
+ } else {
450
+ cb ( ) ;
451
+ }
452
+ } ) ;
453
+ }
454
+
395
455
WriteStream . prototype . _write = function ( data , encoding , cb ) {
396
456
this [ kIsPerformingIO ] = true ;
397
- this [ kFs ] . write ( this . fd , data , 0 , data . length , this . pos , ( er , bytes ) => {
457
+ writeAll . call ( this , data , data . length , this . pos , ( er ) => {
398
458
this [ kIsPerformingIO ] = false ;
399
459
if ( this . destroyed ) {
400
460
// Tell ._destroy() that it's safe to close the fd now.
401
461
cb ( er ) ;
402
462
return this . emit ( kIoDone , er ) ;
403
463
}
404
464
405
- if ( er ) {
406
- return cb ( er ) ;
407
- }
408
-
409
- this . bytesWritten += bytes ;
410
- cb ( ) ;
465
+ cb ( er ) ;
411
466
} ) ;
412
467
413
468
if ( this . pos !== undefined )
@@ -427,20 +482,15 @@ WriteStream.prototype._writev = function(data, cb) {
427
482
}
428
483
429
484
this [ kIsPerformingIO ] = true ;
430
- this [ kFs ] . writev ( this . fd , chunks , this . pos , ( er , bytes ) => {
485
+ writevAll . call ( this , chunks , size , this . pos , ( er ) => {
431
486
this [ kIsPerformingIO ] = false ;
432
487
if ( this . destroyed ) {
433
488
// Tell ._destroy() that it's safe to close the fd now.
434
489
cb ( er ) ;
435
490
return this . emit ( kIoDone , er ) ;
436
491
}
437
492
438
- if ( er ) {
439
- return cb ( er ) ;
440
- }
441
-
442
- this . bytesWritten += bytes ;
443
- cb ( ) ;
493
+ cb ( er ) ;
444
494
} ) ;
445
495
446
496
if ( this . pos !== undefined )
0 commit comments