Possible bug in ZipArchive with archive mode update? - c#

I ran into a problem with ZipArchiveMode.Update if the zip file contains "directory entries".
I know there is no such thing as directory entry but some tools produce entries with ZipArchiveEntry.Length = 0 and ZipArchiveEntry.Name = "" for directories in the zip file.
The following code now corrupts the zip file:
using (ZipArchive archive = ZipFile.Open(#"D:\TEMP\test.zip", ZipArchiveMode.Update))
{
}
As you can see I do nothing at all except for opening the zip file with ZipArchiveMode.Update and dispose it in the end.
The problem is that the "directory entries" seem to be treated as file entries. So in the output there are new zero byte entries with the directory names.
I still can open the zip file and even extract files per drag&drop. But attempts to extract the zip file result in error messages. Maybe because there are two entries with the same fullname?
My workaround was to avoid ZipArchiveMode.Update and use a temporary MemoryStream. Then iterate over all entries, ignore "directory entries" and only copy the file entries to the stream. This way it worked.
Is this a bug in ZipArchive or are entries for directories just wrong? What if I want to store empty directories in the zip? And as I said: Many tools out there seem to produce such directory entries.

I got the same issue when trying to update a zip file with directory entries, after updating the file the zip file exist (with the new added file) but its corrupted.
What worked for me eventually was adding Nuget reference to DotNetZip and add the file using Ionic.Zip:
using (Ionic.Zip.ZipFile zip = Ionic.Zip.ZipFile.Read(parameters.ObjzfPath))
{
zip.AddEntry("newFileEntry", "newFileContent"); // you can use zip.AddFile("newFile.txt") as well
zip.Save();
}

Related

Why is WebDriverManager throwing an error? [duplicate]

I am downloading a zip file using c# program and I get the error
at System.IO.Compression.ZipArchive.ReadEndOfCentralDirectory()
at System.IO.Compression.ZipArchive.Init(Stream stream, ZipArchiveMode mode,
Boolean leaveOpen)
at System.IO.Compression.ZipArchive..ctor(Stream stream, ZipArchiveMode mode,
Boolean leaveOpen, Encoding entryNameEncoding)
at System.IO.Compression.ZipFile.Open(String archiveFileName, ZipArchiveMode
mode, Encoding entryNameEncoding)
at System.IO.Compression.ZipFile.ExtractToDirectory(String sourceArchiveFileN
ame, String destinationDirectoryName, Encoding entryNameEncoding)
at System.IO.Compression.ZipFile.ExtractToDirectory(String sourceArchiveFileN
ame, String destinationDirectoryName)
Here's the program
response = (HttpWebResponse)request.GetResponse();
Stream ReceiveStream = response.GetResponseStream();
byte[] buffer = new byte[1024];
FileStream outFile = new FileStream(zipFilePath, FileMode.Create);
int bytesRead;
while ((bytesRead = ReceiveStream.Read(buffer, 0, buffer.Length)) != 0)
outFile.Write(buffer, 0, bytesRead);
outFile.Close();
response.Close();
try
{
ZipFile.ExtractToDirectory(zipFilePath, destnDirectoryName);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
Console.ReadLine();
}
I do not understand the error. Can anybody explain this
Thanks
MR
The problem is ZipFile can't find the line of code that signals the end of the archive, so either:
It is not a .zip archive.
It may be a .rar or other compressed type. Or as I suspect here, you are downloading an html file that auto-redirects to the zip file.
Solution - Gotta find a correct archive to use this code.
The archive is corrupt.
Solution - The archive will need repairing.
There is more than 1 part to the archive.
A multi part zip file.
Solution - Read in all the files before decompression.
As #ElliotSchmelliot notes in comments, the file may be hidden or have extended characters in the name.
Solution - Check your file attributes/permissions and verify the file name.
Opening the file with your favorite zip/unzip utility (7-zip, winzip, etc) will tell which of these it could be.
From your old question you deleted.
I get System.IO.InvalidDataException: End of Central Directory record could not be found.
This most likely means whatever file you are passing in is malformed and the Zip is failing. Since you already have the file outfile on the hard drive I would recommend trying to open that file with with windows built in zip extractor and see if it works. If it fails the problem is not with your unzipping code but with the data the server is sending to you.
I have the same problem, but in my case the problem is with the compression part and not with the decompression.
During the compression I need use the "Using" statament with the Stream and the ZipArchive objects too. The "Using" statament will Close the archive properly and I can decompress it without any problem.
The working code in my case in VB.Net:
Using zipSteramToCreate As New MemoryStream()
Using archive As New ZipArchive(zipSteramToCreate, ZipArchiveMode.Create)
' Add entry...
End Using
' Return the zip byte array for example:
Return zipSteramToCreate.ToArray
End Using
I encountered this same problem. There are many types of compression, .zip being only one of the types. Look and make sure that you aren't trying to 'unzip' a .rar or similar file.
In my case i absolutely KNEW that my zip was not corrupted, and I was able to figure out through trial and error that I was extracting the files to a directory with the filename and extension in the FOLDER Name.
So Unzipping /tmp/data.zip to:
/tmp/staging/data.zip/files_go_here
failed with the error [End of Central Directory record could not be found]
but extracting data.zip to this worked just fine:
/tmp/staging/data/files_go_here
While it might seem unusual to some folks to name a folder a filename with extension, I can't think of a single reason why you should not be able to do this, and more importantly -- the error returned is not obviously related to the cause.
I was getting the same error with both the System.IO.Compression library and 3rd party packages such as SharpZipLib -- which is what eventually clued me in that it was a more general issue.
I hope this helps someone and saves them some time/frustration.
I used SharpCompress C#.net Library available via Nuget Package manager, it solved my purpose of unzipping.
I just came across this thread when I had the same error from a PowerShell script calling the Net.WebClient DownloadFile method.
In my case, the problem was that the web server was unable to provide the requested zip file, and instead provided an HTML page with an error message in it, which obviously could not be unzipped.
So instead, I created an exception handler to extract and present the "real" error message.
Might be useful to someone else. I dealt with this by adding an exception to my code, which then:
Creates a temporary directory
Extracts the zip archive (normally works)
Renames the original ziparchive to *.bak
Zips and replaces the original archive file with one that works
For me, the problem had to do with git settings.
To solve it, I added:
*.zip binary
to my .gitattributes file.
Then I downloaded an uncorrupted version of the file (without using git) and added a new commit updating the .zip file to the uncorrupted version and also updating the .gitattributes file.
I wish I could avoid adding that extra commit to update the .zip file, but the only way I can think of avoiding that would be to insert a commit updating the .gitattributes file into or before the commit that added the .zip file (using a rebase) and using git push -f to update the remote repo, but I can't do that.
I also had this error because I was trying to open a .json file as a .zip archive:
using(ZipArchive archive = ZipFile.Open(fileToSend.FilePath, ZipArchiveMode.Read))
{
ZipArchiveEntry entry = archive.GetEntry(fileToSend.FileName);
using (StreamReader reader = new StreamReader(entry.Open(), Encoding.UTF8))
{
fileContent = reader.ReadToEnd();
}
}
I was expecting that fileToSend.FilePath = "C:\MyProject\mydata.zip"
but it was actually fileToSend.FilePath = "C:\MyProject\mydata.json" and that was causing the error.
Write down the stream to a file then inspect it with a (hex) editor.
I got the same message in Visual Studio when downloading nupkg from nuget.org. It was because nuget.org was blacklisted by the firewall. So instead of the pkg I got a html error page which (of course) cannot be unzipped.
In my case: I was mistakenly saving an input stream to *.zip.
While Archive Utility had no issues opening the file, all the rest failed (unzip cmd or java libs) with the same "end of central" error.
The plot-twist was: the file I'm downloading is in gzip format, i.e. *.gz, and not zip.
Make sure it is a zip file you trying to decompress.
The web-service I querying zips results when there are two files, but in this instance it was just returning one. My code was saving the embedded base64 as a stream and therefore my code was assigning the zip extension.
Whereas it was already actually just a plain PDF...
In my case, I was receiving this error in a combination with FileSystemWatcher, which triggered a processing method upon the zip archive before the archive was fully copied/created in its target folder.
I solved it with a check of whether the zip archive was truly eligible for reading in a try/catch block within a while loop.
My solution compress with powershell
Compress-Archive * -DestinationPath a.zip
I found resolution.
Move "Tools->Nuget PackageManager ->Package Manager Settings" and in "Nuget Package Manager" -General Tab , click Clear All Nuget Caches button and OK. You can install package from online

Add Files to Tar Archive Without Copying Parent File Structure

I'm creating a game in which a user can create custom content. There are two files associated with each custom creation: an .ogg file and a .xml file. Previously, I had a folder that contained all of the associated files, but I'd like to wrap all the associated files within a .tar file instead.
Using the following code, I can create a .tar archive (with the custom extension ".krs"):
FileInfo[] filesInDirectory = folder.GetFiles();
string tarArchiveName = #"C:\Users\me\Desktop\UserData\songs\songName.krs";
using (Stream targetStream = new GZipOutputStream(File.Create(tarArchiveName)))
using (TarArchive tarArchive = TarArchive.CreateOutputTarArchive(targetStream, TarBuffer.DefaultBlockFactor))
{
foreach (FileInfo file in filesInDirectory)
{
TarEntry entry = TarEntry.CreateEntryFromFile(file.FullName);
tarArchive.WriteEntry(entry, false);
}
}
This doesn't give any errors, but when I open the .krs file as a .tar using 7zip, the the files are buried underneath ALL the parent directories of the original files that were copied to the archive. For example, the path of the "data.xml" file within the .tar file is "C:\Users\me\Desktop\UserData\songs\songName\data.xml".
I want to open the .tar file and there no top-level directory - just the two files. For example the data.xml file within the .tar archive should be simply "data.xml".
I know this is achieveable because I can do it manually using 7zip. How can I do this using the SharpZipLib library in C#? I found this answer that seems to address my problem, but it's written in Python, a language I have no understanding of.
EDIT: I did some more searching and found this answer. I tried the solution, and it took away everything except the first parent directory of the files (".tar : parentFolder\data.xml"). Is it possible to remove that as well to avoid having to do any digging when I extract these files later?
When testing the answer I posted in my edit, I found that when extracting the files, they come out by themselves and do not come in a folder. This is the answer I was looking for.

System.IO.Compression End of Central Directory record could not be found

On executing the following code.. I get an exception on the OpenRead statement:
End of Central Directory record could not be found.
I am however able to open the zip file with no issues through windows explorer.
Any thoughts?
string zipPath = #"c:\testfiles\MMM_C13000_2016M08.zip";
using (ZipArchive archive = ZipFile.OpenRead(zipPath))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
}
}
It is possible to process a zip file in two different ways. You can simply read sequentially from the beginning, processing local headers and compressed data as you go. Or you can use the central directory at the end of the zip file to find the entries and process them by seeking in the file.
It appears that the zip file is damaged or has junk at the end that is preventing one method from working, but not the other.

