| #include <linux/zutil.h> |
| #include <linux/errno.h> |
| #include <linux/slab.h> |
| #include <linux/vmalloc.h> |
| |
| /* Utility function: initialize zlib, unpack binary blob, clean up zlib, |
| * return len or negative error code. |
| */ |
| int zlib_inflate_blob(void *gunzip_buf, unsigned int sz, |
| const void *buf, unsigned int len) |
| { |
| const u8 *zbuf = buf; |
| struct z_stream_s *strm; |
| int rc; |
| |
| rc = -ENOMEM; |
| strm = kmalloc(sizeof(*strm), GFP_KERNEL); |
| if (strm == NULL) |
| goto gunzip_nomem1; |
| strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); |
| if (strm->workspace == NULL) |
| goto gunzip_nomem2; |
| |
| /* gzip header (1f,8b,08... 10 bytes total + possible asciz filename) |
| * expected to be stripped from input |
| */ |
| strm->next_in = zbuf; |
| strm->avail_in = len; |
| strm->next_out = gunzip_buf; |
| strm->avail_out = sz; |
| |
| rc = zlib_inflateInit2(strm, -MAX_WBITS); |
| if (rc == Z_OK) { |
| rc = zlib_inflate(strm, Z_FINISH); |
| /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */ |
| if (rc == Z_STREAM_END) |
| rc = sz - strm->avail_out; |
| else |
| rc = -EINVAL; |
| zlib_inflateEnd(strm); |
| } else |
| rc = -EINVAL; |
| |
| kfree(strm->workspace); |
| gunzip_nomem2: |
| kfree(strm); |
| gunzip_nomem1: |
| return rc; /* returns Z_OK (0) if successful */ |
| } |