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