Skip to content

Commit

Permalink
Fix: Improve stats logic to avoid problems when files not owned
Browse files Browse the repository at this point in the history
  • Loading branch information
piranna authored and phated committed Nov 30, 2017
1 parent fce3b66 commit 559c2d5
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 80 deletions.
102 changes: 92 additions & 10 deletions lib/dest/writeContents/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,65 @@
'use strict';

var fs = require('fs');

var writeDir = require('./writeDir');
var writeStream = require('./writeStream');
var writeBuffer = require('./writeBuffer');
var writeSymbolicLink = require('./writeSymbolicLink');


function getMode(oldStat, newStat) {
if (typeof newStat.mode !== 'number') {
return;
}

var currentMode = (oldStat.mode & parseInt('0777', 8));
var expectedMode = (newStat.mode & parseInt('0777', 8));
if (currentMode !== expectedMode) {
return expectedMode;
}
}

function getUtimes(oldStat, newStat) {
// `futimes` only works if we own the file
if (oldStat.uid !== process.getuid()) {
return;
}

// Given `mtime` is not valid, do nothing
var mtime = newStat.mtime;
if (!validDate(mtime)) {
return;
}

// Given `atime` is not valid, assign a new one with current time
var atime = newStat.atime;
if (!validDate(atime)) {
atime = new Date();
}

return { atime: atime, mtime: mtime };
}


// http://stackoverflow.com/a/10589791/586382
function validDate(date) {
return date instanceof Date && !isNaN(date.valueOf());
}

function futimes(fd, oldStat, newStat, cb) {
setTimeout(function() {
var stat = getUtimes(oldStat, newStat);
if (!stat) {
return cb();
}

// Set file `atime` and `mtime` fields
fs.futimes(fd, stat.atime, stat.mtime, cb);
}, 0);
}


function writeContents(writePath, file, cb) {
// If directory then mkdirp it
if (file.isDirectory()) {
Expand Down Expand Up @@ -36,26 +90,54 @@ function writeContents(writePath, file, cb) {
cb(err, file);
}

function written(err) {
function stat(fd) {
function complete2(err1) {
fs.close(fd, function(err2) {
complete(err1 || err2);
});
}

fs.fstat(fd, function(err, st) {
if (err) {
return complete2(err);
}

var stat = file.stat;
var mode = getMode(st, stat);
if (mode == null) {
return futimes(fd, st, stat, complete2);
}

fs.fchmod(fd, mode, function(error) {
if (error) {
return complete2(error);
}

futimes(fd, st, stat, complete2);
});
});
}


function written(err, fd) {
if (isErrorFatal(err)) {
return complete(err);
}

if (!file.stat || typeof file.stat.mode !== 'number' || file.symlink) {
if (!file.stat) {
return complete();
}

fs.stat(writePath, function(err, st) {
if (typeof fd === 'number') {
return stat(fd);
}

fs.open(writePath, 'r', function(err, fd) {
if (err) {
return complete(err);
}
var currentMode = (st.mode & parseInt('0777', 8));
var expectedMode = (file.stat.mode & parseInt('0777', 8));
if (currentMode === expectedMode) {
return complete();
}
fs.chmod(writePath, expectedMode, complete);

stat(fd);
});
}

Expand All @@ -64,8 +146,8 @@ function writeContents(writePath, file, cb) {
return false;
}

// Handle scenario for file overwrite failures.
if (err.code === 'EEXIST' && file.flag === 'wx') {
// Handle scenario for file overwrite failures.
return false; // "These aren't the droids you're looking for"
}

Expand Down
16 changes: 2 additions & 14 deletions lib/dest/writeContents/writeBuffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

var fs = require('graceful-fs');

var futimes = require('../../futimes');

function writeBuffer(writePath, file, cb) {
var stat = file.stat;

Expand All @@ -12,19 +10,9 @@ function writeBuffer(writePath, file, cb) {
return cb(err);
}

fs.write(fd, file.contents, 0, file.contents.length, 0, function(error) {
if (error) {
return complete(error);
}
futimes(fd, stat, complete);
fs.write(fd, file.contents, 0, file.contents.length, 0, function(err) {
cb(err, fd);
});

// Cleanup
function complete(err1) {
fs.close(fd, function(err2) {
cb(err1 || err2);
});
}
});
}

Expand Down
26 changes: 14 additions & 12 deletions lib/dest/writeContents/writeStream.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,28 @@
var fs = require('graceful-fs');

var streamFile = require('../../src/getContents/streamFile');
var futimes = require('../../futimes');

function writeStream(writePath, file, cb) {
var stat = file.stat;
var mode = stat.mode;

var outStream;
var outFD;

fs.open(writePath, 'w', file.stat.mode, function(err, fd) {
fs.open(writePath, 'w', mode, function(err, fd) {
if (err) {
cb(err);
}

var opt = {
mode: mode,
flag: file.flag,
autoClose: false,
fd: fd,
};

outFD = fd;
outStream = fs.createWriteStream(null, { fd: fd });
outStream = fs.createWriteStream(null, opt);

file.contents.once('error', complete);
file.contents.once('end', readStreamEnd);
Expand All @@ -35,14 +43,8 @@ function writeStream(writePath, file, cb) {
return complete(error);
}

futimes(outFD, stat, function(error) {
if (error) {
return complete(error);
}

// All finished with WriteStream, close and clean up
outStream.end();
});
// All finished with WriteStream, close and clean up
outStream.end();
});
}

Expand All @@ -54,7 +56,7 @@ function writeStream(writePath, file, cb) {
outStream.removeListener('error', complete);
outStream.removeListener('finish', complete);
}
cb(err);
cb(err, outFD);
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/dest/writeContents/writeSymbolicLink.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ function writeSymbolicLink(writePath, file, cb) {
return cb(err);
}

cb(null, file);
cb();
});
}

Expand Down
27 changes: 0 additions & 27 deletions lib/futimes.js

This file was deleted.

Loading

0 comments on commit 559c2d5

Please sign in to comment.