⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gzip.c

📁 采用 LZ77 运算规则 压缩及解压工具
💻 C
📖 第 1 页 / 共 3 页
字号:
	   /* Remove the z or .z suffix */
#ifdef NO_MULTIPLE_DOTS
	    if (ofname[iflen - 2] != '.') {
		ofname[iflen - 1] = '\0'; /* remove z suffix */
	    } else
#endif
	    ofname[iflen - 2] = '\0'; /* Remove the .z suffix */
	} else if (zip_suffix) {
	    ofname[iflen - 4] = '\0'; /* Remove the .zip suffix */
	}
	/* ofname might be changed later if infile contains an original name */

    } else { /* compress */
	if (z_suffix) {
	    /* Avoid annoying messages with -r (see treat_dir()) */
	    if (verbose || !recursive) {
		fprintf(stderr,"%s already has .%c suffix -- unchanged\n",
			ifname, ifname[iflen-1]);
	    }
	    return -1;
	}
	if (zip_suffix) {
	    fprintf(stderr,"%s already has .zip suffix -- unchanged\n",
		    ifname);
	    return -1;
	}
	strcpy(ofname, ifname);
	save_orig_name = 0;

#ifdef NO_MULTIPLE_DOTS
	{
	    char *p = strrchr(ofname, '.');
	    if (p != NULL) {
		strcat(ofname, do_lzw ? "Z" : "z");
		save_orig_name = 1;
		return 0;
	    }
	}
#endif
	strcat(ofname, do_lzw ? ".Z" : ".z");

    } /* decompress ? */
    return 0;
}


/* ========================================================================
 * 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.
 * 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;
    char magic[2]; /* magic header */

    magic[0] = (char)get_byte();
    magic[1] = (char)get_byte();

    time_stamp = istat.st_mtime; /* may be modified later for some methods */
    method = -1;                 /* unknown yet */
    part_nb++;                   /* number of parts in gzip file */
    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) {

	work = unzip;
	method = (int)get_byte();
	flags  = (uch)get_byte();
	if ((flags & ENCRYPTED) != 0) {
	    fprintf(stderr, "%s is encrypted -- get newer version of gzip\n",
		    ifname);
	    exit_code = ERROR;
	    return -1;
	}
	if ((flags & CONTINUATION) != 0) {
	    fprintf(stderr,
	       "%s is a a multi-part gzip file -- get newer version of gzip\n",
		    ifname);
	    exit_code = ERROR;
	    if (force <= 1) return -1;
	}
	if ((flags & RESERVED) != 0) {
	    fprintf(stderr, "%s has flags 0x%x -- get newer version of gzip\n",
		    ifname, flags);
	    exit_code = ERROR;
	    if (force <= 1) return -1;
	}
	time_stamp  = (ulg)get_byte();
	time_stamp |= ((ulg)get_byte()) << 8;
	time_stamp |= ((ulg)get_byte()) << 16;
	time_stamp |= ((ulg)get_byte()) << 24;

	(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: part number %u\n",
			ifname, part);
	    }
	}
	if ((flags & EXTRA_FIELD) != 0) {
	    unsigned len = (unsigned)get_byte();
	    len |= ((unsigned)get_byte())<<8;
	    if (verbose) {
		fprintf(stderr,"%s: extra field of %u bytes ignored\n",
			ifname, len);
	    }
	    while (len--) (void)get_byte();
	}

	/* Get original file name if it was truncated */
	if ((flags & ORIG_NAME) != 0) {
	    if (to_stdout || part_nb > 1) {
		/* Discard the old name */
		while (get_byte() != 0) /* null */ ;
	    } else {
		/* Copy the base name. Keep a directory prefix intact. */
		char *p = basename(ofname);
		for (;;) {
		    *p = (char)get_byte();
		    if (*p++ == '\0') break;
		    if (p >= ofname+sizeof(ofname)) {
			error("corrupted input -- file name too large");
		    }
		}
	    } /* to_stdout */
	} /* orig_name */

	/* Discard file comment if any */
	if ((flags & COMMENT) != 0) {
	    while (get_byte() != 0) /* null */ ;
	}

    } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
	    && memcmp(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) == -1) 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;
    }
    if (method == -1) {
	fprintf(stderr, part_nb == 1 ? "%s is not in gzip format\n"
				     : "trailing garbage ignored in %s\n",
		ifname);
	fflush(stderr);
	if (exit_code != ERROR) exit_code = part_nb == 1 ? ERROR : WARNING;
	return part_nb == 1 ? -1 : -2;
    }
    return method;
}

/* ========================================================================
 * Return true if the two stat structures correspond to the same file.
 */
local int same_file(stat1, stat2)
    struct stat *stat1;
    struct stat *stat2;
{
    return stat1->st_mode  == stat2->st_mode
	&& stat1->st_ino   == stat2->st_ino
	&& stat1->st_dev   == stat2->st_dev
	&& stat1->st_uid   == stat2->st_uid
	&& stat1->st_gid   == stat2->st_gid
	&& stat1->st_size  == stat2->st_size
	&& stat1->st_atime == stat2->st_atime
	&& stat1->st_mtime == stat2->st_mtime
	&& stat1->st_ctime == stat2->st_ctime;
}

