📄 gzip.c
字号:
return ERROR; } /* Create the output file */ remove_ofname = 1; ofd = OPEN(ofname, flags, RW_USER); if (ofd == -1) { perror(ofname); close(ifd); exit_code = ERROR; return ERROR; } /* Check for name truncation on new file (1234567890123.gz) */#ifdef NO_FSTAT if (stat(ofname, &ostat) != 0) {#else if (fstat(ofd, &ostat) != 0) {#endif fprintf(stderr, "%s: ", progname); perror(ofname); close(ifd); close(ofd); unlink(ofname); exit_code = ERROR; return ERROR; } if (!name_too_long(ofname, &ostat)) return OK; if (decompress) { /* name might be too long if an original name was saved */ WARN((stderr, "%s: %s: warning, name truncated\n", progname, ofname)); return OK; } close(ofd); unlink(ofname);#ifdef NO_MULTIPLE_DOTS /* Should never happen, see check_ofname() */ fprintf(stderr, "%s: %s: name too long\n", progname, ofname); do_exit(ERROR);#endif shorten_name(ofname); }}/* ======================================================================== * 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;{ errno = 0;#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, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are * accepted suffixes, in addition to the value of the --suffix option. * ".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. * On systems allowing multiple versions of the same file (such as VMS), * this function removes any version suffix in the given name. */local char *get_suffix(name) char *name;{ int nlen, slen; char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */ static char *known_suffixes[] = {z_suffix, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",#ifdef MAX_EXT_CHARS "z",#endif NULL}; char **suf = known_suffixes; if (strequ(z_suffix, "z")) suf++; /* check long suffixes first */#ifdef SUFFIX_SEP /* strip a version number from the file name */ { char *v = strrchr(name, SUFFIX_SEP); if (v != NULL) *v = '\0'; }#endif nlen = strlen(name); if (nlen <= MAX_SUFFIX+2) { strcpy(suffix, name); } else { strcpy(suffix, name+nlen-MAX_SUFFIX-2); } strlwr(suffix); slen = strlen(suffix); do { int s = strlen(*suf); if (slen > s && suffix[slen-s-1] != PATH_SEP && strequ(suffix + slen - s, *suf)) { return name+nlen-s; } } while (*++suf != NULL); return NULL;}/* ======================================================================== * Set ifname to the input file name (with a suffix appended if necessary) * and istat to its stats. For decompression, if no file exists with the * original name, try adding successively z_suffix, .gz, .z, -z and .Z. * For MSDOS, we try only z_suffix and z. * Return OK or ERROR. */local int get_istat(iname, sbuf) char *iname; struct stat *sbuf;{ int ilen; /* strlen(ifname) */ static char *suffixes[] = {z_suffix, ".gz", ".z", "-z", ".Z", NULL}; char **suf = suffixes; char *s;#ifdef NO_MULTIPLE_DOTS char *dot; /* pointer to ifname extension, or NULL */#endif strcpy(ifname, iname); /* If input file exists, return OK. */ if (do_stat(ifname, sbuf) == 0) return OK; if (!decompress || errno != ENOENT) { perror(ifname); exit_code = ERROR; return ERROR; } /* file.ext doesn't exist, try adding a suffix (after removing any * version number for VMS). */ s = get_suffix(ifname); if (s != NULL) { perror(ifname); /* ifname already has z suffix and does not exist */ exit_code = ERROR; return ERROR; }#ifdef NO_MULTIPLE_DOTS dot = strrchr(ifname, '.'); if (dot == NULL) { strcat(ifname, "."); dot = strrchr(ifname, '.'); }#endif ilen = strlen(ifname); if (strequ(z_suffix, ".gz")) suf++; /* Search for all suffixes */ do { s = *suf;#ifdef NO_MULTIPLE_DOTS if (*s == '.') s++;#endif#ifdef MAX_EXT_CHARS strcpy(ifname, iname); /* Needed if the suffixes are not sorted by increasing length */ if (*dot == '\0') strcpy(dot, "."); dot[MAX_EXT_CHARS+1-strlen(s)] = '\0';#endif strcat(ifname, s); if (do_stat(ifname, sbuf) == 0) return OK; ifname[ilen] = '\0'; } while (*++suf != NULL); /* No suffix found, complain using z_suffix: */#ifdef MAX_EXT_CHARS strcpy(ifname, iname); if (*dot == '\0') strcpy(dot, "."); dot[MAX_EXT_CHARS+1-z_len] = '\0';#endif strcat(ifname, z_suffix); perror(ifname); exit_code = ERROR; return ERROR;}/* ======================================================================== * Generate ofname given ifname. Return OK, or WARNING if file must be skipped. * Sets save_orig_name to true if the file name has been truncated. */local int make_ofname(){ char *suff; /* ofname z suffix */ strcpy(ofname, ifname); /* strip a version number if any and get the gzip suffix if present: */ suff = get_suffix(ofname); if (decompress) { if (suff == NULL) { /* Whith -t or -l, try all files (even without .gz suffix) * except with -r (behave as with just -dr). */ if (!recursive && (list || test)) return OK; /* Avoid annoying messages with -r */ if (verbose || (!recursive && !quiet)) { WARN((stderr,"%s: %s: unknown suffix -- ignored\n", progname, ifname)); } return WARNING; } /* Make a special case for .tgz and .taz: */ strlwr(suff); if (strequ(suff, ".tgz") || strequ(suff, ".taz")) { strcpy(suff, ".tar"); } else { *suff = '\0'; /* strip the z suffix */ } /* ofname might be changed later if infile contains an original name */ } else if (suff != NULL) { /* Avoid annoying messages with -r (see treat_dir()) */ if (verbose || (!recursive && !quiet)) { fprintf(stderr, "%s: %s already has %s suffix -- unchanged\n", progname, ifname, suff); } if (exit_code == OK) exit_code = WARNING; return WARNING; } else { save_orig_name = 0;#ifdef NO_MULTIPLE_DOTS suff = strrchr(ofname, '.'); if (suff == NULL) { strcat(ofname, ".");# ifdef MAX_EXT_CHARS if (strequ(z_suffix, "z")) { strcat(ofname, "gz"); /* enough room */ return OK; } /* On the Atari and some versions of MSDOS, name_too_long() * does not work correctly because of a bug in stat(). So we * must truncate here. */ } else if (strlen(suff)-1 + z_len > MAX_SUFFIX) { suff[MAX_SUFFIX+1-z_len] = '\0'; save_orig_name = 1;# endif }#endif /* NO_MULTIPLE_DOTS */ strcat(ofname, z_suffix); } /* decompress ? */ return OK;}/* ======================================================================== * Check the magic number of the input file and update ofname if an * original name was given and to_stdout is not set. * Return the compression method, -1 for error, -2 for warning. * Set inptr to the offset of the next byte to be processed. * Updates time_stamp if there is one and --no-time is not used. * This function may be called repeatedly for an input file consisting * of several contiguous gzip'ed members. * IN assertions: there is at least one remaining compressed member. * If the member is a zip file, it must be the only one. */local int get_method(in) int in; /* input file descriptor */{ uch flags; /* compression flags */ char magic[2]; /* magic header */ ulg stamp; /* time stamp */ /* If --force and --stdout, zcat == cat, so do not complain about * premature end of file: use try_byte instead of get_byte. */ if (force && to_stdout) { magic[0] = (char)try_byte(); magic[1] = (char)try_byte(); /* If try_byte returned EOF, magic[1] == 0xff */ } else { magic[0] = (char)get_byte(); magic[1] = (char)get_byte(); } method = -1; /* unknown yet */ part_nb++; /* number of parts in gzip file */ header_bytes = 0; last_member = RECORD_IO; /* assume multiple members in gzip file except for record oriented I/O */ if (memcmp(magic, GZIP_MAGIC, 2) == 0 || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) { method = (int)get_byte(); if (method != DEFLATED) { fprintf(stderr, "%s: %s: unknown method %d -- get newer version of gzip\n", progname, ifname, method); exit_code = ERROR; return -1; } work = unzip; flags = (uch)get_byte(); if ((flags & ENCRYPTED) != 0) { fprintf(stderr, "%s: %s is encrypted -- get newer version of gzip\n", progname, ifname); exit_code = ERROR; return -1; } if ((flags & CONTINUATION) != 0) { fprintf(stderr, "%s: %s is a a multi-part gzip file -- get newer version of gzip\n", progname, ifname); exit_code = ERROR; if (force <= 1) return -1; } if ((flags & RESERVED) != 0) { fprintf(stderr, "%s: %s has flags 0x%x -- get newer version of gzip\n", progname, ifname, flags); exit_code = ERROR; if (force <= 1) return -1; } stamp = (ulg)get_byte(); stamp |= ((ulg)get_byte()) << 8; stamp |= ((ulg)get_byte()) << 16; stamp |= ((ulg)get_byte()) << 24; if (stamp != 0 && !no_time) time_stamp = stamp; (void)get_byte(); /* Ignore extra flags for the moment */ (void)get_byte(); /* Ignore OS type for the moment */ if ((flags & CONTINUATION) != 0) { unsigned part = (unsigned)get_byte(); part |= ((unsigned)get_byte())<<8; if (verbose) { fprintf(stderr,"%s: %s: part number %u\n", progname, ifname, part); } } if ((flags & EXTRA_FIELD) != 0) { unsigned len = (unsigned)get_byte(); len |= ((unsigned)get_byte())<<8; if (verbose) { fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n", progname, ifname, len); } while (len--) (void)get_byte(); } /* Get original file name if it was truncated */ if ((flags & ORIG_NAME) != 0) { if (no_name || (to_stdout && !list) || part_nb > 1) { /* Discard the old name */ char c; /* dummy used for NeXTstep 3.0 cc optimizer bug */ do {c=get_byte();} while (c != 0); } else { /* Copy the base name. Keep a directory prefix intact. */ char *p = basename(ofname); char *base = p; for (;;) { *p = (char)get_char(); if (*p++ == '\0') break; if (p >= ofname+sizeof(ofname)) { error("corrupted input -- file name too large"); } } /* If necessary, adapt the name to local OS conventions: */ if (!list) { MAKE_LEGAL_NAME(base); if (base) list=0; /* avoid warning about unused variable */ } } /* no_name || to_stdout */ } /* ORIG_NAME */ /* Discard file comment if any */ if ((flags & COMMENT) != 0) { while (get_char() != 0) /* null */ ; } if (part_nb == 1) { header_bytes = inptr + 2*sizeof(long); /* include crc and size */ } } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2 && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0) { /* To simplify the code, we support a zip file when alone only. * We are thus guaranteed that the entire local header fits in inbuf. */ inptr = 0; work = unzip; if (check_zipfile(in) != OK) return -1; /* check_zipfile may get ofname from the local header */ last_member = 1; } else if (memcmp(magic, PACK_MAGIC, 2) == 0) { work = unpack; method = PACKED; } else if (memcmp(magic, LZW_MAGIC, 2) == 0) { work = unlzw; method = COMPRESSED; last_member = 1; } else if (memcmp(magic, LZH_MAGIC, 2) == 0) { work = unlzh; method = LZHED; last_member = 1; } else if (force && to_stdout && !list) { /* pass input unchanged */ method = STORED; work = copy; inptr = 0; last_member = 1; } if (method >= 0) return method; if (part_nb == 1) { fprintf(stderr, "\n%s: %s: not in gzip format\n", progname, ifname); exit_code = ERROR; return -1; } else { WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n", progname, ifname)); return -2; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -