Skip to content

Breakage when files are added to archive in the "wrong" order #102

@mrclayman

Description

@mrclayman

Hi guys,

I have been battling for a few days with a curious issue. My use case is one where I need to replace the contents of one (JSON) text file after fetching it from the archive, deserializing it into a dedicated class instance, making the necessary changes and then serializing the class instance back to a new file and adding it to the archive as a new entry. When I do that, however, I get the following exception

Unhandled exception. System.IO.IOException: An attempt was made to move the position before the beginning of the stream.
   at System.IO.MemoryStream.Seek(Int64 offset, SeekOrigin loc)
   at Xamarin.Tools.Zip.ZipArchive.stream_callback(IntPtr state, IntPtr data, UInt64 len, SourceCommand cmd)

I have spent a good few hours getting a debug environment working and tracing through the native libzip library code. It does indeed try to seek to an apparently nonsensical position within the stream when trying to read extra fields for the archive entries at one point (we're talking position shifts by tens of thousands of bytes in an archive that is just barely over a kilobyte in compressed size). I don't have the details on the problematic spot in libzip with me at the moment, but I should be able to provide them easily if need be.

In addition to that, I have discovered that the order in which I add files to the archive does matter to LibZipSharp/libzip. To demonstrate that, I have put together a simple project. See this GitHub repository for the source code and test files. The info.json file is the one getting read and subsequently replaced in the archive.

During my experiments, I tried different orders of files on the command line to see the impact of those changes. I use the standard zip command in Linux. I have tried these permutations of files on the command line.

zip -9 object.zip characters_players.json info.json object_spawn.json,
zip -9 object.zip object_spawn.json info.json characters_players.json,
zip -9 object.zip info.json object_spawn.json characters_players.json, and
zip -9 object.zip object_spawn.json characters_players.json info.json
produce an archive file that the test application is able to successfully process and run to completion.

However, commands
zip -9 object.zip info.json characters_players.json object_spawn.json and
zip -9 object.zip characters_players.json object_spawn.json info.json
produce an archive file that the app fails to process and fails with the traceback listed above.

To complicate this even more, I found that when I try to iterate through the entries of the archive and then do the read/update/replace operation, most of the archive variations created by the commands above run to completion except

zip -9 object.zip info.json object_spawn.json characters_players.json and
zip -9 object.zip object_spawn.json characters_players.json info.json.

Lines 38-39 are commented out and uncommenting them will print the contents of the archive to stdout together with position information of the archive stream.

That's really all I can think of at the moment. I hope this helps. Let me know if you need anything else. 🙂

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions