jarfile.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 1,150 行 · 第 1/2 页
C
1,150 行
/* * 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. *//* * JARFILE * * Parsing of a Jar file */#define JAR_SIZE 256#include "jar.h"#include "jarint.h"#include "jarfile.h"/* commercial compression */#include "jzlib.h"#ifdef XP_UNIX#include "sys/stat.h"#endif/* extracting */static int jar_guess_jar (char *filename, JAR_FILE fp);static int jar_inflate_memory (unsigned int method, long *length, long expected_out_len, char ZHUGEP **data);static int jar_physical_extraction (JAR_FILE fp, char *outpath, long offset, long length);static int jar_physical_inflate (JAR_FILE fp, char *outpath, long offset, long length, unsigned int method);static int jar_verify_extract (JAR *jar, char *path, char *physical_path);static JAR_Physical *jar_get_physical (JAR *jar, char *pathname);static int jar_extract_manifests (JAR *jar, jarArch format, JAR_FILE fp);static int jar_extract_mf (JAR *jar, jarArch format, JAR_FILE fp, char *ext);/* indexing */static int jar_gen_index (JAR *jar, jarArch format, JAR_FILE fp);static int jar_listtar (JAR *jar, JAR_FILE fp);static int jar_listzip (JAR *jar, JAR_FILE fp);/* conversions */static int dosdate (char *date, char *s);static int dostime (char *time, char *s);static unsigned int xtoint (unsigned char *ii);static unsigned long xtolong (unsigned char *ll);static long atoo (char *s);/* * J A R _ p a s s _ a r c h i v e * * For use by naive clients. Slam an entire archive file * into this function. We extract manifests, parse, index * the archive file, and do whatever nastiness. * */int JAR_pass_archive (JAR *jar, jarArch format, char *filename, const char *url) { JAR_FILE fp; int status = 0; if (filename == NULL) return JAR_ERR_GENERAL; if ((fp = JAR_FOPEN (filename, "rb")) != NULL) { if (format == jarArchGuess) format = (jarArch)jar_guess_jar (filename, fp); jar->format = format; jar->url = url ? PORT_Strdup (url) : NULL; jar->filename = PORT_Strdup (filename); status = jar_gen_index (jar, format, fp); if (status == 0) status = jar_extract_manifests (jar, format, fp); JAR_FCLOSE (fp); if (status < 0) return status; /* people were expecting it this way */ return jar->valid; } else { /* file not found */ return JAR_ERR_FNF; } }/* * J A R _ p a s s _ a r c h i v e _ u n v e r i f i e d * * Same as JAR_pass_archive, but doesn't parse signatures. * */int JAR_pass_archive_unverified (JAR *jar, jarArch format, char *filename, const char *url){ JAR_FILE fp; int status = 0; if (filename == NULL) { return JAR_ERR_GENERAL; } if ((fp = JAR_FOPEN (filename, "rb")) != NULL) { if (format == jarArchGuess) { format = (jarArch)jar_guess_jar (filename, fp); } jar->format = format; jar->url = url ? PORT_Strdup (url) : NULL; jar->filename = PORT_Strdup (filename); status = jar_gen_index (jar, format, fp); if (status == 0) { status = jar_extract_mf(jar, format, fp, "mf"); } JAR_FCLOSE (fp); if (status < 0) { return status; } /* people were expecting it this way */ return jar->valid; } else { /* file not found */ return JAR_ERR_FNF; }}/* * J A R _ v e r i f i e d _ e x t r a c t * * Optimization: keep a file descriptor open * inside the JAR structure, so we don't have to * open the file 25 times to run java. * */int JAR_verified_extract (JAR *jar, char *path, char *outpath) { int status; status = JAR_extract (jar, path, outpath); if (status >= 0) return jar_verify_extract (jar, path, outpath); else return status; }int JAR_extract (JAR *jar, char *path, char *outpath) { int result; JAR_FILE fp; JAR_Physical *phy; if (jar->fp == NULL && jar->filename) { jar->fp = (FILE*)JAR_FOPEN (jar->filename, "rb"); } if (jar->fp == NULL) { /* file not found */ return JAR_ERR_FNF; } phy = jar_get_physical (jar, path); if (phy) { if (phy->compression != 0 && phy->compression != 8) { /* unsupported compression method */ result = JAR_ERR_CORRUPT; } if (phy->compression == 0) { result = jar_physical_extraction ((PRFileDesc*)jar->fp, outpath, phy->offset, phy->length); } else { result = jar_physical_inflate ((PRFileDesc*)jar->fp, outpath, phy->offset, phy->length, (unsigned int) phy->compression); }#ifdef XP_UNIX if (phy->mode) chmod (outpath, 0400 | (mode_t) phy->mode);#endif } else { /* pathname not found in archive */ result = JAR_ERR_PNF; } return result; }/* * p h y s i c a l _ e x t r a c t i o n * * This needs to be done in chunks of say 32k, instead of * in one bulk calloc. (Necessary under Win16 platform.) * This is done for uncompressed entries only. * */#define CHUNK 32768static int jar_physical_extraction (JAR_FILE fp, char *outpath, long offset, long length) { JAR_FILE out; char *buffer; long at, chunk; int status = 0; buffer = (char *) PORT_ZAlloc (CHUNK); if (buffer == NULL) return JAR_ERR_MEMORY; if ((out = JAR_FOPEN (outpath, "wb")) != NULL) { at = 0; JAR_FSEEK (fp, offset, (PRSeekWhence)0); while (at < length) { chunk = (at + CHUNK <= length) ? CHUNK : length - at; if (JAR_FREAD (fp, buffer, chunk) != chunk) { status = JAR_ERR_DISK; break; } at += chunk; if (JAR_FWRITE (out, buffer, chunk) < chunk) { /* most likely a disk full error */ status = JAR_ERR_DISK; break; } } JAR_FCLOSE (out); } else { /* error opening output file */ status = JAR_ERR_DISK; } PORT_Free (buffer); return status; }/* * j a r _ p h y s i c a l _ i n f l a t e * * Inflate a range of bytes in a file, writing the inflated * result to "outpath". Chunk based. * *//* input and output chunks differ, assume 4x compression */#define ICHUNK 8192#define OCHUNK 32768static int jar_physical_inflate (JAR_FILE fp, char *outpath, long offset, long length, unsigned int method) { z_stream zs; JAR_FILE out; long at, chunk; char *inbuf, *outbuf; int status = 0; unsigned long prev_total, ochunk, tin; if ((inbuf = (char *) PORT_ZAlloc (ICHUNK)) == NULL) return JAR_ERR_MEMORY; if ((outbuf = (char *) PORT_ZAlloc (OCHUNK)) == NULL) { PORT_Free (inbuf); return JAR_ERR_MEMORY; } PORT_Memset (&zs, 0, sizeof (zs)); status = inflateInit2 (&zs, -MAX_WBITS); if (status != Z_OK) return JAR_ERR_GENERAL; if ((out = JAR_FOPEN (outpath, "wb")) != NULL) { at = 0; JAR_FSEEK (fp, offset, (PRSeekWhence)0); while (at < length) { chunk = (at + ICHUNK <= length) ? ICHUNK : length - at; if (JAR_FREAD (fp, inbuf, chunk) != chunk) { /* incomplete read */ return JAR_ERR_CORRUPT; } at += chunk; zs.next_in = (Bytef *) inbuf; zs.avail_in = chunk; zs.avail_out = OCHUNK; tin = zs.total_in; while ((zs.total_in - tin < chunk) || (zs.avail_out == 0)) { prev_total = zs.total_out; zs.next_out = (Bytef *) outbuf; zs.avail_out = OCHUNK; status = inflate (&zs, Z_NO_FLUSH); if (status != Z_OK && status != Z_STREAM_END) { /* error during decompression */ return JAR_ERR_CORRUPT; } ochunk = zs.total_out - prev_total; if (JAR_FWRITE (out, outbuf, ochunk) < ochunk) { /* most likely a disk full error */ status = JAR_ERR_DISK; break; } if (status == Z_STREAM_END) break; } } JAR_FCLOSE (out); status = inflateEnd (&zs); } else { /* error opening output file */ status = JAR_ERR_DISK; } PORT_Free (inbuf); PORT_Free (outbuf); return status; }/* * j a r _ i n f l a t e _ m e m o r y * * Call zlib to inflate the given memory chunk. It is re-XP_ALLOC'd, * and thus appears to operate inplace to the caller. * */static int jar_inflate_memory (unsigned int method, long *length, long expected_out_len, char ZHUGEP **data) { int status; z_stream zs; long insz, outsz; char *inbuf, *outbuf; inbuf = *data; insz = *length; outsz = expected_out_len; outbuf = (char*)PORT_ZAlloc (outsz); if (outbuf == NULL) return JAR_ERR_MEMORY; PORT_Memset (&zs, 0, sizeof (zs)); status = inflateInit2 (&zs, -MAX_WBITS); if (status < 0) { /* error initializing zlib stream */ return JAR_ERR_GENERAL; } zs.next_in = (Bytef *) inbuf; zs.next_out = (Bytef *) outbuf; zs.avail_in = insz; zs.avail_out = outsz; status = inflate (&zs, Z_FINISH); if (status != Z_OK && status != Z_STREAM_END) { /* error during deflation */ return JAR_ERR_GENERAL; } status = inflateEnd (&zs); if (status != Z_OK) { /* error during deflation */ return JAR_ERR_GENERAL; } PORT_Free (*data); *data = outbuf; *length = zs.total_out; return 0; }/* * v e r i f y _ e x t r a c t * * Validate signature on the freshly extracted file. * */static int jar_verify_extract (JAR *jar, char *path, char *physical_path) { int status; JAR_Digest dig; PORT_Memset (&dig, 0, sizeof (JAR_Digest)); status = JAR_digest_file (physical_path, &dig); if (!status) status = JAR_verify_digest (jar, path, &dig); return status; }/* * g e t _ p h y s i c a l * * Let's get physical. * Obtains the offset and length of this file in the jar file. * */static JAR_Physical *jar_get_physical (JAR *jar, char *pathname) { JAR_Item *it; JAR_Physical *phy; ZZLink *link; ZZList *list; list = jar->phy; if (ZZ_ListEmpty (list)) return NULL; for (link = ZZ_ListHead (list); !ZZ_ListIterDone (list, link); link = link->next) { it = link->thing; if (it->type == jarTypePhy && it->pathname && !PORT_Strcmp (it->pathname, pathname)) { phy = (JAR_Physical *) it->data; return phy; } } return NULL; }/* * j a r _ e x t r a c t _ m a n i f e s t s * * Extract the manifest files and parse them, * from an open archive file whose contents are known. * */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?