📄 gzip.c
字号:
* Return true if a file name is ambiguous because the operating system * truncates file names. */local int name_too_long(name, statb) char *name; /* file name to check */ struct stat *statb; /* stat buf for this file name */{ DBGPrintfi(("name_too_long(In)\r\n")); { int s = (int)strlen(name); char c = name[s-1]; struct stat tstat; /* stat for truncated name */ int res; tstat = *statb; /* Just in case OS does not fill all fields */ name[s-1] = '\0'; res = stat(name, &tstat) == 0 && same_file(statb, &tstat); name[s-1] = c; Trace((stderr, " too_long(%s) => %d\n", name, res)); DBGPrintfo(("name_too_long(out1)\r\n")); return res; }}/* ======================================================================== * Shorten the given name by one character, or replace a .tar extension * with .tgz. Truncate the last part of the name which is longer than * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name * has only parts shorter than MIN_PART truncate the longest part. * For decompression, just remove the last character of the name. * * IN assertion: for compression, the suffix of the given name is z_suffix. */local int shorten_name(name) char *name;{ DBGPrintfi(("shorten_name(In)\r\n")); { int len; /* length of name without z_suffix */ char *trunc = NULL; /* character to be truncated */ int plen; /* current part length */ int min_part = MIN_PART; /* current minimum part length */ char *p; len = (int)strlen(name); if (decompress) { if (len <= 1) { error("name too short"); DBGPrintfo(("shorten_name(out10)\r\n")); return -1; } name[len-1] = '\0'; DBGPrintfo(("shorten_name(out1)\r\n")); return 0; } p = get_suffix(name); if (p == NULL) { error("can't recover suffix\n"); DBGPrintfo(("shorten_name(out11)\r\n")); return -1; } *p = '\0'; save_orig_name = 1; /* compress 1234567890.tar to 1234567890.tgz */ if (len > 4 && strequ(p-4, ".tar")) { strcpy(p-4, ".tgz"); DBGPrintfo(("shorten_name(out2)\r\n")); return 0; } /* Try keeping short extensions intact: * 1234.678.012.gz -> 123.678.012.gz */ do { p = strrchr(name, PATH_SEP); p = p ? p+1 : name; while (*p) { plen = (int)strcspn(p, PART_SEP); p += plen; if (plen > min_part) trunc = p-1; if (*p) p++; } } while (trunc == NULL && --min_part != 0); if (trunc != NULL) { do { trunc[0] = trunc[1]; } while (*trunc++); trunc--; } else { trunc = strrchr(name, PART_SEP[0]); if (trunc == NULL) { error("internal error in shorten_name"); DBGPrintfo(("shorten_name(out3)\r\n")); return -1; } if (trunc[1] == '\0') trunc--; /* force truncation */ } strcpy(trunc, z_suffix); } DBGPrintfo(("shorten_name(out)\r\n")); return 0;}/* ======================================================================== * 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 the compressed file already exists, ask for confirmation. * The check for name truncation is made dynamically, because different * file systems on the same OS might use different truncation rules (on SVR4 * s5 truncates to 14 chars and ufs does not truncate). * This function returns -1 if the file must be skipped, and * updates save_orig_name if necessary. * IN assertions: save_orig_name is already set if ofname has been * already truncated because of NO_MULTIPLE_DOTS. The input file has * already been open and istat is set. */local int check_ofname(){ DBGPrintfi(("check_ofname(In)\r\n")); { struct stat ostat; /* stat for ofname */#ifdef ENAMETOOLONG /* Check for strictly conforming Posix systems (which return ENAMETOOLONG * instead of silently truncating filenames). */ errno = 0; while (stat(ofname, &ostat) != 0) { if (errno != ENAMETOOLONG) { DBGPrintfo(("check_ofname(out1)\r\n")); return 0; } /* ofname does not exist */ if ( shorten_name(ofname) < 0 ) { DBGPrintfo(("check_ofname(out11)\r\n")); return ERROR; } }#else if (stat(ofname, &ostat) != 0) { DBGPrintfo(("check_ofname(out2)\r\n")); return 0; }#endif /* Check for name truncation on existing file. Do this even on systems * defining ENAMETOOLONG, because on most systems the strict Posix * behavior is disabled by default (silent name truncation allowed). */ if (!decompress && name_too_long(ofname, &ostat)) { if ( shorten_name(ofname) < 0 ) { DBGPrintfo(("check_ofname(out30)\r\n")); return -1; } if (stat(ofname, &ostat) != 0) { DBGPrintfo(("check_ofname(out3)\r\n")); return 0; } } /* Check that the input and output files are different (could be * the same by name truncation or links). */ if (same_file(&istat, &ostat)) { if (strequ(ifname, ofname)) { fprintf(stderr, "%s: %s: cannot %scompress onto itself\n", progname, ifname, decompress ? "de" : ""); } else { fprintf(stderr, "%s: %s and %s are the same file\n", progname, ifname, ofname); } exit_code = ERROR; DBGPrintfo(("check_ofname(out4)\r\n")); return ERROR; } /* Ask permission to overwrite the existing file */ if (!force) { char response[80]; strcpy(response,"n"); fprintf(stderr, "%s: %s already exists;", progname, ofname); if (foreground && isatty(fileno(stdin))) { fprintf(stderr, " do you wish to overwrite (y or n)? "); fflush(stderr); (void)fgets(response, sizeof(response)-1, stdin); } if (tolow(*response) != 'y') { fprintf(stderr, "\tnot overwritten\n"); if (exit_code == OK) exit_code = WARNING; DBGPrintfo(("check_ofname(out5)\r\n")); return ERROR; } } (void) chmod(ofname, 0777); if (unlink(ofname)) { fprintf(stderr, "%s: ", progname); perror(ofname); exit_code = ERROR; DBGPrintfo(("check_ofname(out6)\r\n")); return ERROR; } DBGPrintfo(("check_ofname(out7)\r\n")); return OK; }}#ifndef NO_UTIME/* ======================================================================== * Set the access and modification times from the given stat buffer. */local void reset_times (name, statb) char *name; struct stat *statb;{ DBGPrintfi(("reset_times(In)\r\n")); { struct utimbuf timep; /* Copy the time stamp */ timep.actime = statb->st_atime; timep.modtime = statb->st_mtime; /* Some systems (at least OS/2) do not support utime on directories */ if (utime(name, &timep) && !S_ISDIR(statb->st_mode)) { WARN((stderr, "%s: ", progname)); if (!quiet) perror(ofname); } } DBGPrintfo(("reset_times(out)\r\n"));}#endif/* ======================================================================== * Copy modes, times, ownership from input file to output file. * IN assertion: to_stdout is false. */local void copy_stat(ifstat) struct stat *ifstat;{ DBGPrintfi(("copy_stat(In)\r\n")); {#ifndef NO_UTIME if (decompress && time_stamp != 0 && ifstat->st_mtime != time_stamp) { ifstat->st_mtime = time_stamp; if (verbose > 1) { fprintf(stderr, "%s: time stamp restored\n", ofname); } } reset_times(ofname, ifstat);#endif /* Copy the protection modes */ if (chmod(ofname, ifstat->st_mode & 07777)) { WARN((stderr, "%s: ", progname)); if (!quiet) perror(ofname); }#ifndef NO_CHOWN chown(ofname, ifstat->st_uid, ifstat->st_gid); /* Copy ownership */#endif remove_ofname = 0; /* It's now safe to remove the input file: */ (void) chmod(ifname, 0777); if (unlink(ifname)) { WARN((stderr, "%s: ", progname)); if (!quiet) perror(ifname); } } DBGPrintfo(("copy_stat(out)\r\n"));}#ifndef NO_DIR/* ======================================================================== * Recurse through the given directory. This code is taken from ncompress. */local void treat_dir(dir) char *dir;{ DBGPrintfi(("treat_dir(In)\r\n")); { dir_type *dp; DIR *dirp; char nbuf[MAX_PATH_LEN]; int len; dirp = opendir(dir); if (dirp == NULL) { fprintf(stderr, "%s: %s unreadable\n", progname, dir); exit_code = ERROR; DBGPrintfo(("treat_dir(out1)\r\n")); return ; } /* ** WARNING: the following algorithm could occasionally cause ** compress to produce error warnings of the form "<filename>.gz ** already has .gz suffix - ignored". This occurs when the ** .gz output file is inserted into the directory below ** readdir's current pointer. ** These warnings are harmless but annoying, so they are suppressed ** with option -r (except when -v is on). An alternative ** to allowing this would be to store the entire directory ** list in memory, then compress the entries in the stored ** list. Given the depth-first recursive algorithm used here, ** this could use up a tremendous amount of memory. I don't ** think it's worth it. -- Dave Mack ** (An other alternative might be two passes to avoid depth-first.) */ while ((dp = readdir(dirp)) != NULL) { if (strequ(dp->d_name,".") || strequ(dp->d_name,"..")) { continue; } len = strlen(dir); if (len + NLENGTH(dp) + 1 < MAX_PATH_LEN - 1) { strcpy(nbuf,dir); if (len != 0 /* dir = "" means current dir on Amiga */#ifdef PATH_SEP2 && dir[len-1] != PATH_SEP2#endif#ifdef PATH_SEP3 && dir[len-1] != PATH_SEP3#endif ) { nbuf[len++] = PATH_SEP; } strcpy(nbuf+len, dp->d_name); treat_file(nbuf); } else { fprintf(stderr,"%s: %s/%s: pathname too long\n", progname, dir, dp->d_name); exit_code = ERROR; } } closedir(dirp); } DBGPrintfo(("treat_dir(out)\r\n"));}#endif /* ? NO_DIR *//* ======================================================================== * Free all dynamically allocated variables and exit with the given code. */extern void TPEG_free(void * mem);int in_exit = 0;local void do_exit(exitcode) int exitcode;{ DBGPrintfi(("do_exit(In)\r\n")); { if (in_exit) { DBGPrintfo(("do_exit(out1)\r\n")); return; } in_exit = 1; if (env != NULL) TPEG_free(env), env = NULL; if (args != NULL) TPEG_free((char*)args), args = NULL;// if (env != NULL) free(env), env = NULL;// if (args != NULL) free((char*)args), args = NULL; FREE(inbuf); FREE(outbuf); FREE(d_buf); FREE(window);#ifndef MAXSEG_64K FREE(tab_prefix);#else FREE(tab_prefix0); FREE(tab_prefix1);#endif //exit(exitcode); } DBGPrintfo(("do_exit(out)\r\n"));}#if 0local void do_exit(exitcode) int exitcode;{ DBGPrintfi(("do_exit(In)\r\n")); { static int in_exit = 0; if (in_exit) exit(exitcode); in_exit = 1; if (env != NULL) free(env), env = NULL; if (args != NULL) free((char*)args), args = NULL; FREE(inbuf); FREE(outbuf); FREE(d_buf); FREE(window);#ifndef MAXSEG_64K FREE(tab_prefix);#else FREE(tab_prefix0); FREE(tab_prefix1);#endif exit(exitcode); } DBGPrintfo(("do_exit(out)\r\n"));}#endif/* ======================================================================== * Signal and error handler. */// by bskimRETSIGTYPE abort_gzip(){ DBGPrintfi(("abort_gzip(In)\r\n")); {// if (remove_ofname) {// close(ofd);// unlink (ofname);// } do_exit(ERROR); } DBGPrintfo(("abort_gzip(Out)\r\n"));}#if 0RETSIGTYPE abort_gzip(){ DBGPrintfi(("abort_gzip(In)\r\n")); { if (remove_ofname) { close(ofd); unlink (ofname); } do_exit(ERROR); }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -