Skip to content

Commit bdec777

Browse files
sensslenpikselSimon Ensslen
authored
fix(tar): enable unix paths in tar RootPath (#582)
Co-authored-by: nils måsén <[email protected]> Co-authored-by: Simon Ensslen <[email protected]>
1 parent 79614c5 commit bdec777

File tree

4 files changed

+63
-12
lines changed

4 files changed

+63
-12
lines changed

src/ICSharpCode.SharpZipLib/Tar/TarArchive.cs

+4-3
Original file line numberDiff line numberDiff line change
@@ -356,8 +356,7 @@ public string RootPath
356356
{
357357
throw new ObjectDisposedException("TarArchive");
358358
}
359-
// Convert to forward slashes for matching. Trim trailing / for correct final path
360-
rootPath = value.Replace('\\', '/').TrimEnd('/');
359+
rootPath = value.ToTarArchivePath().TrimEnd('/');
361360
}
362361
}
363362

@@ -660,7 +659,9 @@ private void ExtractEntry(string destDir, TarEntry entry, bool allowParentTraver
660659
string destFile = Path.Combine(destDir, name);
661660
var destFileDir = Path.GetDirectoryName(Path.GetFullPath(destFile)) ?? "";
662661

663-
if (!allowParentTraversal && !destFileDir.StartsWith(destDir, StringComparison.InvariantCultureIgnoreCase))
662+
var isRootDir = entry.IsDirectory && entry.Name == "";
663+
664+
if (!allowParentTraversal && !isRootDir && !destFileDir.StartsWith(destDir, StringComparison.InvariantCultureIgnoreCase))
664665
{
665666
throw new InvalidNameException("Parent traversal in paths is not allowed");
666667
}

src/ICSharpCode.SharpZipLib/Tar/TarEntry.cs

+1-6
Original file line numberDiff line numberDiff line change
@@ -372,15 +372,10 @@ public void GetFileTarHeader(TarHeader header, string file)
372372
}
373373
*/
374374

375-
name = name.Replace(Path.DirectorySeparatorChar, '/');
376-
377375
// No absolute pathnames
378376
// Windows (and Posix?) paths can start with UNC style "\\NetworkDrive\",
379377
// so we loop on starting /'s.
380-
while (name.StartsWith("/", StringComparison.Ordinal))
381-
{
382-
name = name.Substring(1);
383-
}
378+
name = name.ToTarArchivePath();
384379

385380
header.LinkName = String.Empty;
386381
header.Name = name;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System.IO;
2+
using ICSharpCode.SharpZipLib.Core;
3+
4+
namespace ICSharpCode.SharpZipLib.Tar
5+
{
6+
internal static class TarStringExtension
7+
{
8+
public static string ToTarArchivePath(this string s)
9+
{
10+
return PathUtils.DropPathRoot(s).Replace(Path.DirectorySeparatorChar, '/');
11+
}
12+
}
13+
}

test/ICSharpCode.SharpZipLib.Tests/Tar/TarTests.cs

+45-3
Original file line numberDiff line numberDiff line change
@@ -833,7 +833,7 @@ public void ParseHeaderWithEncoding(int length, string encodingName)
833833
reparseHeader.ParseBuffer(headerbytes, enc);
834834
Assert.AreEqual(name, reparseHeader.Name);
835835
// top 100 bytes are name field in tar header
836-
for (int i = 0;i < encodedName.Length;i++)
836+
for (int i = 0; i < encodedName.Length; i++)
837837
{
838838
Assert.AreEqual(encodedName[i], headerbytes[i]);
839839
}
@@ -852,9 +852,9 @@ public async Task StreamWithJapaneseNameAsync(int length, string encodingName)
852852
var entryName = new string((char)0x3042, length);
853853
var data = new byte[32];
854854
var encoding = Encoding.GetEncoding(encodingName);
855-
using(var memoryStream = new MemoryStream())
855+
using (var memoryStream = new MemoryStream())
856856
{
857-
using(var tarOutput = new TarOutputStream(memoryStream, encoding))
857+
using (var tarOutput = new TarOutputStream(memoryStream, encoding))
858858
{
859859
var entry = TarEntry.CreateTarEntry(entryName);
860860
entry.Size = 32;
@@ -874,5 +874,47 @@ public async Task StreamWithJapaneseNameAsync(int length, string encodingName)
874874
File.WriteAllBytes(Path.Combine(Path.GetTempPath(), $"jpnametest_{length}_{encodingName}.tar"), memoryStream.ToArray());
875875
}
876876
}
877+
/// <summary>
878+
/// This test could be considered integration test. it creates a tar archive with the root directory specified
879+
/// Then extracts it and compares the two folders. This used to fail on unix due to issues with root folder handling
880+
/// in the tar archive.
881+
/// </summary>
882+
[Test]
883+
[Category("Tar")]
884+
public void RootPathIsRespected()
885+
{
886+
using (var extractDirectory = new TempDir())
887+
using (var tarFileName = new TempFile())
888+
using (var tempDirectory = new TempDir())
889+
{
890+
tempDirectory.CreateDummyFile();
891+
892+
using (var tarFile = File.Open(tarFileName.FullName, FileMode.Create))
893+
{
894+
using (var tarOutputStream = TarArchive.CreateOutputTarArchive(tarFile))
895+
{
896+
tarOutputStream.RootPath = tempDirectory.FullName;
897+
var entry = TarEntry.CreateEntryFromFile(tempDirectory.FullName);
898+
tarOutputStream.WriteEntry(entry, true);
899+
}
900+
}
901+
902+
using (var file = File.OpenRead(tarFileName.FullName))
903+
{
904+
using (var archive = TarArchive.CreateInputTarArchive(file, Encoding.UTF8))
905+
{
906+
archive.ExtractContents(extractDirectory.FullName);
907+
}
908+
}
909+
910+
var expectationDirectory = new DirectoryInfo(tempDirectory.FullName);
911+
foreach (var checkFile in expectationDirectory.GetFiles("", SearchOption.AllDirectories))
912+
{
913+
var relativePath = checkFile.FullName.Substring(expectationDirectory.FullName.Length + 1);
914+
FileAssert.Exists(Path.Combine(extractDirectory.FullName, relativePath));
915+
FileAssert.AreEqual(checkFile.FullName, Path.Combine(extractDirectory.FullName, relativePath));
916+
}
917+
}
918+
}
877919
}
878920
}

0 commit comments

Comments
 (0)