From: joeyh Date: Tue, 2 Oct 2007 19:01:19 +0000 (+0000) Subject: merge from paravoid X-Git-Tag: 0.2~29 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a99c1d42cad5e7bddacfba0d39d3ac044c9c6414;p=tools%2Fpristine-tar.git merge from paravoid --- diff --git a/Makefile b/Makefile index ba573c9..7efc0e5 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,5 @@ -bsd-gzip: bsd-gzip.c - gcc -O2 -DNO_COMPRESS_SUPPORT -DNO_BZIP2_SUPPORT -lz \ - -o bsd-gzip bsd-gzip.c +zgz: zgz.c + gcc -O2 -DNO_COMPRESS_SUPPORT -DNO_BZIP2_SUPPORT -lz -o zgz zgz.c clean: - rm -f bsd-gzip + rm -f zgz diff --git a/bsd-gzip.c b/bsd-gzip.c deleted file mode 100644 index 7f20428..0000000 --- a/bsd-gzip.c +++ /dev/null @@ -1,2054 +0,0 @@ -/* $NetBSD: gzip.c,v 1.85 2006/09/27 22:20:31 mrg Exp $ */ - -/*- - * Copyright (c) 1997, 1998, 2003, 2004, 2006 Matthew R. Green - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include - -/* - * gzip.c -- GPL free gzip using zlib. - * - * RFC 1950 covers the zlib format - * RFC 1951 covers the deflate format - * RFC 1952 covers the gzip format - * - * TODO: - * - use mmap where possible - * - handle some signals better (remove outfile?) - * - make bzip2/compress -v/-t/-l support work as well as possible - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef PRIdOFF -#define PRIdOFF PRId64 -#endif - -/* what type of file are we dealing with */ -enum filetype { - FT_GZIP, -#ifndef NO_BZIP2_SUPPORT - FT_BZIP2, -#endif -#ifndef NO_COMPRESS_SUPPORT - FT_Z, -#endif - FT_LAST, - FT_UNKNOWN -}; - -#ifndef NO_BZIP2_SUPPORT -#include - -#define BZ2_SUFFIX ".bz2" -#define BZIP2_MAGIC "\102\132\150" -#endif - -#ifndef NO_COMPRESS_SUPPORT -#define Z_SUFFIX ".Z" -#define Z_MAGIC "\037\235" -#endif - -#define GZ_SUFFIX ".gz" - -#define BUFLEN (64 * 1024) - -#define GZIP_MAGIC0 0x1F -#define GZIP_MAGIC1 0x8B -#define GZIP_OMAGIC1 0x9E - -#define GZIP_TIMESTAMP (off_t)4 -#define GZIP_ORIGNAME (off_t)10 - -#define HEAD_CRC 0x02 -#define EXTRA_FIELD 0x04 -#define ORIG_NAME 0x08 -#define COMMENT 0x10 - -#define OS_CODE 3 /* Unix */ - -typedef struct { - const char *zipped; - int ziplen; - const char *normal; /* for unzip - must not be longer than zipped */ -} suffixes_t; -static suffixes_t suffixes[] = { -#define SUFFIX(Z, N) {Z, sizeof Z - 1, N} - SUFFIX(GZ_SUFFIX, ""), /* Overwritten by -S .xxx */ -#ifndef SMALL - SUFFIX(GZ_SUFFIX, ""), - SUFFIX(".z", ""), - SUFFIX("-gz", ""), - SUFFIX("-z", ""), - SUFFIX("_z", ""), - SUFFIX(".taz", ".tar"), - SUFFIX(".tgz", ".tar"), -#ifndef NO_BZIP2_SUPPORT - SUFFIX(BZ2_SUFFIX, ""), -#endif -#ifndef NO_COMPRESS_SUPPORT - SUFFIX(Z_SUFFIX, ""), -#endif - SUFFIX(GZ_SUFFIX, ""), /* Overwritten by -S "" */ -#endif /* SMALL */ -#undef SUFFIX -}; -#define NUM_SUFFIXES (sizeof suffixes / sizeof suffixes[0]) - -static const char gzip_version[] = "Debian bsd-gzip 20060927"; - -#ifndef SMALL -static const char gzip_copyright[] = \ -" Copyright (c) 1997, 1998, 2003, 2004, 2006 Matthew R. Green\n" -" * All rights reserved.\n" -" *\n" -" * Redistribution and use in source and binary forms, with or without\n" -" * modification, are permitted provided that the following conditions\n" -" * are met:\n" -" * 1. Redistributions of source code must retain the above copyright\n" -" * notice, this list of conditions and the following disclaimer.\n" -" * 2. Redistributions in binary form must reproduce the above copyright\n" -" * notice, this list of conditions and the following disclaimer in the\n" -" * documentation and/or other materials provided with the distribution.\n" -" * 3. The name of the author may not be used to endorse or promote products\n" -" * derived from this software without specific prior written permission.\n" -" *\n" -" * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n" -" * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n" -" * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n" -" * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n" -" * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n" -" * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n" -" * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\n" -" * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n" -" * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n" -" * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n" -" * SUCH DAMAGE."; -#endif - -static int cflag; /* stdout mode */ -static int dflag; /* decompress mode */ -static int lflag; /* list mode */ -static int numflag = 6; /* gzip -1..-9 value */ - -#ifndef SMALL -static int fflag; /* force mode */ -static int nflag; /* don't save name (impiles -m) */ -static int Nflag; /* restore name/timestamp */ -static int mflag; /* undocumented: don't save timestamp */ -static int qflag; /* quiet mode */ -static int rflag; /* recursive mode */ -static int tflag; /* test */ -static int vflag; /* verbose mode */ -#else -#define qflag 0 -#define tflag 0 -#endif - -static int exit_value = 0; /* exit value */ - -static char *infile; /* name of file coming in */ - -static void maybe_err(const char *fmt, ...) - __attribute__((__format__(__printf__, 1, 2))); -#ifndef NO_BZIP2_SUPPORT -static void maybe_errx(const char *fmt, ...) - __attribute__((__format__(__printf__, 1, 2))); -#endif -static void maybe_warn(const char *fmt, ...) - __attribute__((__format__(__printf__, 1, 2))); -static void maybe_warnx(const char *fmt, ...) - __attribute__((__format__(__printf__, 1, 2))); -static enum filetype file_gettype(u_char *); -#ifdef SMALL -#define gz_compress(if, of, sz, fn, tm) gz_compress(if, of, sz) -#endif -static off_t gz_compress(int, int, off_t *, const char *, uint32_t); -static off_t gz_uncompress(int, int, char *, size_t, off_t *, const char *); -static off_t file_compress(char *, char *, size_t); -static off_t file_uncompress(char *, char *, size_t); -static void handle_pathname(char *); -static void handle_file(char *, struct stat *); -static void handle_stdin(void); -static void handle_stdout(void); -static void print_ratio(off_t, off_t, FILE *); -static void print_list(int fd, off_t, const char *, time_t); -static void usage(void); -static void display_version(void); -#ifndef SMALL -static void display_license(void); -#endif -static const suffixes_t *check_suffix(char *, int); -static ssize_t read_retry(int, void *, size_t); - -#ifdef SMALL -#define unlink_input(f, sb) unlink(f) -#else -static off_t cat_fd(unsigned char *, size_t, off_t *, int fd); -static void prepend_gzip(char *, int *, char ***); -static void handle_dir(char *); -static void print_verbage(const char *, const char *, off_t, off_t); -static void print_test(const char *, int); -static void copymodes(int fd, const struct stat *, const char *file); -static int check_outfile(const char *outfile); -#endif - -#ifndef NO_BZIP2_SUPPORT -static off_t unbzip2(int, int, char *, size_t, off_t *); -#endif - -#ifndef NO_COMPRESS_SUPPORT -static FILE *zdopen(int); -static off_t zuncompress(FILE *, FILE *, char *, size_t, off_t *); -#endif - -int main(int, char **p); - -#ifdef SMALL -#define getopt_long(a,b,c,d,e) getopt(a,b,c) -#else -static const struct option longopts[] = { - { "stdout", no_argument, 0, 'c' }, - { "to-stdout", no_argument, 0, 'c' }, - { "decompress", no_argument, 0, 'd' }, - { "uncompress", no_argument, 0, 'd' }, - { "force", no_argument, 0, 'f' }, - { "help", no_argument, 0, 'h' }, - { "list", no_argument, 0, 'l' }, - { "no-name", no_argument, 0, 'n' }, - { "name", no_argument, 0, 'N' }, - { "no-timestamp", no_argument, 0, 'm' }, - { "force-timestamp", no_argument, 0, 'M' }, - { "quiet", no_argument, 0, 'q' }, - { "recursive", no_argument, 0, 'r' }, - { "suffix", required_argument, 0, 'S' }, - { "test", no_argument, 0, 't' }, - { "verbose", no_argument, 0, 'v' }, - { "version", no_argument, 0, 'V' }, - { "fast", no_argument, 0, '1' }, - { "best", no_argument, 0, '9' }, - { "ascii", no_argument, 0, 'a' }, - { "license", no_argument, 0, 'L' }, - { NULL, no_argument, 0, 0 }, -}; -#endif - -int -main(int argc, char **argv) -{ - const char *progname = argv[0]; -#ifndef SMALL - char *gzip; - int len; -#endif - int ch; - - /* XXX set up signals */ - -#ifndef SMALL - if ((gzip = getenv("GZIP")) != NULL) - prepend_gzip(gzip, &argc, &argv); -#endif - - /* - * XXX - * handle being called `gunzip', `zcat' and `gzcat' - */ - if (strcmp(progname, "gunzip") == 0) - dflag = 1; - else if (strcmp(progname, "zcat") == 0 || - strcmp(progname, "gzcat") == 0) - dflag = cflag = 1; - -#ifdef SMALL -#define OPT_LIST "123456789cdhltV" -#else -#define OPT_LIST "123456789acdfhlLNnMmqrS:tVv" -#endif - - while ((ch = getopt_long(argc, argv, OPT_LIST, longopts, NULL)) != -1) { - switch (ch) { - case '1': case '2': case '3': - case '4': case '5': case '6': - case '7': case '8': case '9': - numflag = ch - '0'; - break; - case 'c': - cflag = 1; - break; - case 'd': - dflag = 1; - break; - case 'l': - lflag = 1; - dflag = 1; - break; - case 'V': - display_version(); - /* NOTREACHED */ -#ifndef SMALL - case 'a': - fprintf(stderr, "%s: option --ascii ignored on this system\n", progname); - break; - case 'f': - fflag = 1; - break; - case 'L': - display_license(); - /* NOT REACHED */ - case 'N': - nflag = 0; - Nflag = 1; - break; - case 'n': - nflag = 1; - Nflag = 0; - /* no break, n implies m */ - case 'm': - mflag = 1; - break; - case 'M': - mflag = 0; - break; - case 'q': - qflag = 1; - break; - case 'r': - rflag = 1; - break; - case 'S': - len = strlen(optarg); - if (len != 0) { - suffixes[0].zipped = optarg; - suffixes[0].ziplen = len; - } else { - suffixes[NUM_SUFFIXES - 1].zipped = ""; - suffixes[NUM_SUFFIXES - 1].ziplen = 0; - } - break; - case 't': - cflag = 1; - tflag = 1; - dflag = 1; - break; - case 'v': - vflag = 1; - break; -#endif - default: - usage(); - /* NOTREACHED */ - } - } - argv += optind; - argc -= optind; - - if (argc == 0) { - if (dflag) /* stdin mode */ - handle_stdin(); - else /* stdout mode */ - handle_stdout(); - } else { - do { - handle_pathname(argv[0]); - } while (*++argv); - } -#ifndef SMALL - if (qflag == 0 && lflag && argc > 1) - print_list(-1, 0, "(totals)", 0); -#endif - exit(exit_value); -} - -/* maybe print a warning */ -void -maybe_warn(const char *fmt, ...) -{ - va_list ap; - - if (qflag == 0) { - va_start(ap, fmt); - vwarn(fmt, ap); - va_end(ap); - } - if (exit_value == 0) - exit_value = 1; -} - -/* ... without an errno. */ -void -maybe_warnx(const char *fmt, ...) -{ - va_list ap; - - if (qflag == 0) { - va_start(ap, fmt); - vwarnx(fmt, ap); - va_end(ap); - } - if (exit_value == 0) - exit_value = 1; -} - -/* maybe print an error */ -void -maybe_err(const char *fmt, ...) -{ - va_list ap; - - if (qflag == 0) { - va_start(ap, fmt); - vwarn(fmt, ap); - va_end(ap); - } - exit(2); -} - -#ifndef NO_BZIP2_SUPPORT -/* ... without an errno. */ -void -maybe_errx(const char *fmt, ...) -{ - va_list ap; - - if (qflag == 0) { - va_start(ap, fmt); - vwarnx(fmt, ap); - va_end(ap); - } - exit(2); -} -#endif - -#ifndef SMALL -/* split up $GZIP and prepend it to the argument list */ -static void -prepend_gzip(char *gzip, int *argc, char ***argv) -{ - char *s, **nargv, **ac; - int nenvarg = 0, i; - - /* scan how many arguments there are */ - for (s = gzip;;) { - while (*s == ' ' || *s == '\t') - s++; - if (*s == 0) - goto count_done; - nenvarg++; - while (*s != ' ' && *s != '\t') - if (*s++ == 0) - goto count_done; - } -count_done: - /* punt early */ - if (nenvarg == 0) - return; - - *argc += nenvarg; - ac = *argv; - - nargv = (char **)malloc((*argc + 1) * sizeof(char *)); - if (nargv == NULL) - maybe_err("malloc"); - - /* stash this away */ - *argv = nargv; - - /* copy the program name first */ - i = 0; - nargv[i++] = *(ac++); - - /* take a copy of $GZIP and add it to the array */ - s = strdup(gzip); - if (s == NULL) - maybe_err("strdup"); - for (;;) { - /* Skip whitespaces. */ - while (*s == ' ' || *s == '\t') - s++; - if (*s == 0) - goto copy_done; - nargv[i++] = s; - /* Find the end of this argument. */ - while (*s != ' ' && *s != '\t') - if (*s++ == 0) - /* Argument followed by NUL. */ - goto copy_done; - /* Terminate by overwriting ' ' or '\t' with NUL. */ - *s++ = 0; - } -copy_done: - - /* copy the original arguments and a NULL */ - while (*ac) - nargv[i++] = *(ac++); - nargv[i] = NULL; -} -#endif - -/* compress input to output. Return bytes read, -1 on error */ -static off_t -gz_compress(int in, int out, off_t *gsizep, const char *origname, uint32_t mtime) -{ - z_stream z; - char *outbufp, *inbufp; - off_t in_tot = 0, out_tot = 0; - ssize_t in_size; - int i, error; - uLong crc; -#ifdef SMALL - static char header[] = { GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED, 0, - 0, 0, 0, 0, - 0, OS_CODE }; -#endif - - outbufp = malloc(BUFLEN); - inbufp = malloc(BUFLEN); - if (outbufp == NULL || inbufp == NULL) { - maybe_err("malloc failed"); - goto out; - } - - memset(&z, 0, sizeof z); - z.zalloc = Z_NULL; - z.zfree = Z_NULL; - z.opaque = 0; - -#ifdef SMALL - memcpy(outbufp, header, sizeof header); - i = sizeof header; -#else - if (mflag != 0) - mtime = 0; - if (nflag != 0) - origname = ""; - - i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c%c%c%s", - GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED, - *origname ? ORIG_NAME : 0, - mtime & 0xff, - (mtime >> 8) & 0xff, - (mtime >> 16) & 0xff, - (mtime >> 24) & 0xff, - numflag == 1 ? 4 : numflag == 9 ? 2 : 0, - OS_CODE, origname); - if (i >= BUFLEN) - /* this need PATH_MAX > BUFLEN ... */ - maybe_err("snprintf"); - if (*origname) - i++; -#endif - - z.next_out = (unsigned char *)outbufp + i; - z.avail_out = BUFLEN - i; - - error = deflateInit2(&z, numflag, Z_DEFLATED, - (-MAX_WBITS), 8, Z_DEFAULT_STRATEGY); - if (error != Z_OK) { - maybe_warnx("deflateInit2 failed"); - in_tot = -1; - goto out; - } - - crc = crc32(0L, Z_NULL, 0); - for (;;) { - if (z.avail_out == 0) { - if (write(out, outbufp, BUFLEN) != BUFLEN) { - maybe_warn("write"); - in_tot = -1; - goto out; - } - - out_tot += BUFLEN; - z.next_out = (unsigned char *)outbufp; - z.avail_out = BUFLEN; - } - - if (z.avail_in == 0) { - in_size = read(in, inbufp, BUFLEN); - if (in_size < 0) { - maybe_warn("read"); - in_tot = -1; - goto out; - } - if (in_size == 0) - break; - - crc = crc32(crc, (const Bytef *)inbufp, (unsigned)in_size); - in_tot += in_size; - z.next_in = (unsigned char *)inbufp; - z.avail_in = in_size; - } - - error = deflate(&z, Z_NO_FLUSH); - if (error != Z_OK && error != Z_STREAM_END) { - maybe_warnx("deflate failed"); - in_tot = -1; - goto out; - } - } - - /* clean up */ - for (;;) { - size_t len; - ssize_t w; - - error = deflate(&z, Z_FINISH); - if (error != Z_OK && error != Z_STREAM_END) { - maybe_warnx("deflate failed"); - in_tot = -1; - goto out; - } - - len = (char *)z.next_out - outbufp; - - w = write(out, outbufp, len); - if (w == -1 || (size_t)w != len) { - maybe_warn("write"); - out_tot = -1; - goto out; - } - out_tot += len; - z.next_out = (unsigned char *)outbufp; - z.avail_out = BUFLEN; - - if (error == Z_STREAM_END) - break; - } - - if (deflateEnd(&z) != Z_OK) { - maybe_warnx("deflateEnd failed"); - in_tot = -1; - goto out; - } - - i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c", - (int)crc & 0xff, - (int)(crc >> 8) & 0xff, - (int)(crc >> 16) & 0xff, - (int)(crc >> 24) & 0xff, - (int)in_tot & 0xff, - (int)(in_tot >> 8) & 0xff, - (int)(in_tot >> 16) & 0xff, - (int)(in_tot >> 24) & 0xff); - if (i != 8) - maybe_err("snprintf"); - if (write(out, outbufp, i) != i) { - maybe_warn("write"); - in_tot = -1; - } else - out_tot += i; - -out: - if (inbufp != NULL) - free(inbufp); - if (outbufp != NULL) - free(outbufp); - if (gsizep) - *gsizep = out_tot; - return in_tot; -} - -/* - * uncompress input to output then close the input. return the - * uncompressed size written, and put the compressed sized read - * into `*gsizep'. - */ -static off_t -gz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep, - const char *filename) -{ - z_stream z; - char *outbufp, *inbufp; - off_t out_tot = -1, in_tot = 0; - uint32_t out_sub_tot = 0; - enum { - GZSTATE_MAGIC0, - GZSTATE_MAGIC1, - GZSTATE_METHOD, - GZSTATE_FLAGS, - GZSTATE_SKIPPING, - GZSTATE_EXTRA, - GZSTATE_EXTRA2, - GZSTATE_EXTRA3, - GZSTATE_ORIGNAME, - GZSTATE_COMMENT, - GZSTATE_HEAD_CRC1, - GZSTATE_HEAD_CRC2, - GZSTATE_INIT, - GZSTATE_READ, - GZSTATE_CRC, - GZSTATE_LEN, - } state = GZSTATE_MAGIC0; - int flags = 0, skip_count = 0; - int error = Z_STREAM_ERROR, done_reading = 0; - uLong crc = 0; - ssize_t wr; - int needmore = 0; - -#define ADVANCE() { z.next_in++; z.avail_in--; } - - if ((outbufp = malloc(BUFLEN)) == NULL) { - maybe_err("malloc failed"); - goto out2; - } - if ((inbufp = malloc(BUFLEN)) == NULL) { - maybe_err("malloc failed"); - goto out1; - } - - memset(&z, 0, sizeof z); - z.avail_in = prelen; - z.next_in = (unsigned char *)pre; - z.avail_out = BUFLEN; - z.next_out = (unsigned char *)outbufp; - z.zalloc = NULL; - z.zfree = NULL; - z.opaque = 0; - - in_tot = prelen; - out_tot = 0; - - for (;;) { - if ((z.avail_in == 0 || needmore) && done_reading == 0) { - ssize_t in_size; - - if (z.avail_in > 0) { - memmove(inbufp, z.next_in, z.avail_in); - } - z.next_in = (unsigned char *)inbufp; - in_size = read(in, z.next_in + z.avail_in, - BUFLEN - z.avail_in); - - if (in_size == -1) { - maybe_warn("failed to read stdin"); - goto stop_and_fail; - } else if (in_size == 0) { - done_reading = 1; - } - - z.avail_in += in_size; - needmore = 0; - - in_tot += in_size; - } - if (z.avail_in == 0) { - if (done_reading && state != GZSTATE_MAGIC0) - maybe_warnx("%s: unexpected end of file", - filename); - goto stop; - } - switch (state) { - case GZSTATE_MAGIC0: - if (*z.next_in != GZIP_MAGIC0) { - maybe_warnx("input not gziped (MAGIC0)"); - goto stop_and_fail; - } - ADVANCE(); - state++; - out_sub_tot = 0; - crc = crc32(0L, Z_NULL, 0); - break; - - case GZSTATE_MAGIC1: - if (*z.next_in != GZIP_MAGIC1 && - *z.next_in != GZIP_OMAGIC1) { - maybe_warnx("input not gziped (MAGIC1)"); - goto stop_and_fail; - } - ADVANCE(); - state++; - break; - - case GZSTATE_METHOD: - if (*z.next_in != Z_DEFLATED) { - maybe_warnx("unknown compression method"); - goto stop_and_fail; - } - ADVANCE(); - state++; - break; - - case GZSTATE_FLAGS: - flags = *z.next_in; - ADVANCE(); - skip_count = 6; - state++; - break; - - case GZSTATE_SKIPPING: - if (skip_count > 0) { - skip_count--; - ADVANCE(); - } else - state++; - break; - - case GZSTATE_EXTRA: - if ((flags & EXTRA_FIELD) == 0) { - state = GZSTATE_ORIGNAME; - break; - } - skip_count = *z.next_in; - ADVANCE(); - state++; - break; - - case GZSTATE_EXTRA2: - skip_count |= ((*z.next_in) << 8); - ADVANCE(); - state++; - break; - - case GZSTATE_EXTRA3: - if (skip_count > 0) { - skip_count--; - ADVANCE(); - } else - state++; - break; - - case GZSTATE_ORIGNAME: - if ((flags & ORIG_NAME) == 0) { - state++; - break; - } - if (*z.next_in == 0) - state++; - ADVANCE(); - break; - - case GZSTATE_COMMENT: - if ((flags & COMMENT) == 0) { - state++; - break; - } - if (*z.next_in == 0) - state++; - ADVANCE(); - break; - - case GZSTATE_HEAD_CRC1: - if (flags & HEAD_CRC) - skip_count = 2; - else - skip_count = 0; - state++; - break; - - case GZSTATE_HEAD_CRC2: - if (skip_count > 0) { - skip_count--; - ADVANCE(); - } else - state++; - break; - - case GZSTATE_INIT: - if (inflateInit2(&z, -MAX_WBITS) != Z_OK) { - maybe_warnx("failed to inflateInit"); - goto stop_and_fail; - } - state++; - break; - - case GZSTATE_READ: - error = inflate(&z, Z_FINISH); - switch (error) { - /* Z_BUF_ERROR goes with Z_FINISH... */ - case Z_BUF_ERROR: - case Z_STREAM_END: - case Z_OK: - break; - - case Z_NEED_DICT: - maybe_warnx("Z_NEED_DICT error"); - goto stop_and_fail; - case Z_DATA_ERROR: - maybe_warnx("data stream error"); - goto stop_and_fail; - case Z_STREAM_ERROR: - maybe_warnx("internal stream error"); - goto stop_and_fail; - case Z_MEM_ERROR: - maybe_warnx("memory allocation error"); - goto stop_and_fail; - - default: - maybe_warn("unknown error from inflate(): %d", - error); - } - wr = BUFLEN - z.avail_out; - - if (wr != 0) { - crc = crc32(crc, (const Bytef *)outbufp, (unsigned)wr); - if ( -#ifndef SMALL - /* don't write anything with -t */ - tflag == 0 && -#endif - write(out, outbufp, wr) != wr) { - maybe_warn("error writing to output"); - goto stop_and_fail; - } - - out_tot += wr; - out_sub_tot += wr; - } - - if (error == Z_STREAM_END) { - inflateEnd(&z); - state++; - } - - z.next_out = (unsigned char *)outbufp; - z.avail_out = BUFLEN; - - break; - case GZSTATE_CRC: - { - uLong origcrc; - - if (z.avail_in < 4) { - if (!done_reading) { - needmore = 1; - continue; - } - maybe_warnx("truncated input"); - goto stop_and_fail; - } - origcrc = ((unsigned)z.next_in[0] & 0xff) | - ((unsigned)z.next_in[1] & 0xff) << 8 | - ((unsigned)z.next_in[2] & 0xff) << 16 | - ((unsigned)z.next_in[3] & 0xff) << 24; - if (origcrc != crc) { - maybe_warnx("invalid compressed" - " data--crc error"); - goto stop_and_fail; - } - } - - z.avail_in -= 4; - z.next_in += 4; - - if (!z.avail_in && done_reading) { - goto stop; - } - state++; - break; - case GZSTATE_LEN: - { - uLong origlen; - - if (z.avail_in < 4) { - if (!done_reading) { - needmore = 1; - continue; - } - maybe_warnx("truncated input"); - goto stop_and_fail; - } - origlen = ((unsigned)z.next_in[0] & 0xff) | - ((unsigned)z.next_in[1] & 0xff) << 8 | - ((unsigned)z.next_in[2] & 0xff) << 16 | - ((unsigned)z.next_in[3] & 0xff) << 24; - - if (origlen != out_sub_tot) { - maybe_warnx("invalid compressed" - " data--length error"); - goto stop_and_fail; - } - } - - z.avail_in -= 4; - z.next_in += 4; - - if (error < 0) { - maybe_warnx("decompression error"); - goto stop_and_fail; - } - state = GZSTATE_MAGIC0; - break; - } - continue; -stop_and_fail: - out_tot = -1; -stop: - break; - } - if (state > GZSTATE_INIT) - inflateEnd(&z); - - free(inbufp); -out1: - free(outbufp); -out2: - if (gsizep) - *gsizep = in_tot; - return (out_tot); -} - -#ifndef SMALL -/* - * set the owner, mode, flags & utimes using the given file descriptor. - * file is only used in possible warning messages. - */ -static void -copymodes(int fd, const struct stat *sbp, const char *file) -{ - struct timeval times[2]; - struct stat sb; - - /* - * If we have no info on the input, give this file some - * default values and return.. - */ - if (sbp == NULL) { - mode_t mask = umask(022); - - (void)fchmod(fd, DEFFILEMODE & ~mask); - (void)umask(mask); - return; - } - sb = *sbp; - - /* if the chown fails, remove set-id bits as-per compress(1) */ - if (fchown(fd, sb.st_uid, sb.st_gid) < 0) { - if (errno != EPERM) - maybe_warn("couldn't fchown: %s", file); - sb.st_mode &= ~(S_ISUID|S_ISGID); - } - - /* we only allow set-id and the 9 normal permission bits */ - sb.st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; - if (fchmod(fd, sb.st_mode) < 0) - maybe_warn("couldn't fchmod: %s", file); - -#if 0 /* broken on Linux */ - /* only try flags if they exist already */ - if (sb.st_flags != 0 && fchflags(fd, sb.st_flags) < 0) - maybe_warn("couldn't fchflags: %s", file); - - TIMESPEC_TO_TIMEVAL(×[0], &sb.st_atimespec); - TIMESPEC_TO_TIMEVAL(×[1], &sb.st_mtimespec); -#endif - if (futimes(fd, times) < 0) - maybe_warn("couldn't utimes: %s", file); -} -#endif - -/* what sort of file is this? */ -static enum filetype -file_gettype(u_char *buf) -{ - - if (buf[0] == GZIP_MAGIC0 && - (buf[1] == GZIP_MAGIC1 || buf[1] == GZIP_OMAGIC1)) - return FT_GZIP; - else -#ifndef NO_BZIP2_SUPPORT - if (memcmp(buf, BZIP2_MAGIC, 3) == 0 && - buf[3] >= '0' && buf[3] <= '9') - return FT_BZIP2; - else -#endif -#ifndef NO_COMPRESS_SUPPORT - if (memcmp(buf, Z_MAGIC, 2) == 0) - return FT_Z; - else -#endif - return FT_UNKNOWN; -} - -#ifndef SMALL -/* check the outfile is OK. */ -static int -check_outfile(const char *outfile) -{ - struct stat sb; - int ok = 1; - - if (lflag == 0 && stat(outfile, &sb) == 0) { - if (fflag) - unlink(outfile); - else if (isatty(STDIN_FILENO)) { - char ans[10] = { 'n', '\0' }; /* default */ - - fprintf(stderr, "%s already exists -- do you wish to " - "overwrite (y or n)? " , outfile); - (void)fgets(ans, sizeof(ans) - 1, stdin); - if (ans[0] != 'y' && ans[0] != 'Y') { - fprintf(stderr, "\tnot overwritting\n"); - ok = 0; - } else - unlink(outfile); - } else { - maybe_warnx("%s already exists -- skipping", outfile); - ok = 0; - } - } - return ok; -} - -static void -unlink_input(const char *file, const struct stat *sb) -{ - struct stat nsb; - - if (stat(file, &nsb) != 0) - /* Must be gone alrady */ - return; - if (nsb.st_dev != sb->st_dev || nsb.st_ino != sb->st_ino) - /* Definitely a different file */ - return; - unlink(file); -} -#endif - -static const suffixes_t * -check_suffix(char *file, int xlate) -{ - const suffixes_t *s; - int len = strlen(file); - char *sp; - - for (s = suffixes; s != suffixes + NUM_SUFFIXES; s++) { - /* if it doesn't fit in "a.suf", don't bother */ - if (s->ziplen >= len) - continue; - sp = file + len - s->ziplen; - if (strcmp(s->zipped, sp) != 0) - continue; - if (xlate) - strcpy(sp, s->normal); - return s; - } - return NULL; -} - -/* - * compress the given file: create a corresponding .gz file and remove the - * original. - */ -static off_t -file_compress(char *file, char *outfile, size_t outsize) -{ - int in; - int out; - off_t size, insize; -#ifndef SMALL - struct stat isb, osb; - const suffixes_t *suff; -#endif - - in = open(file, O_RDONLY); - if (in == -1) { - maybe_warn("can't open %s", file); - return -1; - } - - if (cflag == 0) { -#ifndef SMALL - if (fstat(in, &isb) == 0) { - if (isb.st_nlink > 1 && fflag == 0) { - maybe_warnx("%s has %d other link%s -- " - "skipping", file, isb.st_nlink - 1, - isb.st_nlink == 1 ? "" : "s"); - close(in); - return -1; - } - } - - if (fflag == 0 && (suff = check_suffix(file, 0)) - && suff->zipped[0] != 0) { - maybe_warnx("%s already has %s suffix -- unchanged", - file, suff->zipped); - close(in); - return -1; - } -#endif - - /* Add (usually) .gz to filename */ - if ((size_t)snprintf(outfile, outsize, "%s%s", - file, suffixes[0].zipped) >= outsize) - memcpy(outfile - suffixes[0].ziplen - 1, - suffixes[0].zipped, suffixes[0].ziplen + 1); - -#ifndef SMALL - if (check_outfile(outfile) == 0) { - close(in); - return -1; - } -#endif - } - - if (cflag == 0) { - out = open(outfile, O_WRONLY | O_CREAT | O_EXCL, 0600); - if (out == -1) { - maybe_warn("could not create output: %s", outfile); - fclose(stdin); - return -1; - } - } else - out = STDOUT_FILENO; - - insize = gz_compress(in, out, &size, basename(file), (uint32_t)isb.st_mtime); - - (void)close(in); - - /* - * If there was an error, insize will be -1. - * If we compressed to stdout, just return the size. - * Otherwise stat the file and check it is the correct size. - * We only blow away the file if we can stat the output and it - * has the expected size. - */ - if (cflag != 0) - return insize == -1 ? -1 : size; - -#ifndef SMALL - if (fstat(out, &osb) != 0) { - maybe_warn("couldn't stat: %s", outfile); - goto bad_outfile; - } - - if (osb.st_size != size) { - maybe_warnx("output file: %s wrong size (%" PRIdOFF - " != %" PRIdOFF "), deleting", - outfile, osb.st_size, size); - goto bad_outfile; - } - - copymodes(out, &isb, outfile); -#endif - if (close(out) == -1) - maybe_warn("couldn't close output"); - - /* output is good, ok to delete input */ - unlink_input(file, &isb); - return size; - -#ifndef SMALL - bad_outfile: - if (close(out) == -1) - maybe_warn("couldn't close output"); - - maybe_warnx("leaving original %s", file); - unlink(outfile); - return size; -#endif -} - -/* uncompress the given file and remove the original */ -static off_t -file_uncompress(char *file, char *outfile, size_t outsize) -{ - struct stat isb, osb; - off_t size; - ssize_t rbytes; - unsigned char header1[4]; - enum filetype method; - int rv, fd, ofd, zfd = -1; -#ifndef SMALL - time_t timestamp = 0; - unsigned char name[PATH_MAX + 1]; -#endif - - /* gather the old name info */ - - fd = open(file, O_RDONLY); - if (fd < 0) { - maybe_warn("can't open %s", file); - goto lose; - } - - strncpy(outfile, file, outsize); - if (check_suffix(outfile, 1) == NULL && !(cflag || lflag)) { - maybe_warnx("%s: unknown suffix -- ignored", file); - goto lose; - } - - rbytes = read(fd, header1, sizeof header1); - if (rbytes != sizeof header1) { - /* we don't want to fail here. */ -#ifndef SMALL - if (fflag) - goto lose; -#endif - if (rbytes == -1) - maybe_warn("can't read %s", file); - else - goto unexpected_EOF; - goto lose; - } - - method = file_gettype(header1); - -#ifndef SMALL - if (fflag == 0 && method == FT_UNKNOWN) { - maybe_warnx("%s: not in gzip format", file); - goto lose; - } - -#endif - -#ifndef SMALL - if (method == FT_GZIP && Nflag) { - unsigned char ts[4]; /* timestamp */ - - rv = pread(fd, ts, sizeof ts, GZIP_TIMESTAMP); - if (rv >= 0 && (size_t)rv < sizeof ts) - goto unexpected_EOF; - if (rv == -1) { - if (!fflag) - maybe_warn("can't read %s", file); - goto lose; - } - timestamp = ts[3] << 24 | ts[2] << 16 | ts[1] << 8 | ts[0]; - - if (header1[3] & ORIG_NAME) { - rbytes = pread(fd, name, sizeof name, GZIP_ORIGNAME); - if (rbytes < 0) { - maybe_warn("can't read %s", file); - goto lose; - } - if (name[0] != 0) { - /* preserve original directory name */ - char *dp = strrchr(file, '/'); - if (dp == NULL) - dp = file; - else - dp++; - snprintf(outfile, outsize, "%.*s%.*s", - (int) (dp - file), - file, (int) rbytes, name); - } - } - } -#endif - lseek(fd, 0, SEEK_SET); - - if (cflag == 0 || lflag) { - if (fstat(fd, &isb) != 0) - goto lose; -#ifndef SMALL - if (isb.st_nlink > 1 && lflag == 0 && fflag == 0) { - maybe_warnx("%s has %d other links -- skipping", - file, isb.st_nlink - 1); - goto lose; - } - if (mflag == 0 && timestamp) - isb.st_mtime = timestamp; - if (check_outfile(outfile) == 0) - goto lose; -#endif - } - - if (cflag == 0 && lflag == 0) { - zfd = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0600); - if (zfd == STDOUT_FILENO) { - /* We won't close STDOUT_FILENO later... */ - zfd = dup(zfd); - close(STDOUT_FILENO); - } - if (zfd == -1) { - maybe_warn("can't open %s", outfile); - goto lose; - } - } else - zfd = STDOUT_FILENO; - -#ifndef NO_BZIP2_SUPPORT - if (method == FT_BZIP2) { - - /* XXX */ - if (lflag) { - maybe_warnx("no -l with bzip2 files"); - goto lose; - } - - size = unbzip2(fd, zfd, NULL, 0, NULL); - } else -#endif - -#ifndef NO_COMPRESS_SUPPORT - if (method == FT_Z) { - FILE *in, *out; - - /* XXX */ - if (lflag) { - maybe_warnx("no -l with Lempel-Ziv files"); - goto lose; - } - - if ((in = zdopen(fd)) == NULL) { - maybe_warn("zdopen for read: %s", file); - goto lose; - } - - out = fdopen(dup(zfd), "w"); - if (out == NULL) { - maybe_warn("fdopen for write: %s", outfile); - fclose(in); - goto lose; - } - - size = zuncompress(in, out, NULL, 0, NULL); - /* need to fclose() if ferror() is true... */ - if (ferror(in) | fclose(in)) { - maybe_warn("failed infile fclose"); - unlink(outfile); - (void)fclose(out); - } - if (fclose(out) != 0) { - maybe_warn("failed outfile fclose"); - unlink(outfile); - goto lose; - } - } else -#endif - -#ifndef SMALL - if (method == FT_UNKNOWN) { - if (lflag) { - maybe_warnx("no -l for unknown filetypes"); - goto lose; - } - size = cat_fd(NULL, 0, NULL, fd); - } else -#endif - { - if (lflag) { - print_list(fd, isb.st_size, outfile, isb.st_mtime); - close(fd); - return -1; /* XXX */ - } - - size = gz_uncompress(fd, zfd, NULL, 0, NULL, file); - } - - if (close(fd) != 0) - maybe_warn("couldn't close input"); - if (zfd != STDOUT_FILENO && close(zfd) != 0) - maybe_warn("couldn't close output"); - - if (size == -1) { - if (cflag == 0) - unlink(outfile); - maybe_warnx("%s: uncompress failed", file); - return -1; - } - - /* if testing, or we uncompressed to stdout, this is all we need */ -#ifndef SMALL - if (tflag) - return size; -#endif - /* if we are uncompressing to stdin, don't remove the file. */ - if (cflag) - return size; - - /* - * if we create a file... - */ - /* - * if we can't stat the file don't remove the file. - */ - - ofd = open(outfile, O_RDWR, 0); - if (ofd == -1) { - maybe_warn("couldn't open (leaving original): %s", - outfile); - return -1; - } - if (fstat(ofd, &osb) != 0) { - maybe_warn("couldn't stat (leaving original): %s", - outfile); - close(ofd); - return -1; - } - if (osb.st_size != size) { - maybe_warnx("stat gave different size: %" PRIdOFF - " != %" PRIdOFF " (leaving original)", - size, osb.st_size); - close(ofd); - unlink(outfile); - return -1; - } - unlink_input(file, &isb); -#ifndef SMALL - copymodes(ofd, &isb, outfile); -#endif - close(ofd); - return size; - - unexpected_EOF: - maybe_warnx("%s: unexpected end of file", file); - lose: - if (fd != -1) - close(fd); - if (zfd != -1 && zfd != STDOUT_FILENO) - close(fd); - return -1; -} - -#ifndef SMALL -static off_t -cat_fd(unsigned char * prepend, size_t count, off_t *gsizep, int fd) -{ - char buf[BUFLEN]; - off_t in_tot; - ssize_t w; - - in_tot = count; - w = write(STDOUT_FILENO, prepend, count); - if (w == -1 || (size_t)w != count) { - maybe_warn("write to stdout"); - return -1; - } - for (;;) { - ssize_t rv; - - rv = read(fd, buf, sizeof buf); - if (rv == 0) - break; - if (rv < 0) { - maybe_warn("read from fd %d", fd); - break; - } - - if (write(STDOUT_FILENO, buf, rv) != rv) { - maybe_warn("write to stdout"); - break; - } - in_tot += rv; - } - - if (gsizep) - *gsizep = in_tot; - return (in_tot); -} -#endif - -static void -handle_stdin(void) -{ - unsigned char header1[4]; - off_t usize, gsize; - enum filetype method; - ssize_t bytes_read; -#ifndef NO_COMPRESS_SUPPORT - FILE *in; -#endif - -#ifndef SMALL - if (fflag == 0 && lflag == 0 && isatty(STDIN_FILENO)) { - maybe_warnx("standard input is a terminal -- ignoring"); - return; - } -#endif - - if (lflag) { - struct stat isb; - - /* XXX could read the whole file, etc. */ - if (fstat(STDIN_FILENO, &isb) < 0) { - maybe_warn("fstat"); - return; - } - print_list(STDIN_FILENO, isb.st_size, "stdout", isb.st_mtime); - return; - } - - bytes_read = read_retry(STDIN_FILENO, header1, sizeof header1); - if (bytes_read == -1) { - maybe_warn("can't read stdin"); - return; - } else if (bytes_read != sizeof(header1)) { - maybe_warnx("(stdin): unexpected end of file"); - return; - } - - method = file_gettype(header1); - switch (method) { - default: -#ifndef SMALL - if (fflag == 0) { - maybe_warnx("unknown compression format"); - return; - } - usize = cat_fd(header1, sizeof header1, &gsize, STDIN_FILENO); - break; -#endif - case FT_GZIP: - usize = gz_uncompress(STDIN_FILENO, STDOUT_FILENO, - (char *)header1, sizeof header1, &gsize, "(stdin)"); - break; -#ifndef NO_BZIP2_SUPPORT - case FT_BZIP2: - usize = unbzip2(STDIN_FILENO, STDOUT_FILENO, - (char *)header1, sizeof header1, &gsize); - break; -#endif -#ifndef NO_COMPRESS_SUPPORT - case FT_Z: - if ((in = zdopen(STDIN_FILENO)) == NULL) { - maybe_warnx("zopen of stdin"); - return; - } - - usize = zuncompress(in, stdout, (char *)header1, sizeof header1, &gsize); - fclose(in); - break; -#endif - } - -#ifndef SMALL - if (vflag && !tflag && usize != -1 && gsize != -1) - print_verbage(NULL, NULL, usize, gsize); - if (vflag && tflag) - print_test("(stdin)", usize != -1); -#endif - -} - -static void -handle_stdout(void) -{ - off_t gsize, usize; - struct stat sb; - time_t systime; - uint32_t mtime; - int ret; - -#ifndef SMALL - if (fflag == 0 && isatty(STDOUT_FILENO)) { - maybe_warnx("standard output is a terminal -- ignoring"); - return; - } -#endif - /* If stdin is a file use it's mtime, otherwise use current time */ - ret = fstat(STDIN_FILENO, &sb); - -#ifndef SMALL - if (ret < 0) { - maybe_warn("Can't stat stdin"); - return; - } -#endif - - if (S_ISREG(sb.st_mode)) - mtime = (uint32_t)sb.st_mtime; - else { - systime = time(NULL); -#ifndef SMALL - if (systime == -1) { - maybe_warn("time"); - return; - } -#endif - mtime = (uint32_t)systime; - } - - usize = gz_compress(STDIN_FILENO, STDOUT_FILENO, &gsize, "", mtime); -#ifndef SMALL - if (vflag && !tflag && usize != -1 && gsize != -1) - print_verbage(NULL, NULL, usize, gsize); -#endif -} - -/* do what is asked for, for the path name */ -static void -handle_pathname(char *path) -{ - char *opath = path, *s = NULL; - ssize_t len; - int slen; - struct stat sb; - - /* check for stdout/stdin */ - if (path[0] == '-' && path[1] == '\0') { - if (dflag) - handle_stdin(); - else - handle_stdout(); - return; - } - -retry: - if (stat(path, &sb) != 0) { - /* lets try .gz if we're decompressing */ - if (dflag && s == NULL && errno == ENOENT) { - len = strlen(path); - slen = suffixes[0].ziplen; - s = malloc(len + slen + 1); - if (s == NULL) - maybe_err("malloc"); - memcpy(s, path, len); - memcpy(s + len, suffixes[0].zipped, slen + 1); - path = s; - goto retry; - } - maybe_warn("can't stat: %s", opath); - goto out; - } - - if (S_ISDIR(sb.st_mode)) { -#ifndef SMALL - if (rflag) - handle_dir(path); - else -#endif - maybe_warnx("%s is a directory", path); - goto out; - } - - if (S_ISREG(sb.st_mode)) - handle_file(path, &sb); - else - maybe_warnx("%s is not a regular file", path); - -out: - if (s) - free(s); -} - -/* compress/decompress a file */ -static void -handle_file(char *file, struct stat *sbp) -{ - off_t usize, gsize; - char outfile[PATH_MAX]; - - infile = file; - if (dflag) { - usize = file_uncompress(file, outfile, sizeof(outfile)); -#ifndef SMALL - if (vflag && tflag) - print_test(file, usize != -1); -#endif - if (usize == -1) - return; - gsize = sbp->st_size; - } else { - gsize = file_compress(file, outfile, sizeof(outfile)); - if (gsize == -1) - return; - usize = sbp->st_size; - } - - -#ifndef SMALL - if (vflag && !tflag) - print_verbage(file, (cflag) ? NULL : outfile, usize, gsize); -#endif -} - -#ifndef SMALL -/* this is used with -r to recursively descend directories */ -static void -handle_dir(char *dir) -{ - char *path_argv[2]; - FTS *fts; - FTSENT *entry; - - path_argv[0] = dir; - path_argv[1] = 0; - fts = fts_open(path_argv, FTS_PHYSICAL, NULL); - if (fts == NULL) { - warn("couldn't fts_open %s", dir); - return; - } - - while ((entry = fts_read(fts))) { - switch(entry->fts_info) { - case FTS_D: - case FTS_DP: - continue; - - case FTS_DNR: - case FTS_ERR: - case FTS_NS: - maybe_warn("%s", entry->fts_path); - continue; - case FTS_F: - handle_file(entry->fts_name, entry->fts_statp); - } - } - (void)fts_close(fts); -} -#endif - -/* print a ratio - size reduction as a fraction of uncompressed size */ -static void -print_ratio(off_t in, off_t out, FILE *where) -{ - int percent10; /* 10 * percent */ - off_t diff; - char buff[8]; - int len; - - diff = in - out/2; - if (diff <= 0) - /* - * Output is more than double size of input! print -99.9% - * Quite possibly we've failed to get the original size. - */ - percent10 = -999; - else { - /* - * We only need 12 bits of result from the final division, - * so reduce the values until a 32bit division will suffice. - */ - while (in > 0x100000) { - diff >>= 1; - in >>= 1; - } - if (in != 0) - percent10 = ((u_int)diff * 2000) / (u_int)in - 1000; - else - percent10 = 0; - } - - len = snprintf(buff, sizeof buff, "%2.2d.", percent10); - /* Move the '.' to before the last digit */ - buff[len - 1] = buff[len - 2]; - buff[len - 2] = '.'; - fprintf(where, "%5s%%", buff); -} - -#ifndef SMALL -/* print compression statistics, and the new name (if there is one!) */ -static void -print_verbage(const char *file, const char *nfile, off_t usize, off_t gsize) -{ - if (file) - fprintf(stderr, "%s:%s ", file, - strlen(file) < 7 ? "\t\t" : "\t"); - print_ratio(usize, gsize, stderr); - if (nfile) - fprintf(stderr, " -- replaced with %s", nfile); - fprintf(stderr, "\n"); - fflush(stderr); -} - -/* print test results */ -static void -print_test(const char *file, int ok) -{ - - if (exit_value == 0 && ok == 0) - exit_value = 1; - fprintf(stderr, "%s:%s %s\n", file, - strlen(file) < 7 ? "\t\t" : "\t", ok ? "OK" : "NOT OK"); - fflush(stderr); -} -#endif - -/* print a file's info ala --list */ -/* eg: - compressed uncompressed ratio uncompressed_name - 354841 1679360 78.8% /usr/pkgsrc/distfiles/libglade-2.0.1.tar -*/ -static void -print_list(int fd, off_t out, const char *outfile, time_t ts) -{ - static int first = 1; -#ifndef SMALL - static off_t in_tot, out_tot; - uint32_t crc = 0; -#endif - off_t in = 0, rv; - - if (first) { -#ifndef SMALL - if (vflag) - printf("method crc date time "); -#endif - if (qflag == 0) - printf(" compressed uncompressed " - "ratio uncompressed_name\n"); - } - first = 0; - - /* print totals? */ -#ifndef SMALL - if (fd == -1) { - in = in_tot; - out = out_tot; - } else -#endif - { - /* read the last 4 bytes - this is the uncompressed size */ - rv = lseek(fd, (off_t)(-8), SEEK_END); - if (rv != -1) { - unsigned char buf[8]; - uint32_t usize; - - rv = read(fd, (char *)buf, sizeof(buf)); - if (rv == -1) - maybe_warn("read of uncompressed size"); - else if (rv != sizeof(buf)) - maybe_warnx("read of uncompressed size"); - - else { - usize = buf[4] | buf[5] << 8 | - buf[6] << 16 | buf[7] << 24; - in = (off_t)usize; -#ifndef SMALL - crc = buf[0] | buf[1] << 8 | - buf[2] << 16 | buf[3] << 24; -#endif - } - } - } - -#ifndef SMALL - if (vflag && fd == -1) - printf(" "); - else if (vflag) { - char *date = ctime(&ts); - - /* skip the day, 1/100th second, and year */ - date += 4; - date[12] = 0; - printf("%5s %08x %11s ", "defla"/*XXX*/, crc, date); - } - in_tot += in; - out_tot += out; -#endif - printf("%12llu %12llu ", (unsigned long long)out, (unsigned long long)in); - print_ratio(in, out, stdout); - printf(" %s\n", outfile); -} - -/* display the usage of NetBSD gzip */ -static void -usage(void) -{ - - fprintf(stderr, "%s\n", gzip_version); - fprintf(stderr, - "usage: %s [-" OPT_LIST "] [ [ ...]]\n" -#ifndef SMALL - " -1 --fast fastest (worst) compression\n" - " -2 .. -8 set compression level\n" - " -9 --best best (slowest) compression\n" - " -c --stdout write to stdout, keep original files\n" - " --to-stdout\n" - " -d --decompress uncompress files\n" - " --uncompress\n" - " -f --force force overwriting & compress links\n" - " -h --help display this help\n" - " -l --list list compressed file contents\n" - " -N --name save or restore original file name and time stamp\n" - " -n --no-name don't save original file name or time stamp\n" - " -q --quiet output no warnings\n" - " -r --recursive recursively compress files in directories\n" - " -S .suf use suffix .suf instead of .gz\n" - " --suffix .suf\n" - " -t --test test compressed file\n" - " -V --version display program version\n" - " -v --verbose print extra statistics\n", -#else - , -#endif - "gzip"); - exit(0); -} - -#ifndef SMALL -/* display the license information of NetBSD gzip */ -static void -display_license(void) -{ - - fprintf(stderr, "%s\n", gzip_version); - fprintf(stderr, "%s\n", gzip_copyright); - exit(0); -} -#endif - -/* display the version of NetBSD gzip */ -static void -display_version(void) -{ - - fprintf(stderr, "%s\n", gzip_version); - exit(0); -} - -#ifndef NO_BZIP2_SUPPORT -#include "unbzip2.c" -#endif -#ifndef NO_COMPRESS_SUPPORT -#include "zuncompress.c" -#endif - -static ssize_t -read_retry(int fd, void *buf, size_t sz) -{ - char *cp = buf; - size_t left = MIN(sz, (size_t) SSIZE_MAX); - - while (left > 0) { - ssize_t ret; - - ret = read(fd, cp, left); - if (ret == -1) { - return ret; - } else if (ret == 0) { - break; /* EOF */ - } - cp += ret; - left -= ret; - } - - return sz - left; -} - diff --git a/debian/copyright b/debian/copyright index f6d8ad6..dcaf98b 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,11 +1,13 @@ Files: * -Copyright: 2007 Joey Hess +Copyright: (c) 2007 Joey Hess + (c) 2007 Faidon Liambotis License: GPL-2+ On Debian systems, the complete text of the GPL can be found in /usr/share/common-licenses/GPL. -Files: bsd-gzip.c +Files: zgz.c Copyright: (c) 1997, 1998, 2003, 2004, 2006 Matthew R. Green + (c) 2007 Faidon Liambotis License: BSD-3 On Debian systems, the complete text of the 3 clause BSD license can be found in /usr/share/common-licenses/BSD. diff --git a/delta-format.txt b/delta-format.txt index 1d5eeb7..8227cec 100644 --- a/delta-format.txt +++ b/delta-format.txt @@ -21,18 +21,10 @@ wrapper For gz files it contains: -program - The program to run to recreate the original gz. - ("gzip" or "bsd-gzip") params - Parameters to pass to the program. + Parameters to pass to zgz. ("-n 9", "-M", "--rsyncable") -filename - The filename of the file contained in the gz. timestamp - Contains the timestamp of the file contained in the gz, as number - of seconds from the spoch. -os - OS number from the original gz. Optional, if not present, no OS - field munging is done. - + Timestamp of the original input file, in seconds from epoch. +filename + Filename of the original input file. diff --git a/pristine-gz b/pristine-gz index 013ee33..3cf0679 100755 --- a/pristine-gz +++ b/pristine-gz @@ -161,7 +161,7 @@ sub readgzip($) { return (\@flags, $timestamp, $level, $os, $name); } -sub findgzipargs($$$) { +sub predictgzipargs($$$) { my ($flags, $timestamp, $level) = @_; my @flags = @$flags; @@ -194,109 +194,88 @@ sub comparefiles($$) { return $? >> 8; } -sub gunzip($$) { - my ($filename, $name) = (shift, shift); - doit('gunzip', '-N', $filename); - if (-e $filename) { - die("gunzip failed, aborting"); - } elsif ($name && -e $name) { - # original filename because we passed -N to gunzip - return $name; - } else { - $filename =~ s/\.gz$//; - unless (-e $filename) { - die("gunzip succeded but I can't find the filename"); +sub testvariant($$$@) { + my ($old, $new, $origname, @args) = @_; + + # Unzip attempt of the previous run (or the original on the first run) + doit('gunzip', '-N', $new); + if (-e $new) { + die "gunzip failed, aborting"; + } + elsif ($origname && -e $origname) { + # original new because we passed -N to gunzip + $new = $origname; + } + else { + $new =~ s/\.gz$//; + unless (-e $new) { + die("gunzip succeded but I can't find the new file"); } - return $filename; } -} -sub gzip($@) { - my ($filename, @args) = @_; - - doit(@args, $filename); - $filename .= '.gz'; - unless (-e $filename) { - die("gzip failed, aborting"); + # try gzipping with the arguments passed + doit('zgz', @args, $new); + $new .= '.gz'; + unless (-e $new) { + die("zgz failed, aborting"); } - return $filename; -} - -sub cyclegzip($$@) { - my ($filename, $name, @args) = @_; -print ">> @args\n"; - $filename = gunzip($filename, $name); - $filename = gzip($filename, @args); - return $filename; + # and compare the generated with the original + return !comparefiles($old, $new); } -sub reproducegz { - my $orig=shift; - my $wd=shift; - - # copy the original .gz to the newly created temporary directory - my $tmp = "$wd/".basename($orig); - doit("cp", $orig, $tmp); +sub reproducegz($$$) { + my ($wd, $orig, $new) = (shift, shift, shift); # read fields from gzip headers - my ($flags, $timestamp, $level, $os, $name) = readgzip($tmp); - debug("Examining $orig", $name ? " (real: $name)" : ''); - $name = "$wd/$name" if $name; + my ($flags, $timestamp, $level, $os, $name) = readgzip($new); # try to guess the gzip arguments that are needed by the header # information - my @args = findgzipargs($flags, $timestamp, $level); - - my @methods=( - # for 98% of the cases the simple heuristic works - sub { - debug("Trying 'gzip ", join(' ', @args), "'..."); - return undef, "gzip", @args; - }, - # some archives have an Operating System flag different - # than Unix - # XXX: if they're the same, just replace the bit - #sub { - # if ($os != GZIP_OS_UNIX) { - # debug("Unknown Operating System: $os"); - # } - #}, - # some .gz are created using --rsyncable -- this is a - # Debian-specific option however and it's not very popular - sub { - debug("Trying with --rsyncable..."); - return undef, "gzip", @args, '--rsyncable'; - }, - # many of the .gz out there are created using the BSD version - # of gzip which is using the zlib library; try with our version - # of bsd-gzip with added support for the undocumented GNU gzip - # options -m and -M - sub { - debug("Trying with bsd-gzip..."); - return undef, "bsd-gzip", @args; - }, - # apparently, there is an old version of bsd-gzip (or a similar - # tool based on zlib) that creates gz using maximum compression - # (-9) but does not indicate so in the headers. surprisingly, - # there are many .gz out there - sub { - debug("Trying with buggy variant of bsd-gzip..."); - return undef, "bsd-gzip", @args, '--no-xfl'; - }, - ); - - foreach my $method (@methods) { - my @r=$method->(); - my $postsub=shift @r; - $tmp = cyclegzip($tmp, $name, @r); - $postsub->() if $postsub; - doit("md5sum", $orig, $tmp); - if (comparefiles($orig, $tmp) == 0) { - $tmp=~s/\.gz$//; - return basename($tmp), $timestamp, 0, @r; - } - }; + my @args = predictgzipargs($flags, $timestamp, $level); + + $name = "$wd/$name" if $name && $name !~ /\//; + + if ($os == GZIP_OS_UNIX && $name !~ /\//) { + # for 98% of the cases the simple heuristic above works + testvariant($orig, $new, $name, '--gnu', @args) + && return $name, $timestamp, '--gnu', @args; + + # some .gz are created using --rsyncable + # it is a Debian-specific option not very popular + testvariant($orig, $new, $name, '--gnu', @args, '--rsyncable') + && return $name, $timestamp, '--gnu', @args, '--rsyncable'; + } + + if ($name =~ /\//) { + push @args, "--original-name", $name; + $name = basename($name); + $name = "$wd/$name"; + } + + # Windows' NTFS gzip implementation; quirk is really really evil + if ($os == GZIP_OS_NTFS) { + testvariant($orig, $new, $name, @args, '--quirk', 'ntfs') + && return $name, $timestamp, @args, '--quirk', 'ntfs'; + } + + # set the Operating System flag to the one found in the original + # archive + push @args, ("--osflag", $os) if $os != GZIP_OS_UNIX; + + # many of the .gz out there are created using the BSD version of + # gzip which is using the zlib library; try with our version of + # bsd-gzip with added support for the undocumented GNU gzip options + # -m and -M + testvariant($orig, $new, $name, @args) + && return $name, $timestamp, @args; + + # apparently, there is an old version of bsd-gzip (or a similar tool + # based on zlib) that creates gz using maximum compression (-9) but + # does not indicate so in the headers. surprisingly, there are many + # .gz out there. + testvariant($orig, $new, $name, @args, '--quirk', 'buggy-bsd') + && return $name. $timestamp, @args, '--quirk', 'buggy-bsd'; print STDERR("pristine-gz failed to reproduce build of $orig\n"); print STDERR("(Please file a bug report.)\n"); @@ -330,24 +309,29 @@ sub gengz { } - open (IN, "$tempdir/program") || die "delta lacks program file ($!)"; - my $program=; - chomp $program; - if ($program !~ /^(gzip|bsd-gzip)$/) { - die "paranoia check failed on program file from delta ($program)"; - } - close IN; open (IN, "$tempdir/params") || die "delta lacks params file ($!)"; my $params=; chomp $params; my @params=split(' ', $params); - if (grep { ! /^(--no-xfl|--rsyncable|-[nmM1-9])$/ } @params) { - die "paranoia check failed on params file from delta (@params)"; + while (@params) { + $_=shift @params; + next if /^(--gnu|--rsyncable|-[nmM1-9])$/; + if (/^(--original-name|--quirk|--osflag)$/) { + shift @params; + } + die "paranoia check failed on params file from delta ($params)"; } + @params=split(' ', $params); close IN; open (IN, "$tempdir/filename") || die "delta lacks filename file ($!)"; my $filename=; chomp $filename; + if ($filename =~ /\//) { + die "paranoia check failed on filename field from delta ($filename)"; + } + if (! length $filename) { + $filename="input"; + } close IN; open (IN, "$tempdir/timestamp") || die "delta lacks timestamp file ($!)"; my $timestamp=; @@ -357,7 +341,7 @@ sub gengz { doit("cp", $file, "$tempdir/$filename"); utime($timestamp, $timestamp, "$tempdir/$filename") || die "utime: $!"; - doit($program, @params, "-f", "$tempdir/$filename"); + doit("zgz", @params, "-f", "$tempdir/$filename"); doit("mv", "$tempdir/$filename.gz", "$file.gz"); doit("rm", "-f", "$tempdir/$filename.gz", $file); } @@ -367,13 +351,11 @@ sub gendelta { my $delta=shift; my $tempdir=tempdir(); - my @files=qw(version type program params filename timestamp); - - my $sourcedir="$tempdir/tmp"; - doit("mkdir $sourcedir"); + my @files=qw(version type params filename timestamp); - my ($filename, $timestamp, $osflag, $program, @params)= - reproducegz($gzfile, $tempdir); + doit("cp", $gzfile, "$tempdir/test.gz"); + my ($filename, $timestamp, @params)= + reproducegz($tempdir, $gzfile, "$tempdir/test.gz"); open(OUT, ">", "$tempdir/version") || die "$!"; print OUT "1.1\n"; @@ -381,9 +363,6 @@ sub gendelta { open(OUT, ">", "$tempdir/type") || die "$!"; print OUT "gz\n"; close OUT; - open(OUT, ">", "$tempdir/program") || die "$!"; - print OUT "$program\n"; - close OUT; open(OUT, ">", "$tempdir/params") || die "$!"; print OUT "@params\n"; close OUT;