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