199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Copyright (c) 1998 Michael Smith.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Copyright (c) 2000 Maxim Sobolev
199767f8919635c4928607450d9e0abb932109ceToomas Soome * All rights reserved.
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Redistribution and use in source and binary forms, with or without
199767f8919635c4928607450d9e0abb932109ceToomas Soome * modification, are permitted provided that the following conditions
199767f8919635c4928607450d9e0abb932109ceToomas Soome * are met:
199767f8919635c4928607450d9e0abb932109ceToomas Soome * 1. Redistributions of source code must retain the above copyright
199767f8919635c4928607450d9e0abb932109ceToomas Soome * notice, this list of conditions and the following disclaimer.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
199767f8919635c4928607450d9e0abb932109ceToomas Soome * notice, this list of conditions and the following disclaimer in the
199767f8919635c4928607450d9e0abb932109ceToomas Soome * documentation and/or other materials provided with the distribution.
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
199767f8919635c4928607450d9e0abb932109ceToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
199767f8919635c4928607450d9e0abb932109ceToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
199767f8919635c4928607450d9e0abb932109ceToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
199767f8919635c4928607450d9e0abb932109ceToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
199767f8919635c4928607450d9e0abb932109ceToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
199767f8919635c4928607450d9e0abb932109ceToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
199767f8919635c4928607450d9e0abb932109ceToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
199767f8919635c4928607450d9e0abb932109ceToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
199767f8919635c4928607450d9e0abb932109ceToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
199767f8919635c4928607450d9e0abb932109ceToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
199767f8919635c4928607450d9e0abb932109ceToomas Soome * SUCH DAMAGE.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/cdefs.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome__FBSDID("$FreeBSD$");
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#ifndef REGRESSION
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include "stand.h"
199767f8919635c4928607450d9e0abb932109ceToomas Soome#else
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <stdlib.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/errno.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/fcntl.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/types.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/unistd.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct open_file {
199767f8919635c4928607450d9e0abb932109ceToomas Soome int f_flags; /* see F_* below */
199767f8919635c4928607450d9e0abb932109ceToomas Soome void *f_fsdata; /* file system specific data */
199767f8919635c4928607450d9e0abb932109ceToomas Soome};
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define F_READ 0x0001 /* file opened for reading */
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define EOFFSET (ELAST+8) /* relative seek not supported */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic inline u_int min(u_int a, u_int b) { return(a < b ? a : b); }
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define panic(x, y) abort()
199767f8919635c4928607450d9e0abb932109ceToomas Soome#endif
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/stat.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <string.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <bzlib.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define BZ_BUFSIZE 2048 /* XXX larger? */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct bz_file
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome int bzf_rawfd;
199767f8919635c4928607450d9e0abb932109ceToomas Soome bz_stream bzf_bzstream;
199767f8919635c4928607450d9e0abb932109ceToomas Soome char bzf_buf[BZ_BUFSIZE];
199767f8919635c4928607450d9e0abb932109ceToomas Soome int bzf_endseen;
199767f8919635c4928607450d9e0abb932109ceToomas Soome};
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bzf_fill(struct bz_file *z);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bzf_open(const char *path, struct open_file *f);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bzf_close(struct open_file *f);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bzf_read(struct open_file *f, void *buf, size_t size, size_t *resid);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic off_t bzf_seek(struct open_file *f, off_t offset, int where);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bzf_stat(struct open_file *f, struct stat *sb);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#ifndef REGRESSION
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct fs_ops bzipfs_fsops = {
199767f8919635c4928607450d9e0abb932109ceToomas Soome "bzip",
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzf_open,
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzf_close,
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzf_read,
199767f8919635c4928607450d9e0abb932109ceToomas Soome null_write,
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzf_seek,
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzf_stat,
199767f8919635c4928607450d9e0abb932109ceToomas Soome null_readdir
199767f8919635c4928607450d9e0abb932109ceToomas Soome};
199767f8919635c4928607450d9e0abb932109ceToomas Soome#endif
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomebzf_fill(struct bz_file *bzf)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome int result;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int req;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome req = BZ_BUFSIZE - bzf->bzf_bzstream.avail_in;
199767f8919635c4928607450d9e0abb932109ceToomas Soome result = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* If we need more */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (req > 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* move old data to bottom of buffer */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (req < BZ_BUFSIZE)
199767f8919635c4928607450d9e0abb932109ceToomas Soome bcopy(bzf->bzf_buf + req, bzf->bzf_buf, BZ_BUFSIZE - req);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* read to fill buffer and update availibility data */
199767f8919635c4928607450d9e0abb932109ceToomas Soome result = read(bzf->bzf_rawfd, bzf->bzf_buf + bzf->bzf_bzstream.avail_in, req);
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzf->bzf_bzstream.next_in = bzf->bzf_buf;
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (result >= 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzf->bzf_bzstream.avail_in += result;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(result);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Adapted from get_byte/check_header in libz
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Returns 0 if the header is OK, nonzero if not.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomeget_byte(struct bz_file *bzf)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((bzf->bzf_bzstream.avail_in == 0) && (bzf_fill(bzf) == -1))
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzf->bzf_bzstream.avail_in--;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(*(bzf->bzf_bzstream.next_in)++);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int bz_magic[3] = {'B', 'Z', 'h'}; /* bzip2 magic header */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomecheck_header(struct bz_file *bzf)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome unsigned int len;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int c;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Check the bzip2 magic header */
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (len = 0; len < 3; len++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome c = get_byte(bzf);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (c != bz_magic[len]) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Check that the block size is valid */
199767f8919635c4928607450d9e0abb932109ceToomas Soome c = get_byte(bzf);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (c < '1' || c > '9')
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Put back bytes that we've took from the input stream */
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzf->bzf_bzstream.next_in -= 4;
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzf->bzf_bzstream.avail_in += 4;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomebzf_open(const char *fname, struct open_file *f)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome static char *bzfname;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int rawfd;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct bz_file *bzf;
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *cp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int error;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct stat sb;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Have to be in "just read it" mode */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (f->f_flags != F_READ)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(EPERM);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* If the name already ends in .gz or .bz2, ignore it */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".gz")
199767f8919635c4928607450d9e0abb932109ceToomas Soome || !strcmp(cp, ".bz2") || !strcmp(cp, ".split")))
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(ENOENT);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Construct new name */
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzfname = malloc(strlen(fname) + 5);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (bzfname == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(ENOMEM);
199767f8919635c4928607450d9e0abb932109ceToomas Soome sprintf(bzfname, "%s.bz2", fname);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Try to open the compressed datafile */
199767f8919635c4928607450d9e0abb932109ceToomas Soome rawfd = open(bzfname, O_RDONLY);
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(bzfname);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (rawfd == -1)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(ENOENT);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (fstat(rawfd, &sb) < 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("bzf_open: stat failed\n");
199767f8919635c4928607450d9e0abb932109ceToomas Soome close(rawfd);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(ENOENT);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (!S_ISREG(sb.st_mode)) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("bzf_open: not a file\n");
199767f8919635c4928607450d9e0abb932109ceToomas Soome close(rawfd);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(EISDIR); /* best guess */
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Allocate a bz_file structure, populate it */
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzf = malloc(sizeof(struct bz_file));
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (bzf == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(ENOMEM);
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzero(bzf, sizeof(struct bz_file));
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzf->bzf_rawfd = rawfd;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Verify that the file is bzipped */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (check_header(bzf)) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome close(bzf->bzf_rawfd);
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(bzf);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(EFTYPE);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Initialise the inflation engine */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((error = BZ2_bzDecompressInit(&(bzf->bzf_bzstream), 0, 1)) != BZ_OK) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("bzf_open: BZ2_bzDecompressInit returned %d\n", error);
199767f8919635c4928607450d9e0abb932109ceToomas Soome close(bzf->bzf_rawfd);
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(bzf);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(EIO);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Looks OK, we'll take it */
199767f8919635c4928607450d9e0abb932109ceToomas Soome f->f_fsdata = bzf;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomebzf_close(struct open_file *f)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome BZ2_bzDecompressEnd(&(bzf->bzf_bzstream));
199767f8919635c4928607450d9e0abb932109ceToomas Soome close(bzf->bzf_rawfd);
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(bzf);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomebzf_read(struct open_file *f, void *buf, size_t size, size_t *resid)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int error;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzf->bzf_bzstream.next_out = buf; /* where and how much */
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzf->bzf_bzstream.avail_out = size;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (bzf->bzf_bzstream.avail_out && bzf->bzf_endseen == 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((bzf->bzf_bzstream.avail_in == 0) && (bzf_fill(bzf) == -1)) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("bzf_read: fill error\n");
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(EIO);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (bzf->bzf_bzstream.avail_in == 0) { /* oops, unexpected EOF */
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("bzf_read: unexpected EOF\n");
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (bzf->bzf_bzstream.avail_out == size)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(EIO);
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome error = BZ2_bzDecompress(&bzf->bzf_bzstream); /* decompression pass */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (error == BZ_STREAM_END) { /* EOF, all done */
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzf->bzf_endseen = 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (error != BZ_OK) { /* argh, decompression error */
199767f8919635c4928607450d9e0abb932109ceToomas Soome printf("bzf_read: BZ2_bzDecompress returned %d\n", error);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(EIO);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (resid != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome *resid = bzf->bzf_bzstream.avail_out;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomebzf_rewind(struct open_file *f)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct bz_file *bzf_tmp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /*
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Since bzip2 does not have an equivalent inflateReset function a crude
199767f8919635c4928607450d9e0abb932109ceToomas Soome * one needs to be provided. The functions all called in such a way that
199767f8919635c4928607450d9e0abb932109ceToomas Soome * at any time an error occurs a roll back can be done (effectively making
199767f8919635c4928607450d9e0abb932109ceToomas Soome * this rewind 'atomic', either the reset occurs successfully or not at all,
199767f8919635c4928607450d9e0abb932109ceToomas Soome * with no 'undefined' state happening).
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Allocate a bz_file structure, populate it */
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzf_tmp = malloc(sizeof(struct bz_file));
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (bzf_tmp == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzero(bzf_tmp, sizeof(struct bz_file));
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzf_tmp->bzf_rawfd = bzf->bzf_rawfd;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Initialise the inflation engine */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (BZ2_bzDecompressInit(&(bzf_tmp->bzf_bzstream), 0, 1) != BZ_OK) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(bzf_tmp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Seek back to the beginning of the file */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (lseek(bzf->bzf_rawfd, 0, SEEK_SET) == -1) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome BZ2_bzDecompressEnd(&(bzf_tmp->bzf_bzstream));
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(bzf_tmp);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Free old bz_file data */
199767f8919635c4928607450d9e0abb932109ceToomas Soome BZ2_bzDecompressEnd(&(bzf->bzf_bzstream));
199767f8919635c4928607450d9e0abb932109ceToomas Soome free(bzf);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Use the new bz_file data */
199767f8919635c4928607450d9e0abb932109ceToomas Soome f->f_fsdata = bzf_tmp;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic off_t
199767f8919635c4928607450d9e0abb932109ceToomas Soomebzf_seek(struct open_file *f, off_t offset, int where)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
199767f8919635c4928607450d9e0abb932109ceToomas Soome off_t target;
199767f8919635c4928607450d9e0abb932109ceToomas Soome char discard[16];
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome switch (where) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome case SEEK_SET:
199767f8919635c4928607450d9e0abb932109ceToomas Soome target = offset;
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome case SEEK_CUR:
199767f8919635c4928607450d9e0abb932109ceToomas Soome target = offset + bzf->bzf_bzstream.total_out_lo32;
199767f8919635c4928607450d9e0abb932109ceToomas Soome break;
199767f8919635c4928607450d9e0abb932109ceToomas Soome case SEEK_END:
199767f8919635c4928607450d9e0abb932109ceToomas Soome target = -1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome default:
199767f8919635c4928607450d9e0abb932109ceToomas Soome errno = EINVAL;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* Can we get there from here? */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (target < bzf->bzf_bzstream.total_out_lo32 && bzf_rewind(f) != 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome errno = EOFFSET;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return -1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* if bzf_rewind was called then bzf has changed */
199767f8919635c4928607450d9e0abb932109ceToomas Soome bzf = (struct bz_file *)f->f_fsdata;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* skip forwards if required */
199767f8919635c4928607450d9e0abb932109ceToomas Soome while (target > bzf->bzf_bzstream.total_out_lo32) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome errno = bzf_read(f, discard, min(sizeof(discard),
199767f8919635c4928607450d9e0abb932109ceToomas Soome target - bzf->bzf_bzstream.total_out_lo32), NULL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (errno)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(-1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* This is where we are (be honest if we overshot) */
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(bzf->bzf_bzstream.total_out_lo32);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomebzf_stat(struct open_file *f, struct stat *sb)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int result;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* stat as normal, but indicate that size is unknown */
199767f8919635c4928607450d9e0abb932109ceToomas Soome if ((result = fstat(bzf->bzf_rawfd, sb)) == 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome sb->st_size = -1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return(result);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomevoid
199767f8919635c4928607450d9e0abb932109ceToomas Soomebz_internal_error(int errorcode)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome panic("bzipfs: critical error %d in bzip2 library occured\n", errorcode);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#ifdef REGRESSION
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* Small test case, open and decompress test.bz2 */
199767f8919635c4928607450d9e0abb932109ceToomas Soomeint main()
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct open_file f;
199767f8919635c4928607450d9e0abb932109ceToomas Soome char buf[1024];
199767f8919635c4928607450d9e0abb932109ceToomas Soome size_t resid;
199767f8919635c4928607450d9e0abb932109ceToomas Soome int err;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome memset(&f, '\0', sizeof(f));
199767f8919635c4928607450d9e0abb932109ceToomas Soome f.f_flags = F_READ;
199767f8919635c4928607450d9e0abb932109ceToomas Soome err = bzf_open("test", &f);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (err != 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome exit(1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome do {
199767f8919635c4928607450d9e0abb932109ceToomas Soome err = bzf_read(&f, buf, sizeof(buf), &resid);
199767f8919635c4928607450d9e0abb932109ceToomas Soome } while (err == 0 && resid != sizeof(buf));
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (err != 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome exit(2);
199767f8919635c4928607450d9e0abb932109ceToomas Soome exit(0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome#endif