2021-05-24 17:26:13 +01:00
/*!
* Tmp
*
* Copyright (c) 2011-2017 KARASZI Istvan <github@spam.raszi.hu>
*
* MIT Licensed
*/
/*
* Module dependencies.
*/
const fs = require ( 'fs' ) ;
const os = require ( 'os' ) ;
const path = require ( 'path' ) ;
const crypto = require ( 'crypto' ) ;
2022-03-03 17:18:51 +00:00
const _c = { fs : fs . constants , os : os . constants } ;
2021-05-24 17:26:13 +01:00
const rimraf = require ( 'rimraf' ) ;
/*
* The working inner variables.
*/
const
// the random characters to choose from
RANDOM _CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' ,
TEMPLATE _PATTERN = /XXXXXX/ ,
DEFAULT _TRIES = 3 ,
CREATE _FLAGS = ( _c . O _CREAT || _c . fs . O _CREAT ) | ( _c . O _EXCL || _c . fs . O _EXCL ) | ( _c . O _RDWR || _c . fs . O _RDWR ) ,
2022-03-03 17:18:51 +00:00
// constants are off on the windows platform and will not match the actual errno codes
IS _WIN32 = os . platform ( ) === 'win32' ,
2021-05-24 17:26:13 +01:00
EBADF = _c . EBADF || _c . os . errno . EBADF ,
ENOENT = _c . ENOENT || _c . os . errno . ENOENT ,
2022-03-03 17:18:51 +00:00
DIR _MODE = 0o700 /* 448 */ ,
FILE _MODE = 0o600 /* 384 */ ,
2021-05-24 17:26:13 +01:00
EXIT = 'exit' ,
// this will hold the objects need to be removed on exit
2022-03-03 17:18:51 +00:00
_removeObjects = [ ] ,
2021-05-24 17:26:13 +01:00
2022-03-03 17:18:51 +00:00
// API change in fs.rmdirSync leads to error when passing in a second parameter, e.g. the callback
FN _RMDIR _SYNC = fs . rmdirSync . bind ( fs ) ,
FN _RIMRAF _SYNC = rimraf . sync ;
2021-05-24 17:26:13 +01:00
2022-03-03 17:18:51 +00:00
let
_gracefulCleanup = false ;
2021-05-24 17:26:13 +01:00
/**
* Gets a temporary file name.
*
* @param {(Options|tmpNameCallback)} options options or callback
* @param {?tmpNameCallback} callback the callback function
*/
function tmpName ( options , callback ) {
2022-03-03 17:18:51 +00:00
const
2021-05-24 17:26:13 +01:00
args = _parseArguments ( options , callback ) ,
opts = args [ 0 ] ,
2022-03-03 17:18:51 +00:00
cb = args [ 1 ] ;
2021-05-24 17:26:13 +01:00
2022-03-03 17:18:51 +00:00
try {
_assertAndSanitizeOptions ( opts ) ;
} catch ( err ) {
return cb ( err ) ;
}
2021-05-24 17:26:13 +01:00
2022-03-03 17:18:51 +00:00
let tries = opts . tries ;
2021-05-24 17:26:13 +01:00
( function _getUniqueName ( ) {
try {
const name = _generateTmpName ( opts ) ;
// check whether the path exists then retry if needed
fs . stat ( name , function ( err ) {
/* istanbul ignore else */
if ( ! err ) {
/* istanbul ignore else */
if ( tries -- > 0 ) return _getUniqueName ( ) ;
return cb ( new Error ( 'Could not get a unique tmp filename, max tries reached ' + name ) ) ;
}
cb ( null , name ) ;
} ) ;
} catch ( err ) {
cb ( err ) ;
}
} ( ) ) ;
}
/**
* Synchronous version of tmpName.
*
* @param {Object} options
* @returns {string} the generated random name
* @throws {Error} if the options are invalid or could not generate a filename
*/
function tmpNameSync ( options ) {
2022-03-03 17:18:51 +00:00
const
2021-05-24 17:26:13 +01:00
args = _parseArguments ( options ) ,
2022-03-03 17:18:51 +00:00
opts = args [ 0 ] ;
2021-05-24 17:26:13 +01:00
2022-03-03 17:18:51 +00:00
_assertAndSanitizeOptions ( opts ) ;
2021-05-24 17:26:13 +01:00
2022-03-03 17:18:51 +00:00
let tries = opts . tries ;
2021-05-24 17:26:13 +01:00
do {
const name = _generateTmpName ( opts ) ;
try {
fs . statSync ( name ) ;
} catch ( e ) {
return name ;
}
} while ( tries -- > 0 ) ;
throw new Error ( 'Could not get a unique tmp filename, max tries reached' ) ;
}
/**
* Creates and opens a temporary file.
*
2022-03-03 17:18:51 +00:00
* @param {(Options|null|undefined|fileCallback)} options the config options or the callback function or null or undefined
2021-05-24 17:26:13 +01:00
* @param {?fileCallback} callback
*/
function file ( options , callback ) {
2022-03-03 17:18:51 +00:00
const
2021-05-24 17:26:13 +01:00
args = _parseArguments ( options , callback ) ,
opts = args [ 0 ] ,
cb = args [ 1 ] ;
// gets a temporary filename
tmpName ( opts , function _tmpNameCreated ( err , name ) {
/* istanbul ignore else */
if ( err ) return cb ( err ) ;
// create and open the file
fs . open ( name , CREATE _FLAGS , opts . mode || FILE _MODE , function _fileCreated ( err , fd ) {
2022-03-03 17:18:51 +00:00
/* istanbu ignore else */
2021-05-24 17:26:13 +01:00
if ( err ) return cb ( err ) ;
if ( opts . discardDescriptor ) {
2022-03-03 17:18:51 +00:00
return fs . close ( fd , function _discardCallback ( possibleErr ) {
// the chance of getting an error on close here is rather low and might occur in the most edgiest cases only
return cb ( possibleErr , name , undefined , _prepareTmpFileRemoveCallback ( name , - 1 , opts , false ) ) ;
2021-05-24 17:26:13 +01:00
} ) ;
2022-03-03 17:18:51 +00:00
} else {
// detachDescriptor passes the descriptor whereas discardDescriptor closes it, either way, we no longer care
// about the descriptor
const discardOrDetachDescriptor = opts . discardDescriptor || opts . detachDescriptor ;
cb ( null , name , fd , _prepareTmpFileRemoveCallback ( name , discardOrDetachDescriptor ? - 1 : fd , opts , false ) ) ;
2021-05-24 17:26:13 +01:00
}
} ) ;
} ) ;
}
/**
* Synchronous version of file.
*
* @param {Options} options
* @returns {FileSyncObject} object consists of name, fd and removeCallback
* @throws {Error} if cannot create a file
*/
function fileSync ( options ) {
2022-03-03 17:18:51 +00:00
const
2021-05-24 17:26:13 +01:00
args = _parseArguments ( options ) ,
opts = args [ 0 ] ;
const discardOrDetachDescriptor = opts . discardDescriptor || opts . detachDescriptor ;
const name = tmpNameSync ( opts ) ;
var fd = fs . openSync ( name , CREATE _FLAGS , opts . mode || FILE _MODE ) ;
/* istanbul ignore else */
if ( opts . discardDescriptor ) {
fs . closeSync ( fd ) ;
fd = undefined ;
}
return {
name : name ,
fd : fd ,
2022-03-03 17:18:51 +00:00
removeCallback : _prepareTmpFileRemoveCallback ( name , discardOrDetachDescriptor ? - 1 : fd , opts , true )
2021-05-24 17:26:13 +01:00
} ;
}
/**
* Creates a temporary directory.
*
* @param {(Options|dirCallback)} options the options or the callback function
* @param {?dirCallback} callback
*/
function dir ( options , callback ) {
2022-03-03 17:18:51 +00:00
const
2021-05-24 17:26:13 +01:00
args = _parseArguments ( options , callback ) ,
opts = args [ 0 ] ,
cb = args [ 1 ] ;
// gets a temporary filename
tmpName ( opts , function _tmpNameCreated ( err , name ) {
/* istanbul ignore else */
if ( err ) return cb ( err ) ;
// create the directory
fs . mkdir ( name , opts . mode || DIR _MODE , function _dirCreated ( err ) {
/* istanbul ignore else */
if ( err ) return cb ( err ) ;
2022-03-03 17:18:51 +00:00
cb ( null , name , _prepareTmpDirRemoveCallback ( name , opts , false ) ) ;
2021-05-24 17:26:13 +01:00
} ) ;
} ) ;
}
/**
* Synchronous version of dir.
*
* @param {Options} options
* @returns {DirSyncObject} object consists of name and removeCallback
* @throws {Error} if it cannot create a directory
*/
function dirSync ( options ) {
2022-03-03 17:18:51 +00:00
const
2021-05-24 17:26:13 +01:00
args = _parseArguments ( options ) ,
opts = args [ 0 ] ;
const name = tmpNameSync ( opts ) ;
fs . mkdirSync ( name , opts . mode || DIR _MODE ) ;
return {
name : name ,
2022-03-03 17:18:51 +00:00
removeCallback : _prepareTmpDirRemoveCallback ( name , opts , true )
2021-05-24 17:26:13 +01:00
} ;
}
/**
* Removes files asynchronously.
*
* @param {Object} fdPath
* @param {Function} next
* @private
*/
function _removeFileAsync ( fdPath , next ) {
const _handler = function ( err ) {
2022-03-03 17:18:51 +00:00
if ( err && ! _isENOENT ( err ) ) {
2021-05-24 17:26:13 +01:00
// reraise any unanticipated error
return next ( err ) ;
}
next ( ) ;
2022-03-03 17:18:51 +00:00
} ;
2021-05-24 17:26:13 +01:00
if ( 0 <= fdPath [ 0 ] )
2022-03-03 17:18:51 +00:00
fs . close ( fdPath [ 0 ] , function ( ) {
2021-05-24 17:26:13 +01:00
fs . unlink ( fdPath [ 1 ] , _handler ) ;
} ) ;
else fs . unlink ( fdPath [ 1 ] , _handler ) ;
}
/**
* Removes files synchronously.
*
* @param {Object} fdPath
* @private
*/
function _removeFileSync ( fdPath ) {
2022-03-03 17:18:51 +00:00
let rethrownException = null ;
2021-05-24 17:26:13 +01:00
try {
if ( 0 <= fdPath [ 0 ] ) fs . closeSync ( fdPath [ 0 ] ) ;
} catch ( e ) {
// reraise any unanticipated error
2022-03-03 17:18:51 +00:00
if ( ! _isEBADF ( e ) && ! _isENOENT ( e ) ) throw e ;
2021-05-24 17:26:13 +01:00
} finally {
try {
fs . unlinkSync ( fdPath [ 1 ] ) ;
}
catch ( e ) {
// reraise any unanticipated error
2022-03-03 17:18:51 +00:00
if ( ! _isENOENT ( e ) ) rethrownException = e ;
2021-05-24 17:26:13 +01:00
}
}
2022-03-03 17:18:51 +00:00
if ( rethrownException !== null ) {
throw rethrownException ;
}
2021-05-24 17:26:13 +01:00
}
/**
* Prepares the callback for removal of the temporary file.
*
2022-03-03 17:18:51 +00:00
* Returns either a sync callback or a async callback depending on whether
* fileSync or file was called, which is expressed by the sync parameter.
*
2021-05-24 17:26:13 +01:00
* @param {string} name the path of the file
* @param {number} fd file descriptor
* @param {Object} opts
2022-03-03 17:18:51 +00:00
* @param {boolean} sync
* @returns {fileCallback | fileCallbackSync}
2021-05-24 17:26:13 +01:00
* @private
*/
2022-03-03 17:18:51 +00:00
function _prepareTmpFileRemoveCallback ( name , fd , opts , sync ) {
const removeCallbackSync = _prepareRemoveCallback ( _removeFileSync , [ fd , name ] , sync ) ;
const removeCallback = _prepareRemoveCallback ( _removeFileAsync , [ fd , name ] , sync , removeCallbackSync ) ;
2021-05-24 17:26:13 +01:00
if ( ! opts . keep ) _removeObjects . unshift ( removeCallbackSync ) ;
2022-03-03 17:18:51 +00:00
return sync ? removeCallbackSync : removeCallback ;
2021-05-24 17:26:13 +01:00
}
/**
* Prepares the callback for removal of the temporary directory.
*
2022-03-03 17:18:51 +00:00
* Returns either a sync callback or a async callback depending on whether
* tmpFileSync or tmpFile was called, which is expressed by the sync parameter.
*
2021-05-24 17:26:13 +01:00
* @param {string} name
* @param {Object} opts
2022-03-03 17:18:51 +00:00
* @param {boolean} sync
2021-05-24 17:26:13 +01:00
* @returns {Function} the callback
* @private
*/
2022-03-03 17:18:51 +00:00
function _prepareTmpDirRemoveCallback ( name , opts , sync ) {
const removeFunction = opts . unsafeCleanup ? rimraf : fs . rmdir . bind ( fs ) ;
const removeFunctionSync = opts . unsafeCleanup ? FN _RIMRAF _SYNC : FN _RMDIR _SYNC ;
const removeCallbackSync = _prepareRemoveCallback ( removeFunctionSync , name , sync ) ;
const removeCallback = _prepareRemoveCallback ( removeFunction , name , sync , removeCallbackSync ) ;
2021-05-24 17:26:13 +01:00
if ( ! opts . keep ) _removeObjects . unshift ( removeCallbackSync ) ;
2022-03-03 17:18:51 +00:00
return sync ? removeCallbackSync : removeCallback ;
2021-05-24 17:26:13 +01:00
}
/**
* Creates a guarded function wrapping the removeFunction call.
*
2022-03-03 17:18:51 +00:00
* The cleanup callback is save to be called multiple times.
* Subsequent invocations will be ignored.
*
2021-05-24 17:26:13 +01:00
* @param {Function} removeFunction
2022-03-03 17:18:51 +00:00
* @param {string} fileOrDirName
* @param {boolean} sync
* @param {cleanupCallbackSync?} cleanupCallbackSync
* @returns {cleanupCallback | cleanupCallbackSync}
2021-05-24 17:26:13 +01:00
* @private
*/
2022-03-03 17:18:51 +00:00
function _prepareRemoveCallback ( removeFunction , fileOrDirName , sync , cleanupCallbackSync ) {
let called = false ;
2021-05-24 17:26:13 +01:00
2022-03-03 17:18:51 +00:00
// if sync is true, the next parameter will be ignored
2021-05-24 17:26:13 +01:00
return function _cleanupCallback ( next ) {
2022-03-03 17:18:51 +00:00
/* istanbul ignore else */
2021-05-24 17:26:13 +01:00
if ( ! called ) {
2022-03-03 17:18:51 +00:00
// remove cleanupCallback from cache
2021-05-24 17:26:13 +01:00
const toRemove = cleanupCallbackSync || _cleanupCallback ;
const index = _removeObjects . indexOf ( toRemove ) ;
/* istanbul ignore else */
if ( index >= 0 ) _removeObjects . splice ( index , 1 ) ;
called = true ;
2022-03-03 17:18:51 +00:00
if ( sync || removeFunction === FN _RMDIR _SYNC || removeFunction === FN _RIMRAF _SYNC ) {
return removeFunction ( fileOrDirName ) ;
} else {
return removeFunction ( fileOrDirName , next || function ( ) { } ) ;
}
}
2021-05-24 17:26:13 +01:00
} ;
}
/**
* The garbage collector.
*
* @private
*/
function _garbageCollector ( ) {
/* istanbul ignore else */
if ( ! _gracefulCleanup ) return ;
// the function being called removes itself from _removeObjects,
// loop until _removeObjects is empty
while ( _removeObjects . length ) {
try {
_removeObjects [ 0 ] ( ) ;
} catch ( e ) {
// already removed?
}
}
}
/**
2022-03-03 17:18:51 +00:00
* Random name generator based on crypto.
* Adapted from http://blog.tompawlak.org/how-to-generate-random-values-nodejs-javascript
*
* @param {number} howMany
* @returns {string} the generated random name
* @private
2021-05-24 17:26:13 +01:00
*/
2022-03-03 17:18:51 +00:00
function _randomChars ( howMany ) {
let
value = [ ] ,
rnd = null ;
// make sure that we do not fail because we ran out of entropy
try {
rnd = crypto . randomBytes ( howMany ) ;
} catch ( e ) {
rnd = crypto . pseudoRandomBytes ( howMany ) ;
}
for ( var i = 0 ; i < howMany ; i ++ ) {
value . push ( RANDOM _CHARS [ rnd [ i ] % RANDOM _CHARS . length ] ) ;
}
return value . join ( '' ) ;
2021-05-24 17:26:13 +01:00
}
/**
2022-03-03 17:18:51 +00:00
* Helper which determines whether a string s is blank, that is undefined, or empty or null.
*
* @private
* @param {string} s
* @returns {Boolean} true whether the string s is blank, false otherwise
2021-05-24 17:26:13 +01:00
*/
2022-03-03 17:18:51 +00:00
function _isBlank ( s ) {
return s === null || _isUndefined ( s ) || ! s . trim ( ) ;
2021-05-24 17:26:13 +01:00
}
/**
2022-03-03 17:18:51 +00:00
* Checks whether the `obj` parameter is defined or not.
2021-05-24 17:26:13 +01:00
*
2022-03-03 17:18:51 +00:00
* @param {Object} obj
* @returns {boolean} true if the object is undefined
* @private
*/
function _isUndefined ( obj ) {
return typeof obj === 'undefined' ;
}
/**
* Parses the function arguments.
2021-05-24 17:26:13 +01:00
*
2022-03-03 17:18:51 +00:00
* This function helps to have optional arguments.
2021-05-24 17:26:13 +01:00
*
2022-03-03 17:18:51 +00:00
* @param {(Options|null|undefined|Function)} options
* @param {?Function} callback
* @returns {Array} parsed arguments
* @private
2021-05-24 17:26:13 +01:00
*/
2022-03-03 17:18:51 +00:00
function _parseArguments ( options , callback ) {
/* istanbul ignore else */
if ( typeof options === 'function' ) {
return [ { } , options ] ;
}
/* istanbul ignore else */
if ( _isUndefined ( options ) ) {
return [ { } , callback ] ;
}
// copy options so we do not leak the changes we make internally
const actualOptions = { } ;
for ( const key of Object . getOwnPropertyNames ( options ) ) {
actualOptions [ key ] = options [ key ] ;
}
return [ actualOptions , callback ] ;
2021-05-24 17:26:13 +01:00
}
/**
2022-03-03 17:18:51 +00:00
* Generates a new temporary name.
2021-05-24 17:26:13 +01:00
*
2022-03-03 17:18:51 +00:00
* @param {Object} opts
* @returns {string} the new random name according to opts
2021-05-24 17:26:13 +01:00
* @private
*/
2022-03-03 17:18:51 +00:00
function _generateTmpName ( opts ) {
const tmpDir = opts . tmpdir ;
/* istanbul ignore else */
if ( ! _isUndefined ( opts . name ) )
return path . join ( tmpDir , opts . dir , opts . name ) ;
/* istanbul ignore else */
if ( ! _isUndefined ( opts . template ) )
return path . join ( tmpDir , opts . dir , opts . template ) . replace ( TEMPLATE _PATTERN , _randomChars ( 6 ) ) ;
// prefix and postfix
const name = [
opts . prefix ? opts . prefix : 'tmp' ,
'-' ,
process . pid ,
'-' ,
_randomChars ( 12 ) ,
opts . postfix ? '-' + opts . postfix : ''
] . join ( '' ) ;
return path . join ( tmpDir , opts . dir , name ) ;
2021-05-24 17:26:13 +01:00
}
/**
2022-03-03 17:18:51 +00:00
* Asserts whether the specified options are valid, also sanitizes options and provides sane defaults for missing
* options.
*
* @param {Options} options
* @private
2021-05-24 17:26:13 +01:00
*/
2022-03-03 17:18:51 +00:00
function _assertAndSanitizeOptions ( options ) {
options . tmpdir = _getTmpDir ( options ) ;
const tmpDir = options . tmpdir ;
/* istanbul ignore else */
if ( ! _isUndefined ( options . name ) )
_assertIsRelative ( options . name , 'name' , tmpDir ) ;
/* istanbul ignore else */
if ( ! _isUndefined ( options . dir ) )
_assertIsRelative ( options . dir , 'dir' , tmpDir ) ;
/* istanbul ignore else */
if ( ! _isUndefined ( options . template ) ) {
_assertIsRelative ( options . template , 'template' , tmpDir ) ;
if ( ! options . template . match ( TEMPLATE _PATTERN ) )
throw new Error ( ` Invalid template, found " ${ options . template } ". ` ) ;
}
/* istanbul ignore else */
if ( ! _isUndefined ( options . tries ) && isNaN ( options . tries ) || options . tries < 0 )
throw new Error ( ` Invalid tries, found " ${ options . tries } ". ` ) ;
// if a name was specified we will try once
options . tries = _isUndefined ( options . name ) ? options . tries || DEFAULT _TRIES : 1 ;
options . keep = ! ! options . keep ;
options . detachDescriptor = ! ! options . detachDescriptor ;
options . discardDescriptor = ! ! options . discardDescriptor ;
options . unsafeCleanup = ! ! options . unsafeCleanup ;
// sanitize dir, also keep (multiple) blanks if the user, purportedly sane, requests us to
options . dir = _isUndefined ( options . dir ) ? '' : path . relative ( tmpDir , _resolvePath ( options . dir , tmpDir ) ) ;
options . template = _isUndefined ( options . template ) ? undefined : path . relative ( tmpDir , _resolvePath ( options . template , tmpDir ) ) ;
// sanitize further if template is relative to options.dir
options . template = _isBlank ( options . template ) ? undefined : path . relative ( options . dir , options . template ) ;
// for completeness' sake only, also keep (multiple) blanks if the user, purportedly sane, requests us to
options . name = _isUndefined ( options . name ) ? undefined : _sanitizeName ( options . name ) ;
options . prefix = _isUndefined ( options . prefix ) ? '' : options . prefix ;
options . postfix = _isUndefined ( options . postfix ) ? '' : options . postfix ;
2021-05-24 17:26:13 +01:00
}
/**
2022-03-03 17:18:51 +00:00
* Resolve the specified path name in respect to tmpDir.
*
* The specified name might include relative path components, e.g. ../
* so we need to resolve in order to be sure that is is located inside tmpDir
2021-05-24 17:26:13 +01:00
*
2022-03-03 17:18:51 +00:00
* @param name
* @param tmpDir
* @returns {string}
2021-05-24 17:26:13 +01:00
* @private
*/
2022-03-03 17:18:51 +00:00
function _resolvePath ( name , tmpDir ) {
const sanitizedName = _sanitizeName ( name ) ;
if ( sanitizedName . startsWith ( tmpDir ) ) {
return path . resolve ( sanitizedName ) ;
} else {
return path . resolve ( path . join ( tmpDir , sanitizedName ) ) ;
}
2021-05-24 17:26:13 +01:00
}
/**
2022-03-03 17:18:51 +00:00
* Sanitize the specified path name by removing all quote characters.
2021-05-24 17:26:13 +01:00
*
2022-03-03 17:18:51 +00:00
* @param name
* @returns {string}
2021-05-24 17:26:13 +01:00
* @private
*/
2022-03-03 17:18:51 +00:00
function _sanitizeName ( name ) {
if ( _isBlank ( name ) ) {
return name ;
}
return name . replace ( /["']/g , '' ) ;
2021-05-24 17:26:13 +01:00
}
/**
2022-03-03 17:18:51 +00:00
* Asserts whether specified name is relative to the specified tmpDir.
2021-05-24 17:26:13 +01:00
*
2022-03-03 17:18:51 +00:00
* @param {string} name
* @param {string} option
* @param {string} tmpDir
* @throws {Error}
2021-05-24 17:26:13 +01:00
* @private
*/
2022-03-03 17:18:51 +00:00
function _assertIsRelative ( name , option , tmpDir ) {
if ( option === 'name' ) {
// assert that name is not absolute and does not contain a path
if ( path . isAbsolute ( name ) )
throw new Error ( ` ${ option } option must not contain an absolute path, found " ${ name } ". ` ) ;
// must not fail on valid .<name> or ..<name> or similar such constructs
let basename = path . basename ( name ) ;
if ( basename === '..' || basename === '.' || basename !== name )
throw new Error ( ` ${ option } option must not contain a path, found " ${ name } ". ` ) ;
2021-05-24 17:26:13 +01:00
}
2022-03-03 17:18:51 +00:00
else { // if (option === 'dir' || option === 'template') {
// assert that dir or template are relative to tmpDir
if ( path . isAbsolute ( name ) && ! name . startsWith ( tmpDir ) ) {
throw new Error ( ` ${ option } option must be relative to " ${ tmpDir } ", found " ${ name } ". ` ) ;
2021-05-24 17:26:13 +01:00
}
2022-03-03 17:18:51 +00:00
let resolvedPath = _resolvePath ( name , tmpDir ) ;
if ( ! resolvedPath . startsWith ( tmpDir ) )
throw new Error ( ` ${ option } option must be relative to " ${ tmpDir } ", found " ${ resolvedPath } ". ` ) ;
}
2021-05-24 17:26:13 +01:00
}
/**
2022-03-03 17:18:51 +00:00
* Helper for testing against EBADF to compensate changes made to Node 7.x under Windows.
2021-05-24 17:26:13 +01:00
*
* @private
*/
2022-03-03 17:18:51 +00:00
function _isEBADF ( error ) {
return _isExpectedError ( error , - EBADF , 'EBADF' ) ;
}
2021-05-24 17:26:13 +01:00
2022-03-03 17:18:51 +00:00
/**
* Helper for testing against ENOENT to compensate changes made to Node 7.x under Windows.
*
* @private
*/
function _isENOENT ( error ) {
return _isExpectedError ( error , - ENOENT , 'ENOENT' ) ;
2021-05-24 17:26:13 +01:00
}
2022-03-03 17:18:51 +00:00
/**
* Helper to determine whether the expected error code matches the actual code and errno,
* which will differ between the supported node versions.
*
* - Node >= 7.0:
* error.code {string}
* error.errno {number} any numerical value will be negated
*
* CAVEAT
*
* On windows, the errno for EBADF is -4083 but os.constants.errno.EBADF is different and we must assume that ENOENT
* is no different here.
*
* @param {SystemError} error
* @param {number} errno
* @param {string} code
* @private
*/
function _isExpectedError ( error , errno , code ) {
return IS _WIN32 ? error . code === code : error . code === code && error . errno === errno ;
}
/**
* Sets the graceful cleanup.
*
* If graceful cleanup is set, tmp will remove all controlled temporary objects on process exit, otherwise the
* temporary objects will remain in place, waiting to be cleaned up on system restart or otherwise scheduled temporary
* object removals.
*/
function setGracefulCleanup ( ) {
_gracefulCleanup = true ;
}
/**
* Returns the currently configured tmp dir from os.tmpdir().
*
* @private
* @param {?Options} options
* @returns {string} the currently configured tmp dir
*/
function _getTmpDir ( options ) {
return path . resolve ( _sanitizeName ( options && options . tmpdir || os . tmpdir ( ) ) ) ;
}
// Install process exit listener
process . addListener ( EXIT , _garbageCollector ) ;
2021-05-24 17:26:13 +01:00
/**
* Configuration options.
*
* @typedef {Object} Options
2022-03-03 17:18:51 +00:00
* @property {?boolean} keep the temporary object (file or dir) will not be garbage collected
2021-05-24 17:26:13 +01:00
* @property {?number} tries the number of tries before give up the name generation
2022-03-03 17:18:51 +00:00
* @property (?int) mode the access mode, defaults are 0o700 for directories and 0o600 for files
2021-05-24 17:26:13 +01:00
* @property {?string} template the "mkstemp" like filename template
2022-03-03 17:18:51 +00:00
* @property {?string} name fixed name relative to tmpdir or the specified dir option
* @property {?string} dir tmp directory relative to the root tmp directory in use
2021-05-24 17:26:13 +01:00
* @property {?string} prefix prefix for the generated name
* @property {?string} postfix postfix for the generated name
2022-03-03 17:18:51 +00:00
* @property {?string} tmpdir the root tmp directory which overrides the os tmpdir
2021-05-24 17:26:13 +01:00
* @property {?boolean} unsafeCleanup recursively removes the created temporary directory, even when it's not empty
2022-03-03 17:18:51 +00:00
* @property {?boolean} detachDescriptor detaches the file descriptor, caller is responsible for closing the file, tmp will no longer try closing the file during garbage collection
* @property {?boolean} discardDescriptor discards the file descriptor (closes file, fd is -1), tmp will no longer try closing the file during garbage collection
2021-05-24 17:26:13 +01:00
*/
/**
* @typedef {Object} FileSyncObject
* @property {string} name the name of the file
2022-03-03 17:18:51 +00:00
* @property {string} fd the file descriptor or -1 if the fd has been discarded
2021-05-24 17:26:13 +01:00
* @property {fileCallback} removeCallback the callback function to remove the file
*/
/**
* @typedef {Object} DirSyncObject
* @property {string} name the name of the directory
* @property {fileCallback} removeCallback the callback function to remove the directory
*/
/**
* @callback tmpNameCallback
* @param {?Error} err the error object if anything goes wrong
* @param {string} name the temporary file name
*/
/**
* @callback fileCallback
* @param {?Error} err the error object if anything goes wrong
* @param {string} name the temporary file name
2022-03-03 17:18:51 +00:00
* @param {number} fd the file descriptor or -1 if the fd had been discarded
2021-05-24 17:26:13 +01:00
* @param {cleanupCallback} fn the cleanup callback function
*/
2022-03-03 17:18:51 +00:00
/**
* @callback fileCallbackSync
* @param {?Error} err the error object if anything goes wrong
* @param {string} name the temporary file name
* @param {number} fd the file descriptor or -1 if the fd had been discarded
* @param {cleanupCallbackSync} fn the cleanup callback function
*/
2021-05-24 17:26:13 +01:00
/**
* @callback dirCallback
* @param {?Error} err the error object if anything goes wrong
* @param {string} name the temporary file name
* @param {cleanupCallback} fn the cleanup callback function
*/
2022-03-03 17:18:51 +00:00
/**
* @callback dirCallbackSync
* @param {?Error} err the error object if anything goes wrong
* @param {string} name the temporary file name
* @param {cleanupCallbackSync} fn the cleanup callback function
*/
2021-05-24 17:26:13 +01:00
/**
* Removes the temporary created file or directory.
*
* @callback cleanupCallback
2022-03-03 17:18:51 +00:00
* @param {simpleCallback} [next] function to call whenever the tmp object needs to be removed
*/
/**
* Removes the temporary created file or directory.
*
* @callback cleanupCallbackSync
2021-05-24 17:26:13 +01:00
*/
/**
* Callback function for function composition.
* @see {@link https://github.com/raszi/node-tmp/issues/57|raszi/node-tmp#57}
*
* @callback simpleCallback
*/
// exporting all the needed methods
2022-03-03 17:18:51 +00:00
// evaluate _getTmpDir() lazily, mainly for simplifying testing but it also will
2021-05-24 17:26:13 +01:00
// allow users to reconfigure the temporary directory
Object . defineProperty ( module . exports , 'tmpdir' , {
enumerable : true ,
configurable : false ,
get : function ( ) {
return _getTmpDir ( ) ;
}
} ) ;
module . exports . dir = dir ;
module . exports . dirSync = dirSync ;
module . exports . file = file ;
module . exports . fileSync = fileSync ;
module . exports . tmpName = tmpName ;
module . exports . tmpNameSync = tmpNameSync ;
module . exports . setGracefulCleanup = setGracefulCleanup ;