Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Fix bug in ZipArchiveEntry data descriptor#37601

Merged
carlossanlop merged 4 commits intodotnet:masterfrom
carlossanlop:datadescriptor
May 14, 2019
Merged

Fix bug in ZipArchiveEntry data descriptor#37601
carlossanlop merged 4 commits intodotnet:masterfrom
carlossanlop:datadescriptor

Conversation

@carlossanlop
Copy link
Copy Markdown

Fixes https://github.com/dotnet/corefx/issues/29872

When a zip file is created using an unseekable stream, the data descriptor bit is turned on. If we update that same zip file, we should expect the data descriptor to get turned off. If it doesn't get turned off, the file gets in a bad state: we can open it with File Explorer or 7-Zip without problems, but we cannot drag-drop files into that zip file anymore; those programs say the file is corrupted.

Added a unit test to verify the data descriptor value is the expected one in the first local file header, after creating a zip file with an unseekable stream and after updating the zip file.

…ls) when data descriptor bit is turned on in a seekable file that is being updated.
…ile that was created with an unseekable stream.
@carlossanlop carlossanlop self-assigned this May 11, 2019
@carlossanlop
Copy link
Copy Markdown
Author

carlossanlop commented May 14, 2019

Ran an automation job that targets the Compression unit tests:
https://mc.dot.net/#/user/calope/pr~2Fdotnet~2Fcorefx/test~2Ffunctional~2Fcli~2F/20190513.00

Edit: It passed.

@carlossanlop carlossanlop merged commit 05ada9b into dotnet:master May 14, 2019
@carlossanlop carlossanlop deleted the datadescriptor branch May 14, 2019 21:26
{
using var memoryStream = new MemoryStream();
// We need an non-seekable stream so the data descriptor bit is turned on when saving
var wrappedStream = new WrappedStream(memoryStream, true, true, false, null);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, not worth going back and changing now, but when passing booleans into a method, it's nice to name them since it often makes it clearer what's going on. eg Foo(bar, baz, enableFrob:true)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sometimes also nulls.

{
ZipArchiveEntry entry = archive.Entries[0];
using Stream entryStream = entry.Open();
StreamReader reader = new StreamReader(entryStream);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

technically this Reader is a disable object that will close the stream when disposed. If the GC decided to collect after the last reference to reader it would close your MemoryStream and your other calls can fail with ObjectDisposed.

ZipArchiveEntry entry = archive.Entries[0];
using Stream entryStream = entry.Open();
StreamReader reader = new StreamReader(entryStream);
string content = reader.ReadToEnd();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: you read the stream, didn't do anything with the output, and also seeked to the end (which I believe is a noop if you read to the end already). Maybe just delete this code that's using the reader and just keep the seek call.


// Append a string to this entry
entryStream.Seek(0, SeekOrigin.End);
StreamWriter writer = new StreamWriter(entryStream);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe StreamWriter has the same problem as the reader, you need to specify leaveOpen = true

var wrappedStream = new WrappedStream(memoryStream, true, true, false, null);

// Creation will go through the path that sets the data descriptor bit when the stream is unseekable
using (var archive = new ZipArchive(wrappedStream, ZipArchiveMode.Create))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ZipArchive usage here and below also need leaveOpen=true.

@carlossanlop
Copy link
Copy Markdown
Author

@thank you for your comments, @danmosemsft / @ericstj . I will address them in a future PR because I had already closed this one.

@karelz karelz added this to the 3.0 milestone May 22, 2019
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
* Prevent data corruption (can't drag drop files using external zip tools) when data descriptor bit is turned on in a seekable file that is being updated.

* Add unit test to verify data descriptor is off after updating a zip file that was created with an unseekable stream.


Commit migrated from dotnet/corefx@05ada9b
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update of zip file with DataDescriptor using ZipArchive results in corrupted file

5 participants