Bug 39282 - [System.IO.Compression] issues with ZipArchiveEntry streams
Summary: [System.IO.Compression] issues with ZipArchiveEntry streams
Alias: None
Product: Class Libraries
Classification: Mono
Component: General ()
Version: master
Hardware: PC Linux
: --- normal
Target Milestone: Untriaged
Assignee: João Matos
Depends on:
Reported: 2016-03-02 02:00 UTC by RichardW
Modified: 2016-06-29 10:44 UTC (History)
2 users (show)

Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.

Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:

Description RichardW 2016-03-02 02:00:14 UTC
As mentioned at


It Seems that the MS version of ZipArchiveEntry.Open (in some cases at least) returns a stream whose length can be queried, whereas the Mono version always throws.
Running the tests for the Microsoft Open XML SDK on Mono master gets a lot of failures due to it relying on being able to query the length (though as the linked issue says, the SDK contains its own workaround to make it work in some cases).

I know that DeflateStream doesn't support querying the length (as mentioned in #36638), however the documentation for ZipArchiveEntry.Open doesn't actually state the type of stream it returns, and as the MS implementation allows it in some cases this is at least an inconsistency in operation.
Comment 1 RichardW 2016-03-02 14:01:33 UTC
With a bit more testing, it seems that code along the lines of

string _path = Path.Combine(Directory.GetCurrentDirectory(), "Temp-16ab1efb9254430987adc092eeb60c63.docx");

var _containerStream = new FileStream(_path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);

var zipArchive = new ZipArchive(_containerStream, ZipArchiveMode.Update, true, Encoding.UTF8);

var firstEntry = zipArchive.Entries [0].Open ();

using (StreamWriter sw = new StreamWriter(firstEntry))

Will write to the stream when run on MS.NET, but throw a 'Stream is not writeable' exception on Mono. Seems like it should be possible to write to the stream when the archive is in update mode?
Comment 2 João Matos 2016-06-13 23:46:32 UTC
I'll look into it.
Comment 3 João Matos 2016-06-21 23:22:08 UTC
Comment 4 João Matos 2016-06-24 00:29:31 UTC
Second round of fixes: https://github.com/mono/mono/pull/3209
Comment 5 RichardW 2016-06-27 14:19:46 UTC
I had a go at running the Open XML SDK on the latest Mono master, and got a bunch of new failures along the lines of

System.IO.Packaging.Tests.Tests.T104_String_Create_ReadWrite_Open_Write [FAIL]
      SharpCompress.Common.ArchiveException : Cannot add entry with duplicate key: dummy.xml
      Stack Trace:
           at SharpCompress.Archive.AbstractWritableArchive`2[TEntry,TVolume].AddEntry (System.String key, System.IO.Stream source, System.Boolean closeStream, System.Int64 size, System.Nullable`1[T] modified) <0x10d965100 + 0x001bd> in <filename unknown>:0 
           at SharpCompress.Archive.AbstractWritableArchive`2[TEntry,TVolume].AddEntry (System.String key, System.IO.Stream source, System.Int64 size, System.Nullable`1[T] modified) <0x10d9650a0 + 0x00043> in <filename unknown>:0 
           at System.IO.Compression.ZipArchive.CreateEntryInternal (System.String entryName) <0x10d965010 + 0x00078> in <filename unknown>:0 
           at System.IO.Compression.ZipArchiveEntryStream.SetWriteable () <0x10d97f910 + 0x00056> in <filename unknown>:0 
           at System.IO.Compression.ZipArchiveEntryStream.Write (System.Byte[] buffer, System.Int32 offset, System.Int32 count) <0x10d97f870 + 0x0005d> in <filename unknown>:0 
           at System.IO.Packaging.ZipWrappingStream.Write (System.Byte[] buffer, System.Int32 offset, System.Int32 count) <0x10d97f830 + 0x00038> in <filename unknown>:0 
           at System.IO.StreamWriter.Flush (System.Boolean flushStream, System.Boolean flushEncoder) <0x10dc17ad0 + 0x00115> in <filename unknown>:0 

Which looks to be because code along the lines of

var mStream = new MemoryStream();
var zipArchive = new ZipArchive(mStream, ZipArchiveMode.Update);

var newEntry = zipArchive.CreateEntry("testEntry");

using (var newStream = newEntry.Open())
    using (var sw = new StreamWriter(newStream))

which runs ok in Mono 4.4 now throws with an error about duplicate entries on master.

It seems ok when working on existing archives that contain other entries, but looking at the code that might be because of another issue.

In System.IO.Compression/SharpCompress/Archive/AbstractWritableArchive.cs there is a DoesKeyMatchExisting function that looks like it should be checking the name of each entry in the archive but only actually checks the first.

As a test, If I do

var e2 = zipArchive.CreateEntry("BBB");
var e3 = zipArchive.CreateEntry("BBB");

Then I get an exception about duplicate errors, but if I do 

var e1 = zipArchive.CreateEntry("AAA");
var e2 = zipArchive.CreateEntry("BBB");
var e3 = zipArchive.CreateEntry("BBB");

then I don't, which doesn't seem right.
Comment 6 João Matos 2016-06-28 17:08:46 UTC
One more fix: https://github.com/mono/mono/pull/3214
Comment 7 João Matos 2016-06-29 10:44:26 UTC
Marking this one as fixed now that all the PRs landed.

For the duplicate entries problem: