| #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_obj(*strm); | |
| 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 */ | |
| } |