Unbreak GENERIC building
[dragonfly.git] / lib / libstand / bzipfs.c
blob7de3a8ce798df08423c1750423df7922d285de4f
1 /*
2 * Copyright (c) 1998 Michael Smith.
3 * Copyright (c) 2000 Maxim Sobolev
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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
25 * SUCH DAMAGE.
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 $
32 #include "stand.h"
34 #include <sys/stat.h>
35 #include <string.h>
36 #include <bzlib.h>
38 #define BZ_BUFSIZE 2048 /* XXX larger? */
40 struct bz_file
42 int bzf_rawfd;
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 = {
55 "bzip",
56 bzf_open,
57 bzf_close,
58 bzf_read,
59 null_write,
60 bzf_seek,
61 bzf_stat,
62 null_readdir
65 #if 0
66 void *
67 calloc(int items, size_t size)
69 return(malloc(items * size));
71 #endif
73 static int
74 bzf_fill(struct bz_file *bzf)
76 int result;
77 int req;
79 req = BZ_BUFSIZE - bzf->bzf_bzstream.avail_in;
80 result = 0;
82 /* If we need more */
83 if (req > 0) {
84 /* move old data to bottom of buffer */
85 if (req < BZ_BUFSIZE)
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;
91 if (result >= 0)
92 bzf->bzf_bzstream.avail_in += result;
94 return(result);
98 * Adapted from get_byte/check_header in libz
100 * Returns 0 if the header is OK, nonzero if not.
102 static int
103 get_byte(struct bz_file *bzf)
105 if ((bzf->bzf_bzstream.avail_in == 0) && (bzf_fill(bzf) == -1))
106 return(-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 */
113 static int
114 check_header(struct bz_file *bzf)
116 unsigned int len;
117 int c;
119 /* Check the bzip2 magic header */
120 for (len = 0; len < 3; len++) {
121 c = get_byte(bzf);
122 if (c != bz_magic[len]) {
123 return(1);
126 /* Check that the block size is valid */
127 c = get_byte(bzf);
128 if (c < '1' || c > '9')
129 return(1);
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;
135 return(0);
138 static int
139 bzf_open(const char *fname, struct open_file *f)
141 static char *bzfname;
142 int rawfd;
143 struct bz_file *bzf;
144 char *cp;
145 int error;
146 struct stat sb;
148 /* Have to be in "just read it" mode */
149 if (f->f_flags != F_READ)
150 return(EPERM);
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")))
155 return(ENOENT);
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);
163 free(bzfname);
164 if (rawfd == -1)
165 return(ENOENT);
167 if (fstat(rawfd, &sb) < 0) {
168 printf("bzf_open: stat failed\n");
169 close(rawfd);
170 return(ENOENT);
172 if (!S_ISREG(sb.st_mode)) {
173 printf("bzf_open: not a file\n");
174 close(rawfd);
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));
187 free(bzf);
188 return(EFTYPE);
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);
195 free(bzf);
196 return(EIO);
199 /* Looks OK, we'll take it */
200 f->f_fsdata = bzf;
201 return(0);
204 static int
205 bzf_close(struct open_file *f)
207 struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
209 f->f_fsdata = NULL;
210 if (bzf) {
211 BZ2_bzDecompressEnd(&(bzf->bzf_bzstream));
212 close(bzf->bzf_rawfd);
213 free(bzf);
215 return(0);
218 static int
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;
222 int error;
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");
230 return(-1);
232 if (bzf->bzf_bzstream.avail_in == 0) { /* oops, unexpected EOF */
233 printf("bzf_read: unexpected EOF\n");
234 break;
237 error = BZ2_bzDecompress(&bzf->bzf_bzstream); /* decompression pass */
238 if (error == BZ_STREAM_END) { /* EOF, all done */
239 break;
241 if (error != BZ_OK) { /* argh, decompression error */
242 printf("bzf_read: BZ2_bzDecompress returned %d\n", error);
243 errno = EIO;
244 return(-1);
247 if (resid != NULL)
248 *resid = bzf->bzf_bzstream.avail_out;
249 return(0);
252 static off_t
253 bzf_seek(struct open_file *f, off_t offset, int where)
255 struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
256 off_t target;
257 char discard[16];
259 switch (where) {
260 case SEEK_SET:
261 target = offset;
262 break;
263 case SEEK_CUR:
264 target = offset + bzf->bzf_bzstream.total_out_lo32;
265 break;
266 default:
267 target = -1;
270 /* Can we get there from here? */
271 if (target < bzf->bzf_bzstream.total_out_lo32) {
272 errno = EOFFSET;
273 return -1;
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)
279 return(-1);
281 /* This is where we are (be honest if we overshot) */
282 return (bzf->bzf_bzstream.total_out_lo32);
285 static int
286 bzf_stat(struct open_file *f, struct stat *sb)
288 struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
289 int result;
291 /* stat as normal, but indicate that size is unknown */
292 if ((result = fstat(bzf->bzf_rawfd, sb)) == 0)
293 sb->st_size = -1;
294 return(result);
297 void
298 bz_internal_error(int errorcode)
300 panic("bzipfs: critical error %d in bzip2 library occurred\n", errorcode);