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