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