diff options
Diffstat (limited to 'tools/perf/util/zlib.c')
| -rw-r--r-- | tools/perf/util/zlib.c | 78 | 
1 files changed, 78 insertions, 0 deletions
diff --git a/tools/perf/util/zlib.c b/tools/perf/util/zlib.c new file mode 100644 index 000000000000..495a449fc25c --- /dev/null +++ b/tools/perf/util/zlib.c @@ -0,0 +1,78 @@ +#include <stdio.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <zlib.h> + +#include "util/util.h" +#include "util/debug.h" + + +#define CHUNK_SIZE  16384 + +int gzip_decompress_to_file(const char *input, int output_fd) +{ +	int ret = Z_STREAM_ERROR; +	int input_fd; +	void *ptr; +	int len; +	struct stat stbuf; +	unsigned char buf[CHUNK_SIZE]; +	z_stream zs = { +		.zalloc		= Z_NULL, +		.zfree		= Z_NULL, +		.opaque		= Z_NULL, +		.avail_in	= 0, +		.next_in	= Z_NULL, +	}; + +	input_fd = open(input, O_RDONLY); +	if (input_fd < 0) +		return -1; + +	if (fstat(input_fd, &stbuf) < 0) +		goto out_close; + +	ptr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_PRIVATE, input_fd, 0); +	if (ptr == MAP_FAILED) +		goto out_close; + +	if (inflateInit2(&zs, 16 + MAX_WBITS) != Z_OK) +		goto out_unmap; + +	zs.next_in = ptr; +	zs.avail_in = stbuf.st_size; + +	do { +		zs.next_out = buf; +		zs.avail_out = CHUNK_SIZE; + +		ret = inflate(&zs, Z_NO_FLUSH); +		switch (ret) { +		case Z_NEED_DICT: +			ret = Z_DATA_ERROR; +			/* fall through */ +		case Z_DATA_ERROR: +		case Z_MEM_ERROR: +			goto out; +		default: +			break; +		} + +		len = CHUNK_SIZE - zs.avail_out; +		if (writen(output_fd, buf, len) != len) { +			ret = Z_DATA_ERROR; +			goto out; +		} + +	} while (ret != Z_STREAM_END); + +out: +	inflateEnd(&zs); +out_unmap: +	munmap(ptr, stbuf.st_size); +out_close: +	close(input_fd); + +	return ret == Z_STREAM_END ? 0 : -1; +}  |