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 */ #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,25 +570,82 @@ 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)
{ {
item->name = new char[namelen+1]; item->name = new char[namelen+1];
@ -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
{ {
@ -611,17 +713,12 @@ PRInt32 nsZipArchive::BuildFileList()
delete item; delete item;
} }
} }
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;
@ -178,7 +179,7 @@ private:
nsZipArchive(const nsZipArchive& rhs); // prevent copies nsZipArchive(const nsZipArchive& rhs); // prevent copies
PRInt32 BuildFileList(); PRInt32 BuildFileList();
nsZipItem* GetFileItem( const char * aFilename ); nsZipItem* GetFileItem( const char * aFilename );
PRUint32 HashName( const char* aName ); PRUint32 HashName( const char* aName );
PRInt32 ReadInitImpl(const char* aFilename, nsZipItem** aItem); PRInt32 ReadInitImpl(const char* aFilename, nsZipItem** aItem);

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

@ -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 */