📄 gzip.c
字号:
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. However, on systems supporting * pseudo ttys, let the beginner stare at the 'hung' program * (explicity request from Noah Friedman). Don't give an error message * if the user only wanted the version number (gzip -V). */ if (quit_on_tty) do_exit(OK);#ifdef NO_PTY fprintf(stderr, "%s: compressed data not %s a terminal. Redirect %s file or pipe.\n", progname, decompress ? "read from" : "written to", decompress ? "from" : "to"); fprintf(stderr,"For help, type: %s -h\n", progname); do_exit(ERROR);#endif } 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 < 0) { 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) { struct stat st; st = istat; treat_dir(iname); /* Warning: ifname is now garbage */ reset_times (iname, &st); } else#endif WARN((stderr,"%s: %s is a directory -- ignored\n", progname, ifname)); return; } if (!S_ISREG(istat.st_mode)) { WARN((stderr, "%s: %s is not a directory or a regular file - ignored\n", progname, ifname)); return; } if (istat.st_nlink > 1 && !to_stdout && !force) { WARN((stderr, "%s: %s has %d other link%c -- unchanged\n", progname, ifname, (int)istat.st_nlink - 1, istat.st_nlink > 2 ? 's' : ' ')); 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. The mode * parameter is ignored but required by some systems (VMS). */ ifd = open(ifname, O_RDONLY | O_BINARY, RW_USER); 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 < 0) { close(ifd); return; /* error message already emitted */ } } /* If compressing to a file, check if ofname is not ambiguous * 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 && !quiet) { fprintf(stderr, "%s: %s compressed to %s\n", progname, 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. Loop over zipped members. */ for (;;) { (*work)(ifd, ofd); if (!decompress || last_member || inptr == insize) break; /* end of file */ method = get_method(ifd); if (method < 0) 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; /* error, don't display success msg */ /* 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. Return 0 for success, -1 for error. * 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 assertions: the input file has already been open (ifd is set) and * ofname has already been updated if there was an original name. * OUT assertions: ifd and ofd are closed in case of error. */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) { fprintf(stderr, "%s: ", progname); perror(ofname); 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 */ WARN((stderr, "%s: %s: warning, name truncated\n", progname, ofname)); return 0; } else {#ifdef NO_MULTIPLE_DOTS /* Should never happen, see check_ofname() */ fprintf(stderr, "%s: %s: name too long\n", progname, ofname); do_exit(ERROR);#else close(ofd); unlink(ofname); save_orig_name = 1; strcpy(ofname+strlen(ofname)-Z_LEN-1, Z_SUFFIX); /* 1234567890123.z -> 123456789012.z */#endif } /* decompress ? */ } /* for (n) */ close(ifd); fprintf(stderr, "%s: %s: name too long\n", progname, 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);}/* ======================================================================== * Return a pointer to the 'z' suffix of a file name, or NULL. * For all systems, ".z", ".Z", ".taz", ".tgz", "-z" are accepted suffixes. * ".tgz" is a useful convention for tar.z files on systems limited * to 3 characters extensions. On such systems, ".?z" and ".??z" are * also accepted suffixes. For Unix, we do not want to accept any * .??z suffix as indicating a compressed file; some people use .xyz * to denote volume data. */local char *get_suffix(name) char *name;{ int len; char *p = strrchr(name, '.'); char suffix[10]; /* last few chars of name, forced to lower case */ if (p == NULL || p == name || strchr(p-1, PATH_SEP) != NULL) return NULL; strncpy(suffix, p, sizeof(suffix)); suffix[sizeof(suffix)-1] = '\0'; /* Force null termination */#ifdef SUFFIX_SEP /* strip a version number from the file name */ { char *v = strrchr(suffix, SUFFIX_SEP); if (v != NULL) *v = '\0'; }#endif strlwr(suffix); if (strequ(suffix, ".z") || strequ(suffix, ".zip") || strequ(suffix, ".tgz") || strequ(suffix, ".taz")) { return p; } len = strlen(suffix); if (len <= 2) return NULL; if (strequ(suffix+len-2, "-z")) return p+len-2;#ifdef MAX_EXT_CHARS if (suffix[len-1] == 'z') return p+len-1;#endif return NULL;}/* ======================================================================== * 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); char *suff; 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. For MSDOS * try file.exz, for VMS try file.ext-z. */ suff = get_suffix(ifname); if (suff != NULL) { perror(ifname); /* ifname already has z suffix and does not exist */ exit_code = ERROR; return -1; }#ifdef SUFFIX_SEP /* strip a version number from the input file name */ if ((suff = strrchr(ifname, SUFFIX_SEP)) != NULL) *suff = '\0';#endif if (strrchr(ifname, '.') != NULL) { strcat(ifname, Z_SUFFIX); ilen += Z_LEN; } else { 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)) { WARN((stderr, "%s: %s: not a regular file -- ignored\n", progname, ifname)); return -1; } return 0; /* ok */}/* ======================================================================== * Generate ofname given ifname. Return 0 if ok, -1 if file must be skipped. * Initializes save_orig_name. * IN assertion: this function is not called if to_stdout is true. */local int make_ofname(){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -