root/lib/libsa/cread.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zcalloc
  2. zcfree
  3. get_byte
  4. getLong
  5. check_header
  6. open
  7. close
  8. read
  9. lseek

    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 }

/* [<][>][^][v][top][bottom][index][help] */