first commit
This commit is contained in:
206
build/node_modules/vinyl-fs/lib/fileOperations.js
generated
vendored
Normal file
206
build/node_modules/vinyl-fs/lib/fileOperations.js
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
'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,
|
||||
};
|
||||
Reference in New Issue
Block a user