diff --git a/bin/kuduSync.js b/bin/kuduSync.js index 2bab775..098a85d 100644 --- a/bin/kuduSync.js +++ b/bin/kuduSync.js @@ -286,6 +286,14 @@ var DirectoryInfo = (function (_super) { DirectoryInfo.prototype.subDirectoriesList = function () { return this._subDirectoriesList; }; + DirectoryInfo.prototype.isSubdirectoryOf = function (potentialParentDirectory) { + if(potentialParentDirectory == null || this.path() == null || potentialParentDirectory.path() == null) { + return false; + } + var thisPath = pathUtil.resolve(this.path()); + var potentialParentDirectoryPath = pathUtil.resolve(potentialParentDirectory.path()); + return thisPath.toUpperCase().indexOf(potentialParentDirectoryPath.toUpperCase()) == 0; + }; return DirectoryInfo; })(FileInfoBase); var Manifest = (function () { @@ -352,6 +360,9 @@ function kuduSync(fromPath, toPath, nextManifestPath, previousManifestPath, igno if(!from.exists()) { return Q.reject(new Error("From directory doesn't exist")); } + if(from.isSubdirectoryOf(to) || to.isSubdirectoryOf(from)) { + return Q.reject(new Error("Source and destination directories cannot be sub-directories of each other")); + } var nextManifest = new Manifest(); var ignoreList = parseIgnoreList(ignore); log("Kudu sync from: '" + from.path() + "' to: '" + to.path() + "'"); diff --git a/lib/DirectoryInfo.ts b/lib/DirectoryInfo.ts index 7254551..e1724e5 100644 --- a/lib/DirectoryInfo.ts +++ b/lib/DirectoryInfo.ts @@ -149,4 +149,15 @@ class DirectoryInfo extends FileInfoBase { subDirectoriesList() { return this._subDirectoriesList; } + + isSubdirectoryOf(potentialParentDirectory: DirectoryInfo): bool { + if (potentialParentDirectory == null || this.path() == null || potentialParentDirectory.path() == null) { + return false; + } + + var thisPath = pathUtil.resolve(this.path()); + var potentialParentDirectoryPath = pathUtil.resolve(potentialParentDirectory.path()); + + return thisPath.toUpperCase().indexOf(potentialParentDirectoryPath.toUpperCase()) == 0; + } } diff --git a/lib/FileUtils.ts b/lib/FileUtils.ts index 4fc59be..01130ed 100644 --- a/lib/FileUtils.ts +++ b/lib/FileUtils.ts @@ -13,6 +13,10 @@ function kuduSync(fromPath: string, toPath: string, nextManifestPath: string, pr return Q.reject(new Error("From directory doesn't exist")); } + if (from.isSubdirectoryOf(to) || to.isSubdirectoryOf(from)) { + return Q.reject(new Error("Source and destination directories cannot be sub-directories of each other")); + } + var nextManifest = new Manifest(); var ignoreList = parseIgnoreList(ignore); diff --git a/test/functionalTests.js b/test/functionalTests.js index f9ac793..fb93b8f 100644 --- a/test/functionalTests.js +++ b/test/functionalTests.js @@ -137,7 +137,7 @@ suite('Kudu Sync Functional Tests', function () { runKuduSyncTestScenario(["file1", "file2", "file3"], [], null, done, /*whatIf*/true); }); - test('Several files and direcotires should not be sync\'d with whatIf flag set to true', function (done) { + test('Several files and directories should not be sync\'d with whatIf flag set to true', function (done) { runKuduSyncTestScenario(["file1", "file2", "dir1/dir2/file3"], [], null, done, /*whatIf*/true); }); @@ -250,25 +250,28 @@ suite('Kudu Sync Functional Tests', function () { test('From directory doesn\'t exist should fail with an error', function (done) { var from = pathUtil.join(baseTestTempDir, testDir, 'doesntexist'); var to = pathUtil.join(baseTestTempDir, testDir, 'to'); - var prevManifestPath = pathUtil.join(baseTestTempDir, testDir, 'manifest'); - var nextManifestPath = pathUtil.join(baseTestTempDir, testDir, 'manifest'); - - var command = testTarget.cmd + " -f " + from + " -t " + to + " -n " + nextManifestPath + " -p " + prevManifestPath; - - exec(command, - function (error, stdout, stderr) { - if (stdout !== '') { - console.log('---------stdout: ---------\n' + stdout); - } - if (stderr !== '') { - console.log('---------stderr: ---------\n' + stderr); - } - if (error !== null) { - console.log('---------exec error: ---------\n[' + error + ']'); - } - should.exist(error); - done(); - }); + + runKuduSyncTestExpectError(from, to, done); + }); + + test('KuduSync should fail when target is subdirectory of source', function (done) { + var from = pathUtil.join(baseTestTempDir, testDir, fromDir); + var to = pathUtil.join(from, 'subdirectory'); + + ensurePathExists(from); + ensurePathExists(to); + + runKuduSyncTestExpectError(from, to, done); + }); + + test('KuduSync should fail when source is subdirectory of target', function (done) { + var to = pathUtil.join(baseTestTempDir, testDir, fromDir); + var from = pathUtil.join(to, 'subdirectory'); + + ensurePathExists(to); + ensurePathExists(from); + + runKuduSyncTestExpectError(from, to, done); }); setup(function () { @@ -310,6 +313,31 @@ function runKuduSyncTestScenario(updatedFiles, expectedFiles, ignore, callback, }); } +function runKuduSyncTestExpectError(from, to, callback) { + var prevManifestPath = pathUtil.join(baseTestTempDir, testDir, 'manifest'); + var nextManifestPath = pathUtil.join(baseTestTempDir, testDir, 'manifest'); + + var command = testTarget.cmd + " -f " + from + " -t " + to + " -n " + nextManifestPath + " -p " + prevManifestPath; + console.log("command: " + command); + + var child = exec(command, + function (error, stdout, stderr) { + if (stdout !== '') { + console.log('---------stdout: ---------\n' + stdout); + } + if (stderr !== '') { + console.log('---------stderr: ---------\n' + stderr); + } + if (error !== null) { + console.log('---------exec error: ---------\n[' + error + ']'); + } + should.exist(error); + callback(); + }); + + child.stderr.pipe(process.stderr); +} + function removeManifestFile() { var manifestPath = pathUtil.join(baseTestTempDir, testDir, "manifest1"); tryRemoveFile(manifestPath);