1 #include <stdio.h> 2 #include <unistd.h> 3 #include <sys/stat.h> 4 #include <sys/mman.h> 5 #include <zlib.h> 6 7 #include "util/util.h" 8 #include "util/debug.h" 9 10 11 #define CHUNK_SIZE 16384 12 13 int gzip_decompress_to_file(const char *input, int output_fd) 14 { 15 int ret = Z_STREAM_ERROR; 16 int input_fd; 17 void *ptr; 18 int len; 19 struct stat stbuf; 20 unsigned char buf[CHUNK_SIZE]; 21 z_stream zs = { 22 .zalloc = Z_NULL, 23 .zfree = Z_NULL, 24 .opaque = Z_NULL, 25 .avail_in = 0, 26 .next_in = Z_NULL, 27 }; 28 29 input_fd = open(input, O_RDONLY); 30 if (input_fd < 0) 31 return -1; 32 33 if (fstat(input_fd, &stbuf) < 0) 34 goto out_close; 35 36 ptr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_PRIVATE, input_fd, 0); 37 if (ptr == MAP_FAILED) 38 goto out_close; 39 40 if (inflateInit2(&zs, 16 + MAX_WBITS) != Z_OK) 41 goto out_unmap; 42 43 zs.next_in = ptr; 44 zs.avail_in = stbuf.st_size; 45 46 do { 47 zs.next_out = buf; 48 zs.avail_out = CHUNK_SIZE; 49 50 ret = inflate(&zs, Z_NO_FLUSH); 51 switch (ret) { 52 case Z_NEED_DICT: 53 ret = Z_DATA_ERROR; 54 /* fall through */ 55 case Z_DATA_ERROR: 56 case Z_MEM_ERROR: 57 goto out; 58 default: 59 break; 60 } 61 62 len = CHUNK_SIZE - zs.avail_out; 63 if (writen(output_fd, buf, len) != len) { 64 ret = Z_DATA_ERROR; 65 goto out; 66 } 67 68 } while (ret != Z_STREAM_END); 69 70 out: 71 inflateEnd(&zs); 72 out_unmap: 73 munmap(ptr, stbuf.st_size); 74 out_close: 75 close(input_fd); 76 77 return ret == Z_STREAM_END ? 0 : -1; 78 } 79