Mark Adler wrote: >> A test case will be forthcoming (I need to create a case that delicately >> crosses a buffer boundary). Once I get a test case working, you can push it. > > Jim, > > It turns out that is no condition in which the lack of the patch to the patch > causes a problem. So I have no test case for it. I will leave the patch to > the patch in nevertheless, since otherwise it still looks like a bug.
I may have encountered this already when I was trying to create a compressed file of size one smaller than gzip's internal buffer size. It appeared to be impossible. Here's the output of "git format-patch --stdout -1" for that patch. I'll push it today. >From 1204630c96e0c368b4325f95cbaef95c3f9c482a Mon Sep 17 00:00:00 2001 From: Mark Adler <mad...@alumni.caltech.edu> Date: Wed, 3 Feb 2010 10:11:33 +0100 Subject: [PATCH] gzip -cdf now handles concatenation of gzip'd and uncompressed data * util.c (copy): Change semantics so as to honor a decremented inptr. * gzip.c (get_method): When needed (-cdf), decrement inptr rather than clearing it -- and output the first magic byte. --- gnulib | 2 +- gzip.c | 12 ++++++++++-- util.c | 22 +++++++++++++--------- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/gnulib b/gnulib index a5b5500..9d0ad65 160000 --- a/gnulib +++ b/gnulib @@ -1 +1 @@ -Subproject commit a5b5500500ba4d6aaa9a1b3bb214f6917dc1ac3c +Subproject commit 9d0ad652de159d08e5f679842f8a2a5658196361 diff --git a/gzip.c b/gzip.c index f523be7..141397e 100644 --- a/gzip.c +++ b/gzip.c @@ -1239,6 +1239,7 @@ local int get_method(in) { uch flags; /* compression flags */ char magic[2]; /* magic header */ + int imagic0; /* first magic byte or EOF */ int imagic1; /* like magic[1], but can represent EOF */ ulg stamp; /* time stamp */ @@ -1246,12 +1247,14 @@ local int get_method(in) * premature end of file: use try_byte instead of get_byte. */ if (force && to_stdout) { - magic[0] = (char)try_byte(); + imagic0 = try_byte(); + magic[0] = (char) imagic0; imagic1 = try_byte (); magic[1] = (char) imagic1; /* If try_byte returned EOF, magic[1] == (char) EOF. */ } else { magic[0] = (char)get_byte(); + imagic0 = 0; if (magic[0]) { magic[1] = (char)get_byte(); imagic1 = 0; /* avoid lint warning */ @@ -1395,8 +1398,13 @@ local int get_method(in) } else if (force && to_stdout && !list) { /* pass input unchanged */ method = STORED; work = copy; - inptr = 0; + if (imagic1 != EOF) + inptr--; last_member = 1; + if (imagic0 != EOF) { + write_buf(fileno(stdout), magic, 1); + bytes_out++; + } } if (method >= 0) return method; diff --git a/util.c b/util.c index 1de2701..80b1075 100644 --- a/util.c +++ b/util.c @@ -44,21 +44,25 @@ extern ulg crc_32_tab[]; /* crc table, defined below */ /* =========================================================================== * Copy input to output unchanged: zcat == cat with --force. - * IN assertion: insize bytes have already been read in inbuf. + * IN assertion: insize bytes have already been read in inbuf and inptr bytes + * already processed or copied. */ int copy(in, out) int in, out; /* input and output file descriptors */ { + int got; + errno = 0; - while (insize != 0 && (int)insize != -1) { - write_buf(out, (char*)inbuf, insize); - bytes_out += insize; - insize = read_buffer (in, (char *) inbuf, INBUFSIZ); - } - if ((int)insize == -1) { - read_error(); + while (insize > inptr) { + write_buf(out, (char*)inbuf + inptr, insize - inptr); + bytes_out += insize - inptr; + got = read_buffer (in, (char *) inbuf, INBUFSIZ); + if (got == -1) + read_error(); + bytes_in += got; + insize = (unsigned)got; + inptr = 0; } - bytes_in = bytes_out; return OK; } -- 1.7.0.rc1.193.ge8618