using System; using System.Collections.Generic; using System.IO; using SharpCompress.Common; using SharpCompress.Readers; using SharpCompress.Readers.Tar; using SharpCompress.Test.Mocks; using Xunit; namespace SharpCompress.Test.Tar; public class TarReaderTests : ReaderTests { public TarReaderTests() => UseExtensionInsteadOfNameToVerify = true; [Fact] public void Tar_Reader() => Read("Tar.tar", CompressionType.None); [Fact] public void Tar_Skip() { using ( Stream stream = new ForwardOnlyStream( File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar")) ) ) using (IReader reader = ReaderFactory.Open(stream)) { int x = 0; while (reader.MoveToNextEntry()) { if (!reader.Entry.IsDirectory) { x++; if (x % 2 == 0) { reader.WriteEntryToDirectory( SCRATCH_FILES_PATH, new ExtractionOptions() { ExtractFullPath = true, Overwrite = true } ); } } } } } [Fact] public void Tar_BZip2_Reader() => Read("Tar.tar.bz2", CompressionType.BZip2); [Fact] public void Tar_GZip_Reader() => Read("Tar.tar.gz", CompressionType.GZip); [Fact] public void Tar_LZip_Reader() => Read("Tar.tar.lz", CompressionType.LZip); [Fact] public void Tar_Xz_Reader() => Read("Tar.tar.xz", CompressionType.Xz); [Fact] public void Tar_BZip2_Entry_Stream() { using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.bz2"))) using (var reader = TarReader.Open(stream)) { while (reader.MoveToNextEntry()) { if (!reader.Entry.IsDirectory) { Assert.Equal(CompressionType.BZip2, reader.Entry.CompressionType); using (var entryStream = reader.OpenEntryStream()) { string file = Path.GetFileName(reader.Entry.Key); string folder = Path.GetDirectoryName(reader.Entry.Key) ?? throw new ArgumentNullException(); string destdir = Path.Combine(SCRATCH_FILES_PATH, folder); if (!Directory.Exists(destdir)) { Directory.CreateDirectory(destdir); } string destinationFileName = Path.Combine(destdir, file); using (FileStream fs = File.OpenWrite(destinationFileName)) { entryStream.TransferTo(fs); } } } } } VerifyFiles(); } [Fact] public void Tar_LongNamesWithLongNameExtension() { var filePaths = new List(); using ( Stream stream = File.OpenRead( Path.Combine(TEST_ARCHIVES_PATH, "Tar.LongPathsWithLongNameExtension.tar") ) ) using (var reader = TarReader.Open(stream)) { while (reader.MoveToNextEntry()) { if (!reader.Entry.IsDirectory) { filePaths.Add(reader.Entry.Key); } } } Assert.Equal(3, filePaths.Count); Assert.Contains("a.txt", filePaths); Assert.Contains( "wp-content/plugins/gravityformsextend/lib/Aws/Symfony/Component/ClassLoader/Tests/Fixtures/Apc/beta/Apc/ApcPrefixCollision/A/B/Bar.php", filePaths ); Assert.Contains( "wp-content/plugins/gravityformsextend/lib/Aws/Symfony/Component/ClassLoader/Tests/Fixtures/Apc/beta/Apc/ApcPrefixCollision/A/B/Foo.php", filePaths ); } [Fact] public void Tar_BZip2_Skip_Entry_Stream() { using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.bz2"))) using (var reader = TarReader.Open(stream)) { List names = new List(); while (reader.MoveToNextEntry()) { if (!reader.Entry.IsDirectory) { Assert.Equal(CompressionType.BZip2, reader.Entry.CompressionType); using (var entryStream = reader.OpenEntryStream()) { entryStream.SkipEntry(); names.Add(reader.Entry.Key); } } } Assert.Equal(3, names.Count); } } [Fact] public void Tar_Containing_Rar_Reader() { string archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.ContainsRar.tar"); using (Stream stream = File.OpenRead(archiveFullPath)) using (IReader reader = ReaderFactory.Open(stream)) { Assert.True(reader.ArchiveType == ArchiveType.Tar); } } [Fact] public void Tar_With_TarGz_With_Flushed_EntryStream() { string archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.ContainsTarGz.tar"); using (Stream stream = File.OpenRead(archiveFullPath)) using (IReader reader = ReaderFactory.Open(stream)) { Assert.True(reader.MoveToNextEntry()); Assert.Equal("inner.tar.gz", reader.Entry.Key); using (var entryStream = reader.OpenEntryStream()) { using (FlushOnDisposeStream flushingStream = new FlushOnDisposeStream(entryStream)) { // Extract inner.tar.gz using (var innerReader = ReaderFactory.Open(flushingStream)) { Assert.True(innerReader.MoveToNextEntry()); Assert.Equal("test", innerReader.Entry.Key); } } } } } [Fact] public void Tar_Broken_Stream() { string archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"); using (Stream stream = File.OpenRead(archiveFullPath)) using (IReader reader = ReaderFactory.Open(stream)) { var memoryStream = new MemoryStream(); Action action = () => reader.MoveToNextEntry(); var exception = Record.Exception(action); Assert.Null(exception); reader.MoveToNextEntry(); reader.WriteEntryTo(memoryStream); stream.Close(); Assert.Throws(action); } } #if !NETFRAMEWORK [Fact] public void Tar_GZip_With_Symlink_Entries() { var isWindows = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform( System.Runtime.InteropServices.OSPlatform.Windows ); using ( Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "TarWithSymlink.tar.gz")) ) using (var reader = TarReader.Open(stream)) { List names = new List(); while (reader.MoveToNextEntry()) { if (reader.Entry.IsDirectory) { continue; } reader.WriteEntryToDirectory( SCRATCH_FILES_PATH, new ExtractionOptions() { ExtractFullPath = true, Overwrite = true, WriteSymbolicLink = (sourcePath, targetPath) => { if (!isWindows) { var link = new Mono.Unix.UnixSymbolicLinkInfo(sourcePath); if (File.Exists(sourcePath)) { link.Delete(); // equivalent to ln -s -f } link.CreateSymbolicLinkTo(targetPath); } } } ); if (!isWindows) { if (reader.Entry.LinkTarget != null) { var path = System.IO.Path.Combine(SCRATCH_FILES_PATH, reader.Entry.Key); var link = new Mono.Unix.UnixSymbolicLinkInfo(path); if (link.HasContents) { // need to convert the link to an absolute path for comparison var target = reader.Entry.LinkTarget; var realTarget = System.IO.Path.GetFullPath( System.IO.Path.Combine( $"{System.IO.Path.GetDirectoryName(path)}", target ) ); Assert.Equal(realTarget, link.GetContents().ToString()); } else { Assert.True(false, "Symlink has no target"); } } } } } } #endif }