quazip icon indicating copy to clipboard operation
quazip copied to clipboard

quazip fails to unzip zip64 archive with extra leading data (e.g. self-extractor)

Open chazste opened this issue 7 years ago • 8 comments
trafficstars

quazip will correctly unzip a normal (32-bit) zip archive even if the self-extractor is pre-pended. However if the archive is large are requires ZIP64 extensions then the extraction will fail. The search for ZIP64 end of central directory fails if the correct signature is not found pointed to by the ECL record, for non-ZIP64 archives the analogous routine will actually search backward for the central directory.

The Info-Zip version of unzip will make a guess that the ZIP64 End of Central directory is exactly 56 bytes before the locator record if the lookup using the explicit offset fails. I have implemented a similar solution for libquazip for use in my application. It seems to work well for me. I will issue a pull request for this change if you wish.

The issue is that unz64local_SearchCentralDir64 does not have any other options on line 574 if the signature check fails.

chazste avatar Nov 20 '18 20:11 chazste

PRs are always welcome, provided they maintain backwards API and ABI compatibility. Since the routine you mention is purely an implementation detail, it should be fine.

stachenov avatar Nov 21 '18 04:11 stachenov

Hi, Did you manage to resolve this please?

perseedossrajiv avatar Apr 28 '21 10:04 perseedossrajiv

There was no PR, as of the moment.

stachenov avatar Apr 28 '21 10:04 stachenov

Ok. Could you please provide some more information on what you fixed locally?

Is your issue also similar to this? https://github.com/stachenov/quazip/issues/117

Thanks

perseedossrajiv avatar Apr 28 '21 11:04 perseedossrajiv

This appears to be similar to #117. At least this failure would return error -103. I ended up not actually needing to fix this issue and since the unit tests seemed like they would take a long time to run since they needed to create several 4GB archives I decided not to pursue submitting a PR.

Here is my local change

diff --git a/../../quazip-0.7.2/quazip/unzip.c b/unzip.c
old mode 100644
new mode 100755
index bca03f8..57f6468
--- a/../../quazip-0.7.2/quazip/unzip.c
+++ b/unzip.c
@@ -487,12 +487,11 @@ local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib
     ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
     ZPOS64_T uPosFound=0;
     uLong uL;
-                ZPOS64_T relativeOffset;
+    ZPOS64_T relativeOffset;
 
     if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
         return 0;
 
-
     uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
 
     if (uMaxBack>uSizeFile)
@@ -570,7 +569,22 @@ local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib
         return 0;
 
     if (uL != 0x06064b50)
-        return 0;
+	{
+		// Not where expected so just look back a fixed size (assumed size of ECDIR64)
+		relativeOffset = (uPosFound - 56);
+
+		/* Try again - Goto end of central directory record 64 */
+		if (ZSEEK64(*pzlib_filefunc_def, filestream, relativeOffset, ZLIB_FILEFUNC_SEEK_SET) != 0)
+			return 0;
+
+		/* the signature */
+		if (unz64local_getLong(pzlib_filefunc_def, filestream, &uL) != UNZ_OK)
+			return 0;
+
+		/* check again */
+		if (uL != 0x06064b50)
+			return 0;
+	}
 
     return relativeOffset;
 }
@@ -625,7 +639,7 @@ extern unzFile unzOpenInternal (voidpf file,
         return NULL;
 
     central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream);
-    if (central_pos)
+	if (central_pos)
     {
         uLong uS;
         ZPOS64_T uL64;
@@ -913,7 +927,6 @@ local int unz64local_GetCurrentFileInfoInternal (unzFile file,
               ZLIB_FILEFUNC_SEEK_SET)!=0)
         err=UNZ_ERRNO;
 
-
     /* we check the magic */
     if (err==UNZ_OK)
     {
@@ -922,50 +935,35 @@ local int unz64local_GetCurrentFileInfoInternal (unzFile file,
         else if (uMagic!=0x02014b50)
             err=UNZ_BADZIPFILE;
     }
-
     if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK)
         err=UNZ_ERRNO;
-
     if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK)
         err=UNZ_ERRNO;
-
     if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK)
         err=UNZ_ERRNO;
-
     if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK)
         err=UNZ_ERRNO;
-
     if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK)
         err=UNZ_ERRNO;
-
     unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
-
     if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK)
         err=UNZ_ERRNO;
-
     if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
         err=UNZ_ERRNO;
     file_info.compressed_size = uL;
-
     if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
         err=UNZ_ERRNO;
     file_info.uncompressed_size = uL;
-
     if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK)
         err=UNZ_ERRNO;
-
     if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK)
         err=UNZ_ERRNO;
-
     if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK)
         err=UNZ_ERRNO;
-
     if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK)
         err=UNZ_ERRNO;
-
     if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK)
         err=UNZ_ERRNO;
-
     if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK)
         err=UNZ_ERRNO;
 
@@ -1000,7 +998,6 @@ local int unz64local_GetCurrentFileInfoInternal (unzFile file,
             uSizeRead = file_info.size_file_extra;
         else
             uSizeRead = extraFieldBufferSize;
-
         if (llSeek!=0)
         {
             if (ZSEEK64(s->z_filefunc, s->filestream,llSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)

chazste avatar Apr 28 '21 19:04 chazste

Quazip4gbError

Hello, I tried the above patch but i still get the same error sadly.

I do not know what else to do here. @stachenov any idea please?

Thanks

perseedossrajiv avatar Apr 29 '21 10:04 perseedossrajiv

No ideas at the moment, and I'm a bit busy currently to look into it deeper. I don't expect to have enough free time for this until at least August. Sad, but true...

stachenov avatar Apr 29 '21 18:04 stachenov

ok - thanks for helping anyways.

perseedossrajiv avatar Apr 30 '21 16:04 perseedossrajiv