linux/lib/decompress_inflate.c
<<
>>
Prefs
   1#ifdef STATIC
   2/* Pre-boot environment: included */
   3
   4/* prevent inclusion of _LINUX_KERNEL_H in pre-boot environment: lots
   5 * errors about console_printk etc... on ARM */
   6#define _LINUX_KERNEL_H
   7
   8#include "zlib_inflate/inftrees.c"
   9#include "zlib_inflate/inffast.c"
  10#include "zlib_inflate/inflate.c"
  11
  12#else /* STATIC */
  13/* initramfs et al: linked */
  14
  15#include <linux/zutil.h>
  16
  17#include "zlib_inflate/inftrees.h"
  18#include "zlib_inflate/inffast.h"
  19#include "zlib_inflate/inflate.h"
  20
  21#include "zlib_inflate/infutil.h"
  22
  23#endif /* STATIC */
  24
  25#include <linux/decompress/mm.h>
  26
  27#define GZIP_IOBUF_SIZE (16*1024)
  28
  29static int INIT nofill(void *buffer, unsigned int len)
  30{
  31        return -1;
  32}
  33
  34/* Included from initramfs et al code */
  35STATIC int INIT gunzip(unsigned char *buf, int len,
  36                       int(*fill)(void*, unsigned int),
  37                       int(*flush)(void*, unsigned int),
  38                       unsigned char *out_buf,
  39                       int *pos,
  40                       void(*error)(char *x)) {
  41        u8 *zbuf;
  42        struct z_stream_s *strm;
  43        int rc;
  44        size_t out_len;
  45
  46        rc = -1;
  47        if (flush) {
  48                out_len = 0x8000; /* 32 K */
  49                out_buf = malloc(out_len);
  50        } else {
  51                out_len = 0x7fffffff; /* no limit */
  52        }
  53        if (!out_buf) {
  54                error("Out of memory while allocating output buffer");
  55                goto gunzip_nomem1;
  56        }
  57
  58        if (buf)
  59                zbuf = buf;
  60        else {
  61                zbuf = malloc(GZIP_IOBUF_SIZE);
  62                len = 0;
  63        }
  64        if (!zbuf) {
  65                error("Out of memory while allocating input buffer");
  66                goto gunzip_nomem2;
  67        }
  68
  69        strm = malloc(sizeof(*strm));
  70        if (strm == NULL) {
  71                error("Out of memory while allocating z_stream");
  72                goto gunzip_nomem3;
  73        }
  74
  75        strm->workspace = malloc(flush ? zlib_inflate_workspacesize() :
  76                                 sizeof(struct inflate_state));
  77        if (strm->workspace == NULL) {
  78                error("Out of memory while allocating workspace");
  79                goto gunzip_nomem4;
  80        }
  81
  82        if (!fill)
  83                fill = nofill;
  84
  85        if (len == 0)
  86                len = fill(zbuf, GZIP_IOBUF_SIZE);
  87
  88        /* verify the gzip header */
  89        if (len < 10 ||
  90           zbuf[0] != 0x1f || zbuf[1] != 0x8b || zbuf[2] != 0x08) {
  91                if (pos)
  92                        *pos = 0;
  93                error("Not a gzip file");
  94                goto gunzip_5;
  95        }
  96
  97        /* skip over gzip header (1f,8b,08... 10 bytes total +
  98         * possible asciz filename)
  99         */
 100        strm->next_in = zbuf + 10;
 101        strm->avail_in = len - 10;
 102        /* skip over asciz filename */
 103        if (zbuf[3] & 0x8) {
 104                do {
 105                        /*
 106                         * If the filename doesn't fit into the buffer,
 107                         * the file is very probably corrupt. Don't try
 108                         * to read more data.
 109                         */
 110                        if (strm->avail_in == 0) {
 111                                error("header error");
 112                                goto gunzip_5;
 113                        }
 114                        --strm->avail_in;
 115                } while (*strm->next_in++);
 116        }
 117
 118        strm->next_out = out_buf;
 119        strm->avail_out = out_len;
 120
 121        rc = zlib_inflateInit2(strm, -MAX_WBITS);
 122
 123        if (!flush) {
 124                WS(strm)->inflate_state.wsize = 0;
 125                WS(strm)->inflate_state.window = NULL;
 126        }
 127
 128        while (rc == Z_OK) {
 129                if (strm->avail_in == 0) {
 130                        /* TODO: handle case where both pos and fill are set */
 131                        len = fill(zbuf, GZIP_IOBUF_SIZE);
 132                        if (len < 0) {
 133                                rc = -1;
 134                                error("read error");
 135                                break;
 136                        }
 137                        strm->next_in = zbuf;
 138                        strm->avail_in = len;
 139                }
 140                rc = zlib_inflate(strm, 0);
 141
 142                /* Write any data generated */
 143                if (flush && strm->next_out > out_buf) {
 144                        int l = strm->next_out - out_buf;
 145                        if (l != flush(out_buf, l)) {
 146                                rc = -1;
 147                                error("write error");
 148                                break;
 149                        }
 150                        strm->next_out = out_buf;
 151                        strm->avail_out = out_len;
 152                }
 153
 154                /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */
 155                if (rc == Z_STREAM_END) {
 156                        rc = 0;
 157                        break;
 158                } else if (rc != Z_OK) {
 159                        error("uncompression error");
 160                        rc = -1;
 161                }
 162        }
 163
 164        zlib_inflateEnd(strm);
 165        if (pos)
 166                /* add + 8 to skip over trailer */
 167                *pos = strm->next_in - zbuf+8;
 168
 169gunzip_5:
 170        free(strm->workspace);
 171gunzip_nomem4:
 172        free(strm);
 173gunzip_nomem3:
 174        if (!buf)
 175                free(zbuf);
 176gunzip_nomem2:
 177        if (flush)
 178                free(out_buf);
 179gunzip_nomem1:
 180        return rc; /* returns Z_OK (0) if successful */
 181}
 182
 183#define decompress gunzip
 184