ExtractAllEntries returns no entries when reading a ZIP from a Stream #704

Closed
opened 2026-01-29 22:16:13 +00:00 by claunia · 9 comments
Owner

Originally created by @alnkesq on GitHub (Oct 19, 2025).

Originally assigned to: @adamhathcock on GitHub.

Appears to be a regression in 0.41.0

test.zip

Generated via 7z a test.zip wallhaven-225935.jpg. Example input file must be sufficiently large for the bug to become apparent.

The following code produces 0 results in SharpCompress 0.41.0.

using var zipStream = File.OpenRead(@"C:\test.zip"); // Important! don't use ArchiveFactory.Open(string) overload
using var archive = SharpCompress.Archives.ArchiveFactory.Open(zipStream);
using var reader = archive.ExtractAllEntries();
while (reader.MoveToNextEntry())
{
    Console.WriteLine(reader.Entry);
}

I bisected and the issue starts occurring here 76de7d54c7 (replacing stream.Position = 0; with ((IStreamStack)stream).StackSeek(0);)

Originally created by @alnkesq on GitHub (Oct 19, 2025). Originally assigned to: @adamhathcock on GitHub. Appears to be a regression in 0.41.0 [test.zip](https://github.com/user-attachments/files/22993107/test.zip) Generated via ```7z a test.zip wallhaven-225935.jpg```. Example input file must be sufficiently large for the bug to become apparent. The following code produces 0 results in SharpCompress 0.41.0. ```csharp using var zipStream = File.OpenRead(@"C:\test.zip"); // Important! don't use ArchiveFactory.Open(string) overload using var archive = SharpCompress.Archives.ArchiveFactory.Open(zipStream); using var reader = archive.ExtractAllEntries(); while (reader.MoveToNextEntry()) { Console.WriteLine(reader.Entry); } ``` I bisected and the issue starts occurring here https://github.com/adamhathcock/sharpcompress/commit/76de7d54c7eacf014d3fafc8352f61f3e32ef11d (replacing `stream.Position = 0;` with `((IStreamStack)stream).StackSeek(0);`)
Author
Owner

@adamhathcock commented on GitHub (Oct 20, 2025):

I think this is slightly misleading.

You have a zip file using the Archive interface then switch to solid extraction (which is only meant for SOLID rars and 7zip) which doesn't result in anything. This is expected behavior (though I should probably throw an error).

Use the Entries collection from the archive to get your file. Or use the ReaderFactory.Open to get entries via the IReader interface.

Combining both isn't necessary for this zip nor supported

@adamhathcock commented on GitHub (Oct 20, 2025): I think this is slightly misleading. You have a zip file using the Archive interface then switch to solid extraction (which is only meant for SOLID rars and 7zip) which doesn't result in anything. This is expected behavior (though I should probably throw an error). Use the Entries collection from the archive to get your file. Or use the ReaderFactory.Open to get entries via the IReader interface. Combining both isn't necessary for this zip nor supported
Author
Owner

@alnkesq commented on GitHub (Oct 20, 2025):

I see, I didn't realize ExtractAllEntries wasn't meant to be called on non-IsSolid archives.
Now it works as expected.

@alnkesq commented on GitHub (Oct 20, 2025): I see, I didn't realize `ExtractAllEntries` wasn't meant to be called on non-`IsSolid` archives. Now it works as expected.
Author
Owner

@arthurvb commented on GitHub (Oct 26, 2025):

Although the issue is closed, a small question. If I do not know in advance if my archive is a SOLID rar, 7zip or something else and I want a IReader-interface to get all entries in the archive. I should first open it with the ArchiveFactory to determine this, correct? And if it is just an ordinary zip-file, close the archive and re-open using the ReaderFactory.

Would it make sense to have one method to get an IReader-interface that works on all archives? (I know I could make it myself, but I was just wondering if it would make sense or that I am missing something).

@arthurvb commented on GitHub (Oct 26, 2025): Although the issue is closed, a small question. If I do not know in advance if my archive is a SOLID rar, 7zip or something else and I want a IReader-interface to get all entries in the archive. I should first open it with the ArchiveFactory to determine this, correct? And if it is just an ordinary zip-file, close the archive and re-open using the ReaderFactory. Would it make sense to have one method to get an IReader-interface that works on all archives? (I know I could make it myself, but I was just wondering if it would make sense or that I am missing something).
Author
Owner

@adamhathcock commented on GitHub (Oct 27, 2025):

It's a thing to consider something that does work for everything. I haven't thought about it in a while and SOLID/Streams from 7Zip does throw a spanner into my "purity" of the interfaces.

I'd make a new issue about this.

@adamhathcock commented on GitHub (Oct 27, 2025): It's a thing to consider something that does work for everything. I haven't thought about it in a while and SOLID/Streams from 7Zip does throw a spanner into my "purity" of the interfaces. I'd make a new issue about this.
Author
Owner

@alex-konstantinov commented on GitHub (Dec 5, 2025):

Although the issue is closed, a small question. If I do not know in advance if my archive is a SOLID rar, 7zip or something else and I want a IReader-interface to get all entries in the archive. I should first open it with the ArchiveFactory to determine this, correct? And if it is just an ordinary zip-file, close the archive and re-open using the ReaderFactory.

Would it make sense to have one method to get an IReader-interface that works on all archives? (I know I could make it myself, but I was just wondering if it would make sense or that I am missing something).

It does seems a bit counter-productive right now yes. We have updated SharpCompress dependency to the latest version and now we have exception thrown for some of the files. As we process our users' files when we get them - we don't know what the files are, zip, rar, 7z, how they were created etc. We just need to extract all content and that's it. ExtractAllEntries was ideal way of handling archives.

Now seems like either we better revert to previous version or spend a lot of time on writing the handling code to identify the archive type, etc. etc.

From my point of view, it would be more optimal to incapsulate that kind of checks inside.

@alex-konstantinov commented on GitHub (Dec 5, 2025): > Although the issue is closed, a small question. If I do not know in advance if my archive is a SOLID rar, 7zip or something else and I want a IReader-interface to get all entries in the archive. I should first open it with the ArchiveFactory to determine this, correct? And if it is just an ordinary zip-file, close the archive and re-open using the ReaderFactory. > > Would it make sense to have one method to get an IReader-interface that works on all archives? (I know I could make it myself, but I was just wondering if it would make sense or that I am missing something). It does seems a bit counter-productive right now yes. We have updated SharpCompress dependency to the latest version and now we have exception thrown for some of the files. As we process our users' files when we get them - we don't know what the files are, zip, rar, 7z, how they were created etc. We just need to extract all content and that's it. ExtractAllEntries was ideal way of handling archives. Now seems like either we better revert to previous version or spend a lot of time on writing the handling code to identify the archive type, etc. etc. From my point of view, it would be more optimal to incapsulate that kind of checks inside.
Author
Owner

@adamhathcock commented on GitHub (Dec 5, 2025):

I get what you mean: you'd like to be able to handle all types with just one interface.

Are you using Archive or Reader?

@adamhathcock commented on GitHub (Dec 5, 2025): I get what you mean: you'd like to be able to handle all types with just one interface. Are you using Archive or Reader?
Author
Owner

@alex-konstantinov commented on GitHub (Dec 8, 2025):

I get what you mean: you'd like to be able to handle all types with just one interface.

Are you using Archive or Reader?

Currently as we've reverted to version 0.40.0 we are using IArchive instance which we get from factory to extract all entries. However we also use 'Entries' properties to enumerate entries to see if there are any nested archives if we need to extract them as well. Sometimes users place archives into archives of archives :)

Image
@alex-konstantinov commented on GitHub (Dec 8, 2025): > I get what you mean: you'd like to be able to handle all types with just one interface. > > Are you using Archive or Reader? Currently as we've reverted to version 0.40.0 we are using IArchive instance which we get from factory to extract all entries. However we also use 'Entries' properties to enumerate entries to see if there are any nested archives if we need to extract them as well. Sometimes users place archives into archives of archives :) <img width="1313" height="687" alt="Image" src="https://github.com/user-attachments/assets/d744e4a7-8cf0-4caa-bcc4-400d41b29247" />
Author
Owner

