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