Bug 39282

Summary: [System.IO.Compression] issues with ZipArchiveEntry streams
Product: [Mono] Class Libraries Reporter: RichardW <numpsyuk>
Component: GeneralAssignee: João Matos <joao.matos>
Severity: normal CC: masafa, mono-bugs+mono
Priority: ---    
Version: master   
Target Milestone: Untriaged   
Hardware: PC   
OS: Linux   
Tags: Is this bug a regression?: ---
Last known good build:

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: