diff options
Diffstat (limited to 'security/nss/cmd/signtool/zip.c')
-rw-r--r-- | security/nss/cmd/signtool/zip.c | 678 |
1 files changed, 678 insertions, 0 deletions
diff --git a/security/nss/cmd/signtool/zip.c b/security/nss/cmd/signtool/zip.c new file mode 100644 index 000000000..62e885137 --- /dev/null +++ b/security/nss/cmd/signtool/zip.c @@ -0,0 +1,678 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include "signtool.h" +#include "zip.h" +#include "zlib.h" +#include "prmem.h" + +static void inttox (int in, char *out); +static void longtox (long in, char *out); + +/**************************************************************** + * + * J z i p O p e n + * + * Opens a new ZIP file and creates a new ZIPfile structure to + * control the process of installing files into a zip. + */ +ZIPfile* +JzipOpen(char *filename, char *comment) +{ + ZIPfile *zipfile; + PRExplodedTime prtime; + + zipfile = PORT_ZAlloc(sizeof(ZIPfile)); + if(!zipfile) out_of_memory(); + + /* Construct time and date */ + PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prtime); + zipfile->date = ((prtime.tm_year-1980) << 9) | + ((prtime.tm_month+1) << 5) | + prtime.tm_mday; + zipfile->time = (prtime.tm_hour<<11) | + (prtime.tm_min<<5) | + (prtime.tm_sec&0x3f); + + if (filename && + (zipfile->fp = PR_Open(filename, + PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, 0777)) == NULL) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "%s: can't open output jar, %s.%s\n", PROGRAM_NAME, + filename, nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit (ERRX); + } + + zipfile->list = NULL; + if(filename) { + zipfile->filename = PORT_ZAlloc(strlen(filename)+1); + if(!zipfile->filename) out_of_memory(); + PORT_Strcpy(zipfile->filename, filename); + } + if(comment) { + zipfile->comment = PORT_ZAlloc(strlen(comment)+1); + if(!zipfile->comment) out_of_memory(); + PORT_Strcpy(zipfile->comment, comment); + } + + return zipfile; +} + +static +void* +my_alloc_func(void* opaque, uInt items, uInt size) +{ + return PORT_Alloc(items*size); +} + +static +void +my_free_func(void* opaque, void* address) +{ + PORT_Free(address); +} + +static +void +handle_zerror(int err, char *msg) +{ + if(!msg) { + msg = ""; + } + + errorCount++; /* unless Z_OK...see below */ + + switch(err) { + case Z_OK: + PR_fprintf(errorFD, "No error: %s\n", msg); + errorCount--; /* this was incremented above */ + break; + case Z_MEM_ERROR: + PR_fprintf(errorFD, "Deflation ran out of memory: %s\n", msg); + break; + case Z_STREAM_ERROR: + PR_fprintf(errorFD, "Invalid compression level: %s\n", msg); + break; + case Z_VERSION_ERROR: + PR_fprintf(errorFD, "Incompatible compression library version: %s\n", msg); + break; + case Z_DATA_ERROR: + PR_fprintf(errorFD, "Compression data error: %s\n", msg); + break; + default: + PR_fprintf(errorFD, "Unknown error in compression library: %s\n", msg); + break; + } +} + + +/**************************************************************** + * + * J z i p A d d + * + * Adds a new file into a ZIP file. The ZIP file must have already + * been opened with JzipOpen. + */ +int +JzipAdd(char *fullname, char *filename, ZIPfile *zipfile, int compression_level) +{ + ZIPentry *entry; + PRFileDesc *readfp; + PRFileDesc *zipfp; + int num; + Bytef inbuf[BUFSIZ], outbuf[BUFSIZ]; + unsigned long crc; + z_stream zstream; + int err; + unsigned long local_size_pos; + int deflate_percent; + + + if( !fullname || !filename || !zipfile) { + return -1; + } + + zipfp = zipfile->fp; + + + if( (readfp = PR_Open(fullname, PR_RDONLY, 0777)) == NULL) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "%s: %s\n", fullname, nsprErr ? nsprErr : ""); + errorCount++; + if(nsprErr) PR_Free(nsprErr); + exit(ERRX); + } + + /* + * Make sure the input file is not the output file. + * Add a few bytes to the end of the JAR file and see if the input file + * twitches + */ + { + PRInt32 endOfJar; + PRInt32 inputSize; + PRBool isSame; + + inputSize = PR_Available(readfp); + + endOfJar = PR_Seek(zipfp, 0L, PR_SEEK_CUR); + + if(PR_Write(zipfp, "abcde", 5) < 5) { + char *nsprErr; + + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing to zip file: %s\n", + nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + + isSame = (PR_Available(readfp) != inputSize); + + PR_Seek(zipfp, endOfJar, PR_SEEK_SET); + + if(isSame) { + /* It's the same file! Forget it! */ + PR_Close(readfp); + return 0; + } + } + + if(verbosity >= 0) { + PR_fprintf(outputFD, "adding %s to %s...", fullname, zipfile->filename); + } + + entry = PORT_ZAlloc(sizeof(ZIPentry)); + if(!entry) out_of_memory(); + + entry->filename = PORT_Strdup(filename); + entry->comment = NULL; + + /* Set up local file header */ + longtox(LSIG, entry->local.signature); + inttox(strlen(filename), entry->local.filename_len); + inttox(zipfile->time, entry->local.time); + inttox(zipfile->date, entry->local.date); + inttox(Z_DEFLATED, entry->local.method); + + /* Set up central directory entry */ + longtox(CSIG, entry->central.signature); + inttox(strlen(filename), entry->central.filename_len); + if(entry->comment) { + inttox(strlen(entry->comment), entry->central.commentfield_len); + } + longtox(PR_Seek(zipfile->fp, 0, PR_SEEK_CUR), + entry->central.localhdr_offset); + inttox(zipfile->time, entry->central.time); + inttox(zipfile->date, entry->central.date); + inttox(Z_DEFLATED, entry->central.method); + + /* Compute crc. Too bad we have to process the whole file to do this*/ + crc = crc32(0L, NULL, 0); + while( (num = PR_Read(readfp, inbuf, BUFSIZ)) > 0) { + crc = crc32(crc, inbuf, num); + } + PR_Seek(readfp, 0L, PR_SEEK_SET); + + /* Store CRC */ + longtox(crc, entry->local.crc32); + longtox(crc, entry->central.crc32); + + /* Stick this entry onto the end of the list */ + entry->next = NULL; + if( zipfile->list == NULL ) { + /* First entry */ + zipfile->list = entry; + } else { + ZIPentry *pe; + + pe = zipfile->list; + while(pe->next != NULL) { + pe = pe->next; + } + pe->next = entry; + } + + /* + * Start writing stuff out + */ + + local_size_pos = PR_Seek(zipfp, 0, PR_SEEK_CUR) + 18; + /* File header */ + if(PR_Write(zipfp, &entry->local, sizeof(struct ZipLocal)) + < sizeof(struct ZipLocal)) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + + /* File Name */ + if( PR_Write(zipfp, filename, strlen(filename)) < strlen(filename)) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + + /* + * File data + */ + /* Initialize zstream */ + zstream.zalloc = my_alloc_func; + zstream.zfree = my_free_func; + zstream.opaque = NULL; + zstream.next_in = inbuf; + zstream.avail_in = BUFSIZ; + zstream.next_out = outbuf; + zstream.avail_out = BUFSIZ; + /* Setting the windowBits to -MAX_WBITS is an undocumented feature of + * zlib (see deflate.c in zlib). It is the same thing that Java does + * when you specify the nowrap option for deflation in java.util.zip. + * It causes zlib to leave out its headers and footers, which don't + * work in PKZIP files. + */ + err = deflateInit2(&zstream, compression_level, Z_DEFLATED, + -MAX_WBITS, 8 /*default*/, Z_DEFAULT_STRATEGY); + if(err != Z_OK) { + handle_zerror(err, zstream.msg); + exit(ERRX); + } + + while( (zstream.avail_in = PR_Read(readfp, inbuf, BUFSIZ)) > 0) { + zstream.next_in = inbuf; + /* Process this chunk of data */ + while(zstream.avail_in > 0) { + err = deflate(&zstream, Z_NO_FLUSH); + if(err != Z_OK) { + handle_zerror(err, zstream.msg); + exit(ERRX); + } + if(zstream.avail_out <= 0) { + if( PR_Write(zipfp, outbuf, BUFSIZ) < BUFSIZ) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", + nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + zstream.next_out = outbuf; + zstream.avail_out = BUFSIZ; + } + } + } + + /* Now flush everything */ + while(1) { + err = deflate(&zstream, Z_FINISH); + if(err == Z_STREAM_END) { + break; + } else if(err == Z_OK) { + /* output buffer full, repeat */ + } else { + handle_zerror(err, zstream.msg); + exit(ERRX); + } + if( PR_Write(zipfp, outbuf, BUFSIZ) < BUFSIZ) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", + nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + zstream.avail_out = BUFSIZ; + zstream.next_out = outbuf; + } + + /* If there's any output left, write it out. */ + if(zstream.next_out != outbuf) { + if( PR_Write(zipfp, outbuf, zstream.next_out-outbuf) < + zstream.next_out-outbuf) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", + nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + zstream.avail_out = BUFSIZ; + zstream.next_out = outbuf; + } + + /* Now that we know the compressed size, write this to the headers */ + longtox(zstream.total_in, entry->local.orglen); + longtox(zstream.total_out, entry->local.size); + if(PR_Seek(zipfp, local_size_pos, PR_SEEK_SET) == -1) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Accessing zip file: %s\n", nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + if( PR_Write(zipfp, entry->local.size, 8) != 8) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + if(PR_Seek(zipfp, 0L, PR_SEEK_END) == -1) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Accessing zip file: %s\n", nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + longtox(zstream.total_in, entry->central.orglen); + longtox(zstream.total_out, entry->central.size); + + /* Close out the deflation operation */ + err = deflateEnd(&zstream); + if(err != Z_OK) { + handle_zerror(err, zstream.msg); + exit(ERRX); + } + + PR_Close(readfp); + + if((zstream.total_in > zstream.total_out) && (zstream.total_in > 0)) { + deflate_percent = (int) ( (zstream.total_in-zstream.total_out)*100 / + zstream.total_in ); + } else { + deflate_percent = 0; + } + if(verbosity >= 0) { + PR_fprintf(outputFD, "(deflated %d%%)\n", deflate_percent); + } + + return 0; +} + +/******************************************************************** + * J z i p C l o s e + * + * Finishes the ZipFile. ALSO DELETES THE ZIPFILE STRUCTURE PASSED IN!! + */ +int +JzipClose(ZIPfile *zipfile) +{ + ZIPentry *pe, *dead; + PRFileDesc *zipfp; + struct ZipEnd zipend; + unsigned int entrycount = 0; + + if(!zipfile) { + return -1; + } + + if(!zipfile->filename) { + /* bogus */ + return 0; + } + + zipfp = zipfile->fp; + zipfile->central_start = PR_Seek(zipfp, 0L, PR_SEEK_CUR); + + /* Write out all the central directories */ + pe = zipfile->list; + while(pe) { + entrycount++; + + /* Write central directory info */ + if( PR_Write(zipfp, &pe->central, sizeof(struct ZipCentral)) + < sizeof(struct ZipCentral)) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", + nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + + /* Write filename */ + if( PR_Write(zipfp, pe->filename, strlen(pe->filename)) + < strlen(pe->filename)) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", + nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + + /* Write file comment */ + if(pe->comment) { + if( PR_Write(zipfp, pe->comment, strlen(pe->comment)) + < strlen(pe->comment)) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", + nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + } + + /* Delete the structure */ + dead = pe; + pe = pe->next; + if(dead->filename) { + PORT_Free(dead->filename); + } + if(dead->comment) { + PORT_Free(dead->comment); + } + PORT_Free(dead); + } + zipfile->central_end = PR_Seek(zipfile->fp, 0L, PR_SEEK_CUR); + + /* Create the ZipEnd structure */ + PORT_Memset(&zipend, 0, sizeof(zipend)); + longtox(ESIG, zipend.signature); + inttox(entrycount, zipend.total_entries_disk); + inttox(entrycount, zipend.total_entries_archive); + longtox(zipfile->central_end-zipfile->central_start, + zipend.central_dir_size); + longtox(zipfile->central_start, zipend.offset_central_dir); + if(zipfile->comment) { + inttox(strlen(zipfile->comment), zipend.commentfield_len); + } + + /* Write out ZipEnd xtructure */ + if( PR_Write(zipfp, &zipend, sizeof(zipend)) < sizeof(zipend)) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + + /* Write out Zipfile comment */ + if(zipfile->comment) { + if( PR_Write(zipfp, zipfile->comment, strlen(zipfile->comment)) + < strlen(zipfile->comment)) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", + nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + } + + PR_Close(zipfp); + + /* Free the memory of the zipfile structure */ + if(zipfile->filename) { + PORT_Free(zipfile->filename); + } + if(zipfile->comment) { + PORT_Free(zipfile->comment); + } + PORT_Free(zipfile); + + return 0; +} + +/********************************************** + * i n t t o x + * + * Converts a two byte ugly endianed integer + * to our platform's integer. + * + */ + +static void inttox (int in, char *out) +{ + out [0] = (in & 0xFF); + out [1] = (in & 0xFF00) >> 8; +} + +/********************************************* + * l o n g t o x + * + * Converts a four byte ugly endianed integer + * to our platform's integer. + * + */ + +static void longtox (long in, char *out) +{ + out [0] = (in & 0xFF); + out [1] = (in & 0xFF00) >> 8; + out [2] = (in & 0xFF0000) >> 16; + out [3] = (in & 0xFF000000) >> 24; +} + |