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
27 * $FreeBSD: src/lib/libstand/bzipfs.c,v 1.2.2.3 2002/04/08 13:50:09 sobomax Exp $
28 * $DragonFly: src/lib/libstand/bzipfs.c,v 1.4 2007/05/13 18:33:56 swildner Exp $
38 #define BZ_BUFSIZE 2048 /* XXX larger? */
43 bz_stream bzf_bzstream
;
44 char bzf_buf
[BZ_BUFSIZE
];
47 static int bzf_fill(struct bz_file
*z
);
48 static int bzf_open(const char *path
, struct open_file
*f
);
49 static int bzf_close(struct open_file
*f
);
50 static int bzf_read(struct open_file
*f
, void *buf
, size_t size
, size_t *resid
);
51 static off_t
bzf_seek(struct open_file
*f
, off_t offset
, int where
);
52 static int bzf_stat(struct open_file
*f
, struct stat
*sb
);
54 struct fs_ops bzipfs_fsops
= {
67 calloc(int items
, size_t size
)
69 return(malloc(items
* size
));
74 bzf_fill(struct bz_file
*bzf
)
79 req
= BZ_BUFSIZE
- bzf
->bzf_bzstream
.avail_in
;
84 /* move old data to bottom of buffer */
86 bcopy(bzf
->bzf_buf
+ req
, bzf
->bzf_buf
, BZ_BUFSIZE
- req
);
88 /* read to fill buffer and update availibility data */
89 result
= read(bzf
->bzf_rawfd
, bzf
->bzf_buf
+ bzf
->bzf_bzstream
.avail_in
, req
);
90 bzf
->bzf_bzstream
.next_in
= bzf
->bzf_buf
;
92 bzf
->bzf_bzstream
.avail_in
+= result
;
98 * Adapted from get_byte/check_header in libz
100 * Returns 0 if the header is OK, nonzero if not.
103 get_byte(struct bz_file
*bzf
)
105 if ((bzf
->bzf_bzstream
.avail_in
== 0) && (bzf_fill(bzf
) == -1))
107 bzf
->bzf_bzstream
.avail_in
--;
108 return(*(bzf
->bzf_bzstream
.next_in
)++);
111 static int bz_magic
[3] = {'B', 'Z', 'h'}; /* bzip2 magic header */
114 check_header(struct bz_file
*bzf
)
119 /* Check the bzip2 magic header */
120 for (len
= 0; len
< 3; len
++) {
122 if (c
!= bz_magic
[len
]) {
126 /* Check that the block size is valid */
128 if (c
< '1' || c
> '9')
131 /* Put back bytes that we've took from the input stream */
132 bzf
->bzf_bzstream
.next_in
-= 4;
133 bzf
->bzf_bzstream
.avail_in
+= 4;
139 bzf_open(const char *fname
, struct open_file
*f
)
141 static char *bzfname
;
148 /* Have to be in "just read it" mode */
149 if (f
->f_flags
!= F_READ
)
152 /* If the name already ends in .gz or .bz2, ignore it */
153 if ((cp
= strrchr(fname
, '.')) && (!strcmp(cp
, ".gz")
154 || !strcmp(cp
, ".bz2") || !strcmp(cp
, ".split")))
157 /* Construct new name */
158 bzfname
= malloc(strlen(fname
) + 5);
159 sprintf(bzfname
, "%s.bz2", fname
);
161 /* Try to open the compressed datafile */
162 rawfd
= open(bzfname
, O_RDONLY
);
167 if (fstat(rawfd
, &sb
) < 0) {
168 printf("bzf_open: stat failed\n");
172 if (!S_ISREG(sb
.st_mode
)) {
173 printf("bzf_open: not a file\n");
175 return(EISDIR
); /* best guess */
178 /* Allocate a bz_file structure, populate it */
179 bzf
= malloc(sizeof(struct bz_file
));
180 bzero(bzf
, sizeof(struct bz_file
));
181 bzf
->bzf_rawfd
= rawfd
;
183 /* Verify that the file is bzipped (XXX why do this afterwards?) */
184 if (check_header(bzf
)) {
185 close(bzf
->bzf_rawfd
);
186 BZ2_bzDecompressEnd(&(bzf
->bzf_bzstream
));
191 /* Initialise the inflation engine */
192 if ((error
= BZ2_bzDecompressInit(&(bzf
->bzf_bzstream
), 0, 1)) != BZ_OK
) {
193 printf("bzf_open: BZ2_bzDecompressInit returned %d\n", error
);
194 close(bzf
->bzf_rawfd
);
199 /* Looks OK, we'll take it */
205 bzf_close(struct open_file
*f
)
207 struct bz_file
*bzf
= (struct bz_file
*)f
->f_fsdata
;
211 BZ2_bzDecompressEnd(&(bzf
->bzf_bzstream
));
212 close(bzf
->bzf_rawfd
);
219 bzf_read(struct open_file
*f
, void *buf
, size_t size
, size_t *resid
)
221 struct bz_file
*bzf
= (struct bz_file
*)f
->f_fsdata
;
224 bzf
->bzf_bzstream
.next_out
= buf
; /* where and how much */
225 bzf
->bzf_bzstream
.avail_out
= size
;
227 while (bzf
->bzf_bzstream
.avail_out
) {
228 if ((bzf
->bzf_bzstream
.avail_in
== 0) && (bzf_fill(bzf
) == -1)) {
229 printf("bzf_read: fill error\n");
232 if (bzf
->bzf_bzstream
.avail_in
== 0) { /* oops, unexpected EOF */
233 printf("bzf_read: unexpected EOF\n");
237 error
= BZ2_bzDecompress(&bzf
->bzf_bzstream
); /* decompression pass */
238 if (error
== BZ_STREAM_END
) { /* EOF, all done */
241 if (error
!= BZ_OK
) { /* argh, decompression error */
242 printf("bzf_read: BZ2_bzDecompress returned %d\n", error
);
248 *resid
= bzf
->bzf_bzstream
.avail_out
;
253 bzf_seek(struct open_file
*f
, off_t offset
, int where
)
255 struct bz_file
*bzf
= (struct bz_file
*)f
->f_fsdata
;
264 target
= offset
+ bzf
->bzf_bzstream
.total_out_lo32
;
270 /* Can we get there from here? */
271 if (target
< bzf
->bzf_bzstream
.total_out_lo32
) {
276 /* skip forwards if required */
277 while (target
> bzf
->bzf_bzstream
.total_out_lo32
) {
278 if (bzf_read(f
, discard
, min(sizeof(discard
), target
- bzf
->bzf_bzstream
.total_out_lo32
), NULL
) == -1)
281 /* This is where we are (be honest if we overshot) */
282 return (bzf
->bzf_bzstream
.total_out_lo32
);
286 bzf_stat(struct open_file
*f
, struct stat
*sb
)
288 struct bz_file
*bzf
= (struct bz_file
*)f
->f_fsdata
;
291 /* stat as normal, but indicate that size is unknown */
292 if ((result
= fstat(bzf
->bzf_rawfd
, sb
)) == 0)
298 bz_internal_error(int errorcode
)
300 panic("bzipfs: critical error %d in bzip2 library occurred\n", errorcode
);