root/tools/perf/util/zlib.c
// 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;
}