@paul-ennemoser-jaha commented on GitHub (Dec 9, 2025):

Hi!

We have the following method, which now after this change throws errors - it worked perfectly fine before:

      public void ExtractToDirectory( string archivePath, string extractPath )
      {
          // Lock for Extraction Progress because of Singleton
          lock( extractToDictionarySyncObject )
          {
              var options = new ExtractionOptions() {
                  ExtractFullPath = true,
                  Overwrite = true
              };

              Directory.CreateDirectory( extractPath );

              using IArchive archive = ArchiveFactory.Open( archivePath );
              double totalSize = archive.Entries.Where( e => !e.IsDirectory ).Sum( e => e.Size );
              long completed = 0;

              IReader reader = archive.ExtractAllEntries();
              while( reader.MoveToNextEntry() )
              {
                  if( !reader.Entry.IsDirectory )
                  {
                      reader.WriteEntryToDirectory( extractPath, options );

                      completed += reader.Entry.Size;
                      ExtractionProgress?.Invoke( this, new ExtractionProgressEventArgs( completed / totalSize ) );
                  }
              }
          }
      }

Error:

System.InvalidOperationException: ExtractAllEntries can only be used on solid archives or 7Zip archives (which require random access).
   at SharpCompress.Archives.AbstractArchive`2.ExtractAllEntries() in /_/src/SharpCompress/Archives/AbstractArchive.cs:line 149

What instead of ExtractAllEntries should we use?

In the meantime we also have to downgrade to 0.41.0

Thanks :)

@paul-ennemoser-jaha commented on GitHub (Dec 9, 2025): Hi! We have the following method, which now after this change throws errors - it worked perfectly fine before: ``` public void ExtractToDirectory( string archivePath, string extractPath ) { // Lock for Extraction Progress because of Singleton lock( extractToDictionarySyncObject ) { var options = new ExtractionOptions() { ExtractFullPath = true, Overwrite = true }; Directory.CreateDirectory( extractPath ); using IArchive archive = ArchiveFactory.Open( archivePath ); double totalSize = archive.Entries.Where( e => !e.IsDirectory ).Sum( e => e.Size ); long completed = 0; IReader reader = archive.ExtractAllEntries(); while( reader.MoveToNextEntry() ) { if( !reader.Entry.IsDirectory ) { reader.WriteEntryToDirectory( extractPath, options ); completed += reader.Entry.Size; ExtractionProgress?.Invoke( this, new ExtractionProgressEventArgs( completed / totalSize ) ); } } } } ``` Error: ``` System.InvalidOperationException: ExtractAllEntries can only be used on solid archives or 7Zip archives (which require random access). at SharpCompress.Archives.AbstractArchive`2.ExtractAllEntries() in /_/src/SharpCompress/Archives/AbstractArchive.cs:line 149 ``` What instead of ExtractAllEntries should we use? In the meantime we also have to downgrade to 0.41.0 Thanks :)
Author
Owner

@adamhathcock commented on GitHub (Dec 9, 2025):

I tried to capture this here: https://github.com/adamhathcock/sharpcompress/issues/1070

All ideas (including reverting) are welcome

@adamhathcock commented on GitHub (Dec 9, 2025): I tried to capture this here: https://github.com/adamhathcock/sharpcompress/issues/1070 All ideas (including reverting) are welcome
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/sharpcompress#704