1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * "Compressed" file system File: cfe_zlibfs.c 5 * 6 * This is more of a filesystem "hook" than an actual file system. 7 * You can stick it on the front of the chain of file systems 8 * that CFE calls and it will route data read from the 9 * underlying filesystem through ZLIB before passing it up to the 10 * user. 11 * 12 * Author: Mitch Lichtenberg 13 * 14 ********************************************************************* 15 * 16 * Copyright 2000,2001,2002,2003 17 * Broadcom Corporation. All rights reserved. 18 * 19 * This software is furnished under license and may be used and 20 * copied only in accordance with the following terms and 21 * conditions. Subject to these conditions, you may download, 22 * copy, install, use, modify and distribute modified or unmodified 23 * copies of this software in source and/or binary form. No title 24 * or ownership is transferred hereby. 25 * 26 * 1) Any source code used, modified or distributed must reproduce 27 * and retain this copyright notice and list of conditions 28 * as they appear in the source file. 29 * 30 * 2) No right is granted to use any trade name, trademark, or 31 * logo of Broadcom Corporation. The "Broadcom Corporation" 32 * name may not be used to endorse or promote products derived 33 * from this software without the prior written permission of 34 * Broadcom Corporation. 35 * 36 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 37 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 38 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 39 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 40 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 41 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 42 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 43 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 44 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 45 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 46 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 47 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 48 * THE POSSIBILITY OF SUCH DAMAGE. 49 ********************************************************************* */ 50 51#if CFG_ZLIB 52 53 54#include "cfe.h" 55#include "cfe_fileops.h" 56 57#include "zlib.h" 58 59/* ********************************************************************* 60 * ZLIBFS context 61 ********************************************************************* */ 62 63/* 64 * File system context - describes overall file system info, 65 * such as the handle to the underlying device. 66 */ 67 68typedef struct zlibfs_fsctx_s { 69 void *zlibfsctx_subfsctx; 70 const fileio_dispatch_t *zlibfsctx_subops; 71 int zlibfsctx_refcnt; 72} zlibfs_fsctx_t; 73 74/* 75 * File context - describes an open file on the file system. 76 * For raw devices, this is pretty meaningless, but we do 77 * keep track of where we are. 78 */ 79 80#define ZLIBFS_BUFSIZE 1024 81typedef struct zlibfs_file_s { 82 zlibfs_fsctx_t *zlibfs_fsctx; 83 int zlibfs_fileoffset; 84 void *zlibfs_subfile; 85 z_stream zlibfs_stream; 86 uint8_t *zlibfs_inbuf; 87 uint8_t *zlibfs_outbuf; 88 int zlibfs_outlen; 89 uint8_t *zlibfs_outptr; 90 int zlibfs_eofseen; 91} zlibfs_file_t; 92 93/* ********************************************************************* 94 * Prototypes 95 ********************************************************************* */ 96 97static int zlibfs_fileop_init(void **fsctx,void *ctx); 98static int zlibfs_fileop_open(void **ref,void *fsctx,char *filename,int mode); 99static int zlibfs_fileop_read(void *ref,hsaddr_t buf,int len); 100static int zlibfs_fileop_write(void *ref,hsaddr_t buf,int len); 101static int zlibfs_fileop_seek(void *ref,int offset,int how); 102static void zlibfs_fileop_close(void *ref); 103static void zlibfs_fileop_uninit(void *fsctx); 104 105voidpf zcalloc(voidpf opaque,unsigned items, unsigned size); 106void zcfree(voidpf opaque,voidpf ptr); 107 108/* ********************************************************************* 109 * ZLIB fileio dispatch table 110 ********************************************************************* */ 111 112 113static uint8_t gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ 114 115 116/* gzip flag byte */ 117#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ 118#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ 119#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ 120#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ 121#define COMMENT 0x10 /* bit 4 set: file comment present */ 122#define RESERVED 0xE0 /* bits 5..7: reserved */ 123 124const fileio_dispatch_t zlibfs_fileops = { 125 "z", 126 0, 127 zlibfs_fileop_init, 128 zlibfs_fileop_open, 129 zlibfs_fileop_read, 130 zlibfs_fileop_write, 131 zlibfs_fileop_seek, 132 zlibfs_fileop_close, 133 zlibfs_fileop_uninit 134}; 135 136/* 137 * Utility functions needed by the ZLIB routines 138 */ 139voidpf zcalloc(voidpf opaque,unsigned items, unsigned size) 140{ 141 void *ptr; 142 143 ptr = KMALLOC(items*size,0); 144 if (ptr) lib_memset(ptr,0,items*size); 145 return ptr; 146} 147 148void zcfree(voidpf opaque,voidpf ptr) 149{ 150 KFREE(ptr); 151} 152 153 154static int zlibfs_fileop_init(void **newfsctx,void *curfsvoid) 155{ 156 zlibfs_fsctx_t *fsctx; 157 fileio_ctx_t *curfsctx = (fileio_ctx_t *) curfsvoid; 158 159 *newfsctx = NULL; 160 161 fsctx = KMALLOC(sizeof(zlibfs_fsctx_t),0); 162 if (!fsctx) { 163 return CFE_ERR_NOMEM; 164 } 165 166 fsctx->zlibfsctx_refcnt = 0; 167 fsctx->zlibfsctx_subops = curfsctx->ops; 168 fsctx->zlibfsctx_subfsctx = curfsctx->fsctx; 169 170 *newfsctx = fsctx; 171 172 return 0; 173} 174 175 176static int get_byte(zlibfs_file_t *file,uint8_t *ch) 177{ 178 int res; 179 180 res = BDREAD(file->zlibfs_fsctx->zlibfsctx_subops, 181 file->zlibfs_subfile, 182 PTR2HSADDR(ch), 183 1); 184 185 return res; 186} 187 188 189static int check_header(zlibfs_file_t *file) 190{ 191 int method; /* method byte */ 192 int flags; /* flags byte */ 193 uInt len; 194 uint8_t c; 195 int res; 196 197 /* Check the gzip magic header */ 198 for (len = 0; len < 2; len++) { 199 res = get_byte(file,&c); 200 if (c != gz_magic[len]) { 201 return -1; 202 } 203 } 204 205 get_byte(file,&c); method = (int) c; 206 get_byte(file,&c); flags = (int) c; 207 208 if (method != Z_DEFLATED || (flags & RESERVED) != 0) { 209 return -1; 210 } 211 212 /* Discard time, xflags and OS code: */ 213 for (len = 0; len < 6; len++) (void)get_byte(file,&c); 214 215 if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ 216 get_byte(file,&c); 217 len = (uInt) c; 218 get_byte(file,&c); 219 len += ((uInt)c)<<8; 220 /* len is garbage if EOF but the loop below will quit anyway */ 221 while ((len-- != 0) && (get_byte(file,&c) == 1)) ; 222 } 223 if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ 224 while ((get_byte(file,&c) == 1) && (c != 0)) ; 225 } 226 if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ 227 while ((get_byte(file,&c) == 1) && (c != 0)) ; 228 } 229 if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ 230 for (len = 0; len < 2; len++) (void)get_byte(file,&c); 231 } 232 233 return 0; 234} 235 236static int zlibfs_fileop_open(void **ref,void *fsctx_arg,char *filename,int mode) 237{ 238 zlibfs_fsctx_t *fsctx; 239 zlibfs_file_t *file; 240 int err; 241 242 if (mode != FILE_MODE_READ) return CFE_ERR_UNSUPPORTED; 243 244 fsctx = (zlibfs_fsctx_t *) fsctx_arg; 245 246 file = KMALLOC(sizeof(zlibfs_file_t),0); 247 if (!file) { 248 return CFE_ERR_NOMEM; 249 } 250 251 file->zlibfs_fileoffset = 0; 252 file->zlibfs_fsctx = fsctx; 253 file->zlibfs_inbuf = NULL; 254 file->zlibfs_outbuf = NULL; 255 file->zlibfs_eofseen = 0; 256 257 err = BDOPEN(fsctx->zlibfsctx_subops,&(file->zlibfs_subfile), 258 fsctx->zlibfsctx_subfsctx,filename); 259 260 if (err != 0) { 261 goto error2; 262 return err; 263 } 264 265 /* Open the zstream */ 266 267 file->zlibfs_inbuf = KMALLOC(ZLIBFS_BUFSIZE,0); 268 file->zlibfs_outbuf = KMALLOC(ZLIBFS_BUFSIZE,0); 269 270 if (!file->zlibfs_inbuf || !file->zlibfs_outbuf) { 271 err = CFE_ERR_NOMEM; 272 goto error; 273 } 274 275 file->zlibfs_stream.next_in = NULL; 276 file->zlibfs_stream.avail_in = 0; 277 file->zlibfs_stream.next_out = file->zlibfs_outbuf; 278 file->zlibfs_stream.avail_out = ZLIBFS_BUFSIZE; 279 file->zlibfs_stream.zalloc = (alloc_func)0; 280 file->zlibfs_stream.zfree = (free_func)0; 281 282 file->zlibfs_outlen = 0; 283 file->zlibfs_outptr = file->zlibfs_outbuf; 284 285 err = inflateInit2(&(file->zlibfs_stream),-15); 286 if (err != Z_OK) { 287 err = CFE_ERR; 288 goto error; 289 } 290 291 check_header(file); 292 293 fsctx->zlibfsctx_refcnt++; 294 295 *ref = file; 296 return 0; 297 298error: 299 BDCLOSE(file->zlibfs_fsctx->zlibfsctx_subops,file->zlibfs_subfile); 300error2: 301 if (file->zlibfs_inbuf) KFREE(file->zlibfs_inbuf); 302 if (file->zlibfs_outbuf) KFREE(file->zlibfs_outbuf); 303 KFREE(file); 304 return err; 305} 306 307static int zlibfs_fileop_read(void *ref,hsaddr_t buf,int len) 308{ 309 zlibfs_file_t *file = (zlibfs_file_t *) ref; 310 int res = 0; 311 int err; 312 int amtcopy; 313 int ttlcopy = 0; 314 315 if (len == 0) return 0; 316 317 while (len) { 318 319 /* Figure the amount to copy. This is the min of what we 320 have left to do and what is available. */ 321 amtcopy = len; 322 if (amtcopy > file->zlibfs_outlen) { 323 amtcopy = file->zlibfs_outlen; 324 } 325 326 /* Copy the data. */ 327 328 if (buf) { 329 hs_memcpy_to_hs(buf,file->zlibfs_outptr,amtcopy); 330 buf += amtcopy; 331 } 332 333 /* Update the pointers. */ 334 file->zlibfs_outptr += amtcopy; 335 file->zlibfs_outlen -= amtcopy; 336 len -= amtcopy; 337 ttlcopy += amtcopy; 338 339 /* If we've eaten all of the output, reset and call inflate 340 again. */ 341 342 if (file->zlibfs_outlen == 0) { 343 /* If no input data to decompress, get some more if we can. */ 344 if (file->zlibfs_eofseen) break; 345 if (file->zlibfs_stream.avail_in == 0) { 346 res = BDREAD(file->zlibfs_fsctx->zlibfsctx_subops, 347 file->zlibfs_subfile, 348 PTR2HSADDR(file->zlibfs_inbuf), 349 ZLIBFS_BUFSIZE); 350 /* If at EOF or error, get out. */ 351 if (res <= 0) break; 352 file->zlibfs_stream.next_in = file->zlibfs_inbuf; 353 file->zlibfs_stream.avail_in = res; 354 } 355 356 /* inflate the input data. */ 357 file->zlibfs_stream.next_out = file->zlibfs_outbuf; 358 file->zlibfs_stream.avail_out = ZLIBFS_BUFSIZE; 359 file->zlibfs_outptr = file->zlibfs_outbuf; 360 err = inflate(&(file->zlibfs_stream),Z_SYNC_FLUSH); 361 if (err == Z_STREAM_END) { 362 /* We can get a partial buffer fill here. */ 363 file->zlibfs_eofseen = 1; 364 } 365 else if (err != Z_OK) { 366 res = CFE_ERR; 367 break; 368 } 369 file->zlibfs_outlen = file->zlibfs_stream.next_out - 370 file->zlibfs_outptr; 371 } 372 373 } 374 375 file->zlibfs_fileoffset += ttlcopy; 376 377 return (res < 0) ? res : ttlcopy; 378} 379 380static int zlibfs_fileop_write(void *ref,hsaddr_t buf,int len) 381{ 382 return CFE_ERR_UNSUPPORTED; 383} 384 385static int zlibfs_fileop_seek(void *ref,int offset,int how) 386{ 387 zlibfs_file_t *file = (zlibfs_file_t *) ref; 388 int res; 389 int delta; 390 391 switch (how) { 392 case FILE_SEEK_BEGINNING: 393 delta = offset - file->zlibfs_fileoffset; 394 break; 395 case FILE_SEEK_CURRENT: 396 delta = offset; 397 break; 398 default: 399 return CFE_ERR_UNSUPPORTED; 400 break; 401 } 402 403 /* backward seeking not allowed on compressed streams */ 404 if (delta < 0) { 405 return CFE_ERR_UNSUPPORTED; 406 } 407 408 res = zlibfs_fileop_read(ref,NULL,delta); 409 410 if (res < 0) return res; 411 412 return file->zlibfs_fileoffset; 413} 414 415 416static void zlibfs_fileop_close(void *ref) 417{ 418 zlibfs_file_t *file = (zlibfs_file_t *) ref; 419 420 file->zlibfs_fsctx->zlibfsctx_refcnt--; 421 422 inflateEnd(&(file->zlibfs_stream)); 423 424 BDCLOSE(file->zlibfs_fsctx->zlibfsctx_subops,file->zlibfs_subfile); 425 426 KFREE(file); 427} 428 429static void zlibfs_fileop_uninit(void *fsctx_arg) 430{ 431 zlibfs_fsctx_t *fsctx = (zlibfs_fsctx_t *) fsctx_arg; 432 433 if (fsctx->zlibfsctx_refcnt) { 434 xprintf("zlibfs_fileop_uninit: warning: refcnt not zero\n"); 435 } 436 437 BDUNINIT(fsctx->zlibfsctx_subops,fsctx->zlibfsctx_subfsctx); 438 439 KFREE(fsctx); 440} 441 442 443#endif 444