svn commit: r201268 - stable/7/lib/libstand
John Baldwin
jhb at FreeBSD.org
Wed Dec 30 17:55:21 UTC 2009
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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#ifndef REGRESSION
#include "stand.h"
+#else
+#include <stdlib.h>
+#include <sys/errno.h>
+#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <sys/unistd.h>
+
+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 <sys/stat.h>
#include <string.h>
@@ -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);
}
More information about the svn-src-stable-7
mailing list