makedrive
Version:
Webmaker Filesystem
159 lines (123 loc) • 4.48 kB
JavaScript
var rsyncUtils = require('./rsync-utils');
var async = require('../async-lite');
// Generate checksums for every source node in a given destination path
module.exports = function checksums(fs, path, srcList, options, callback) {
callback = rsyncUtils.findCallback(callback, options);
var paramError = rsyncUtils.validateParams(fs, path);
if(paramError) {
return callback(paramError);
}
options = rsyncUtils.configureOptions(options);
var checksumList = [];
function ChecksumNode(path, type) {
this.path = path;
this.type = type;
}
function checksumsForFile(checksumNode, sourceNode, callback) {
function generateChecksumsForFile() {
rsyncUtils.blockChecksums(fs, sourceNode.path, options.size, function(err, checksums) {
if(err) {
return callback(err);
}
checksumNode.checksums = checksums;
checksumNode.modified = sourceNode.modified;
checksumList.push(checksumNode);
callback();
});
}
// Checksums are always calculated even for identical files
// if and only if checksums are turned on and rsync is not
// implemented recursively
if(options.checksum && !options.recursive) {
return generateChecksumsForFile();
}
// Skip identical files if checksums are turned off or
// if rsync is performed recursively
fs.stat(sourceNode.path, function(err, stat) {
if(err && err.code !== 'ENOENT') {
return callback(err);
}
// Add the 'identical' flag if the modified time and size
// of the existing file match
if(stat && stat.mtime === sourceNode.modified && stat.size === sourceNode.size) {
checksumNode.checksums = [];
checksumNode.modified = sourceNode.modified;
checksumNode.identical = true;
checksumList.push(checksumNode);
return callback();
}
generateChecksumsForFile();
});
}
function checksumsForLink(checksumNode, sourceNode, callback) {
function generateChecksumsForLink() {
fs.readlink(sourceNode.path, function(err, linkContents) {
if(err) {
return callback(err);
}
rsyncUtils.blockChecksums(fs, linkContents, options.size, function(err, checksums) {
if(err) {
return callback(err);
}
checksumNode.checksums = checksums;
checksumList.push(checksumNode);
callback();
});
});
}
// Checksums are always calculated even for identical links
// if and only if checksums are turned on and rsync is not
// implemented recursively
if(options.checksum && !options.recursive) {
checksumList.push(checksumNode);
return callback();
}
// Skip identical links if checksums are turned off or
// if rsync is performed recursively
fs.stat(sourceNode.path, function(err, stat) {
if(err && err.code !== 'ENOENT') {
return callback(err);
}
// Add `identical` if the modified time and size of the existing file match
if(stat && stat.mtime === sourceNode.modified && stat.size === sourceNode.size) {
checksumNode.identical = true;
checksumList.push(checksumNode);
return callback();
}
// Link does not exist i.e. no checksums
if(err && err.code === 'ENOENT') {
checksumList.push(checksumNode);
return callback();
}
// Link exists and is not identical to the source link
generateChecksumsForLink();
});
}
function checksumsForDir(checksumNode, callback) {
checksumNode.checksums = [];
checksumList.push(checksumNode);
callback();
}
function getChecksumsForSourceNode(sourceNode, callback) {
var sourceNodeType = sourceNode.type;
var checksumNode = new ChecksumNode(sourceNode.path, sourceNodeType);
// Directory
if(sourceNodeType === 'DIRECTORY') {
return checksumsForDir(checksumNode, callback);
}
// Link
if(sourceNodeType === 'SYMLINK' && options.links){
checksumNode.link = true;
return checksumsForLink(checksumNode, sourceNode, callback);
}
// File or Links treated as files
checksumsForFile(checksumNode, sourceNode, callback);
}
async.eachSeries(srcList, getChecksumsForSourceNode, function(err) {
if(err) {
callback(err);
} else {
callback(null, checksumList);
}
});
};