public void Constructor_ConversionFromUstar_From_UnseekableTarReader(TarEntryFormat writerFormat) { using MemoryStream source = GetTarMemoryStream(CompressionMethod.Uncompressed, TestTarFormat.ustar, "file"); using WrappedStream wrappedSource = new WrappedStream(source, canRead: true, canWrite: false, canSeek: false); using TarReader sourceReader = new TarReader(wrappedSource, leaveOpen: true); UstarTarEntry ustarEntry = sourceReader.GetNextEntry(copyData: false) as UstarTarEntry; V7TarEntry v7Entry = new V7TarEntry(other: ustarEntry); // Convert, and avoid advancing wrappedSource position using MemoryStream destination = new MemoryStream(); using (TarWriter writer = new TarWriter(destination, writerFormat, leaveOpen: true)) { writer.WriteEntry(v7Entry); // Write DataStream exactly where the wrappedSource position was left } destination.Position = 0; // Rewind using (TarReader destinationReader = new TarReader(destination, leaveOpen: false)) { V7TarEntry resultEntry = destinationReader.GetNextEntry() as V7TarEntry; Assert.NotNull(resultEntry); using (StreamReader streamReader = new StreamReader(resultEntry.DataStream)) { Assert.Equal("Hello file", streamReader.ReadToEnd()); } } }
public void SupportedEntryType_Directory() { UstarTarEntry directory = new UstarTarEntry(TarEntryType.Directory, InitialEntryName); SetDirectory(directory); VerifyDirectory(directory); }
public void SupportedEntryType_RegularFile() { UstarTarEntry regularFile = new UstarTarEntry(TarEntryType.RegularFile, InitialEntryName); SetRegularFile(regularFile); VerifyRegularFile(regularFile, isWritable: true); }
public void SupportedEntryType_SymbolicLink() { UstarTarEntry symbolicLink = new UstarTarEntry(TarEntryType.SymbolicLink, InitialEntryName); SetSymbolicLink(symbolicLink); VerifySymbolicLink(symbolicLink); }
public void SupportedEntryType_HardLink() { UstarTarEntry hardLink = new UstarTarEntry(TarEntryType.HardLink, InitialEntryName); SetHardLink(hardLink); VerifyHardLink(hardLink); }
public async Task LongEndMarkers_DoNotAdvanceStream_Async() { await using (MemoryStream archive = new MemoryStream()) { await using (TarWriter writer = new TarWriter(archive, TarEntryFormat.Ustar, leaveOpen: true)) { UstarTarEntry entry = new UstarTarEntry(TarEntryType.Directory, "dir"); await writer.WriteEntryAsync(entry); } byte[] buffer = new byte[2048]; // Four additional end markers (512 each) Array.Fill <byte>(buffer, 0x0); archive.Write(buffer); archive.Seek(0, SeekOrigin.Begin); await using (TarReader reader = new TarReader(archive)) { Assert.NotNull(await reader.GetNextEntryAsync()); Assert.Null(await reader.GetNextEntryAsync()); long expectedPosition = archive.Position; // After reading the first null entry, should not advance more Assert.Null(await reader.GetNextEntryAsync()); Assert.Equal(expectedPosition, archive.Position); } } }
public void SupportedEntryType_BlockDevice() { UstarTarEntry blockDevice = new UstarTarEntry(TarEntryType.BlockDevice, InitialEntryName); SetBlockDevice(blockDevice); VerifyBlockDevice(blockDevice); }
public void SupportedEntryType_CharacterDevice() { UstarTarEntry characterDevice = new UstarTarEntry(TarEntryType.CharacterDevice, InitialEntryName); SetCharacterDevice(characterDevice); VerifyCharacterDevice(characterDevice); }
public void ExtractEntry_ManySubfolderSegments_NoPrecedingDirectoryEntries() { using TempDirectory root = new TempDirectory(); string firstSegment = "a"; string secondSegment = Path.Join(firstSegment, "b"); string fileWithTwoSegments = Path.Join(secondSegment, "c.txt"); using MemoryStream archive = new MemoryStream(); using (TarWriter writer = new TarWriter(archive, TarFormat.Ustar, leaveOpen: true)) { // No preceding directory entries for the segments UstarTarEntry entry = new UstarTarEntry(TarEntryType.RegularFile, fileWithTwoSegments); entry.DataStream = new MemoryStream(); entry.DataStream.Write(new byte[] { 0x1 }); entry.DataStream.Seek(0, SeekOrigin.Begin); writer.WriteEntry(entry); } archive.Seek(0, SeekOrigin.Begin); TarFile.ExtractToDirectory(archive, root.Path, overwriteFiles: false); Assert.True(Directory.Exists(Path.Join(root.Path, firstSegment))); Assert.True(Directory.Exists(Path.Join(root.Path, secondSegment))); Assert.True(File.Exists(Path.Join(root.Path, fileWithTwoSegments))); }
public void SupportedEntryType_Fifo() { UstarTarEntry fifo = new UstarTarEntry(TarEntryType.Fifo, InitialEntryName); SetFifo(fifo); VerifyFifo(fifo); }
public async Task GetNextEntry_UnseekableArchive_ReplaceDataStream_ExcludeFromDisposing_Async(bool copyData) { await using (MemoryStream archive = new MemoryStream()) { await using (TarWriter writer = new TarWriter(archive, TarEntryFormat.Ustar, leaveOpen: true)) { UstarTarEntry entry1 = new UstarTarEntry(TarEntryType.RegularFile, "file.txt"); entry1.DataStream = new MemoryStream(); using (StreamWriter streamWriter = new StreamWriter(entry1.DataStream, leaveOpen: true)) { streamWriter.WriteLine("Hello world!"); } entry1.DataStream.Seek(0, SeekOrigin.Begin); // Rewind to ensure it gets written from the beginning await writer.WriteEntryAsync(entry1); UstarTarEntry entry2 = new UstarTarEntry(TarEntryType.Directory, "dir"); await writer.WriteEntryAsync(entry2); } archive.Seek(0, SeekOrigin.Begin); await using (WrappedStream wrapped = new WrappedStream(archive, canRead: true, canWrite: false, canSeek: false)) { UstarTarEntry entry; Stream oldStream; await using (TarReader reader = new TarReader(wrapped)) // Unseekable { entry = await reader.GetNextEntryAsync(copyData) as UstarTarEntry; Assert.NotNull(entry); Assert.Equal(TarEntryType.RegularFile, entry.EntryType); oldStream = entry.DataStream; entry.DataStream = new MemoryStream(); // Substitution, setter should dispose the previous stream using (StreamWriter streamWriter = new StreamWriter(entry.DataStream, leaveOpen: true)) { streamWriter.WriteLine("Substituted"); } } // Disposing reader should not dispose the substituted DataStream Assert.Throws <ObjectDisposedException>(() => oldStream.Read(new byte[1])); entry.DataStream.Seek(0, SeekOrigin.Begin); using (StreamReader streamReader = new StreamReader(entry.DataStream)) { Assert.Equal("Substituted", streamReader.ReadLine()); } } } }
public async Task GetNextEntry_CopyDataTrue_UnseekableArchive_Async() { string expectedText = "Hello world!"; await using (MemoryStream archive = new MemoryStream()) { await using (TarWriter writer = new TarWriter(archive, TarEntryFormat.Ustar, leaveOpen: true)) { UstarTarEntry entry1 = new UstarTarEntry(TarEntryType.RegularFile, "file.txt"); entry1.DataStream = new MemoryStream(); using (StreamWriter streamWriter = new StreamWriter(entry1.DataStream, leaveOpen: true)) { streamWriter.WriteLine(expectedText); } entry1.DataStream.Seek(0, SeekOrigin.Begin); await writer.WriteEntryAsync(entry1); UstarTarEntry entry2 = new UstarTarEntry(TarEntryType.Directory, "dir"); await writer.WriteEntryAsync(entry2); } archive.Seek(0, SeekOrigin.Begin); await using (WrappedStream wrapped = new WrappedStream(archive, canRead: true, canWrite: false, canSeek: false)) { UstarTarEntry entry; await using (TarReader reader = new TarReader(wrapped, leaveOpen: true)) // Unseekable { entry = await reader.GetNextEntryAsync(copyData : true) as UstarTarEntry; Assert.NotNull(entry); Assert.Equal(TarEntryType.RegularFile, entry.EntryType); // Force reading the next entry to advance the underlying stream position Assert.NotNull(await reader.GetNextEntryAsync()); Assert.Null(await reader.GetNextEntryAsync()); Assert.NotNull(entry.DataStream); entry.DataStream.Seek(0, SeekOrigin.Begin); // Should not throw: This is a new stream, not the archive's disposed stream using (StreamReader streamReader = new StreamReader(entry.DataStream)) { string actualText = streamReader.ReadLine(); Assert.Equal(expectedText, actualText); } } // The reader must stay alive because it's in charge of disposing all the entries it collected Assert.Throws <ObjectDisposedException>(() => entry.DataStream.Read(new byte[1])); } } }
public void Constructor_Name_FullPath_DestinationDirectory_Match() { using TempDirectory root = new TempDirectory(); string fullPath = Path.Join(root.Path, "file.txt"); UstarTarEntry entry = new UstarTarEntry(TarEntryType.RegularFile, fullPath); entry.DataStream = new MemoryStream(); entry.DataStream.Write(new byte[] { 0x1 }); entry.DataStream.Seek(0, SeekOrigin.Begin); entry.ExtractToFile(fullPath, overwrite: false); Assert.True(File.Exists(fullPath)); }
public void ExtractToFile_Link_Throws(TarEntryType entryType) { using TempDirectory root = new TempDirectory(); string fileName = "mylink"; string fullPath = Path.Join(root.Path, fileName); string linkTarget = PlatformDetection.IsWindows ? @"C:\Windows\system32\notepad.exe" : "/usr/bin/nano"; UstarTarEntry entry = new UstarTarEntry(entryType, fileName); entry.LinkName = linkTarget; Assert.Throws <InvalidOperationException>(() => entry.ExtractToFile(fileName, overwrite: false)); Assert.Equal(0, Directory.GetFileSystemEntries(root.Path).Count()); }
public void Constructor_Name_FullPath_DestinationDirectory_Mismatch_Throws() { using TempDirectory root = new TempDirectory(); string fullPath = Path.Join(Path.GetPathRoot(root.Path), "dir", "file.txt"); UstarTarEntry entry = new UstarTarEntry(TarEntryType.RegularFile, fullPath); entry.DataStream = new MemoryStream(); entry.DataStream.Write(new byte[] { 0x1 }); entry.DataStream.Seek(0, SeekOrigin.Begin); Assert.Throws <IOException>(() => entry.ExtractToFile(root.Path, overwrite: false)); Assert.False(File.Exists(fullPath)); }
public void GetNextEntry_CopyDataTrue_SeekableArchive() { string expectedText = "Hello world!"; MemoryStream archive = new MemoryStream(); using (TarWriter writer = new TarWriter(archive, TarEntryFormat.Ustar, leaveOpen: true)) { UstarTarEntry entry1 = new UstarTarEntry(TarEntryType.RegularFile, "file.txt"); entry1.DataStream = new MemoryStream(); using (StreamWriter streamWriter = new StreamWriter(entry1.DataStream, leaveOpen: true)) { streamWriter.WriteLine(expectedText); } entry1.DataStream.Seek(0, SeekOrigin.Begin); // Rewind to ensure it gets written from the beginning writer.WriteEntry(entry1); UstarTarEntry entry2 = new UstarTarEntry(TarEntryType.Directory, "dir"); writer.WriteEntry(entry2); } archive.Seek(0, SeekOrigin.Begin); UstarTarEntry entry; using (TarReader reader = new TarReader(archive)) // Seekable { entry = reader.GetNextEntry(copyData: true) as UstarTarEntry; Assert.NotNull(entry); Assert.Equal(TarEntryType.RegularFile, entry.EntryType); // Force reading the next entry to advance the underlying stream position Assert.NotNull(reader.GetNextEntry()); Assert.Null(reader.GetNextEntry()); entry.DataStream.Seek(0, SeekOrigin.Begin); // Should not throw: This is a new stream, not the archive's disposed stream using (StreamReader streamReader = new StreamReader(entry.DataStream)) { string actualText = streamReader.ReadLine(); Assert.Equal(expectedText, actualText); } } // The reader must stay alive because it's in charge of disposing all the entries it collected Assert.Throws <ObjectDisposedException>(() => entry.DataStream.Read(new byte[1])); }
protected override Task <Stream?> CreateReadOnlyStreamCore(byte[]?initialData) { var ms = new MemoryStream(); using (var writer = new TarWriter(ms, leaveOpen: true)) { var entry = new UstarTarEntry(TarEntryType.RegularFile, "Test"); if (initialData is not null) { entry.DataStream = new MemoryStream(initialData); } writer.WriteEntry(entry); } ms.Position = 0; return(Task.FromResult(new TarReader(ms).GetNextEntry().DataStream)); }
public void Extract_LinkEntry_TargetOutsideDirectory(TarEntryType entryType) { using MemoryStream archive = new MemoryStream(); using (TarWriter writer = new TarWriter(archive, TarFormat.Ustar, leaveOpen: true)) { UstarTarEntry entry = new UstarTarEntry(entryType, "link"); entry.LinkName = PlatformDetection.IsWindows ? @"C:\Windows\System32\notepad.exe" : "/usr/bin/nano"; writer.WriteEntry(entry); } archive.Seek(0, SeekOrigin.Begin); using TempDirectory root = new TempDirectory(); Assert.Throws <IOException>(() => TarFile.ExtractToDirectory(archive, root.Path, overwriteFiles: false)); Assert.Equal(0, Directory.GetFileSystemEntries(root.Path).Count()); }
public void WriteBlockDevice() { using MemoryStream archiveStream = new MemoryStream(); using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Ustar, leaveOpen: true)) { UstarTarEntry blockDevice = new UstarTarEntry(TarEntryType.BlockDevice, InitialEntryName); SetBlockDevice(blockDevice); VerifyBlockDevice(blockDevice); writer.WriteEntry(blockDevice); } archiveStream.Position = 0; using (TarReader reader = new TarReader(archiveStream)) { UstarTarEntry blockDevice = reader.GetNextEntry() as UstarTarEntry; VerifyBlockDevice(blockDevice); } }
public void WriteFifo() { using MemoryStream archiveStream = new MemoryStream(); using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Ustar, leaveOpen: true)) { UstarTarEntry fifo = new UstarTarEntry(TarEntryType.Fifo, InitialEntryName); SetFifo(fifo); VerifyFifo(fifo); writer.WriteEntry(fifo); } archiveStream.Position = 0; using (TarReader reader = new TarReader(archiveStream)) { UstarTarEntry fifo = reader.GetNextEntry() as UstarTarEntry; VerifyFifo(fifo); } }
public void WriteRegularFile() { using MemoryStream archiveStream = new MemoryStream(); using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Ustar, leaveOpen: true)) { UstarTarEntry regularFile = new UstarTarEntry(TarEntryType.RegularFile, InitialEntryName); SetRegularFile(regularFile); VerifyRegularFile(regularFile, isWritable: true); writer.WriteEntry(regularFile); } archiveStream.Position = 0; using (TarReader reader = new TarReader(archiveStream)) { UstarTarEntry regularFile = reader.GetNextEntry() as UstarTarEntry; VerifyRegularFile(regularFile, isWritable: false); } }
public void WriteSymbolicLink() { using MemoryStream archiveStream = new MemoryStream(); using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Ustar, leaveOpen: true)) { UstarTarEntry symbolicLink = new UstarTarEntry(TarEntryType.SymbolicLink, InitialEntryName); SetSymbolicLink(symbolicLink); VerifySymbolicLink(symbolicLink); writer.WriteEntry(symbolicLink); } archiveStream.Position = 0; using (TarReader reader = new TarReader(archiveStream)) { UstarTarEntry symbolicLink = reader.GetNextEntry() as UstarTarEntry; VerifySymbolicLink(symbolicLink); } }
public void WriteDirectory() { using MemoryStream archiveStream = new MemoryStream(); using (TarWriter writer = new TarWriter(archiveStream, TarFormat.Ustar, leaveOpen: true)) { UstarTarEntry directory = new UstarTarEntry(TarEntryType.Directory, InitialEntryName); SetDirectory(directory); VerifyDirectory(directory); writer.WriteEntry(directory); } archiveStream.Position = 0; using (TarReader reader = new TarReader(archiveStream)) { UstarTarEntry directory = reader.GetNextEntry() as UstarTarEntry; VerifyDirectory(directory); } }
public async Task GetNextEntry_CopyDataFalse_UnseekableArchive_Exceptions_Async() { await using (MemoryStream archive = new MemoryStream()) { await using (TarWriter writer = new TarWriter(archive, TarEntryFormat.Ustar, leaveOpen: true)) { UstarTarEntry entry1 = new UstarTarEntry(TarEntryType.RegularFile, "file.txt"); entry1.DataStream = new MemoryStream(); using (StreamWriter streamWriter = new StreamWriter(entry1.DataStream, leaveOpen: true)) { streamWriter.WriteLine("Hello world!"); } entry1.DataStream.Seek(0, SeekOrigin.Begin); // Rewind to ensure it gets written from the beginning await writer.WriteEntryAsync(entry1); UstarTarEntry entry2 = new UstarTarEntry(TarEntryType.Directory, "dir"); await writer.WriteEntryAsync(entry2); } archive.Seek(0, SeekOrigin.Begin); await using (WrappedStream wrapped = new WrappedStream(archive, canRead: true, canWrite: false, canSeek: false)) { UstarTarEntry entry; await using (TarReader reader = new TarReader(wrapped)) // Unseekable { entry = await reader.GetNextEntryAsync(copyData : false) as UstarTarEntry; Assert.NotNull(entry); Assert.Equal(TarEntryType.RegularFile, entry.EntryType); entry.DataStream.ReadByte(); // Reading is possible as long as we don't move to the next entry // Attempting to read the next entry should automatically move the position pointer to the beginning of the next header Assert.NotNull(await reader.GetNextEntryAsync()); Assert.Null(await reader.GetNextEntryAsync()); // This is not possible because the position of the main stream is already past the data Assert.Throws <EndOfStreamException>(() => entry.DataStream.Read(new byte[1])); } // The reader must stay alive because it's in charge of disposing all the entries it collected Assert.Throws <ObjectDisposedException>(() => entry.DataStream.Read(new byte[1])); } } }
public async Task WriteDirectory_Async() { using MemoryStream archiveStream = new MemoryStream(); await using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Ustar, leaveOpen: true)) { UstarTarEntry directory = new UstarTarEntry(TarEntryType.Directory, InitialEntryName); SetDirectory(directory); VerifyDirectory(directory); await writer.WriteEntryAsync(directory); } archiveStream.Position = 0; await using (TarReader reader = new TarReader(archiveStream)) { UstarTarEntry directory = await reader.GetNextEntryAsync() as UstarTarEntry; VerifyDirectory(directory); } }
public async Task WriteSymbolicLink_Async() { using MemoryStream archiveStream = new MemoryStream(); await using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Ustar, leaveOpen: true)) { UstarTarEntry symbolicLink = new UstarTarEntry(TarEntryType.SymbolicLink, InitialEntryName); SetSymbolicLink(symbolicLink); VerifySymbolicLink(symbolicLink); await writer.WriteEntryAsync(symbolicLink); } archiveStream.Position = 0; await using (TarReader reader = new TarReader(archiveStream)) { UstarTarEntry symbolicLink = await reader.GetNextEntryAsync() as UstarTarEntry; VerifySymbolicLink(symbolicLink); } }
public async Task WriteBlockDevice_Async() { using MemoryStream archiveStream = new MemoryStream(); await using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Ustar, leaveOpen: true)) { UstarTarEntry blockDevice = new UstarTarEntry(TarEntryType.BlockDevice, InitialEntryName); SetBlockDevice(blockDevice); VerifyBlockDevice(blockDevice); await writer.WriteEntryAsync(blockDevice); } archiveStream.Position = 0; await using (TarReader reader = new TarReader(archiveStream)) { UstarTarEntry blockDevice = await reader.GetNextEntryAsync() as UstarTarEntry; VerifyBlockDevice(blockDevice); } }
public async Task WriteFifo_Async() { using MemoryStream archiveStream = new MemoryStream(); await using (TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Ustar, leaveOpen: true)) { UstarTarEntry fifo = new UstarTarEntry(TarEntryType.Fifo, InitialEntryName); SetFifo(fifo); VerifyFifo(fifo); await writer.WriteEntryAsync(fifo); } archiveStream.Position = 0; await using (TarReader reader = new TarReader(archiveStream)) { UstarTarEntry fifo = await reader.GetNextEntryAsync() as UstarTarEntry; VerifyFifo(fifo); } }
public void Write_V7RegularFileEntry_As_RegularFileEntry() { using MemoryStream archive = new MemoryStream(); using (TarWriter writer = new TarWriter(archive, archiveFormat: TarFormat.Ustar, leaveOpen: true)) { V7TarEntry entry = new V7TarEntry(TarEntryType.V7RegularFile, InitialEntryName); // Should be written as RegularFile writer.WriteEntry(entry); } archive.Seek(0, SeekOrigin.Begin); using (TarReader reader = new TarReader(archive)) { UstarTarEntry entry = reader.GetNextEntry() as UstarTarEntry; Assert.NotNull(entry); Assert.Equal(TarEntryType.RegularFile, entry.EntryType); Assert.Null(reader.GetNextEntry()); } }
public async Task WriteHardLink_Async() { using MemoryStream archiveStream = new MemoryStream(); TarWriter writer = new TarWriter(archiveStream, TarEntryFormat.Ustar, leaveOpen: true); await using (writer) { UstarTarEntry hardLink = new UstarTarEntry(TarEntryType.HardLink, InitialEntryName); SetHardLink(hardLink); VerifyHardLink(hardLink); await writer.WriteEntryAsync(hardLink); } archiveStream.Position = 0; TarReader reader = new TarReader(archiveStream); await using (reader) { UstarTarEntry hardLink = await reader.GetNextEntryAsync() as UstarTarEntry; VerifyHardLink(hardLink); } }