📄 gzip.c
字号:
break;
case 'v':
verbose++; break;
case 'V':
version(); break;
case 'Z':
#ifdef LZW
do_lzw = 1; break;
#else
fprintf(stderr, "-Z not supported in this version\n");
usage();
do_exit(ERROR); break;
#endif
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
level = optc - '0';
break;
default:
/* Error message already emitted by getopt_long. */
usage();
do_exit(ERROR);
}
} /* loop on all arguments */
file_count = argc - optind;
if (do_lzw && !decompress) work = lzw;
/* Allocate all global buffers (for DYN_ALLOC option) */
ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
ALLOC(ush, d_buf, DIST_BUFSIZE);
ALLOC(uch, window, 2L*WSIZE);
#ifndef MAXSEG_64K
ALLOC(ush, tab_prefix, 1L<<BITS);
#else
ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
#endif
/* And get to work */
if (file_count != 0) {
if (to_stdout && !test) {
SET_BINARY_MODE(fileno(stdout));
}
while (optind < argc) {
treat_file(argv[optind++]);
}
} else { /* Standard input */
treat_stdin();
}
do_exit(exit_code);
return exit_code; /* just to avoid lint warning */
}
/* ========================================================================
* Compress or decompress stdin
*/
local void treat_stdin()
{
if (isatty(fileno((FILE *)(decompress ? stdin : stdout)))) {
/* Do not send compressed data to the terminal or read it from
* the terminal. We get here when user invoked the program
* without parameters, so be helpful.
*/
fprintf(stderr,
"Compressed data not %s a terminal. Redirect %s file or pipe.\n",
decompress ? "read from" : "written to",
decompress ? "from" : "to");
fprintf(stderr,"For help, type: %s -h\n", progname);
do_exit(ERROR);
}
SET_BINARY_MODE(fileno(stdin));
if (!test) SET_BINARY_MODE(fileno(stdout));
strcpy(ifname, "stdin");
strcpy(ofname, "stdout");
/* Get the time stamp on the input file */
#ifdef NO_STDIN_FSTAT
time_stamp = 0; /* time unknown */
#else
if (fstat(fileno(stdin), &istat) != 0) {
error("fstat(stdin)");
}
time_stamp = istat.st_mtime;
#endif
ifile_size = -1L; /* convention for unknown size */
clear_bufs(); /* clear input and output buffers */
to_stdout = 1;
part_nb = 0;
if (decompress) {
method = get_method(ifd);
if (method == -1) {
do_exit(exit_code); /* error message already emitted */
}
}
/* Actually do the compression/decompression. Loop over zipped members.
*/
for (;;) {
(*work)(fileno(stdin), fileno(stdout));
if (!decompress || last_member || inptr == insize) break;
/* end of file */
method = get_method(ifd);
if (method == -1) return; /* error message already emitted */
bytes_out = 0; /* required for length check */
}
if (verbose) {
if (test) {
fprintf(stderr, " OK");
} else if (!decompress) {
fprintf(stderr, "Compression: ");
display_ratio(bytes_in-bytes_out-overhead, bytes_in);
}
fprintf(stderr, "\n");
}
}
/* ========================================================================
* Compress or decompress the given file
*/
local void treat_file(iname)
char *iname;
{
/* Check if the input file is present, set ifname and istat: */
if (get_istat(iname, &istat) != 0) return;
/* If the input name is that of a directory, recurse or ignore: */
if (S_ISDIR(istat.st_mode)) {
#ifndef NO_DIR
if (recursive) {
treat_dir(iname);
/* Warning: ifname is now garbage */
} else
#endif
fprintf(stderr,"%s is a directory -- ignored\n", ifname);
if (exit_code == OK) exit_code = WARNING;
return;
}
if (!S_ISREG(istat.st_mode)) {
fprintf(stderr,"%s is not a directory or a regular file - ignored\n",
ifname);
return;
}
if (istat.st_nlink > 1 && !to_stdout && !force) {
fprintf(stderr, "%s has %d other link%c -- unchanged\n", ifname,
(int)istat.st_nlink - 1, istat.st_nlink > 2 ? 's' : ' ');
if (exit_code == OK) exit_code = WARNING;
return;
}
ifile_size = istat.st_size;
time_stamp = istat.st_mtime;
/* Generate output file name */
if (to_stdout) {
strcpy(ofname, "stdout");
} else if (make_ofname() != 0) {
return;
}
/* Open the input file and determine compression method */
ifd = open(ifname, O_RDONLY | O_BINARY);
if (ifd == -1) {
perror(ifname);
exit_code = ERROR;
return;
}
clear_bufs(); /* clear input and output buffers */
part_nb = 0;
if (decompress) {
method = get_method(ifd); /* updates ofname if original given */
if (method == -1) return; /* error message already emitted */
}
/* If compressing to a file, check if ofname is not ambigous
* because the operating system truncates names. Otherwise, generate
* a new ofname and save the original name in the compressed file.
*/
if (to_stdout) {
ofd = fileno(stdout);
/* keep remove_ofname as zero */
} else {
if (create_outfile() == -1) return;
if (save_orig_name && !verbose && !force) {
fprintf(stderr, "%s compressed to %s\n", ifname, ofname);
}
}
if (verbose) {
fprintf(stderr, "%s:\t%s", ifname, (int)strlen(ifname) >= 15 ?
"" : ((int)strlen(ifname) >= 7 ? "\t" : "\t\t"));
}
/* Actually do the compression/decompression. If testing only and
* input file is in LZW format (which has no CRC) skip it. Loop over
* zipped members.
*/
for (;;) {
(*work)(ifd, ofd);
if (!decompress || last_member || inptr == insize) break;
/* end of file */
method = get_method(ifd);
if (method == -1) break; /* error message already emitted */
bytes_out = 0; /* required for length check */
}
close(ifd);
if (!to_stdout && close(ofd)) {
write_error();
}
if (method == -1) return;
/* Display statistics */
if(verbose) {
if (!decompress) {
display_ratio(bytes_in-bytes_out-overhead, bytes_in);
}
if (test) {
fprintf(stderr, " OK");
} else if (!to_stdout) {
fprintf(stderr, " -- replaced with %s", ofname);
}
fprintf(stderr, "\n");
}
/* Copy modes, times, ownership */
if (!to_stdout) {
copy_stat(&istat);
}
}
/* ========================================================================
* Create the output file. Try twice if ofname is exactly one beyond the
* name limit, to avoid creating a compressed file of name "1234567890123."
* We could actually loop more than once if the user gives an extra long
* name, but I prefer generating an error then. (Posix forbids the system
* to truncate names.) The error message is generated by check_ofname()
* in this case.
* IN assertion: the input file has already been open (ifd is set) and
* ofname has already been updated if there was an original name.
*/
local int create_outfile()
{
struct stat ostat; /* stat for ofname */
int n; /* loop counter */
for (n = 1; n <= 2; n++) {
if (check_ofname() == -1) {
close(ifd);
return -1;
}
/* Create the output file */
remove_ofname = 1;
ofd = open(ofname, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, RW_USER);
if (ofd == -1) {
perror(ofname);
close(ifd);
exit_code = ERROR;
return -1;
}
/* Check for name truncation on new file (1234567890123.z) */
if (fstat(ofd, &ostat) != 0) {
perror(ofname);
fprintf(stderr, " fstat failed\n");
close(ifd); close(ofd);
unlink(ofname);
exit_code = ERROR;
return -1;
}
if (!name_too_long(ofname, &ostat)) return 0;
if (decompress) {
/* name might be too long if an original name was saved */
fprintf(stderr, " warning, name truncated: %s\n", ofname);
return 0;
} else {
#ifdef NO_MULTIPLE_DOTS
/* Should never happen, see check_ofname() */
fprintf(stderr, "ERROR: name too long: %s\n", ofname);
do_exit(ERROR);
#else
close(ofd);
unlink(ofname);
save_orig_name = 1;
strcpy(ofname+strlen(ofname)-3, ".z");
/* 1234567890123.z -> 123456789012.z */
#endif
} /* decompress ? */
} /* for (n) */
close(ifd);
fprintf(stderr, " name too long: %s\n", ofname);
exit_code = ERROR;
return -1;
}
/* ========================================================================
* Use lstat if available, except for -c or -f. Use stat otherwise.
* This allows links when not removing the original file.
*/
local int do_stat(name, sbuf)
char *name;
struct stat *sbuf;
{
#if (defined(S_IFLNK) || defined (S_ISLNK)) && !defined(NO_SYMLINK)
if (!to_stdout && !force) {
return lstat(name, sbuf);
}
#endif
return stat(name, sbuf);
}
/* ========================================================================
* Set ifname to the input file name (with .z appended if necessary)
* and istat to its stats. Return 0 if ok, -1 if error.
*/
local int get_istat(iname, sbuf)
char *iname;
struct stat *sbuf;
{
int iexists; /* set if iname exists */
int ilen = strlen(iname);
strcpy(ifname, iname);
errno = 0;
/* If input file exists, return OK. */
if (do_stat(ifname, sbuf) == 0) return 0;
if (!decompress || errno != ENOENT) {
perror(ifname);
exit_code = ERROR;
return -1;
}
/* file.ext doesn't exist, try file.ext.z and file.ext.Z (or file.extz) */
if (ilen < 3 || (strcmp(ifname + ilen - 2, ".Z") != 0
&& strcmp(ifname + ilen - 2, ".z") != 0)) {
#ifdef NO_MULTIPLE_DOTS
if (strrchr(ifname, '.') != NULL) {
strcat(ifname, "z"), ilen += 1;
} else
#endif
strcat(ifname, ".z"), ilen += 2;
errno = 0;
iexists = !do_stat(ifname, sbuf);
if (!iexists) {
errno = 0;
ifname[ilen-1] = 'Z';
iexists = !do_stat(ifname, sbuf);
}
#ifdef NO_MULTIPLE_DOTS
/* One more try just to be nice to you */
if (!iexists) {
char c = ifname[ilen-2];
errno = 0;
strcpy(ifname+ilen-2, "z");
iexists = !do_stat(ifname, sbuf);
if (!iexists) {
ifname[ilen-2] = c;
}
}
#endif
if (!iexists) {
ifname[ilen-1] = 'z';
perror(ifname);
exit_code = ERROR;
return -1;
}
if (!S_ISREG (sbuf->st_mode)) {
fprintf(stderr, "%s: Not a regular file -- ignored\n", ifname);
if (exit_code == OK) exit_code = WARNING;
return -1;
}
return 0; /* ok */
} /* try file.z */
perror(ifname); /* ifname and ifname.z do not exist */
exit_code = ERROR;
return -1;
}
/* ========================================================================
* Generate ofname given ifname. Return 0 if ok, -1 if file must be skipped.
* Initializes save_orig_name.
*/
local int make_ofname()
{
int iflen = strlen(ifname);
#ifdef NO_MULTIPLE_DOTS
int z_suffix = iflen > 2 && tolow(ifname[iflen-1]) == 'z';
#else
int z_suffix = iflen > 2 && (strcmp(ifname+iflen-2, ".z") == 0
|| strcmp(ifname+iflen-2, ".Z") == 0);
#endif
int zip_suffix = iflen > 4 && (strcmp(ifname+iflen-4, ".zip") == 0
|| strcmp(ifname+iflen-4, ".ZIP") == 0);
if (decompress) {
/* Be tolerant for "zcat foo.tar-z | tar xf -" but do not
* complain for "gunzip -r *". In other words, force .z suffix
* for gunzip but not zcat.
*/
if (!to_stdout && !z_suffix && !zip_suffix) {
if (verbose) {
fprintf(stderr,"%s -- no z suffix, ignored\n", ifname);
}
return -1;
}
strcpy(ofname, ifname);
if (z_suffix) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -