📄 unzip.c
字号:
kind of a brute-force way to do things; but aside from that, isn't the
-a option useful when listing the directory (i.e., for reading zipfile
comments)? It's a modifier, not an action in and of itself, so perhaps
it should not be included in the test--certainly, in the case of zipfile
testing, it can just be ignored.]
---------------------------------------------------------------------------*/
if ((aflag && tflag) || (aflag && vflag) || (cflag && tflag) ||
(cflag && uflag) || (cflag && vflag) || (tflag && uflag) ||
(tflag && vflag) || (uflag && vflag) || (fflag && overwrite_none)) {
fprintf(stderr, "error:\
-at, -av, -ct, -cu, -cv, -fn, -tu, -tv, -uv combinations not allowed\n");
error = TRUE;
}
if (quietflg && zflag)
quietflg = 0;
if (overwrite_all && overwrite_none) {
fprintf(stderr, "caution: both -n and -o specified; ignoring -o\n");
overwrite_all = FALSE;
}
if ((argc-- == 0) || error)
RETURN(usage(error));
/*---------------------------------------------------------------------------
Now get the zipfile name from the command line and see if it exists as a
regular (non-directory) file. If not, append the ".zip" suffix. We don't
immediately check to see if this results in a good name, but we will do so
later. In the meantime, see if there are any member filespecs on the com-
mand line, and if so, set the filename pointer to point at them.
---------------------------------------------------------------------------*/
strcpy(zipfn, *argv++);
if (stat(zipfn, &statbuf) || (statbuf.st_mode & S_IFMT) == S_IFDIR)
strcat(zipfn, ZSUFX);
#if (defined(UNIX) && !defined(VMS)) /* Unix executables have no extension-- */
else if (statbuf.st_mode & S_IXUSR) /* might find zip, not zip.zip; etc */
fprintf(stderr, "\nnote: file [ %s ] may be an executable\n\n", zipfn);
#endif /* UNIX && !VMS */
if (stat(zipfn, &statbuf)) {/* try again */
fprintf(stderr, "error: can't find zipfile [ %s ]\n", zipfn);
RETURN(9); /* 9: file not found */
} else
ziplen = statbuf.st_size;
if (argc != 0) {
fnv = argv;
process_all_files = FALSE;
} else
process_all_files = TRUE; /* for speed */
/*---------------------------------------------------------------------------
Okey dokey, we have everything we need to get started. Let's roll.
---------------------------------------------------------------------------*/
inbuf = (byte *) malloc(INBUFSIZ + 4); /* 4 extra for hold[] (below) */
outbuf = (byte *) malloc(OUTBUFSIZ + 1); /* 1 extra for string termin. */
#ifndef DOS_OS2
if (aflag) /* if need an ascebc scratch, */
outout = (byte *) malloc(OUTBUFSIZ);
else /* allocate it... */
#endif /* !DOS_OS2 */
outout = outbuf; /* else just point to outbuf */
if ((inbuf == (byte *)NULL) || (outbuf == (byte *)NULL) ||
(outout == (byte *)NULL)) {
fprintf(stderr, "error: can't allocate unzip buffers\n");
RETURN(4); /* 4-8: insufficient memory */
}
hold = &inbuf[INBUFSIZ]; /* to check for boundary-spanning signatures */
RETURN(process_zipfile()); /* keep passing errors back... */
} /* end main() */
/**********************/
/* Function usage() */
/**********************/
int usage(error) /* return PK-type error code */
int error;
{
#ifdef NATIVE
#ifdef EBCDIC
char *astring = "-a convert ASCII to EBCDIC";
#else /* !EBCDIC */
char *astring = "-a convert ASCII to native chars";
#endif /* ?EBCDIC */
/* char *astring = "-a convert ASCII to " NATIVE; (ANSI C concatenation) */
char *loc_str = "";
#else /* !NATIVE */
#ifdef DOS_OS2
char *astring = "-a convert text (LF => CR LF)";
char *loc_str = "-s spaces in filenames => _";
#else /* !DOS_OS2 */
#ifdef MACOS
char *astring = "-a convert text (CR LF => CR)";
char *loc_str = "";
#else /* !MACOS: UNIX, VMS */
char *astring = "-a convert text (CR LF => LF)";
#ifdef VMS
char *loc_str = "-X restore owner/protection info";
#else /* !VMS */
char *loc_str = "";
#endif /* ?VMS */
#endif /* ?MACOS */
#endif /* ?DOS_OS2 */
#endif /* ?NATIVE */
FILE *usagefp;
/*---------------------------------------------------------------------------
If user requested usage, send it to stdout; else send to stderr.
---------------------------------------------------------------------------*/
if (error)
usagefp = (FILE *) stderr;
else
usagefp = (FILE *) stdout;
fprintf(usagefp, "\
UnZip %s, by Info-ZIP. Portions (c) 1989 by S. H. Smith.\n\
Bug reports ONLY to zip-bugs%%wkuvx1.bitnet@ukcc.uky.edu; see README for detail\
s\n\n", VERSION);
fprintf(usagefp, "\
Usage: unzip [ -options[modifiers] ] file[.zip] [filespec...]\n\
-x extract files (default) -l list files (short format)\n\
-c extract files to stdout/screen (CRT) -v list files (verbose format)\n\
-f freshen existing files, create none -p extract to pipe, no messages\n\
-u update files, create if necessary -t test archive integrity\n\
-z display archive comment\n\
modifiers:\n\
-n never overwrite existing files %s\n", loc_str);
fprintf(usagefp, "\
-o overwrite files WITHOUT prompting %s\n\
-j junk paths (don't make directories) -U don't make names lowercase\n\
-q quiet mode (-qq => quieter) -V retain VMS version numbers\
\n\n\
Examples: (See manual for more information)\n\
unzip data1 ReadMe => extracts file ReadMe from zipfile data1.zip\n\
unzip -p foo | more => send contents of foo.zip via pipe into program more\n\
unzip -fo foo => quietly replace existing files if archive files newer\
\n", astring);
#ifdef VMS
fprintf(usagefp, "\
unzip \"-V\" foo \"Bar\" => must quote uppercase options and filenames in VMS\
\n");
#endif
if (error)
return 10; /* 10: bad or illegal parameters specified */
else
return 0; /* just wanted usage screen: no error */
} /* end function usage() */
#endif /* ?MSWIN */
/********************************/
/* Function process_zipfile() */
/********************************/
int process_zipfile() /* return PK-type error code */
{
int error=0, error_in_archive;
longint real_ecrec_offset, expect_ecrec_offset;
/*---------------------------------------------------------------------------
Open the zipfile for reading and in BINARY mode to prevent CR/LF trans-
lation, which would corrupt the bitstreams.
---------------------------------------------------------------------------*/
#ifdef VMS
if (check_format()) /* check for variable-length format */
return 2; /* 2: error in zipfile */
#endif /* VMS */
if (open_input_file()) /* this should never happen, given the */
return 9; /* stat() test in main(), but... */
/*---------------------------------------------------------------------------
Reconstruct the various PK signature strings, and find and process the
end-of-central-directory header.
---------------------------------------------------------------------------*/
strcat(local_hdr_sig, LOCAL_HDR_SIG);
strcat(central_hdr_sig, CENTRAL_HDR_SIG);
strcat(end_central_sig, END_CENTRAL_SIG);
/* strcat(extd_local_sig, EXTD_LOCAL_SIG); */
if (find_end_central_dir()) { /* not found; nothing to do */
close(zipfd);
return 2; /* 2: error in zipfile */
}
real_ecrec_offset = cur_zipfile_bufstart+(inptr-inbuf);
#ifdef TEST
printf("\n found end-of-central-dir signature at offset %ld (%.8lXh)\n",
real_ecrec_offset, real_ecrec_offset);
printf(" from beginning of file; offset %d (%.4Xh) within block\n",
inptr-inbuf, inptr-inbuf);
#endif
if ((error_in_archive = process_end_central_dir()) > 1) {
close(zipfd);
return error_in_archive;
}
if (zflag) {
close(zipfd);
return 0;
}
/*---------------------------------------------------------------------------
Test the end-of-central-directory info for incompatibilities and incon-
sistencies.
---------------------------------------------------------------------------*/
#ifndef PAKFIX
if (ecrec.number_this_disk == 0) {
#else /* PAKFIX */
error = ((ecrec.number_this_disk == 1) &&
(ecrec.num_disk_with_start_central_dir == 1));
if ((ecrec.number_this_disk == 0) || error) {
if (error) {
fprintf(stderr,
"\n Warning: zipfile claims to be disk 2 of a two-part archive;\n\
attempting to process anyway. If no further errors occur, this\n\
archive was probably created by PAK v2.51 or earlier. This bug\n\
was reported to NoGate in March 1991 and was supposed to have been\n\
fixed by mid-1991; as of mid-1992 it still hadn't been.\n\n");
error_in_archive = 1; /* 1: warning */
}
#endif /* ?PAKFIX */
expect_ecrec_offset = ecrec.offset_start_central_directory +
ecrec.size_central_directory;
if ((extra_bytes = real_ecrec_offset - expect_ecrec_offset) < 0) {
fprintf(stderr, "\nerror: missing %ld bytes in zipfile (\
attempting to process anyway)\n\n", -extra_bytes);
error_in_archive = 2; /* 2: (weak) error in zipfile */
} else if (extra_bytes > 0) {
if ((ecrec.offset_start_central_directory == 0) &&
(ecrec.size_central_directory != 0)) /* zip 1.5 -go bug */
{
fprintf(stderr, "\nerror: NULL central directory offset (\
attempting to process anyway)\n\n");
ecrec.offset_start_central_directory = extra_bytes;
extra_bytes = 0;
error_in_archive = 2; /* 2: (weak) error in zipfile */
} else {
fprintf(stderr, "\nwarning: extra %ld bytes at beginning or\
within zipfile\n (attempting to process anyway)\n\n", extra_bytes);
error_in_archive = 1; /* 1: warning error */
}
}
/*-----------------------------------------------------------------------
Check for empty zipfile and exit now if so.
-----------------------------------------------------------------------*/
if (expect_ecrec_offset == 0L && ecrec.size_central_directory == 0) {
fprintf(stderr, "warning: zipfile is empty\n");
close(zipfd);
return (error_in_archive > 1)? error_in_archive : 1;
}
/*-----------------------------------------------------------------------
Compensate for missing or extra bytes, and seek to where the start
of central directory should be. If header not found, uncompensate
and try again (necessary for at least some Atari archives created
with STZIP, as well as archives created by J.H. Holm's ZIPSPLIT).
-----------------------------------------------------------------------*/
LSEEK( ecrec.offset_start_central_directory )
if ((readbuf(sig, 4) <= 0) || strncmp(sig, central_hdr_sig, 4)) {
longint tmp = extra_bytes;
extra_bytes = 0;
LSEEK( ecrec.offset_start_central_directory )
if ((readbuf(sig, 4) <= 0) || strncmp(sig, central_hdr_sig, 4)) {
fprintf(stderr,
"error: start of central directory not found; zipfile corrupt.\n");
fprintf(stderr, ReportMsg);
close(zipfd);
return 3; /* 3: severe error in zipfile */
}
fprintf(stderr, "error: reported length of central directory is \
%d bytes too\n long (Atari STZIP zipfile? J.H. Holm ZIPSPLIT zipfile?)\
.\n Compensating...\n\n", -tmp);
error_in_archive = 2; /* 2: (weak) error in zipfile */
}
/*-----------------------------------------------------------------------
Seek to the start of the central directory one last time, since we
have just read the first entry's signature bytes; then list, extract
or test member files as instructed, and close the zipfile.
-----------------------------------------------------------------------*/
LSEEK( ecrec.offset_start_central_directory )
if (vflag)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -