From 4726bafd7dd597aeb70bc44f5b7183f53a9695da Mon Sep 17 00:00:00 2001 From: Chris Johnston Date: Thu, 25 Aug 2022 17:27:51 -0700 Subject: [PATCH] fix #337: use absolute paths consistently, even under working dir WIP. This change updates the behavior of adding files under the current working dir when the RootPath is set If the rootpath is unset, the behavior is unchanged. If the rootpath is a relative directory under the current directory, the current directory + root path will be removed from the start of the entry filepath If the rootpath is an absolute directory under the current directory, the root path will be removed from the start of the entry filepath --- src/ICSharpCode.SharpZipLib/Tar/TarArchive.cs | 20 ++ src/ICSharpCode.SharpZipLib/Tar/TarEntry.cs | 14 +- .../Tar/TarTests.cs | 175 ++++++++++++++++++ 3 files changed, 205 insertions(+), 4 deletions(-) diff --git a/src/ICSharpCode.SharpZipLib/Tar/TarArchive.cs b/src/ICSharpCode.SharpZipLib/Tar/TarArchive.cs index 878649017..852b241ea 100644 --- a/src/ICSharpCode.SharpZipLib/Tar/TarArchive.cs +++ b/src/ICSharpCode.SharpZipLib/Tar/TarArchive.cs @@ -855,14 +855,34 @@ private void WriteEntryCore(TarEntry sourceEntry, bool recurse) string newName = null; + // need to have a test if the root path is set to a child directory of the working directory + var currentDirectory = Directory.GetCurrentDirectory() + .ToTarArchivePath(); + if (!String.IsNullOrEmpty(rootPath)) { + // hack: fix this + if (entry.Name.StartsWith(rootPath, StringComparison.OrdinalIgnoreCase)) { newName = entry.Name.Substring(rootPath.Length + 1); } + // root path is set, is root path under the current directory? + else if (entry.Name.StartsWith(currentDirectory + "/" + RootPath, StringComparison.OrdinalIgnoreCase)) + { + newName = entry.Name.Substring(rootPath.Length + 2 + currentDirectory.Length); + } + } + else + { + + if (entry.Name.StartsWith(currentDirectory, StringComparison.OrdinalIgnoreCase)) + { + newName = entry.Name.Substring(currentDirectory.Length); + } } + if (pathPrefix != null) { newName = (newName == null) ? pathPrefix + "/" + entry.Name : pathPrefix + "/" + newName; diff --git a/src/ICSharpCode.SharpZipLib/Tar/TarEntry.cs b/src/ICSharpCode.SharpZipLib/Tar/TarEntry.cs index 82c813367..e59165afe 100644 --- a/src/ICSharpCode.SharpZipLib/Tar/TarEntry.cs +++ b/src/ICSharpCode.SharpZipLib/Tar/TarEntry.cs @@ -348,11 +348,17 @@ public void GetFileTarHeader(TarHeader header, string file) // bugfix from torhovl from #D forum: string name = file; + // not sure if I understand this comment, unsure if this needs to move // 23-Jan-2004 GnuTar allows device names in path where the name is not local to the current directory - if (name.IndexOf(Directory.GetCurrentDirectory(), StringComparison.Ordinal) == 0) - { - name = name.Substring(Directory.GetCurrentDirectory().Length); - } + + // the functional difference here is that TarEntry has changed + // is this something that we are concerned about? + + // TODO: this has moved + //if (name.IndexOf(Directory.GetCurrentDirectory(), StringComparison.Ordinal) == 0) + //{ + // name = name.Substring(Directory.GetCurrentDirectory().Length); + //} /* if (Path.DirectorySeparatorChar == '\\') diff --git a/test/ICSharpCode.SharpZipLib.Tests/Tar/TarTests.cs b/test/ICSharpCode.SharpZipLib.Tests/Tar/TarTests.cs index c6a35ff08..261aef1d7 100644 --- a/test/ICSharpCode.SharpZipLib.Tests/Tar/TarTests.cs +++ b/test/ICSharpCode.SharpZipLib.Tests/Tar/TarTests.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using NUnit.Framework.Internal; +using System.Linq; namespace ICSharpCode.SharpZipLib.Tests.Tar { @@ -916,5 +917,179 @@ public void RootPathIsRespected() } } } + + /// + /// This tests ensure that the property is respected, even if the + /// path is under the current working directory. + /// + [Test] + [Category("Tar")] + public void RootPathUnderWorkDirRespected() + { + // If a user specifies that the RootDir is a path under the working directory + // the RootDir properly must correctly trim away the root path + // this must not alter existing behavior + using (var workDir = new TempDir()) + using (var tarFileName = new TempFile()) + using (var extractDirectory = new TempDir()) + { + // the files created must be under the current working dir + Environment.CurrentDirectory = workDir.FullName; + + // create a temp dir and file under this path + var expectDir = Path.Combine(workDir.FullName, "temp"); // TODO: improve quality of this + Directory.CreateDirectory(expectDir); + var fileName = Path.Combine(expectDir, "testFile.txt"); + File.WriteAllText(fileName, "test123"); + + // extract files under the given path + using (var tarFile = File.Open(tarFileName.FullName, FileMode.Create)) + { + using (var tarOutputStream = TarArchive.CreateOutputTarArchive(tarFile)) + { + tarOutputStream.RootPath = Path.Combine(Environment.CurrentDirectory, "temp"); + var entry = TarEntry.CreateEntryFromFile(fileName); + tarOutputStream.WriteEntry(entry, true); + } + } + + using (var file = File.OpenRead(tarFileName.FullName)) + { + using (var archive = TarArchive.CreateInputTarArchive(file, Encoding.UTF8)) + { + archive.ExtractContents(extractDirectory.FullName); + } + } + + // the resulting files must be the same as the expectation dir, should no longer have the "temp" prefix + var expectationDirectory = new DirectoryInfo(expectDir); + var expectedFile = expectationDirectory.GetFiles("", SearchOption.AllDirectories) + .First(); + + // the archive should contain the entry "testFile.txt", not "temp/testFile.txt", because + // the root dir is configured to "{CurrentDirectory}/tmp/" + FileAssert.DoesNotExist(Path.Combine(extractDirectory.FullName, "temp", "testFile.txt")); + FileAssert.Exists(Path.Combine(extractDirectory.FullName, "testFile.txt")); + + FileAssert.AreEqual(fileName, Path.Combine(extractDirectory.FullName, "testFile.txt")); + } + } + + /// + /// This tests ensure that the property is respected, even if the + /// path is under the current working directory. + /// + [Test] + [Category("Tar")] + public void RootPathUnderWorkDirRespectedExistingBehavior() + { + // If a user specifies that the RootDir is a path under the working directory + // the RootDir properly must correctly trim away the root path + // this must not alter existing behavior + using (var workDir = new TempDir()) + using (var tarFileName = new TempFile()) + using (var extractDirectory = new TempDir()) + { + // the files created must be under the current working dir + Environment.CurrentDirectory = workDir.FullName; + + // create a temp dir and file under this path + var expectDir = Path.Combine(workDir.FullName, "temp"); // TODO: improve quality of this + Directory.CreateDirectory(expectDir); + var fileName = Path.Combine(expectDir, "testFile.txt"); + File.WriteAllText(fileName, "test123"); + + // extract files under the given path + using (var tarFile = File.Open(tarFileName.FullName, FileMode.Create)) + { + using (var tarOutputStream = TarArchive.CreateOutputTarArchive(tarFile)) + { + // when root path is NOT included, maintain the existing behavior + // tarOutputStream.RootPath = Path.Combine(Environment.CurrentDirectory, "temp"); + var entry = TarEntry.CreateEntryFromFile(fileName); + tarOutputStream.WriteEntry(entry, true); + } + } + + using (var file = File.OpenRead(tarFileName.FullName)) + { + using (var archive = TarArchive.CreateInputTarArchive(file, Encoding.UTF8)) + { + archive.ExtractContents(extractDirectory.FullName); + } + } + + // the resulting files must be the same as the expectation dir, should no longer have the "temp" prefix + var expectationDirectory = new DirectoryInfo(expectDir); + var expectedFile = expectationDirectory.GetFiles("", SearchOption.AllDirectories) + .First(); + + // the archive should contain the entry "testFile.txt", not "temp/testFile.txt", because + // the root dir is configured to "{CurrentDirectory}/tmp/" + FileAssert.Exists(Path.Combine(extractDirectory.FullName, "temp", "testFile.txt")); + FileAssert.DoesNotExist(Path.Combine(extractDirectory.FullName, "testFile.txt")); + + FileAssert.AreEqual(fileName, Path.Combine(extractDirectory.FullName, "temp", "testFile.txt")); + } + } + + /// + /// This tests ensure that the property is respected, even if the + /// path is under the current working directory. + /// + [Test] + [Category("Tar")] + public void RootPathUnderWorkDirRespectedExistingBehaviorRootPathIsRelative() + { + // If a user specifies that the RootDir is a path under the working directory + // the RootDir properly must correctly trim away the root path + // this must not alter existing behavior + using (var workDir = new TempDir()) + using (var tarFileName = new TempFile()) + using (var extractDirectory = new TempDir()) + { + // the files created must be under the current working dir + Environment.CurrentDirectory = workDir.FullName; + + // create a temp dir and file under this path + var expectDir = Path.Combine(workDir.FullName, "temp"); // TODO: improve quality of this + Directory.CreateDirectory(expectDir); + var fileName = Path.Combine(expectDir, "testFile.txt"); + File.WriteAllText(fileName, "test123"); + + // extract files under the given path + using (var tarFile = File.Open(tarFileName.FullName, FileMode.Create)) + { + using (var tarOutputStream = TarArchive.CreateOutputTarArchive(tarFile)) + { + // when root path is NOT included, maintain the existing behavior + // tarOutputStream.RootPath = Path.Combine(Environment.CurrentDirectory, "temp"); + tarOutputStream.RootPath = "temp"; + var entry = TarEntry.CreateEntryFromFile(fileName); + tarOutputStream.WriteEntry(entry, true); + } + } + + using (var file = File.OpenRead(tarFileName.FullName)) + { + using (var archive = TarArchive.CreateInputTarArchive(file, Encoding.UTF8)) + { + archive.ExtractContents(extractDirectory.FullName); + } + } + + // the resulting files must be the same as the expectation dir, should no longer have the "temp" prefix + var expectationDirectory = new DirectoryInfo(expectDir); + var expectedFile = expectationDirectory.GetFiles("", SearchOption.AllDirectories) + .First(); + + // the archive should contain the entry "testFile.txt", not "temp/testFile.txt", because + // the root dir is configured to "{CurrentDirectory}/tmp/" + FileAssert.DoesNotExist(Path.Combine(extractDirectory.FullName, "temp", "testFile.txt")); + FileAssert.Exists(Path.Combine(extractDirectory.FullName, "testFile.txt")); + + FileAssert.AreEqual(fileName, Path.Combine(extractDirectory.FullName, "temp", "testFile.txt")); + } + } } }