@@ -16,6 +16,7 @@ const crypto = require('crypto');
16
16
const _c = fs . constants && os . constants ?
17
17
{ fs : fs . constants , os : os . constants } :
18
18
process . binding ( 'constants' ) ;
19
+ const rimraf = require ( 'rimraf' ) ;
19
20
20
21
/*
21
22
* The working inner variables.
@@ -302,45 +303,6 @@ function fileSync(options) {
302
303
} ;
303
304
}
304
305
305
- /**
306
- * Removes files and folders in a directory recursively.
307
- *
308
- * @param {string } root
309
- * @private
310
- */
311
- function _rmdirRecursiveSync ( root ) {
312
- const dirs = [ root ] ;
313
-
314
- do {
315
- var
316
- dir = dirs . pop ( ) ,
317
- deferred = false ,
318
- files = fs . readdirSync ( dir ) ;
319
-
320
- for ( var i = 0 , length = files . length ; i < length ; i ++ ) {
321
- var
322
- file = path . join ( dir , files [ i ] ) ,
323
- stat = fs . lstatSync ( file ) ; // lstat so we don't recurse into symlinked directories
324
-
325
- if ( stat . isDirectory ( ) ) {
326
- /* istanbul ignore else */
327
- if ( ! deferred ) {
328
- deferred = true ;
329
- dirs . push ( dir ) ;
330
- }
331
- dirs . push ( file ) ;
332
- } else {
333
- fs . unlinkSync ( file ) ;
334
- }
335
- }
336
-
337
- /* istanbul ignore else */
338
- if ( ! deferred ) {
339
- fs . rmdirSync ( dir ) ;
340
- }
341
- } while ( dirs . length !== 0 ) ;
342
- }
343
-
344
306
/**
345
307
* Creates a temporary directory.
346
308
*
@@ -390,52 +352,94 @@ function dirSync(options) {
390
352
}
391
353
392
354
/**
393
- * Prepares the callback for removal of the temporary file .
355
+ * Removes files asynchronously .
394
356
*
395
- * @param {string } name the path of the file
396
- * @param {number } fd file descriptor
397
- * @param {Object } opts
398
- * @returns {fileCallback }
357
+ * @param {Object } fdPath
358
+ * @param {Function } next
399
359
* @private
400
360
*/
401
- function _prepareTmpFileRemoveCallback ( name , fd , opts ) {
402
- const removeCallback = _prepareRemoveCallback ( function _removeCallback ( fdPath ) {
403
- try {
404
- /* istanbul ignore else */
405
- if ( 0 <= fdPath [ 0 ] ) {
406
- fs . closeSync ( fdPath [ 0 ] ) ;
407
- }
408
- }
409
- catch ( e ) {
410
- // under some node/windows related circumstances, a temporary file
411
- // may have not be created as expected or the file was already closed
412
- // by the user, in which case we will simply ignore the error
413
- /* istanbul ignore else */
414
- if ( ! isEBADF ( e ) && ! isENOENT ( e ) ) {
415
- // reraise any unanticipated error
416
- throw e ;
417
- }
361
+ function _removeFileAsync ( fdPath , next ) {
362
+ const _handler = function ( err ) {
363
+ if ( err && ! isENOENT ( err ) ) {
364
+ // reraise any unanticipated error
365
+ return next ( err ) ;
418
366
}
367
+ next ( ) ;
368
+ }
369
+
370
+ if ( 0 <= fdPath [ 0 ] )
371
+ fs . close ( fdPath [ 0 ] , function ( err ) {
372
+ fs . unlink ( fdPath [ 1 ] , _handler ) ;
373
+ } ) ;
374
+ else fs . unlink ( fdPath [ 1 ] , _handler ) ;
375
+ }
376
+
377
+ /**
378
+ * Removes files synchronously.
379
+ *
380
+ * @param {Object } fdPath
381
+ * @private
382
+ */
383
+ function _removeFileSync ( fdPath ) {
384
+ try {
385
+ if ( 0 <= fdPath [ 0 ] ) fs . closeSync ( fdPath [ 0 ] ) ;
386
+ } catch ( e ) {
387
+ // reraise any unanticipated error
388
+ if ( ! isEBADF ( e ) && ! isENOENT ( e ) ) throw e ;
389
+ } finally {
419
390
try {
420
391
fs . unlinkSync ( fdPath [ 1 ] ) ;
421
392
}
422
393
catch ( e ) {
423
- /* istanbul ignore else */
424
- if ( ! isENOENT ( e ) ) {
425
- // reraise any unanticipated error
426
- throw e ;
427
- }
394
+ // reraise any unanticipated error
395
+ if ( ! isENOENT ( e ) ) throw e ;
428
396
}
429
- } , [ fd , name ] ) ;
430
-
431
- /* istanbul ignore else */
432
- if ( ! opts . keep ) {
433
- _removeObjects . unshift ( removeCallback ) ;
434
397
}
398
+ }
399
+
400
+ /**
401
+ * Prepares the callback for removal of the temporary file.
402
+ *
403
+ * @param {string } name the path of the file
404
+ * @param {number } fd file descriptor
405
+ * @param {Object } opts
406
+ * @returns {fileCallback }
407
+ * @private
408
+ */
409
+ function _prepareTmpFileRemoveCallback ( name , fd , opts ) {
410
+ const removeCallbackSync = _prepareRemoveCallback ( _removeFileSync , [ fd , name ] ) ;
411
+ const removeCallback = _prepareRemoveCallback ( _removeFileAsync , [ fd , name ] , removeCallbackSync ) ;
412
+
413
+ if ( ! opts . keep ) _removeObjects . unshift ( removeCallbackSync ) ;
435
414
436
415
return removeCallback ;
437
416
}
438
417
418
+ /**
419
+ * Simple wrapper for rimraf.
420
+ *
421
+ * @param {string } dirPath
422
+ * @param {Function } next
423
+ * @private
424
+ */
425
+ function _rimrafRemoveDirWrapper ( dirPath , next ) {
426
+ rimraf ( dirPath , next ) ;
427
+ }
428
+
429
+ /**
430
+ * Simple wrapper for rimraf.sync.
431
+ *
432
+ * @param {string } dirPath
433
+ * @private
434
+ */
435
+ function _rimrafRemoveDirSyncWrapper ( dirPath , next ) {
436
+ try {
437
+ return next ( null , rimraf . sync ( dirPath ) ) ;
438
+ } catch ( err ) {
439
+ return next ( err ) ;
440
+ }
441
+ }
442
+
439
443
/**
440
444
* Prepares the callback for removal of the temporary directory.
441
445
*
@@ -445,13 +449,11 @@ function _prepareTmpFileRemoveCallback(name, fd, opts) {
445
449
* @private
446
450
*/
447
451
function _prepareTmpDirRemoveCallback ( name , opts ) {
448
- const removeFunction = opts . unsafeCleanup ? _rmdirRecursiveSync : fs . rmdirSync . bind ( fs ) ;
449
- const removeCallback = _prepareRemoveCallback ( removeFunction , name ) ;
450
-
451
- /* istanbul ignore else */
452
- if ( ! opts . keep ) {
453
- _removeObjects . unshift ( removeCallback ) ;
454
- }
452
+ const removeFunction = opts . unsafeCleanup ? _rimrafRemoveDirWrapper : fs . rmdir . bind ( fs ) ;
453
+ const removeFunctionSync = opts . unsafeCleanup ? _rimrafRemoveDirSyncWrapper : fs . rmdirSync . bind ( fs ) ;
454
+ const removeCallbackSync = _prepareRemoveCallback ( removeFunctionSync , name ) ;
455
+ const removeCallback = _prepareRemoveCallback ( removeFunction , name , removeCallbackSync ) ;
456
+ if ( ! opts . keep ) _removeObjects . unshift ( removeCallbackSync ) ;
455
457
456
458
return removeCallback ;
457
459
}
@@ -464,24 +466,32 @@ function _prepareTmpDirRemoveCallback(name, opts) {
464
466
* @returns {Function }
465
467
* @private
466
468
*/
467
- function _prepareRemoveCallback ( removeFunction , arg ) {
469
+ function _prepareRemoveCallback ( removeFunction , arg , cleanupCallbackSync ) {
468
470
var called = false ;
469
471
470
472
return function _cleanupCallback ( next ) {
471
- /* istanbul ignore else */
473
+ next = next || function ( ) { } ;
472
474
if ( ! called ) {
473
- const index = _removeObjects . indexOf ( _cleanupCallback ) ;
475
+ const toRemove = cleanupCallbackSync || _cleanupCallback ;
476
+ const index = _removeObjects . indexOf ( toRemove ) ;
474
477
/* istanbul ignore else */
475
- if ( index >= 0 ) {
476
- _removeObjects . splice ( index , 1 ) ;
477
- }
478
+ if ( index >= 0 ) _removeObjects . splice ( index , 1 ) ;
478
479
479
480
called = true ;
480
- removeFunction ( arg ) ;
481
- }
482
-
483
- /* istanbul ignore else */
484
- if ( next ) next ( null ) ;
481
+ // sync?
482
+ if ( removeFunction . length == 1 ) {
483
+ try {
484
+ removeFunction ( arg ) ;
485
+ return next ( null ) ;
486
+ }
487
+ catch ( err ) {
488
+ // if no next is provided and since we are
489
+ // in silent cleanup mode on process exit,
490
+ // we will ignore the error
491
+ return next ( err ) ;
492
+ }
493
+ } else return removeFunction ( arg , next ) ;
494
+ } else return next ( new Error ( 'cleanup callback has already been called' ) ) ;
485
495
} ;
486
496
}
487
497
@@ -492,15 +502,13 @@ function _prepareRemoveCallback(removeFunction, arg) {
492
502
*/
493
503
function _garbageCollector ( ) {
494
504
/* istanbul ignore else */
495
- if ( ! _gracefulCleanup ) {
496
- return ;
497
- }
505
+ if ( ! _gracefulCleanup ) return ;
498
506
499
507
// the function being called removes itself from _removeObjects,
500
508
// loop until _removeObjects is empty
501
509
while ( _removeObjects . length ) {
502
510
try {
503
- _removeObjects [ 0 ] . call ( null ) ;
511
+ _removeObjects [ 0 ] ( ) ;
504
512
} catch ( e ) {
505
513
// already removed?
506
514
}
@@ -555,12 +563,21 @@ function setGracefulCleanup() {
555
563
/**
556
564
* If there are multiple different versions of tmp in place, make sure that
557
565
* we recognize the old listeners.
566
+ *
567
+ * @param {Function } listener
568
+ * @private
569
+ * @returns {Boolean } true whether listener is a legacy listener
558
570
*/
559
571
function _is_legacy_listener ( listener ) {
560
572
return ( listener . name == '_exit' || listener . name == '_uncaughtExceptionThrown' )
561
573
&& listener . toString ( ) . indexOf ( '_garbageCollector();' ) > - 1 ;
562
574
}
563
575
576
+ /**
577
+ * Safely install process exit listeners.
578
+ *
579
+ * @private
580
+ */
564
581
function _safely_install_listener ( ) {
565
582
var listeners = process . listeners ( EVENT ) ;
566
583
@@ -570,7 +587,7 @@ function _safely_install_listener() {
570
587
var lstnr = listeners [ i ] ;
571
588
/* istanbul ignore else */
572
589
if ( lstnr . name == '_tmp$safe_listener' || _is_legacy_listener ( lstnr ) ) {
573
- /* istanbul ignore else */
590
+ // we must forget about the uncaughtException listener
574
591
if ( lstnr . name != '_uncaughtExceptionThrown' ) existingListeners . push ( lstnr ) ;
575
592
process . removeListener ( EVENT , lstnr ) ;
576
593
}
0 commit comments