Boot loader fixes - fix recursive malloc()/free() errors, NULL freed fields
[dragonfly.git] / lib / libstand / bzipfs.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 1998 Michael Smith.
3 * Copyright (c) 2000 Maxim Sobolev
4 * All rights reserved.
5 *
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.
14 *
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.
26 *
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 $
29 *
30 */
31
32#include "stand.h"
33
34#include <sys/stat.h>
35#include <string.h>
36#include <bzlib.h>
37
38#define BZ_BUFSIZE 2048 /* XXX larger? */
39
40struct bz_file
41{
42 int bzf_rawfd;
43 bz_stream bzf_bzstream;
44 char bzf_buf[BZ_BUFSIZE];
45};
46
47static int bzf_fill(struct bz_file *z);
48static int bzf_open(const char *path, struct open_file *f);
49static int bzf_close(struct open_file *f);
50static int bzf_read(struct open_file *f, void *buf, size_t size, size_t *resid);
51static off_t bzf_seek(struct open_file *f, off_t offset, int where);
52static int bzf_stat(struct open_file *f, struct stat *sb);
53
54struct 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
63};
64
65#if 0
66void *
67calloc(int items, size_t size)
68{
69 return(malloc(items * size));
70}
71#endif
72
73static int
74bzf_fill(struct bz_file *bzf)
75{
76 int result;
77 int req;
78
79 req = BZ_BUFSIZE - bzf->bzf_bzstream.avail_in;
80 result = 0;
81
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);
87
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;
93 }
94 return(result);
95}
96
97/*
98 * Adapted from get_byte/check_header in libz
99 *
100 * Returns 0 if the header is OK, nonzero if not.
101 */
102static int
103get_byte(struct bz_file *bzf)
104{
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)++);
109}
110
111static int bz_magic[3] = {'B', 'Z', 'h'}; /* bzip2 magic header */
112
113static int
114check_header(struct bz_file *bzf)
115{
116 unsigned int len;
117 int c;
118
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);
124 }
125 }
126 /* Check that the block size is valid */
127 c = get_byte(bzf);
128 if (c < '1' || c > '9')
129 return(1);
130
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;
134
135 return(0);
136}
137
138static int
139bzf_open(const char *fname, struct open_file *f)
140{
141 static char *bzfname;
142 int rawfd;
143 struct bz_file *bzf;
144 char *cp;
145 int error;
146 struct stat sb;
147
148 /* Have to be in "just read it" mode */
149 if (f->f_flags != F_READ)
150 return(EPERM);
151
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);
156
157 /* Construct new name */
158 bzfname = malloc(strlen(fname) + 5);
159 sprintf(bzfname, "%s.bz2", fname);
160
161 /* Try to open the compressed datafile */
162 rawfd = open(bzfname, O_RDONLY);
163 free(bzfname);
164 if (rawfd == -1)
165 return(ENOENT);
166
167 if (fstat(rawfd, &sb) < 0) {
168 printf("bzf_open: stat failed\n");
169 close(rawfd);
170 return(ENOENT);
171 }
172 if (!S_ISREG(sb.st_mode)) {
173 printf("bzf_open: not a file\n");
174 close(rawfd);
175 return(EISDIR); /* best guess */
176 }
177
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;
182
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);
189 }
190
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);
197 }
198
199 /* Looks OK, we'll take it */
200 f->f_fsdata = bzf;
201 return(0);
202}
203
204static int
205bzf_close(struct open_file *f)
206{
207 struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
208
209 f->f_fsdata = NULL;
210 if (bzf) {
211 BZ2_bzDecompressEnd(&(bzf->bzf_bzstream));
212 close(bzf->bzf_rawfd);
213 free(bzf);
214 }
215 return(0);
216}
217
218static int
219bzf_read(struct open_file *f, void *buf, size_t size, size_t *resid)
220{
221 struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
222 int error;
223
224 bzf->bzf_bzstream.next_out = buf; /* where and how much */
225 bzf->bzf_bzstream.avail_out = size;
226
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);
231 }
232 if (bzf->bzf_bzstream.avail_in == 0) { /* oops, unexpected EOF */
233 printf("bzf_read: unexpected EOF\n");
234 break;
235 }
236
237 error = BZ2_bzDecompress(&bzf->bzf_bzstream); /* decompression pass */
238 if (error == BZ_STREAM_END) { /* EOF, all done */
239 break;
240 }
241 if (error != BZ_OK) { /* argh, decompression error */
242 printf("bzf_read: BZ2_bzDecompress returned %d\n", error);
243 errno = EIO;
244 return(-1);
245 }
246 }
247 if (resid != NULL)
248 *resid = bzf->bzf_bzstream.avail_out;
249 return(0);
250}
251
252static off_t
253bzf_seek(struct open_file *f, off_t offset, int where)
254{
255 struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
256 off_t target;
257 char discard[16];
258
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;
268 }
269
270 /* Can we get there from here? */
271 if (target < bzf->bzf_bzstream.total_out_lo32) {
272 errno = EOFFSET;
273 return -1;
274 }
275
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);
280 }
281 /* This is where we are (be honest if we overshot) */
282 return (bzf->bzf_bzstream.total_out_lo32);
283}
284
285static int
286bzf_stat(struct open_file *f, struct stat *sb)
287{
288 struct bz_file *bzf = (struct bz_file *)f->f_fsdata;
289 int result;
290
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);
295}
296
297void
298bz_internal_error(int errorcode)
299{
300 panic("bzipfs: critical error %d in bzip2 library occurred\n", errorcode);
301}