Repository navigation
Suggest using ZipArchiveMode.Create when compressing files without modifying their ZipArchivEntry objects #35815
Description
Consider the following code:
using System.IO;
using System.IO.Compression;
namespace ConsoleApp
{
class Program
{
static void Main()
{
DirectoryInfo directory = new DirectoryInfo(@"C:\path\to\directory\with\huge\files\to\compress");
using (FileStream stream = new FileStream(@"C:\path\to\new\Compressed.zip", FileMode.CreateNew))
{
using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Update /* this is the problem */, leaveOpen: false))
{
foreach (FileInfo file in directory.EnumerateFiles("*", SearchOption.AllDirectories))
{
archive.CreateEntryFromFile(
sourceFileName: file.FullName,
entryName: file.Name,
CompressionLevel.Optimal); // throws
}
}
}
}
}
}The exception would be:
Backup failed with exception System.IO.IOException: Stream was too long.
at System.IO.MemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count)
at System.IO.Stream.InternalCopyTo(Stream destination, Int32 bufferSize)
at System.IO.Compression.ZipFileExtensions.DoCreateEntryFromFile(ZipArchive destination, String sourceFileName, String entryName, Nullable`1 compressionLevel)
CreateEntryFromFile has this exception documented here.
The exception is thrown because we restrict the size of a file to Int32.MaxValue. The restriction is reached because the code is opening the ZipArchive with ZipArchiveMode.Update. That mode requires a stream that allows seeking, so we internally create a MemoryStream so that we can update the archive, but the size limit for the file is Int32.MaxValue.
The ZipArchiveMode remarks state that ZipArchiveMode.Update allows both reading and writing, but in this code, writing is not needed.
The Roslyn analyzer would only create a diagnostic if we can detect that the code:
- Is creating a new
ZipArchivewithFileMode.CreateorFileMode.CreateNew, and- Is either calling
CreateEntryFromFile, which takes the file name and creates theZipArchiveEntryinternally (and it does not get updated), or - Is creating
ZipArchiveEntryinstances but does not manipulate them before adding them to theZipArchive.
- Is either calling
The Roslyn fixer would suggest changing ZipArchiveMode.Update to ZipArchiveMode.Create.
Is this a good candidate for a Roslyn analyzer/fixer?
Activity
bartonjs commentedon May 5, 2020
Do you believe that in the majority of scenarios that would hit this have all of the code in one method? In projects where I've previously worked with building zip files, opening the zipfile context and adding things / reading things were in different methods; which means the analyzer wouldn't be able to detect it.
It seems like perhaps what's missing is just some accelerator API, like
static ZipArchive.Create(string filename, bool overwrite=???),static ZipArchive.Update(string filename)buyaa-n commentedon Oct 23, 2020
Sounds like the hardest part would be determining if
it does not get updatedmight need more clarification/rule on how to determine that.For me, its better only account for operations in one method, if it is passed to a different method most likely its being processed more i.e has a high possibility of getting updated.
Can be helpful, but not sure how much that could prevent from using the existing old APIs that are causing the issue
dotnet-policy-service commentedon Apr 24, 2025
Due to lack of recent activity, this issue has been marked as a candidate for backlog cleanup. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will undo this process.
This process is part of our issue cleanup automation.
dotnet-policy-service commentedon May 9, 2025
This issue will now be closed since it had been marked
no-recent-activitybut received no further activity in the past 14 days. It is still possible to reopen or comment on the issue, but please note that the issue will be locked if it remains inactive for another 30 days.