diff --git a/src/ICSharpCode.SharpZipLib/Tar/TarArchive.cs b/src/ICSharpCode.SharpZipLib/Tar/TarArchive.cs index 878649017..a20ca2455 100644 --- a/src/ICSharpCode.SharpZipLib/Tar/TarArchive.cs +++ b/src/ICSharpCode.SharpZipLib/Tar/TarArchive.cs @@ -857,12 +857,34 @@ private void WriteEntryCore(TarEntry sourceEntry, bool recurse) if (!String.IsNullOrEmpty(rootPath)) { - if (entry.Name.StartsWith(rootPath, StringComparison.OrdinalIgnoreCase)) + string newRootPath = rootPath; + + // remove CurrentDirectory from RootPath to be consistent with TarEntry behavior + var currentDirectory = Directory.GetCurrentDirectory() + .ToTarArchivePath(); + if (rootPath.StartsWith(currentDirectory, StringComparison.OrdinalIgnoreCase)) { - newName = entry.Name.Substring(rootPath.Length + 1); + if (rootPath.Length == currentDirectory.Length) + { + // if they are the same, rootPath would be empty + // and so the entry name is not modified + newRootPath = string.Empty; + } + else + { + // TarEntry would have removed the current directory from the entry name, and so do the same here + newRootPath = rootPath.Substring(currentDirectory.Length + 1); + } + } + + if (!string.IsNullOrEmpty(newRootPath) && + entry.Name.StartsWith(newRootPath, StringComparison.OrdinalIgnoreCase)) + { + newName = entry.Name.Substring(newRootPath.Length + 1); } } + if (pathPrefix != null) { newName = (newName == null) ? pathPrefix + "/" + entry.Name : pathPrefix + "/" + newName; diff --git a/test/ICSharpCode.SharpZipLib.Tests/Tar/TarTests.cs b/test/ICSharpCode.SharpZipLib.Tests/Tar/TarTests.cs index c6a35ff08..e6236d382 100644 --- a/test/ICSharpCode.SharpZipLib.Tests/Tar/TarTests.cs +++ b/test/ICSharpCode.SharpZipLib.Tests/Tar/TarTests.cs @@ -4,6 +4,7 @@ using NUnit.Framework; using System; using System.IO; +using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -916,5 +917,113 @@ public void RootPathIsRespected() } } } + + /// + /// This tests the behavior of the property on + /// which are created under the . + /// + /// + /// The value to set to the property. + /// A value of will keep the property unset. + /// + /// + /// If true, prefixes the with the . + /// + /// + /// If true, changes the to point to the + /// temporary working directory where the test files are created. + /// + /// + /// The list of path segments to join, which represents the expeced path of + /// the file in the archive. + /// + [Test] + [Category("Tar")] + // {workingDirectory}/temp {workingDirectory}/temp/file.txt -> "file.txt" + [TestCase("temp", true, true, new string[] { "file.txt" })] + // (unset) {workingDirectory}/temp/file.txt -> "temp/file.txt" + [TestCase("", false, true, new string[] { "temp", "file.txt" })] + // "temp" {workingDirectory}/temp/file.txt -> "file.txt" + [TestCase("temp", false, true, new string[] { "file.txt" })] + // nonWorkDir/temp/ nonWorkDir/temp/file.txt -> "file.txt" + [TestCase("temp", true, false, new string[] { "file.txt" })] + // (unset) /nonWorkDir/temp/file.txt -> "/nonWorkDir/temp/file.txt" + // cannot test this case, it relies on the path of the temp dir + // [TestCase("", true, false, new string[] { "temp", "file.txt" })] + public void TestRootPathBehavior(string rootPath, bool setRootPathPrefix, bool setCurrentDirectory, string[] expectedFilePath) + { + // when overrideWorkingDirectory is false, assumption is that working directory is that of the assembly + // which is not the same as the temporary directory + + using (var workDir = new TempDir()) + using (var tarFileName = new TempFile()) + using (var extractDirectory = new TempDir()) + { + if (setCurrentDirectory) + { + Environment.CurrentDirectory = workDir; + } + + if (setRootPathPrefix) + { + rootPath = Path.Combine(workDir, rootPath); + } + + string testFilePath = Path.Combine(workDir, "temp", "file.txt"); + Directory.CreateDirectory(Path.Combine(workDir, "temp")); + File.WriteAllText(testFilePath, Guid.NewGuid().ToString()); + + using (var tarFile = File.Open(tarFileName.FullName, FileMode.Create)) + { + using (var tarOutputStream = TarArchive.CreateOutputTarArchive(tarFile)) + { + if (rootPath != string.Empty) + { + tarOutputStream.RootPath = rootPath; + } + + string assignedRootPath = tarOutputStream.RootPath; + + var entry = TarEntry.CreateEntryFromFile(testFilePath); + + // TarEntry.Name may be relative or absolute depending on if it + // was created under the CurrentDirectory + if (setCurrentDirectory) + { + Assert.AreEqual("temp/file.txt", entry.Name); + } + else + { + Assert.IsTrue(entry.Name.EndsWith("temp/file.txt")); + } + + tarOutputStream.WriteEntry(entry, true); + + // RootPath property does not change + Assert.AreEqual(assignedRootPath, tarOutputStream.RootPath); + } + } + + using (var file = File.OpenRead(tarFileName.FullName)) + { + using (var archive = TarArchive.CreateInputTarArchive(file, Encoding.UTF8)) + { + archive.ExtractContents(extractDirectory.FullName); + } + } + + var expectationDirectory = new DirectoryInfo(extractDirectory.FullName); + var expectedFile = expectationDirectory.GetFiles("", SearchOption.AllDirectories) + .First(); // should only contain a single file + + var expected = Path.Combine(extractDirectory.FullName, Path.Combine(expectedFilePath)); + + // the extraced files must contain either "temp/file.txt" or "file.txt" based on test inputs + FileAssert.Exists(expected); + + // contents of the input file must equal the extracted file + FileAssert.AreEqual(testFilePath, expected); + } + } } }