Skip to content

Commit 6f245b3

Browse files
Numpsypiksel
authored andcommitted
Merge PR #326: Dispose TarArchive output streams in case of an exception
* Refactor TarArchive.ExtractEntry() to use using blocks for stream disposal * Unit test to check that TarArchive.ExtractContents() doesn't leak file handles when an exception occurs
1 parent f03a2ef commit 6f245b3

File tree

2 files changed

+79
-31
lines changed

2 files changed

+79
-31
lines changed

src/ICSharpCode.SharpZipLib/Tar/TarArchive.cs

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -623,20 +623,32 @@ private void ExtractEntry(string destDir, TarEntry entry)
623623

624624
if (process)
625625
{
626-
bool asciiTrans = false;
627-
628-
Stream outputStream = File.Create(destFile);
629-
if (this.asciiTranslate)
626+
using (var outputStream = File.Create(destFile))
630627
{
631-
asciiTrans = !IsBinary(destFile);
628+
if (this.asciiTranslate)
629+
{
630+
// May need to translate the file.
631+
ExtractAndTranslateEntry(destFile, outputStream);
632+
}
633+
else
634+
{
635+
// If translation is disabled, just copy the entry across directly.
636+
tarIn.CopyEntryContents(outputStream);
637+
}
632638
}
639+
}
640+
}
641+
}
633642

634-
StreamWriter outw = null;
635-
if (asciiTrans)
636-
{
637-
outw = new StreamWriter(outputStream);
638-
}
643+
// Extract a TAR entry, and perform an ASCII translation if required.
644+
private void ExtractAndTranslateEntry(string destFile, Stream outputStream)
645+
{
646+
bool asciiTrans = !IsBinary(destFile);
639647

648+
if (asciiTrans)
649+
{
650+
using (var outw = new StreamWriter(outputStream, new UTF8Encoding(false), 1024, true))
651+
{
640652
byte[] rdbuf = new byte[32 * 1024];
641653

642654
while (true)
@@ -648,34 +660,23 @@ private void ExtractEntry(string destDir, TarEntry entry)
648660
break;
649661
}
650662

651-
if (asciiTrans)
663+
for (int off = 0, b = 0; b < numRead; ++b)
652664
{
653-
for (int off = 0, b = 0; b < numRead; ++b)
665+
if (rdbuf[b] == 10)
654666
{
655-
if (rdbuf[b] == 10)
656-
{
657-
string s = Encoding.ASCII.GetString(rdbuf, off, (b - off));
658-
outw.WriteLine(s);
659-
off = b + 1;
660-
}
667+
string s = Encoding.ASCII.GetString(rdbuf, off, (b - off));
668+
outw.WriteLine(s);
669+
off = b + 1;
661670
}
662671
}
663-
else
664-
{
665-
outputStream.Write(rdbuf, 0, numRead);
666-
}
667-
}
668-
669-
if (asciiTrans)
670-
{
671-
outw.Dispose();
672-
}
673-
else
674-
{
675-
outputStream.Dispose();
676672
}
677673
}
678674
}
675+
else
676+
{
677+
// No translation required.
678+
tarIn.CopyEntryContents(outputStream);
679+
}
679680
}
680681

681682
/// <summary>

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

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using ICSharpCode.SharpZipLib.Tar;
2+
using ICSharpCode.SharpZipLib.GZip;
23
using ICSharpCode.SharpZipLib.Tests.TestSupport;
34
using NUnit.Framework;
45
using System;
@@ -787,5 +788,51 @@ public void SingleLargeEntry()
787788
}
788789
);
789790
}
791+
792+
// Test for corruption issue described @ https://github.com/icsharpcode/SharpZipLib/issues/321
793+
[Test]
794+
[Category("Tar")]
795+
public void ExtractingCorruptTarShouldntLeakFiles()
796+
{
797+
using (var memoryStream = new MemoryStream())
798+
{
799+
//Create a tar.gz in the output stream
800+
using (var gzipStream = new GZipOutputStream(memoryStream))
801+
{
802+
gzipStream.IsStreamOwner = false;
803+
804+
using (var tarOut = TarArchive.CreateOutputTarArchive(gzipStream))
805+
using (var dummyFile = Utils.GetDummyFile(32000))
806+
{
807+
tarOut.IsStreamOwner = false;
808+
tarOut.WriteEntry(TarEntry.CreateEntryFromFile(dummyFile.Filename), false);
809+
}
810+
}
811+
812+
// corrupt archive - make sure the file still has more than one block
813+
memoryStream.SetLength(16000);
814+
memoryStream.Seek(0, SeekOrigin.Begin);
815+
816+
// try to extract
817+
using (var gzipStream = new GZipInputStream(memoryStream))
818+
{
819+
string tempDirName;
820+
gzipStream.IsStreamOwner = false;
821+
822+
using (var tempDir = new Utils.TempDir())
823+
{
824+
tempDirName = tempDir.Fullpath;
825+
826+
using (var tarIn = TarArchive.CreateInputTarArchive(gzipStream))
827+
{
828+
tarIn.IsStreamOwner = false;
829+
Assert.Throws<SharpZipBaseException>(() => tarIn.ExtractContents(tempDir.Fullpath));
830+
}
831+
}
832+
833+
Assert.That(Directory.Exists(tempDirName), Is.False, "Temporary folder should have been removed");
834+
}
835+
}
836+
}
790837
}
791838
}

0 commit comments

Comments
 (0)