2 * Copyright (c) 1998 Michael Smith.
3 * Copyright (c) 2000 Maxim Sobolev
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
37 #define BZ_BUFSIZE 2048 /* XXX larger? */
42 bz_stream bzf_bzstream;
43 char bzf_buf[BZ_BUFSIZE];
46 static int bzf_fill(struct bz_file *z);
47 static int bzf_open(const char *path, struct open_file *f);
48 static int bzf_close(struct open_file *f);
49 static int bzf_read(struct open_file *f, void *buf, size_t size, size_t *resid);
50 static off_t bzf_seek(struct open_file *f, off_t offset, int where);
51 static int bzf_stat(struct open_file *f, struct stat *sb);
53 struct fs_ops bzipfs_fsops = {
66 calloc(int items, size_t size)
68 return(malloc(items * size));
73 bzf_fill(struct bz_file *bzf)
78 req = BZ_BUFSIZE - bzf->bzf_bzstream.avail_in;
83 /* move old data to bottom of buffer */
85 bcopy(bzf->bzf_buf + req, bzf->bzf_buf, BZ_BUFSIZE - req);
87 /* read to fill buffer and update availibility data */
88 result = read(bzf->bzf_rawfd, bzf->bzf_buf + bzf->bzf_bzstream.avail_in, req);
89 bzf->bzf_bzstream.next_in = bzf->bzf_buf;
91 bzf->bzf_bzstream.avail_in += result;
97 * Adapted from get_byte/check_header in libz
99 * Returns 0 if the header is OK, nonzero if not.
102 get_byte(struct bz_file *bzf)
104 if ((bzf->bzf_bzstream.avail_in == 0) && (bzf_fill(bzf) == -1))
106 bzf->bzf_bzstream.avail_in--;
107 return(*(bzf->bzf_bzstream.next_in)++);
110 static int bz_magic[3] = {'B', 'Z', 'h'}; /* bzip2 magic header */
113 check_header(struct bz_file *bzf)
118 /* Check the bzip2 magic header */
119 for (len = 0; len < 3; len++) {
121 if (c != bz_magic[len]) {
125 /* Check that the block size is valid */
127 if (c < '1' || c > '9')
130 /* Put back bytes that we've took from the input stream */
131 bzf->bzf_bzstream.next_in -= 4;
132 bzf->bzf_bzstream.avail_in += 4;
138 bzf_open(const char *fname, struct open_file *f)
140 static char *bzfname;
147 /* Have to be in "just read it" mode */
148 if (f->f_flags != F_READ)
151 /* If the name already ends in .gz or .bz2, ignore it */
152 if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".gz")
153 || !strcmp(cp, ".bz2")))
156 /* Construct new name */
157 bzfname = malloc(strlen(fname) + 5);
158 sprintf(bzfname, "%s.bz2", fname);
160 /* Try to open the compressed datafile */
161 rawfd = open(bzfname, O_RDONLY);
166 if (fstat(rawfd, &sb) < 0) {
167 printf("bzf_open: stat failed\n");
171 if (!S_ISREG(sb.st_mode)) {
172 printf("bzf_open: not a file\n");
174 return(EISDIR); /* best guess */
177 /* Allocate a bz_file structure, populate it */
178 bzf = malloc(sizeof(struct bz_file));
179 bzero(bzf, sizeof(struct bz_file));
180 bzf->bzf_rawfd = rawfd;
182 /* Verify that the file is bzipped (XXX why do this afterwards?) */
183 if (check_header(bzf)) {
184 close(bzf->bzf_rawfd);
185 BZ2_bzDecompressEnd(&(bzf->bzf_bzstream));
190 /* Initialise the inflation engine */
191 if ((error = BZ2_bzDecompressInit(&(bzf->bzf_bzstream), 0, 1)) != BZ_OK) {
192 printf("bzf_open: BZ2_bzDecompressInit returned %d\n", error);
193 close(bzf->bzf_rawfd);
198 /* Looks OK, we'll take it */
204 bzf_close(struct open_file *f)
206 struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
208 BZ2_bzDecompressEnd(&(bzf->bzf_bzstream));
209 close(bzf->bzf_rawfd);
215 bzf_read(struct open_file *f, void *buf, size_t size, size_t *resid)
217 struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
220 bzf->bzf_bzstream.next_out = buf; /* where and how much */
221 bzf->bzf_bzstream.avail_out = size;
223 while (bzf->bzf_bzstream.avail_out) {
224 if ((bzf->bzf_bzstream.avail_in == 0) && (bzf_fill(bzf) == -1)) {
225 printf("bzf_read: fill error\n");
228 if (bzf->bzf_bzstream.avail_in == 0) { /* oops, unexpected EOF */
229 printf("bzf_read: unexpected EOF\n");
233 error = BZ2_bzDecompress(&bzf->bzf_bzstream); /* decompression pass */
234 if (error == BZ_STREAM_END) { /* EOF, all done */
237 if (error != BZ_OK) { /* argh, decompression error */
238 printf("bzf_read: BZ2_bzDecompress returned %d\n", error);
244 *resid = bzf->bzf_bzstream.avail_out;
249 bzf_seek(struct open_file *f, off_t offset, int where)
251 struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
260 target = offset + bzf->bzf_bzstream.total_out_lo32;
266 /* Can we get there from here? */
267 if (target < bzf->bzf_bzstream.total_out_lo32) {
272 /* skip forwards if required */
273 while (target > bzf->bzf_bzstream.total_out_lo32) {
274 if (bzf_read(f, discard, min(sizeof(discard), target - bzf->bzf_bzstream.total_out_lo32), NULL) == -1)
277 /* This is where we are (be honest if we overshot) */
278 return (bzf->bzf_bzstream.total_out_lo32);
282 bzf_stat(struct open_file *f, struct stat *sb)
284 struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
287 /* stat as normal, but indicate that size is unknown */
288 if ((result = fstat(bzf->bzf_rawfd, sb)) == 0)
294 bz_internal_error(int errorcode)
296 panic("bzipfs: critical error %d in bzip2 library occured\n", errorcode);