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 40 struct bz_file 41 { 42 int bzf_rawfd; 43 bz_stream bzf_bzstream; 44 char bzf_buf[BZ_BUFSIZE]; 45 }; 46 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); 53 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 63 }; 64 65 #if 0 66 void * 67 calloc(int items, size_t size) 68 { 69 return(malloc(items * size)); 70 } 71 #endif 72 73 static int 74 bzf_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 */ 102 static int 103 get_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 111 static int bz_magic[3] = {'B', 'Z', 'h'}; /* bzip2 magic header */ 112 113 static int 114 check_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 138 static int 139 bzf_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 | F_WRITE)) != 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 204 static int 205 bzf_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 218 static int 219 bzf_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 252 static off_t 253 bzf_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 285 static int 286 bzf_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 297 void 298 bz_internal_error(int errorcode) 299 { 300 panic("bzipfs: critical error %d in bzip2 library occurred\n", errorcode); 301 } 302