The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/lib/libsa/cread.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: cread.c,v 1.15 2004/03/24 17:29:14 drochner 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  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   26  *
   27  */
   28 
   29 /*
   30  * Support for compressed bootfiles  (only read)
   31  *
   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 #ifdef _STANDALONE
   45 #include <lib/libkern/libkern.h>
   46 #include <lib/libz/zlib.h>
   47 #else
   48 #include <string.h>
   49 #include <zlib.h>
   50 #endif
   51 
   52 #define EOF (-1) /* needed by compression code */
   53 
   54 #ifdef SAVE_MEMORY
   55 #define Z_BUFSIZE 1024
   56 #else
   57 #define Z_BUFSIZE 4096
   58 #endif
   59 
   60 static const int gz_magic[2] = {0x1f, 0x8b};    /* gzip magic header */
   61 
   62 /* gzip flag byte */
   63 #define ASCII_FLAG      0x01    /* bit 0 set: file probably ascii text */
   64 #define HEAD_CRC        0x02    /* bit 1 set: header CRC present */
   65 #define EXTRA_FIELD     0x04    /* bit 2 set: extra field present */
   66 #define ORIG_NAME       0x08    /* bit 3 set: original file name present */
   67 #define COMMENT         0x10    /* bit 4 set: file comment present */
   68 #define RESERVED        0xE0    /* bits 5..7: reserved */
   69 
   70 static struct sd {
   71         z_stream        stream;
   72         int             z_err;  /* error code for last stream operation */
   73         int             z_eof;  /* set if end of input file */
   74         int             fd;
   75         unsigned char   *inbuf; /* input buffer */
   76         unsigned long   crc;    /* crc32 of uncompressed data */
   77         int             compressed;     /* 1 if input file is a .gz file */
   78 } *ss[SOPEN_MAX];
   79 
   80 static int              get_byte __P((struct sd *));
   81 static unsigned long    getLong __P((struct sd *));
   82 static void             check_header __P((struct sd *));
   83 
   84 /* XXX - find suitable header file for these: */
   85 void    *zcalloc __P((void *, unsigned int, unsigned int));
   86 void    zcfree __P((void *, void *));
   87 void    zmemcpy __P((unsigned char *, unsigned char *, unsigned int));
   88 
   89 
   90 /*
   91  * compression utilities
   92  */
   93 
   94 void *
   95 zcalloc (opaque, items, size)
   96         void *opaque;
   97         unsigned items;
   98         unsigned size;
   99 {
  100         return(alloc(items * size));
  101 }
  102 
  103 void
  104 zcfree (opaque, ptr)
  105         void *opaque;
  106         void *ptr;
  107 {
  108         free(ptr, 0); /* XXX works only with modified allocator */
  109 }
  110 
  111 void
  112 zmemcpy(dest, source, len)
  113         unsigned char *dest;
  114         unsigned char *source;
  115         unsigned int len;
  116 {
  117         bcopy(source, dest, len);
  118 }
  119 
  120 static int
  121 get_byte(s)
  122         struct sd *s;
  123 {
  124         if (s->z_eof)
  125                 return (EOF);
  126 
  127         if (s->stream.avail_in == 0) {
  128                 int got;
  129 
  130                 errno = 0;
  131                 got = oread(s->fd, s->inbuf, Z_BUFSIZE);
  132                 if (got <= 0) {
  133                         s->z_eof = 1;
  134                         if (errno) s->z_err = Z_ERRNO;
  135                         return EOF;
  136                 }
  137                 s->stream.avail_in = got;
  138                 s->stream.next_in = s->inbuf;
  139         }
  140         s->stream.avail_in--;
  141         return *(s->stream.next_in)++;
  142 }
  143 
  144 static unsigned long
  145 getLong (s)
  146     struct sd *s;
  147 {
  148         unsigned long x = (unsigned long)get_byte(s);
  149         int c;
  150 
  151         x += ((unsigned long)get_byte(s)) << 8;
  152         x += ((unsigned long)get_byte(s)) << 16;
  153         c = get_byte(s);
  154         if (c == EOF)
  155                 s->z_err = Z_DATA_ERROR;
  156         x += ((unsigned long)c)<<24;
  157         return x;
  158 }
  159 
  160 static void
  161 check_header(s)
  162         struct sd *s;
  163 {
  164         int method; /* method byte */
  165         int flags;  /* flags byte */
  166         unsigned int len;
  167         int c;
  168 
  169         /* Check the gzip magic header */
  170         for (len = 0; len < 2; len++) {
  171                 c = get_byte(s);
  172                 if (c == gz_magic[len])
  173                         continue;
  174                 if ((c == EOF) && (len == 0))  {
  175                         /*
  176                          * We must not change s->compressed if we are at EOF;
  177                          * we may have come to the end of a gzipped file and be
  178                          * check to see if another gzipped file is concatenated
  179                          * to this one. If one isn't, we still need to be able
  180                          * to lseek on this file as a compressed file.
  181                          */
  182                         return;
  183                 }
  184                 s->compressed = 0;
  185                 if (c != EOF) {
  186                         s->stream.avail_in++;
  187                         s->stream.next_in--;
  188                 }
  189                 s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
  190                 return;
  191         }
  192         s->compressed = 1;
  193         method = get_byte(s);
  194         flags = get_byte(s);
  195         if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
  196                 s->z_err = Z_DATA_ERROR;
  197                 return;
  198         }
  199 
  200         /* Discard time, xflags and OS code: */
  201         for (len = 0; len < 6; len++)
  202                 (void)get_byte(s);
  203 
  204         if ((flags & EXTRA_FIELD) != 0) {
  205                 /* skip the extra field */
  206                 len  =  (unsigned int)get_byte(s);
  207                 len += ((unsigned int)get_byte(s)) << 8;
  208                 /* len is garbage if EOF but the loop below will quit anyway */
  209                 while (len-- != 0 && get_byte(s) != EOF) /*void*/;
  210         }
  211         if ((flags & ORIG_NAME) != 0) {
  212                 /* skip the original file name */
  213                 while ((c = get_byte(s)) != 0 && c != EOF) /*void*/;
  214         }
  215         if ((flags & COMMENT) != 0) {
  216                 /* skip the .gz file comment */
  217                 while ((c = get_byte(s)) != 0 && c != EOF) /*void*/;
  218         }
  219         if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
  220                 for (len = 0; len < 2; len++)
  221                         (void)get_byte(s);
  222         }
  223         s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
  224 }
  225 
  226 /*
  227  * new open(), close(), read(), lseek()
  228  */
  229 
  230 int
  231 open(fname, mode)
  232         const char *fname;
  233         int mode;
  234 {
  235         int fd;
  236         struct sd *s = 0;
  237 
  238         if (((fd = oopen(fname, mode)) == -1) || (mode != 0))
  239                 /* compression only for read */
  240                 return (fd);
  241 
  242         ss[fd] = s = alloc(sizeof(struct sd));
  243         if (s == 0)
  244                 goto errout;
  245         bzero(s, sizeof(struct sd));
  246 
  247         if (inflateInit2(&(s->stream), -15) != Z_OK)
  248                 goto errout;
  249 
  250         s->stream.next_in  = s->inbuf = (unsigned char*)alloc(Z_BUFSIZE);
  251         if (s->inbuf == 0) {
  252                 inflateEnd(&(s->stream));
  253                 goto errout;
  254         }
  255 
  256         s->fd = fd;
  257         check_header(s); /* skip the .gz header */
  258         return (fd);
  259 
  260 errout:
  261         if (s != 0)
  262                 free(s, sizeof(struct sd));
  263         oclose(fd);
  264         return (-1);
  265 }
  266 
  267 int
  268 close(fd)
  269         int fd;
  270 {
  271         struct open_file *f;
  272         struct sd *s;
  273 
  274 #if !defined(LIBSA_NO_FD_CHECKING)
  275         if ((unsigned)fd >= SOPEN_MAX) {
  276                 errno = EBADF;
  277                 return (-1);
  278         }
  279 #endif
  280         f = &files[fd];
  281 
  282         if ((f->f_flags & F_READ) == 0)
  283                 return (oclose(fd));
  284 
  285         s = ss[fd];
  286 
  287         inflateEnd(&(s->stream));
  288 
  289         free(s->inbuf, Z_BUFSIZE);
  290         free(s, sizeof(struct sd));
  291 
  292         return (oclose(fd));
  293 }
  294 
  295 ssize_t
  296 read(fd, buf, len)
  297         int fd;
  298         void *buf;
  299         size_t len;
  300 {
  301         struct sd *s;
  302         unsigned char *start = buf; /* starting point for crc computation */
  303 
  304         s = ss[fd];
  305 
  306         if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)
  307                 return (-1);
  308         if (s->z_err == Z_STREAM_END)
  309                 return (0);  /* EOF */
  310 
  311         s->stream.next_out = buf;
  312         s->stream.avail_out = len;
  313 
  314         while (s->stream.avail_out != 0) {
  315 
  316                 if (s->compressed == 0) {
  317                         /* Copy first the lookahead bytes: */
  318                         unsigned int n = s->stream.avail_in;
  319                         if (n > s->stream.avail_out)
  320                                 n = s->stream.avail_out;
  321                         if (n > 0) {
  322                                 zmemcpy(s->stream.next_out,
  323                                         s->stream.next_in, n);
  324                                 s->stream.next_out  += n;
  325                                 s->stream.next_in   += n;
  326                                 s->stream.avail_out -= n;
  327                                 s->stream.avail_in  -= n;
  328                         }
  329                         if (s->stream.avail_out > 0) {
  330                                 int got;
  331                                 got = oread(s->fd, s->stream.next_out,
  332                                             s->stream.avail_out);
  333                                 if (got == -1)
  334                                         return (got);
  335                                 s->stream.avail_out -= got;
  336                         }
  337                         return (int)(len - s->stream.avail_out);
  338                 }
  339 
  340                 if (s->stream.avail_in == 0 && !s->z_eof) {
  341                         int got;
  342                         errno = 0;
  343                         got = oread(fd, s->inbuf, Z_BUFSIZE);
  344                         if (got <= 0) {
  345                                 s->z_eof = 1;
  346                                 if (errno) {
  347                                         s->z_err = Z_ERRNO;
  348                                         break;
  349                                 }
  350                         }
  351                         s->stream.avail_in = got;
  352                         s->stream.next_in = s->inbuf;
  353                 }
  354 
  355                 s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
  356 
  357                 if (s->z_err == Z_STREAM_END) {
  358                         /* Check CRC and original size */
  359                         s->crc = crc32(s->crc, start, (unsigned int)
  360                                         (s->stream.next_out - start));
  361                         start = s->stream.next_out;
  362 
  363                         if (getLong(s) != s->crc ||
  364                             getLong(s) != s->stream.total_out) {
  365 
  366                                 s->z_err = Z_DATA_ERROR;
  367                         } else {
  368                                 /* Check for concatenated .gz files: */
  369                                 check_header(s);
  370                                 if (s->z_err == Z_OK) {
  371                                         inflateReset(&(s->stream));
  372                                         s->crc = crc32(0L, Z_NULL, 0);
  373                                 }
  374                         }
  375                 }
  376                 if (s->z_err != Z_OK || s->z_eof)
  377                         break;
  378         }
  379 
  380         s->crc = crc32(s->crc, start,
  381                        (unsigned int)(s->stream.next_out - start));
  382 
  383         return (int)(len - s->stream.avail_out);
  384 }
  385 
  386 off_t
  387 lseek(fd, offset, where)
  388         int fd;
  389         off_t offset;
  390         int where;
  391 {
  392         struct open_file *f;
  393         struct sd *s;
  394 
  395 #if !defined(LIBSA_NO_FD_CHECKING)
  396         if ((unsigned)fd >= SOPEN_MAX) {
  397                 errno = EBADF;
  398                 return (-1);
  399         }
  400 #endif
  401         f = &files[fd];
  402 
  403         if ((f->f_flags & F_READ) == 0)
  404                 return (olseek(fd, offset, where));
  405 
  406         s = ss[fd];
  407 
  408         if(s->compressed == 0) {
  409                 off_t res = olseek(fd, offset, where);
  410                 if (res != (off_t)-1) {
  411                         /* make sure the lookahead buffer is invalid */
  412                         s->stream.avail_in = 0;
  413                 }
  414                 return (res);
  415         }
  416 
  417         switch(where) {
  418         case SEEK_CUR:
  419                     offset += s->stream.total_out;
  420         case SEEK_SET:
  421                 /* if seek backwards, simply start from the beginning */
  422                 if (offset < s->stream.total_out) {
  423                         off_t res;
  424                         void *sav_inbuf;
  425 
  426                         res = olseek(fd, 0, SEEK_SET);
  427                         if(res == (off_t)-1)
  428                             return(res);
  429                         /* ??? perhaps fallback to close / open */
  430 
  431                         inflateEnd(&(s->stream));
  432 
  433                         sav_inbuf = s->inbuf; /* don't allocate again */
  434                         bzero(s, sizeof(struct sd)); /* this resets total_out to 0! */
  435 
  436                         inflateInit2(&(s->stream), -15);
  437                         s->stream.next_in = s->inbuf = sav_inbuf;
  438 
  439                         s->fd = fd;
  440                         check_header(s); /* skip the .gz header */
  441                 }
  442 
  443                     /* to seek forwards, throw away data */
  444                 if (offset > s->stream.total_out) {
  445                         off_t toskip = offset - s->stream.total_out;
  446 
  447                         while (toskip > 0) {
  448 #define DUMMYBUFSIZE 256
  449                                 char dummybuf[DUMMYBUFSIZE];
  450                                 off_t len = toskip;
  451                                 if (len > DUMMYBUFSIZE) len = DUMMYBUFSIZE;
  452                                 if (read(fd, dummybuf, len) != len) {
  453                                         errno = EOFFSET;
  454                                         return ((off_t)-1);
  455                                 }
  456                                 toskip -= len;
  457                         }
  458                 }
  459 #ifdef DEBUG
  460                 if (offset != s->stream.total_out)
  461                         panic("lseek compressed");
  462 #endif
  463                 return (offset);
  464         case SEEK_END:
  465                 errno = EOFFSET;
  466                 break;
  467         default:
  468                 errno = EINVAL;
  469         }
  470 
  471         return ((off_t)-1);
  472 }

Cache object: 4a9bfc934a10c2d9c4a1183d46a7851c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.