significantly rototill. don't use the high-level gzio functions

anymore, use the low-level inflate()/deflate() directly.  this
allows support file-type detection on stdin; now can decompress
.Z and .bz2 files fed to stdin (fixes PR#25192) additionally it
makes -v work with stdin or stdout (fixes PR#25215.)

(with these changes, we no longer need gzopenfull(3) in libz.)

thanks to martin@ for the code gzip.c:gz_uncompress() is based on.
This commit is contained in:
mrg 2004-04-25 16:20:33 +00:00
parent 04d1f5de72
commit 1d0e9794a0
4 changed files with 503 additions and 174 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: gzip.1,v 1.14 2004/02/18 09:16:27 wiz Exp $
.\" $NetBSD: gzip.1,v 1.15 2004/04/25 16:20:33 mrg Exp $
.\"
.\" Copyright (c) 1997, 2003, 2004 Matthew R. Green
.\" All rights reserved.
@ -191,24 +191,9 @@ program for
This manual documents
.Nx
.Nm
version 2.1.
version 20040425.
.Sh AUTHORS
The
.Nx
This implementation of
.Nm
program was written by
was written by
.An Matthew R. Green Aq mrg@eterna.com.au .
.Sh BUGS
The
.Nx
.Nm
program does not print the compression ratio when not using files.
.Pp
The
.Nx
.Nm
program depends on
.Nx
specific enhancements to the
.Xr zlib 3
library.

View File

@ -1,7 +1,7 @@
/* $NetBSD: gzip.c,v 1.36 2004/04/12 14:42:14 mrg Exp $ */
/* $NetBSD: gzip.c,v 1.37 2004/04/25 16:20:33 mrg Exp $ */
/*
* Copyright (c) 1997, 1998, 2003 Matthew R. Green
* Copyright (c) 1997, 1998, 2003, 2004 Matthew R. Green
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -30,21 +30,19 @@
#include <sys/cdefs.h>
#ifndef lint
__COPYRIGHT("@(#) Copyright (c) 1997, 1998, 2003 Matthew R. Green\n\
__COPYRIGHT("@(#) Copyright (c) 1997, 1998, 2003, 2004 Matthew R. Green\n\
All rights reserved.\n");
__RCSID("$NetBSD: gzip.c,v 1.36 2004/04/12 14:42:14 mrg Exp $");
__RCSID("$NetBSD: gzip.c,v 1.37 2004/04/25 16:20:33 mrg Exp $");
#endif /* not lint */
/*
* gzip.c -- GPL free gzip using zlib.
*
* very minor portions of this code are (very loosely) derived from
* the minigzip.c in the zlib distribution.
*
* TODO:
* - handle .taz/.tgz files?
* - use mmap where possible
* - handle some signals better (remove outfile?)
* - audit maybe_err()/maybe_warn() usage
*/
#include <sys/param.h>
@ -91,25 +89,25 @@ enum filetype {
#define GZ_SUFFIX ".gz"
#define BUFLEN (32 * 1024)
#define BUFLEN (64 * 1024)
#define GZIP_MAGIC0 0x1F
#define GZIP_MAGIC1 0x8B
#define GZIP_OMAGIC1 0x9E
#define ORIG_NAME 0x08
#define HEAD_CRC 0x02
#define EXTRA_FIELD 0x04
#define ORIG_NAME 0x08
#define COMMENT 0x10
/* Define this if you have the NetBSD gzopenfull(3) extension to zlib(3) */
#ifndef HAVE_ZLIB_GZOPENFULL
#define HAVE_ZLIB_GZOPENFULL 1
#endif
#define OS_CODE 3 /* Unix */
static const char gzip_version[] = "NetBSD gzip 2.3";
static const char gzip_version[] = "NetBSD gzip 20040425";
static char gzipflags[3]; /* `w' or `r', possible with [1-9] */
static int cflag; /* stdout mode */
static int dflag; /* decompress mode */
static int lflag; /* list mode */
static int numflag = 5; /* gzip -1..-9 value */
#ifndef SMALL
static int fflag; /* force mode */
@ -134,8 +132,8 @@ static void maybe_errx(int rv, const char *fmt, ...);
static void maybe_warn(const char *fmt, ...);
static void maybe_warnx(const char *fmt, ...);
static enum filetype file_gettype(u_char *);
static void gz_compress(FILE *, gzFile);
static off_t gz_uncompress(gzFile, FILE *);
static off_t gz_compress(FILE *, int, off_t *, const char *, time_t);
static off_t gz_uncompress(int, int, char *, size_t, off_t *);
static off_t file_compress(char *);
static off_t file_uncompress(char *);
static void handle_pathname(char *);
@ -156,12 +154,12 @@ static void copymodes(const char *, struct stat *);
#endif
#ifndef NO_BZIP2_SUPPORT
static off_t unbzip2(int, int);
static off_t unbzip2(int, int, char *, size_t, off_t *);
#endif
#ifndef NO_COMPRESS_SUPPORT
static FILE *zopen(const char *);
static off_t zuncompress(FILE *, FILE *);
static FILE *zopen(const char *, FILE *);
static off_t zuncompress(FILE *, FILE *, char *, size_t, off_t *);
#endif
int main(int, char *p[]);
@ -210,9 +208,6 @@ main(int argc, char **argv)
/* XXX set up signals */
gzipflags[0] = 'w';
gzipflags[1] = '\0';
suffix = GZ_SUFFIX;;
#ifndef SMALL
@ -254,8 +249,7 @@ main(int argc, char **argv)
case '1': case '2': case '3':
case '4': case '5': case '6':
case '7': case '8': case '9':
gzipflags[1] = (char)ch;
gzipflags[2] = '\0';
numflag = ch;
break;
#ifndef SMALL
case 'f':
@ -293,8 +287,6 @@ main(int argc, char **argv)
}
argv += optind;
argc -= optind;
if (dflag)
gzipflags[0] = 'r';
if (argc == 0) {
if (dflag) /* stdin mode */
@ -426,72 +418,337 @@ prepend_gzip(char *gzip, int *argc, char ***argv)
#endif
/* compress input to output then close both files */
static void
gz_compress(FILE *in, gzFile out)
{
char buf[BUFLEN];
ssize_t len;
int i;
for (;;) {
len = fread(buf, 1, sizeof(buf), in);
if (ferror(in))
maybe_err(1, "fread");
if (len == 0)
break;
if ((ssize_t)gzwrite(out, buf, len) != len)
maybe_err(1, gzerror(out, &i));
}
if (fclose(in) < 0)
maybe_err(1, "failed fclose");
if (gzclose(out) != Z_OK)
maybe_err(1, "failed gzclose");
}
/* uncompress input to output then close the input */
static off_t
gz_uncompress(gzFile in, FILE *out)
gz_compress(FILE *in, int out, off_t *gsizep, const char *origname, time_t mtime)
{
char buf[BUFLEN];
off_t size;
ssize_t len;
int i;
z_stream z;
char inbuf[BUFLEN], outbuf[BUFLEN];
off_t in_tot = 0, out_tot = 0;
ssize_t in_size;
char *str;
int i, error;
uLong crc;
for (size = 0;;) {
len = gzread(in, buf, sizeof(buf));
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(1, "asprintf");
if (origname)
i++;
if (write(out, str, i) != i)
maybe_err(1, "write");
free(str);
if (len < 0) {
#ifndef SMALL
if (tflag) {
print_test(infile, 0);
return (0);
} else
#endif
maybe_errx(1, gzerror(in, &i));
} else if (len == 0) {
#ifndef SMALL
if (tflag)
print_test(infile, 1);
#endif
break;
memset(&z, 0, sizeof z);
z.next_out = outbuf;
z.avail_out = sizeof outbuf;
z.zalloc = NULL;
z.zfree = NULL;
z.opaque = 0;
error = deflateInit2(&z, numflag, Z_DEFLATED,
-MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
if (error != Z_OK)
maybe_errx(1, "deflateInit2 failed");
crc = crc32(0L, Z_NULL, 0);
for (;;) {
if (z.avail_out == 0) {
if (write(out, outbuf, sizeof outbuf) != sizeof outbuf)
maybe_err(1, "write");
out_tot += sizeof outbuf;
z.next_out = outbuf;
z.avail_out = sizeof outbuf;
}
size += len;
if (z.avail_in == 0) {
in_size = fread(inbuf, 1, sizeof inbuf, in);
if (ferror(in))
maybe_err(1, "fread");
if (in_size == 0)
break;
crc = crc32(crc, (const Bytef *)inbuf, (unsigned)in_size);
in_tot += in_size;
z.next_in = inbuf;
z.avail_in = in_size;
}
error = deflate(&z, Z_NO_FLUSH);
if (error != Z_OK && error != Z_STREAM_END)
maybe_errx(1, "deflate failed2 (%d)", error);
}
/* clean up */
for (;;) {
size_t len;
error = deflate(&z, Z_FINISH);
if (error != Z_OK && error != Z_STREAM_END)
maybe_errx(1, "deflate failed1 (%d)", error);
len = sizeof outbuf - z.avail_out;
if (write(out, outbuf, len) != len)
maybe_err(1, "write");
out_tot += len;
z.next_out = outbuf;
z.avail_out = sizeof outbuf;
if (error == Z_STREAM_END)
break;
}
if (deflateEnd(&z) != Z_OK)
maybe_errx(1, "deflateEnd failed");
i = asprintf(&str, "%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(1, "asprintf");
if (write(out, str, i) != i)
maybe_err(1, "write");
free(str);
if (fclose(in) < 0)
maybe_err(1, "failed fclose");
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)
{
z_stream z;
char outbuf[BUFLEN], inbuf[BUFLEN];
off_t out_tot, in_tot;
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
} state = GZSTATE_MAGIC0;
int flags = 0, skip_count = 0;
int error, done_reading = 0;
#define ADVANCE() { z.next_in++; z.avail_in--; }
memset(&z, 0, sizeof z);
z.avail_in = prelen;
z.next_in = pre;
z.avail_out = sizeof outbuf;
z.next_out = outbuf;
z.zalloc = NULL;
z.zfree = NULL;
z.opaque = 0;
in_tot = prelen;
out_tot = 0;
for (;;) {
if (z.avail_in == 0 && done_reading == 0) {
size_t in_size = read(in, inbuf, BUFLEN);
if (in_size == -1) {
#ifndef SMALL
if (tflag) {
print_test("(stdin)", 0);
return 0;
}
#endif
maybe_warn("failed to read stdin\n");
return -1;
} else if (in_size == 0)
done_reading = 1;
z.avail_in = in_size;
z.next_in = inbuf;
in_tot += in_size;
}
switch (state) {
case GZSTATE_MAGIC0:
if (*z.next_in != GZIP_MAGIC0)
maybe_err(1, "input not gziped\n");
ADVANCE();
state++;
break;
case GZSTATE_MAGIC1:
if (*z.next_in != GZIP_MAGIC1 &&
*z.next_in != GZIP_OMAGIC1)
maybe_err(1, "input not gziped\n");
ADVANCE();
state++;
break;
case GZSTATE_METHOD:
if (*z.next_in != Z_DEFLATED)
maybe_err(1, "unknown compression method\n");
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_err(1, "failed to inflateInit\n");
goto stop;
}
state++;
break;
case GZSTATE_READ:
error = inflate(&z, Z_FINISH);
if (error == Z_STREAM_END || error == Z_BUF_ERROR) {
size_t wr = BUFLEN - z.avail_out;
if (
#ifndef SMALL
/* don't write anything with -t */
tflag == 0 &&
#endif
write(STDOUT_FILENO, outbuf, wr) != wr)
maybe_err(1, "error writing "
"to stdout\n");
if (error == Z_STREAM_END)
goto stop;
z.next_out = outbuf;
z.avail_out = BUFLEN;
out_tot += wr;
break;
}
if (error < 0) {
maybe_warnx("decompression error (%d)\n", error);
out_tot = -1;
goto stop;
}
break;
}
continue;
stop:
break;
}
if (state > GZSTATE_INIT)
inflateEnd(&z);
#ifndef SMALL
/* don't write anything with -t */
if (tflag)
continue;
if (tflag) {
print_test("(stdin)", 1);
return 0;
}
#endif
if (fwrite(buf, 1, (unsigned)len, out) != (ssize_t)len)
maybe_err(1, "failed fwrite");
}
if (gzclose(in) != Z_OK)
maybe_errx(1, "failed gzclose");
return (size);
if (gsizep)
*gsizep = in_tot;
return (out_tot);
}
#ifndef SMALL
@ -569,12 +826,13 @@ static off_t
file_compress(char *file)
{
FILE *in;
gzFile out;
int out;
struct stat isb, osb;
char outfile[MAXPATHLEN];
off_t size;
#ifndef SMALL
u_int32_t mtime = 0;
char *savename;
#endif
if (cflag == 0) {
@ -607,26 +865,21 @@ file_compress(char *file)
maybe_err(1, "can't fopen %s", file);
if (cflag == 0) {
#if HAVE_ZLIB_GZOPENFULL && !defined(SMALL)
char *savename;
#ifndef SMALL
if (nflag == 0)
savename = basename(file);
else
savename = NULL;
out = gzopenfull(outfile, gzipflags, savename, mtime);
#else
out = gzopen(outfile, gzipflags);
#endif
out = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0600);
} else
out = gzdopen(STDOUT_FILENO, gzipflags);
out = STDOUT_FILENO;
if (out == 0)
maybe_err(1, "can't gz%sopen %s",
cflag ? "d" : "",
cflag ? "stdout" : outfile);
gz_compress(in, out);
#ifdef SMALL
gz_compress(in, out, NULL, NULL, 0);
#else
gz_compress(in, out, NULL, savename, mtime);
#endif
/*
* if we compressed to stdout, we don't know the size and
@ -664,12 +917,10 @@ file_uncompress(char *file)
struct stat isb, osb;
char buf[PATH_MAX];
char *outfile = buf, *s;
FILE *out;
gzFile in;
off_t size;
ssize_t len = strlen(file);
int fd;
unsigned char header1[10], name[PATH_MAX + 1];
unsigned char header1[4], name[PATH_MAX + 1];
enum filetype method;
/* gather the old name info */
@ -677,7 +928,7 @@ file_uncompress(char *file)
fd = open(file, O_RDONLY);
if (fd < 0)
maybe_err(1, "can't open %s", file);
if (read(fd, header1, 10) != 10) {
if (read(fd, header1, sizeof header1) != sizeof header1) {
/* we don't want to fail here. */
#ifndef SMALL
if (fflag)
@ -784,7 +1035,7 @@ close_it:
if (out == -1)
maybe_err(1, "open for write: %s", outfile);
if ((size = unbzip2(in, out)) == 0) {
if ((size = unbzip2(in, out, NULL, 0, NULL)) == 0) {
if (cflag == 0)
unlink(outfile);
goto lose;
@ -801,7 +1052,7 @@ close_it:
if (lflag)
maybe_errx(1, "no -l with Lempel-Ziv files");
if ((in = zopen(file)) == NULL)
if ((in = zopen(file, NULL)) == NULL)
maybe_err(1, "open for read: %s", file);
if (cflag == 1)
@ -815,7 +1066,7 @@ close_it:
if (out == NULL)
maybe_err(1, "open for write: %s", outfile);
size = zuncompress(in, out);
size = zuncompress(in, out, NULL, 0, NULL);
if (cflag == 0) {
if (size == 0) {
unlink(outfile);
@ -833,40 +1084,35 @@ close_it:
} else
#endif
{
if (lflag) {
int fd;
int fd, in;
if (lflag) {
if ((fd = open(file, O_RDONLY)) == -1)
maybe_err(1, "open");
print_list(fd, isb.st_size, outfile, isb.st_mtime);
return 0; /* XXX */
}
in = gzopen(file, gzipflags);
if (in == NULL)
maybe_err(1, "can't gzopen %s", file);
in = open(file, O_RDONLY);
if (in == -1)
maybe_err(1, "can't open %s", file);
if (cflag == 0) {
int fd;
/* Use open(2) directly to get a safe file. */
fd = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0600);
if (fd < 0)
maybe_err(1, "can't open %s", outfile);
out = fdopen(fd, "w");
if (out == NULL)
maybe_err(1, "can't fdopen %s", outfile);
} else
out = stdout;
fd = STDOUT_FILENO;
size = gz_uncompress(in, out);
size = gz_uncompress(in, fd, NULL, 0, NULL);
if (cflag == 0) {
if (size == 0) {
if (size == -1) {
unlink(outfile);
goto lose;
}
if (fclose(out))
maybe_err(1, "failed fclose");
if (close(fd))
maybe_err(1, "failed close");
}
}
@ -913,10 +1159,40 @@ lose:
return 0;
}
#ifndef SMALL
static off_t
cat_stdin(unsigned char * prepend, size_t count, off_t *gsizep)
{
char buf[BUFLEN];
size_t rv;
off_t in_tot;
in_tot = count;
if (write(STDOUT_FILENO, prepend, count) != count)
maybe_err(1, "write to stdout");
for (;;) {
rv = read(STDIN_FILENO, buf, sizeof buf);
if (write(STDOUT_FILENO, buf, rv) != rv)
maybe_err(1, "write to stdout");
in_tot += rv;
}
if (gsizep)
*gsizep = in_tot;
return (in_tot);
}
#endif
static void
handle_stdin(void)
{
gzFile *file;
unsigned char header1[4];
off_t usize, gsize;
enum filetype method;
#ifndef NO_COMPRESS_SUPPORT
FILE *in;
#endif
#ifndef SMALL
if (fflag == 0 && lflag == 0 && isatty(STDIN_FILENO)) {
@ -928,22 +1204,56 @@ handle_stdin(void)
if (lflag) {
struct stat isb;
/* XXX could read the whole file, etc. */
if (fstat(STDIN_FILENO, &isb) < 0)
maybe_err(1, "fstat");
print_list(STDIN_FILENO, isb.st_size, "stdout", isb.st_mtime);
return;
}
file = gzdopen(STDIN_FILENO, gzipflags);
if (file == NULL)
maybe_err(1, "can't gzdopen stdin");
gz_uncompress(file, stdout);
if (read(STDIN_FILENO, header1, sizeof header1) != sizeof header1)
maybe_err(1, "can't read stdin");
method = file_gettype(header1);
switch (method) {
default:
#ifndef SMALL
if (fflag == 0)
maybe_errx(1, "unknown compression format");
usize = cat_stdin(header1, sizeof header1, &gsize);
break;
#endif
case FT_GZIP:
usize = gz_uncompress(STDIN_FILENO, STDOUT_FILENO,
header1, sizeof header1, &gsize);
break;
#ifndef NO_BZIP2_SUPPORT
case FT_BZIP2:
usize = unbzip2(STDIN_FILENO, STDOUT_FILENO,
header1, sizeof header1, &gsize);
break;
#endif
#ifndef NO_COMPRESS_SUPPORT
case FT_Z:
if ((in = zopen(NULL, stdin)) == NULL)
maybe_err(1, "zopen of stdin");
usize = zuncompress(in, stdout, header1, sizeof header1, &gsize);
break;
#endif
}
#ifndef SMALL
if (vflag && !tflag && usize != -1 && gsize != -1)
print_verbage(NULL, 0, usize, gsize);
#endif
}
static void
handle_stdout(void)
{
gzFile *file;
off_t gsize, usize;
#ifndef SMALL
if (fflag == 0 && isatty(STDOUT_FILENO)) {
@ -951,10 +1261,12 @@ handle_stdout(void)
return;
}
#endif
file = gzdopen(STDOUT_FILENO, gzipflags);
if (file == NULL)
maybe_err(1, "can't gzdopen stdout");
gz_compress(stdin, file);
usize = gz_compress(stdin, STDOUT_FILENO, &gsize, NULL, 0);
#ifndef SMALL
if (vflag && !tflag && usize != -1 && gsize != -1)
print_verbage(NULL, 0, usize, gsize);
#endif
}
/* do what is asked for, for the path name */
@ -1108,8 +1420,9 @@ print_ratio(off_t in, off_t out, FILE *where)
static void
print_verbage(char *file, char *nfile, off_t usize, off_t gsize)
{
fprintf(stderr, "%s:%s ", file,
strlen(file) < 7 ? "\t\t" : "\t");
if (file)
fprintf(stderr, "%s:%s ", file,
strlen(file) < 7 ? "\t\t" : "\t");
print_ratio((off_t)usize, (off_t)gsize, stderr);
if (nfile)
fprintf(stderr, " -- replaced with %s", nfile);
@ -1170,7 +1483,7 @@ print_list(int fd, off_t out, const char *outfile, time_t ts)
u_int32_t usize;
if (read(fd, (char *)buf, sizeof(buf)) != sizeof(buf))
maybe_err(1, "read of uncompressed size");
maybe_warn("read of uncompressed size");
usize = buf[4] | buf[5] << 8 | buf[6] << 16 | buf[7] << 24;
in = (off_t)usize;
#ifndef SMALL

View File

@ -1,21 +1,19 @@
/* $NetBSD: unbzip2.c,v 1.3 2004/03/30 11:43:32 mrg Exp $ */
/* $NetBSD: unbzip2.c,v 1.4 2004/04/25 16:20:33 mrg Exp $ */
/* This file is #included by gzip.c */
#define INBUFSIZE (64 * 1024)
#define OUTBUFSIZE (64 * 1024)
static off_t
unbzip2(int in, int out)
unbzip2(int in, int out, char *pre, size_t prelen, off_t *bytes_in)
{
int n, ret, end_of_file;
int ret, end_of_file;
size_t n;
off_t bytes_out = 0;
bz_stream bzs;
static char *inbuf, *outbuf;
if (inbuf == NULL && (inbuf = malloc(INBUFSIZE)) == NULL)
if (inbuf == NULL && (inbuf = malloc(BUFLEN)) == NULL)
maybe_err(1, "malloc");
if (outbuf == NULL && (outbuf = malloc(OUTBUFSIZE)) == NULL)
if (outbuf == NULL && (outbuf = malloc(BUFLEN)) == NULL)
maybe_err(1, "malloc");
bzs.bzalloc = NULL;
@ -27,22 +25,28 @@ unbzip2(int in, int out)
if (ret != BZ_OK)
maybe_errx(1, "bzip2 init");
bzs.avail_in = 0;
/* Prepend. */
bzs.avail_in = prelen;
bzs.next_in = pre;
if (bytes_in)
*bytes_in = prelen;
while (ret != BZ_STREAM_END) {
if (bzs.avail_in == 0 && !end_of_file) {
n = read(in, inbuf, INBUFSIZE);
n = read(in, inbuf, BUFLEN);
if (n < 0)
maybe_err(1, "read");
if (n == 0)
end_of_file = 1;
bzs.next_in = inbuf;
bzs.avail_in = n;
} else
n = 0;
if (bytes_in)
*bytes_in += n;
}
bzs.next_out = outbuf;
bzs.avail_out = OUTBUFSIZE;
bzs.avail_out = BUFLEN;
ret = BZ2_bzDecompress(&bzs);
switch (ret) {
@ -51,7 +55,7 @@ unbzip2(int in, int out)
if (ret == BZ_OK && end_of_file)
maybe_err(1, "read");
if (!tflag) {
n = write(out, outbuf, OUTBUFSIZE - bzs.avail_out);
n = write(out, outbuf, BUFLEN - bzs.avail_out);
if (n < 0)
maybe_err(1, "write");
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: zuncompress.c,v 1.2 2004/02/18 18:29:07 he Exp $ */
/* $NetBSD: zuncompress.c,v 1.3 2004/04/25 16:20:33 mrg Exp $ */
/*-
* Copyright (c) 1985, 1986, 1992, 1993
@ -76,6 +76,10 @@ static char_type magic_header[] =
static char_type rmask[9] =
{0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
/* XXX zuncompress global */
off_t total_compressed_bytes;
size_t compressed_prelen;
char *compressed_pre;
struct s_zstate {
FILE *zs_fp; /* File stream for I/O */
@ -124,22 +128,33 @@ struct s_zstate {
static code_int getcode(struct s_zstate *zs);
static off_t
zuncompress(FILE *in, FILE *out)
zuncompress(FILE *in, FILE *out, char *pre, size_t prelen,
off_t *compressed_bytes)
{
off_t bin, bout = 0;
char buf[BUFSIZE];
/* XXX */
compressed_prelen = prelen;
if (prelen != 0)
compressed_pre = pre;
else
compressed_pre = NULL;
while ((bin = fread(buf, 1, sizeof(buf), in)) != 0) {
if (fwrite(buf, 1, bin, out) != bin)
return 0;
bout += bin;
}
if (compressed_bytes)
*compressed_bytes = total_compressed_bytes;
return bout;
}
FILE *
zopen(const char *fname)
zopen(const char *fname, FILE *preopen)
{
struct s_zstate *zs;
@ -164,7 +179,8 @@ zopen(const char *fname)
* Layering compress on top of stdio in order to provide buffering,
* and ensure that reads and write work with the data specified.
*/
if ((zs->zs_fp = fopen(fname, "r")) == NULL) {
if ((zs->zs_fp = preopen) == NULL &&
(zs->zs_fp = fopen(fname, "r")) == NULL) {
free(zs);
return NULL;
}
@ -181,7 +197,7 @@ zopen(const char *fname)
static int
zread(void *cookie, char *rbp, int num)
{
u_int count;
u_int count, i;
struct s_zstate *zs;
u_char *bp, header[3];
@ -202,12 +218,16 @@ zread(void *cookie, char *rbp, int num)
}
/* Check the magic number */
if (fread(header,
sizeof(char), sizeof(header), zs->zs_fp) != sizeof(header) ||
for (i = 0; i < 3 && compressed_prelen; i++, compressed_prelen--)
header[i] = *compressed_pre++;
if (fread(header + i, 1, sizeof(header) - i, zs->zs_fp) !=
sizeof(header) - i ||
memcmp(header, magic_header, sizeof(magic_header)) != 0) {
errno = EFTYPE;
return (-1);
}
total_compressed_bytes = 0;
zs->zs_maxbits = header[2]; /* Set -b from file. */
zs->zs_block_compress = zs->zs_maxbits & BLOCK_MASK;
zs->zs_maxbits &= BIT_MASK;
@ -291,7 +311,7 @@ static code_int
getcode(struct s_zstate *zs)
{
code_int gcode;
int r_off, bits;
int r_off, bits, i;
char_type *bp;
bp = zs->u.r.zs_gbuf;
@ -313,10 +333,17 @@ getcode(struct s_zstate *zs)
zs->zs_maxcode = MAXCODE(zs->zs_n_bits = INIT_BITS);
zs->zs_clear_flg = 0;
}
zs->u.r.zs_size = fread(zs->u.r.zs_gbuf, 1, zs->zs_n_bits, zs->zs_fp);
/* XXX */
for (i = 0; i < zs->zs_n_bits && compressed_prelen; i++, compressed_prelen--)
zs->u.r.zs_gbuf[i] = *compressed_pre++;
zs->u.r.zs_size = fread(zs->u.r.zs_gbuf + i, 1, zs->zs_n_bits - i, zs->zs_fp);
zs->u.r.zs_size += i;
if (zs->u.r.zs_size <= 0) /* End of file. */
return (-1);
zs->u.r.zs_roffset = 0;
total_compressed_bytes += zs->u.r.zs_size;
/* Round size down to integral number of codes. */
zs->u.r.zs_size = (zs->u.r.zs_size << 3) - (zs->zs_n_bits - 1);
}