?? unzip.c
字號:
error = list_files(); /* LIST 'EM */
else
error = extract_or_test_files(); /* EXTRACT OR TEST 'EM */
if (error > error_in_archive) /* don't overwrite stronger error */
error_in_archive = error; /* with (for example) a warning */
} else {
fprintf(stderr, "\nerror: zipfile is part of multi-disk archive \
(sorry, not supported).\n");
/* fprintf(stderr, "Please report to zip-bugs@cs.ucla.edu\n"); */
error_in_archive = 11; /* 11: no files found */
}
close(zipfd);
return error_in_archive;
} /* end function process_zipfile() */
/************************************/
/* Function find_end_central_dir() */
/************************************/
int find_end_central_dir() /* return 0 if found, 1 otherwise */
{
int i, numblks;
longint tail_len;
/*---------------------------------------------------------------------------
Treat case of short zipfile separately.
---------------------------------------------------------------------------*/
if (ziplen <= INBUFSIZ) {
lseek(zipfd, 0L, SEEK_SET);
if ((incnt = read(zipfd,(char *)inbuf,(unsigned int)ziplen)) ==
(int)ziplen)
/* 'P' must be at least 22 bytes from end of zipfile */
for (inptr = inbuf+(int)ziplen-22; inptr >= inbuf; --inptr)
if ((ascii_to_native(*inptr) == 'P') &&
!strncmp((char *)inptr, end_central_sig, 4)) {
incnt -= inptr - inbuf;
return 0; /* found it! */
} /* ...otherwise fall through & fail */
/*---------------------------------------------------------------------------
Zipfile is longer than INBUFSIZ: may need to loop. Start with short
block at end of zipfile (if not TOO short).
---------------------------------------------------------------------------*/
} else {
if ((tail_len = ziplen % INBUFSIZ) > ECREC_SIZE) {
cur_zipfile_bufstart = lseek(zipfd, ziplen-tail_len, SEEK_SET);
if ((incnt = read(zipfd,(char *)inbuf,(unsigned int)tail_len)) !=
(int)tail_len)
goto fail; /* shut up; it's expedient. */
/* 'P' must be at least 22 bytes from end of zipfile */
for (inptr = inbuf+(int)tail_len-22; inptr >= inbuf; --inptr)
if ((ascii_to_native(*inptr) == 'P') &&
!strncmp((char *)inptr, end_central_sig, 4)) {
incnt -= inptr - inbuf;
return 0; /* found it */
} /* ...otherwise search next block */
strncpy((char *)hold, (char *)inbuf, 3); /* sig may span block
boundary */
} else {
cur_zipfile_bufstart = ziplen - tail_len;
}
/*-----------------------------------------------------------------------
Loop through blocks of zipfile data, starting at the end and going
toward the beginning. Need only check last 65557 bytes of zipfile:
comment may be up to 65535 bytes long, end-of-central-directory rec-
ord is 18 bytes (shouldn't hardcode this number, but what the hell:
already did so above (22=18+4)), and sig itself is 4 bytes.
-----------------------------------------------------------------------*/
numblks = (int)
((MIN(ziplen,65557L) - tail_len + (INBUFSIZ-1)) / INBUFSIZ);
/* =amount to search= ==done== ==rounding== =blksiz= */
for (i = 1; i <= numblks; ++i) {
cur_zipfile_bufstart -= INBUFSIZ;
lseek(zipfd, cur_zipfile_bufstart, SEEK_SET);
if ((incnt = read(zipfd,(char *)inbuf,INBUFSIZ)) != INBUFSIZ)
break; /* fall through and fail */
for (inptr = inbuf+INBUFSIZ-1; inptr >= inbuf; --inptr)
if ((ascii_to_native(*inptr) == 'P') &&
!strncmp((char *)inptr, end_central_sig, 4)) {
incnt -= inptr - inbuf;
return 0; /* found it */
}
strncpy((char *)hold, (char *)inbuf, 3); /* sig may span block
boundary */
}
} /* end if (ziplen > INBUFSIZ) */
/*---------------------------------------------------------------------------
Searched through whole region where signature should be without finding
it. Print informational message and die a horrible death.
---------------------------------------------------------------------------*/
fail:
#ifdef MSWIN
MessageBeep(1);
#endif
fprintf(stderr, "\nFile: %s\n\n\
End-of-central-directory signature not found. Either this file is not\n\
a zipfile, or it constitutes one disk of a multi-part archive. In the\n\
latter case the central directory and zipfile comment will be found on\n\
the last disk(s) of this archive.\n", zipfn);
return 1;
} /* end function find_end_central_dir() */
/***************************************/
/* Function process_end_central_dir() */
/***************************************/
int process_end_central_dir() /* return PK-type error code */
{
ec_byte_rec byterec;
int error=0;
/*---------------------------------------------------------------------------
Read the end-of-central-directory record and do any necessary machine-
type conversions (byte ordering, structure padding compensation) by
reading data into character array, then copying to struct.
---------------------------------------------------------------------------*/
if (readbuf((char *) byterec, ECREC_SIZE+4) <= 0)
return 51;
ecrec.number_this_disk =
makeword(&byterec[NUMBER_THIS_DISK]);
ecrec.num_disk_with_start_central_dir =
makeword(&byterec[NUM_DISK_WITH_START_CENTRAL_DIR]);
ecrec.num_entries_centrl_dir_ths_disk =
makeword(&byterec[NUM_ENTRIES_CENTRL_DIR_THS_DISK]);
ecrec.total_entries_central_dir =
makeword(&byterec[TOTAL_ENTRIES_CENTRAL_DIR]);
ecrec.size_central_directory =
makelong(&byterec[SIZE_CENTRAL_DIRECTORY]);
ecrec.offset_start_central_directory =
makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]);
ecrec.zipfile_comment_length =
makeword(&byterec[ZIPFILE_COMMENT_LENGTH]);
/*---------------------------------------------------------------------------
Get the zipfile comment, if any, and print it out. (Comment may be up
to 64KB long. May the fleas of a thousand camels infest the armpits of
anyone who actually takes advantage of this fact.) Then position the
file pointer to the beginning of the central directory and fill buffer.
---------------------------------------------------------------------------*/
#ifdef MSWIN
cchComment = ecrec.zipfile_comment_length; /* save for comment button */
if (ecrec.zipfile_comment_length && zflag) {
#else /* !MSWIN */
if (ecrec.zipfile_comment_length && !quietflg) {
if (!zflag)
printf("[%s] comment:\n", zipfn);
#endif /* ?MSWIN */
if (do_string(ecrec.zipfile_comment_length,DISPLAY)) {
fprintf(stderr, "\ncaution: zipfile comment truncated\n");
error = 1; /* 1: warning error */
}
}
return error;
} /* end function process_end_central_dir() */
/* also referenced in UpdateListBox() in updatelb.c (Windows version) */
char *Headers[][2] = {
{" Length Date Time Name",
" ------ ---- ---- ----"},
{" Length Method Size Ratio Date Time CRC-32 Name",
" ------ ------ ---- ----- ---- ---- ------ ----"}
};
/*************************/
/* Function list_files() */
/*************************/
int list_files() /* return PK-type error code */
{
char **fnamev;
int do_this_file=FALSE, ratio, error, error_in_archive=0;
int which_hdr=(vflag>1), date_format;
UWORD j, yr, mo, dy, hh, mm, members=0;
ULONG tot_csize=0L, tot_ucsize=0L;
#ifdef OS2
ULONG tot_easize=0L, tot_eafiles=0L, ea_size;
#endif
#ifdef MSWIN
PSTR psLBEntry; /* list box entry */
#endif
min_info info;
static char *method[NUM_METHODS+1] =
{"Stored", "Shrunk", "Reduce1", "Reduce2", "Reduce3", "Reduce4",
"Implode", "Token", "Deflate", unkn};
/*---------------------------------------------------------------------------
Unlike extract_or_test_files(), this routine confines itself to the cen-
tral directory. Thus its structure is somewhat simpler, since we can do
just a single loop through the entire directory, listing files as we go.
So to start off, print the heading line and then begin main loop through
the central directory. The results will look vaguely like the following:
Length Method Size Ratio Date Time CRC-32 Name ("^" ==> case
------ ------ ---- ----- ---- ---- ------ ---- conversion)
44004 Implode 13041 71% 11-02-89 19:34 8b4207f7 Makefile.UNIX
3438 Shrunk 2209 36% 09-15-90 14:07 a2394fd8 ^dos-file.ext
---------------------------------------------------------------------------*/
pInfo = &info;
date_format = dateformat();
#ifndef MSWIN
if (quietflg < 2)
if (U_flag)
printf("%s\n%s\n", Headers[which_hdr][0], Headers[which_hdr][1]);
else
printf("%s (\"^\" ==> case\n%s conversion)\n",
Headers[which_hdr][0], Headers[which_hdr][1]);
#endif /* !MSWIN */
for (j = 0; j < ecrec.total_entries_central_dir; ++j) {
if (readbuf(sig, 4) <= 0)
return 51; /* 51: unexpected EOF */
if (strncmp(sig, central_hdr_sig, 4)) { /* just to make sure */
fprintf(stderr, CentSigMsg, j); /* sig not found */
fprintf(stderr, ReportMsg); /* check binary transfers */
return 3; /* 3: error in zipfile */
}
if ((error = process_cdir_file_hdr()) != 0) /* (sets pInfo->lcflag) */
return error; /* only 51 (EOF) defined */
/*
* We could DISPLAY the filename instead of storing (and possibly trun-
* cating, in the case of a very long name) and printing it, but that
* has the disadvantage of not allowing case conversion--and it's nice
* to be able to see in the listing precisely how you have to type each
* filename in order for unzip to consider it a match. Speaking of
* which, if member names were specified on the command line, check in
* with match() to see if the current file is one of them, and make a
* note of it if it is.
*/
if ((error = do_string(crec.filename_length, FILENAME)) != 0) {
error_in_archive = error; /* ^--(uses pInfo->lcflag) */
if (error > 1) /* fatal: can't continue */
return error;
}
if (extra_field != (byte *)NULL)
free(extra_field);
extra_field = (byte *)NULL;
if ((error = do_string(crec.extra_field_length, EXTRA_FIELD)) != 0) {
error_in_archive = error;
if (error > 1) /* fatal: can't continue */
return error;
}
if (!process_all_files) { /* check if specified on command line */
do_this_file = FALSE;
fnamev = fnv; /* don't destroy permanent filename ptr */
for (--fnamev; *++fnamev;)
if (match(filename, *fnamev)) {
do_this_file = TRUE;
break; /* found match, so stop looping */
}
}
/*
* If current file was specified on command line, or if no names were
* specified, do the listing for this file. Otherwise, get rid of the
* file comment and go back for the next file.
*/
if (process_all_files || do_this_file) {
yr = (((crec.last_mod_file_date >> 9) & 0x7f) + 80) % (unsigned)100;
mo = (crec.last_mod_file_date >> 5) & 0x0f;
dy = crec.last_mod_file_date & 0x1f;
/* twist date so it displays according to national convention */
switch (date_format) {
case DF_YMD:
hh = mo; mo = yr; yr = dy; dy = hh; break;
case DF_DMY:
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -