Skip to content

Commit be6fce9

Browse files
committed
fix #197: cleanupCallback must be sync or async based on initial API call
1 parent 6e79e62 commit be6fce9

File tree

2 files changed

+66
-45
lines changed

2 files changed

+66
-45
lines changed

CHANGELOG.md

Whitespace-only changes.

lib/tmp.js

Lines changed: 66 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,9 @@ function file(options, callback) {
251251
/* istanbul ignore else */
252252
if (err) return cb(err);
253253

254+
// FIXME overall handling of opts.discardDescriptor is off
254255
if (opts.discardDescriptor) {
256+
// FIXME must not unlink
255257
return fs.close(fd, function _discardCallback(err) {
256258
/* istanbul ignore else */
257259
if (err) {
@@ -270,12 +272,11 @@ function file(options, callback) {
270272
}
271273
cb(null, name, undefined, _prepareTmpFileRemoveCallback(name, -1, opts));
272274
});
275+
} else {
276+
// FIXME detachDescriptor passes the descriptor whereas discardDescriptor closes it
277+
const discardOrDetachDescriptor = opts.discardDescriptor || opts.detachDescriptor;
278+
cb(null, name, fd, _prepareTmpFileRemoveCallback(name, discardOrDetachDescriptor ? -1 : fd, opts, false));
273279
}
274-
/* istanbul ignore else */
275-
if (opts.detachDescriptor) {
276-
return cb(null, name, fd, _prepareTmpFileRemoveCallback(name, -1, opts));
277-
}
278-
cb(null, name, fd, _prepareTmpFileRemoveCallback(name, fd, opts));
279280
});
280281
});
281282
}
@@ -304,7 +305,7 @@ function fileSync(options) {
304305
return {
305306
name: name,
306307
fd: fd,
307-
removeCallback: _prepareTmpFileRemoveCallback(name, discardOrDetachDescriptor ? -1 : fd, opts)
308+
removeCallback: _prepareTmpFileRemoveCallback(name, discardOrDetachDescriptor ? -1 : fd, opts, true)
308309
};
309310
}
310311

@@ -330,7 +331,7 @@ function dir(options, callback) {
330331
/* istanbul ignore else */
331332
if (err) return cb(err);
332333

333-
cb(null, name, _prepareTmpDirRemoveCallback(name, opts));
334+
cb(null, name, _prepareTmpDirRemoveCallback(name, opts, false));
334335
});
335336
});
336337
}
@@ -352,7 +353,7 @@ function dirSync(options) {
352353

353354
return {
354355
name: name,
355-
removeCallback: _prepareTmpDirRemoveCallback(name, opts)
356+
removeCallback: _prepareTmpDirRemoveCallback(name, opts, true)
356357
};
357358
}
358359

@@ -370,7 +371,7 @@ function _removeFileAsync(fdPath, next) {
370371
return next(err);
371372
}
372373
next();
373-
}
374+
};
374375

