GNU Linux-libre 4.9.290-gnu1
[releases.git] / lib / decompress_inflate.c
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
31 static long INIT nofill(void *buffer, unsigned long len)
32 {
33         return -1;
34 }
35
36 /* Included from initramfs et al code */
37 STATIC 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
171 gunzip_5:
172         free(strm->workspace);
173 gunzip_nomem4:
174         free(strm);
175 gunzip_nomem3:
176         if (!buf)
177                 free(zbuf);
178 gunzip_nomem2:
179         if (flush)
180                 free(out_buf);
181 gunzip_nomem1:
182         return rc; /* returns Z_OK (0) if successful */
183 }
184
185 #ifndef PREBOOT
186 STATIC 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
196 STATIC 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