File: /var/www/tana/frontend/node_modules/download/node_modules/vinyl-fs/lib/fileOperations.js
'use strict';
var fs = require('graceful-fs');
var assign = require('object-assign');
var isEqual = require('lodash.isequal');
var isValidDate = require('vali-date');
// TODO shared module
// TODO include sticky/setuid/setgid, i.e. 7777?
var MASK_MODE = parseInt('0777', 8);
var DEFAULT_FILE_MODE = parseInt('0666', 8);
var APPEND_MODE_REGEXP = /a/;
function closeFd(propagatedErr, fd, callback) {
  if (typeof fd !== 'number') {
    return callback(propagatedErr);
  }
  fs.close(fd, onClosed);
  function onClosed(closeErr) {
    if (propagatedErr || closeErr) {
      return callback(propagatedErr || closeErr);
    }
    callback();
  }
}
function getModeDiff(fsMode, vinylMode) {
  var modeDiff = 0;
  if (typeof vinylMode === 'number') {
    modeDiff = (vinylMode ^ fsMode) & MASK_MODE;
  }
  return modeDiff;
}
function getTimesDiff(fsStat, vinylStat) {
  if (!isValidDate(vinylStat.mtime)) {
    return;
  }
  if (isEqual(vinylStat.mtime, fsStat.mtime) &&
      isEqual(vinylStat.atime, fsStat.atime)) {
    return;
  }
  var atime;
  if (isValidDate(vinylStat.atime)) {
    atime = vinylStat.atime;
  } else {
    atime = fsStat.atime;
  }
  if (!isValidDate(atime)) {
    atime = undefined;
  }
  var timesDiff = {
    mtime: vinylStat.mtime,
    atime: atime,
  };
  return timesDiff;
}
function isOwner(fsStat) {
  var hasGetuid = (typeof process.getuid === 'function');
  var hasGeteuid = (typeof process.geteuid === 'function');
  // If we don't have either, assume we don't have permissions.
  // This should only happen on Windows.
  // Windows basically noops fchmod and errors on futimes called on directories.
  if (!hasGeteuid && !hasGetuid) {
    return false;
  }
  var uid;
  if (hasGeteuid) {
    uid = process.geteuid();
  } else {
    uid = process.getuid();
  }
  if (fsStat.uid !== uid && uid !== 0) {
    return false;
  }
  return true;
}
function updateMetadata(fd, file, callback) {
  fs.fstat(fd, onStat);
  function onStat(err, stat) {
    if (err) {
      return callback(err, fd);
    }
    // Check if mode needs to be updated
    var modeDiff = getModeDiff(stat.mode, file.stat.mode);
    // Check if atime/mtime need to be updated
    var timesDiff = getTimesDiff(stat, file.stat);
    // Set file.stat to the reflect current state on disk
    assign(file.stat, stat);
    // Nothing to do
    if (!modeDiff && !timesDiff) {
      return callback(null, fd);
    }
    // Check access, `futimes` and `fchmod` only work if we own the file,
    // or if we are effectively root.
    if (!isOwner(stat)) {
      return callback(null, fd);
    }
    if (modeDiff) {
      return mode();
    }
    times();
    function mode() {
      var mode = stat.mode ^ modeDiff;
      fs.fchmod(fd, mode, onFchmod);
      function onFchmod(fchmodErr) {
        if (!fchmodErr) {
          file.stat.mode = mode;
        }
        if (timesDiff) {
          return times(fchmodErr);
        }
        callback(fchmodErr, fd);
      }
    }
    function times(fchmodErr) {
      fs.futimes(fd, timesDiff.atime, timesDiff.mtime, onFutimes);
      function onFutimes(futimesErr) {
        if (!futimesErr) {
          file.stat.atime = timesDiff.atime;
          file.stat.mtime = timesDiff.mtime;
        }
        callback(fchmodErr || futimesErr, fd);
      }
    }
  }
}
/*
  Custom writeFile implementation because we need access to the
  file descriptor after the write is complete.
  Most of the implementation taken from node core.
 */
function writeFile(path, data, options, callback) {
  if (typeof options === 'function') {
    callback = options;
    options = {};
  }
  if (!Buffer.isBuffer(data)) {
    callback(new TypeError('Data must be a Buffer'));
    return;
  }
  if (!options) {
    options = {};
  }
  // Default the same as node
  var mode = options.mode || DEFAULT_FILE_MODE;
  var flag = options.flag || 'w';
  var position = APPEND_MODE_REGEXP.test(flag) ? null : 0;
  fs.open(path, flag, mode, onOpen);
  function onOpen(err, fd) {
    if (err) {
      return onComplete(err);
    }
    fs.write(fd, data, 0, data.length, position, onComplete);
    function onComplete(err) {
      callback(err, fd);
    }
  }
}
module.exports = {
  closeFd: closeFd,
  getModeDiff: getModeDiff,
  getTimesDiff: getTimesDiff,
  isOwner: isOwner,
  updateMetadata: updateMetadata,
  writeFile: writeFile,
};