📄 extract.c
字号:
overwrite_none = TRUE;
overwrite_all = FALSE; /* make sure */
force_flag = FALSE; /* ditto */
/* FALL THROUGH, skip */
case 'n':
continue; /* skip file */
default:
fprintf(stderr, "error: invalid response [%c]\n",
*answerbuf); /* warn the user */
goto reprompt; /* why not another goto? */
} /* end switch (*answerbuf) */
#endif /* ?MSWIN */
} /* end if (query) */
/*#endif*/ /* !VMS */
} /* end if (extracting to disk) */
#ifdef CRYPT
if (pInfo->encrypted && ((error = decrypt_member()) != 0)) {
if (error == 10) {
if (error > error_in_archive)
error_in_archive = error;
fprintf(stderr,
" skipping: %-22s unable to get password\n", filename);
} else { /* (error == 1) */
fprintf(stderr,
" skipping: %-22s incorrect password\n", filename);
++num_bad_pwd;
}
continue; /* go on to next file */
}
#endif /* CRYPT */
#ifdef MSWIN
SoundDuring(); /* play sound during extraction or test if requested */
#endif
disk_full = 0;
if ((error = extract_or_test_member()) != 0) {
if (error > error_in_archive)
error_in_archive = error; /* ...and keep going */
if (disk_full > 1)
return error_in_archive; /* (unless disk full) */
}
} /* end for-loop (i: files in current block) */
/*
* Jump back to where we were in the central directory, then go and do
* the next batch of files.
*/
cur_zipfile_bufstart = lseek(zipfd, cd_bufstart, SEEK_SET);
read(zipfd, (char *)inbuf, INBUFSIZ); /* were there b4 ==> no error */
inptr = cd_inptr;
incnt = cd_incnt;
++blknum;
#ifdef TEST
printf("\ncd_bufstart = %ld (%.8lXh)\n", cd_bufstart, cd_bufstart);
printf("cur_zipfile_bufstart = %ld (%.8lXh)\n", cur_zipfile_bufstart,
cur_zipfile_bufstart);
printf("inptr-inbuf = %d\n", inptr-inbuf);
printf("incnt = %d\n\n", incnt);
#endif
} /* end while-loop (blocks of files in central directory) */
/*---------------------------------------------------------------------------
Double-check that we're back at the end-of-central-directory record, and
print quick summary of results, if we were just testing the archive. We
send the summary to stdout so that people doing the testing in the back-
ground and redirecting to a file can just do a "tail" on the output file.
---------------------------------------------------------------------------*/
readbuf(sig, 4);
if (strncmp(sig, end_central_sig, 4)) { /* just to make sure again */
fprintf(stderr, EndSigMsg); /* didn't find end-of-central-dir sig */
fprintf(stderr, ReportMsg); /* check binary transfers */
if (!error_in_archive) /* don't overwrite stronger error */
error_in_archive = 1; /* 1: warning error */
}
if (tflag && (quietflg == 1)) {
int num=filnum+1 - num_bad_pwd;
if (error_in_archive)
printf("At least one error was detected in %s.\n", zipfn);
else if (num == 0)
printf("Caution: zero files tested in %s.\n", zipfn);
else if (process_all_files && (num_skipped+num_bad_pwd == 0))
printf("No errors detected in %s.\n", zipfn);
else
printf("No errors detected in %s for the %d file%s tested.\n",
zipfn, num, (num==1)? "":"s");
if (num_skipped > 0)
printf("%d file%s skipped because of unsupported compression or\
encoding.\n",
num_skipped, (num_skipped==1)? "":"s");
#ifdef CRYPT
if (num_bad_pwd > 0)
printf("%d file%s skipped because of incorrect password.\n",
num_bad_pwd, (num_bad_pwd==1)? "":"s");
#endif /* CRYPT */
}
if ((num_skipped > 0) && !error_in_archive) /* files not tested or */
error_in_archive = 1; /* extracted: warning */
#ifdef CRYPT
if ((num_bad_pwd > 0) && !error_in_archive) /* files not tested or */
error_in_archive = 1; /* extracted: warning */
#endif /* CRYPT */
return (error_in_archive);
} /* end function extract_or_test_files() */
/***************************/
/* Function store_info() */
/***************************/
static int store_info() /* return 1 if skipping, 0 if OK */
{
ULONG tmp;
#define UNKN_COMPR \
(crec.compression_method>IMPLODED && crec.compression_method!=DEFLATED)
#if 0 /* old */
# define UNKN_COMPR (crec.compression_method>IMPLODED)
#endif
/*---------------------------------------------------------------------------
Check central directory info for version/compatibility requirements.
---------------------------------------------------------------------------*/
pInfo->encrypted = crec.general_purpose_bit_flag & 1; /* bit field */
pInfo->ExtLocHdr = (crec.general_purpose_bit_flag & 8) == 8; /* bit */
pInfo->text = crec.internal_file_attributes & 1; /* bit field */
pInfo->crc = crec.crc32;
pInfo->compr_size = crec.compressed_size;
if (crec.version_needed_to_extract[1] == VMS_) {
if (crec.version_needed_to_extract[0] > VMS_VERSION) {
fprintf(stderr, VersionMsg, filename, "VMS",
crec.version_needed_to_extract[0] / 10,
crec.version_needed_to_extract[0] % 10,
VMS_VERSION / 10, VMS_VERSION % 10);
return 1;
}
#ifndef VMS /* won't be able to use extra field, but still have data */
else if (!tflag && !force_flag) { /* if forcing, extract regardless */
fprintf(stderr,
"\n%s: stored in VMS format. Extract anyway? (y/n) ",
filename);
FFLUSH /* for Amiga and Mac MPW */
fgets(answerbuf, 9, stdin);
if ((*answerbuf != 'y') && (*answerbuf != 'Y'))
return 1;
}
#endif /* !VMS */
/* usual file type: don't need VMS to extract */
} else if (crec.version_needed_to_extract[0] > UNZIP_VERSION) {
fprintf(stderr, VersionMsg, filename, "PK",
crec.version_needed_to_extract[0] / 10,
crec.version_needed_to_extract[0] % 10,
UNZIP_VERSION / 10, UNZIP_VERSION % 10);
return 1;
}
if UNKN_COMPR {
fprintf(stderr, ComprMsg, filename, crec.compression_method);
return 1;
}
#ifndef CRYPT
if (pInfo->encrypted) {
fprintf(stderr, " skipping: %-22s encrypted (not supported)\n",
filename);
return 1;
}
#endif /* !CRYPT */
/*---------------------------------------------------------------------------
Store some central-directory information (encryption, file attributes,
offsets) for later use.
---------------------------------------------------------------------------*/
tmp = crec.external_file_attributes;
pInfo->dos_attr = 32; /* set archive bit: file is not backed up */
switch (pInfo->hostnum) {
case UNIX_:
case VMS_:
pInfo->unix_attr = (unsigned) (tmp >> 16);
break;
case DOS_OS2_FAT_:
case OS2_HPFS_:
pInfo->dos_attr = (unsigned) tmp;
tmp = (!(tmp & 1)) << 1; /* read-only bit */
pInfo->unix_attr = (unsigned) (0444 | (tmp<<6) | (tmp<<3) | tmp);
#ifdef UNIX
umask( (int)(tmp=umask(0)) );
pInfo->unix_attr &= ~tmp;
#endif
break;
case MAC_:
pInfo->unix_attr = (unsigned) (tmp & 1); /* read-only bit */
break;
default:
pInfo->unix_attr = 0666;
break;
} /* end switch (host-OS-created-by) */
pInfo->offset = (longint) crec.relative_offset_local_header;
return 0;
} /* end function store_info() */
/***************************************/
/* Function extract_or_test_member() */
/***************************************/
static int extract_or_test_member() /* return PK-type error code */
{
#ifdef S_IFLNK
int symlnk=FALSE;
#endif /* S_IFLNK */
int r, error=0;
UWORD b;
/*---------------------------------------------------------------------------
Initialize variables, buffers, etc.
---------------------------------------------------------------------------*/
bits_left = 0;
bitbuf = 0L;
outpos = 0L;
outcnt = 0;
outptr = outbuf;
zipeof = 0;
crc32val = 0xFFFFFFFFL;
#ifdef S_IFLNK
if ((pInfo->unix_attr & S_IFMT) == S_IFLNK && (pInfo->hostnum == UNIX_)
&& !tflag && !cflag)
symlnk = TRUE;
#endif /* S_IFLNK */
memset(outbuf, 0xaa, OUTBUFSIZ);
#ifndef DOS_OS2
if (aflag) /* if we have a scratchpad, clear it out */
memset(outout, 0xaa, OUTBUFSIZ);
#endif /* !DOS_OS2 */
if (tflag) {
if (!quietflg) {
fprintf(stdout, " Testing: %-22s ", filename);
fflush(stdout);
}
} else {
if (cflag) { /* output to stdout (copy of it) */
#if (defined(MACOS) || defined(AMIGA))
outfd = 1;
#else /* !(MACOS || AMIGA) */
outfd = dup(1); /* GRR: change this to #define for Mac/Amiga */
#endif /* ?(MACOS || AMIGA) */
#ifdef DOS_OS2
if (!aflag)
setmode(outfd, O_BINARY);
#endif /* DOS_OS2 */
#ifdef VMS
if (create_output_file()) /* VMS version required for stdout! */
return 50; /* 50: disk full (?) */
#endif
} else
#ifdef S_IFLNK
if (!symlnk) /* symlink() takes care of file creation */
#endif /* !S_IFLNK */
{
if (create_output_file())
return 50; /* 50: disk full (?) */
}
} /* endif (!tflag) */
/*---------------------------------------------------------------------------
Unpack the file.
---------------------------------------------------------------------------*/
switch (lrec.compression_method) {
case STORED:
if (!tflag && (quietflg < 2)) {
fprintf(stdout, " Extracting: %-22s ", filename);
if (cflag)
fprintf(stdout, "\n");
fflush(stdout);
}
#ifdef S_IFLNK
/*
* If file came from Unix and is a symbolic link and we are extracting
* to disk, allocate a storage area, put the data in it, and create the
* link. Since we know it's a symbolic link to start with, shouldn't
* have to worry about overflowing unsigned ints with unsigned longs.
* (This doesn't do anything for compressed symlinks, but that can be
* added later...it also doesn't set the time or permissions of the
* link, but does anyone really care?)
*/
if (symlnk) {
#if (defined(MTS) || defined(MACOS))
fprintf(stdout, "\n warning: symbolic link ignored\n");
error = 1; /* 1: warning error */
#else /* !(MTS || MACOS) */
char *orig = (char *)malloc((unsigned)lrec.uncompressed_size+1);
char *p = orig;
while (ReadByte(&b))
*p++ = b;
*p = 0; /* terminate string */
UpdateCRC((unsigned char *)orig, p-orig);
if (symlink(orig, filename))
if ((errno == EEXIST) && overwrite_all) { /* OK to overwrite */
unlink(filename);
if (symlink(orig, filename))
perror("symlink error");
} else
perror("symlink error");
free(orig);
#endif /* ?(MTS || MACOS) */
} else
#endif /* S_IFLNK */
while (ReadByte(&b) && !disk_full)
OUTB(b)
break;
case SHRUNK:
if (!tflag && (quietflg < 2)) {
fprintf(stdout, "UnShrinking: %-22s ", filename);
if (cflag)
fprintf(stdout, "\n");
fflush(stdout);
}
#ifdef S_IFLNK /* !!! This code needs to be added to unShrink, etc. !!! */
if (symlnk) {
fprintf(stdout, "\n warning: symbolic link ignored\n");
error = 1; /* 1: warning error */
}
#endif /* S_IFLNK */
unShrink();
break;
case REDUCED1:
case REDUCED2:
case REDUCED3:
case REDUCED4:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -