0001
0002 #include <fcntl.h>
0003 #include <stdio.h>
0004 #include <string.h>
0005 #include <unistd.h>
0006 #include <sys/stat.h>
0007 #include <sys/mman.h>
0008 #include <zlib.h>
0009 #include <linux/compiler.h>
0010 #include <internal/lib.h>
0011
0012 #include "util/compress.h"
0013
0014 #define CHUNK_SIZE 16384
0015
0016 int gzip_decompress_to_file(const char *input, int output_fd)
0017 {
0018 int ret = Z_STREAM_ERROR;
0019 int input_fd;
0020 void *ptr;
0021 int len;
0022 struct stat stbuf;
0023 unsigned char buf[CHUNK_SIZE];
0024 z_stream zs = {
0025 .zalloc = Z_NULL,
0026 .zfree = Z_NULL,
0027 .opaque = Z_NULL,
0028 .avail_in = 0,
0029 .next_in = Z_NULL,
0030 };
0031
0032 input_fd = open(input, O_RDONLY);
0033 if (input_fd < 0)
0034 return -1;
0035
0036 if (fstat(input_fd, &stbuf) < 0)
0037 goto out_close;
0038
0039 ptr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_PRIVATE, input_fd, 0);
0040 if (ptr == MAP_FAILED)
0041 goto out_close;
0042
0043 if (inflateInit2(&zs, 16 + MAX_WBITS) != Z_OK)
0044 goto out_unmap;
0045
0046 zs.next_in = ptr;
0047 zs.avail_in = stbuf.st_size;
0048
0049 do {
0050 zs.next_out = buf;
0051 zs.avail_out = CHUNK_SIZE;
0052
0053 ret = inflate(&zs, Z_NO_FLUSH);
0054 switch (ret) {
0055 case Z_NEED_DICT:
0056 ret = Z_DATA_ERROR;
0057
0058 case Z_DATA_ERROR:
0059 case Z_MEM_ERROR:
0060 goto out;
0061 default:
0062 break;
0063 }
0064
0065 len = CHUNK_SIZE - zs.avail_out;
0066 if (writen(output_fd, buf, len) != len) {
0067 ret = Z_DATA_ERROR;
0068 goto out;
0069 }
0070
0071 } while (ret != Z_STREAM_END);
0072
0073 out:
0074 inflateEnd(&zs);
0075 out_unmap:
0076 munmap(ptr, stbuf.st_size);
0077 out_close:
0078 close(input_fd);
0079
0080 return ret == Z_STREAM_END ? 0 : -1;
0081 }
0082
0083 bool gzip_is_compressed(const char *input)
0084 {
0085 int fd = open(input, O_RDONLY);
0086 const uint8_t magic[2] = { 0x1f, 0x8b };
0087 char buf[2] = { 0 };
0088 ssize_t rc;
0089
0090 if (fd < 0)
0091 return -1;
0092
0093 rc = read(fd, buf, sizeof(buf));
0094 close(fd);
0095 return rc == sizeof(buf) ?
0096 memcmp(buf, magic, sizeof(buf)) == 0 : false;
0097 }