From owner-svn-src-stable@FreeBSD.ORG Wed Dec 30 17:55:21 2009 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 4768C106566C; Wed, 30 Dec 2009 17:55:21 +0000 (UTC) (envelope-from jhb@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 3542B8FC1E; Wed, 30 Dec 2009 17:55:21 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id nBUHtLTd066251; Wed, 30 Dec 2009 17:55:21 GMT (envelope-from jhb@svn.freebsd.org) Received: (from jhb@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id nBUHtLj5066248; Wed, 30 Dec 2009 17:55:21 GMT (envelope-from jhb@svn.freebsd.org) Message-Id: <200912301755.nBUHtLj5066248@svn.freebsd.org> From: John Baldwin Date: Wed, 30 Dec 2009 17:55:21 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r201268 - stable/7/lib/libstand X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 30 Dec 2009 17:55:21 -0000 Author: jhb Date: Wed Dec 30 17:55:20 2009 New Revision: 201268 URL: http://svn.freebsd.org/changeset/base/201268 Log: MFC 174741,200919: - Fix logical bug in the bzip2 reading code, which results in bogus EIO returned on a perfectly valid bzip2 stream whose decompressed size is multiple of read-ahead buffer size. - Add a similar fix to the gzipfs code to be safe (along with a subsequent bugfix to un-break seeking of gzip streams). - Add some ifdef'ed code to enable testing bzipfs.c from witin normal FreeBSD environment as opposed to the restricted loader one, so that one can use gdb and whatnot. - Add lseek() support to bzip2fs. Modified: stable/7/lib/libstand/bzipfs.c stable/7/lib/libstand/gzipfs.c Directory Properties: stable/7/lib/libstand/ (props changed) Modified: stable/7/lib/libstand/bzipfs.c ============================================================================== --- stable/7/lib/libstand/bzipfs.c Wed Dec 30 17:53:07 2009 (r201267) +++ stable/7/lib/libstand/bzipfs.c Wed Dec 30 17:55:20 2009 (r201268) @@ -28,7 +28,24 @@ #include __FBSDID("$FreeBSD$"); +#ifndef REGRESSION #include "stand.h" +#else +#include +#include +#include +#include +#include + +struct open_file { + int f_flags; /* see F_* below */ + void *f_fsdata; /* file system specific data */ +}; +#define F_READ 0x0001 /* file opened for reading */ +#define EOFFSET (ELAST+8) /* relative seek not supported */ +static inline u_int min(u_int a, u_int b) { return(a < b ? a : b); } +#define panic(x, y) abort() +#endif #include #include @@ -41,6 +58,7 @@ struct bz_file int bzf_rawfd; bz_stream bzf_bzstream; char bzf_buf[BZ_BUFSIZE]; + int bzf_endseen; }; static int bzf_fill(struct bz_file *z); @@ -50,6 +68,7 @@ static int bzf_read(struct open_file *f, static off_t bzf_seek(struct open_file *f, off_t offset, int where); static int bzf_stat(struct open_file *f, struct stat *sb); +#ifndef REGRESSION struct fs_ops bzipfs_fsops = { "bzip", bzf_open, @@ -60,6 +79,7 @@ struct fs_ops bzipfs_fsops = { bzf_stat, null_readdir }; +#endif #if 0 void * @@ -155,6 +175,8 @@ bzf_open(const char *fname, struct open_ /* Construct new name */ bzfname = malloc(strlen(fname) + 5); + if (bzfname == NULL) + return(ENOMEM); sprintf(bzfname, "%s.bz2", fname); /* Try to open the compressed datafile */ @@ -176,13 +198,14 @@ bzf_open(const char *fname, struct open_ /* Allocate a bz_file structure, populate it */ bzf = malloc(sizeof(struct bz_file)); + if (bzf == NULL) + return(ENOMEM); bzero(bzf, sizeof(struct bz_file)); bzf->bzf_rawfd = rawfd; - /* Verify that the file is bzipped (XXX why do this afterwards?) */ + /* Verify that the file is bzipped */ if (check_header(bzf)) { close(bzf->bzf_rawfd); - BZ2_bzDecompressEnd(&(bzf->bzf_bzstream)); free(bzf); return(EFTYPE); } @@ -220,7 +243,7 @@ bzf_read(struct open_file *f, void *buf, bzf->bzf_bzstream.next_out = buf; /* where and how much */ bzf->bzf_bzstream.avail_out = size; - while (bzf->bzf_bzstream.avail_out) { + while (bzf->bzf_bzstream.avail_out && bzf->bzf_endseen == 0) { if ((bzf->bzf_bzstream.avail_in == 0) && (bzf_fill(bzf) == -1)) { printf("bzf_read: fill error\n"); return(EIO); @@ -228,12 +251,13 @@ bzf_read(struct open_file *f, void *buf, if (bzf->bzf_bzstream.avail_in == 0) { /* oops, unexpected EOF */ printf("bzf_read: unexpected EOF\n"); if (bzf->bzf_bzstream.avail_out == size) - return (EIO); + return(EIO); break; } error = BZ2_bzDecompress(&bzf->bzf_bzstream); /* decompression pass */ if (error == BZ_STREAM_END) { /* EOF, all done */ + bzf->bzf_endseen = 1; break; } if (error != BZ_OK) { /* argh, decompression error */ @@ -246,6 +270,50 @@ bzf_read(struct open_file *f, void *buf, return(0); } +static int +bzf_rewind(struct open_file *f) +{ + struct bz_file *bzf = (struct bz_file *)f->f_fsdata; + struct bz_file *bzf_tmp; + + /* + * Since bzip2 does not have an equivalent inflateReset function a crude + * one needs to be provided. The functions all called in such a way that + * at any time an error occurs a role back can be done (effectively making + * this rewind 'atomic', either the reset occurs successfully or not at all, + * with no 'undefined' state happening). + */ + + /* Allocate a bz_file structure, populate it */ + bzf_tmp = malloc(sizeof(struct bz_file)); + if (bzf_tmp == NULL) + return(-1); + bzero(bzf_tmp, sizeof(struct bz_file)); + bzf_tmp->bzf_rawfd = bzf->bzf_rawfd; + + /* Initialise the inflation engine */ + if (BZ2_bzDecompressInit(&(bzf_tmp->bzf_bzstream), 0, 1) != BZ_OK) { + free(bzf_tmp); + return(-1); + } + + /* Seek back to the beginning of the file */ + if (lseek(bzf->bzf_rawfd, 0, SEEK_SET) == -1) { + BZ2_bzDecompressEnd(&(bzf_tmp->bzf_bzstream)); + free(bzf_tmp); + return(-1); + } + + /* Free old bz_file data */ + BZ2_bzDecompressEnd(&(bzf->bzf_bzstream)); + free(bzf); + + /* Use the new bz_file data */ + f->f_fsdata = bzf_tmp; + + return(0); +} + static off_t bzf_seek(struct open_file *f, off_t offset, int where) { @@ -264,14 +332,17 @@ bzf_seek(struct open_file *f, off_t offs target = -1; default: errno = EINVAL; - return (-1); + return(-1); } /* Can we get there from here? */ - if (target < bzf->bzf_bzstream.total_out_lo32) { + if (target < bzf->bzf_bzstream.total_out_lo32 && bzf_rewind(f) != 0) { errno = EOFFSET; return -1; - } + } + + /* if bzf_rewind was called then bzf has changed */ + bzf = (struct bz_file *)f->f_fsdata; /* skip forwards if required */ while (target > bzf->bzf_bzstream.total_out_lo32) { @@ -281,7 +352,7 @@ bzf_seek(struct open_file *f, off_t offs return(-1); } /* This is where we are (be honest if we overshot) */ - return (bzf->bzf_bzstream.total_out_lo32); + return(bzf->bzf_bzstream.total_out_lo32); } static int @@ -301,3 +372,27 @@ bz_internal_error(int errorcode) { panic("bzipfs: critical error %d in bzip2 library occured\n", errorcode); } + +#ifdef REGRESSION +/* Small test case, open and decompress test.bz2 */ +int main() +{ + struct open_file f; + char buf[1024]; + size_t resid; + int err; + + memset(&f, '\0', sizeof(f)); + f.f_flags = F_READ; + err = bzf_open("test", &f); + if (err != 0) + exit(1); + do { + err = bzf_read(&f, buf, sizeof(buf), &resid); + } while (err == 0 && resid != sizeof(buf)); + + if (err != 0) + exit(2); + exit(0); +} +#endif Modified: stable/7/lib/libstand/gzipfs.c ============================================================================== --- stable/7/lib/libstand/gzipfs.c Wed Dec 30 17:53:07 2009 (r201267) +++ stable/7/lib/libstand/gzipfs.c Wed Dec 30 17:55:20 2009 (r201268) @@ -41,6 +41,7 @@ struct z_file off_t zf_dataoffset; z_stream zf_zstream; char zf_buf[Z_BUFSIZE]; + int zf_endseen; }; static int zf_fill(struct z_file *z); @@ -211,10 +212,9 @@ zf_open(const char *fname, struct open_f bzero(zf, sizeof(struct z_file)); zf->zf_rawfd = rawfd; - /* Verify that the file is gzipped (XXX why do this afterwards?) */ + /* Verify that the file is gzipped */ if (check_header(zf)) { close(zf->zf_rawfd); - inflateEnd(&(zf->zf_zstream)); free(zf); return(EFTYPE); } @@ -252,7 +252,7 @@ zf_read(struct open_file *f, void *buf, zf->zf_zstream.next_out = buf; /* where and how much */ zf->zf_zstream.avail_out = size; - while (zf->zf_zstream.avail_out) { + while (zf->zf_zstream.avail_out && zf->zf_endseen == 0) { if ((zf->zf_zstream.avail_in == 0) && (zf_fill(zf) == -1)) { printf("zf_read: fill error\n"); return(EIO); @@ -260,12 +260,13 @@ zf_read(struct open_file *f, void *buf, if (zf->zf_zstream.avail_in == 0) { /* oops, unexpected EOF */ printf("zf_read: unexpected EOF\n"); if (zf->zf_zstream.avail_out == size) - return (EIO); + return(EIO); break; } error = inflate(&zf->zf_zstream, Z_SYNC_FLUSH); /* decompression pass */ if (error == Z_STREAM_END) { /* EOF, all done */ + zf->zf_endseen = 1; break; } if (error != Z_OK) { /* argh, decompression error */ @@ -284,12 +285,13 @@ zf_rewind(struct open_file *f) struct z_file *zf = (struct z_file *)f->f_fsdata; if (lseek(zf->zf_rawfd, zf->zf_dataoffset, SEEK_SET) == -1) - return -1; + return(-1); zf->zf_zstream.avail_in = 0; zf->zf_zstream.next_in = NULL; + zf->zf_endseen = 0; (void)inflateReset(&zf->zf_zstream); - return 0; + return(0); } static off_t @@ -310,12 +312,12 @@ zf_seek(struct open_file *f, off_t offse target = -1; default: errno = EINVAL; - return (-1); + return(-1); } /* rewind if required */ if (target < zf->zf_zstream.total_out && zf_rewind(f) != 0) - return -1; + return(-1); /* skip forwards if required */ while (target > zf->zf_zstream.total_out) { @@ -325,7 +327,7 @@ zf_seek(struct open_file *f, off_t offse return(-1); } /* This is where we are (be honest if we overshot) */ - return (zf->zf_zstream.total_out); + return(zf->zf_zstream.total_out); }