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