/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
- Copyright (C) 1999, 2001-2002, 2006-2007, 2009-2010 Free Software
+ Copyright (C) 1999, 2001-2002, 2006-2007, 2009-2011 Free Software
Foundation, Inc.
Copyright (C) 1992-1993 Jean-loup Gailly
*/
static char const *const license_msg[] = {
-"Copyright (C) 2007, 2010 Free Software Foundation, Inc.",
+"Copyright (C) 2007, 2010, 2011 Free Software Foundation, Inc.",
"Copyright (C) 1993 Jean-loup Gailly.",
"This is free software. You may redistribute copies of it under the terms of",
"the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.",
#endif
#ifdef off_t
- off_t lseek OF((int fd, off_t offset, int whence));
+ off_t lseek (int fd, off_t offset, int whence);
#endif
#ifndef OFF_T_MIN
# define HAVE_WORKING_O_NOFOLLOW 0
#endif
-#ifndef ELOOP
-# define ELOOP EINVAL
-#endif
-
/* Separator for file name parts (see shorten_name()) */
#ifdef NO_MULTIPLE_DOTS
# define PART_SEP "-"
is deliberately not documented, and only for testing. */
static bool presume_input_tty;
-int ascii = 0; /* convert end-of-lines to local OS conventions */
-int to_stdout = 0; /* output to stdout (-c) */
-int decompress = 0; /* decompress (-d) */
-int force = 0; /* don't ask questions, compress links (-f) */
-int no_name = -1; /* don't save or restore the original file name */
-int no_time = -1; /* don't save or restore the original file time */
-int recursive = 0; /* recurse through directories (-r) */
-int list = 0; /* list the file contents (-l) */
-int verbose = 0; /* be verbose (-v) */
-int quiet = 0; /* be very quiet (-q) */
-int do_lzw = 0; /* generate output compatible with old compress (-Z) */
-int test = 0; /* test .gz file integrity */
-int foreground = 0; /* set if program run in foreground */
-char *program_name; /* program name */
-int maxbits = BITS; /* max bits per code for LZW */
-int method = DEFLATED;/* compression method */
-int level = 6; /* compression level */
-int exit_code = OK; /* program exit code */
-int save_orig_name; /* set if original name must be saved */
-int last_member; /* set for .zip and .Z files */
-int part_nb; /* number of parts in .gz file */
-struct timespec time_stamp; /* original time stamp (modification time) */
-off_t ifile_size; /* input file size, -1 for devices (debug only) */
-char *env; /* contents of GZIP env variable */
-char **args = NULL; /* argv pointer if GZIP env variable defined */
-char const *z_suffix; /* default suffix (can be set with --suffix) */
-size_t z_len; /* strlen(z_suffix) */
+static int ascii = 0; /* convert end-of-lines to local OS conventions */
+ int to_stdout = 0; /* output to stdout (-c) */
+static int decompress = 0; /* decompress (-d) */
+static int force = 0; /* don't ask questions, compress links (-f) */
+static int no_name = -1; /* don't save or restore the original file name */
+static int no_time = -1; /* don't save or restore the original file time */
+static int recursive = 0; /* recurse through directories (-r) */
+static int list = 0; /* list the file contents (-l) */
+ int verbose = 0; /* be verbose (-v) */
+ int quiet = 0; /* be very quiet (-q) */
+static int do_lzw = 0; /* generate output compatible with old compress (-Z) */
+ int test = 0; /* test .gz file integrity */
+static int foreground = 0; /* set if program run in foreground */
+ char *program_name; /* program name */
+ int maxbits = BITS; /* max bits per code for LZW */
+ int method = DEFLATED;/* compression method */
+ int level = 6; /* compression level */
+ int exit_code = OK; /* program exit code */
+ int save_orig_name; /* set if original name must be saved */
+static int last_member; /* set for .zip and .Z files */
+static int part_nb; /* number of parts in .gz file */
+ struct timespec time_stamp; /* original time stamp (modification time) */
+ off_t ifile_size; /* input file size, -1 for devices (debug only) */
+static char *env; /* contents of GZIP env variable */
+static char **args = NULL; /* argv pointer if GZIP env variable defined */
+static char const *z_suffix; /* default suffix (can be set with --suffix) */
+static size_t z_len; /* strlen(z_suffix) */
/* The set of signals that are caught. */
static sigset_t caught_signals;
off_t bytes_in; /* number of input bytes */
off_t bytes_out; /* number of output bytes */
-off_t total_in; /* input bytes for all files */
-off_t total_out; /* output bytes for all files */
+static off_t total_in; /* input bytes for all files */
+static off_t total_out; /* output bytes for all files */
char ifname[MAX_PATH_LEN]; /* input file name */
char ofname[MAX_PATH_LEN]; /* output file name */
-struct stat istat; /* status for input file */
+static struct stat istat; /* status for input file */
int ifd; /* input file descriptor */
int ofd; /* output file descriptor */
unsigned insize; /* valid bytes in inbuf */
#ifdef SIGHUP
, SIGHUP
#endif
-#ifdef SIGPIPE
, SIGPIPE
-#else
-# define SIGPIPE 0
-#endif
#ifdef SIGTERM
, SIGTERM
#endif
PRESUME_INPUT_TTY_OPTION = CHAR_MAX + 1
};
-struct option longopts[] =
+static const struct option longopts[] =
{
/* { name has_arg *flag val } */
{"ascii", 0, 0, 'a'}, /* ascii text mode */
/* local functions */
-local void try_help OF((void)) ATTRIBUTE_NORETURN;
-local void help OF((void));
-local void license OF((void));
-local void version OF((void));
-local int input_eof OF((void));
-local void treat_stdin OF((void));
-local void treat_file OF((char *iname));
-local int create_outfile OF((void));
-local char *get_suffix OF((char *name));
-local int open_input_file OF((char *iname, struct stat *sbuf));
-local int make_ofname OF((void));
-local void shorten_name OF((char *name));
-local int get_method OF((int in));
-local void do_list OF((int ifd, int method));
-local int check_ofname OF((void));
-local void copy_stat OF((struct stat *ifstat));
-local void install_signal_handlers OF((void));
-local void remove_output_file OF((void));
-local RETSIGTYPE abort_gzip_signal OF((int));
-local void do_exit OF((int exitcode)) ATTRIBUTE_NORETURN;
- int main OF((int argc, char **argv));
-int (*work) OF((int infile, int outfile)) = zip; /* function to call */
+local void try_help (void) ATTRIBUTE_NORETURN;
+local void help (void);
+local void license (void);
+local void version (void);
+local int input_eof (void);
+local void treat_stdin (void);
+local void treat_file (char *iname);
+local int create_outfile (void);
+local char *get_suffix (char *name);
+local int open_input_file (char *iname, struct stat *sbuf);
+local void discard_input_bytes (size_t nbytes, unsigned int flags);
+local int make_ofname (void);
+local void shorten_name (char *name);
+local int get_method (int in);
+local void do_list (int ifd, int method);
+local int check_ofname (void);
+local void copy_stat (struct stat *ifstat);
+local void install_signal_handlers (void);
+local void remove_output_file (void);
+local RETSIGTYPE abort_gzip_signal (int);
+local void do_exit (int exitcode) ATTRIBUTE_NORETURN;
+ int main (int argc, char **argv);
+static int (*work) (int infile, int outfile) = zip; /* function to call */
#if ! NO_DIR
-local void treat_dir OF((int fd, char *dir));
+local void treat_dir (int fd, char *dir);
#endif
#define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
return WARNING;
}
+/* Discard NBYTES input bytes from the input, or up through the next
+ zero byte if NBYTES == (size_t) -1. If FLAGS say that the header
+ CRC should be computed, update the CRC accordingly. */
+static void
+discard_input_bytes (nbytes, flags)
+ size_t nbytes;
+ unsigned int flags;
+{
+ while (nbytes != 0)
+ {
+ uch c = get_byte ();
+ if (flags & HEADER_CRC)
+ updcrc (&c, 1);
+ if (nbytes != (size_t) -1)
+ nbytes--;
+ else if (! c)
+ break;
+ }
+}
/* ========================================================================
* Check the magic number of the input file and update ofname if an
int in; /* input file descriptor */
{
uch flags; /* compression flags */
- char magic[2]; /* magic header */
+ uch magic[10]; /* magic header */
int imagic0; /* first magic byte or EOF */
int imagic1; /* like magic[1], but can represent EOF */
ulg stamp; /* time stamp */
*/
if (force && to_stdout) {
imagic0 = try_byte();
- magic[0] = (char) imagic0;
+ magic[0] = imagic0;
imagic1 = try_byte ();
- magic[1] = (char) imagic1;
+ magic[1] = imagic1;
/* If try_byte returned EOF, magic[1] == (char) EOF. */
} else {
- magic[0] = (char)get_byte();
+ magic[0] = get_byte ();
imagic0 = 0;
if (magic[0]) {
- magic[1] = (char)get_byte();
+ magic[1] = get_byte ();
imagic1 = 0; /* avoid lint warning */
} else {
imagic1 = try_byte ();
- magic[1] = (char) imagic1;
+ magic[1] = imagic1;
}
}
method = -1; /* unknown yet */
exit_code = ERROR;
return -1;
}
- if ((flags & CONTINUATION) != 0) {
- fprintf(stderr,
- "%s: %s is a multi-part gzip file -- not supported\n",
- program_name, ifname);
- exit_code = ERROR;
- if (force <= 1) return -1;
- }
if ((flags & RESERVED) != 0) {
fprintf(stderr,
"%s: %s has flags 0x%x -- not supported\n",
time_stamp.tv_nsec = 0;
}
- (void)get_byte(); /* Ignore extra flags for the moment */
- (void)get_byte(); /* Ignore OS type for the moment */
+ magic[8] = get_byte (); /* Ignore extra flags. */
+ magic[9] = get_byte (); /* Ignore OS type. */
+
+ if (flags & HEADER_CRC)
+ {
+ magic[2] = DEFLATED;
+ magic[3] = flags;
+ magic[4] = stamp & 0xff;
+ magic[5] = (stamp >> 8) & 0xff;
+ magic[6] = (stamp >> 16) & 0xff;
+ magic[7] = stamp >> 24;
+ updcrc (NULL, 0);
+ updcrc (magic, 10);
+ }
- if ((flags & CONTINUATION) != 0) {
- unsigned part = (unsigned)get_byte();
- part |= ((unsigned)get_byte())<<8;
- if (verbose) {
- fprintf(stderr,"%s: %s: part number %u\n",
- program_name, ifname, part);
- }
- }
if ((flags & EXTRA_FIELD) != 0) {
- unsigned len = (unsigned)get_byte();
- len |= ((unsigned)get_byte())<<8;
+ uch lenbuf[2];
+ unsigned int len = lenbuf[0] = get_byte ();
+ len |= (lenbuf[1] = get_byte ()) << 8;
if (verbose) {
fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
program_name, ifname, len);
}
- while (len--) (void)get_byte();
+ if (flags & HEADER_CRC)
+ updcrc (lenbuf, 2);
+ discard_input_bytes (len, flags);
}
/* 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);
+ discard_input_bytes (-1, flags);
} else {
/* Copy the base name. Keep a directory prefix intact. */
char *p = gzip_base_name (ofname);
char *base = p;
for (;;) {
- *p = (char)get_char();
+ *p = (char) get_byte ();
if (*p++ == '\0') break;
if (p >= ofname+sizeof(ofname)) {
gzip_error ("corrupted input -- file name too large");
}
}
+ if (flags & HEADER_CRC)
+ updcrc ((uch *) base, p - base);
p = gzip_base_name (base);
memmove (base, p, strlen (p) + 1);
/* If necessary, adapt the name to local OS conventions: */
/* Discard file comment if any */
if ((flags & COMMENT) != 0) {
- while (get_char() != 0) /* null */ ;
+ discard_input_bytes (-1, flags);
}
+
+ if (flags & HEADER_CRC)
+ {
+ unsigned int crc16 = updcrc (magic, 0) & 0xffff;
+ unsigned int header16 = get_byte ();
+ header16 |= ((unsigned int) get_byte ()) << 8;
+ if (header16 != crc16)
+ {
+ fprintf (stderr,
+ "%s: %s: header checksum 0x%04x != computed checksum 0x%04x\n",
+ program_name, ifname, header16, crc16);
+ exit_code = ERROR;
+ if (force <= 1)
+ return -1;
+ }
+ }
+
if (part_nb == 1) {
- header_bytes = inptr + 2*sizeof(long); /* include crc and size */
+ header_bytes = inptr + 2*4; /* include crc and size */
}
} else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
bytes_out = -1L;
bytes_in = ifile_size;
-#if RECORD_IO == 0
- if (method == DEFLATED && !last_member) {
+ if (!RECORD_IO && method == DEFLATED && !last_member) {
/* Get the crc and uncompressed size for gzip'ed (not zip'ed) files.
* If the lseek fails, we could use read() to get to the end, but
* --list is used to get quick results.
bytes_out = LG(buf+4);
}
}
-#endif /* RECORD_IO */
+
if (verbose)
{
struct tm *tm = localtime (&time_stamp.tv_sec);
}
}
- if (gl_futimens (ofd, ofname, timespec) != 0)
+ if (fdutimens (ofd, ofname, timespec) != 0)
{
int e = errno;
WARN ((stderr, "%s: ", program_name));