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