Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #337: Enable use of TarArchive.RootPath for files under working directory #769

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 24 additions & 2 deletions src/ICSharpCode.SharpZipLib/Tar/TarArchive.cs
Expand Up @@ -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;
Expand Down
109 changes: 109 additions & 0 deletions test/ICSharpCode.SharpZipLib.Tests/Tar/TarTests.cs
Expand Up @@ -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;
Expand Down Expand Up @@ -916,5 +917,113 @@ public void RootPathIsRespected()
}
}
}

/// <summary>
/// This tests the behavior of the <see cref="TarArchive.RootPath"/> property on
/// <see cref="TarEntry"/> which are created under the <see cref="Environment.CurrentDirectory"/>.
/// </summary>
/// <param name="rootPath">
/// The value to set to the <see cref="TarArchive.RootPath"/> property.
/// A value of <see cref="string.Empty"/> will keep the property unset.
/// </param>
/// <param name="setRootPathPrefix">
/// If <c>true</c>, prefixes the <paramref name="rootPath"/> with the <see cref="Environment.CurrentDirectory"/>.
/// </param>
/// <param name="setCurrentDirectory">
/// If <c>true</c>, changes the <see cref="Environment.CurrentDirectory"/> to point to the
/// temporary working directory where the test files are created.
/// </param>
/// <param name="expectedFilePath">
/// The list of path segments to join, which represents the expeced path of
/// the file in the archive.
/// </param>
[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);
}
}
}
}