linux/lib/decompress_inflate.c
<<
>>
Prefs
   1#ifdef STATIC
   2#define PREBOOT
   3/* Pre-boot environment: included */
   4
   5/* prevent inclusion of _LINUX_KERNEL_H in pre-boot environment: lots
   6 * errors about console_printk etc... on ARM */
   7#define _LINUX_KERNEL_H
   8
   9#include "zlib_inflate/inftrees.c"
  10#include "zlib_inflate/inffast.c"
  11#include "zlib_inflate/inflate.c"
  12
  13#else /* STATIC */
  14/* initramfs et al: linked */
  15
  16#include <linux/zutil.h>
  17
  18#include "zlib_inflate/inftrees.h"
  19#include "zlib_inflate/inffast.h"
  20#include "zlib_inflate/inflate.h"
  21
  22#include "zlib_inflate/infutil.h"
  23#include <linux/decompress/inflate.h>
  24
  25#endif /* STATIC */
  26
  27#include <linux/decompress/mm.h>
  28
  29#define GZIP_IOBUF_SIZE (16*1024)
  30
  31static long INIT nofill(void *buffer, unsigned long len)
  32{
  33        return -1;
  34}
  35
  36/* Included from initramfs et al code */
  37STATIC int INIT __gunzip(unsigned char *buf, long len,
  38                       long (*fill)(void*, unsigned long),
  39                       long (*flush)(void*, unsigned long),
  40                       unsigned char *out_buf, long out_len,
  41                       long *pos,
  42                       void(*error)(char *x)) {
  43        u8 *zbuf;
  44        struct z_stream_s *strm;
  45        int rc;
  46
  47        rc = -1;
  48        if (flush) {
  49                out_len = 0x8000; /* 32 K */
  50                out_buf = malloc(out_len);
  51        } else {
  52                if (!out_len)
  53                        out_len = ((size_t)~0) - (size_t)out_buf; /* 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        strm->avail_in = len - 10;
 104        /* skip over asciz filename */
 105        if (zbuf[3] & 0x8) {
 106                do {
 107                        /*
 108                         * If the filename doesn't fit into the buffer,
 109                         * the file is very probably corrupt. Don't try
 110                         * to read more data.
 111                         */
 112                        if (strm->avail_in == 0) {
 113                                error("header error");
 114                                goto gunzip_5;
 115                        }
 116                        --strm->avail_in;
 117                } while (*strm->next_in++);
 118        }
 119
 120        strm->next_out = out_buf;
 121        strm->avail_out = out_len;
 122
 123        rc = zlib_inflateInit2(strm, -MAX_WBITS);
 124
 125        if (!flush) {
 126                WS(strm)->inflate_state.wsize = 0;
 127                WS(strm)->inflate_state.window = NULL;
 128        }
 129
 130        while (rc == Z_OK) {
 131                if (strm->avail_in == 0) {
 132                        /* TODO: handle case where both pos and fill are set */
 133                        len = fill(zbuf, GZIP_IOBUF_SIZE);
 134                        if (len < 0) {
 135                                rc = -1;
 136                                error("read error");
 137                                break;
 138                        }
 139                        strm->next_in = zbuf;
 140                        strm->avail_in = len;
 141                }
 142                rc = zlib_inflate(strm, 0);
 143
 144                /* Write any data generated */
 145                if (flush && strm->next_out > out_buf) {
 146                        long l = strm->next_out - out_buf;
 147                        if (l != flush(out_buf, l)) {
 148                                rc = -1;
 149                                error("write error");
 150                                break;
 151                        }
 152                        strm->next_out = out_buf;
 153                        strm->avail_out = out_len;
 154                }
 155
 156                /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */
 157                if (rc == Z_STREAM_END) {
 158                        rc = 0;
 159                        break;
 160                } else if (rc != Z_OK) {
 161                        error("uncompression error");
 162                        rc = -1;
 163                }
 164        }
 165
 166        zlib_inflateEnd(strm);
 167        if (pos)
 168                /* add + 8 to skip over trailer */
 169                *pos = strm->next_in - zbuf+8;
 170
 171gunzip_5:
 172        free(strm->workspace);
 173gunzip_nomem4:
 174        free(strm);
 175gunzip_nomem3:
 176        if (!buf)
 177                free(zbuf);
 178gunzip_nomem2:
 179        if (flush)
 180                free(out_buf);
 181gunzip_nomem1:
 182        return rc; /* returns Z_OK (0) if successful */
 183}
 184
 185#ifndef PREBOOT
 186STATIC int INIT gunzip(unsigned char *buf, long len,
 187                       long (*fill)(void*, unsigned long),
 188                       long (*flush)(void*, unsigned long),
 189                       unsigned char *out_buf,
 190                       long *pos,
 191                       void (*error)(char *x))
 192{
 193        return __gunzip(buf, len, fill, flush, out_buf, 0, pos, error);
 194}
 195#else
 196STATIC int INIT __decompress(unsigned char *buf, long len,
 197                           long (*fill)(void*, unsigned long),
 198                           long (*flush)(void*, unsigned long),
 199                           unsigned char *out_buf, long out_len,
 200                           long *pos,
 201                           void (*error)(char *x))
 202{
 203        return __gunzip(buf, len, fill, flush, out_buf, out_len, pos, error);
 204}
 205#endif
 206