зеркало из https://github.com/mozilla/pjs.git
Fixed bugs 10540, 9148. Libjar now reads teh central directory headers as opposed to the local file headers. This enables us to glean permissions informationand restore file mode upon extraction. A side-effect is the bug 10540 fix where the Install.Execute() API now works on Linux since we restore the execute bits in temporarily extracted files. [r=ssu]
This commit is contained in:
Родитель
f63e2ea775
Коммит
abca066b9b
|
@ -58,6 +58,11 @@
|
||||||
|
|
||||||
#endif /* STANDALONE */
|
#endif /* STANDALONE */
|
||||||
|
|
||||||
|
#if defined(XP_UNIX)
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#else if defined(XP_PC)
|
||||||
|
#include <io.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "zipfile.h"
|
#include "zipfile.h"
|
||||||
#include "zipstruct.h"
|
#include "zipstruct.h"
|
||||||
|
@ -66,6 +71,7 @@
|
||||||
|
|
||||||
static PRUint16 xtoint(unsigned char *ii);
|
static PRUint16 xtoint(unsigned char *ii);
|
||||||
static PRUint32 xtolong(unsigned char *ll);
|
static PRUint32 xtolong(unsigned char *ll);
|
||||||
|
static PRUint16 ExtractMode(PRUint32 ext_attr);
|
||||||
|
|
||||||
|
|
||||||
/*---------------------------------------------
|
/*---------------------------------------------
|
||||||
|
@ -384,15 +390,27 @@ PRInt32 nsZipArchive::ExtractFile(const char* aFilename, const char* aOutname)
|
||||||
switch( item->compression )
|
switch( item->compression )
|
||||||
{
|
{
|
||||||
case STORED:
|
case STORED:
|
||||||
return CopyItemToDisk( item, aOutname );
|
status = CopyItemToDisk( item, aOutname );
|
||||||
|
break;
|
||||||
|
|
||||||
case DEFLATED:
|
case DEFLATED:
|
||||||
return InflateItem( item, aOutname, 0 );
|
status = InflateItem( item, aOutname, 0 );
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
//-- unsupported compression type
|
//-- unsupported compression type
|
||||||
return ZIP_ERR_UNSUPPORTED;
|
return ZIP_ERR_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(XP_UNIX) || defined(XP_PC)
|
||||||
|
if (status == ZIP_OK)
|
||||||
|
{
|
||||||
|
//-- set extracted file permissions
|
||||||
|
chmod(aOutname, item->mode);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -517,19 +535,17 @@ PRInt32 nsZipArchive::BuildFileList()
|
||||||
{
|
{
|
||||||
PRInt32 status = ZIP_OK;
|
PRInt32 status = ZIP_OK;
|
||||||
PRUint32 sig = 0L;
|
PRUint32 sig = 0L;
|
||||||
PRUint32 namelen, extralen;
|
PRUint32 namelen, extralen, commentlen;
|
||||||
PRUint32 hash;
|
PRUint32 hash;
|
||||||
|
PRUint32 size;
|
||||||
|
|
||||||
ZipLocal Local;
|
ZipLocal Local;
|
||||||
|
ZipCentral Central;
|
||||||
|
|
||||||
nsZipItem* item;
|
nsZipItem* item;
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
// read the local file headers.
|
// skip to the central directory
|
||||||
//
|
|
||||||
// What we *should* be doing is reading the central directory at the end,
|
|
||||||
// all in one place. We'll have to change this eventually since the local
|
|
||||||
// headers don't have the mode information we need for Unix files.
|
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
PRInt32 pos = 0L;
|
PRInt32 pos = 0L;
|
||||||
while ( status == ZIP_OK )
|
while ( status == ZIP_OK )
|
||||||
|
@ -554,22 +570,79 @@ PRInt32 nsZipArchive::BuildFileList()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-- make sure we're processing a local header
|
//-- check if we hit the central directory
|
||||||
sig = xtolong( Local.signature );
|
sig = xtolong( Local.signature );
|
||||||
if ( sig == CENTRALSIG )
|
if ( sig == LOCALSIG )
|
||||||
{
|
{
|
||||||
// we're onto the next section
|
//-- check length of this file and its metadata so we can skip over it
|
||||||
|
namelen = xtoint( Local.filename_len );
|
||||||
|
extralen = xtoint( Local.extrafield_len );
|
||||||
|
size = xtolong( Local.size );
|
||||||
|
|
||||||
|
//-- reposition file mark to next expected local header
|
||||||
|
pos += sizeof(ZipLocal) + namelen + extralen + size;
|
||||||
|
}
|
||||||
|
else if ( sig == CENTRALSIG )
|
||||||
|
{
|
||||||
|
// file mark set to start of central directory
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if ( sig != LOCALSIG )
|
else
|
||||||
{
|
{
|
||||||
//-- otherwise expected to find a local header
|
//-- otherwise expected to find a local header
|
||||||
status = ZIP_ERR_CORRUPT;
|
status = ZIP_ERR_CORRUPT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} /* while reading local headers */
|
||||||
|
|
||||||
namelen = xtoint( Local.filename_len );
|
//-------------------------------------------------------
|
||||||
extralen = xtoint( Local.extrafield_len );
|
// read the central directory headers
|
||||||
|
//-------------------------------------------------------
|
||||||
|
while ( status == ZIP_OK )
|
||||||
|
{
|
||||||
|
#ifndef STANDALONE
|
||||||
|
if ( PR_Seek( mFd, pos, PR_SEEK_SET ) != (PRInt32)pos )
|
||||||
|
#else
|
||||||
|
if ( PR_Seek( mFd, pos, PR_SEEK_SET ) != 0 )
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
//-- couldn't seek to next position
|
||||||
|
status = ZIP_ERR_CORRUPT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( PR_Read( mFd, (char*)&Central, sizeof(Central) ) != sizeof(ZipCentral) )
|
||||||
|
{
|
||||||
|
//-- central dir end record is smaller than a central dir header
|
||||||
|
sig = xtolong( Central.signature );
|
||||||
|
if ( sig == ENDSIG )
|
||||||
|
{
|
||||||
|
//-- we've reached the end of the central dir
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = ZIP_ERR_CORRUPT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sig = xtolong( Central.signature );
|
||||||
|
if ( sig == ENDSIG )
|
||||||
|
{
|
||||||
|
//-- we've reached the end of the central dir
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if ( sig != CENTRALSIG )
|
||||||
|
{
|
||||||
|
//-- otherwise expected to find a central dir header
|
||||||
|
status = ZIP_ERR_CORRUPT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
namelen = xtoint( Central.filename_len );
|
||||||
|
extralen = xtoint( Central.extrafield_len );
|
||||||
|
commentlen = xtoint( Central.commentfield_len );
|
||||||
|
|
||||||
item = new nsZipItem();
|
item = new nsZipItem();
|
||||||
if (item != 0)
|
if (item != 0)
|
||||||
|
@ -583,19 +656,48 @@ PRInt32 nsZipArchive::BuildFileList()
|
||||||
item->name[namelen] = 0;
|
item->name[namelen] = 0;
|
||||||
item->namelen = namelen;
|
item->namelen = namelen;
|
||||||
|
|
||||||
item->headerloc = pos;
|
item->headerloc = xtolong( Central.localhdr_offset );
|
||||||
item->offset = pos + sizeof(ZipLocal) + namelen + extralen;
|
|
||||||
item->compression = xtoint( Local.method );
|
//-- seek to local header
|
||||||
item->size = xtolong( Local.size );
|
#ifndef STANDALONE
|
||||||
item->realsize = xtolong( Local.orglen );
|
if ( PR_Seek( mFd, item->headerloc, PR_SEEK_SET ) != (PRInt32)item->headerloc )
|
||||||
item->crc32 = xtolong( Local.crc32 );
|
#else
|
||||||
|
if ( PR_Seek( mFd, item->headerloc, PR_SEEK_SET ) != 0 )
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
//-- couldn't seek to next position
|
||||||
|
status = ZIP_ERR_CORRUPT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-- read local header to extract local extralen
|
||||||
|
//-- NOTE: extralen is different in central header and local header
|
||||||
|
//-- for archives created using the Unix "zip" utility. To set
|
||||||
|
//-- the offset accurately we need the local extralen.
|
||||||
|
if ( PR_Read( mFd, (char*)&Local, sizeof(ZipLocal) ) != (READTYPE)sizeof(ZipLocal) )
|
||||||
|
{
|
||||||
|
//-- expected a complete local header
|
||||||
|
status = ZIP_ERR_CORRUPT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
item->offset = item->headerloc +
|
||||||
|
sizeof(ZipLocal) +
|
||||||
|
namelen +
|
||||||
|
xtoint( Local.extrafield_len );
|
||||||
|
item->compression = xtoint( Central.method );
|
||||||
|
item->size = xtolong( Central.size );
|
||||||
|
item->realsize = xtolong( Central.orglen );
|
||||||
|
item->crc32 = xtolong( Central.crc32 );
|
||||||
|
item->mode = ExtractMode(xtolong( Central.external_attributes ));
|
||||||
|
|
||||||
//-- add item to file table
|
//-- add item to file table
|
||||||
hash = HashName( item->name );
|
hash = HashName( item->name );
|
||||||
item->next = mFiles[hash];
|
item->next = mFiles[hash];
|
||||||
mFiles[hash] = item;
|
mFiles[hash] = item;
|
||||||
|
|
||||||
pos = item->offset + item->size;
|
//-- set pos to next expected central dir header
|
||||||
|
pos += sizeof(ZipCentral) + namelen + extralen + commentlen;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -613,15 +715,10 @@ PRInt32 nsZipArchive::BuildFileList()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//-- couldn't create a nsZipItem
|
//-- couldn't create an nsZipItem
|
||||||
status = ZIP_ERR_MEMORY;
|
status = ZIP_ERR_MEMORY;
|
||||||
}
|
}
|
||||||
} /* while reading local headers */
|
} /* while reading central directory records */
|
||||||
|
|
||||||
//-------------------------------------------------------
|
|
||||||
// we don't care about the rest of the file (until we
|
|
||||||
// fix this to read the central directory instead)
|
|
||||||
//-------------------------------------------------------
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -1108,4 +1205,20 @@ static PRUint32 xtolong (unsigned char *ll)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ExtractMode
|
||||||
|
*
|
||||||
|
* Extracts bits 17-24 from a 32-bit unsigned long
|
||||||
|
* representation of the external attributes field.
|
||||||
|
* Subsequently it tacks on the implicit user-read
|
||||||
|
* bit.
|
||||||
|
*/
|
||||||
|
static PRUint16 ExtractMode(PRUint32 ext_attr)
|
||||||
|
{
|
||||||
|
ext_attr &= 0x00FF0000;
|
||||||
|
ext_attr >>= 16;
|
||||||
|
ext_attr |= 0x00000100;
|
||||||
|
|
||||||
|
return (PRUint16) ext_attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ public:
|
||||||
PRUint32 size;
|
PRUint32 size;
|
||||||
PRUint32 realsize;
|
PRUint32 realsize;
|
||||||
PRUint32 crc32;
|
PRUint32 crc32;
|
||||||
|
PRUint16 mode;
|
||||||
|
|
||||||
nsZipItem* next;
|
nsZipItem* next;
|
||||||
|
|
||||||
|
|
|
@ -49,35 +49,35 @@ typedef struct ZipLocal_
|
||||||
|
|
||||||
typedef struct ZipCentral_
|
typedef struct ZipCentral_
|
||||||
{
|
{
|
||||||
char signature [4];
|
unsigned char signature [4];
|
||||||
char version_made_by [2];
|
unsigned char version_made_by [2];
|
||||||
char version [2];
|
unsigned char version [2];
|
||||||
char bitflag [2];
|
unsigned char bitflag [2];
|
||||||
char method [2];
|
unsigned char method [2];
|
||||||
char time [2];
|
unsigned char time [2];
|
||||||
char date [2];
|
unsigned char date [2];
|
||||||
char crc32 [4];
|
unsigned char crc32 [4];
|
||||||
char size [4];
|
unsigned char size [4];
|
||||||
char orglen [4];
|
unsigned char orglen [4];
|
||||||
char filename_len [2];
|
unsigned char filename_len [2];
|
||||||
char extrafield_len [2];
|
unsigned char extrafield_len [2];
|
||||||
char commentfield_len [2];
|
unsigned char commentfield_len [2];
|
||||||
char diskstart_number [2];
|
unsigned char diskstart_number [2];
|
||||||
char internal_attributes [2];
|
unsigned char internal_attributes [2];
|
||||||
char external_attributes [4];
|
unsigned char external_attributes [4];
|
||||||
char localhdr_offset [4];
|
unsigned char localhdr_offset [4];
|
||||||
} ZipCentral;
|
} ZipCentral;
|
||||||
|
|
||||||
typedef struct ZipEnd_
|
typedef struct ZipEnd_
|
||||||
{
|
{
|
||||||
char signature [4];
|
unsigned char signature [4];
|
||||||
char disk_nr [2];
|
unsigned char disk_nr [2];
|
||||||
char start_central_dir [2];
|
unsigned char start_central_dir [2];
|
||||||
char total_entries_disk [2];
|
unsigned char total_entries_disk [2];
|
||||||
char total_entries_archive [2];
|
unsigned char total_entries_archive [2];
|
||||||
char central_dir_size [4];
|
unsigned char central_dir_size [4];
|
||||||
char offset_central_dir [4];
|
unsigned char offset_central_dir [4];
|
||||||
char commentfield_len [2];
|
unsigned char commentfield_len [2];
|
||||||
} ZipEnd;
|
} ZipEnd;
|
||||||
|
|
||||||
/* signatures */
|
/* signatures */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче