jarfile.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:23k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is the Netscape security libraries.
  13.  * 
  14.  * The Initial Developer of the Original Code is Netscape
  15.  * Communications Corporation.  Portions created by Netscape are 
  16.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  17.  * Rights Reserved.
  18.  * 
  19.  * Contributor(s):
  20.  * 
  21.  * Alternatively, the contents of this file may be used under the
  22.  * terms of the GNU General Public License Version 2 or later (the
  23.  * "GPL"), in which case the provisions of the GPL are applicable 
  24.  * instead of those above.  If you wish to allow use of your 
  25.  * version of this file only under the terms of the GPL and not to
  26.  * allow others to use your version of this file under the MPL,
  27.  * indicate your decision by deleting the provisions above and
  28.  * replace them with the notice and other provisions required by
  29.  * the GPL.  If you do not delete the provisions above, a recipient
  30.  * may use your version of this file under either the MPL or the
  31.  * GPL.
  32.  */
  33. /*
  34.  *  JARFILE
  35.  *
  36.  *  Parsing of a Jar file
  37.  */
  38. #define JAR_SIZE 256
  39. #include "jar.h"
  40. #include "jarint.h"
  41. #include "jarfile.h"
  42. /* commercial compression */
  43. #include "jzlib.h"
  44. #ifdef XP_UNIX
  45. #include "sys/stat.h"
  46. #endif
  47. /* extracting */
  48. static int jar_guess_jar (char *filename, JAR_FILE fp);
  49. static int jar_inflate_memory 
  50.    (unsigned int method, long *length, long expected_out_len, char ZHUGEP **data);
  51. static int jar_physical_extraction 
  52.    (JAR_FILE fp, char *outpath, long offset, long length);
  53. static int jar_physical_inflate
  54.    (JAR_FILE fp, char *outpath, long offset, 
  55.          long length, unsigned int method);
  56. static int jar_verify_extract 
  57.    (JAR *jar, char *path, char *physical_path);
  58. static JAR_Physical *jar_get_physical (JAR *jar, char *pathname);
  59. static int jar_extract_manifests (JAR *jar, jarArch format, JAR_FILE fp);
  60. static int jar_extract_mf (JAR *jar, jarArch format, JAR_FILE fp, char *ext);
  61. /* indexing */
  62. static int jar_gen_index (JAR *jar, jarArch format, JAR_FILE fp);
  63. static int jar_listtar (JAR *jar, JAR_FILE fp);
  64. static int jar_listzip (JAR *jar, JAR_FILE fp);
  65. /* conversions */
  66. static int dosdate (char *date, char *s);
  67. static int dostime (char *time, char *s);
  68. static unsigned int xtoint (unsigned char *ii);
  69. static unsigned long xtolong (unsigned char *ll);
  70. static long atoo (char *s);
  71. /*
  72.  *  J A R _ p a s s _ a r c h i v e
  73.  *
  74.  *  For use by naive clients. Slam an entire archive file
  75.  *  into this function. We extract manifests, parse, index
  76.  *  the archive file, and do whatever nastiness.
  77.  *
  78.  */
  79. int JAR_pass_archive
  80.     (JAR *jar, jarArch format, char *filename, const char *url)
  81.   {
  82.   JAR_FILE fp;
  83.   int status = 0;
  84.   if (filename == NULL)
  85.     return JAR_ERR_GENERAL;
  86.   if ((fp = JAR_FOPEN (filename, "rb")) != NULL)
  87.     {
  88.     if (format == jarArchGuess)
  89.       format = (jarArch)jar_guess_jar (filename, fp);
  90.     jar->format = format;
  91.     jar->url = url ? PORT_Strdup (url) : NULL;
  92.     jar->filename = PORT_Strdup (filename);
  93.     status = jar_gen_index (jar, format, fp);
  94.     if (status == 0)
  95.       status = jar_extract_manifests (jar, format, fp);
  96.     JAR_FCLOSE (fp);
  97.     if (status < 0)
  98.       return status;
  99.     /* people were expecting it this way */
  100.     return jar->valid;
  101.     }
  102.   else
  103.     {
  104.     /* file not found */
  105.     return JAR_ERR_FNF;
  106.     }
  107.   }
  108. /*
  109.  *  J A R _ p a s s _ a r c h i v e _ u n v e r i f i e d
  110.  *
  111.  * Same as JAR_pass_archive, but doesn't parse signatures.
  112.  *
  113.  */
  114. int JAR_pass_archive_unverified
  115.         (JAR *jar, jarArch format, char *filename, const char *url)
  116. {
  117.         JAR_FILE fp;
  118.         int status = 0;
  119.         if (filename == NULL) {
  120.                 return JAR_ERR_GENERAL;
  121.         }
  122.         if ((fp = JAR_FOPEN (filename, "rb")) != NULL) {
  123.                 if (format == jarArchGuess) {
  124.                         format = (jarArch)jar_guess_jar (filename, fp);
  125.                 }
  126.                 jar->format = format;
  127.                 jar->url = url ? PORT_Strdup (url) : NULL;
  128.                 jar->filename = PORT_Strdup (filename);
  129.                 status = jar_gen_index (jar, format, fp);
  130.                 if (status == 0) {
  131.                         status = jar_extract_mf(jar, format, fp, "mf");
  132.                 }
  133.                 JAR_FCLOSE (fp);
  134.                 if (status < 0) {
  135.                         return status;
  136.                 }
  137.                 /* people were expecting it this way */
  138.                 return jar->valid;
  139.         } else {
  140.                 /* file not found */
  141.                 return JAR_ERR_FNF;
  142.         }
  143. }
  144. /*
  145.  *  J A R _ v e r i f i e d _ e x t r a c t
  146.  *
  147.  *  Optimization: keep a file descriptor open
  148.  *  inside the JAR structure, so we don't have to
  149.  *  open the file 25 times to run java. 
  150.  *
  151.  */
  152. int JAR_verified_extract
  153.     (JAR *jar, char *path, char *outpath)
  154.   {
  155.   int status;
  156.   status = JAR_extract (jar, path, outpath);
  157.   if (status >= 0)
  158.     return jar_verify_extract (jar, path, outpath);
  159.   else
  160.     return status;
  161.   }
  162. int JAR_extract
  163.     (JAR *jar, char *path, char *outpath)
  164.   {
  165.   int result;
  166.   JAR_FILE fp;
  167.   JAR_Physical *phy;
  168.   if (jar->fp == NULL && jar->filename)
  169.     {
  170.     jar->fp = (FILE*)JAR_FOPEN (jar->filename, "rb");
  171.     }
  172.   if (jar->fp == NULL)
  173.     {
  174.     /* file not found */
  175.     return JAR_ERR_FNF;
  176.     }
  177.   phy = jar_get_physical (jar, path);
  178.   if (phy)
  179.     {
  180.     if (phy->compression != 0 && phy->compression != 8)
  181.       {
  182.       /* unsupported compression method */
  183.       result = JAR_ERR_CORRUPT;
  184.       }
  185.     if (phy->compression == 0)
  186.       {
  187.       result = jar_physical_extraction 
  188.          ((PRFileDesc*)jar->fp, outpath, phy->offset, phy->length);
  189.       }
  190.     else
  191.       {
  192.       result = jar_physical_inflate 
  193.          ((PRFileDesc*)jar->fp, outpath, phy->offset, phy->length, 
  194.             (unsigned int) phy->compression);
  195.       }
  196. #ifdef XP_UNIX
  197.     if (phy->mode)
  198.       chmod (outpath, 0400 | (mode_t) phy->mode);
  199. #endif
  200.     }
  201.   else
  202.     {
  203.     /* pathname not found in archive */
  204.     result = JAR_ERR_PNF;
  205.     }
  206.   return result;
  207.   }
  208. /* 
  209.  *  p h y s i c a l _ e x t r a c t i o n
  210.  *
  211.  *  This needs to be done in chunks of say 32k, instead of
  212.  *  in one bulk calloc. (Necessary under Win16 platform.)
  213.  *  This is done for uncompressed entries only.
  214.  *
  215.  */
  216. #define CHUNK 32768
  217. static int jar_physical_extraction 
  218.      (JAR_FILE fp, char *outpath, long offset, long length)
  219.   {
  220.   JAR_FILE out;
  221.   char *buffer;
  222.   long at, chunk;
  223.   int status = 0;
  224.   buffer = (char *) PORT_ZAlloc (CHUNK);
  225.   if (buffer == NULL)
  226.     return JAR_ERR_MEMORY;
  227.   if ((out = JAR_FOPEN (outpath, "wb")) != NULL)
  228.     {
  229.     at = 0;
  230.     JAR_FSEEK (fp, offset, (PRSeekWhence)0);
  231.     while (at < length)
  232.       {
  233.       chunk = (at + CHUNK <= length) ? CHUNK : length - at;
  234.       if (JAR_FREAD (fp, buffer, chunk) != chunk)
  235.         {
  236.         status = JAR_ERR_DISK;
  237.         break;
  238.         }
  239.       at += chunk;
  240.       if (JAR_FWRITE (out, buffer, chunk) < chunk)
  241.         {
  242.         /* most likely a disk full error */
  243.         status = JAR_ERR_DISK;
  244.         break;
  245.         }
  246.       }
  247.     JAR_FCLOSE (out);
  248.     }
  249.   else
  250.     {
  251.     /* error opening output file */
  252.     status = JAR_ERR_DISK;
  253.     }
  254.   PORT_Free (buffer);
  255.   return status;
  256.   }
  257. /*
  258.  *  j a r _ p h y s i c a l _ i n f l a t e
  259.  *
  260.  *  Inflate a range of bytes in a file, writing the inflated
  261.  *  result to "outpath". Chunk based.
  262.  *
  263.  */
  264. /* input and output chunks differ, assume 4x compression */
  265. #define ICHUNK 8192
  266. #define OCHUNK 32768
  267. static int jar_physical_inflate
  268.      (JAR_FILE fp, char *outpath, long offset, 
  269.           long length, unsigned int method)
  270.   {
  271.   z_stream zs;
  272.   JAR_FILE out;
  273.   long at, chunk;
  274.   char *inbuf, *outbuf;
  275.   int status = 0;
  276.   unsigned long prev_total, ochunk, tin;
  277.   if ((inbuf = (char *) PORT_ZAlloc (ICHUNK)) == NULL)
  278.     return JAR_ERR_MEMORY;
  279.   if ((outbuf = (char *) PORT_ZAlloc (OCHUNK)) == NULL)
  280.     {
  281.     PORT_Free (inbuf);
  282.     return JAR_ERR_MEMORY;
  283.     }
  284.   PORT_Memset (&zs, 0, sizeof (zs));
  285.   status = inflateInit2 (&zs, -MAX_WBITS);
  286.   if (status != Z_OK)
  287.     return JAR_ERR_GENERAL;
  288.   if ((out = JAR_FOPEN (outpath, "wb")) != NULL)
  289.     {
  290.     at = 0;
  291.     JAR_FSEEK (fp, offset, (PRSeekWhence)0);
  292.     while (at < length)
  293.       {
  294.       chunk = (at + ICHUNK <= length) ? ICHUNK : length - at;
  295.       if (JAR_FREAD (fp, inbuf, chunk) != chunk)
  296.         {
  297.         /* incomplete read */
  298.         return JAR_ERR_CORRUPT;
  299.         }
  300.       at += chunk;
  301.       zs.next_in = (Bytef *) inbuf;
  302.       zs.avail_in = chunk;
  303.       zs.avail_out = OCHUNK;
  304.       tin = zs.total_in;
  305.       while ((zs.total_in - tin < chunk) || (zs.avail_out == 0))
  306.         {
  307.         prev_total = zs.total_out;
  308.         zs.next_out = (Bytef *) outbuf;
  309.         zs.avail_out = OCHUNK;
  310.         status = inflate (&zs, Z_NO_FLUSH);
  311.         if (status != Z_OK && status != Z_STREAM_END)
  312.           {
  313.           /* error during decompression */
  314.           return JAR_ERR_CORRUPT;
  315.           }
  316. ochunk = zs.total_out - prev_total;
  317.         if (JAR_FWRITE (out, outbuf, ochunk) < ochunk)
  318.           {
  319.           /* most likely a disk full error */
  320.           status = JAR_ERR_DISK;
  321.           break;
  322.           }
  323.         if (status == Z_STREAM_END)
  324.           break;
  325.         }
  326.       }
  327.     JAR_FCLOSE (out);
  328.     status = inflateEnd (&zs);
  329.     }
  330.   else
  331.     {
  332.     /* error opening output file */
  333.     status = JAR_ERR_DISK;
  334.     }
  335.   PORT_Free (inbuf);
  336.   PORT_Free (outbuf);
  337.   return status;
  338.   }
  339. /*
  340.  *  j a r _ i n f l a t e _ m e m o r y
  341.  *
  342.  *  Call zlib to inflate the given memory chunk. It is re-XP_ALLOC'd, 
  343.  *  and thus appears to operate inplace to the caller.
  344.  *
  345.  */
  346. static int jar_inflate_memory 
  347.      (unsigned int method, long *length, long expected_out_len, char ZHUGEP **data)
  348.   {
  349.   int status;
  350.   z_stream zs;
  351.   long insz, outsz;
  352.   char *inbuf, *outbuf;
  353.   inbuf =  *data;
  354.   insz = *length;
  355.   outsz = expected_out_len;
  356.   outbuf = (char*)PORT_ZAlloc (outsz);
  357.   if (outbuf == NULL)
  358.     return JAR_ERR_MEMORY;
  359.   PORT_Memset (&zs, 0, sizeof (zs));
  360.   status = inflateInit2 (&zs, -MAX_WBITS);
  361.   if (status < 0)
  362.     {
  363.     /* error initializing zlib stream */
  364.     return JAR_ERR_GENERAL;
  365.     }
  366.   zs.next_in = (Bytef *) inbuf;
  367.   zs.next_out = (Bytef *) outbuf;
  368.   zs.avail_in = insz;
  369.   zs.avail_out = outsz;
  370.   status = inflate (&zs, Z_FINISH);
  371.   if (status != Z_OK && status != Z_STREAM_END)
  372.     {
  373.     /* error during deflation */
  374.     return JAR_ERR_GENERAL; 
  375.     }
  376.   status = inflateEnd (&zs);
  377.   if (status != Z_OK)
  378.     {
  379.     /* error during deflation */
  380.     return JAR_ERR_GENERAL;
  381.     }
  382.   PORT_Free (*data);
  383.   *data = outbuf;
  384.   *length = zs.total_out;
  385.   return 0;
  386.   }
  387. /*
  388.  *  v e r i f y _ e x t r a c t
  389.  *
  390.  *  Validate signature on the freshly extracted file.
  391.  *
  392.  */
  393. static int jar_verify_extract (JAR *jar, char *path, char *physical_path)
  394.   {
  395.   int status;
  396.   JAR_Digest dig;
  397.   PORT_Memset (&dig, 0, sizeof (JAR_Digest));
  398.   status = JAR_digest_file (physical_path, &dig);
  399.   if (!status)
  400.     status = JAR_verify_digest (jar, path, &dig);
  401.   return status;
  402.   }
  403. /*
  404.  *  g e t _ p h y s i c a l
  405.  *
  406.  *  Let's get physical.
  407.  *  Obtains the offset and length of this file in the jar file.
  408.  *
  409.  */
  410. static JAR_Physical *jar_get_physical (JAR *jar, char *pathname)
  411.   {
  412.   JAR_Item *it;
  413.   JAR_Physical *phy;
  414.   ZZLink *link;
  415.   ZZList *list;
  416.   list = jar->phy;
  417.   if (ZZ_ListEmpty (list))
  418.     return NULL;
  419.   for (link = ZZ_ListHead (list);
  420.        !ZZ_ListIterDone (list, link);
  421.        link = link->next)
  422.     {
  423.     it = link->thing;
  424.     if (it->type == jarTypePhy 
  425.           && it->pathname && !PORT_Strcmp (it->pathname, pathname))
  426.       {
  427.       phy = (JAR_Physical *) it->data;
  428.       return phy;
  429.       }
  430.     }
  431.   return NULL;
  432.   }
  433. /*
  434.  *  j a r _ e x t r a c t _ m a n i f e s t s
  435.  *
  436.  *  Extract the manifest files and parse them,
  437.  *  from an open archive file whose contents are known.
  438.  *
  439.  */
  440. static int jar_extract_manifests (JAR *jar, jarArch format, JAR_FILE fp)
  441.   {
  442.   int status;
  443.   if (format != jarArchZip && format != jarArchTar)
  444.     return JAR_ERR_CORRUPT;
  445.   if ((status = jar_extract_mf (jar, format, fp, "mf")) < 0)
  446.     return status;
  447.   if ((status = jar_extract_mf (jar, format, fp, "sf")) < 0)
  448.     return status;
  449.   if ((status = jar_extract_mf (jar, format, fp, "rsa")) < 0)
  450.     return status;
  451.   if ((status = jar_extract_mf (jar, format, fp, "dsa")) < 0)
  452.     return status;
  453.   return 0;
  454.   }
  455. /*
  456.  *  j a r _ e x t r a c t _ m f
  457.  *
  458.  *  Extracts manifest files based on an extension, which 
  459.  *  should be .MF, .SF, .RSA, etc. Order of the files is now no 
  460.  *  longer important when zipping jar files.
  461.  *
  462.  */
  463. static int jar_extract_mf (JAR *jar, jarArch format, JAR_FILE fp, char *ext)
  464.   {
  465.   JAR_Item *it;
  466.   JAR_Physical *phy;
  467.   ZZLink *link;
  468.   ZZList *list;
  469.   char *fn, *e;
  470.   char ZHUGEP *manifest;
  471.   long length;
  472.   int status, ret = 0, num;
  473.   list = jar->phy;
  474.   if (ZZ_ListEmpty (list))
  475.     return JAR_ERR_PNF;
  476.   for (link = ZZ_ListHead (list);
  477.        !ZZ_ListIterDone (list, link);
  478.        link = link->next)
  479.     {
  480.     it = link->thing;
  481.     if (it->type == jarTypePhy 
  482.           && !PORT_Strncmp (it->pathname, "META-INF", 8))
  483.       {
  484.       phy = (JAR_Physical *) it->data;
  485.       if (PORT_Strlen (it->pathname) < 8)
  486.         continue;
  487.       fn = it->pathname + 8;
  488.       if (*fn == '/' || *fn == '\') fn++;
  489.       if (*fn == 0)
  490.         {
  491.         /* just a directory entry */
  492.         continue;
  493.         }
  494.       /* skip to extension */
  495.       for (e = fn; *e && *e != '.'; e++)
  496.         /* yip */ ;
  497.       /* and skip dot */
  498.       if (*e == '.') e++;
  499.       if (PORT_Strcasecmp (ext, e))
  500.         {
  501.         /* not the right extension */
  502.         continue;
  503.         }
  504.       if (phy->length == 0)
  505.         {
  506.         /* manifest files cannot be zero length! */
  507.         return JAR_ERR_CORRUPT;
  508.         }
  509.       /* Read in the manifest and parse it */
  510.       /* FIX? Does this break on win16 for very very large manifest files? */
  511. #ifdef XP_WIN16
  512.       PORT_Assert( phy->length+1 < 0xFFFF );
  513. #endif
  514.       manifest = (char ZHUGEP *) PORT_ZAlloc (phy->length + 1);
  515.       if (manifest)
  516.         {
  517.         JAR_FSEEK (fp, phy->offset, (PRSeekWhence)0);
  518.         num = JAR_FREAD (fp, manifest, phy->length);
  519.         if (num != phy->length)
  520.           {
  521.           /* corrupt archive file */
  522.           return JAR_ERR_CORRUPT;
  523.           }
  524.         if (phy->compression == 8)
  525.           {
  526.           length = phy->length;
  527.           status = jar_inflate_memory ((unsigned int) phy->compression, &length,  phy->uncompressed_length, &manifest);
  528.           if (status < 0)
  529.             return status;
  530.           }
  531.         else if (phy->compression)
  532.           {
  533.           /* unsupported compression method */
  534.           return JAR_ERR_CORRUPT;
  535.           }
  536.         else
  537.           length = phy->length;
  538.         status = JAR_parse_manifest 
  539.            (jar, manifest, length, it->pathname, "url");
  540.         PORT_Free (manifest);
  541.         if (status < 0 && ret == 0) ret = status;
  542.         }
  543.       else
  544.         return JAR_ERR_MEMORY;
  545.       }
  546.     else if (it->type == jarTypePhy)
  547.       {
  548.       /* ordinary file */
  549.       }
  550.     }
  551.   return ret;
  552.   }
  553. /*
  554.  *  j a r _ g e n _ i n d e x
  555.  *
  556.  *  Generate an index for the various types of
  557.  *  known archive files. Right now .ZIP and .TAR
  558.  *
  559.  */
  560. static int jar_gen_index (JAR *jar, jarArch format, JAR_FILE fp)
  561.   {
  562.   int result = JAR_ERR_CORRUPT;
  563.   JAR_FSEEK (fp, 0, (PRSeekWhence)0);
  564.   switch (format)
  565.     {
  566.     case jarArchZip:
  567.       result = jar_listzip (jar, fp);
  568.       break;
  569.     case jarArchTar:
  570.       result = jar_listtar (jar, fp);
  571.       break;
  572.     }
  573.   JAR_FSEEK (fp, 0, (PRSeekWhence)0);
  574.   return result;
  575.   }
  576. /*
  577.  *  j a r _ l i s t z i p
  578.  *
  579.  *  List the physical contents of a Phil Katz 
  580.  *  style .ZIP file into the JAR linked list.
  581.  *
  582.  */
  583. static int jar_listzip (JAR *jar, JAR_FILE fp)
  584.   {
  585.   int err = 0;
  586.   long pos = 0L;
  587.   char filename [JAR_SIZE];
  588.   char date [9], time [9];
  589.   char sig [4];
  590.   unsigned int compression;
  591.   unsigned int filename_len, extra_len;
  592.   struct ZipLocal *Local;
  593.   struct ZipCentral *Central;
  594.   struct ZipEnd *End;
  595.   /* phy things */
  596.   ZZLink  *ent;
  597.   JAR_Item *it;
  598.   JAR_Physical *phy;
  599.   Local = (struct ZipLocal *) PORT_ZAlloc (30);
  600.   Central = (struct ZipCentral *) PORT_ZAlloc (46);
  601.   End = (struct ZipEnd *) PORT_ZAlloc (22);
  602.   if (!Local || !Central || !End)
  603.     {
  604.     /* out of memory */
  605.     err = JAR_ERR_MEMORY;
  606.     goto loser;
  607.     }
  608.   while (1)
  609.     {
  610.     JAR_FSEEK (fp, pos, (PRSeekWhence)0);
  611.     if (JAR_FREAD (fp, (char *) sig, 4) != 4)
  612.       {
  613.       /* zip file ends prematurely */
  614.       err = JAR_ERR_CORRUPT;
  615.       goto loser;
  616.       }
  617.     JAR_FSEEK (fp, pos, (PRSeekWhence)0);
  618.     if (xtolong ((unsigned char *)sig) == LSIG)
  619.       {
  620.       JAR_FREAD (fp, (char *) Local, 30);
  621.       filename_len = xtoint ((unsigned char *) Local->filename_len);
  622.       extra_len = xtoint ((unsigned char *) Local->extrafield_len);
  623.       if (filename_len >= JAR_SIZE)
  624.         {
  625.         /* corrupt zip file */
  626.         err = JAR_ERR_CORRUPT;
  627.         goto loser;
  628.         }
  629.       if (JAR_FREAD (fp, filename, filename_len) != filename_len)
  630.         {
  631.         /* truncated archive file */
  632.         err = JAR_ERR_CORRUPT;
  633.         goto loser;
  634.         }
  635.       filename [filename_len] = 0;
  636.       /* Add this to our jar chain */
  637.       phy = (JAR_Physical *) PORT_ZAlloc (sizeof (JAR_Physical));
  638.       if (phy == NULL)
  639.         {
  640.         err = JAR_ERR_MEMORY;
  641.         goto loser;
  642.         }
  643.       /* We will index any file that comes our way, but when it comes
  644.          to actually extraction, compression must be 0 or 8 */
  645.       compression = xtoint ((unsigned char *) Local->method);
  646.       phy->compression = compression >= 0 && 
  647.               compression <= 255 ? compression : 222;
  648.       phy->offset = pos + 30 + filename_len + extra_len;
  649.       phy->length = xtolong ((unsigned char *) Local->size);
  650.       phy->uncompressed_length = xtolong((unsigned char *) Local->orglen);
  651.       dosdate (date, Local->date);
  652.       dostime (time, Local->time);
  653.       it = (JAR_Item*)PORT_ZAlloc (sizeof (JAR_Item));
  654.       if (it == NULL)
  655.         {
  656.         err = JAR_ERR_MEMORY;
  657.         goto loser;
  658.         }
  659.       it->pathname = PORT_Strdup (filename);
  660.       it->type = jarTypePhy;
  661.       it->data = (unsigned char *) phy;
  662.       it->size = sizeof (JAR_Physical);
  663.       ent = ZZ_NewLink (it);
  664.       if (ent == NULL)
  665.         {
  666.         err = JAR_ERR_MEMORY;
  667.         goto loser;
  668.         }
  669.       ZZ_AppendLink (jar->phy, ent);
  670.  
  671.       pos = phy->offset + phy->length;
  672.       }
  673.     else if (xtolong ( (unsigned char *)sig) == CSIG)
  674.       {
  675.       if (JAR_FREAD (fp, (char *) Central, 46) != 46)
  676.         {
  677.         /* apparently truncated archive */
  678.         err = JAR_ERR_CORRUPT;
  679.         goto loser;
  680.         }
  681. #ifdef XP_UNIX
  682.       /* with unix we need to locate any bits from 
  683.          the protection mask in the external attributes. */
  684.         {
  685.         unsigned int attr;
  686.         /* determined empirically */
  687.         attr = Central->external_attributes [2];
  688.         if (attr)
  689.           {
  690.           /* we have to read the filename, again */
  691.           filename_len = xtoint ((unsigned char *) Central->filename_len);
  692.           if (filename_len >= JAR_SIZE)
  693.             {
  694.             /* corrupt in central directory */
  695.             err = JAR_ERR_CORRUPT;
  696.             goto loser;
  697.             }
  698.           if (JAR_FREAD (fp, filename, filename_len) != filename_len)
  699.             {
  700.             /* truncated in central directory */
  701.             err = JAR_ERR_CORRUPT;
  702.             goto loser;
  703.             }
  704.           filename [filename_len] = 0;
  705.           /* look up this name again */
  706.           phy = jar_get_physical (jar, filename);
  707.           if (phy)
  708.             {
  709.             /* always allow access by self */
  710.             phy->mode = 0400 | attr;
  711.             }
  712.           }
  713.         }
  714. #endif
  715.       pos += 46 + xtoint ( (unsigned char *)Central->filename_len)
  716.                 + xtoint ( (unsigned char *)Central->commentfield_len)
  717.                 + xtoint ( (unsigned char *)Central->extrafield_len);
  718.       }
  719.     else if (xtolong ( (unsigned char *)sig) == ESIG)
  720.       {
  721.       if (JAR_FREAD (fp, (char *) End, 22) != 22)
  722.         {
  723.         err = JAR_ERR_CORRUPT;
  724.         goto loser;
  725.         }
  726.       else
  727.         break;
  728.       }
  729.     else
  730.       {
  731.       /* garbage in archive */
  732.       err = JAR_ERR_CORRUPT;
  733.       goto loser;
  734.       }
  735.     }
  736. loser:
  737.   if (Local) PORT_Free (Local);
  738.   if (Central) PORT_Free (Central);
  739.   if (End) PORT_Free (End);
  740.   return err;
  741.   }
  742. /*
  743.  *  j a r _ l i s t t a r
  744.  *
  745.  *  List the physical contents of a Unix 
  746.  *  .tar file into the JAR linked list.
  747.  *
  748.  */
  749. static int jar_listtar (JAR *jar, JAR_FILE fp)
  750.   {
  751.   long pos = 0L;
  752.   long sz, mode;
  753.   time_t when;
  754.   union TarEntry tarball;
  755.   char *s;
  756.   /* phy things */
  757.   ZZLink  *ent;
  758.   JAR_Item *it;
  759.   JAR_Physical *phy;
  760.   while (1)
  761.     {
  762.     JAR_FSEEK (fp, pos, (PRSeekWhence)0);
  763.     if (JAR_FREAD (fp, (char *) &tarball, 512) < 512)
  764.       break;
  765.     if (!*tarball.val.filename)
  766.       break;
  767.     when = atoo (tarball.val.time);
  768.     sz = atoo (tarball.val.size);
  769.     mode = atoo (tarball.val.mode);
  770.     /* Tag the end of filename */
  771.     s = tarball.val.filename;
  772.     while (*s && *s != ' ') s++;
  773.     *s = 0;
  774.     /* Add to our linked list */
  775.     phy = (JAR_Physical *) PORT_ZAlloc (sizeof (JAR_Physical));
  776.     if (phy == NULL)
  777.       return JAR_ERR_MEMORY;
  778.     phy->compression = 0;
  779.     phy->offset = pos + 512;
  780.     phy->length = sz;
  781.     ADDITEM (jar->phy, jarTypePhy, 
  782.        tarball.val.filename, phy, sizeof (JAR_Physical));
  783.     /* Advance to next file entry */
  784.     sz += 511;
  785.     sz = (sz / 512) * 512;
  786.     pos += sz + 512;
  787.     }
  788.   return 0;
  789.   }
  790. /*
  791.  *  d o s d a t e
  792.  *
  793.  *  Not used right now, but keep it in here because
  794.  *  it will be needed. 
  795.  *
  796.  */
  797. static int dosdate (char *date, char *s)
  798.   {
  799.   int num = xtoint ( (unsigned char *)s);
  800.   PR_snprintf (date, 9, "%02d-%02d-%02d",
  801.      ((num >> 5) & 0x0F), (num & 0x1F), ((num >> 9) + 80));
  802.   return 0;
  803.   }
  804. /*
  805.  *  d o s t i m e
  806.  *
  807.  *  Not used right now, but keep it in here because
  808.  *  it will be needed. 
  809.  *
  810.  */
  811. static int dostime (char *time, char *s)
  812.   {
  813.   int num = xtoint ( (unsigned char *)s);
  814.   PR_snprintf (time, 6, "%02d:%02d",
  815.      ((num >> 11) & 0x1F), ((num >> 5) & 0x3F));
  816.   return 0;
  817.   }
  818. /*
  819.  *  x t o i n t
  820.  *
  821.  *  Converts a two byte ugly endianed integer
  822.  *  to our platform's integer.
  823.  *
  824.  */
  825. static unsigned int xtoint (unsigned char *ii)
  826.   {
  827.   return (int) (ii [0]) | ((int) ii [1] << 8);
  828.   }
  829. /*
  830.  *  x t o l o n g
  831.  *
  832.  *  Converts a four byte ugly endianed integer
  833.  *  to our platform's integer.
  834.  *
  835.  */
  836. static unsigned long xtolong (unsigned char *ll)
  837.   {
  838.   unsigned long ret;
  839.   ret =  (
  840.          (((unsigned long) ll [0]) <<  0) |
  841.          (((unsigned long) ll [1]) <<  8) |
  842.          (((unsigned long) ll [2]) << 16) |
  843.          (((unsigned long) ll [3]) << 24)
  844.          );
  845.   return ret;
  846.   }
  847. /*
  848.  *  a t o o
  849.  *
  850.  *  Ascii octal to decimal.
  851.  *  Used for integer encoding inside tar files.
  852.  *
  853.  */
  854. static long atoo (char *s)
  855.   {
  856.   long num = 0L;
  857.   while (*s == ' ') s++;
  858.   while (*s >= '0' && *s <= '7')
  859.     {
  860.     num <<= 3;
  861.     num += *s++ - '0';
  862.     }
  863.   return num;
  864.   }
  865. /*
  866.  *  g u e s s _ j a r
  867.  *
  868.  *  Try to guess what kind of JAR file this is.
  869.  *  Maybe tar, maybe zip. Look in the file for magic
  870.  *  or at its filename.
  871.  *
  872.  */
  873. static int jar_guess_jar (char *filename, JAR_FILE fp)
  874.   {
  875.   char *ext;
  876.   ext = filename + PORT_Strlen (filename) - 4;
  877.   if (!PORT_Strcmp (ext, ".tar"))
  878.     return jarArchTar;
  879.   return jarArchZip;
  880.   }