version 1.29.2.29.2.2, 2005/05/13 17:21:22 |
version 1.29.2.29.2.3, 2005/07/24 21:21:17 |
Line 38 __RCSID("$NetBSD$"); |
|
Line 38 __RCSID("$NetBSD$"); |
|
/* |
/* |
* gzip.c -- GPL free gzip using zlib. |
* 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: |
* TODO: |
* - handle .taz/.tgz files? |
|
* - use mmap where possible |
* - use mmap where possible |
* - handle some signals better (remove outfile?) |
* - handle some signals better (remove outfile?) |
* - make bzip2/compress -v/-t/-l support work as well as possible |
* - make bzip2/compress -v/-t/-l support work as well as possible |
Line 49 __RCSID("$NetBSD$"); |
|
Line 52 __RCSID("$NetBSD$"); |
|
#include <sys/stat.h> |
#include <sys/stat.h> |
#include <sys/time.h> |
#include <sys/time.h> |
|
|
|
#include <inttypes.h> |
#include <unistd.h> |
#include <unistd.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <string.h> |
#include <string.h> |
Line 63 __RCSID("$NetBSD$"); |
|
Line 67 __RCSID("$NetBSD$"); |
|
#include <getopt.h> |
#include <getopt.h> |
#include <time.h> |
#include <time.h> |
|
|
|
#ifndef PRIdOFF |
|
#define PRIdOFF PRId64 |
|
#endif |
|
|
/* what type of file are we dealing with */ |
/* what type of file are we dealing with */ |
enum filetype { |
enum filetype { |
FT_GZIP, |
FT_GZIP, |
|
|
|
|
#define OS_CODE 3 /* Unix */ |
#define OS_CODE 3 /* Unix */ |
|
|
#ifndef SMALL |
typedef struct { |
static char const *suffixes[] = { |
const char *zipped; |
GZ_SUFFIX, ".z", ".taz", ".tgz", "-gz", "-z", "_z", |
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 |
#ifndef NO_BZIP2_SUPPORT |
BZ2_SUFFIX, |
SUFFIX(BZ2_SUFFIX, ""), |
#endif |
#endif |
#ifndef NO_COMPRESS_SUPPORT |
#ifndef NO_COMPRESS_SUPPORT |
Z_SUFFIX, |
SUFFIX(Z_SUFFIX, ""), |
#endif |
#endif |
NULL |
SUFFIX(GZ_SUFFIX, ""), /* Overwritten by -S "" */ |
}; |
|
#endif /* SMALL */ |
#endif /* SMALL */ |
|
#undef SUFFIX |
|
}; |
|
#define NUM_SUFFIXES (sizeof suffixes / sizeof suffixes[0]) |
|
|
static const char gzip_version[] = "NetBSD gzip 20040711"; |
static const char gzip_version[] = "NetBSD gzip 20040830"; |
|
|
static int cflag; /* stdout mode */ |
static int cflag; /* stdout mode */ |
static int dflag; /* decompress mode */ |
static int dflag; /* decompress mode */ |
Line 133 static int Nflag; /* don't restore nam |
|
Line 156 static int Nflag; /* don't restore nam |
|
static int qflag; /* quiet mode */ |
static int qflag; /* quiet mode */ |
static int rflag; /* recursive mode */ |
static int rflag; /* recursive mode */ |
static int tflag; /* test */ |
static int tflag; /* test */ |
static char *Sflag; |
|
static int vflag; /* verbose mode */ |
static int vflag; /* verbose mode */ |
#else |
#else |
#define qflag 0 |
#define qflag 0 |
|
#define tflag 0 |
#endif |
#endif |
|
|
static int exit_value = 0; /* exit value */ |
static int exit_value = 0; /* exit value */ |
|
|
static const char *suffix; |
|
#define suffix_len (strlen(suffix) + 1) /* len + nul */ |
|
static char *infile; /* name of file coming in */ |
static char *infile; /* name of file coming in */ |
|
|
static void maybe_err(const char *fmt, ...); |
static void maybe_err(const char *fmt, ...) |
static void maybe_errx(const char *fmt, ...); |
__attribute__((__format__(__printf__, 1, 2))); |
static void maybe_warn(const char *fmt, ...); |
#ifndef NO_BZIP2_SUPPORT |
static void maybe_warnx(const char *fmt, ...); |
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 *); |
static enum filetype file_gettype(u_char *); |
static off_t gz_compress(FILE *, int, off_t *, const char *, time_t); |
#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 gz_uncompress(int, int, char *, size_t, off_t *, const char *); |
static off_t file_compress(char *, char *, size_t); |
static off_t file_compress(char *, char *, size_t); |
static off_t file_uncompress(char *, char *, size_t); |
static off_t file_uncompress(char *, char *, size_t); |
static off_t cat_fd(unsigned char *, size_t, off_t *, int fd); |
|
static void handle_pathname(char *); |
static void handle_pathname(char *); |
static void handle_file(char *, struct stat *); |
static void handle_file(char *, struct stat *); |
static void handle_stdin(void); |
static void handle_stdin(void); |
Line 163 static void print_ratio(off_t, off_t, FI |
|
Line 192 static void print_ratio(off_t, off_t, FI |
|
static void print_list(int fd, off_t, const char *, time_t); |
static void print_list(int fd, off_t, const char *, time_t); |
static void usage(void); |
static void usage(void); |
static void display_version(void); |
static void display_version(void); |
|
static const suffixes_t *check_suffix(char *, int); |
|
static ssize_t read_retry(int, void *, size_t); |
|
|
#ifndef SMALL |
#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 prepend_gzip(char *, int *, char ***); |
static void handle_dir(char *, struct stat *); |
static void handle_dir(char *, struct stat *); |
static void print_verbage(char *, char *, off_t, off_t); |
static void print_verbage(const char *, const char *, off_t, off_t); |
static void print_test(const char *, int); |
static void print_test(const char *, int); |
static void copymodes(const char *, struct stat *); |
static void copymodes(const char *, struct stat *); |
static int check_outfile(const char *outfile, struct stat *sb); |
static int check_outfile(const char *outfile, struct stat *sb); |
static const char *check_suffix(char *); |
|
#endif |
#endif |
|
|
#ifndef NO_BZIP2_SUPPORT |
#ifndef NO_BZIP2_SUPPORT |
Line 179 static off_t unbzip2(int, int, char *, s |
|
Line 212 static off_t unbzip2(int, int, char *, s |
|
#endif |
#endif |
|
|
#ifndef NO_COMPRESS_SUPPORT |
#ifndef NO_COMPRESS_SUPPORT |
static FILE *zopen(const char *, FILE *); |
static FILE *zdopen(int); |
static off_t zuncompress(FILE *, FILE *, char *, size_t, off_t *); |
static off_t zuncompress(FILE *, FILE *, char *, size_t, off_t *); |
#endif |
#endif |
|
|
Line 224 main(int argc, char **argv) |
|
Line 257 main(int argc, char **argv) |
|
const char *progname = getprogname(); |
const char *progname = getprogname(); |
#ifndef SMALL |
#ifndef SMALL |
char *gzip; |
char *gzip; |
|
int len; |
#endif |
#endif |
int ch; |
int ch; |
|
|
/* XXX set up signals */ |
/* XXX set up signals */ |
|
|
suffix = GZ_SUFFIX; |
|
|
|
#ifndef SMALL |
#ifndef SMALL |
if ((gzip = getenv("GZIP")) != NULL) |
if ((gzip = getenv("GZIP")) != NULL) |
prepend_gzip(gzip, &argc, &argv); |
prepend_gzip(gzip, &argc, &argv); |
Line 252 main(int argc, char **argv) |
|
Line 284 main(int argc, char **argv) |
|
#define OPT_LIST "cdfhHlnNqrS:tvV123456789" |
#define OPT_LIST "cdfhHlnNqrS:tvV123456789" |
#endif |
#endif |
|
|
while ((ch = getopt_long(argc, argv, OPT_LIST, longopts, NULL)) != -1) |
while ((ch = getopt_long(argc, argv, OPT_LIST, longopts, NULL)) != -1) { |
switch (ch) { |
switch (ch) { |
case 'c': |
case 'c': |
cflag = 1; |
cflag = 1; |
Line 291 main(int argc, char **argv) |
|
Line 323 main(int argc, char **argv) |
|
rflag = 1; |
rflag = 1; |
break; |
break; |
case 'S': |
case 'S': |
Sflag = optarg; |
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; |
break; |
case 't': |
case 't': |
cflag = 1; |
cflag = 1; |
Line 306 main(int argc, char **argv) |
|
Line 345 main(int argc, char **argv) |
|
usage(); |
usage(); |
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |
|
} |
argv += optind; |
argv += optind; |
argc -= optind; |
argc -= optind; |
|
|
Line 370 maybe_err(const char *fmt, ...) |
|
Line 410 maybe_err(const char *fmt, ...) |
|
exit(2); |
exit(2); |
} |
} |
|
|
|
#ifndef NO_BZIP2_SUPPORT |
/* ... without an errno. */ |
/* ... without an errno. */ |
void |
void |
maybe_errx(const char *fmt, ...) |
maybe_errx(const char *fmt, ...) |
Line 383 maybe_errx(const char *fmt, ...) |
|
Line 424 maybe_errx(const char *fmt, ...) |
|
} |
} |
exit(2); |
exit(2); |
} |
} |
|
#endif |
|
|
#ifndef SMALL |
#ifndef SMALL |
/* split up $GZIP and prepend it to the argument list */ |
/* split up $GZIP and prepend it to the argument list */ |
Line 393 prepend_gzip(char *gzip, int *argc, char |
|
Line 435 prepend_gzip(char *gzip, int *argc, char |
|
int nenvarg = 0, i; |
int nenvarg = 0, i; |
|
|
/* scan how many arguments there are */ |
/* scan how many arguments there are */ |
for (s = gzip; *s; s++) { |
for (s = gzip;;) { |
if (*s == ' ' || *s == '\t') |
while (*s == ' ' || *s == '\t') |
continue; |
s++; |
|
if (*s == 0) |
|
goto count_done; |
nenvarg++; |
nenvarg++; |
for (; *s; s++) |
while (*s != ' ' && *s != '\t') |
if (*s == ' ' || *s == '\t') |
if (*s++ == 0) |
break; |
goto count_done; |
if (*s == 0x0) |
|
break; |
|
} |
} |
|
count_done: |
/* punt early */ |
/* punt early */ |
if (nenvarg == 0) |
if (nenvarg == 0) |
return; |
return; |
Line 425 prepend_gzip(char *gzip, int *argc, char |
|
Line 468 prepend_gzip(char *gzip, int *argc, char |
|
s = strdup(gzip); |
s = strdup(gzip); |
if (s == NULL) |
if (s == NULL) |
maybe_err("strdup"); |
maybe_err("strdup"); |
for (; *s; s++) { |
for (;;) { |
if (*s == ' ' || *s == '\t') |
/* Skip whitespaces. */ |
continue; |
while (*s == ' ' || *s == '\t') |
|
s++; |
|
if (*s == 0) |
|
goto copy_done; |
nargv[i++] = s; |
nargv[i++] = s; |
for (; *s; s++) |
/* Find the end of this argument. */ |
if (*s == ' ' || *s == '\t') { |
while (*s != ' ' && *s != '\t') |
*s = 0; |
if (*s++ == 0) |
break; |
/* 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 */ |
/* copy the original arguments and a NULL */ |
while (*ac) |
while (*ac) |
Line 443 prepend_gzip(char *gzip, int *argc, char |
|
Line 492 prepend_gzip(char *gzip, int *argc, char |
|
} |
} |
#endif |
#endif |
|
|
/* compress input to output then close both files */ |
/* compress input to output. Return bytes read, -1 on error */ |
static off_t |
static off_t |
gz_compress(FILE *in, int out, off_t *gsizep, const char *origname, time_t mtime) |
gz_compress(int in, int out, off_t *gsizep, const char *origname, uint32_t mtime) |
{ |
{ |
z_stream z; |
z_stream z; |
char *outbufp, *inbufp; |
char *outbufp, *inbufp; |
off_t in_tot = 0, out_tot = 0; |
off_t in_tot = 0, out_tot = 0; |
ssize_t in_size; |
ssize_t in_size; |
char *str; |
|
int i, error; |
int i, error; |
uLong crc; |
uLong crc; |
|
#ifdef SMALL |
|
static char header[] = { GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED, 0, |
|
0, 0, 0, 0, |
|
0, OS_CODE }; |
|
#endif |
|
|
if ((outbufp = malloc(BUFLEN)) == NULL) { |
outbufp = malloc(BUFLEN); |
|
inbufp = malloc(BUFLEN); |
|
if (outbufp == NULL || inbufp == NULL) { |
maybe_err("malloc failed"); |
maybe_err("malloc failed"); |
goto out2; |
|
} |
|
if ((inbufp = malloc(BUFLEN)) == NULL) { |
|
maybe_err("malloc failed"); |
|
goto out1; |
|
} |
|
|
|
i = asprintf(&str, "%c%c%c%c%c%c%c%c%c%c%s", |
|
GZIP_MAGIC0, GZIP_MAGIC1, |
|
Z_DEFLATED, origname ? ORIG_NAME : 0, |
|
(int)mtime & 0xff, |
|
(int)(mtime >> 8) & 0xff, |
|
(int)(mtime >> 16) & 0xff, |
|
(int)(mtime >> 24) & 0xff, |
|
0, OS_CODE, origname ? origname : ""); |
|
if (i == -1) |
|
maybe_err("asprintf"); |
|
if (origname) |
|
i++; |
|
if (write(out, str, i) != i) { |
|
maybe_warn("write"); |
|
in_tot = -1; |
|
goto out; |
goto out; |
} |
} |
free(str); |
|
|
|
memset(&z, 0, sizeof z); |
memset(&z, 0, sizeof z); |
z.next_out = outbufp; |
|
z.avail_out = BUFLEN; |
|
z.zalloc = Z_NULL; |
z.zalloc = Z_NULL; |
z.zfree = Z_NULL; |
z.zfree = Z_NULL; |
z.opaque = 0; |
z.opaque = 0; |
|
|
|
#ifdef SMALL |
|
memcpy(outbufp, header, sizeof header); |
|
i = sizeof header; |
|
#else |
|
if (nflag != 0) { |
|
mtime = 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 = outbufp + i; |
|
z.avail_out = BUFLEN - i; |
|
|
error = deflateInit2(&z, numflag, Z_DEFLATED, |
error = deflateInit2(&z, numflag, Z_DEFLATED, |
-MAX_WBITS, 8, Z_DEFAULT_STRATEGY); |
-MAX_WBITS, 8, Z_DEFAULT_STRATEGY); |
if (error != Z_OK) { |
if (error != Z_OK) { |
Line 513 gz_compress(FILE *in, int out, off_t *gs |
|
Line 571 gz_compress(FILE *in, int out, off_t *gs |
|
} |
} |
|
|
if (z.avail_in == 0) { |
if (z.avail_in == 0) { |
in_size = fread(inbufp, 1, BUFLEN, in); |
in_size = read(in, inbufp, BUFLEN); |
if (ferror(in)) { |
if (in_size < 0) { |
maybe_warn("fread"); |
maybe_warn("read"); |
in_tot = -1; |
in_tot = -1; |
goto out; |
goto out; |
} |
} |
Line 547 gz_compress(FILE *in, int out, off_t *gs |
|
Line 605 gz_compress(FILE *in, int out, off_t *gs |
|
goto out; |
goto out; |
} |
} |
|
|
len = BUFLEN - z.avail_out; |
len = (char *)z.next_out - outbufp; |
|
|
if (write(out, outbufp, len) != len) { |
if (write(out, outbufp, len) != len) { |
maybe_warn("write"); |
maybe_warn("write"); |
Line 568 gz_compress(FILE *in, int out, off_t *gs |
|
Line 626 gz_compress(FILE *in, int out, off_t *gs |
|
goto out; |
goto out; |
} |
} |
|
|
i = asprintf(&str, "%c%c%c%c%c%c%c%c", |
i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c", |
(int)crc & 0xff, |
(int)crc & 0xff, |
(int)(crc >> 8) & 0xff, |
(int)(crc >> 8) & 0xff, |
(int)(crc >> 16) & 0xff, |
(int)(crc >> 16) & 0xff, |
Line 578 gz_compress(FILE *in, int out, off_t *gs |
|
Line 636 gz_compress(FILE *in, int out, off_t *gs |
|
(int)(in_tot >> 16) & 0xff, |
(int)(in_tot >> 16) & 0xff, |
(int)(in_tot >> 24) & 0xff); |
(int)(in_tot >> 24) & 0xff); |
if (i != 8) |
if (i != 8) |
maybe_err("asprintf"); |
maybe_err("snprintf"); |
if (write(out, str, i) != i) { |
if (write(out, outbufp, i) != i) { |
maybe_warn("write"); |
maybe_warn("write"); |
in_tot = -1; |
in_tot = -1; |
} |
} else |
free(str); |
out_tot += i; |
|
|
out: |
out: |
free(inbufp); |
if (inbufp != NULL) |
out1: |
free(inbufp); |
free(outbufp); |
if (outbufp != NULL) |
out2: |
free(outbufp); |
if (gsizep) |
if (gsizep) |
*gsizep = out_tot; |
*gsizep = out_tot; |
return in_tot; |
return in_tot; |
Line 606 gz_uncompress(int in, int out, char *pre |
|
Line 664 gz_uncompress(int in, int out, char *pre |
|
{ |
{ |
z_stream z; |
z_stream z; |
char *outbufp, *inbufp; |
char *outbufp, *inbufp; |
off_t out_tot, in_tot; |
off_t out_tot = -1, in_tot = 0; |
uint32_t out_sub_tot; |
uint32_t out_sub_tot = 0; |
enum { |
enum { |
GZSTATE_MAGIC0, |
GZSTATE_MAGIC0, |
GZSTATE_MAGIC1, |
GZSTATE_MAGIC1, |
Line 627 gz_uncompress(int in, int out, char *pre |
|
Line 685 gz_uncompress(int in, int out, char *pre |
|
GZSTATE_LEN, |
GZSTATE_LEN, |
} state = GZSTATE_MAGIC0; |
} state = GZSTATE_MAGIC0; |
int flags = 0, skip_count = 0; |
int flags = 0, skip_count = 0; |
int error, done_reading = 0; |
int error = Z_STREAM_ERROR, done_reading = 0; |
uLong crc; |
uLong crc = 0; |
|
ssize_t wr; |
|
int needmore = 0; |
|
|
#define ADVANCE() { z.next_in++; z.avail_in--; } |
#define ADVANCE() { z.next_in++; z.avail_in--; } |
|
|
Line 654 gz_uncompress(int in, int out, char *pre |
|
Line 714 gz_uncompress(int in, int out, char *pre |
|
out_tot = 0; |
out_tot = 0; |
|
|
for (;;) { |
for (;;) { |
if (z.avail_in == 0 && done_reading == 0) { |
if ((z.avail_in == 0 || needmore) && done_reading == 0) { |
size_t in_size = read(in, inbufp, BUFLEN); |
size_t in_size; |
|
|
|
if (z.avail_in > 0) { |
|
memmove(inbufp, z.next_in, z.avail_in); |
|
} |
|
z.next_in = inbufp; |
|
in_size = read(in, z.next_in + z.avail_in, |
|
BUFLEN - z.avail_in); |
|
|
if (in_size == -1) { |
if (in_size == -1) { |
#ifndef SMALL |
#ifndef SMALL |
Line 665 gz_uncompress(int in, int out, char *pre |
|
Line 732 gz_uncompress(int in, int out, char *pre |
|
maybe_warn("failed to read stdin"); |
maybe_warn("failed to read stdin"); |
out_tot = -1; |
out_tot = -1; |
goto stop; |
goto stop; |
} else if (in_size == 0) |
} else if (in_size == 0) { |
done_reading = 1; |
done_reading = 1; |
|
} |
|
|
z.avail_in = in_size; |
z.avail_in += in_size; |
z.next_in = inbufp; |
needmore = 0; |
|
|
in_tot += in_size; |
in_tot += in_size; |
} |
} |
Line 800 gz_uncompress(int in, int out, char *pre |
|
Line 868 gz_uncompress(int in, int out, char *pre |
|
case GZSTATE_READ: |
case GZSTATE_READ: |
error = inflate(&z, Z_FINISH); |
error = inflate(&z, Z_FINISH); |
/* Z_BUF_ERROR goes with Z_FINISH... */ |
/* Z_BUF_ERROR goes with Z_FINISH... */ |
if (error == Z_STREAM_END || error == Z_BUF_ERROR) { |
if (error != Z_STREAM_END && error != Z_BUF_ERROR) |
ssize_t wr = BUFLEN - z.avail_out; |
/* Just need more input */ |
|
break; |
/* Nothing left? */ |
wr = BUFLEN - z.avail_out; |
if (wr == 0) |
|
goto stop; |
|
|
|
|
if (wr != 0) { |
crc = crc32(crc, (const Bytef *)outbufp, (unsigned)wr); |
crc = crc32(crc, (const Bytef *)outbufp, (unsigned)wr); |
if ( |
if ( |
#ifndef SMALL |
#ifndef SMALL |
Line 821 gz_uncompress(int in, int out, char *pre |
|
Line 888 gz_uncompress(int in, int out, char *pre |
|
|
|
out_tot += wr; |
out_tot += wr; |
out_sub_tot += wr; |
out_sub_tot += wr; |
|
} |
|
|
if (error == Z_STREAM_END) { |
if (error == Z_STREAM_END) { |
inflateEnd(&z); |
inflateEnd(&z); |
state++; |
state++; |
} |
} |
|
|
z.next_out = outbufp; |
z.next_out = outbufp; |
z.avail_out = BUFLEN; |
z.avail_out = BUFLEN; |
|
|
break; |
break; |
} |
|
case GZSTATE_CRC: |
case GZSTATE_CRC: |
{ |
{ |
static int empty_buffer = 0; |
|
uLong origcrc; |
uLong origcrc; |
|
|
if (z.avail_in < 4) { |
if (z.avail_in < 4) { |
if (!done_reading && empty_buffer++ < 4) |
if (!done_reading) { |
|
needmore = 1; |
continue; |
continue; |
|
} |
maybe_warnx("truncated input"); |
maybe_warnx("truncated input"); |
out_tot = -1; |
out_tot = -1; |
goto stop; |
goto stop; |
} |
} |
empty_buffer = 0; |
|
origcrc = ((unsigned)z.next_in[0] & 0xff) | |
origcrc = ((unsigned)z.next_in[0] & 0xff) | |
((unsigned)z.next_in[1] & 0xff) << 8 | |
((unsigned)z.next_in[1] & 0xff) << 8 | |
((unsigned)z.next_in[2] & 0xff) << 16 | |
((unsigned)z.next_in[2] & 0xff) << 16 | |
Line 860 gz_uncompress(int in, int out, char *pre |
|
Line 927 gz_uncompress(int in, int out, char *pre |
|
z.avail_in -= 4; |
z.avail_in -= 4; |
z.next_in += 4; |
z.next_in += 4; |
|
|
if (!z.avail_in) |
if (!z.avail_in && done_reading) { |
goto stop; |
goto stop; |
|
} |
state++; |
state++; |
break; |
break; |
case GZSTATE_LEN: |
case GZSTATE_LEN: |
{ |
{ |
static int empty_buffer = 0; |
|
uLong origlen; |
uLong origlen; |
|
|
if (z.avail_in < 4) { |
if (z.avail_in < 4) { |
if (!done_reading && empty_buffer++ < 4) |
if (!done_reading) { |
|
needmore = 1; |
continue; |
continue; |
|
} |
maybe_warnx("truncated input"); |
maybe_warnx("truncated input"); |
out_tot = -1; |
out_tot = -1; |
goto stop; |
goto stop; |
} |
} |
empty_buffer = 0; |
|
origlen = ((unsigned)z.next_in[0] & 0xff) | |
origlen = ((unsigned)z.next_in[0] & 0xff) | |
((unsigned)z.next_in[1] & 0xff) << 8 | |
((unsigned)z.next_in[1] & 0xff) << 8 | |
((unsigned)z.next_in[2] & 0xff) << 16 | |
((unsigned)z.next_in[2] & 0xff) << 16 | |
Line 951 copymodes(const char *file, struct stat |
|
Line 1019 copymodes(const char *file, struct stat |
|
} |
} |
|
|
/* we only allow set-id and the 9 normal permission bits */ |
/* we only allow set-id and the 9 normal permission bits */ |
sbp->st_mode &= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO; |
sbp->st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; |
if (chmod(file, sbp->st_mode) < 0) |
if (chmod(file, sbp->st_mode) < 0) |
maybe_warn("couldn't chmod: %s", file); |
maybe_warn("couldn't chmod: %s", file); |
|
|
Line 1018 check_outfile(const char *outfile, struc |
|
Line 1086 check_outfile(const char *outfile, struc |
|
return ok; |
return ok; |
} |
} |
|
|
static const char * |
static void |
check_suffix(char *file) |
unlink_input(const char *file, struct stat *sb) |
{ |
{ |
char const **s; |
struct stat nsb; |
size_t slen, len = strlen(file); |
|
|
|
for (s = suffixes; *s; s++) { |
if (stat(file, &nsb) != 0) |
slen = strlen(*s); |
/* 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 it doesn't fit in "a.suf", don't bother */ |
if (slen + 1 > len) |
if (s->ziplen >= len) |
|
continue; |
|
sp = file + len - s->ziplen; |
|
if (strcmp(s->zipped, sp) != 0) |
continue; |
continue; |
if (strcmp(*s, file + len - slen) == 0) |
if (xlate) |
return *s; |
strcpy(sp, s->normal); |
|
return s; |
} |
} |
return NULL; |
return NULL; |
} |
} |
#endif |
|
|
|
/* |
/* |
* compress the given file: create a corresponding .gz file and remove the |
* compress the given file: create a corresponding .gz file and remove the |
Line 1043 check_suffix(char *file) |
|
Line 1129 check_suffix(char *file) |
|
static off_t |
static off_t |
file_compress(char *file, char *outfile, size_t outsize) |
file_compress(char *file, char *outfile, size_t outsize) |
{ |
{ |
FILE *in; |
int in; |
int out; |
int out; |
struct stat isb, osb; |
off_t size, insize; |
off_t size; |
|
#ifndef SMALL |
#ifndef SMALL |
u_int32_t mtime = 0; |
struct stat isb, osb; |
char *savename; |
const suffixes_t *suff; |
#endif |
|
|
|
if (cflag == 0) { |
|
#ifndef SMALL |
|
const char *suff; |
|
|
|
if (fflag == 0 && (suff = check_suffix(file))) { |
|
maybe_warnx("%s already has %s suffix -- unchanged", |
|
file, suff); |
|
goto lose; |
|
} |
|
|
|
#endif |
#endif |
|
|
(void)strncpy(outfile, file, outsize - suffix_len); |
in = open(file, O_RDONLY); |
outfile[outsize - suffix_len] = '\0'; |
if (in == -1) { |
(void)strlcat(outfile, suffix, outsize); |
maybe_warn("can't open %s", file); |
|
return -1; |
|
} |
|
|
|
if (cflag == 0) { |
#ifndef SMALL |
#ifndef SMALL |
if (check_outfile(outfile, &osb) == 0) |
|
goto lose; |
|
|
|
if (stat(file, &isb) == 0) { |
if (stat(file, &isb) == 0) { |
if (isb.st_nlink > 1 && fflag == 0) { |
if (isb.st_nlink > 1 && fflag == 0) { |
maybe_warnx("%s has %d other link%s -- " |
maybe_warnx("%s has %d other link%s -- " |
"skipping", file, isb.st_nlink - 1, |
"skipping", file, isb.st_nlink - 1, |
isb.st_nlink == 1 ? "" : "s"); |
isb.st_nlink == 1 ? "" : "s"); |
goto lose; |
close(in); |
|
return -1; |
} |
} |
if (nflag == 0) |
} |
mtime = (u_int32_t)isb.st_mtime; |
|
|
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 |
#endif |
} |
|
in = fopen(file, "r"); |
/* Add (usually) .gz to filename */ |
if (in == NULL) { |
if (snprintf(outfile, outsize, "%s%s", |
maybe_warn("can't fopen %s", file); |
file, suffixes[0].zipped) >= outsize) |
goto lose; |
memcpy(outfile - suffixes[0].ziplen - 1, |
} |
suffixes[0].zipped, suffixes[0].ziplen + 1); |
|
|
#ifndef SMALL |
#ifndef SMALL |
if (nflag == 0) |
if (check_outfile(outfile, &osb) == 0) { |
savename = basename(file); |
close(in); |
else |
return -1; |
savename = NULL; |
} |
#endif |
#endif |
|
} |
|
|
if (cflag == 0) { |
if (cflag == 0) { |
out = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0600); |
out = open(outfile, O_WRONLY | O_CREAT | O_EXCL, 0600); |
if (out == -1) { |
if (out == -1) { |
maybe_warn("could not create output: %s", outfile); |
maybe_warn("could not create output: %s", outfile); |
goto lose; |
fclose(stdin); |
|
return -1; |
} |
} |
} else |
} else |
out = STDOUT_FILENO; |
out = STDOUT_FILENO; |
|
|
#ifdef SMALL |
insize = gz_compress(in, out, &size, basename(file), (uint32_t)isb.st_mtime); |
gz_compress(in, out, NULL, NULL, 0); |
|
#else |
|
gz_compress(in, out, NULL, savename, mtime); |
|
#endif |
|
|
|
(void)fclose(in); |
(void)close(in); |
|
|
/* |
/* |
* if we compressed to stdout, we don't know the size and |
* If there was an error, insize will be -1. |
* we don't know the new file name, punt. if we can't stat |
* If we compressed to stdout, just return the size. |
* the file, whine, otherwise set the size from the stat |
* Otherwise stat the file and check it is the correct size. |
* buffer. we only blow away the file if we can stat the |
* We only blow away the file if we can stat the output and it |
* output, just in case. |
* has the expected size. |
*/ |
*/ |
if (cflag == 0) { |
if (cflag != 0) |
if (close(out) == -1) |
return insize == -1 ? -1 : size; |
maybe_warn("couldn't close ouput"); |
|
|
if (close(out) == -1) |
|
maybe_warn("couldn't close ouput"); |
|
|
if (stat(outfile, &osb) < 0) { |
|
maybe_warn("couldn't stat: %s", outfile); |
|
maybe_warnx("leaving original %s", file); |
|
size = 0; |
|
} else { |
|
unlink(file); |
|
size = osb.st_size; |
|
} |
|
#ifndef SMALL |
#ifndef SMALL |
copymodes(outfile, &isb); |
if (stat(outfile, &osb) < 0) { |
#endif |
maybe_warn("couldn't stat: %s", outfile); |
} else { |
goto bad_outfile; |
lose: |
} |
size = -1; |
|
|
if (osb.st_size != size) { |
|
maybe_warnx("output file: %s wrong size (%" PRIdOFF |
|
" != %" PRIdOFF "), deleting", |
|
outfile, osb.st_size, size); |
|
goto bad_outfile; |
} |
} |
|
|
return (size); |
copymodes(outfile, &isb); |
|
#endif |
|
|
|
/* output is good, ok to delete input */ |
|
unlink_input(file, &isb); |
|
return size; |
|
|
|
#ifndef SMALL |
|
bad_outfile: |
|
maybe_warnx("leaving original %s", file); |
|
unlink(outfile); |
|
return size; |
|
#endif |
} |
} |
|
|
/* uncompress the given file and remove the original */ |
/* uncompress the given file and remove the original */ |
|
|
file_uncompress(char *file, char *outfile, size_t outsize) |
file_uncompress(char *file, char *outfile, size_t outsize) |
{ |
{ |
struct stat isb, osb; |
struct stat isb, osb; |
char *s; |
|
off_t size; |
off_t size; |
ssize_t rbytes, len = strlen(file); |
ssize_t rbytes; |
unsigned char header1[4], name[PATH_MAX + 1]; |
unsigned char header1[4]; |
enum filetype method; |
enum filetype method; |
int fd, zfd; |
int fd, zfd = -1; |
#ifndef SMALL |
#ifndef SMALL |
time_t timestamp = 0; |
time_t timestamp = 0; |
|
unsigned char name[PATH_MAX + 1]; |
#endif |
#endif |
|
|
/* gather the old name info */ |
/* gather the old name info */ |
Line 1165 file_uncompress(char *file, char *outfil |
|
Line 1255 file_uncompress(char *file, char *outfil |
|
maybe_warn("can't open %s", file); |
maybe_warn("can't open %s", file); |
goto lose; |
goto lose; |
} |
} |
|
|
|
strlcpy(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); |
rbytes = read(fd, header1, sizeof header1); |
if (rbytes != sizeof header1) { |
if (rbytes != sizeof header1) { |
/* we don't want to fail here. */ |
/* we don't want to fail here. */ |
#ifndef SMALL |
#ifndef SMALL |
if (fflag) |
if (fflag) |
goto lose_close_it; |
goto lose; |
#endif |
#endif |
if (rbytes == -1) |
if (rbytes == -1) |
maybe_warn("can't read %s", file); |
maybe_warn("can't read %s", file); |
else |
else |
maybe_warnx("%s: unexpected end of file", file); |
maybe_warnx("%s: unexpected end of file", file); |
goto lose_close_it; |
goto lose; |
} |
} |
|
|
method = file_gettype(header1); |
method = file_gettype(header1); |
|
|
#ifndef SMALL |
#ifndef SMALL |
if (Sflag == NULL) { |
|
# ifndef NO_BZIP2_SUPPORT |
|
if (method == FT_BZIP2) |
|
suffix = BZ2_SUFFIX; |
|
else |
|
# endif |
|
# ifndef NO_COMPRESS_SUPPORT |
|
if (method == FT_Z) |
|
suffix = Z_SUFFIX; |
|
# endif |
|
} |
|
|
|
if (fflag == 0 && method == FT_UNKNOWN) { |
if (fflag == 0 && method == FT_UNKNOWN) { |
maybe_warnx("%s: not in gzip format", file); |
maybe_warnx("%s: not in gzip format", file); |
goto lose_close_it; |
goto lose; |
} |
|
#endif |
|
|
|
if (cflag == 0 || lflag) { |
|
s = 0; |
|
if (len - suffix_len + 1 > 0 && |
|
(s = &file[len - suffix_len + 1]) && |
|
strncmp(s, suffix, suffix_len) == 0) { |
|
(void)strncpy(outfile, file, len - suffix_len + 1); |
|
outfile[len - suffix_len + 1] = '\0'; |
|
} else if (lflag == 0) { |
|
maybe_warnx("%s: unknown suffix -- ignored", file); |
|
goto lose_close_it; |
|
} |
|
} |
} |
|
|
#ifdef SMALL |
|
if (method == FT_GZIP && lflag) |
|
#else |
|
if (method == FT_GZIP && (Nflag || lflag)) |
|
#endif |
#endif |
{ |
|
#ifndef SMALL |
#ifndef SMALL |
unsigned char header2[4]; /* timestamp */ |
if (method == FT_GZIP && Nflag) { |
|
unsigned char ts[4]; /* timestamp */ |
|
|
if (lseek(fd, GZIP_TIMESTAMP, SEEK_SET) == -1) { |
if (pread(fd, ts, sizeof ts, GZIP_TIMESTAMP) != sizeof ts) { |
maybe_warn("can't lseek %s", file); |
if (!fflag) |
goto close_header_read; |
maybe_warn("can't read %s", file); |
} |
goto lose; |
if (read(fd, header2, sizeof header2) != sizeof header2) { |
} |
if (fflag) |
timestamp = ts[3] << 24 | ts[2] << 16 | ts[1] << 8 | ts[0]; |
goto lose_close_it; |
|
maybe_warn("can't read %s", file); |
|
goto lose_close_it; |
|
} |
|
timestamp = ((time_t)header2[3] << 24) |
|
+ ((time_t)header2[2] << 16) |
|
+ ((time_t)header2[1] << 8) |
|
+ (time_t)header2[0]; |
|
#endif |
|
|
|
if (header1[3] & ORIG_NAME) { |
if (header1[3] & ORIG_NAME) { |
int i; |
rbytes = pread(fd, name, sizeof name, GZIP_ORIGNAME); |
|
|
if (lseek(fd, GZIP_ORIGNAME, SEEK_SET) == -1) { |
|
maybe_warn("can't lseek %s", file); |
|
goto close_header_read; |
|
} |
|
rbytes = read(fd, name, PATH_MAX + 1); |
|
if (rbytes < 0) { |
if (rbytes < 0) { |
maybe_warn("can't read %s", file); |
maybe_warn("can't read %s", file); |
goto lose_close_it; |
goto lose; |
} |
} |
for (i = 0; i < rbytes && name[i]; i++) |
if (name[0] != 0) { |
; |
/* preserve original directory name */ |
if (i < rbytes) { |
char *dp = strrchr(file, '/'); |
name[i] = 0; |
if (dp == NULL) |
/* now maybe merge old dirname */ |
dp = file; |
if (strchr(outfile, '/') == NULL) |
else |
(void) strlcpy(outfile, name, outsize); |
dp++; |
else { |
snprintf(outfile, outsize, "%.*s%.*s", |
char newbuf[PATH_MAX + 1]; |
(int) (dp - file), |
|
file, (int) rbytes, name); |
(void) snprintf(newbuf, sizeof(newbuf), |
|
"%s/%s", dirname(outfile), |
|
name); |
|
(void) strlcpy(outfile, newbuf, |
|
outsize); |
|
} |
|
} |
} |
} |
} |
} |
} |
close_header_read: |
#endif |
close(fd); |
lseek(fd, 0, SEEK_SET); |
|
|
if (cflag == 0 || lflag) { |
if (cflag == 0 || lflag) { |
|
if (fstat(fd, &isb) != 0) |
|
goto lose; |
#ifndef SMALL |
#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 (nflag == 0 && timestamp) |
|
isb.st_mtime = timestamp; |
if (check_outfile(outfile, &osb) == 0) |
if (check_outfile(outfile, &osb) == 0) |
goto lose; |
goto lose; |
|
|
#endif |
|
if (stat(file, &isb) == 0) { |
|
#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 (nflag == 0 && timestamp) |
|
isb.st_mtime = timestamp; |
|
#endif |
#endif |
} else |
|
goto lose; |
|
} |
} |
|
|
if (cflag == 0 && lflag == 0) { |
if (cflag == 0 && lflag == 0) { |
zfd = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0600); |
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) { |
if (zfd == -1) { |
maybe_warn("can't open %s", outfile); |
maybe_warn("can't open %s", outfile); |
goto lose; |
goto lose; |
Line 1303 close_header_read: |
|
Line 1351 close_header_read: |
|
|
|
#ifndef NO_BZIP2_SUPPORT |
#ifndef NO_BZIP2_SUPPORT |
if (method == FT_BZIP2) { |
if (method == FT_BZIP2) { |
int in; |
|
|
|
/* XXX */ |
/* XXX */ |
if (lflag) { |
if (lflag) { |
Line 1311 close_header_read: |
|
Line 1358 close_header_read: |
|
goto lose; |
goto lose; |
} |
} |
|
|
if ((in = open(file, O_RDONLY)) == -1) { |
size = unbzip2(fd, zfd, NULL, 0, NULL); |
maybe_warn("open for read: %s", file); |
|
goto lose; |
|
} |
|
|
|
size = unbzip2(in, zfd, NULL, 0, NULL); |
|
if (size == -1) { |
|
if (cflag == 0) |
|
unlink(outfile); |
|
maybe_warnx("%s: uncompress failed", file); |
|
goto lose; |
|
} |
|
if (close(in) != 0) |
|
maybe_warn("couldn't close input"); |
|
if (cflag == 0 && close(zfd) != 0) |
|
maybe_warn("couldn't close output"); |
|
} else |
} else |
#endif |
#endif |
|
|
Line 1340 close_header_read: |
|
Line 1372 close_header_read: |
|
goto lose; |
goto lose; |
} |
} |
|
|
if ((in = zopen(file, NULL)) == NULL) { |
if ((in = zdopen(fd)) == NULL) { |
maybe_warn("open for read: %s", file); |
maybe_warn("zdopen for read: %s", file); |
goto lose; |
goto lose; |
} |
} |
|
|
out = fdopen(zfd, "w"); |
out = fdopen(dup(zfd), "w"); |
if (out == NULL) { |
if (out == NULL) { |
maybe_warn("open for write: %s", outfile); |
maybe_warn("fdopen for write: %s", outfile); |
|
fclose(in); |
goto lose; |
goto lose; |
} |
} |
|
|
size = zuncompress(in, out, NULL, 0, NULL); |
size = zuncompress(in, out, NULL, 0, NULL); |
if (ferror(in) || fclose(in) != 0) { |
/* need to fclose() if ferror() is true... */ |
|
if (ferror(in) | fclose(in)) { |
|
maybe_warn("failed infile fclose"); |
unlink(outfile); |
unlink(outfile); |
(void)fclose(out); |
(void)fclose(out); |
maybe_warn("failed infile fclose"); |
|
} |
} |
if (cflag == 0) { |
if (fclose(out) != 0) { |
if (size == -1) { |
maybe_warn("failed outfile fclose"); |
maybe_warnx("%s: uncompress failed", file); |
unlink(outfile); |
(void)fclose(out); |
goto lose; |
unlink(outfile); |
|
goto lose; |
|
} |
|
if (fclose(out) != 0) { |
|
unlink(outfile); |
|
maybe_warn("failed outfile close"); |
|
goto lose; |
|
} |
|
} |
} |
} else |
} else |
#endif |
#endif |
|
|
#ifndef SMALL |
#ifndef SMALL |
if (method == FT_UNKNOWN) { |
if (method == FT_UNKNOWN) { |
int in; |
if (lflag) { |
|
maybe_warnx("no -l for unknown filetypes"); |
in = open(file, O_RDONLY); |
|
if (in == -1) { |
|
maybe_warn("can't open %s", file); |
|
goto lose; |
goto lose; |
} |
} |
size = cat_fd(NULL, 0, NULL, in); |
size = cat_fd(NULL, 0, NULL, fd); |
} else |
} else |
#endif |
#endif |
{ |
{ |
int in; |
|
|
|
if (lflag) { |
if (lflag) { |
if ((zfd = open(file, O_RDONLY)) == -1) { |
print_list(fd, isb.st_size, outfile, isb.st_mtime); |
maybe_warn("open: %s", file); |
close(fd); |
goto lose; |
|
} |
|
print_list(zfd, isb.st_size, outfile, isb.st_mtime); |
|
return -1; /* XXX */ |
return -1; /* XXX */ |
} |
} |
|
|
in = open(file, O_RDONLY); |
size = gz_uncompress(fd, zfd, NULL, 0, NULL, file); |
if (in == -1) { |
} |
maybe_warn("can't open %s", file); |
|
goto lose; |
|
} |
|
|
|
size = gz_uncompress(in, zfd, NULL, 0, NULL, file); |
if (close(fd) != 0) |
(void)close(in); |
maybe_warn("couldn't close input"); |
if (cflag == 0) { |
if (zfd != STDOUT_FILENO && close(zfd) != 0) |
if (close(zfd)) |
maybe_warn("couldn't close output"); |
maybe_warn("failed close"); |
|
if (size == -1) { |
if (size == -1) { |
maybe_warnx("%s: uncompress failed", file); |
if (cflag == 0) |
unlink(outfile); |
unlink(outfile); |
goto lose; |
maybe_warnx("%s: uncompress failed", file); |
} |
return -1; |
} |
|
} |
} |
|
|
/* if testing, or we uncompressed to stdout, this is all we need */ |
/* if testing, or we uncompressed to stdout, this is all we need */ |
#ifndef SMALL |
#ifndef SMALL |
if (tflag) |
if (tflag) |
return (size); |
return size; |
#endif |
#endif |
/* if we are uncompressing to stdin, don't remove the file. */ |
/* if we are uncompressing to stdin, don't remove the file. */ |
if (cflag) |
if (cflag) |
return (size); |
return size; |
|
|
/* |
/* |
* if we create a file... |
* if we create a file... |
*/ |
*/ |
if (cflag == 0) { |
/* |
/* |
* if we can't stat the file don't remove the file. |
* if we can't stat the file don't remove the file. |
*/ |
*/ |
if (stat(outfile, &osb) < 0) { |
if (stat(outfile, &osb) < 0) { |
maybe_warn("couldn't stat (leaving original): %s", |
maybe_warn("couldn't stat (leaving original): %s", |
outfile); |
outfile); |
return -1; |
goto lose; |
} |
} |
if (osb.st_size != size) { |
if (osb.st_size != size) { |
maybe_warn("stat gave different size: %" PRIdOFF |
maybe_warn("stat gave different size: %llu != %llu " |
" != %" PRIdOFF " (leaving original)", |
"(leaving original)", |
size, osb.st_size); |
(unsigned long long)size, |
unlink(outfile); |
(unsigned long long)osb.st_size); |
return -1; |
goto lose; |
} |
} |
unlink_input(file, &isb); |
if (cflag == 0) |
|
unlink(file); |
|
size = osb.st_size; |
|
#ifndef SMALL |
#ifndef SMALL |
copymodes(outfile, &isb); |
copymodes(outfile, &isb); |
#endif |
#endif |
} |
return size; |
return (size); |
|
|
|
lose_close_it: |
lose: |
close(fd); |
if (fd != -1) |
lose: |
close(fd); |
|
if (zfd != -1 && zfd != STDOUT_FILENO) |
|
close(fd); |
return -1; |
return -1; |
} |
} |
|
|
Line 1500 handle_stdin(void) |
|
Line 1512 handle_stdin(void) |
|
unsigned char header1[4]; |
unsigned char header1[4]; |
off_t usize, gsize; |
off_t usize, gsize; |
enum filetype method; |
enum filetype method; |
|
ssize_t bytes_read; |
#ifndef NO_COMPRESS_SUPPORT |
#ifndef NO_COMPRESS_SUPPORT |
FILE *in; |
FILE *in; |
#endif |
#endif |
Line 1523 handle_stdin(void) |
|
Line 1536 handle_stdin(void) |
|
return; |
return; |
} |
} |
|
|
if (read(STDIN_FILENO, header1, sizeof header1) != sizeof header1) { |
bytes_read = read_retry(STDIN_FILENO, header1, sizeof header1); |
|
if (bytes_read == -1) { |
maybe_warn("can't read stdin"); |
maybe_warn("can't read stdin"); |
return; |
return; |
|
} else if (bytes_read != sizeof(header1)) { |
|
maybe_warnx("unexpected EOF"); |
|
return; |
} |
} |
|
|
method = file_gettype(header1); |
method = file_gettype(header1); |
Line 1551 handle_stdin(void) |
|
Line 1568 handle_stdin(void) |
|
#endif |
#endif |
#ifndef NO_COMPRESS_SUPPORT |
#ifndef NO_COMPRESS_SUPPORT |
case FT_Z: |
case FT_Z: |
if ((in = zopen(NULL, stdin)) == NULL) { |
if ((in = zdopen(STDIN_FILENO)) == NULL) { |
maybe_warnx("zopen of stdin"); |
maybe_warnx("zopen of stdin"); |
return; |
return; |
} |
} |
|
|
usize = zuncompress(in, stdout, header1, sizeof header1, &gsize); |
usize = zuncompress(in, stdout, header1, sizeof header1, &gsize); |
|
fclose(in); |
break; |
break; |
#endif |
#endif |
} |
} |
|
|
#ifndef SMALL |
#ifndef SMALL |
if (vflag && !tflag && usize != -1 && gsize != -1) |
if (vflag && !tflag && usize != -1 && gsize != -1) |
print_verbage(NULL, 0, usize, gsize); |
print_verbage(NULL, NULL, usize, gsize); |
#endif |
#endif |
|
|
} |
} |
Line 1605 handle_stdout(void) |
|
Line 1623 handle_stdout(void) |
|
#endif |
#endif |
mtime = (uint32_t)systime; |
mtime = (uint32_t)systime; |
} |
} |
|
|
usize = gz_compress(stdin, STDOUT_FILENO, &gsize, NULL, mtime); |
usize = gz_compress(STDIN_FILENO, STDOUT_FILENO, &gsize, "", mtime); |
#ifndef SMALL |
#ifndef SMALL |
if (vflag && !tflag && usize != -1 && gsize != -1) |
if (vflag && !tflag && usize != -1 && gsize != -1) |
print_verbage(NULL, 0, usize, gsize); |
print_verbage(NULL, NULL, usize, gsize); |
#endif |
#endif |
} |
} |
|
|
Line 1619 handle_pathname(char *path) |
|
Line 1637 handle_pathname(char *path) |
|
{ |
{ |
char *opath = path, *s = NULL; |
char *opath = path, *s = NULL; |
ssize_t len; |
ssize_t len; |
|
int slen; |
struct stat sb; |
struct stat sb; |
|
|
/* check for stdout/stdin */ |
/* check for stdout/stdin */ |
|
|
/* lets try <path>.gz if we're decompressing */ |
/* lets try <path>.gz if we're decompressing */ |
if (dflag && s == NULL && errno == ENOENT) { |
if (dflag && s == NULL && errno == ENOENT) { |
len = strlen(path); |
len = strlen(path); |
s = malloc(len + suffix_len + 1); |
slen = suffixes[0].ziplen; |
|
s = malloc(len + slen + 1); |
if (s == NULL) |
if (s == NULL) |
maybe_err("malloc"); |
maybe_err("malloc"); |
memmove(s, path, len); |
memcpy(s, path, len); |
memmove(&s[len], suffix, suffix_len); |
memcpy(s + len, suffixes[0].zipped, slen + 1); |
s[len + suffix_len] = 0x0; |
|
path = s; |
path = s; |
goto retry; |
goto retry; |
} |
} |
|
|
|
|
if (S_ISREG(sb.st_mode)) |
if (S_ISREG(sb.st_mode)) |
handle_file(path, &sb); |
handle_file(path, &sb); |
|
else |
|
maybe_warnx("%s is not a regular file", path); |
|
|
out: |
out: |
if (s) |
if (s) |
Line 1694 handle_file(char *file, struct stat *sbp |
|
Line 1715 handle_file(char *file, struct stat *sbp |
|
} |
} |
|
|
#ifndef SMALL |
#ifndef SMALL |
/* this is used with -r to recursively decend directories */ |
/* this is used with -r to recursively descend directories */ |
static void |
static void |
handle_dir(char *dir, struct stat *sbp) |
handle_dir(char *dir, struct stat *sbp) |
{ |
{ |
Line 1729 handle_dir(char *dir, struct stat *sbp) |
|
Line 1750 handle_dir(char *dir, struct stat *sbp) |
|
} |
} |
#endif |
#endif |
|
|
/* print a ratio */ |
/* print a ratio - size reduction as a fraction of uncompressed size */ |
static void |
static void |
print_ratio(off_t in, off_t out, FILE *where) |
print_ratio(off_t in, off_t out, FILE *where) |
{ |
{ |
int64_t percent10; /* 10 * percent */ |
int percent10; /* 10 * percent */ |
off_t diff = in - out; |
off_t diff; |
char ch; |
char buff[8]; |
|
int len; |
if (in == 0) |
|
percent10 = 0; |
|
else if (diff > 0x400000) /* anything with 22 or more bits */ |
|
percent10 = diff / (in / 1000); |
|
else |
|
percent10 = (1000 * diff) / in; |
|
|
|
if (percent10 < 0) { |
diff = in - out/2; |
percent10 = -percent10; |
if (diff <= 0) |
ch = '-'; |
/* |
} else |
* Output is more than double size of input! print -99.9% |
ch = ' '; |
* 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); |
* ugh. for negative percentages < 10, we need to avoid printing a |
/* Move the '.' to before the last digit */ |
* a space between the "-" and the single number. |
buff[len - 1] = buff[len - 2]; |
*/ |
buff[len - 2] = '.'; |
if (ch == '-' && percent10 / 10LL < 10) |
fprintf(where, "%5s%%", buff); |
fprintf(where, " -%1d.%1u%%", (unsigned)(percent10 / 10LL), |
|
(unsigned)(percent10 % 10LL)); |
|
else |
|
fprintf(where, "%c%2d.%1u%%", ch, (unsigned)(percent10 / 10LL), |
|
(unsigned)(percent10 % 10LL)); |
|
} |
} |
|
|
#ifndef SMALL |
#ifndef SMALL |
/* print compression statistics, and the new name (if there is one!) */ |
/* print compression statistics, and the new name (if there is one!) */ |
static void |
static void |
print_verbage(char *file, char *nfile, off_t usize, off_t gsize) |
print_verbage(const char *file, const char *nfile, off_t usize, off_t gsize) |
{ |
{ |
if (file) |
if (file) |
fprintf(stderr, "%s:%s ", file, |
fprintf(stderr, "%s:%s ", file, |
strlen(file) < 7 ? "\t\t" : "\t"); |
strlen(file) < 7 ? "\t\t" : "\t"); |
print_ratio((off_t)usize, (off_t)gsize, stderr); |
print_ratio(usize, gsize, stderr); |
if (nfile) |
if (nfile) |
fprintf(stderr, " -- replaced with %s", nfile); |
fprintf(stderr, " -- replaced with %s", nfile); |
fprintf(stderr, "\n"); |
fprintf(stderr, "\n"); |
Line 1801 print_list(int fd, off_t out, const char |
|
Line 1827 print_list(int fd, off_t out, const char |
|
static int first = 1; |
static int first = 1; |
#ifndef SMALL |
#ifndef SMALL |
static off_t in_tot, out_tot; |
static off_t in_tot, out_tot; |
u_int32_t crc; |
uint32_t crc = 0; |
#endif |
#endif |
off_t in; |
off_t in = 0; |
int rv; |
int rv; |
|
|
if (first) { |
if (first) { |
Line 1829 print_list(int fd, off_t out, const char |
|
Line 1855 print_list(int fd, off_t out, const char |
|
rv = lseek(fd, (off_t)(-8), SEEK_END); |
rv = lseek(fd, (off_t)(-8), SEEK_END); |
if (rv != -1) { |
if (rv != -1) { |
unsigned char buf[8]; |
unsigned char buf[8]; |
u_int32_t usize; |
uint32_t usize; |
|
|
if (read(fd, (char *)buf, sizeof(buf)) != sizeof(buf)) |
if (read(fd, (char *)buf, sizeof(buf)) != sizeof(buf)) |
maybe_warn("read of uncompressed size"); |
maybe_warn("read of uncompressed size"); |
Line 1909 display_version(void) |
|
Line 1935 display_version(void) |
|
#ifndef NO_COMPRESS_SUPPORT |
#ifndef NO_COMPRESS_SUPPORT |
#include "zuncompress.c" |
#include "zuncompress.c" |
#endif |
#endif |
|
|
|
static ssize_t |
|
read_retry(int fd, void *buf, size_t sz) |
|
{ |
|
char *cp = buf; |
|
ssize_t left = sz; |
|
|
|
while (left > 0) { |
|
ssize_t ret; |
|
|
|
ret = read(fd, cp, sz); |
|
if (ret == -1) { |
|
return ret; |
|
} else if (ret == 0) { |
|
break; /* EOF */ |
|
} |
|
cp += ret; |
|
left -= ret; |
|
} |
|
|
|
return sz - left; |
|
} |