Annotation of sys/lib/libsa/cread.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: cread.c,v 1.12 2004/04/02 04:39:51 deraadt Exp $ */
! 2: /* $NetBSD: cread.c,v 1.2 1997/02/04 18:38:20 thorpej Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1996
! 6: * Matthias Drochner. All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: *
! 17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 18: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 19: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 20: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 21: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 22: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 23: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 24: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 25: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 26: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 27: *
! 28: */
! 29:
! 30: /* support for compressed bootfiles
! 31: (only read)
! 32: replaces open(), close(), read(), lseek().
! 33: original libsa open(), close(), read(), lseek() are called
! 34: as oopen(), oclose(), oread() resp. olseek().
! 35: compression parts stripped from zlib:gzio.c
! 36: */
! 37:
! 38: /* gzio.c -- IO on .gz files
! 39: * Copyright (C) 1995-1996 Jean-loup Gailly.
! 40: * For conditions of distribution and use, see copyright notice in zlib.h
! 41: */
! 42:
! 43: #include "stand.h"
! 44: #include "../libz/zlib.h"
! 45:
! 46: #define EOF (-1) /* needed by compression code */
! 47:
! 48: #define zmemcpy memcpy
! 49:
! 50: #ifdef SAVE_MEMORY
! 51: #define Z_BUFSIZE 1024
! 52: #else
! 53: #define Z_BUFSIZE 4096
! 54: #endif
! 55:
! 56: static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
! 57:
! 58: /* gzip flag byte */
! 59: #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
! 60: #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
! 61: #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
! 62: #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
! 63: #define COMMENT 0x10 /* bit 4 set: file comment present */
! 64: #define RESERVED 0xE0 /* bits 5..7: reserved */
! 65:
! 66: static struct sd {
! 67: z_stream stream;
! 68: int z_err; /* error code for last stream operation */
! 69: int z_eof; /* set if end of input file */
! 70: int fd;
! 71: unsigned char *inbuf; /* input buffer */
! 72: unsigned long crc; /* crc32 of uncompressed data */
! 73: int transparent; /* 1 if input file is not a .gz file */
! 74: } *ss[SOPEN_MAX];
! 75:
! 76: #ifdef DEBUG
! 77: int z_verbose = 0;
! 78: #endif
! 79:
! 80: /*
! 81: * compression utilities
! 82: */
! 83:
! 84: void *zcalloc(void *, unsigned int, unsigned int);
! 85: void zcfree(void *, void *);
! 86:
! 87: void *
! 88: zcalloc(void *opaque, unsigned int items, unsigned int size)
! 89: {
! 90: return(alloc(items * size));
! 91: }
! 92:
! 93: void
! 94: zcfree(void *opaque, void *ptr)
! 95: {
! 96: free(ptr, 0); /* XXX works only with modified allocator */
! 97: }
! 98:
! 99: static int
! 100: get_byte(struct sd *s)
! 101: {
! 102: if (s->z_eof)
! 103: return EOF;
! 104: if (s->stream.avail_in == 0) {
! 105: errno = 0;
! 106: s->stream.avail_in = oread(s->fd, s->inbuf, Z_BUFSIZE);
! 107: if (s->stream.avail_in <= 0) {
! 108: s->z_eof = 1;
! 109: if (errno)
! 110: s->z_err = Z_ERRNO;
! 111: return EOF;
! 112: }
! 113: s->stream.next_in = s->inbuf;
! 114: }
! 115: s->stream.avail_in--;
! 116: return *(s->stream.next_in)++;
! 117: }
! 118:
! 119: static unsigned long
! 120: getLong(struct sd *s)
! 121: {
! 122: unsigned long x = (unsigned long)get_byte(s);
! 123: int c;
! 124:
! 125: x += ((unsigned long)get_byte(s))<<8;
! 126: x += ((unsigned long)get_byte(s))<<16;
! 127: c = get_byte(s);
! 128: if (c == EOF)
! 129: s->z_err = Z_DATA_ERROR;
! 130: x += ((unsigned long)c)<<24;
! 131: return x;
! 132: }
! 133:
! 134: static void
! 135: check_header(struct sd *s)
! 136: {
! 137: int method; /* method byte */
! 138: int flags; /* flags byte */
! 139: unsigned int len;
! 140: int c;
! 141:
! 142: /* Check the gzip magic header */
! 143: for (len = 0; len < 2; len++) {
! 144: c = get_byte(s);
! 145: if (c != gz_magic[len]) {
! 146: if (len != 0) {
! 147: s->stream.avail_in++;
! 148: s->stream.next_in--;
! 149: }
! 150: if (c != EOF) {
! 151: s->stream.avail_in++;
! 152: s->stream.next_in--;
! 153: s->transparent = 1;
! 154: }
! 155:
! 156: s->z_err = s->stream.avail_in != 0 ? Z_OK :
! 157: Z_STREAM_END;
! 158: return;
! 159: }
! 160: }
! 161: method = get_byte(s);
! 162: flags = get_byte(s);
! 163: if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
! 164: s->z_err = Z_DATA_ERROR;
! 165: return;
! 166: }
! 167:
! 168: /* Discard time, xflags and OS code: */
! 169: for (len = 0; len < 6; len++)
! 170: (void)get_byte(s);
! 171:
! 172: if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
! 173: len = (unsigned int)get_byte(s);
! 174: len += ((unsigned int)get_byte(s))<<8;
! 175: /* len is garbage if EOF but the loop below will quit anyway */
! 176: while (len-- != 0 && get_byte(s) != EOF)
! 177: ;
! 178: }
! 179: if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
! 180: while ((c = get_byte(s)) != 0 && c != EOF)
! 181: ;
! 182: }
! 183: if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
! 184: while ((c = get_byte(s)) != 0 && c != EOF)
! 185: ;
! 186: }
! 187: if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
! 188: for (len = 0; len < 2; len++)
! 189: (void)get_byte(s);
! 190: }
! 191: s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
! 192: }
! 193:
! 194: /*
! 195: * new open(), close(), read(), lseek()
! 196: */
! 197:
! 198: int
! 199: open(const char *fname, int mode)
! 200: {
! 201: int fd;
! 202: struct sd *s = 0;
! 203:
! 204: if (((fd = oopen(fname, mode)) == -1) ||
! 205: (mode != 0)) /* compression only for read */
! 206: return(fd);
! 207:
! 208: ss[fd] = s = alloc(sizeof(struct sd));
! 209: if (!s)
! 210: goto errout;
! 211: bzero(s, sizeof(struct sd));
! 212:
! 213: #ifdef SAVE_MEMORY
! 214: if (inflateInit2(&(s->stream), -11) != Z_OK)
! 215: #else
! 216: if (inflateInit2(&(s->stream), -15) != Z_OK)
! 217: #endif
! 218: goto errout;
! 219:
! 220: s->stream.next_in = s->inbuf = (unsigned char *)alloc(Z_BUFSIZE);
! 221: if (!s->inbuf) {
! 222: inflateEnd(&(s->stream));
! 223: goto errout;
! 224: }
! 225:
! 226: s->fd = fd;
! 227: check_header(s); /* skip the .gz header */
! 228: return(fd);
! 229:
! 230: errout:
! 231: if (s)
! 232: free(s, sizeof(struct sd));
! 233: oclose(fd);
! 234: return(-1);
! 235: }
! 236:
! 237: int
! 238: close(int fd)
! 239: {
! 240: struct open_file *f;
! 241: struct sd *s;
! 242:
! 243: if ((unsigned)fd >= SOPEN_MAX) {
! 244: errno = EBADF;
! 245: return (-1);
! 246: }
! 247: f = &files[fd];
! 248:
! 249: if (!(f->f_flags & F_READ))
! 250: return(oclose(fd));
! 251:
! 252: s = ss[fd];
! 253:
! 254: inflateEnd(&(s->stream));
! 255:
! 256: free(s->inbuf, Z_BUFSIZE);
! 257: free(s, sizeof(struct sd));
! 258:
! 259: return(oclose(fd));
! 260: }
! 261:
! 262: ssize_t
! 263: read(int fd, void *buf, size_t len)
! 264: {
! 265: struct sd *s;
! 266: unsigned char *start = buf; /* starting point for crc computation */
! 267:
! 268: s = ss[fd];
! 269:
! 270: if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)
! 271: return -1;
! 272: if (s->z_err == Z_STREAM_END)
! 273: return 0; /* EOF */
! 274:
! 275: s->stream.next_out = buf;
! 276: s->stream.avail_out = len;
! 277:
! 278: while (s->stream.avail_out != 0) {
! 279:
! 280: if (s->transparent) {
! 281: /* Copy first the lookahead bytes: */
! 282: unsigned int n = s->stream.avail_in;
! 283:
! 284: if (n > s->stream.avail_out)
! 285: n = s->stream.avail_out;
! 286: if (n > 0) {
! 287: zmemcpy(s->stream.next_out, s->stream.next_in, n);
! 288: s->stream.next_out += n;
! 289: s->stream.next_in += n;
! 290: s->stream.avail_out -= n;
! 291: s->stream.avail_in -= n;
! 292: }
! 293: if (s->stream.avail_out > 0) {
! 294: int n;
! 295:
! 296: n = oread(fd, s->stream.next_out,
! 297: s->stream.avail_out);
! 298: if (n <= 0) {
! 299: s->z_eof = 1;
! 300: if (errno) {
! 301: s->z_err = Z_ERRNO;
! 302: break;
! 303: }
! 304: }
! 305: s->stream.avail_out -= n;
! 306: }
! 307: len -= s->stream.avail_out;
! 308: s->stream.total_in += (unsigned long)len;
! 309: s->stream.total_out += (unsigned long)len;
! 310: if (len == 0)
! 311: s->z_eof = 1;
! 312: return (int)len;
! 313: }
! 314:
! 315: if (s->stream.avail_in == 0 && !s->z_eof) {
! 316: errno = 0;
! 317: s->stream.avail_in = oread(fd, s->inbuf, Z_BUFSIZE);
! 318: if (s->stream.avail_in <= 0) {
! 319: s->z_eof = 1;
! 320: if (errno) {
! 321: s->z_err = Z_ERRNO;
! 322: break;
! 323: }
! 324: }
! 325: s->stream.next_in = s->inbuf;
! 326: }
! 327: s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
! 328:
! 329: if (s->z_err == Z_STREAM_END) {
! 330: /* Check CRC and original size */
! 331: s->crc = crc32(s->crc, start,
! 332: (unsigned int)(s->stream.next_out - start));
! 333: start = s->stream.next_out;
! 334:
! 335: if (getLong(s) != s->crc) {
! 336: s->z_err = Z_DATA_ERROR;
! 337: } else {
! 338: (void)getLong(s);
! 339:
! 340: /* The uncompressed length returned by
! 341: * above getlong() may be different from
! 342: * s->stream.total_out in case of concatenated
! 343: * .gz files. Check for such files:
! 344: */
! 345: check_header(s);
! 346: if (s->z_err == Z_OK) {
! 347: unsigned long total_in = s->stream.total_in;
! 348: unsigned long total_out = s->stream.total_out;
! 349:
! 350: inflateReset(&(s->stream));
! 351: s->stream.total_in = total_in;
! 352: s->stream.total_out = total_out;
! 353: s->crc = crc32(0L, Z_NULL, 0);
! 354: }
! 355: }
! 356: }
! 357: if (s->z_err != Z_OK || s->z_eof)
! 358: break;
! 359: }
! 360: s->crc = crc32(s->crc, start, (unsigned int)(s->stream.next_out - start));
! 361:
! 362: return (int)(len - s->stream.avail_out);
! 363: }
! 364:
! 365: off_t
! 366: lseek(int fd, off_t offset, int where)
! 367: {
! 368: struct open_file *f;
! 369: struct sd *s;
! 370:
! 371: if ((unsigned)fd >= SOPEN_MAX) {
! 372: errno = EBADF;
! 373: return (-1);
! 374: }
! 375: f = &files[fd];
! 376:
! 377: if (!(f->f_flags & F_READ))
! 378: return(olseek(fd, offset, where));
! 379:
! 380: s = ss[fd];
! 381:
! 382: if (s->transparent) {
! 383: off_t res = olseek(fd, offset, where);
! 384: if (res != (off_t)-1) {
! 385: /* make sure the lookahead buffer is invalid */
! 386: s->stream.avail_in = 0;
! 387: }
! 388: return(res);
! 389: }
! 390:
! 391: switch(where) {
! 392: case SEEK_CUR:
! 393: offset += s->stream.total_out;
! 394: case SEEK_SET:
! 395:
! 396: /* if seek backwards, simply start from
! 397: the beginning */
! 398: if (offset < s->stream.total_out) {
! 399: off_t res;
! 400: void *sav_inbuf;
! 401:
! 402: res = olseek(fd, 0, SEEK_SET);
! 403: if (res == (off_t)-1)
! 404: return(res);
! 405: /* ??? perhaps fallback to close / open */
! 406:
! 407: inflateEnd(&(s->stream));
! 408:
! 409: sav_inbuf = s->inbuf; /* don't allocate again */
! 410: bzero(s, sizeof(struct sd)); /* this resets total_out to 0! */
! 411:
! 412: inflateInit2(&(s->stream), -15);
! 413: s->stream.next_in = s->inbuf = sav_inbuf;
! 414:
! 415: s->fd = fd;
! 416: check_header(s); /* skip the .gz header */
! 417: }
! 418:
! 419: /* to seek forwards, throw away data */
! 420: if (offset > s->stream.total_out) {
! 421: off_t toskip = offset - s->stream.total_out;
! 422:
! 423: while(toskip > 0) {
! 424: #define DUMMYBUFSIZE 256
! 425: char dummybuf[DUMMYBUFSIZE];
! 426: off_t len = toskip;
! 427:
! 428: if (len > DUMMYBUFSIZE)
! 429: len = DUMMYBUFSIZE;
! 430: if (read(fd, dummybuf, len) != len) {
! 431: errno = EOFFSET;
! 432: return((off_t)-1);
! 433: }
! 434: toskip -= len;
! 435: }
! 436: }
! 437: #ifdef DEBUG
! 438: if (offset != s->stream.total_out)
! 439: panic("lseek compressed");
! 440: #endif
! 441: return(offset);
! 442: case SEEK_END:
! 443: errno = EOFFSET;
! 444: break;
! 445: default:
! 446: errno = EINVAL;
! 447: }
! 448: return((off_t)-1);
! 449: }
CVSweb