home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / UNZP50P1.ZIP / extract.c < prev    next >
C/C++ Source or Header  |  1993-01-23  |  38KB  |  1,045 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   extract.c
  4.  
  5.   This file contains the high-level routines ("driver routines") for extrac-
  6.   ting and testing zipfile members.  It calls the low-level routines in files
  7.   inflate.c, unimplod.c, unreduce.c and unshrink.c.
  8.  
  9.   ---------------------------------------------------------------------------*/
  10.  
  11.  
  12. #include "unzip.h"
  13. #ifdef  MSWIN
  14. #  include "wizunzip.h"
  15. #  include "replace.h"
  16. #endif /* MSWIN */
  17.  
  18.  
  19. /************************************/
  20. /*  Extract Local Prototypes, etc.  */
  21. /************************************/
  22.  
  23. static int store_info __((void));
  24. static int extract_or_test_member __((void));
  25. #ifdef CRYPT
  26.    static int decrypt_member __((void));
  27.    static int testp __((byte *hdr));
  28. #endif
  29.  
  30. static byte *mem_i_buffer;
  31. static byte *mem_o_buffer;
  32. static ULONG mem_i_size, mem_i_offset;
  33. static ULONG mem_o_size, mem_o_offset;
  34.  
  35. static char *VersionMsg =
  36.   " skipping: %-22s  need %s compat. v%u.%u (can do v%u.%u)\n";
  37. static char *ComprMsg =
  38.   " skipping: %-22s  compression method %d\n";
  39. static char *FilNamMsg =
  40.   "%s:  bad filename length (%s)\n";
  41. static char *ExtFieldMsg =
  42.   "%s:  bad extra field length (%s)\n";
  43. static char *OffsetMsg =
  44.   "file #%d:  bad zipfile offset (%s)\n";
  45.  
  46.  
  47.  
  48.  
  49.  
  50. /**************************************/
  51. /*  Function extract_or_test_files()  */
  52. /**************************************/
  53.  
  54. int extract_or_test_files()    /* return PK-type error code */
  55. {
  56.     char **fnamev;
  57.     byte *cd_inptr;
  58.     int cd_incnt, error, error_in_archive=0;
  59.     int renamed, query, len, filnum=(-1), blknum=0;
  60. #ifdef OS2
  61.     extern int longname;  /* from os2unzip.c */
  62. #endif
  63.     UWORD i, j, members_remaining, num_skipped=0, num_bad_pwd=0;
  64.     longint cd_bufstart, bufstart, inbuf_offset, request;
  65.     min_info info[DIR_BLKSIZ];
  66.  
  67.  
  68. /*---------------------------------------------------------------------------
  69.     The basic idea of this function is as follows.  Since the central di-
  70.     rectory lies at the end of the zipfile and the member files lie at the
  71.     beginning or middle or wherever, it is not very desirable to simply
  72.     read a central directory entry, jump to the member and extract it, and
  73.     then jump back to the central directory.  In the case of a large zipfile
  74.     this would lead to a whole lot of disk-grinding, especially if each mem-
  75.     ber file is small.  Instead, we read from the central directory the per-
  76.     tinent information for a block of files, then go extract/test the whole
  77.     block.  Thus this routine contains two small(er) loops within a very
  78.     large outer loop:  the first of the small ones reads a block of files
  79.     from the central directory; the second extracts or tests each file; and
  80.     the outer one loops over blocks.  There's some file-pointer positioning
  81.     stuff in between, but that's about it.  Btw, it's because of this jump-
  82.     ing around that we can afford to be lenient if an error occurs in one of
  83.     the member files:  we should still be able to go find the other members,
  84.     since we know the offset of each from the beginning of the zipfile.
  85.  
  86.     Begin main loop over blocks of member files.  We know the entire central
  87.     directory is on this disk:  we would not have any of this information un-
  88.     less the end-of-central-directory record was on this disk, and we would
  89.     not have gotten to this routine unless this is also the disk on which
  90.     the central directory starts.  In practice, this had better be the ONLY
  91.     disk in the archive, but maybe someday we'll add multi-disk support.
  92.   ---------------------------------------------------------------------------*/
  93.  
  94.     pInfo = info;
  95.     members_remaining = ecrec.total_entries_central_dir;
  96.  
  97.     while (members_remaining) {
  98.         j = 0;
  99.  
  100.         /*
  101.          * Loop through files in central directory, storing offsets, file
  102.          * attributes, and case-conversion flags until block size is reached.
  103.          */
  104.  
  105.         while (members_remaining && (j < DIR_BLKSIZ)) {
  106.             --members_remaining;
  107.             pInfo = &info[j];
  108.  
  109.             if (readbuf(sig, 4) <= 0) {
  110.                 error_in_archive = 51;  /* 51:  unexpected EOF */
  111.                 members_remaining = 0;  /* ...so no more left to do */
  112.                 break;
  113.             }
  114.             if (strncmp(sig, central_hdr_sig, 4)) {  /* just to make sure */
  115.                 fprintf(stderr, CentSigMsg, j);  /* sig not found */
  116.                 fprintf(stderr, ReportMsg);   /* check binary transfers */
  117.                 error_in_archive = 3;   /* 3:  error in zipfile */
  118.                 members_remaining = 0;  /* ...so no more left to do */
  119.                 break;
  120.             }
  121.             /* process_cdir_file_hdr() sets pInfo->hostnum, pInfo->lcflag */
  122.             if ((error = process_cdir_file_hdr()) != 0) {
  123.                 error_in_archive = error;   /* only 51 (EOF) defined */
  124.                 members_remaining = 0;  /* ...so no more left to do */
  125.                 break;
  126.             }
  127.             if ((error = do_string(crec.filename_length, FILENAME)) != 0) {
  128.                 if (error > error_in_archive)
  129.                     error_in_archive = error;
  130.                 if (error > 1) {  /* fatal:  no more left to do */
  131.                     fprintf(stderr, FilNamMsg, filename, "central");
  132.                     members_remaining = 0;
  133.                     break;
  134.                 }
  135.             }
  136.             if ((error = do_string(crec.extra_field_length, EXTRA_FIELD)) != 0)
  137.             {
  138.                 if (error > error_in_archive)
  139.                     error_in_archive = error;
  140.                 if (error > 1) {  /* fatal */
  141.                     fprintf(stderr, ExtFieldMsg, filename, "central");
  142.                     members_remaining = 0;
  143.                     break;
  144.                 }
  145.             }
  146.             if ((error = do_string(crec.file_comment_length, SKIP)) != 0) {
  147.                 if (error > error_in_archive)
  148.                     error_in_archive = error;
  149.                 if (error > 1) {  /* fatal */
  150.                     fprintf(stderr, "\n%s:  bad file comment length\n",
  151.                             filename);
  152.                     members_remaining = 0;
  153.                     break;
  154.                 }
  155.             }
  156.             if (process_all_files) {
  157.                 if (store_info())
  158.                     ++num_skipped;
  159.                 else
  160.                     ++j;  /* file is OK: save info[] and continue with next */
  161.             } else {
  162.                 fnamev = fnv;   /* don't destroy permanent filename pointer */
  163.                 for (--fnamev; *++fnamev;)
  164.                     if (match(filename, *fnamev)) {
  165.                         if (store_info())
  166.                             ++num_skipped;
  167.                         else
  168.                             ++j;   /* file is OK */
  169.                         break;  /* found match for filename, so stop looping */
  170.                     } /* end if (match), for-loop (fnamev) */
  171.             } /* end if (process_all_files) */
  172.  
  173.         } /* end while-loop (adding files to current block) */
  174.  
  175.         /* save position in central directory so can come back later */
  176.         cd_bufstart = cur_zipfile_bufstart;
  177.         cd_inptr = inptr;
  178.         cd_incnt = incnt;
  179.  
  180.     /*-----------------------------------------------------------------------
  181.         Second loop:  process files in current block, extracting or testing
  182.         each one.
  183.       -----------------------------------------------------------------------*/
  184.  
  185.         for (i = 0; i < j; ++i) {
  186.             filnum = i + blknum*DIR_BLKSIZ;
  187.             pInfo = &info[i];
  188.             /*
  189.              * if the target position is not within the current input buffer
  190.              * (either haven't yet read far enough, or (maybe) skipping back-
  191.              * ward) skip to the target position and reset readbuf().
  192.              */
  193.             /* LSEEK(pInfo->offset):  */
  194.             request = pInfo->offset + extra_bytes;
  195.             inbuf_offset = request % INBUFSIZ;
  196.             bufstart = request - inbuf_offset;
  197.  
  198.             if (request < 0) {
  199.                 fprintf(stderr, SeekMsg, ReportMsg);
  200.                 error_in_archive = 3;       /* 3:  severe error in zipfile, */
  201.                 continue;                   /*  but can still go on */
  202.             } else if (bufstart != cur_zipfile_bufstart) {
  203.                 cur_zipfile_bufstart = lseek(zipfd, bufstart, SEEK_SET);
  204.                 if ((incnt = read(zipfd,(char *)inbuf,INBUFSIZ)) <= 0) {
  205.                     fprintf(stderr, OffsetMsg, filnum, "lseek");
  206.                     error_in_archive = 3;   /* 3:  error in zipfile, but */
  207.                     continue;               /*  can still do next file   */
  208.                 }
  209.                 inptr = inbuf + (int)inbuf_offset;
  210.                 incnt -= (int)inbuf_offset;
  211.             } else {
  212.                 incnt += (inptr-inbuf) - (int)inbuf_offset;
  213.                 inptr = inbuf + (int)inbuf_offset;
  214.             }
  215.  
  216.             /* should be in proper position now, so check for sig */
  217.             if (readbuf(sig, 4) <= 0) {  /* bad offset */
  218.                 fprintf(stderr, OffsetMsg, filnum, "EOF");
  219.                 error_in_archive = 3;    /* 3:  error in zipfile */
  220.                 continue;       /* but can still try next one */
  221.             }
  222.             if (strncmp(sig, local_hdr_sig, 4)) {
  223.                 fprintf(stderr, OffsetMsg, filnum,
  224.                         "can't find local header sig");   /* bad offset */
  225.                 error_in_archive = 3;
  226.                 continue;
  227.             }
  228.             if ((error = process_local_file_hdr()) != 0) {
  229.                 fprintf(stderr, "\nfile #%d:  bad local header\n", filnum);
  230.                 error_in_archive = error;       /* only 51 (EOF) defined */
  231.                 continue;       /* can still try next one */
  232.             }
  233.             if ((error = do_string(lrec.filename_length, FILENAME)) != 0) {
  234.                 if (error > error_in_archive)
  235.                     error_in_archive = error;
  236.                 if (error > 1) {
  237.                     fprintf(stderr, FilNamMsg, filename, "local");
  238.                     continue;   /* go on to next one */
  239.                 }
  240.             }
  241.             if (extra_field != (byte *)NULL)
  242.                 free(extra_field);
  243.             extra_field = (byte *)NULL;
  244.             if ((error = do_string(lrec.extra_field_length, EXTRA_FIELD)) != 0)
  245.             {
  246.                 if (error > error_in_archive)
  247.                     error_in_archive = error;
  248.                 if (error > 1) {
  249.                     fprintf(stderr, ExtFieldMsg, filename, "local");
  250.                     continue;   /* go on */
  251.                 }
  252.             }
  253.  
  254.             /*
  255.              * just about to extract file:  if extracting to disk, check if
  256.              * already exists, and if so, take appropriate action according to
  257.              * fflag/uflag/overwrite_all/etc. (we couldn't do this in upper
  258.              * loop because we don't store the possibly renamed filename[] in
  259.              * info[])
  260.              */
  261.             if (!tflag && !cflag) {
  262.                 renamed = FALSE;   /* user hasn't renamed output file yet */
  263. #ifdef OS2
  264.                 longname = FALSE;  /* no long name has yet been stored */
  265. #endif
  266.  
  267. startover:
  268.                 query = FALSE;
  269. #ifdef MACOS
  270.                 macflag = (pInfo->hostnum == MAC_);
  271. #endif
  272.                 /* mapname can create dirs if not freshening or if renamed */
  273.                 if ((error = mapname(!fflag || renamed)) > 1) {    /* skip */
  274.                     if ((error > 2) && (error_in_archive < 2))
  275.                         error_in_archive = 2;   /* (weak) error in zipfile */
  276.                     continue;   /* go on to next file */
  277.                 }
  278.  
  279.                 switch (check_for_newer(filename)) {
  280.                     case DOES_NOT_EXIST:
  281.                         if (fflag && !renamed)  /* don't skip if just renamed */
  282.                             continue;   /* freshen (no new files):  skip */
  283.                         break;
  284.                     case EXISTS_AND_OLDER:
  285.                         if (overwrite_none)
  286.                             continue;   /* never overwrite:  skip file */
  287.                         if (!overwrite_all && !force_flag)
  288.                             query = TRUE;
  289.                         break;
  290.                     case EXISTS_AND_NEWER:             /* (or equal) */
  291.                         if (overwrite_none || (uflag && !renamed))
  292.                             continue;  /* skip if update/freshen & orig name */
  293.                         if (!overwrite_all && !force_flag)
  294.                             query = TRUE;
  295.                         break;
  296.                 }
  297. /*#ifndef VMS*/ /* VMS creates higher version number instead of overwriting
  298.                  * (will have to modify for VMS-style names with specific
  299.                  *  version numbers:  just check V_flag?  don't use stat?) */
  300.                 if (query) {
  301. #ifdef MSWIN
  302.                     FARPROC lpfnprocReplace;
  303.                     int ReplaceDlgRetVal;   /* replace dialog return value */
  304.  
  305.                     ShowCursor(FALSE);      /* turn off cursor */
  306.                     SetCursor(hSaveCursor); /* restore the cursor */
  307.                     lpfnprocReplace = MakeProcInstance(ReplaceProc, hInst);
  308.                     ReplaceDlgRetVal = DialogBoxParam(hInst, "Replace",
  309.                       hWndMain, lpfnprocReplace, (DWORD)(LPSTR)filename);
  310.                     FreeProcInstance(lpfnprocReplace);
  311.                     hSaveCursor = SetCursor(hHourGlass);
  312.                     ShowCursor(TRUE);
  313.                     switch (ReplaceDlgRetVal) {
  314.                         case IDM_REPLACE_RENAME:
  315.                             renamed = TRUE;
  316.                             goto startover;   /* sorry for a goto */
  317.                         case IDM_REPLACE_YES:
  318.                             break;
  319.                         case IDM_REPLACE_ALL:
  320.                             overwrite_all = TRUE;
  321.                             overwrite_none = FALSE;  /* just to make sure */
  322.                             break;
  323.                         case IDM_REPLACE_NONE:
  324.                             overwrite_none = TRUE;
  325.                             overwrite_all = FALSE;  /* make sure */
  326.                             force_flag = FALSE;     /* ditto */
  327.                             /* FALL THROUGH, skip */
  328.                         case IDM_REPLACE_NO:
  329.                             continue;
  330.                     }
  331. #else /* !MSWIN */
  332. reprompt:
  333.                     fprintf(stderr,
  334.                       "replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ",
  335.                       filename);
  336.                     FFLUSH   /* for Amiga and Mac MPW */
  337.                     fgets(answerbuf, 9, stdin);
  338.                     switch (*answerbuf) {
  339.                         case 'A':   /* dangerous option:  force caps */
  340.                             overwrite_all = TRUE;
  341.                             overwrite_none = FALSE;  /* just to make sure */
  342.                             break;
  343.                         case 'r':
  344.                         case 'R':
  345.                             do {
  346.                                 fprintf(stderr, "new name: ");
  347.                                 FFLUSH   /* for AMIGA and Mac MPW */
  348.                                 fgets(filename, FILNAMSIZ, stdin);
  349.                                 /* usually get \n here:  better check for it */
  350.                                 len = strlen(filename);
  351.                                 if (filename[len-1] == '\n')
  352.                                     filename[--len] = 0;
  353.                             } while (len == 0);
  354.                             renamed = TRUE;
  355.                             goto startover;   /* sorry for a goto */
  356.                         case 'y':
  357.                         case 'Y':
  358.                             break;
  359.                         case 'N':
  360.                             overwrite_none = TRUE;
  361.                             overwrite_all = FALSE;  /* make sure */
  362.                             force_flag = FALSE;     /* ditto */
  363.                             /* FALL THROUGH, skip */
  364.                         case 'n':
  365.                             continue;   /* skip file */
  366.                         default:
  367.                             fprintf(stderr, "error:  invalid response [%c]\n",
  368.                               *answerbuf);   /* warn the user */
  369.                             goto reprompt;   /* why not another goto? */
  370.                     } /* end switch (*answerbuf) */
  371. #endif /* ?MSWIN */
  372.                 } /* end if (query) */
  373. /*#endif*/ /* !VMS */
  374.             } /* end if (extracting to disk) */
  375.  
  376. #ifdef CRYPT
  377.             if (pInfo->encrypted && ((error = decrypt_member()) != 0)) {
  378.                 if (error == 10) {
  379.                     if (error > error_in_archive)
  380.                         error_in_archive = error;
  381.                     fprintf(stderr,
  382.                       " skipping: %-22s  unable to get password\n", filename);
  383.                 } else {  /* (error == 1) */
  384.                     fprintf(stderr,
  385.                       " skipping: %-22s  incorrect password\n", filename);
  386.                     ++num_bad_pwd;
  387.                 }
  388.                 continue;   /* go on to next file */
  389.             }
  390. #endif /* CRYPT */
  391.             disk_full = 0;
  392.             if ((error = extract_or_test_member()) != 0) {
  393.                 if (error > error_in_archive)
  394.                     error_in_archive = error;       /* ...and keep going */
  395.                 if (disk_full > 1)
  396.                     return error_in_archive;        /* (unless disk full) */
  397.             }
  398.         } /* end for-loop (i:  files in current block) */
  399.  
  400.  
  401.         /*
  402.          * Jump back to where we were in the central directory, then go and do
  403.          * the next batch of files.
  404.          */
  405.  
  406.         cur_zipfile_bufstart = lseek(zipfd, cd_bufstart, SEEK_SET);
  407.         read(zipfd, (char *)inbuf, INBUFSIZ);  /* were there b4 ==> no error */
  408.         inptr = cd_inptr;
  409.         incnt = cd_incnt;
  410.         ++blknum;
  411.  
  412. #ifdef TEST
  413.         printf("\ncd_bufstart = %ld (%.8lXh)\n", cd_bufstart, cd_bufstart);
  414.         printf("cur_zipfile_bufstart = %ld (%.8lXh)\n", cur_zipfile_bufstart,
  415.           cur_zipfile_bufstart);
  416.         printf("inptr-inbuf = %d\n", inptr-inbuf);
  417.         printf("incnt = %d\n\n", incnt);
  418. #endif
  419.  
  420.     } /* end while-loop (blocks of files in central directory) */
  421.  
  422. /*---------------------------------------------------------------------------
  423.     Double-check that we're back at the end-of-central-directory record, and
  424.     print quick summary of results, if we were just testing the archive.  We
  425.     send the summary to stdout so that people doing the testing in the back-
  426.     ground and redirecting to a file can just do a "tail" on the output file.
  427.   ---------------------------------------------------------------------------*/
  428.  
  429.     readbuf(sig, 4);
  430.     if (strncmp(sig, end_central_sig, 4)) {     /* just to make sure again */
  431.         fprintf(stderr, EndSigMsg);  /* didn't find end-of-central-dir sig */
  432.         fprintf(stderr, ReportMsg);  /* check binary transfers */
  433.         if (!error_in_archive)       /* don't overwrite stronger error */
  434.             error_in_archive = 1;    /* 1:  warning error */
  435.     }
  436.     if (tflag && (quietflg == 1)) {
  437.         int num=filnum+1 - num_bad_pwd;
  438.  
  439.         if (error_in_archive)
  440.             printf("At least one error was detected in %s.\n", zipfn);
  441.         else if (num == 0)
  442.             printf("Caution:  zero files tested in %s.\n", zipfn);
  443.         else if (process_all_files && (num_skipped+num_bad_pwd == 0))
  444.             printf("No errors detected in %s.\n", zipfn);
  445.         else
  446.             printf("No errors detected in %s for the %d file%s tested.\n",
  447.               zipfn, num, (num==1)? "":"s");
  448.         if (num_skipped > 0)
  449.             printf("%d file%s skipped because of unsupported compression or\
  450.  encoding.\n",
  451.               num_skipped, (num_skipped==1)? "":"s");
  452. #ifdef CRYPT
  453.         if (num_bad_pwd > 0)
  454.             printf("%d file%s skipped because of incorrect password.\n",
  455.               num_bad_pwd, (num_bad_pwd==1)? "":"s");
  456. #endif /* CRYPT */
  457.     }
  458.     if ((num_skipped > 0) && !error_in_archive)   /* files not tested or  */
  459.         error_in_archive = 1;                     /*  extracted:  warning */
  460. #ifdef CRYPT
  461.     if ((num_bad_pwd > 0) && !error_in_archive)   /* files not tested or  */
  462.         error_in_archive = 1;                     /*  extracted:  warning */
  463. #endif /* CRYPT */
  464.  
  465.     return (error_in_archive);
  466.  
  467. } /* end function extract_or_test_files() */
  468.  
  469.  
  470.  
  471.  
  472.  
  473. /***************************/
  474. /*  Function store_info()  */
  475. /***************************/
  476.  
  477. static int store_info()   /* return 1 if skipping, 0 if OK */
  478. {
  479.     ULONG tmp;
  480.  
  481. #define UNKN_COMPR \
  482.    (crec.compression_method>IMPLODED && crec.compression_method!=DEFLATED)
  483. #if 0  /* old */
  484. #  define UNKN_COMPR   (crec.compression_method>IMPLODED)
  485. #endif
  486.  
  487.  
  488. /*---------------------------------------------------------------------------
  489.     Check central directory info for version/compatibility requirements.
  490.   ---------------------------------------------------------------------------*/
  491.  
  492.     pInfo->encrypted = crec.general_purpose_bit_flag & 1;    /* bit field */
  493.     pInfo->ExtLocHdr = (crec.general_purpose_bit_flag & 8) == 8;  /* bit */
  494.     pInfo->text = crec.internal_file_attributes & 1;         /* bit field */
  495.     pInfo->crc = crec.crc32;
  496.     pInfo->compr_size = crec.compressed_size;
  497.  
  498.     if (crec.version_needed_to_extract[1] == VMS_) {
  499.         if (crec.version_needed_to_extract[0] > VMS_VERSION) {
  500.             fprintf(stderr, VersionMsg, filename, "VMS",
  501.               crec.version_needed_to_extract[0] / 10,
  502.               crec.version_needed_to_extract[0] % 10,
  503.               VMS_VERSION / 10, VMS_VERSION % 10);
  504.             return 1;
  505.         }
  506. #ifndef VMS   /* won't be able to use extra field, but still have data */
  507.         else if (!tflag && !force_flag) {  /* if forcing, extract regardless */
  508.             fprintf(stderr,
  509.               "\n%s:  stored in VMS format.  Extract anyway? (y/n) ",
  510.               filename);
  511.             FFLUSH   /* for Amiga and Mac MPW */
  512.             fgets(answerbuf, 9, stdin);
  513.             if ((*answerbuf != 'y') && (*answerbuf != 'Y'))
  514.                 return 1;
  515.         }
  516. #endif /* !VMS */
  517.     /* usual file type:  don't need VMS to extract */
  518.     } else if (crec.version_needed_to_extract[0] > UNZIP_VERSION) {
  519.         fprintf(stderr, VersionMsg, filename, "PK",
  520.           crec.version_needed_to_extract[0] / 10,
  521.           crec.version_needed_to_extract[0] % 10,
  522.           UNZIP_VERSION / 10, UNZIP_VERSION % 10);
  523.         return 1;
  524.     }
  525.  
  526.     if UNKN_COMPR {
  527.         fprintf(stderr, ComprMsg, filename, crec.compression_method);
  528.         return 1;
  529.     }
  530. #ifndef CRYPT
  531.     if (pInfo->encrypted) {
  532.         fprintf(stderr, " skipping: %-22s  encrypted (not supported)\n",
  533.           filename);
  534.         return 1;
  535.     }
  536. #endif /* !CRYPT */
  537.  
  538. /*---------------------------------------------------------------------------
  539.     Store some central-directory information (encryption, file attributes,
  540.     offsets) for later use.
  541.   ---------------------------------------------------------------------------*/
  542.  
  543.     tmp = crec.external_file_attributes;
  544.  
  545.     pInfo->dos_attr = 32;   /* set archive bit:  file is not backed up */
  546.     switch (pInfo->hostnum) {
  547.         case UNIX_:
  548.         case VMS_:
  549.             pInfo->unix_attr = (unsigned) (tmp >> 16);
  550.             break;
  551.         case DOS_OS2_FAT_:
  552.         case OS2_HPFS_:
  553.             pInfo->dos_attr = (unsigned) tmp;
  554.             tmp = (!(tmp & 1)) << 1;   /* read-only bit */
  555.             pInfo->unix_attr = (unsigned) (0444 | (tmp<<6) | (tmp<<3) | tmp);
  556. #ifdef UNIX
  557.             umask( (int)(tmp=umask(0)) );
  558.             pInfo->unix_attr &= ~tmp;
  559. #endif
  560.             break;
  561.         case MAC_:
  562.             pInfo->unix_attr = (unsigned) (tmp & 1);   /* read-only bit */
  563.             break;
  564.         default:
  565.             pInfo->unix_attr = 0666;
  566.             break;
  567.     } /* end switch (host-OS-created-by) */
  568.  
  569.     pInfo->offset = (longint) crec.relative_offset_local_header;
  570.     return 0;
  571.  
  572. } /* end function store_info() */
  573.  
  574.  
  575.  
  576.  
  577.  
  578. /***************************************/
  579. /*  Function extract_or_test_member()  */
  580. /***************************************/
  581.  
  582. static int extract_or_test_member()    /* return PK-type error code */
  583. {
  584. #ifdef S_IFLNK
  585.     int symlnk=FALSE;
  586. #endif /* S_IFLNK */
  587.     int error=0;
  588.     UWORD b;
  589.  
  590.  
  591.  
  592. /*---------------------------------------------------------------------------
  593.     Initialize variables, buffers, etc.
  594.   ---------------------------------------------------------------------------*/
  595.  
  596.     bits_left = 0;
  597.     bitbuf = 0L;
  598.     outpos = 0L;
  599.     outcnt = 0;
  600.     outptr = outbuf;
  601.     zipeof = 0;
  602.     crc32val = 0xFFFFFFFFL;
  603.  
  604. #ifdef S_IFLNK
  605.     if ((pInfo->unix_attr & S_IFMT) == S_IFLNK  &&  (pInfo->hostnum == UNIX_)
  606.         && !tflag && !cflag)
  607.         symlnk = TRUE;
  608. #endif /* S_IFLNK */
  609.  
  610.     memset(outbuf, 0xaa, OUTBUFSIZ);
  611. #if (!defined(DOS_OS2) || defined(MSWIN))
  612.     if (aflag)                  /* if we have a scratchpad, clear it out */
  613. #ifdef MSWIN
  614.         _fmemset(outout, 0xaa, OUTBUFSIZ);
  615. #else /* !MSWIN */
  616.         memset(outout, 0xaa, OUTBUFSIZ);
  617. #endif /* ?MSWIN */
  618. #endif /* !DOS_OS2 || MSWIN */
  619.  
  620.     if (tflag) {
  621.         if (!quietflg) {
  622.             fprintf(stdout, "  Testing: %-22s ", filename);
  623.             fflush(stdout);
  624.         }
  625.     } else {
  626.         if (cflag) {            /* output to stdout (copy of it) */
  627. #if (defined(MACOS) || defined(AMIGA))
  628.             outfd = 1;
  629. #else /* !(MACOS || AMIGA) */
  630.             outfd = dup(1);     /* GRR: change this to #define for Mac/Amiga */
  631. #endif /* ?(MACOS || AMIGA) */
  632. #ifdef DOS_OS2
  633.             if (!aflag)
  634.                 setmode(outfd, O_BINARY);
  635. #endif /* DOS_OS2 */
  636. #ifdef VMS
  637.             if (create_output_file())   /* VMS version required for stdout! */
  638.                 return 50;      /* 50:  disk full (?) */
  639. #endif
  640.         } else
  641. #ifdef S_IFLNK
  642.         if (!symlnk)    /* symlink() takes care of file creation */
  643. #endif /* !S_IFLNK */
  644.         {
  645.             if (create_output_file())
  646.                 return 50;      /* 50:  disk full (?) */
  647.         }
  648.     } /* endif (!tflag) */
  649.  
  650. /*---------------------------------------------------------------------------
  651.     Unpack the file.
  652.   ---------------------------------------------------------------------------*/
  653.  
  654.     switch (lrec.compression_method) {
  655.  
  656.     case STORED:
  657.         if (!tflag && (quietflg < 2)) {
  658.             fprintf(stdout, " Extracting: %-22s ", filename);
  659.             if (cflag)
  660.                 fprintf(stdout, "\n");
  661.             fflush(stdout);
  662.         }
  663. #ifdef S_IFLNK
  664.         /*
  665.          * If file came from Unix and is a symbolic link and we are extracting
  666.          * to disk, allocate a storage area, put the data in it, and create the
  667.          * link.  Since we know it's a symbolic link to start with, shouldn't
  668.          * have to worry about overflowing unsigned ints with unsigned longs.
  669.          * (This doesn't do anything for compressed symlinks, but that can be
  670.          * added later...it also doesn't set the time or permissions of the
  671.          * link, but does anyone really care?)
  672.          */
  673.         if (symlnk) {
  674. #if (defined(MTS) || defined(MACOS))
  675.             fprintf(stdout, "\n  warning:  symbolic link ignored\n");
  676.             error = 1;          /* 1:  warning error */
  677. #else /* !(MTS || MACOS) */
  678.             char *orig = (char *)malloc((unsigned)lrec.uncompressed_size+1);
  679.             char *p = orig;
  680.  
  681.             while (ReadByte(&b))
  682.                 *p++ = b;
  683.             *p = 0;   /* terminate string */
  684.             UpdateCRC((unsigned char *)orig, p-orig);
  685.             if (symlink(orig, filename))
  686.                 if ((errno == EEXIST) && overwrite_all) {  /* OK to overwrite */
  687.                     unlink(filename);
  688.                     if (symlink(orig, filename))
  689.                         perror("symlink error");
  690.                 } else
  691.                     perror("symlink error");
  692.             free(orig);
  693. #endif /* ?(MTS || MACOS) */
  694.         } else
  695. #endif /* S_IFLNK */
  696.         while (ReadByte(&b) && !disk_full)
  697.             OUTB(b)
  698.         break;
  699.  
  700.     case SHRUNK:
  701.         if (!tflag && (quietflg < 2)) {
  702.             fprintf(stdout, "UnShrinking: %-22s ", filename);
  703.             if (cflag)
  704.                 fprintf(stdout, "\n");
  705.             fflush(stdout);
  706.         }
  707. #ifdef S_IFLNK   /* !!! This code needs to be added to unShrink, etc. !!! */
  708.         if (symlnk) {
  709.             fprintf(stdout, "\n  warning:  symbolic link ignored\n");
  710.             error = 1;          /* 1:  warning error */
  711.         }
  712. #endif /* S_IFLNK */
  713.         unShrink();
  714.         break;
  715.  
  716.     case REDUCED1:
  717.     case REDUCED2:
  718.     case REDUCED3:
  719.     case REDUCED4:
  720.         if (!tflag && (quietflg < 2)) {
  721.             fprintf(stdout, "  Expanding: %-22s ", filename);
  722.             if (cflag)
  723.                 fprintf(stdout, "\n");
  724.             fflush(stdout);
  725.         }
  726. #ifdef S_IFLNK   /* !!! This code needs to be added to unShrink, etc. !!! */
  727.         if (symlnk) {
  728.             fprintf(stdout, "\n  warning:  symbolic link ignored\n");
  729.             error = 1;          /* 1:  warning error */
  730.         }
  731. #endif /* S_IFLNK */
  732.         unReduce();
  733.         break;
  734.  
  735.     case IMPLODED:
  736.         if (!tflag && (quietflg < 2)) {
  737.             fprintf(stdout, "  Exploding: %-22s ", filename);
  738.             if (cflag)
  739.                 fprintf(stdout, "\n");
  740.             fflush(stdout);
  741.         }
  742. #ifdef S_IFLNK   /* !!! This code needs to be added to unShrink, etc. !!! */
  743.         if (symlnk) {
  744.             fprintf(stdout, "\n  warning:  symbolic link ignored\n");
  745.             error = 1;          /* 1:  warning error */
  746.         }
  747. #endif /* S_IFLNK */
  748.         explode();   /* ignore return code for now */
  749.         break;
  750.  
  751.     case DEFLATED:
  752.         if (!tflag && (quietflg < 2)) {
  753.             fprintf(stdout, "  Inflating: %-22s ", filename);
  754.             if (cflag)
  755.                 fprintf(stdout, "\n");
  756.             fflush(stdout);
  757.         }
  758. #ifdef S_IFLNK   /* !!! This code needs to be added to unShrink, etc. !!! */
  759.         if (symlnk) {
  760.             fprintf(stdout, "\n  warning:  symbolic link ignored\n");
  761.             error = 1;          /* 1:  warning error */
  762.         }
  763. #endif /* S_IFLNK */
  764.         inflate();
  765.         break;
  766.  
  767.     default:   /* should never get to this point */
  768.         fprintf(stderr, "%s:  unknown compression method\n", filename);
  769.         /* close and delete file before return? */
  770.         return 1;               /* 1:  warning error */
  771.  
  772.     } /* end switch (compression method) */
  773.  
  774.     if (disk_full) {            /* set by FlushOutput()/OUTB() macro */
  775.         if (disk_full > 1)
  776.             return 50;          /* 50:  disk full */
  777.         error = 1;              /* 1:  warning error */
  778.     }
  779.  
  780. /*---------------------------------------------------------------------------
  781.     Write the last partial buffer, if any; set the file date and time; and
  782.     close the file (not necessarily in that order).  Then make sure CRC came
  783.     out OK and print result.
  784.   ---------------------------------------------------------------------------*/
  785.  
  786. #ifdef S_IFLNK
  787.     if (!symlnk) {
  788. #endif /* S_IFLNK */
  789.     if (!disk_full && FlushOutput())
  790.         if (disk_full > 1)
  791.             return 50;          /* 50:  disk full */
  792.         else {                  /* disk_full == 1 */
  793.             fprintf(stderr, "%s:  probably corrupt\n", filename);
  794.             error = 1;          /* 1:  warning error */
  795.         }
  796.  
  797.     if (!tflag)
  798. #ifdef VMS
  799.         CloseOutputFile();
  800. #else /* !VMS */
  801. #ifdef MTS                      /* MTS can't set file time */
  802.         close(outfd);
  803. #else /* !MTS */
  804.         set_file_time_and_close();
  805. #endif /* ?MTS */
  806. #endif /* ?VMS */
  807.  
  808. #ifdef S_IFLNK
  809.     } /* endif (!symlnk) */
  810. #endif /* S_IFLNK */
  811.  
  812.     /* logical-AND crc32val for 64-bit machines */
  813.     if ((crc32val = ((~crc32val) & 0xFFFFFFFFL)) != lrec.crc32) {
  814.         /* if quietflg is set, we haven't output the filename yet:  do it */
  815.         if (quietflg)
  816.             printf("%-22s: ", filename);
  817.         fprintf(stdout, " Bad CRC %08lx  (should be %08lx)\n", crc32val,
  818.                 lrec.crc32);
  819.         error = 1;              /* 1:  warning error */
  820.     } else if (tflag) {
  821.         if (!quietflg)
  822.             fprintf(stdout, " OK\n");
  823.     } else {
  824.         if ((quietflg < 2) && !error)
  825.             fprintf(stdout, "\n");
  826.     }
  827.  
  828.     return error;
  829.  
  830. }       /* end function extract_or_test_member() */
  831.  
  832.  
  833.  
  834.  
  835.  
  836. #ifdef CRYPT
  837.  
  838. /*******************************/
  839. /*  Function decrypt_member()  */
  840. /*******************************/
  841.  
  842. static int decrypt_member()   /* return 10 if out of memory or can't get */
  843. {                             /*  tty; 1 if password bad; 0 if password OK */
  844.     UWORD b;
  845.     int n, r;
  846.     static int nopwd=FALSE;
  847.     char *m, *prompt;
  848.     byte h[12];
  849.  
  850.  
  851.     /* get header once */
  852.     for (n = 0; n < 12; n++) {
  853.         ReadByte(&b);
  854.         h[n] = (byte) b;
  855.     }
  856.  
  857.     /* if have key already, test it; else allocate memory for it */
  858.     if (key) {
  859.         if (!testp(h))
  860.             return 0;      /* existing password OK (else prompt for new) */
  861.         else if (nopwd)
  862.             return 1;      /* user indicated no more prompting */
  863.     } else if ((key = (char *)malloc(PWLEN+1)) == (char *)NULL)
  864.         return 10;
  865.  
  866.     if ((prompt = (char *)malloc(FILNAMSIZ+15)) != (char *)NULL) {
  867.         sprintf(prompt, "%s password: ", filename);
  868.         m = prompt;
  869.     } else
  870.         m = "Enter password: ";
  871.  
  872.     /* try a few keys */
  873.     for (r = 0;  r < 3;  ++r) {
  874.         m = getp(m, key, PWLEN+1);
  875.         if (prompt != (char *)NULL) {
  876.             free(prompt);
  877.             prompt = (char *)NULL;
  878.         }
  879.         if (m == (char *)NULL)
  880.             return 10;
  881.         if (!testp(h))
  882.             return 0;
  883.         if (*key == '\0') {
  884.             nopwd = TRUE;
  885.             return 1;
  886.         }
  887.         m = "password incorrect--reenter: ";
  888.     }
  889.     return 1;
  890. }
  891.  
  892.  
  893.  
  894.  
  895.  
  896. /**********************/
  897. /*  Function testp()  */
  898. /**********************/
  899.  
  900. static int testp(h)   /* return -1 if bad password; 0 if OK */
  901.     byte *h;
  902. {
  903.     UWORD b, c;
  904.     int n, t;
  905.     byte *p;
  906.  
  907.     /* set keys */
  908.     init_keys(key);
  909.  
  910.     /* check password */
  911.     for (n = 0; n < 11; n++)
  912.         c = DECRYPT(h[n]);
  913.     b = DECRYPT(h[11]);
  914.  
  915. #ifdef CRYPT_DEBUG
  916.     printf("   lrec.crc = %08lx  crec.crc = %08lx  pInfo->ExtLocHdr = %s\n",
  917.       lrec.crc32, pInfo->crc, pInfo->ExtLocHdr? "true":"false");
  918.     printf("   incnt = %d  unzip offset into zipfile = %ld\n", incnt,
  919.       cur_zipfile_bufstart+(inptr-inbuf));
  920.     printf("   (c | (b<<8)) = %04x  (crc >> 16) = %04x  lrec.time = %04x\n",
  921.       (UWORD)(c | (b<<8)), (UWORD)(lrec.crc32 >> 16), lrec.last_mod_file_time);
  922. #endif /* CRYPT_DEBUG */
  923.  
  924.     /* same test as in zipbare() in crypt.c: */
  925.     if ((UWORD)(c | (b<<8)) != (pInfo->ExtLocHdr? lrec.last_mod_file_time :
  926.         (UWORD)(lrec.crc32 >> 16)))
  927.         return -1;  /* bad */
  928.  
  929.     /* password OK:  decrypt current buffer contents before leaving */
  930.     for (n = (longint)incnt > csize ? (int)csize : incnt, p = inptr; n--; p++)
  931.         *p = (byte) DECRYPT(*p);
  932.     return 0;       /* OK */
  933.  
  934. } /* end function testp() */
  935.  
  936. #endif /* CRYPT */
  937.  
  938.  
  939.  
  940.  
  941.  
  942. /*******************************/
  943. /*  Function ReadMemoryByte()  */
  944. /*******************************/
  945.  
  946. int ReadMemoryByte(x)   /* return PK-type error code */
  947.     UWORD *x;
  948. {
  949.     if (mem_i_offset < mem_i_size) {
  950.         *x = (UWORD) mem_i_buffer[mem_i_offset++];
  951.         return 8;
  952.     } else
  953.         return 0;
  954. }
  955.  
  956.  
  957.  
  958.  
  959.  
  960. /****************************/
  961. /*  Function FlushMemory()  */
  962. /****************************/
  963.  
  964. int FlushMemory()   /* return PK-type error code */
  965. {
  966.     if (outcnt == 0)
  967.         return 0;
  968.  
  969.     if (mem_o_offset + outcnt <= mem_o_size) {
  970.         memcpy((char *)(mem_o_buffer+mem_o_offset), (char *)outbuf, outcnt);
  971.         mem_o_offset += outcnt;
  972.         return 0;
  973.     } else
  974.         return 50;
  975. }
  976.  
  977.  
  978.  
  979.  
  980.  
  981. /***************************/
  982. /*  Function memextract()  */   /* extract compressed extra field block */
  983. /***************************/
  984.  
  985. int memextract(tgt, tgtsize, src, srcsize)  /* return 0 if success, 1 if not */
  986.     byte *tgt, *src;
  987.     ULONG tgtsize, srcsize;
  988. {
  989.     UWORD method, error = 0;
  990.     ULONG crc, oldcrc;
  991.  
  992.     method = makeword(src);
  993.     crc = makelong(src+2);
  994.  
  995.     mem_i_buffer = src + 2 + 4;      /* method and crc */
  996.     mem_i_size   = srcsize - 2 - 4;
  997.     mem_i_offset = 0;
  998.   
  999.     mem_o_buffer = tgt;
  1000.     mem_o_size   = tgtsize;
  1001.     mem_o_offset = 0;
  1002.  
  1003.     mem_mode = 1;
  1004.  
  1005.     bits_left = 0;
  1006.     bitbuf = 0L;
  1007.     outpos = 0L;
  1008.     outcnt = 0;
  1009.     outptr = outbuf;
  1010.     zipeof = 0;
  1011.  
  1012.     switch (method) {
  1013.         case STORED:
  1014.             memcpy(tgt, src + 2 + 4, (extent) (srcsize - 2 - 4));
  1015.             break;
  1016.         case DEFLATED:
  1017.             inflate();
  1018.             FlushOutput();
  1019.             break;
  1020.         default:
  1021.             fprintf(stderr,
  1022.               "warning:  unsupported extra field compression type--skipping\n");
  1023.             error = 1;   /* GRR:  this should be passed on up via SetEAs() */
  1024.             break;
  1025.     }
  1026.  
  1027.     mem_mode = 0;
  1028.  
  1029.     if (!error) {
  1030.         oldcrc = crc32val;
  1031.         crc32val = 0xFFFFFFFFL;
  1032.         UpdateCRC((unsigned char *) mem_o_buffer, (int) mem_o_size);
  1033.         crc32val = (~crc32val) & 0xFFFFFFFFL;
  1034.  
  1035.         if (crc32val != crc) {
  1036.             printf("(Bad extra field CRC %08lx, should be %08lx)\n", crc32val,
  1037.               crc);
  1038.             error = 1;
  1039.         }
  1040.         crc32val = oldcrc; /* grrr ... this ugly kludge should be fixed */
  1041.     }
  1042.  
  1043.     return error;
  1044. }
  1045.