"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/tmp/lib/tmp.js" (11 Apr 2017, 10332 Bytes) of package /windows/misc/atom-windows.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Javascript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*!
    2  * Tmp
    3  *
    4  * Copyright (c) 2011-2015 KARASZI Istvan <github@spam.raszi.hu>
    5  *
    6  * MIT Licensed
    7  */
    8 
    9 /**
   10  * Module dependencies.
   11  */
   12 var
   13   fs     = require('fs'),
   14   path   = require('path'),
   15   os     = require('os'),
   16   crypto = require('crypto'),
   17   exists = fs.exists || path.exists,
   18   existsSync = fs.existsSync || path.existsSync,
   19   tmpDir = require('os-tmpdir'),
   20   _c     = require('constants');
   21 
   22 
   23 /**
   24  * The working inner variables.
   25  */
   26 var
   27   // store the actual TMP directory
   28   _TMP = tmpDir(),
   29 
   30   // the random characters to choose from
   31   RANDOM_CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
   32 
   33   TEMPLATE_PATTERN = /XXXXXX/,
   34 
   35   DEFAULT_TRIES = 3,
   36 
   37   CREATE_FLAGS = _c.O_CREAT | _c.O_EXCL | _c.O_RDWR,
   38 
   39   DIR_MODE = 448 /* 0700 */,
   40   FILE_MODE = 384 /* 0600 */,
   41 
   42   // this will hold the objects need to be removed on exit
   43   _removeObjects = [],
   44 
   45   _gracefulCleanup = false,
   46   _uncaughtException = false;
   47 
   48 /**
   49  * Random name generator based on crypto.
   50  * Adapted from http://blog.tompawlak.org/how-to-generate-random-values-nodejs-javascript
   51  *
   52  * @param {Number} howMany
   53  * @return {String}
   54  * @api private
   55  */
   56 function _randomChars(howMany) {
   57   var
   58     value = [],
   59     rnd = null;
   60 
   61   // make sure that we do not fail because we ran out of entropy
   62   try {
   63     rnd = crypto.randomBytes(howMany);
   64   } catch (e) {
   65     rnd = crypto.pseudoRandomBytes(howMany);
   66   }
   67 
   68   for (var i = 0; i < howMany; i++) {
   69     value.push(RANDOM_CHARS[rnd[i] % RANDOM_CHARS.length]);
   70   }
   71 
   72   return value.join('');
   73 }
   74 
   75 /**
   76  * Checks whether the `obj` parameter is defined or not.
   77  *
   78  * @param {Object} obj
   79  * @return {Boolean}
   80  * @api private
   81  */
   82 function _isUndefined(obj) {
   83   return typeof obj === 'undefined';
   84 }
   85 
   86 /**
   87  * Parses the function arguments.
   88  *
   89  * This function helps to have optional arguments.
   90  *
   91  * @param {Object} options
   92  * @param {Function} callback
   93  * @api private
   94  */
   95 function _parseArguments(options, callback) {
   96   if (typeof options == 'function') {
   97     var
   98       tmp = options;
   99       options = callback || {};
  100       callback = tmp;
  101   } else if (typeof options == 'undefined') {
  102     options = {};
  103   }
  104 
  105   return [options, callback];
  106 }
  107 
  108 /**
  109  * Generates a new temporary name.
  110  *
  111  * @param {Object} opts
  112  * @returns {String}
  113  * @api private
  114  */
  115 function _generateTmpName(opts) {
  116   if (opts.name) {
  117     return path.join(opts.dir || _TMP, opts.name);
  118   }
  119 
  120   // mkstemps like template
  121   if (opts.template) {
  122     return opts.template.replace(TEMPLATE_PATTERN, _randomChars(6));
  123   }
  124 
  125   // prefix and postfix
  126   var name = [
  127     opts.prefix || 'tmp-',
  128     process.pid,
  129     _randomChars(12),
  130     opts.postfix || ''
  131   ].join('');
  132 
  133   return path.join(opts.dir || _TMP, name);
  134 }
  135 
  136 /**
  137  * Gets a temporary file name.
  138  *
  139  * @param {Object} options
  140  * @param {Function} callback
  141  * @api private
  142  */
  143 function _getTmpName(options, callback) {
  144   var
  145     args = _parseArguments(options, callback),
  146     opts = args[0],
  147     cb = args[1],
  148     tries = opts.tries || DEFAULT_TRIES;
  149 
  150   if (isNaN(tries) || tries < 0)
  151     return cb(new Error('Invalid tries'));
  152 
  153   if (opts.template && !opts.template.match(TEMPLATE_PATTERN))
  154     return cb(new Error('Invalid template provided'));
  155 
  156   (function _getUniqueName() {
  157     var name = _generateTmpName(opts);
  158 
  159     // check whether the path exists then retry if needed
  160     exists(name, function _pathExists(pathExists) {
  161       if (pathExists) {
  162         if (tries-- > 0) return _getUniqueName();
  163 
  164         return cb(new Error('Could not get a unique tmp filename, max tries reached ' + name));
  165       }
  166 
  167       cb(null, name);
  168     });
  169   }());
  170 }
  171 
  172 /**
  173  * Synchronous version of _getTmpName.
  174  *
  175  * @param {Object} options
  176  * @returns {String}
  177  * @api private
  178  */
  179 function _getTmpNameSync(options) {
  180   var
  181     args = _parseArguments(options),
  182     opts = args[0],
  183     tries = opts.tries || DEFAULT_TRIES;
  184 
  185   if (isNaN(tries) || tries < 0)
  186     throw new Error('Invalid tries');
  187 
  188   if (opts.template && !opts.template.match(TEMPLATE_PATTERN))
  189     throw new Error('Invalid template provided');
  190 
  191   do {
  192     var name = _generateTmpName(opts);
  193     if (!existsSync(name)) {
  194       return name;
  195     }
  196   } while (tries-- > 0);
  197 
  198   throw new Error('Could not get a unique tmp filename, max tries reached');
  199 }
  200 
  201 /**
  202  * Creates and opens a temporary file.
  203  *
  204  * @param {Object} options
  205  * @param {Function} callback
  206  * @api public
  207  */
  208 function _createTmpFile(options, callback) {
  209   var
  210     args = _parseArguments(options, callback),
  211     opts = args[0],
  212     cb = args[1];
  213 
  214     opts.postfix = (_isUndefined(opts.postfix)) ? '.tmp' : opts.postfix;
  215 
  216   // gets a temporary filename
  217   _getTmpName(opts, function _tmpNameCreated(err, name) {
  218     if (err) return cb(err);
  219 
  220     // create and open the file
  221     fs.open(name, CREATE_FLAGS, opts.mode || FILE_MODE, function _fileCreated(err, fd) {
  222       if (err) return cb(err);
  223 
  224       cb(null, name, fd, _prepareTmpFileRemoveCallback(name, fd, opts));
  225     });
  226   });
  227 }
  228 
  229 /**
  230  * Synchronous version of _createTmpFile.
  231  *
  232  * @param {Object} options
  233  * @returns {Object} object consists of name, fd and removeCallback
  234  * @api private
  235  */
  236 function _createTmpFileSync(options) {
  237   var
  238     args = _parseArguments(options),
  239     opts = args[0];
  240 
  241     opts.postfix = opts.postfix || '.tmp';
  242 
  243   var name = _getTmpNameSync(opts);
  244   var fd = fs.openSync(name, CREATE_FLAGS, opts.mode || FILE_MODE);
  245 
  246   return {
  247     name : name,
  248     fd : fd,
  249     removeCallback : _prepareTmpFileRemoveCallback(name, fd, opts)
  250   };
  251 }
  252 
  253 /**
  254  * Removes files and folders in a directory recursively.
  255  *
  256  * @param {String} root
  257  * @api private
  258  */
  259 function _rmdirRecursiveSync(root) {
  260   var dirs = [root];
  261 
  262   do {
  263     var
  264       dir = dirs.pop(),
  265       deferred = false,
  266       files = fs.readdirSync(dir);
  267 
  268     for (var i = 0, length = files.length; i < length; i++) {
  269       var
  270         file = path.join(dir, files[i]),
  271         stat = fs.lstatSync(file); // lstat so we don't recurse into symlinked directories
  272 
  273       if (stat.isDirectory()) {
  274         if (!deferred) {
  275           deferred = true;
  276           dirs.push(dir);
  277         }  
  278         dirs.push(file);
  279       } else {
  280         fs.unlinkSync(file);
  281       }
  282     }
  283 
  284     if (!deferred) {
  285       fs.rmdirSync(dir);
  286     }
  287   } while (dirs.length !== 0);
  288 }
  289 
  290 /**
  291  * Creates a temporary directory.
  292  *
  293  * @param {Object} options
  294  * @param {Function} callback
  295  * @api public
  296  */
  297 function _createTmpDir(options, callback) {
  298   var
  299     args = _parseArguments(options, callback),
  300     opts = args[0],
  301     cb = args[1];
  302 
  303   // gets a temporary filename
  304   _getTmpName(opts, function _tmpNameCreated(err, name) {
  305     if (err) return cb(err);
  306 
  307     // create the directory
  308     fs.mkdir(name, opts.mode || DIR_MODE, function _dirCreated(err) {
  309       if (err) return cb(err);
  310 
  311       cb(null, name, _prepareTmpDirRemoveCallback(name, opts));
  312     });
  313   });
  314 }
  315 
  316 /**
  317  * Synchronous version of _createTmpDir.
  318  *
  319  * @param {Object} options
  320  * @returns {Object} object consists of name and removeCallback
  321  * @api private
  322  */
  323 function _createTmpDirSync(options) {
  324   var
  325     args = _parseArguments(options),
  326     opts = args[0];
  327 
  328   var name = _getTmpNameSync(opts);
  329   fs.mkdirSync(name, opts.mode || DIR_MODE);
  330 
  331   return {
  332     name : name,
  333     removeCallback : _prepareTmpDirRemoveCallback(name, opts)
  334   };
  335 }
  336 
  337 /**
  338  * Prepares the callback for removal of the temporary file.
  339  *
  340  * @param {String} name
  341  * @param {int} fd
  342  * @param {Object} opts
  343  * @api private
  344  * @returns {Function} the callback
  345  */
  346 function _prepareTmpFileRemoveCallback(name, fd, opts) {
  347   var removeCallback = _prepareRemoveCallback(function _removeCallback(fdPath) {
  348     try {
  349       fs.closeSync(fdPath[0]);
  350     }
  351     catch (e) {
  352       // under some node/windows related circumstances, a temporary file 
  353       // may have not be created as expected or the file was already closed
  354       // by the user, in which case we will simply ignore the error
  355       if (e.errno != -_c.EBADF && e.errno != -c.ENOENT) {
  356         // reraise any unanticipated error
  357         throw e;
  358       }
  359     }
  360     fs.unlinkSync(fdPath[1]);
  361   }, [fd, name]);
  362 
  363   if (!opts.keep) {
  364     _removeObjects.unshift(removeCallback);
  365   }
  366 
  367   return removeCallback;
  368 }
  369 
  370 /**
  371  * Prepares the callback for removal of the temporary directory.
  372  *
  373  * @param {String} name
  374  * @param {Object} opts
  375  * @returns {Function} the callback
  376  * @api private
  377  */
  378 function _prepareTmpDirRemoveCallback(name, opts) {
  379   var removeFunction = opts.unsafeCleanup ? _rmdirRecursiveSync : fs.rmdirSync.bind(fs);
  380   var removeCallback = _prepareRemoveCallback(removeFunction, name);
  381 
  382   if (!opts.keep) {
  383     _removeObjects.unshift(removeCallback);
  384   }
  385 
  386   return removeCallback;
  387 }
  388 
  389 /**
  390  * Creates a guarded function wrapping the removeFunction call.
  391  *
  392  * @param {Function} removeFunction
  393  * @param {Object} arg
  394  * @returns {Function}
  395  * @api private
  396  */
  397 function _prepareRemoveCallback(removeFunction, arg) {
  398   var called = false;
  399 
  400   return function _cleanupCallback() {
  401     if (called) return;
  402 
  403     var index = _removeObjects.indexOf(removeFunction);
  404     if (index >= 0) {
  405       _removeObjects.splice(index, 1);
  406     }
  407 
  408     called = true;
  409     removeFunction(arg);
  410   };
  411 }
  412 
  413 /**
  414  * The garbage collector.
  415  *
  416  * @api private
  417  */
  418 function _garbageCollector() {
  419   if (_uncaughtException && !_gracefulCleanup) {
  420     return;
  421   }
  422 
  423   for (var i = 0, length = _removeObjects.length; i < length; i++) {
  424     try {
  425       _removeObjects[i].call(null);
  426     } catch (e) {
  427       // already removed?
  428     }
  429   }
  430 }
  431 
  432 function _setGracefulCleanup() {
  433   _gracefulCleanup = true;
  434 }
  435 
  436 var version = process.versions.node.split('.').map(function (value) {
  437   return parseInt(value, 10);
  438 });
  439 
  440 if (version[0] === 0 && (version[1] < 9 || version[1] === 9 && version[2] < 5)) {
  441   process.addListener('uncaughtException', function _uncaughtExceptionThrown(err) {
  442     _uncaughtException = true;
  443     _garbageCollector();
  444 
  445     throw err;
  446   });
  447 }
  448 
  449 process.addListener('exit', function _exit(code) {
  450   if (code) _uncaughtException = true;
  451   _garbageCollector();
  452 });
  453 
  454 // exporting all the needed methods
  455 module.exports.tmpdir = _TMP;
  456 module.exports.dir = _createTmpDir;
  457 module.exports.dirSync = _createTmpDirSync;
  458 module.exports.file = _createTmpFile;
  459 module.exports.fileSync = _createTmpFileSync;
  460 module.exports.tmpName = _getTmpName;
  461 module.exports.tmpNameSync = _getTmpNameSync;
  462 module.exports.setGracefulCleanup = _setGracefulCleanup;