| David S. Miller | d4faaec | 2007-10-11 22:15:08 -0700 | [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 | } |