Search code examples
c#streamzipdotnetzip

Corrupt ZIP file if calling Save twice


I am using DotNetZip 1.9.6 in my application which uses a file structure similar to e.g. *.docx: Zip file containing XML files.
Now every module of the application can store such XML files to my custom file management and on "save" they are serialized to streams which are then saved to the Zip file via DotNetZip.
To update the entries I use ZipFile.UpdateEntry(path, stream). This works fine and the first time I save my file via calling ZipFile.Save() everything works.

But If I do this a second time (first some UpdateEntrycalls then Save) on the same instance the Zip file is corrupted: The file structure and meta-data (e.g. uncompressed size of each file) is still there, but all files are 0 byte in compressed size.

If I create a new instance from the just saved file after saving everything works fine, but shouldn't it be possible to avoid that and "reuse" the same instance?

The following example (also see https://dotnetfiddle.net/mHxEIy) can be used to reproduce the problem:

using System.IO;
using System.Text;

public class Program
{
    public static void Main()
    {
        var zipFile = new Ionic.Zip.ZipFile();

        var content1 = new MemoryStream(Encoding.Default.GetBytes("Content 1"));
        zipFile.UpdateEntry("test.txt", content1);

        zipFile.Save("test.zip"); // here the Zip file is correct
        //zipFile = new Ionic.Zip.ZipFile("test.zip"); // uncomment and it works too

        var content2 = new MemoryStream(Encoding.Default.GetBytes("Content 2"));
        zipFile.UpdateEntry("test.txt", content2);

        zipFile.Save();  // after that it is corrupt
    }
}

To run this you need to add the "DotNetZip 1.9.6" NuGet package.

After the first save, this is what you get:
Correct
and after the second save:
Corrupt


Solution

  • As already suspected this was a bug in DotNetZip up to version 1.9.6.
    I think I was able to fix this with THIS change which was just released as version 1.9.7 on NuGet. At least for me the problem does not happen anymore.

    Some background what happend as far as I found out:
    When you call Save the library sets an internal flag which remembers that the ZIP file was just save and on the second Save call instead of "recompressing" all entries in the ZIP file it copies them from the just saved file.
    This works fine for adding/removing entries, but breaks when one of the entries was changed as then it "mixes" the old and the new entry and produces the inconsisten ZIP file.
    My fix basically disables that "copy from old file" logic if an entry was changed.