1 /*- 2 * Copyright (c) 1998 Michael Smith. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: src/lib/libstand/gzipfs.c,v 1.11 2002/12/19 19:34:58 jake Exp $ 27 */ 28 29 #include "stand.h" 30 31 #include <sys/stat.h> 32 #include <string.h> 33 #include <zlib.h> 34 35 #define Z_BUFSIZE 2048 /* XXX larger? */ 36 37 struct z_file 38 { 39 int zf_rawfd; 40 z_stream zf_zstream; 41 char zf_buf[Z_BUFSIZE]; 42 }; 43 44 static int zf_fill(struct z_file *z); 45 static int zf_open(const char *path, struct open_file *f); 46 static int zf_close(struct open_file *f); 47 static int zf_read(struct open_file *f, void *buf, size_t size, size_t *resid); 48 static off_t zf_seek(struct open_file *f, off_t offset, int where); 49 static int zf_stat(struct open_file *f, struct stat *sb); 50 51 struct fs_ops gzipfs_fsops = { 52 "zip", 53 zf_open, 54 zf_close, 55 zf_read, 56 null_write, 57 zf_seek, 58 zf_stat, 59 null_readdir 60 }; 61 62 static int 63 zf_fill(struct z_file *zf) 64 { 65 int result; 66 int req; 67 68 req = Z_BUFSIZE - zf->zf_zstream.avail_in; 69 result = 0; 70 71 /* If we need more */ 72 if (req > 0) { 73 /* move old data to bottom of buffer */ 74 if (req < Z_BUFSIZE) 75 bcopy(zf->zf_buf + req, zf->zf_buf, Z_BUFSIZE - req); 76 77 /* read to fill buffer and update availibility data */ 78 result = read(zf->zf_rawfd, zf->zf_buf + zf->zf_zstream.avail_in, req); 79 zf->zf_zstream.next_in = zf->zf_buf; 80 if (result >= 0) 81 zf->zf_zstream.avail_in += result; 82 } 83 return(result); 84 } 85 86 /* 87 * Adapted from get_byte/check_header in libz 88 * 89 * Returns 0 if the header is OK, nonzero if not. 90 */ 91 static int 92 get_byte(struct z_file *zf) 93 { 94 if ((zf->zf_zstream.avail_in == 0) && (zf_fill(zf) == -1)) 95 return(-1); 96 zf->zf_zstream.avail_in--; 97 return(*(zf->zf_zstream.next_in)++); 98 } 99 100 static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ 101 102 /* gzip flag byte */ 103 #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ 104 #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ 105 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ 106 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ 107 #define COMMENT 0x10 /* bit 4 set: file comment present */ 108 #define RESERVED 0xE0 /* bits 5..7: reserved */ 109 110 static int 111 check_header(struct z_file *zf) 112 { 113 int method; /* method byte */ 114 int flags; /* flags byte */ 115 uInt len; 116 int c; 117 118 /* Check the gzip magic header */ 119 for (len = 0; len < 2; len++) { 120 c = get_byte(zf); 121 if (c != gz_magic[len]) { 122 return(1); 123 } 124 } 125 method = get_byte(zf); 126 flags = get_byte(zf); 127 if (method != Z_DEFLATED || (flags & RESERVED) != 0) { 128 return(1); 129 } 130 131 /* Discard time, xflags and OS code: */ 132 for (len = 0; len < 6; len++) (void)get_byte(zf); 133 134 if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ 135 len = (uInt)get_byte(zf); 136 len += ((uInt)get_byte(zf))<<8; 137 /* len is garbage if EOF but the loop below will quit anyway */ 138 while (len-- != 0 && get_byte(zf) != -1) ; 139 } 140 if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ 141 while ((c = get_byte(zf)) != 0 && c != -1) ; 142 } 143 if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ 144 while ((c = get_byte(zf)) != 0 && c != -1) ; 145 } 146 if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ 147 for (len = 0; len < 2; len++) c = get_byte(zf); 148 } 149 /* if there's data left, we're in business */ 150 return((c == -1) ? 1 : 0); 151 } 152 153 static int 154 zf_open(const char *fname, struct open_file *f) 155 { 156 char *zfname; 157 int rawfd; 158 struct z_file *zf; 159 char *cp; 160 int error; 161 struct stat sb; 162 163 /* Have to be in "just read it" mode */ 164 if ((f->f_flags & (F_READ | F_WRITE)) != F_READ) 165 return(EPERM); 166 167 /* If the name already ends in .gz or .bz2, ignore it */ 168 if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".gz") 169 || !strcmp(cp, ".bz2") || !strcmp(cp, ".split"))) 170 return(ENOENT); 171 172 /* Construct new name */ 173 zfname = malloc(strlen(fname) + 4); 174 if (zfname == NULL) 175 return(ENOMEM); 176 sprintf(zfname, "%s.gz", fname); 177 178 /* Try to open the compressed datafile */ 179 rawfd = open(zfname, O_RDONLY); 180 free(zfname); 181 if (rawfd == -1) 182 return(ENOENT); 183 184 if (fstat(rawfd, &sb) < 0) { 185 printf("zf_open: stat failed\n"); 186 close(rawfd); 187 return(ENOENT); 188 } 189 if (!S_ISREG(sb.st_mode)) { 190 printf("zf_open: not a file\n"); 191 close(rawfd); 192 return(EISDIR); /* best guess */ 193 } 194 195 /* Allocate a z_file structure, populate it */ 196 zf = malloc(sizeof(struct z_file)); 197 if (zf == NULL) 198 return(ENOMEM); 199 bzero(zf, sizeof(struct z_file)); 200 zf->zf_rawfd = rawfd; 201 202 /* Verify that the file is gzipped (XXX why do this afterwards?) */ 203 if (check_header(zf)) { 204 close(zf->zf_rawfd); 205 inflateEnd(&(zf->zf_zstream)); 206 free(zf); 207 return(EFTYPE); 208 } 209 210 /* Initialise the inflation engine */ 211 if ((error = inflateInit2(&(zf->zf_zstream), -15)) != Z_OK) { 212 printf("zf_open: inflateInit returned %d : %s\n", error, zf->zf_zstream.msg); 213 close(zf->zf_rawfd); 214 free(zf); 215 return(EIO); 216 } 217 218 /* Looks OK, we'll take it */ 219 f->f_fsdata = zf; 220 return(0); 221 } 222 223 static int 224 zf_close(struct open_file *f) 225 { 226 struct z_file *zf = (struct z_file *)f->f_fsdata; 227 228 f->f_fsdata = NULL; 229 if (zf) { 230 inflateEnd(&(zf->zf_zstream)); 231 close(zf->zf_rawfd); 232 free(zf); 233 } 234 return(0); 235 } 236 237 static int 238 zf_read(struct open_file *f, void *buf, size_t size, size_t *resid) 239 { 240 struct z_file *zf = (struct z_file *)f->f_fsdata; 241 int error; 242 243 zf->zf_zstream.next_out = buf; /* where and how much */ 244 zf->zf_zstream.avail_out = size; 245 246 while (zf->zf_zstream.avail_out) { 247 if ((zf->zf_zstream.avail_in == 0) && (zf_fill(zf) == -1)) { 248 printf("zf_read: fill error\n"); 249 return(-1); 250 } 251 if (zf->zf_zstream.avail_in == 0) { /* oops, unexpected EOF */ 252 printf("zf_read: unexpected EOF\n"); 253 break; 254 } 255 256 error = inflate(&zf->zf_zstream, Z_SYNC_FLUSH); /* decompression pass */ 257 if (error == Z_STREAM_END) { /* EOF, all done */ 258 break; 259 } 260 if (error != Z_OK) { /* argh, decompression error */ 261 printf("inflate: %s\n", zf->zf_zstream.msg); 262 errno = EIO; 263 return(-1); 264 } 265 } 266 if (resid != NULL) 267 *resid = zf->zf_zstream.avail_out; 268 return(0); 269 } 270 271 static off_t 272 zf_seek(struct open_file *f, off_t offset, int where) 273 { 274 struct z_file *zf = (struct z_file *)f->f_fsdata; 275 off_t target; 276 char discard[16]; 277 278 switch (where) { 279 case SEEK_SET: 280 target = offset; 281 break; 282 case SEEK_CUR: 283 target = offset + zf->zf_zstream.total_out; 284 break; 285 default: 286 target = -1; 287 } 288 289 /* Can we get there from here? */ 290 if (target < zf->zf_zstream.total_out) { 291 errno = EOFFSET; 292 return -1; 293 } 294 295 /* skip forwards if required */ 296 while (target > zf->zf_zstream.total_out) { 297 if (zf_read(f, discard, min(sizeof(discard), target - zf->zf_zstream.total_out), NULL) == -1) 298 return(-1); 299 } 300 /* This is where we are (be honest if we overshot) */ 301 return (zf->zf_zstream.total_out); 302 } 303 304 static int 305 zf_stat(struct open_file *f, struct stat *sb) 306 { 307 struct z_file *zf = (struct z_file *)f->f_fsdata; 308 int result; 309 310 /* stat as normal, but indicate that size is unknown */ 311 if ((result = fstat(zf->zf_rawfd, sb)) == 0) 312 sb->st_size = -1; 313 return(result); 314 } 315