/* ========================================================================
 * Return true if a file name is ambigous 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 */
{
    int s = 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;
    return res;
}

/* ========================================================================
 * 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 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()
{
    int s = strlen(ofname);
    struct stat ostat; /* stat for ofname */

    if (stat(ofname, &ostat) != 0) return 0;

    /* Check for name truncation on existing file: */
#ifdef NO_MULTIPLE_DOTS
    if (!decompress && name_too_long(ofname, &ostat)) {
#else
    if (!decompress && s > 8 && name_too_long(ofname, &ostat)) {
#endif
	save_orig_name = 1;
#ifdef NO_MULTIPLE_DOTS
	strcpy(ofname+s-2, "z");  /* f.extz -> f.exz  */
#else
	strcpy(ofname+s-4, ".z"); /* 12345678901234.z -> 123456789012.z */
#endif
	if (stat(ofname, &ostat) != 0) return 0;
    } /* !decompress && name_too_long */

    /* Check that the input and output files are different (could be
     * the same by name truncation or links).
     */
    if (same_file(&istat, &ostat)) {
	fprintf(stderr, "error: %s and %s are the same file\n",
		ifname, ofname);
	exit_code = ERROR;
	return -1;
    }
    /* Ask permission to overwrite the existing file */
    if (!force) {
	char response[80];
	strcpy(response,"n");
	fprintf(stderr, "%s already exists;", ofname);
	if (foreground && isatty(fileno(stdin))) {
	    fprintf(stderr, " do you wish to overwrite (y or n)? ");
	    fflush(stderr);
	    (void)read(fileno(stdin), response, sizeof(response));
	}
	if (tolow(*response) != 'y') {
	    fprintf(stderr, "\tnot overwritten\n");
	    if (exit_code == OK) exit_code = WARNING;
	    return -1;
	}
    }
    if (unlink(ofname)) {
	fprintf(stderr, "Can't remove old output file\n");
	perror(ofname);
	exit_code = ERROR;
	return -1;
    }
    return 0;
}


/* ========================================================================
 * Copy modes, times, ownership.
 * IN assertion: to_stdout is false.
 */
local void copy_stat(ifstat)
    struct stat *ifstat;
{
#ifndef NO_UTIME
    struct utimbuf      timep;

    /* Copy the time stamp */
    timep.actime = ifstat->st_atime;
    timep.modtime = ifstat->st_mtime;

    if (decompress && timep.modtime != time_stamp && time_stamp != 0) {
	timep.modtime = time_stamp;
	if (verbose) {
	    fprintf(stderr, " (time stamp restored)\n");
	}
    }
    if (utime(ofname, &timep)) {
	fprintf(stderr, "\nutime error (ignored) ");
	perror(ofname);
	if (exit_code == OK) exit_code = WARNING;
    }
#endif
    /* Copy the protection modes */
    if (chmod(ofname, ifstat->st_mode & 07777)) {
	fprintf(stderr, "\nchmod error (ignored) ");
	perror(ofname);
	if (exit_code == OK) exit_code = WARNING;
    }
#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: */
    if (unlink(ifname)) {
	fprintf(stderr, "\nunlink error (ignored) ");
	perror(ifname);
	if (exit_code == OK) exit_code = WARNING;
    }
}

#ifndef NO_DIR

/* ========================================================================
 * Recurse through the given directory. This code is taken from ncompress.
 */
local void treat_dir(dir)
    char *dir;
{
    dir_type *dp;
    DIR      *dirp;
    char     nbuf[MAX_PATH_LEN];

    dirp = opendir(dir);
    
    if (dirp == NULL) {
	fprintf(stderr, "%s unreadable\n", dir);
	return ;
    }
    /*
     ** WARNING: the following algorithm could occasionally cause
     ** compress to produce error warnings of the form "<filename>.z
     ** already has .z suffix - ignored". This occurs when the
     ** .z 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 (dp->d_ino == 0) {
	    continue;
	}
	if (strcmp(dp->d_name,".") == 0 || strcmp(dp->d_name,"..") == 0) {
	    continue;
	}
	if (((int)strlen(dir) + NLENGTH(dp) + 1) < (MAX_PATH_LEN - 1)) {
	    strcpy(nbuf,dir);
	    if (strlen(dir) > 0) { /* dir = "" means current dir on Amiga */
#ifdef OTHER_PATH_SEP
		if (dir[strlen(dir)-1] != OTHER_PATH_SEP)
#endif
		strcat(nbuf,"/");
	    }
	    strcat(nbuf,dp->d_name);
	    treat_file(nbuf);
	} else {
	    fprintf(stderr,"Pathname too long: %s/%s\n", dir, dp->d_name);
	}
    }
    closedir(dirp);
}
#endif /* ? NO_DIR */

/* ========================================================================
 * Free all dynamically allocated variables and exit with the given code.
 */
local void do_exit(exitcode)
    int exitcode;
{
    if (env != NULL)  free(env),  env  = NULL;
    if (args != NULL) free(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);
}

/* ========================================================================
 * Signal and error handler.
 */
RETSIGTYPE abort_gzip(void)
{
   if (remove_ofname) {
       close(ofd);
       unlink (ofname);
   }
   do_exit(ERROR);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -