| xj | b04a402 | 2021-11-25 15:01:52 +0800 | [diff] [blame] | 1 | #include <linux/zutil.h> | 
|  | 2 | #include <linux/errno.h> | 
|  | 3 | #include <linux/slab.h> | 
|  | 4 | #include <linux/vmalloc.h> | 
|  | 5 |  | 
|  | 6 | /* Utility function: initialize zlib, unpack binary blob, clean up zlib, | 
|  | 7 | * return len or negative error code. | 
|  | 8 | */ | 
|  | 9 | int zlib_inflate_blob(void *gunzip_buf, unsigned int sz, | 
|  | 10 | const void *buf, unsigned int len) | 
|  | 11 | { | 
|  | 12 | const u8 *zbuf = buf; | 
|  | 13 | struct z_stream_s *strm; | 
|  | 14 | int rc; | 
|  | 15 |  | 
|  | 16 | rc = -ENOMEM; | 
|  | 17 | strm = kmalloc(sizeof(*strm), GFP_KERNEL); | 
|  | 18 | if (strm == NULL) | 
|  | 19 | goto gunzip_nomem1; | 
|  | 20 | strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); | 
|  | 21 | if (strm->workspace == NULL) | 
|  | 22 | goto gunzip_nomem2; | 
|  | 23 |  | 
|  | 24 | /* gzip header (1f,8b,08... 10 bytes total + possible asciz filename) | 
|  | 25 | * expected to be stripped from input | 
|  | 26 | */ | 
|  | 27 | strm->next_in = zbuf; | 
|  | 28 | strm->avail_in = len; | 
|  | 29 | strm->next_out = gunzip_buf; | 
|  | 30 | strm->avail_out = sz; | 
|  | 31 |  | 
|  | 32 | rc = zlib_inflateInit2(strm, -MAX_WBITS); | 
|  | 33 | if (rc == Z_OK) { | 
|  | 34 | rc = zlib_inflate(strm, Z_FINISH); | 
|  | 35 | /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */ | 
|  | 36 | if (rc == Z_STREAM_END) | 
|  | 37 | rc = sz - strm->avail_out; | 
|  | 38 | else | 
|  | 39 | rc = -EINVAL; | 
|  | 40 | zlib_inflateEnd(strm); | 
|  | 41 | } else | 
|  | 42 | rc = -EINVAL; | 
|  | 43 |  | 
|  | 44 | kfree(strm->workspace); | 
|  | 45 | gunzip_nomem2: | 
|  | 46 | kfree(strm); | 
|  | 47 | gunzip_nomem1: | 
|  | 48 | return rc; /* returns Z_OK (0) if successful */ | 
|  | 49 | } |