50 lines
		
	
	
	
		
			1.2 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			50 lines
		
	
	
	
		
			1.2 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
|   | #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 */ | ||
|  | } |