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 + -
显示快捷键?