From 0ea3a0b2ea0093f6d6b4fad9d2bc4f0936782b36 Mon Sep 17 00:00:00 2001 From: jhb Date: Wed, 23 Dec 2009 21:11:03 +0000 Subject: Fix a bug in gzipfs that prevented lseek() from working and add lseek() support to bzip2fs. This fixes problems with loading compressed amd64 kernel modules containing debug symbols. Submitted by: David Naylor naylor.b.david (gmail) MFC after: 1 week --- lib/libstand/bzipfs.c | 67 +++++++++++++++++++++++++++++++++++++++++++++------ lib/libstand/gzipfs.c | 16 ++++++------ 2 files changed, 67 insertions(+), 16 deletions(-) diff --git a/lib/libstand/bzipfs.c b/lib/libstand/bzipfs.c index 47c799f..46a151b 100644 --- a/lib/libstand/bzipfs.c +++ b/lib/libstand/bzipfs.c @@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$"); #ifndef REGRESSION #include "stand.h" #else +#include #include #include #include @@ -42,7 +43,7 @@ struct open_file { }; #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); } +static inline u_int min(u_int a, u_int b) { return(a < b ? a : b); } #define panic(x, y) abort() #endif @@ -174,6 +175,8 @@ bzf_open(const char *fname, struct open_file *f) /* Construct new name */ bzfname = malloc(strlen(fname) + 5); + if (bzfname == NULL) + return(ENOMEM); sprintf(bzfname, "%s.bz2", fname); /* Try to open the compressed datafile */ @@ -195,13 +198,14 @@ bzf_open(const char *fname, struct open_file *f) /* 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); } @@ -247,7 +251,7 @@ bzf_read(struct open_file *f, void *buf, size_t size, size_t *resid) 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; } @@ -266,6 +270,50 @@ bzf_read(struct open_file *f, void *buf, size_t size, size_t *resid) 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) { @@ -284,14 +332,17 @@ bzf_seek(struct open_file *f, off_t offset, int where) 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) { @@ -301,7 +352,7 @@ bzf_seek(struct open_file *f, off_t offset, int where) 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 diff --git a/lib/libstand/gzipfs.c b/lib/libstand/gzipfs.c index 4f40a4a..9ff7985 100644 --- a/lib/libstand/gzipfs.c +++ b/lib/libstand/gzipfs.c @@ -212,10 +212,9 @@ zf_open(const char *fname, struct open_file *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); } @@ -261,7 +260,7 @@ zf_read(struct open_file *f, void *buf, size_t size, size_t *resid) 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; } @@ -286,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 @@ -312,12 +312,12 @@ zf_seek(struct open_file *f, off_t offset, int where) 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) { @@ -327,7 +327,7 @@ zf_seek(struct open_file *f, off_t offset, int where) return(-1); } /* This is where we are (be honest if we overshot) */ - return (zf->zf_zstream.total_out); + return(zf->zf_zstream.total_out); } -- cgit v1.1