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 #include <linux/compiler.h> 9 10 #include "util/compress.h" 11 #include "util/util.h" 12 #include "util/debug.h" 13 14 15 #define CHUNK_SIZE 16384 16 17 int gzip_decompress_to_file(const char *input, int output_fd) 18 { 19 int ret = Z_STREAM_ERROR; 20 int input_fd; 21 void *ptr; 22 int len; 23 struct stat stbuf; 24 unsigned char buf[CHUNK_SIZE]; 25 z_stream zs = { 26 .zalloc = Z_NULL, 27 .zfree = Z_NULL, 28 .opaque = Z_NULL, 29 .avail_in = 0, 30 .next_in = Z_NULL, 31 }; 32 33 input_fd = open(input, O_RDONLY); 34 if (input_fd < 0) 35 return -1; 36 37 if (fstat(input_fd, &stbuf) < 0) 38 goto out_close; 39 40 ptr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_PRIVATE, input_fd, 0); 41 if (ptr == MAP_FAILED) 42 goto out_close; 43 44 if (inflateInit2(&zs, 16 + MAX_WBITS) != Z_OK) 45 goto out_unmap; 46 47 zs.next_in = ptr; 48 zs.avail_in = stbuf.st_size; 49 50 do { 51 zs.next_out = buf; 52 zs.avail_out = CHUNK_SIZE; 53 54 ret = inflate(&zs, Z_NO_FLUSH); 55 switch (ret) { 56 case Z_NEED_DICT: 57 ret = Z_DATA_ERROR; 58 /* fall through */ 59 case Z_DATA_ERROR: 60 case Z_MEM_ERROR: 61 goto out; 62 default: 63 break; 64 } 65 66 len = CHUNK_SIZE - zs.avail_out; 67 if (writen(output_fd, buf, len) != len) { 68 ret = Z_DATA_ERROR; 69 goto out; 70 } 71 72 } while (ret != Z_STREAM_END); 73 74 out: 75 inflateEnd(&zs); 76 out_unmap: 77 munmap(ptr, stbuf.st_size); 78 out_close: 79 close(input_fd); 80 81 return ret == Z_STREAM_END ? 0 : -1; 82 } 83 84 bool gzip_is_compressed(const char *input) 85 { 86 int fd = open(input, O_RDONLY); 87 const uint8_t magic[2] = { 0x1f, 0x8b }; 88 char buf[2] = { 0 }; 89 ssize_t rc; 90 91 if (fd < 0) 92 return -1; 93 94 rc = read(fd, buf, sizeof(buf)); 95 close(fd); 96 return rc == sizeof(buf) ? 97 memcmp(buf, magic, sizeof(buf)) == 0 : false; 98 } 99