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#include <linux/slab.h>
  27
  28#define INBUF_LEN (16*1024)
  29
  30/* Included from initramfs et al code */
  31STATIC int INIT gunzip(unsigned char *buf, int len,
  32                       int(*fill)(void*, unsigned int),
  33                       int(*flush)(void*, unsigned int),
  34                       unsigned char *out_buf,
  35                       int *pos,
  36                       void(*error_fn)(char *x)) {
  37        u8 *zbuf;
  38        struct z_stream_s *strm;
  39        int rc;
  40        size_t out_len;
  41
  42        set_error_fn(error_fn);
  43        rc = -1;
  44        if (flush) {
  45                out_len = 0x8000; /* 32 K */
  46                out_buf = malloc(out_len);
  47        } else {
  48                out_len = 0x7fffffff; /* no limit */
  49        }
  50        if (!out_buf) {
  51                error("Out of memory while allocating output buffer");
  52                goto gunzip_nomem1;
  53        }
  54
  55        if (buf)
  56                zbuf = buf;
  57        else {
  58                zbuf = malloc(INBUF_LEN);
  59                len = 0;
  60        }
  61        if (!zbuf) {
  62                error("Out of memory while allocating input buffer");
  63                goto gunzip_nomem2;
  64        }
  65
  66        strm = malloc(sizeof(*strm));
  67        if (strm == NULL) {
  68                error("Out of memory while allocating z_stream");
  69                goto gunzip_nomem3;
  70        }
  71
  72        strm->workspace = malloc(flush ? zlib_inflate_workspacesize() :
  73                                 sizeof(struct inflate_state));
  74        if (strm->workspace == NULL) {
  75                error("Out of memory while allocating workspace");
  76                goto gunzip_nomem4;
  77        }
  78
  79        if (len == 0)
  80                len = fill(zbuf, INBUF_LEN);
  81
  82        /* verify the gzip header */
  83        if (len < 10 ||
  84           zbuf[0] != 0x1f || zbuf[1] != 0x8b || zbuf[2] != 0x08) {
  85                if (pos)
  86                        *pos = 0;
  87                error("Not a gzip file");
  88                goto gunzip_5;
  89        }
  90
  91        /* skip over gzip header (1f,8b,08... 10 bytes total +
  92         * possible asciz filename)
  93         */
  94        strm->next_in = zbuf + 10;
  95        /* skip over asciz filename */
  96        if (zbuf[3] & 0x8) {
  97                while (strm->next_in[0])
  98                        strm->next_in++;
  99                strm->next_in++;
 100        }
 101        strm->avail_in = len - (strm->next_in - zbuf);
 102
 103        strm->next_out = out_buf;
 104        strm->avail_out = out_len;
 105
 106        rc = zlib_inflateInit2(strm, -MAX_WBITS);
 107
 108        if (!flush) {
 109                WS(strm)->inflate_state.wsize = 0;
 110                WS(strm)->inflate_state.window = NULL;
 111        }
 112
 113        while (rc == Z_OK) {
 114                if (strm->avail_in == 0) {
 115                        /* TODO: handle case where both pos and fill are set */
 116                        len = fill(zbuf, INBUF_LEN);
 117                        if (len < 0) {
 118                                rc = -1;
 119                                error("read error");
 120                                break;
 121                        }
 122                        strm->next_in = zbuf;
 123                        strm->avail_in = len;
 124                }
 125                rc = zlib_inflate(strm, 0);
 126
 127                /* Write any data generated */
 128                if (flush && strm->next_out > out_buf) {
 129                        int l = strm->next_out - out_buf;
 130                        if (l != flush(out_buf, l)) {
 131                                rc = -1;
 132                                error("write error");
 133                                break;
 134                        }
 135                        strm->next_out = out_buf;
 136                        strm->avail_out = out_len;
 137                }
 138
 139                /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */
 140                if (rc == Z_STREAM_END) {
 141                        rc = 0;
 142                        break;
 143                } else if (rc != Z_OK) {
 144                        error("uncompression error");
 145                        rc = -1;
 146                }
 147        }
 148
 149        zlib_inflateEnd(strm);
 150        if (pos)
 151                /* add + 8 to skip over trailer */
 152                *pos = strm->next_in - zbuf+8;
 153
 154gunzip_5:
 155        free(strm->workspace);
 156gunzip_nomem4:
 157        free(strm);
 158gunzip_nomem3:
 159        if (!buf)
 160                free(zbuf);
 161gunzip_nomem2:
 162        if (flush)
 163                free(out_buf);
 164gunzip_nomem1:
 165        return rc; /* returns Z_OK (0) if successful */
 166}
 167
 168#define decompress gunzip
 169