Home | History | Annotate | Line # | Download | only in libsa
cread.c revision 1.3
      1  1.3  drochner /*	$NetBSD: cread.c,v 1.3 1997/06/13 14:28:52 drochner 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.3  drochner #include <lib/libkern/libkern.h>
     49  1.1       cgd #include "stand.h"
     50  1.3  drochner #include <lib/libz/zlib.h>
     51  1.1       cgd 
     52  1.1       cgd #define EOF (-1) /* needed by compression code */
     53  1.1       cgd 
     54  1.1       cgd #ifdef SAVE_MEMORY
     55  1.1       cgd #define Z_BUFSIZE 1024
     56  1.1       cgd #else
     57  1.1       cgd #define Z_BUFSIZE 4096
     58  1.1       cgd #endif
     59  1.1       cgd 
     60  1.1       cgd static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
     61  1.1       cgd 
     62  1.1       cgd /* gzip flag byte */
     63  1.1       cgd #define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
     64  1.1       cgd #define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
     65  1.1       cgd #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
     66  1.1       cgd #define ORIG_NAME    0x08 /* bit 3 set: original file name present */
     67  1.1       cgd #define COMMENT      0x10 /* bit 4 set: file comment present */
     68  1.1       cgd #define RESERVED     0xE0 /* bits 5..7: reserved */
     69  1.1       cgd 
     70  1.1       cgd static struct sd {
     71  1.1       cgd   z_stream stream;
     72  1.1       cgd   int      z_err;   /* error code for last stream operation */
     73  1.1       cgd   int      z_eof;   /* set if end of input file */
     74  1.1       cgd   int fd;
     75  1.1       cgd   unsigned char     *inbuf;  /* input buffer */
     76  1.1       cgd   unsigned long    crc;     /* crc32 of uncompressed data */
     77  1.1       cgd   int      transparent; /* 1 if input file is not a .gz file */
     78  1.1       cgd } *ss[SOPEN_MAX];
     79  1.1       cgd 
     80  1.1       cgd /*
     81  1.1       cgd  * compression utilities
     82  1.1       cgd  */
     83  1.1       cgd 
     84  1.1       cgd void *zcalloc (opaque, items, size)
     85  1.1       cgd void *opaque;
     86  1.1       cgd unsigned items;
     87  1.1       cgd unsigned size;
     88  1.1       cgd {
     89  1.1       cgd   return(alloc(items * size));
     90  1.1       cgd }
     91  1.1       cgd 
     92  1.1       cgd void  zcfree (opaque, ptr)
     93  1.1       cgd void *opaque;
     94  1.1       cgd void *ptr;
     95  1.1       cgd {
     96  1.1       cgd   free(ptr, 0); /* XXX works only with modified allocator */
     97  1.1       cgd }
     98  1.1       cgd 
     99  1.1       cgd void zmemcpy(dest, source, len)
    100  1.1       cgd unsigned char *dest;
    101  1.1       cgd unsigned char *source;
    102  1.1       cgd unsigned int len;
    103  1.1       cgd {
    104  1.1       cgd   bcopy(source, dest, len);
    105  1.1       cgd }
    106  1.1       cgd 
    107  1.1       cgd static int get_byte(s)
    108  1.1       cgd     struct sd *s;
    109  1.1       cgd {
    110  1.1       cgd     if (s->z_eof) return EOF;
    111  1.1       cgd     if (s->stream.avail_in == 0) {
    112  1.1       cgd 	errno = 0;
    113  1.1       cgd 	s->stream.avail_in = oread(s->fd, s->inbuf, Z_BUFSIZE);
    114  1.1       cgd 	if (s->stream.avail_in == 0) {
    115  1.1       cgd 	    s->z_eof = 1;
    116  1.1       cgd 	    if (errno) s->z_err = Z_ERRNO;
    117  1.1       cgd 	    return EOF;
    118  1.1       cgd 	}
    119  1.1       cgd 	s->stream.next_in = s->inbuf;
    120  1.1       cgd     }
    121  1.1       cgd     s->stream.avail_in--;
    122  1.1       cgd     return *(s->stream.next_in)++;
    123  1.1       cgd }
    124  1.1       cgd 
    125  1.1       cgd static unsigned long getLong (s)
    126  1.1       cgd     struct sd *s;
    127  1.1       cgd {
    128  1.1       cgd     unsigned long x = (unsigned long)get_byte(s);
    129  1.1       cgd     int c;
    130  1.1       cgd 
    131  1.1       cgd     x += ((unsigned long)get_byte(s))<<8;
    132  1.1       cgd     x += ((unsigned long)get_byte(s))<<16;
    133  1.1       cgd     c = get_byte(s);
    134  1.1       cgd     if (c == EOF) s->z_err = Z_DATA_ERROR;
    135  1.1       cgd     x += ((unsigned long)c)<<24;
    136  1.1       cgd     return x;
    137  1.1       cgd }
    138  1.1       cgd 
    139  1.1       cgd static void check_header(s)
    140  1.1       cgd     struct sd *s;
    141  1.1       cgd {
    142  1.1       cgd     int method; /* method byte */
    143  1.1       cgd     int flags;  /* flags byte */
    144  1.1       cgd     unsigned int len;
    145  1.1       cgd     int c;
    146  1.1       cgd 
    147  1.1       cgd     /* Check the gzip magic header */
    148  1.1       cgd     for (len = 0; len < 2; len++) {
    149  1.1       cgd 	c = get_byte(s);
    150  1.1       cgd 	if (c != gz_magic[len]) {
    151  1.1       cgd 	    s->transparent = 1;
    152  1.1       cgd 	    if (c != EOF) s->stream.avail_in++, s->stream.next_in--;
    153  1.1       cgd 	    s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
    154  1.1       cgd 	    return;
    155  1.1       cgd 	}
    156  1.1       cgd     }
    157  1.1       cgd     method = get_byte(s);
    158  1.1       cgd     flags = get_byte(s);
    159  1.1       cgd     if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
    160  1.1       cgd 	s->z_err = Z_DATA_ERROR;
    161  1.1       cgd 	return;
    162  1.1       cgd     }
    163  1.1       cgd 
    164  1.1       cgd     /* Discard time, xflags and OS code: */
    165  1.1       cgd     for (len = 0; len < 6; len++) (void)get_byte(s);
    166  1.1       cgd 
    167  1.1       cgd     if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
    168  1.1       cgd 	len  =  (unsigned int)get_byte(s);
    169  1.1       cgd 	len += ((unsigned int)get_byte(s))<<8;
    170  1.1       cgd 	/* len is garbage if EOF but the loop below will quit anyway */
    171  1.1       cgd 	while (len-- != 0 && get_byte(s) != EOF) ;
    172  1.1       cgd     }
    173  1.1       cgd     if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
    174  1.1       cgd 	while ((c = get_byte(s)) != 0 && c != EOF) ;
    175  1.1       cgd     }
    176  1.1       cgd     if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */
    177  1.1       cgd 	while ((c = get_byte(s)) != 0 && c != EOF) ;
    178  1.1       cgd     }
    179  1.1       cgd     if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
    180  1.1       cgd 	for (len = 0; len < 2; len++) (void)get_byte(s);
    181  1.1       cgd     }
    182  1.1       cgd     s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
    183  1.1       cgd }
    184  1.1       cgd 
    185  1.1       cgd /*
    186  1.1       cgd  * new open(), close(), read(), lseek()
    187  1.1       cgd  */
    188  1.1       cgd 
    189  1.1       cgd int
    190  1.1       cgd open(fname, mode)
    191  1.1       cgd 	const char *fname;
    192  1.1       cgd 	int mode;
    193  1.1       cgd {
    194  1.1       cgd 	  int fd;
    195  1.1       cgd 	  struct sd *s = 0;
    196  1.1       cgd 
    197  1.1       cgd 	  if(((fd = oopen(fname, mode)) == -1)
    198  1.1       cgd 	     || (mode != 0)) /* compression only for read */
    199  1.1       cgd 	  return(fd);
    200  1.1       cgd 
    201  1.1       cgd 	  ss[fd] = s = alloc(sizeof(struct sd));
    202  1.1       cgd 	  if(!s) goto errout;
    203  1.1       cgd 	  bzero(s, sizeof(struct sd));
    204  1.1       cgd 
    205  1.1       cgd 	  if(inflateInit2(&(s->stream), -15) != Z_OK)
    206  1.1       cgd 	      goto errout;
    207  1.1       cgd 
    208  1.1       cgd 	  s->stream.next_in  = s->inbuf = (unsigned char*)alloc(Z_BUFSIZE);
    209  1.1       cgd 	  if(!s->inbuf) {
    210  1.1       cgd 	      inflateEnd(&(s->stream));
    211  1.1       cgd 	      goto errout;
    212  1.1       cgd 	  }
    213  1.1       cgd 
    214  1.1       cgd 	  s->fd = fd;
    215  1.1       cgd 	  check_header(s); /* skip the .gz header */
    216  1.1       cgd 	  return(fd);
    217  1.1       cgd 
    218  1.1       cgd errout:
    219  1.1       cgd           if(s) free(s, sizeof(struct sd));
    220  1.1       cgd           oclose(fd);
    221  1.1       cgd 	  return(-1);
    222  1.1       cgd }
    223  1.1       cgd 
    224  1.1       cgd int
    225  1.1       cgd close(fd)
    226  1.1       cgd 	int fd;
    227  1.1       cgd {
    228  1.2   thorpej 	struct open_file *f;
    229  1.1       cgd         struct sd *s;
    230  1.2   thorpej 
    231  1.2   thorpej 	if ((unsigned)fd >= SOPEN_MAX) {
    232  1.2   thorpej 		errno = EBADF;
    233  1.2   thorpej 		return (-1);
    234  1.2   thorpej 	}
    235  1.2   thorpej 	f = &files[fd];
    236  1.2   thorpej 
    237  1.2   thorpej 	if(!(f->f_flags & F_READ))
    238  1.2   thorpej 		return(oclose(fd));
    239  1.1       cgd 
    240  1.1       cgd 	s = ss[fd];
    241  1.1       cgd 
    242  1.1       cgd 	inflateEnd(&(s->stream));
    243  1.1       cgd 
    244  1.1       cgd 	free(s->inbuf, Z_BUFSIZE);
    245  1.1       cgd 	free(s, sizeof(struct sd));
    246  1.1       cgd 
    247  1.1       cgd 	return(oclose(fd));
    248  1.1       cgd }
    249  1.1       cgd 
    250  1.1       cgd ssize_t
    251  1.1       cgd read(fd, buf, len)
    252  1.1       cgd 	int fd;
    253  1.1       cgd 	void *buf;
    254  1.1       cgd 	size_t len;
    255  1.1       cgd {
    256  1.1       cgd 	  struct sd *s;
    257  1.1       cgd 	  unsigned char *start = buf; /* starting point for crc computation */
    258  1.1       cgd 
    259  1.1       cgd 	  s = ss[fd];
    260  1.1       cgd 
    261  1.1       cgd 	  if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
    262  1.1       cgd 	  if (s->z_err == Z_STREAM_END) return 0;  /* EOF */
    263  1.1       cgd 
    264  1.1       cgd 	  s->stream.next_out = buf;
    265  1.1       cgd 	  s->stream.avail_out = len;
    266  1.1       cgd 
    267  1.1       cgd 	  while (s->stream.avail_out != 0) {
    268  1.1       cgd 
    269  1.1       cgd 	    if (s->transparent) {
    270  1.1       cgd 	      /* Copy first the lookahead bytes: */
    271  1.1       cgd 	      unsigned int n = s->stream.avail_in;
    272  1.1       cgd 	      if (n > s->stream.avail_out) n = s->stream.avail_out;
    273  1.1       cgd 	      if (n > 0) {
    274  1.1       cgd 		zmemcpy(s->stream.next_out, s->stream.next_in, n);
    275  1.1       cgd 		s->stream.next_out += n;
    276  1.1       cgd 		s->stream.next_in   += n;
    277  1.1       cgd 		s->stream.avail_out -= n;
    278  1.1       cgd 		s->stream.avail_in  -= n;
    279  1.1       cgd 	      }
    280  1.1       cgd 	      if (s->stream.avail_out > 0) {
    281  1.1       cgd 		s->stream.avail_out -= oread(s->fd, s->stream.next_out, s->stream.avail_out);
    282  1.1       cgd 	      }
    283  1.1       cgd 	      return (int)(len - s->stream.avail_out);
    284  1.1       cgd 	    }
    285  1.1       cgd 
    286  1.1       cgd 	    if (s->stream.avail_in == 0 && !s->z_eof) {
    287  1.1       cgd 
    288  1.1       cgd 	      errno = 0;
    289  1.1       cgd 	      s->stream.avail_in = oread(fd, s->inbuf, Z_BUFSIZE);
    290  1.1       cgd 	      if (s->stream.avail_in == 0) {
    291  1.1       cgd 		s->z_eof = 1;
    292  1.1       cgd 		if (errno) {
    293  1.1       cgd 		  s->z_err = Z_ERRNO;
    294  1.1       cgd 		  break;
    295  1.1       cgd 		}
    296  1.1       cgd 	      }
    297  1.1       cgd 	      s->stream.next_in = s->inbuf;
    298  1.1       cgd 	    }
    299  1.1       cgd 	    s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
    300  1.1       cgd 
    301  1.1       cgd 	    if (s->z_err == Z_STREAM_END) {
    302  1.1       cgd 	      /* Check CRC and original size */
    303  1.1       cgd 	      s->crc = crc32(s->crc, start, (unsigned int)(s->stream.next_out - start));
    304  1.1       cgd 	      start = s->stream.next_out;
    305  1.1       cgd 
    306  1.1       cgd 	      if (getLong(s) != s->crc || getLong(s) != s->stream.total_out) {
    307  1.1       cgd 		s->z_err = Z_DATA_ERROR;
    308  1.1       cgd 	      } else {
    309  1.1       cgd 		/* Check for concatenated .gz files: */
    310  1.1       cgd 		check_header(s);
    311  1.1       cgd 		if (s->z_err == Z_OK) {
    312  1.1       cgd 		  inflateReset(&(s->stream));
    313  1.1       cgd 		  s->crc = crc32(0L, Z_NULL, 0);
    314  1.1       cgd 		}
    315  1.1       cgd 	      }
    316  1.1       cgd 	    }
    317  1.1       cgd 	    if (s->z_err != Z_OK || s->z_eof) break;
    318  1.1       cgd 	  }
    319  1.1       cgd 	  s->crc = crc32(s->crc, start, (unsigned int)(s->stream.next_out - start));
    320  1.1       cgd 
    321  1.1       cgd 	  return (int)(len - s->stream.avail_out);
    322  1.1       cgd }
    323  1.1       cgd 
    324  1.1       cgd off_t
    325  1.1       cgd lseek(fd, offset, where)
    326  1.1       cgd 	int fd;
    327  1.1       cgd 	off_t offset;
    328  1.1       cgd 	int where;
    329  1.1       cgd {
    330  1.1       cgd 	    register struct open_file *f;
    331  1.1       cgd 	    struct sd *s;
    332  1.1       cgd 
    333  1.1       cgd 	    if ((unsigned)fd >= SOPEN_MAX) {
    334  1.1       cgd 		errno = EBADF;
    335  1.1       cgd 		return (-1);
    336  1.1       cgd 	    }
    337  1.1       cgd 	    f = &files[fd];;
    338  1.1       cgd 
    339  1.1       cgd 	    if(!(f->f_flags & F_READ))
    340  1.1       cgd 		return(olseek(fd, offset, where));
    341  1.1       cgd 
    342  1.1       cgd 	    s = ss[fd];
    343  1.1       cgd 
    344  1.1       cgd 	    if(s->transparent) {
    345  1.1       cgd 		off_t res = olseek(fd, offset, where);
    346  1.1       cgd 		if(res != (off_t)-1) {
    347  1.1       cgd 		    /* make sure the lookahead buffer is invalid */
    348  1.1       cgd 		    s->stream.avail_in = 0;
    349  1.1       cgd 		}
    350  1.1       cgd 		return(res);
    351  1.1       cgd 	    }
    352  1.1       cgd 
    353  1.1       cgd 	    switch(where) {
    354  1.1       cgd 		case SEEK_CUR:
    355  1.1       cgd 		    offset += s->stream.total_out;
    356  1.1       cgd 		case SEEK_SET:
    357  1.1       cgd 
    358  1.1       cgd 		    /* if seek backwards, simply start from
    359  1.1       cgd 		     the beginning */
    360  1.1       cgd 		    if(offset < s->stream.total_out) {
    361  1.1       cgd 			off_t res;
    362  1.1       cgd 			void *sav_inbuf;
    363  1.1       cgd 
    364  1.1       cgd 			res = olseek(fd, 0, SEEK_SET);
    365  1.1       cgd 			if(res == (off_t)-1)
    366  1.1       cgd 			    return(res);
    367  1.1       cgd 			/* ??? perhaps fallback to close / open */
    368  1.1       cgd 
    369  1.1       cgd 			inflateEnd(&(s->stream));
    370  1.1       cgd 
    371  1.1       cgd 			sav_inbuf = s->inbuf; /* don't allocate again */
    372  1.1       cgd 			bzero(s, sizeof(struct sd)); /* this resets total_out to 0! */
    373  1.1       cgd 
    374  1.1       cgd 			inflateInit2(&(s->stream), -15);
    375  1.1       cgd 			s->stream.next_in = s->inbuf = sav_inbuf;
    376  1.1       cgd 
    377  1.1       cgd 			s->fd = fd;
    378  1.1       cgd 			check_header(s); /* skip the .gz header */
    379  1.1       cgd 		    }
    380  1.1       cgd 
    381  1.1       cgd 		    /* to seek forwards, throw away data */
    382  1.1       cgd 		    if(offset > s->stream.total_out) {
    383  1.1       cgd 			off_t toskip = offset - s->stream.total_out;
    384  1.1       cgd 
    385  1.1       cgd 			while(toskip > 0) {
    386  1.1       cgd #define DUMMYBUFSIZE 256
    387  1.1       cgd 			    char dummybuf[DUMMYBUFSIZE];
    388  1.1       cgd 			    off_t len = toskip;
    389  1.1       cgd 			    if(len > DUMMYBUFSIZE) len = DUMMYBUFSIZE;
    390  1.1       cgd 			    if(read(fd, dummybuf, len) != len) {
    391  1.1       cgd 				errno = EOFFSET;
    392  1.1       cgd 				return((off_t)-1);
    393  1.1       cgd 			    }
    394  1.1       cgd 			    toskip -= len;
    395  1.1       cgd 			}
    396  1.1       cgd 		    }
    397  1.1       cgd #ifdef DEBUG
    398  1.1       cgd 		    if(offset != s->stream.total_out)
    399  1.1       cgd 			panic("lseek compressed");
    400  1.1       cgd #endif
    401  1.1       cgd 		    return(offset);
    402  1.1       cgd 		case SEEK_END:
    403  1.1       cgd 		    errno = EOFFSET;
    404  1.1       cgd 		    break;
    405  1.1       cgd 		default:
    406  1.1       cgd 		    errno = EINVAL;
    407  1.1       cgd 	    }
    408  1.1       cgd 	    return((off_t)-1);
    409  1.1       cgd }
    410