Annotation of coherent/b/bin/unzip/extract.c, revision 1.1.1.1

1.1       root        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:   explode.c, inflate.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 r, 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:         if (((r = explode()) != 0) && (r != 5)) {   /* ignore 5 if seekable */
                    749:             if ((tflag && quietflg) || (!tflag && (quietflg > 1)))
                    750:                 fprintf(stderr, "  error:  %s%s\n", r == 3?
                    751:                   "not enough memory to explode " :
                    752:                   "invalid compressed (imploded) data for ", filename);
                    753:             else
                    754:                 fprintf(stderr, "\n  error:  %s\n", r == 3?
                    755:                   "not enough memory for explode operation" :
                    756:                   "invalid compressed data for explode format");
                    757:             error = (r == 3)? 5 : 2;
                    758:         }
                    759:         break;
                    760: 
                    761:     case DEFLATED:
                    762:         if (!tflag && (quietflg < 2)) {
                    763:             fprintf(stdout, "  Inflating: %-22s ", filename);
                    764:             if (cflag)
                    765:                 fprintf(stdout, "\n");
                    766:             fflush(stdout);
                    767:         }
                    768: #ifdef S_IFLNK   /* !!! This code needs to be added to unShrink, etc. !!! */
                    769:         if (symlnk) {
                    770:             fprintf(stdout, "\n  warning:  symbolic link ignored\n");
                    771:             error = 1;          /* 1:  warning error */
                    772:         }
                    773: #endif /* S_IFLNK */
                    774:         if ((r = inflate()) != 0) {
                    775:             if ((tflag && quietflg) || (!tflag && (quietflg > 1)))
                    776:                 fprintf(stderr, "  error:  %s%s\n", r == 3?
                    777:                   "not enough memory to inflate " :
                    778:                   "invalid compressed (deflated) data for ", filename);
                    779:             else
                    780:                 fprintf(stderr, "\n  error:  %s\n", r == 3?
                    781:                   "not enough memory for inflate operation" :
                    782:                   "invalid compressed data for inflate format");
                    783:             error = (r == 3)? 5 : 2;
                    784:         }
                    785:         break;
                    786: 
                    787:     default:   /* should never get to this point */
                    788:         fprintf(stderr, "%s:  unknown compression method\n", filename);
                    789:         /* close and delete file before return? */
                    790:         return 1;               /* 1:  warning error */
                    791: 
                    792:     } /* end switch (compression method) */
                    793: 
                    794:     if (disk_full) {            /* set by FlushOutput()/OUTB() macro */
                    795:         if (disk_full > 1)
                    796:             return 50;          /* 50:  disk full */
                    797:         error = 1;              /* 1:  warning error */
                    798:     }
                    799: 
                    800: /*---------------------------------------------------------------------------
                    801:     Write the last partial buffer, if any; set the file date and time; and
                    802:     close the file (not necessarily in that order).  Then make sure CRC came
                    803:     out OK and print result.
                    804:   ---------------------------------------------------------------------------*/
                    805: 
                    806: #ifdef S_IFLNK
                    807:     if (!symlnk) {
                    808: #endif /* S_IFLNK */
                    809:     if (!disk_full && FlushOutput())
                    810:         if (disk_full > 1)
                    811:             return 50;          /* 50:  disk full */
                    812:         else {                  /* disk_full == 1 */
                    813:             fprintf(stderr, "%s:  probably corrupt\n", filename);
                    814:             error = 1;          /* 1:  warning error */
                    815:         }
                    816: 
                    817:     if (!tflag)
                    818: #ifdef VMS
                    819:         CloseOutputFile();
                    820: #else /* !VMS */
                    821: #ifdef MTS                      /* MTS can't set file time */
                    822:         close(outfd);
                    823: #else /* !MTS */
                    824:         set_file_time_and_close();
                    825: #endif /* ?MTS */
                    826: #endif /* ?VMS */
                    827: 
                    828: #ifdef S_IFLNK
                    829:     } /* endif (!symlnk) */
                    830: #endif /* S_IFLNK */
                    831: 
                    832:     if (error > 1)   /* don't print redundant CRC error if error already */
                    833:         return error;
                    834: 
                    835:     /* logical-AND crc32val for 64-bit machines */
                    836:     if ((crc32val = ((~crc32val) & 0xFFFFFFFFL)) != lrec.crc32) {
                    837:         /* if quietflg is set, we haven't output the filename yet:  do it */
                    838:         if (quietflg)
                    839:             printf("%-22s: ", filename);
                    840:         fprintf(stdout, " Bad CRC %08lx  (should be %08lx)\n", crc32val,
                    841:                 lrec.crc32);
                    842:         error = 1;              /* 1:  warning error */
                    843:     } else if (tflag) {
                    844:         if (!quietflg)
                    845:             fprintf(stdout, " OK\n");
                    846:     } else {
                    847:         if ((quietflg < 2) && !error)
                    848:             fprintf(stdout, "\n");
                    849:     }
                    850: 
                    851:     return error;
                    852: 
                    853: }       /* end function extract_or_test_member() */
                    854: 
                    855: 
                    856: 
                    857: 
                    858: 
                    859: #ifdef CRYPT
                    860: 
                    861: /*******************************/
                    862: /*  Function decrypt_member()  */
                    863: /*******************************/
                    864: 
                    865: static int decrypt_member()   /* return 10 if out of memory or can't get */
                    866: {                             /*  tty; 1 if password bad; 0 if password OK */
                    867:     UWORD b;
                    868:     int n, r;
                    869:     static int nopwd=FALSE;
                    870:     char *m, *prompt;
                    871:     byte h[12];
                    872: 
                    873: 
                    874:     /* get header once (turn off "encrypted" flag temporarily so we don't
                    875:      * try to decrypt the same data twice) */
                    876:     pInfo->encrypted = FALSE;
                    877:     for (n = 0; n < 12; n++) {
                    878:         ReadByte(&b);
                    879:         h[n] = (byte) b;
                    880:     }
                    881:     pInfo->encrypted = TRUE;
                    882: 
                    883:     /* if have key already, test it; else allocate memory for it */
                    884:     if (key) {
                    885:         if (!testp(h))
                    886:             return 0;      /* existing password OK (else prompt for new) */
                    887:         else if (nopwd)
                    888:             return 1;      /* user indicated no more prompting */
                    889:     } else if ((key = (char *)malloc(PWLEN+1)) == (char *)NULL)
                    890:         return 10;
                    891: 
                    892:     if ((prompt = (char *)malloc(FILNAMSIZ+15)) != (char *)NULL) {
                    893:         sprintf(prompt, "%s password: ", filename);
                    894:         m = prompt;
                    895:     } else
                    896:         m = "Enter password: ";
                    897: 
                    898:     /* try a few keys */
                    899:     for (r = 0;  r < 3;  ++r) {
                    900:         m = getp(m, key, PWLEN+1);
                    901:         if (prompt != (char *)NULL) {
                    902:             free(prompt);
                    903:             prompt = (char *)NULL;
                    904:         }
                    905:         if (m == (char *)NULL)
                    906:             return 10;
                    907:         if (!testp(h))
                    908:             return 0;
                    909:         if (*key == '\0') {
                    910:             nopwd = TRUE;
                    911:             return 1;
                    912:         }
                    913:         m = "password incorrect--reenter: ";
                    914:     }
                    915:     return 1;
                    916: }
                    917: 
                    918: 
                    919: 
                    920: 
                    921: 
                    922: /**********************/
                    923: /*  Function testp()  */
                    924: /**********************/
                    925: 
                    926: static int testp(h)   /* return -1 if bad password; 0 if OK */
                    927:     byte *h;
                    928: {
                    929:     UWORD b;
                    930:     int n, t;
                    931:     byte *p;
                    932: 
                    933:     /* set keys */
                    934:     init_keys(key);
                    935: 
                    936:     /* check password */
                    937:     for (n = 0; n < 12; n++)
                    938:         b = DECRYPT(h[n]);
                    939: 
                    940: #ifdef CRYPT_DEBUG
                    941:     printf("   lrec.crc = %08lx  crec.crc = %08lx  pInfo->ExtLocHdr = %s\n",
                    942:       lrec.crc32, pInfo->crc, pInfo->ExtLocHdr? "true":"false");
                    943:     printf("   incnt = %d  unzip offset into zipfile = %ld\n", incnt,
                    944:       cur_zipfile_bufstart+(inptr-inbuf));
                    945:     printf("   b = %02x  (crc >> 24) = %02x  (lrec.time >> 8) = %02x\n",
                    946:       b, (UWORD)(lrec.crc32 >> 24), (lrec.last_mod_file_time >> 8));
                    947: #endif /* CRYPT_DEBUG */
                    948: 
                    949:     /* same test as in zipbare() in crypt.c (now check only one byte): */
                    950:     if (b != (pInfo->ExtLocHdr? lrec.last_mod_file_time >> 8 :
                    951:         (UWORD)(lrec.crc32 >> 24)))
                    952:         return -1;  /* bad */
                    953: 
                    954:     /* password OK:  decrypt current buffer contents before leaving */
                    955:     for (n = (longint)incnt > csize ? (int)csize : incnt, p = inptr; n--; p++)
                    956:         *p = (byte) DECRYPT(*p);
                    957:     return 0;       /* OK */
                    958: 
                    959: } /* end function testp() */
                    960: 
                    961: #endif /* CRYPT */
                    962: 
                    963: 
                    964: 
                    965: 
                    966: 
                    967: /*******************************/
                    968: /*  Function ReadMemoryByte()  */
                    969: /*******************************/
                    970: 
                    971: int ReadMemoryByte(x)   /* return PK-type error code */
                    972:     UWORD *x;
                    973: {
                    974:     if (mem_i_offset < mem_i_size) {
                    975:         *x = (UWORD) mem_i_buffer[mem_i_offset++];
                    976:         return 8;
                    977:     } else
                    978:         return 0;
                    979: }
                    980: 
                    981: 
                    982: 
                    983: 
                    984: 
                    985: /****************************/
                    986: /*  Function FlushMemory()  */
                    987: /****************************/
                    988: 
                    989: int FlushMemory()   /* return PK-type error code */
                    990: {
                    991:     if (outcnt == 0)
                    992:         return 0;
                    993: 
                    994:     if (mem_o_offset + outcnt <= mem_o_size) {
                    995:         memcpy((char *)(mem_o_buffer+(UWORD)mem_o_offset), (char *)outbuf,
                    996:           outcnt);
                    997:         mem_o_offset += outcnt;
                    998:         return 0;
                    999:     } else
                   1000:         return 50;
                   1001: }
                   1002: 
                   1003: 
                   1004: 
                   1005: 
                   1006: 
                   1007: /***************************/
                   1008: /*  Function memextract()  */   /* extract compressed extra field block */
                   1009: /***************************/
                   1010: 
                   1011: int memextract(tgt, tgtsize, src, srcsize)  /* return 0 if success, 1 if not */
                   1012:     byte *tgt, *src;
                   1013:     ULONG tgtsize, srcsize;
                   1014: {
                   1015:     UWORD method, error = 0;
                   1016:     ULONG crc, oldcrc;
                   1017:     int r;
                   1018: 
                   1019:     method = makeword(src);
                   1020:     crc = makelong(src+2);
                   1021: 
                   1022:     mem_i_buffer = src + 2 + 4;      /* method and crc */
                   1023:     mem_i_size   = srcsize - 2 - 4;
                   1024:     mem_i_offset = 0;
                   1025:   
                   1026:     mem_o_buffer = tgt;
                   1027:     mem_o_size   = tgtsize;
                   1028:     mem_o_offset = 0;
                   1029: 
                   1030:     mem_mode = 1;
                   1031: 
                   1032:     bits_left = 0;
                   1033:     bitbuf = 0L;
                   1034:     outpos = 0L;
                   1035:     outcnt = 0;
                   1036:     outptr = outbuf;
                   1037:     zipeof = 0;
                   1038: 
                   1039:     switch (method) {
                   1040:         case STORED:
                   1041:             memcpy(tgt, src + 2 + 4, (extent) (srcsize - 2 - 4));
                   1042:             break;
                   1043:         case DEFLATED:
                   1044:             if ((r = inflate()) != 0) {
                   1045:                 fprintf(stderr, "error:  %s\n", r == 3 ?
                   1046:                   "not enough memory for inflate operation" :
                   1047:                   "invalid compressed data for the inflate format");
                   1048:                 error = (r == 3)? 5 : 2;
                   1049:             }
                   1050:             FlushOutput();
                   1051:             break;
                   1052:         default:
                   1053:             fprintf(stderr,
                   1054:               "warning:  unsupported extra field compression type--skipping\n");
                   1055:             error = 1;   /* GRR:  this should be passed on up via SetEAs() */
                   1056:             break;
                   1057:     }
                   1058: 
                   1059:     mem_mode = 0;
                   1060: 
                   1061:     if (!error) {
                   1062:         oldcrc = crc32val;
                   1063:         crc32val = 0xFFFFFFFFL;
                   1064:         UpdateCRC((unsigned char *) mem_o_buffer, (int) mem_o_size);
                   1065:         crc32val = (~crc32val) & 0xFFFFFFFFL;
                   1066: 
                   1067:         if (crc32val != crc) {
                   1068:             printf("(Bad extra field CRC %08lx, should be %08lx)\n", crc32val,
                   1069:               crc);
                   1070:             error = 1;
                   1071:         }
                   1072:         crc32val = oldcrc; /* grrr ... this ugly kludge should be fixed */
                   1073:     }
                   1074: 
                   1075:     return error;
                   1076: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.