| // SPDX-License-Identifier: GPL-2.0 | |
| #include <fcntl.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <sys/stat.h> | |
| #include <sys/mman.h> | |
| #include <zlib.h> | |
| #include <linux/compiler.h> | |
| #include <internal/lib.h> | |
| #include "util/compress.h" | |
| #define CHUNK_SIZE 16384 | |
| int gzip_decompress_to_file(const char *input, int output_fd) | |
| { | |
| int ret = Z_STREAM_ERROR; | |
| int input_fd; | |
| void *ptr; | |
| int len; | |
| struct stat stbuf; | |
| unsigned char buf[CHUNK_SIZE]; | |
| z_stream zs = { | |
| .zalloc = Z_NULL, | |
| .zfree = Z_NULL, | |
| .opaque = Z_NULL, | |
| .avail_in = 0, | |
| .next_in = Z_NULL, | |
| }; | |
| input_fd = open(input, O_RDONLY); | |
| if (input_fd < 0) | |
| return -1; | |
| if (fstat(input_fd, &stbuf) < 0) | |
| goto out_close; | |
| ptr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_PRIVATE, input_fd, 0); | |
| if (ptr == MAP_FAILED) | |
| goto out_close; | |
| if (inflateInit2(&zs, 16 + MAX_WBITS) != Z_OK) | |
| goto out_unmap; | |
| zs.next_in = ptr; | |
| zs.avail_in = stbuf.st_size; | |
| do { | |
| zs.next_out = buf; | |
| zs.avail_out = CHUNK_SIZE; | |
| ret = inflate(&zs, Z_NO_FLUSH); | |
| switch (ret) { | |
| case Z_NEED_DICT: | |
| ret = Z_DATA_ERROR; | |
| /* fall through */ | |
| case Z_DATA_ERROR: | |
| case Z_MEM_ERROR: | |
| goto out; | |
| default: | |
| break; | |
| } | |
| len = CHUNK_SIZE - zs.avail_out; | |
| if (writen(output_fd, buf, len) != len) { | |
| ret = Z_DATA_ERROR; | |
| goto out; | |
| } | |
| } while (ret != Z_STREAM_END); | |
| out: | |
| inflateEnd(&zs); | |
| out_unmap: | |
| munmap(ptr, stbuf.st_size); | |
| out_close: | |
| close(input_fd); | |
| return ret == Z_STREAM_END ? 0 : -1; | |
| } | |
| bool gzip_is_compressed(const char *input) | |
| { | |
| int fd = open(input, O_RDONLY); | |
| const uint8_t magic[2] = { 0x1f, 0x8b }; | |
| char buf[2] = { 0 }; | |
| ssize_t rc; | |
| if (fd < 0) | |
| return false; | |
| rc = read(fd, buf, sizeof(buf)); | |
| close(fd); | |
| return rc == sizeof(buf) ? | |
| memcmp(buf, magic, sizeof(buf)) == 0 : false; | |
| } |