ALSA: hda - Fix access-after-free in patch_realtek.c
[linux-2.6.git] / lib / decompress_inflate.c
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
30 static int nofill(void *buffer, unsigned int len)
31 {
32         return -1;
33 }
34
35 /* Included from initramfs et al code */
36 STATIC 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
162 gunzip_5:
163         free(strm->workspace);
164 gunzip_nomem4:
165         free(strm);
166 gunzip_nomem3:
167         if (!buf)
168                 free(zbuf);
169 gunzip_nomem2:
170         if (flush)
171                 free(out_buf);
172 gunzip_nomem1:
173         return rc; /* returns Z_OK (0) if successful */
174 }
175
176 #define decompress gunzip