summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2003-07-17 20:06:02 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2003-07-17 20:06:02 +0000
commite110a89f4d58a06bc42084df1a402f1c843e8867 (patch)
treeca73962090982d16fbcd1889f04d481564c71bf4
parenta35fbb20dadabd0766b4f955207bd886c40dc456 (diff)
o implement -l, -n and -N (including setting outfile + mtime)
o make -v behave like GNU gzip for compress/decompress stats o write a full gzip header w/ mtime and file name o for -t/-l just don't write data instead of writing to /dev/null o exit code is now more consistent with GNU gzip o a crc error on decompress no longer causes unlink(outfile) mickey@ OK
-rw-r--r--usr.bin/compress/compress.157
-rw-r--r--usr.bin/compress/compress.h33
-rw-r--r--usr.bin/compress/gzopen.c125
-rw-r--r--usr.bin/compress/main.c266
-rw-r--r--usr.bin/compress/zopen.c37
5 files changed, 380 insertions, 138 deletions
diff --git a/usr.bin/compress/compress.1 b/usr.bin/compress/compress.1
index 876883feabc..7b7127db825 100644
--- a/usr.bin/compress/compress.1
+++ b/usr.bin/compress/compress.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: compress.1,v 1.20 2003/06/30 03:42:05 millert Exp $
+.\" $OpenBSD: compress.1,v 1.21 2003/07/17 20:06:01 millert Exp $
.\" $NetBSD: compress.1,v 1.5 1995/03/26 09:44:34 glass Exp $
.\"
.\" Copyright (c) 1986, 1990, 1993
@@ -47,26 +47,26 @@
.Nm compress
.Op Fl LV
.Nm compress
-.Op Fl cdfghOqrtv123456789
+.Op Fl cdfghlOnNqrtv123456789
.Op Fl b Ar bits
.Op Fl S Ar suffix
.Op Fl o Ar filename
.Op Ar
.Nm uncompress
-.Op Fl cfhqrtv
+.Op Fl cfhlnNqrtv
.Op Fl o Ar filename
.Op Ar
.Pp
.Nm gzip
.Op Fl LV
.Nm gzip
-.Op Fl cdfghOqrtv123456789
+.Op Fl cdfghlnNOqrtv123456789
.Op Fl b Ar bits
.Op Fl S Ar suffix
.Op Fl o Ar filename
.Op Ar
.Nm gunzip
-.Op Fl cfhqrtv
+.Op Fl cfhnNqrltv
.Op Fl o Ar filename
.Op Ar
.Pp
@@ -165,6 +165,53 @@ This flag need not be specified when invoked as
.Nm gzip .
.It Fl h
Print a short help message.
+.It Fl l
+List information for the specified compressed files.
+The following information is listed:
+.Bl -tag -width Ds -offset indent
+.It compressed size
+size of the compressed file
+.It uncompressed size
+size of the file when uncompressed
+.It compression ratio
+ratio of the difference between the compressed and uncompressed
+sizes to the uncompressed size.
+.It uncompressed name
+name the file will be saved as when uncompressing
+.El
+.Pp
+If the
+.Fl v
+option is specified, the following additional information is printed:
+.Bl -tag -width Ds -offset indent
+.It compression method
+name of the method used to compress the file
+.It crc
+32-bit crc of the uncompressed file
+.It "time stamp"
+date and time corresponding to the last data modification time
+(mtime) of the compressed file (if the
+.Fl n
+option is specified, the time stamp stored in the compressed file
+is printed instead).
+.El
+.It Fl n
+When compressing, do not save the original file name and time stamp.
+This information is saved by default when the deflate scheme is used.
+When uncompressing, do not restore the original file name and time stamp.
+By default, the uncompressed file inherits the time stamp of the
+compressed version and the uncompressed file name is generated by
+stripping the
+.Dq Z
+or
+.Dq gz
+extension from the compressed file name.
+.It Fl N
+When compressing, save the original file name and time stamp in the
+compressed file.
+This information is saved by default when the deflate scheme is used.
+When uncompressing or listing, use the time stamp and file name stored
+in the compressed file, if any, for the uncompressed version.
.It Fl 1...9
Use deflate scheme with compression factor of
.Fl 1
diff --git a/usr.bin/compress/compress.h b/usr.bin/compress/compress.h
index b9ce25d7ca2..22671b6b436 100644
--- a/usr.bin/compress/compress.h
+++ b/usr.bin/compress/compress.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: compress.h,v 1.5 2003/07/11 02:31:18 millert Exp $ */
+/* $OpenBSD: compress.h,v 1.6 2003/07/17 20:06:01 millert Exp $ */
/*
* Copyright (c) 1997 Michael Shalayeff
@@ -27,32 +27,45 @@
*
*/
+struct z_info {
+ u_int32_t mtime; /* timestamp */
+ u_int32_t crc; /* crc */
+ u_int32_t hlen; /* header length */
+ u_int64_t total_in; /* # bytes in */
+ u_int64_t total_out; /* # bytes out */
+};
+
/*
* making it any bigger does not affect perfomance very much.
* actually this value is just a little bit better than 8192.
*/
#define Z_BUFSIZE 16384
+/*
+ * exit codes for compress
+ */
+#define SUCCESS 0
+#define FAILURE 1
+#define WARNING 2
+
extern const char main_rcsid[], z_rcsid[], gz_rcsid[], pkzip_rcsid[],
pack_rcsid[], lzh_rcsid[];
-extern int z_check_header(int, struct stat *, const char *);
-extern void *z_open(int, const char *, int, int);
+extern void *z_open(int, const char *, char *, int, u_int32_t, int);
extern FILE *zopen(const char *, const char *,int);
extern int zread(void *, char *, int);
extern int zwrite(void *, const char *, int);
-extern int zclose(void *);
+extern int z_close(void *, struct z_info *);
+
-extern int gz_check_header(int, struct stat *, const char *);
-extern void *gz_open(int, const char *, int, int);
+extern void *gz_open(int, const char *, char *, int, u_int32_t, int);
extern int gz_read(void *, char *, int);
extern int gz_write(void *, const char *, int);
-extern int gz_close(void *);
+extern int gz_close(void *, struct z_info *);
extern int gz_flush(void *, int);
-extern int lzh_check_header(int, struct stat *, const char *);
-extern void *lzh_open(int, const char *, int, int);
+extern void *lzh_open(int, const char *, char *, int, u_int32_t, int);
extern int lzh_read(void *, char *, int);
extern int lzh_write(void *, const char *, int);
-extern int lzh_close(void *);
+extern int lzh_close(void *, struct z_info *);
extern int lzh_flush(void *, int);
diff --git a/usr.bin/compress/gzopen.c b/usr.bin/compress/gzopen.c
index c7c9e203ad3..d9885fc9205 100644
--- a/usr.bin/compress/gzopen.c
+++ b/usr.bin/compress/gzopen.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: gzopen.c,v 1.12 2003/07/11 02:31:18 millert Exp $ */
+/* $OpenBSD: gzopen.c,v 1.13 2003/07/17 20:06:01 millert Exp $ */
/*
* Copyright (c) 1997 Michael Shalayeff
@@ -59,10 +59,11 @@
*/
const char gz_rcsid[] =
- "$OpenBSD: gzopen.c,v 1.12 2003/07/11 02:31:18 millert Exp $";
+ "$OpenBSD: gzopen.c,v 1.13 2003/07/17 20:06:01 millert Exp $";
-#include <sys/types.h>
+#include <sys/param.h>
#include <sys/stat.h>
+#include <sys/uio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -88,6 +89,8 @@ struct gz_stream {
z_stream z_stream; /* libz stream */
int z_eof; /* set if end of input file */
u_char z_buf[Z_BUFSIZE]; /* i/o buffer */
+ u_int32_t z_time; /* timestamp (mtime) */
+ u_int32_t z_hlen; /* length of the gz header */
u_int32_t z_crc; /* crc32 of uncompressed data */
char z_mode; /* 'w' or 'r' */
@@ -97,11 +100,13 @@ static const u_char gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
static int put_int32(gz_stream *, u_int32_t);
static u_int32_t get_int32(gz_stream *);
-static int get_header(gz_stream *, int);
+static int get_header(gz_stream *, char *, int);
+static int put_header(gz_stream *, char *, u_int32_t);
static int get_byte(gz_stream *);
void *
-gz_open(int fd, const char *mode, int bits, int gotmagic)
+gz_open(int fd, const char *mode, char *name, int bits,
+ u_int32_t mtime, int gotmagic)
{
gz_stream *s;
@@ -124,6 +129,8 @@ gz_open(int fd, const char *mode, int bits, int gotmagic)
s->z_stream.avail_in = s->z_stream.avail_out = 0;
s->z_fd = 0;
s->z_eof = 0;
+ s->z_time = 0;
+ s->z_hlen = 0;
s->z_crc = crc32(0L, Z_NULL, 0);
s->z_mode = mode[0];
@@ -148,22 +155,15 @@ gz_open(int fd, const char *mode, int bits, int gotmagic)
s->z_fd = fd;
if (s->z_mode == 'w') {
- u_char buf[10];
- /* Write a very simple .gz header: */
- buf[0] = gz_magic[0];
- buf[1] = gz_magic[1];
- buf[2] = Z_DEFLATED;
- buf[3] = 0 /*flags*/;
- buf[4] = buf[5] = buf[6] = buf[7] = 0 /*time*/;
- buf[8] = 0 /*xflags*/;
- buf[9] = OS_CODE;
- if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
- gz_close(s);
+ /* write the .gz header */
+ if (put_header(s, name, mtime) != 0) {
+ gz_close(s, NULL);
s = NULL;
}
} else {
- if (get_header(s, gotmagic) != 0) { /* skip the .gz header */
- gz_close (s);
+ /* read the .gz header */
+ if (get_header(s, name, gotmagic) != 0) {
+ gz_close(s, NULL);
s = NULL;
}
}
@@ -172,7 +172,7 @@ gz_open(int fd, const char *mode, int bits, int gotmagic)
}
int
-gz_close(void *cookie)
+gz_close(void *cookie, struct z_info *info)
{
gz_stream *s = (gz_stream*)cookie;
int err = 0;
@@ -181,8 +181,11 @@ gz_close(void *cookie)
return -1;
if (s->z_mode == 'w' && (err = gz_flush (s, Z_FINISH)) == Z_OK) {
- if ((err = put_int32 (s, s->z_crc)) == Z_OK)
- err = put_int32 (s, s->z_stream.total_in);
+ if ((err = put_int32 (s, s->z_crc)) == Z_OK) {
+ s->z_hlen += sizeof(int32_t);
+ if ((err = put_int32 (s, s->z_stream.total_in)) == Z_OK)
+ s->z_hlen += sizeof(int32_t);
+ }
}
if (!err && s->z_stream.state != NULL) {
@@ -192,6 +195,14 @@ gz_close(void *cookie)
err = inflateEnd(&s->z_stream);
}
+ if (info != NULL) {
+ info->mtime = s->z_time;
+ info->crc = s->z_crc;
+ info->hlen = s->z_hlen;
+ info->total_in = (off_t)s->z_stream.total_in;
+ info->total_out = (off_t)s->z_stream.total_out;
+ }
+
if (!err)
err = close(s->z_fd);
else
@@ -282,10 +293,11 @@ get_int32(gz_stream *s)
}
static int
-get_header(gz_stream *s, int gotmagic)
+get_header(gz_stream *s, char *name, int gotmagic)
{
int method; /* method byte */
int flags; /* flags byte */
+ char *ep;
uInt len;
int c;
@@ -307,28 +319,49 @@ get_header(gz_stream *s, int gotmagic)
return -1;
}
- /* Discard time, xflags and OS code: */
- for (len = 0; len < 6; len++)
- (void)get_byte(s);
+ /* Stash timestamp (mtime) */
+ s->z_time = get_int32(s);
+
+ /* Discard xflags and OS code */
+ (void)get_byte(s);
+ (void)get_byte(s);
+ s->z_hlen = 10; /* magic, method, flags, time, xflags, OS code */
if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
len = (uInt)get_byte(s);
len += ((uInt)get_byte(s))<<8;
+ s->z_hlen += 2;
/* len is garbage if EOF but the loop below will quit anyway */
while (len-- != 0 && get_byte(s) != EOF)
- ;
+ s->z_hlen++;
}
- if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
- while ((c = get_byte(s)) != 0 && c != EOF) ;
+ if ((flags & ORIG_NAME) != 0) { /* read/save the original file name */
+ if ((ep = name) != NULL)
+ ep += MAXPATHLEN - 1;
+ while ((c = get_byte(s)) != EOF) {
+ s->z_hlen++;
+ if (c == '\0')
+ break;
+ if (name < ep)
+ *name++ = c;
+ }
+ if (name != NULL)
+ *name = '\0';
}
if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
- while ((c = get_byte(s)) != 0 && c != EOF) ;
+ while ((c = get_byte(s)) != EOF) {
+ s->z_hlen++;
+ if (c == '\0')
+ break;
+ }
}
if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
- for (len = 0; len < 2; len++) (void)get_byte(s);
+ for (len = 0; len < 2; len++)
+ (void)get_byte(s);
+ s->z_hlen += 2;
}
if (s->z_eof) {
@@ -339,6 +372,36 @@ get_header(gz_stream *s, int gotmagic)
return 0;
}
+static int
+put_header(gz_stream *s, char *name, u_int32_t mtime)
+{
+ struct iovec iov[2];
+ u_char buf[10];
+
+ buf[0] = gz_magic[0];
+ buf[1] = gz_magic[1];
+ buf[2] = Z_DEFLATED;
+ buf[3] = name ? ORIG_NAME : 0;
+ buf[4] = mtime & 0xff;
+ buf[5] = (mtime >> 8) & 0xff;
+ buf[6] = (mtime >> 16) & 0xff;
+ buf[7] = (mtime >> 24) & 0xff;
+ buf[8] = 0 /* xflags */;
+ buf[9] = OS_CODE;
+ iov[0].iov_base = buf;
+ iov[0].iov_len = sizeof(buf);
+ s->z_hlen = sizeof(buf);
+
+ if (name != NULL) {
+ iov[1].iov_base = name;
+ iov[1].iov_len = strlen(name) + 1;
+ s->z_hlen += iov[1].iov_len;
+ }
+ if (writev(s->z_fd, iov, name ? 2 : 1) == -1)
+ return (-1);
+ return (0);
+}
+
int
gz_read(void *cookie, char *buf, int len)
{
@@ -373,6 +436,7 @@ gz_read(void *cookie, char *buf, int len)
errno = EIO;
return -1;
}
+ s->z_hlen += 2 * sizeof(int32_t);
s->z_eof = 1;
break;
}
@@ -405,4 +469,3 @@ gz_write(void *cookie, const char *buf, int len)
return (int)(len - s->z_stream.avail_in);
}
-
diff --git a/usr.bin/compress/main.c b/usr.bin/compress/main.c
index 445ad8c0779..94208b39b97 100644
--- a/usr.bin/compress/main.c
+++ b/usr.bin/compress/main.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: main.c,v 1.36 2003/07/15 19:01:46 millert Exp $ */
+/* $OpenBSD: main.c,v 1.37 2003/07/17 20:06:01 millert Exp $ */
static const char copyright[] =
"@(#) Copyright (c) 1992, 1993\n\
@@ -35,7 +35,7 @@ static const char license[] =
#if 0
static char sccsid[] = "@(#)compress.c 8.2 (Berkeley) 1/7/94";
#else
-static const char main_rcsid[] = "$OpenBSD: main.c,v 1.36 2003/07/15 19:01:46 millert Exp $";
+static const char main_rcsid[] = "$OpenBSD: main.c,v 1.37 2003/07/17 20:06:01 millert Exp $";
#endif
#endif /* not lint */
@@ -47,6 +47,7 @@ static const char main_rcsid[] = "$OpenBSD: main.c,v 1.36 2003/07/15 19:01:46 mi
#include <err.h>
#include <errno.h>
#include <fts.h>
+#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -59,20 +60,20 @@ static const char main_rcsid[] = "$OpenBSD: main.c,v 1.36 2003/07/15 19:01:46 mi
int pipin, force, verbose, testmode, list, nosave;
int savename, recurse;
-int bits, cat, decomp;
+int cat, decomp;
extern char *__progname;
const struct compressor {
char *name;
char *suffix;
u_char *magic;
- void *(*open)(int, const char *, int, int);
+ void *(*open)(int, const char *, char *, int, u_int32_t, int);
int (*read)(void *, char *, int);
int (*write)(void *, const char *, int);
- int (*close)(void *);
+ int (*close)(void *, struct z_info *);
} c_table[] = {
#define M_COMPRESS (&c_table[0])
- { "compress", ".Z", "\037\235", z_open, zread, zwrite, zclose },
+ { "compress", ".Z", "\037\235", z_open, zread, zwrite, z_close },
#define M_DEFLATE (&c_table[1])
{ "deflate", ".gz", "\037\213", gz_open, gz_read, gz_write, gz_close },
#if 0
@@ -89,13 +90,15 @@ const struct compressor {
int permission(const char *);
void setfile(const char *, struct stat *);
__dead void usage(int);
-int compress(const char *, const char *, const struct compressor *,
+int compress(const char *, char *, const struct compressor *,
int, struct stat *);
-int decompress(const char *, const char *, const struct compressor *,
+int decompress(const char *, char *, const struct compressor *,
int, struct stat *);
-const struct compressor *check_method(int, struct stat *, const char *);
+const struct compressor *check_method(int);
const char *check_suffix(const char *);
char *set_outfile(const char *, char *, size_t);
+void list_stats(const char *, const struct compressor *, struct z_info *);
+void verbose_info(const char *, off_t, off_t, u_int32_t);
#define OPTSTRING "123456789ab:cdfghlLnNOo:qrS:tvV"
const struct option longopts[] = {
@@ -132,7 +135,7 @@ main(int argc, char *argv[])
char *p, *infile;
char outfile[MAXPATHLEN], _infile[MAXPATHLEN], suffix[16];
char *nargv[512]; /* some estimate based on ARG_MAX */
- int exists, oreg, ch, error, i, rc, oflag;
+ int bits, exists, oreg, ch, error, i, rc, oflag;
bits = cat = oflag = decomp = 0;
p = __progname;
@@ -222,12 +225,14 @@ main(int argc, char *argv[])
break;
case 'l':
list++;
+ testmode++;
+ decomp++;
break;
case 'n':
- nosave++;
+ nosave = 1;
break;
case 'N':
- nosave = 0; /* XXX not yet */
+ nosave = -1;
break;
case 'O':
method = M_COMPRESS;
@@ -302,8 +307,7 @@ main(int argc, char *argv[])
if ((ftsp = fts_open(argv, FTS_PHYSICAL|FTS_NOCHDIR, 0)) == NULL)
err(1, NULL);
- /* XXX - set rc in cases where we "continue" below? */
- for (rc = 0; (entry = fts_read(ftsp)) != NULL;) {
+ for (rc = SUCCESS; (entry = fts_read(ftsp)) != NULL;) {
infile = entry->fts_path;
switch (entry->fts_info) {
case FTS_D:
@@ -333,12 +337,13 @@ main(int argc, char *argv[])
case FTS_ERR:
case FTS_DNR:
warnx("%s: %s", infile, strerror(entry->fts_errno));
- error = 1;
+ rc = rc ? rc : WARNING;
continue;
default:
if (!S_ISREG(entry->fts_statp->st_mode) && !pipin) {
warnx("%s not a regular file%s",
infile, cat ? "" : ": unchanged");
+ rc = rc ? rc : WARNING;
continue;
}
break;
@@ -347,12 +352,11 @@ main(int argc, char *argv[])
if (!decomp && !pipin && (s = check_suffix(infile)) != NULL) {
warnx("%s already has %s suffix -- unchanged",
infile, s);
+ rc = rc ? rc : WARNING;
continue;
}
- if (testmode)
- strlcpy(outfile, _PATH_DEVNULL, sizeof outfile);
- else if (cat)
+ if (cat)
strlcpy(outfile, "/dev/stdout", sizeof outfile);
else if (!oflag) {
if (decomp) {
@@ -375,82 +379,77 @@ main(int argc, char *argv[])
exists = !stat(outfile, &osb);
if (!force && exists && S_ISREG(osb.st_mode) &&
- !permission(outfile))
+ !permission(outfile)) {
+ rc = rc ? rc : WARNING;
continue;
+ }
oreg = !exists || S_ISREG(osb.st_mode);
- if (verbose > 0)
+ if (verbose > 0 && !pipin && !list)
fprintf(stderr, "%s:\t", infile);
error = (decomp ? decompress : compress)
(infile, outfile, method, bits, entry->fts_statp);
- if (!error && !cat && !testmode && stat(outfile, &osb) == 0) {
- if (!force && !decomp &&
- osb.st_size >= entry->fts_statp->st_size) {
- if (verbose > 0)
- fprintf(stderr, "file would grow; "
- "left unmodified\n");
- error = 1;
- rc = rc ? rc : 2;
- } else {
+ switch (error) {
+ case SUCCESS:
+ if (!cat && !testmode) {
setfile(outfile, entry->fts_statp);
-
- if (unlink(infile) && verbose >= 0)
+ if (!pipin && unlink(infile) && verbose >= 0)
warn("input: %s", infile);
-
- if (verbose > 0) {
- u_int ratio;
- ratio = (1000 * osb.st_size)
- / entry->fts_statp->st_size;
- fprintf(stderr, "%u", ratio / 10);
- if (ratio % 10)
- fprintf(stderr, ".%u",
- ratio % 10);
- fputc('%', stderr);
- fputc(' ', stderr);
- }
}
+ break;
+ case WARNING:
+ rc = rc ? rc : WARNING;
+ break;
+ default:
+ rc = FAILURE;
+ if (oreg && unlink(outfile) && errno != ENOENT &&
+ verbose >= 0) {
+ if (force)
+ warn("output: %s", outfile);
+ else
+ err(1, "output: %s", outfile);
+ }
+ break;
}
-
- if (error > 0 && oreg && unlink(outfile) && errno != ENOENT &&
- verbose >= 0) {
- if (force) {
- warn("output: %s", outfile);
- rc = 1;
- } else
- err(1, "output: %s", outfile);
- } else if (!error && verbose > 0)
- fputs("OK\n", stderr);
}
+ if (list)
+ list_stats(NULL, NULL, NULL);
exit(rc);
}
int
-compress(const char *in, const char *out, const struct compressor *method,
+compress(const char *in, char *out, const struct compressor *method,
int bits, struct stat *sb)
{
u_char buf[Z_BUFSIZE];
- int error, ifd, ofd;
+ char *name;
+ int error, ifd, ofd, flags;
void *cookie;
ssize_t nr;
+ u_int32_t mtime;
+ struct z_info info;
- error = 0;
+ mtime = 0;
+ flags = 0;
+ error = SUCCESS;
+ name = NULL;
cookie = NULL;
if ((ifd = open(in, O_RDONLY)) < 0) {
if (verbose >= 0)
warn("%s", out);
- return (-1);
+ return (FAILURE);
}
if ((ofd = open(out, O_WRONLY|O_CREAT, S_IWUSR)) < 0) {
if (verbose >= 0)
warn("%s", out);
(void) close(ifd);
- return (-1);
+ return (FAILURE);
}
if (method != M_COMPRESS && !force && isatty(ofd)) {
@@ -459,48 +458,61 @@ compress(const char *in, const char *out, const struct compressor *method,
out);
(void) close(ofd);
(void) close(ifd);
- return (-1);
+ return (FAILURE);
}
- if ((cookie = (*method->open)(ofd, "w", bits, 0)) == NULL) {
+ if (!pipin && nosave <= 0) {
+ name = basename(in);
+ mtime = (u_int32_t)sb->st_mtime;
+ }
+ if ((cookie = (*method->open)(ofd, "w", name, bits, mtime, flags)) == NULL) {
if (verbose >= 0)
warn("%s", in);
(void) close(ofd);
(void) close(ifd);
- return (-1);
+ return (FAILURE);
}
while ((nr = read(ifd, buf, sizeof(buf))) > 0)
if ((method->write)(cookie, buf, nr) != nr) {
if (verbose >= 0)
warn("%s", out);
- error++;
+ error = FAILURE;
break;
}
if (!error && nr < 0) {
if (verbose >= 0)
warn("%s", in);
- error++;
+ error = FAILURE;
}
- if ((method->close)(cookie)) {
+ if ((method->close)(cookie, &info)) {
if (!error && verbose >= 0)
warn("%s", out);
- error++;
+ error = FAILURE;
}
if (close(ifd)) {
if (!error && verbose >= 0)
warn("%s", in);
- error++;
+ error = FAILURE;
}
+
+ if (!force && info.total_out >= info.total_in) {
+ if (verbose > 0)
+ fprintf(stderr, "file would grow; left unmodified\n");
+ error = WARNING;
+ }
+
+ if (!error && verbose > 0)
+ verbose_info(out, info.total_out, info.total_in, info.hlen);
return (error);
}
const struct compressor *
-check_method(int fd, struct stat *sb, const char *out)
+check_method(int fd)
{
const struct compressor *method;
u_char magic[2];
@@ -516,15 +528,16 @@ check_method(int fd, struct stat *sb, const char *out)
}
int
-decompress(const char *in, const char *out, const struct compressor *method,
+decompress(const char *in, char *out, const struct compressor *method,
int bits, struct stat *sb)
{
u_char buf[Z_BUFSIZE];
int error, ifd, ofd;
void *cookie;
ssize_t nr;
+ struct z_info info;
- error = 0;
+ error = SUCCESS;
cookie = NULL;
if ((ifd = open(in, O_RDONLY)) < 0) {
@@ -541,53 +554,73 @@ decompress(const char *in, const char *out, const struct compressor *method,
return -1;
}
- if ((method = check_method(ifd, sb, out)) == NULL) {
+ if ((method = check_method(ifd)) == NULL) {
if (verbose >= 0)
warnx("%s: unrecognized file format", in);
close (ifd);
return -1;
}
- if ((cookie = (*method->open)(ifd, "r", bits, 1)) == NULL) {
+ /* XXX - open constrains outfile to MAXPATHLEN so this is safe */
+ if ((cookie = (*method->open)(ifd, "r", nosave < 0 ? out : NULL,
+ bits, 0, 1)) == NULL) {
if (verbose >= 0)
warn("%s", in);
- error++;
close (ifd);
- return -1;
+ return (FAILURE);
}
- if ((ofd = open(out, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR)) < 0) {
+ if (testmode)
+ ofd = -1;
+ else if ((ofd = open(out, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR)) < 0) {
if (verbose >= 0)
warn("%s", in);
- (method->close)(cookie);
- return -1;
+ (method->close)(cookie, NULL);
+ return (FAILURE);
}
- while ((nr = (method->read)(cookie, buf, sizeof(buf))) > 0)
- if (write(ofd, buf, nr) != nr) {
+ while ((nr = (method->read)(cookie, buf, sizeof(buf))) > 0) {
+ if (ofd != -1 && write(ofd, buf, nr) != nr) {
if (verbose >= 0)
warn("%s", out);
- error++;
+ error = FAILURE;
break;
}
+ }
if (!error && nr < 0) {
if (verbose >= 0)
warnx("%s: %s", in,
errno == EINVAL ? "crc error" : strerror(errno));
- error++;
+ error = errno == EINVAL ? WARNING : FAILURE;
}
- if ((method->close)(cookie)) {
+ if ((method->close)(cookie, &info)) {
if (!error && verbose >= 0)
warnx("%s", in);
- error++;
+ error = FAILURE;
}
- if (close(ofd)) {
+ if (nosave < 0) {
+ sb->st_mtimespec.tv_sec = info.mtime;
+ sb->st_mtimespec.tv_nsec = 0;
+ }
+
+ if (ofd != -1 && close(ofd)) {
if (!error && verbose >= 0)
warn("%s", out);
- error++;
+ error = FAILURE;
+ }
+
+ if (!error) {
+ if (list) {
+ if (info.mtime == 0)
+ info.mtime = (u_int32_t)sb->st_mtime;
+ list_stats(pipin ? "stdout" : out, method, &info);
+ } else if (verbose > 0) {
+ verbose_info(out, info.total_in, info.total_out,
+ info.hlen);
+ }
}
return (error);
@@ -688,6 +721,71 @@ set_outfile(const char *infile, char *outfile, size_t osize)
return (outfile);
}
+/*
+ * Print output for the -l option.
+ */
+void
+list_stats(const char *name, const struct compressor *method,
+ struct z_info *info)
+{
+ static off_t compressed_total, uncompressed_total, header_total;
+ static u_int nruns;
+ char *timestr;
+
+ if (nruns == 0) {
+ if (verbose >= 0) {
+ if (verbose > 0)
+ fputs("method crc date time ", stdout);
+ puts("compressed uncompr. ratio uncompressed_name");
+ }
+ }
+ nruns++;
+
+ if (name != NULL) {
+ if (verbose > 0) {
+ timestr = ctime(&info->mtime) + 4;
+ timestr[12] = '\0';
+ printf("%.5s %08x %s ", method->name, info->crc, timestr);
+ }
+ printf("%9lld %9lld %4.1f%% %s\n",
+ (long long)(info->total_in + info->hlen),
+ (long long)info->total_out,
+ (info->total_out - info->total_in) *
+ 100.0 / info->total_out, name);
+ compressed_total += info->total_in;
+ uncompressed_total += info->total_out;
+ header_total += info->hlen;
+ } else if (verbose >= 0) {
+ if (nruns < 3) /* only do totals for > 1 files */
+ return;
+ if (verbose > 0)
+ fputs(" ", stdout);
+ printf("%9lld %9lld %4.1f%% (totals)\n",
+ (long long)(compressed_total + header_total),
+ (long long)uncompressed_total,
+ (uncompressed_total - compressed_total) *
+ 100.0 / uncompressed_total);
+ }
+}
+
+void
+verbose_info(const char *file, off_t compressed, off_t uncompressed,
+ u_int32_t hlen)
+{
+ if (testmode) {
+ fputs("OK\n", stderr);
+ return;
+ }
+ if (!pipin) {
+ fprintf(stderr, "\t%4.1f%% -- replaced with %s\n",
+ (uncompressed - compressed) * 100.0 / uncompressed, file);
+ }
+ compressed += hlen;
+ fprintf(stderr, "%lld bytes in, %lld bytes out\n",
+ (long long)(decomp ? compressed : uncompressed),
+ (long long)(decomp ? uncompressed : compressed));
+}
+
__dead void
usage(int status)
{
diff --git a/usr.bin/compress/zopen.c b/usr.bin/compress/zopen.c
index 9b26edcb206..058a9008350 100644
--- a/usr.bin/compress/zopen.c
+++ b/usr.bin/compress/zopen.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: zopen.c,v 1.12 2003/07/11 02:31:18 millert Exp $ */
+/* $OpenBSD: zopen.c,v 1.13 2003/07/17 20:06:01 millert Exp $ */
/* $NetBSD: zopen.c,v 1.5 1995/03/26 09:44:53 glass Exp $ */
/*-
@@ -40,7 +40,7 @@
static char sccsid[] = "@(#)zopen.c 8.1 (Berkeley) 6/27/93";
#else
const char z_rcsid[] =
- "$OpenBSD: zopen.c,v 1.12 2003/07/11 02:31:18 millert Exp $";
+ "$OpenBSD: zopen.c,v 1.13 2003/07/17 20:06:01 millert Exp $";
#endif
/*-
@@ -123,7 +123,7 @@ struct s_zstate {
long zs_ratio;
count_int zs_checkpoint;
long zs_in_count; /* Length of input. */
- long zs_bytes_out; /* Length of compressed output. */
+ long zs_bytes_out; /* Length of output. */
long zs_out_count; /* # of codes output (for debugging).*/
u_char zs_buf[ZBUFSIZ]; /* I/O buffer */
u_char *zs_bp; /* Current I/O window in the zs_buf */
@@ -313,7 +313,7 @@ nomatch: if (output(zs, (code_int) zs->zs_ent) == -1)
}
int
-zclose(void *cookie)
+z_close(void *cookie, struct z_info *info)
{
struct s_zstate *zs;
int rval;
@@ -332,11 +332,26 @@ zclose(void *cookie)
return (-1);
}
}
+
+ if (info != NULL) {
+ info->mtime = 0;
+ info->crc = (u_int32_t)-1;
+ info->hlen = 0;
+ info->total_in = (off_t)zs->zs_in_count;
+ info->total_out = (off_t)zs->zs_bytes_out;
+ }
+
rval = close(zs->zs_fd);
free(zs);
return (rval);
}
+int
+zclose(void *cookie)
+{
+ return z_close(cookie, NULL);
+}
+
/*-
* Output the given code.
* Inputs:
@@ -493,6 +508,7 @@ zread(void *cookie, char *rbp, int num)
return (-1);
}
zs->zs_maxbits = header[2]; /* Set -b from file. */
+ zs->zs_in_count += sizeof(header);
zs->zs_block_compress = zs->zs_maxbits & BLOCK_MASK;
zs->zs_maxbits &= BIT_MASK;
zs->zs_maxmaxcode = 1L << zs->zs_maxbits;
@@ -545,8 +561,10 @@ zread(void *cookie, char *rbp, int num)
/* And put them out in forward order. */
middle: do {
- if (count-- == 0)
+ if (count-- == 0) {
+ zs->zs_bytes_out += num;
return (num);
+ }
*bp++ = *--zs->zs_stackp;
} while (zs->zs_stackp > de_stack);
@@ -561,6 +579,7 @@ middle: do {
zs->zs_oldcode = zs->zs_incode;
}
zs->zs_state = S_EOF;
+ zs->zs_bytes_out += num - count;
eof: return (num - count);
}
@@ -607,6 +626,7 @@ getcode(struct s_zstate *zs)
if ((bits = read(zs->zs_fd, bp, ZBUFSIZ -
(bp - zs->zs_buf))) < 0)
return -1;
+ zs->zs_in_count += bits;
zs->zs_bp = zs->zs_buf;
zs->zs_ebp = bp + bits;
}
@@ -717,7 +737,7 @@ zopen(const char *name, const char *mode, int bits)
if ((fd = open(name, (*mode=='r'? O_RDONLY:O_WRONLY|O_CREAT),
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1)
return NULL;
- if ((cookie = z_open(fd, mode, bits, 0)) == NULL) {
+ if ((cookie = z_open(fd, mode, NULL, bits, 0, 0)) == NULL) {
close(fd);
return NULL;
}
@@ -726,7 +746,8 @@ zopen(const char *name, const char *mode, int bits)
}
void *
-z_open(int fd, const char *mode, int bits, int gotmagic)
+z_open(int fd, const char *mode, char *name, int bits,
+ u_int32_t mtime, int gotmagic)
{
struct s_zstate *zs;
@@ -749,7 +770,7 @@ z_open(int fd, const char *mode, int bits, int gotmagic)
zs->zs_clear_flg = 0;
zs->zs_ratio = 0;
zs->zs_checkpoint = CHECK_GAP;
- zs->zs_in_count = 1; /* Length of input. */
+ zs->zs_in_count = 0; /* Length of input. */
zs->zs_out_count = 0; /* # of codes output (for debugging).*/
zs->zs_state = gotmagic ? S_MAGIC : S_START;
zs->zs_offset = 0;