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