Update zip file based on other zip file C#

So i have a zip file in a directory. This zip file contains different kind of files. When a user clicks on a button in my WPF application, the zip file needs to be updated.
It needs to check files from another zip file in another directory. If a file doesnt excist in the first zip file, it needs to copy that file from the other zip file to the new zip file.
i used the Ionic zip methode for this.
So far i just used the file.copy overwrite = true code.
But when the zip file is 1gb+ it is taking very long because it just replaced the zip file.
does someone know how i can resolve this?
Greetings Thomas
UPDATE:
this is the code i got so far:
private void getlocaldata()
{
string admindata = #"\\networklocation\test.zip";
string localPath = #"C:\finaldata\test.zip";
File.Copy(admindata, localPath, true);
}
You can use the DotNetZip library.
Check the file in the zip :
zip["Readme.txt"] = null;
But anyway you must compress files again for changing zips password. You can find examples for that here.

ASP.net MVC - IO.Compression library not recreating the folder structure in a ZIP file

I have a business scenario where I should allow downloading of the encrypted folders as a ZIP file; meaning that the files within the folder and its subfolders are encrypted. As I perform server side decryption of the files it is necessary first to recreate the same folder structure in a temporary folder as well as to decrypt the files itself and save them into the corresponding folders of the temporary folder.
This part works well; the folder structure in a temporary file gets recreated as it should but the problem comes when I'm trying to create a ZIP file of a temporary folder using System.IO.Compression library.
When you open the ZIP file only the first folder of the structure is created as a folder and the rest of the folders are just being created as extensionless files.
Folder structure as the unzipping application sees it
Code snippet:
//Creating temporary folder where the decrypted files will be extracted
var tempFolderPath = _directory.CreateTemporaryFolder(rootFolderPath);
var serverTempFolderPath = HttpContext.Current.Server.MapPath(tempFolderPath);
//Creating the folder structure
RecursiveFolderCreate(folders, tempFolderPath);
//Decrypting the files and recreating them in the corresponding folders
foreach (var file in files)
{
PrepareFile(file, folderPath, tempFolderPath);
}
//Creating the zip file
string zipFileName = string.Concat(folder.Name, ".zip");
string zipFilePath = System.IO.Path.Combine(rootFolderPath, zipFileName);
string serverZipFilePath = HttpContext.Current.Server.MapPath(zipFilePath);
ZipFile.CreateFromDirectory(serverTempFolderPath, serverZipFilePath, CompressionLevel.Optimal, false);
byte[] zipFile = System.IO.File.ReadAllBytes(serverZipFilePath);
Sorry this isn't a comment, but I don't have enough reputation to comment yet.
Is it possible that an exception is being raised and not handled?
Per the documentation (https://msdn.microsoft.com/en-us/library/hh485721(v=vs.110).aspx/), what you are doing should work. But it has the extra caveat as listed below:
If a file in the directory cannot be added to the archive, the archive is left incomplete and invalid, and the method throws an IOException exception.

Categories