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