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
This commit is contained in:
John Baldwin 2009-12-23 21:11:03 +00:00
parent 36fd650f09
commit 59ab6724a4
2 changed files with 67 additions and 16 deletions

View File

@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
#ifndef REGRESSION
#include "stand.h"
#else
#include <stdlib.h>
#include <sys/errno.h>
#include <sys/fcntl.h>
#include <sys/types.h>
@ -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

View File

@ -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);
}