Skip to content

TarReader stops enumerating entries when stream is unseekable #74728

@slang25

Description

@slang25

Description

When enumerating a tar file using TarReader and GetNextEntryAsync, once ExtractToFileAsync is called on one entry then the enumerating stops.

However, if the source tar stream is copied into a MemoryStream then it works as expected.

Reproduction Steps

using System.Formats.Tar;
using static System.Console;

using System.IO.Compression;

// 🎸 Tar Issue that I wish you saw... 🎶

await using var s = File.OpenRead("./my-file.tar.gz");
await using var gz = new GZipStream(s, CompressionMode.Decompress, true);

// Change to true to see what should happen
var copyToMemoryStream = false;

var tarStream = copyToMemoryStream ? await CopyToMemoryStream(gz) : gz;
await using var tarReader = new TarReader(tarStream, true);

var temp = Directory.CreateDirectory("temp").FullName;

var entriesCount = 0;
while (await tarReader.GetNextEntryAsync() is { } entry)
{
	WriteLine(entry.Name);
	entriesCount++;
	
	var destination = Path.Combine(temp, entry.Name);
	if (entry.EntryType is TarEntryType.Directory)
	{
		Directory.CreateDirectory(destination);
	}
	else
	{
		await entry.ExtractToFileAsync(destination, true);
	}
}

WriteLine();
WriteLine("Should have encountered 140 tar entries");
WriteLine($"Actual: {entriesCount}");

async Task<Stream> CopyToMemoryStream(Stream source)
{
	var destination = new MemoryStream();
	await source.CopyToAsync(destination);
	destination.Seek(0, SeekOrigin.Begin);
	return destination;
}

:octocat: Repro here

Expected behavior

In the code example provided, we should see the entries count being 140, and it indeed is when we copy the source to a MemoryStream.

Actual behavior

The TarReader stops returning entries after the first one has been extracted, resulting in an entries count of 7 (we called ExtractToFileAsync on the 7th entry).

Regression?

No response

Known Workarounds

Copy tar stream into a MemoryStream before using TarReader

Configuration

No response

Other information

:octocat: Repro here

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions