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:
sgehani%netscape.com 1999-11-02 20:37:28 +00:00
Родитель f63e2ea775
Коммит abca066b9b
3 изменённых файлов: 171 добавлений и 57 удалений

Просмотреть файл

@ -58,6 +58,11 @@
#endif /* STANDALONE */
#if defined(XP_UNIX)
#include <sys/stat.h>
#else if defined(XP_PC)
#include <io.h>
#endif
#include "zipfile.h"
#include "zipstruct.h"
@ -66,6 +71,7 @@
static PRUint16 xtoint(unsigned char *ii);
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 )
{
case STORED:
return CopyItemToDisk( item, aOutname );
status = CopyItemToDisk( item, aOutname );
break;
case DEFLATED:
return InflateItem( item, aOutname, 0 );
status = InflateItem( item, aOutname, 0 );
break;
default:
//-- unsupported compression type
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;
PRUint32 sig = 0L;
PRUint32 namelen, extralen;
PRUint32 namelen, extralen, commentlen;
PRUint32 hash;
PRUint32 size;
ZipLocal Local;
ZipLocal Local;
ZipCentral Central;
nsZipItem* item;
//-----------------------------------------------------------------------
// read the local file headers.
//
// 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.
// skip to the central directory
//-----------------------------------------------------------------------
PRInt32 pos = 0L;
while ( status == ZIP_OK )
@ -554,25 +570,82 @@ PRInt32 nsZipArchive::BuildFileList()
break;
}
//-- make sure we're processing a local header
//-- check if we hit the central directory
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;
}
else if ( sig != LOCALSIG )
else
{
//-- otherwise expected to find a local header
status = ZIP_ERR_CORRUPT;
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();
if ( item != 0 )
if (item != 0)
{
item->name = new char[namelen+1];
@ -583,19 +656,48 @@ PRInt32 nsZipArchive::BuildFileList()
item->name[namelen] = 0;
item->namelen = namelen;
item->headerloc = pos;
item->offset = pos + sizeof(ZipLocal) + namelen + extralen;
item->compression = xtoint( Local.method );
item->size = xtolong( Local.size );
item->realsize = xtolong( Local.orglen );
item->crc32 = xtolong( Local.crc32 );
item->headerloc = xtolong( Central.localhdr_offset );
//-- seek to local header
#ifndef STANDALONE
if ( PR_Seek( mFd, item->headerloc, PR_SEEK_SET ) != (PRInt32)item->headerloc )
#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
hash = HashName( item->name );
item->next = mFiles[hash];
mFiles[hash] = item;
pos = item->offset + item->size;
//-- set pos to next expected central dir header
pos += sizeof(ZipCentral) + namelen + extralen + commentlen;
}
else
{
@ -611,17 +713,12 @@ PRInt32 nsZipArchive::BuildFileList()
delete item;
}
}
else
else
{
//-- couldn't create a nsZipItem
//-- couldn't create an nsZipItem
status = ZIP_ERR_MEMORY;
}
} /* while reading local headers */
//-------------------------------------------------------
// we don't care about the rest of the file (until we
// fix this to read the central directory instead)
//-------------------------------------------------------
} /* while reading central directory records */
return status;
}
@ -1108,4 +1205,20 @@ static PRUint32 xtolong (unsigned char *ll)
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 realsize;
PRUint32 crc32;
PRUint16 mode;
nsZipItem* next;
@ -178,7 +179,7 @@ private:
nsZipArchive(const nsZipArchive& rhs); // prevent copies
PRInt32 BuildFileList();
nsZipItem* GetFileItem( const char * aFilename );
nsZipItem* GetFileItem( const char * aFilename );
PRUint32 HashName( const char* aName );
PRInt32 ReadInitImpl(const char* aFilename, nsZipItem** aItem);

Просмотреть файл

@ -49,35 +49,35 @@ typedef struct ZipLocal_
typedef struct ZipCentral_
{
char signature [4];
char version_made_by [2];
char version [2];
char bitflag [2];
char method [2];
char time [2];
char date [2];
char crc32 [4];
char size [4];
char orglen [4];
char filename_len [2];
char extrafield_len [2];
char commentfield_len [2];
char diskstart_number [2];
char internal_attributes [2];
char external_attributes [4];
char localhdr_offset [4];
unsigned char signature [4];
unsigned char version_made_by [2];
unsigned char version [2];
unsigned char bitflag [2];
unsigned char method [2];
unsigned char time [2];
unsigned char date [2];
unsigned char crc32 [4];
unsigned char size [4];
unsigned char orglen [4];
unsigned char filename_len [2];
unsigned char extrafield_len [2];
unsigned char commentfield_len [2];
unsigned char diskstart_number [2];
unsigned char internal_attributes [2];
unsigned char external_attributes [4];
unsigned char localhdr_offset [4];
} ZipCentral;
typedef struct ZipEnd_
{
char signature [4];
char disk_nr [2];
char start_central_dir [2];
char total_entries_disk [2];
char total_entries_archive [2];
char central_dir_size [4];
char offset_central_dir [4];
char commentfield_len [2];
unsigned char signature [4];
unsigned char disk_nr [2];
unsigned char start_central_dir [2];
unsigned char total_entries_disk [2];
unsigned char total_entries_archive [2];
unsigned char central_dir_size [4];
unsigned char offset_central_dir [4];
unsigned char commentfield_len [2];
} ZipEnd;
/* signatures */