375376
if (0 <= fdPath[0])
376377
fs.close(fdPath[0], function (err) {
@@ -405,19 +406,23 @@ function _removeFileSync(fdPath) {
405406
/**
406407
* Prepares the callback for removal of the temporary file.
407408
*
409+
* Returns either a sync callback or a async callback depending on whether
410+
* fileSync or file was called, which is expressed by the sync parameter.
411+
*
408412
* @param {string} name the path of the file
409413
* @param {number} fd file descriptor
410414
* @param {Object} opts
411-
* @returns {fileCallback}
415+
* @param {boolean} sync
416+
* @returns {fileCallback | fileCallbackSync}
412417
* @private
413418
*/
414-
function _prepareTmpFileRemoveCallback(name, fd, opts) {
415-
const removeCallbackSync = _prepareRemoveCallback(_removeFileSync, [fd, name]);
416-
const removeCallback = _prepareRemoveCallback(_removeFileAsync, [fd, name], removeCallbackSync);
419+
function _prepareTmpFileRemoveCallback(name, fd, opts, sync) {
420+
const removeCallbackSync = _prepareRemoveCallback(_removeFileSync, [fd, name], sync);
421+
const removeCallback = _prepareRemoveCallback(_removeFileAsync, [fd, name], sync, removeCallbackSync);
417422

418423
if (!opts.keep) _removeObjects.unshift(removeCallbackSync);
419424

420-
return removeCallback;
425+
return sync ? removeCallbackSync : removeCallback;
421426
}
422427

423428
/**
@@ -445,67 +450,62 @@ function _rimrafRemoveDirSyncWrapper(dirPath, next) {
445450
}
446451
}
447452

448-
const FN_RMDIR_SYNC = fs.rmdirSync.bind(fs);
449-
450453
/**
451454
* Prepares the callback for removal of the temporary directory.
452455
*
456+
* Returns either a sync callback or a async callback depending on whether
457+
* tmpFileSync or tmpFile was called, which is expressed by the sync parameter.
458+
*
453459
* @param {string} name
454460
* @param {Object} opts
461+
* @param {boolean} sync
455462
* @returns {Function} the callback
456463
* @private
457464
*/
458-
function _prepareTmpDirRemoveCallback(name, opts) {
465+
function _prepareTmpDirRemoveCallback(name, opts, sync) {
459466
const removeFunction = opts.unsafeCleanup ? _rimrafRemoveDirWrapper : fs.rmdir.bind(fs);
460-
const removeFunctionSync = opts.unsafeCleanup ? _rimrafRemoveDirSyncWrapper : FN_RMDIR_SYNC;
461-
const removeCallbackSync = _prepareRemoveCallback(removeFunctionSync, name);
462-
const removeCallback = _prepareRemoveCallback(removeFunction, name, removeCallbackSync);
467+
const removeFunctionSync = opts.unsafeCleanup ? _rimrafRemoveDirSyncWrapper : fs.rmdirSync.bind(fs);
468+
const removeCallbackSync = _prepareRemoveCallback(removeFunctionSync, name, sync);
469+
const removeCallback = _prepareRemoveCallback(removeFunction, name, sync, removeCallbackSync);
463470
if (!opts.keep) _removeObjects.unshift(removeCallbackSync);
464471

465-
return removeCallback;
472+
return sync ? removeCallbackSync : removeCallback;
466473
}
467474

468475
/**
469476
* Creates a guarded function wrapping the removeFunction call.
470477
*
478+
* The cleanup callback is save to be called multiple times.
479+
* Subsequent invocations will be ignored.
480+
*
471481
* @param {Function} removeFunction
472-
* @param {Object} arg
473-
* @returns {Function}
482+
* @param {string} fileOrDirName
483+
* @param {boolean} sync
484+
* @param {cleanupCallbackSync?} cleanupCallbackSync
485+
* @returns {cleanupCallback | cleanupCallbackSync}
474486
* @private
475487
*/
476-
function _prepareRemoveCallback(removeFunction, arg, cleanupCallbackSync) {
488+
function _prepareRemoveCallback(removeFunction, fileOrDirName, sync, cleanupCallbackSync) {
477489
var called = false;
478490

491+
// if sync is true, the next parameter will be ignored
479492
return function _cleanupCallback(next) {
480-
next = next || function () {};
493+
494+
/* istanbul ignore else */
481495
if (!called) {
496+
// remove cleanupCallback from cache
482497
const toRemove = cleanupCallbackSync || _cleanupCallback;
483498
const index = _removeObjects.indexOf(toRemove);
484499
/* istanbul ignore else */
485500
if (index >= 0) _removeObjects.splice(index, 1);
486501

487502
called = true;
488-
// sync?
489-
if (removeFunction.length === 1) {
490-
try {
491-
removeFunction(arg);
492-
return next(null);
493-
}
494-
catch (err) {
495-
// if no next is provided and since we are
496-
// in silent cleanup mode on process exit,
497-
// we will ignore the error
498-
return next(err);
499-
}
503+
if (sync) {
504+
return removeFunction(fileOrDirName);
500505
} else {
501-
// must no call rmdirSync/rmSync this way
502-
if (removeFunction == FN_RMDIR_SYNC) {
503-
return removeFunction(arg);
504-
} else {
505-
return removeFunction(arg, next);
506-
}
506+
return removeFunction(fileOrDirName, next || function() {});
507507
}
508-
} else return next(new Error('cleanup callback has already been called'));
508+
}
509509
};
510510
}
511511

@@ -726,18 +726,39 @@ _safely_install_sigint_listener();
726726
* @param {cleanupCallback} fn the cleanup callback function
727727
*/
728728

729+
/**
730+
* @callback fileCallbackSync
731+
* @param {?Error} err the error object if anything goes wrong
732+
* @param {string} name the temporary file name
733+
* @param {number} fd the file descriptor
734+
* @param {cleanupCallbackSync} fn the cleanup callback function
735+
*/
736+
729737
/**
730738
* @callback dirCallback
731739
* @param {?Error} err the error object if anything goes wrong
732740
* @param {string} name the temporary file name
733741
* @param {cleanupCallback} fn the cleanup callback function
734742
*/
735743

744+
/**
745+
* @callback dirCallbackSync
746+
* @param {?Error} err the error object if anything goes wrong
747+
* @param {string} name the temporary file name
748+
* @param {cleanupCallbackSync} fn the cleanup callback function
749+
*/
750+
736751
/**
737752
* Removes the temporary created file or directory.
738753
*
739754
* @callback cleanupCallback
740-
* @param {simpleCallback} [next] function to call after entry was removed
755+
* @param {simpleCallback} [next] function to call whenever the tmp object needs to be removed
756+
*/
757+
758+
/**
759+
* Removes the temporary created file or directory.
760+
*
761+
* @callback cleanupCallbackSync
741762
*/
742763

743764
/**

0 commit comments

Comments
 (0)