162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <fcntl.h>
362306a36Sopenharmony_ci#include <stdio.h>
462306a36Sopenharmony_ci#include <string.h>
562306a36Sopenharmony_ci#include <unistd.h>
662306a36Sopenharmony_ci#include <sys/stat.h>
762306a36Sopenharmony_ci#include <sys/mman.h>
862306a36Sopenharmony_ci#include <zlib.h>
962306a36Sopenharmony_ci#include <linux/compiler.h>
1062306a36Sopenharmony_ci#include <internal/lib.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "util/compress.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define CHUNK_SIZE  16384
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ciint gzip_decompress_to_file(const char *input, int output_fd)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	int ret = Z_STREAM_ERROR;
1962306a36Sopenharmony_ci	int input_fd;
2062306a36Sopenharmony_ci	void *ptr;
2162306a36Sopenharmony_ci	int len;
2262306a36Sopenharmony_ci	struct stat stbuf;
2362306a36Sopenharmony_ci	unsigned char buf[CHUNK_SIZE];
2462306a36Sopenharmony_ci	z_stream zs = {
2562306a36Sopenharmony_ci		.zalloc		= Z_NULL,
2662306a36Sopenharmony_ci		.zfree		= Z_NULL,
2762306a36Sopenharmony_ci		.opaque		= Z_NULL,
2862306a36Sopenharmony_ci		.avail_in	= 0,
2962306a36Sopenharmony_ci		.next_in	= Z_NULL,
3062306a36Sopenharmony_ci	};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	input_fd = open(input, O_RDONLY);
3362306a36Sopenharmony_ci	if (input_fd < 0)
3462306a36Sopenharmony_ci		return -1;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	if (fstat(input_fd, &stbuf) < 0)
3762306a36Sopenharmony_ci		goto out_close;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	ptr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_PRIVATE, input_fd, 0);
4062306a36Sopenharmony_ci	if (ptr == MAP_FAILED)
4162306a36Sopenharmony_ci		goto out_close;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	if (inflateInit2(&zs, 16 + MAX_WBITS) != Z_OK)
4462306a36Sopenharmony_ci		goto out_unmap;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	zs.next_in = ptr;
4762306a36Sopenharmony_ci	zs.avail_in = stbuf.st_size;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	do {
5062306a36Sopenharmony_ci		zs.next_out = buf;
5162306a36Sopenharmony_ci		zs.avail_out = CHUNK_SIZE;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci		ret = inflate(&zs, Z_NO_FLUSH);
5462306a36Sopenharmony_ci		switch (ret) {
5562306a36Sopenharmony_ci		case Z_NEED_DICT:
5662306a36Sopenharmony_ci			ret = Z_DATA_ERROR;
5762306a36Sopenharmony_ci			/* fall through */
5862306a36Sopenharmony_ci		case Z_DATA_ERROR:
5962306a36Sopenharmony_ci		case Z_MEM_ERROR:
6062306a36Sopenharmony_ci			goto out;
6162306a36Sopenharmony_ci		default:
6262306a36Sopenharmony_ci			break;
6362306a36Sopenharmony_ci		}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci		len = CHUNK_SIZE - zs.avail_out;
6662306a36Sopenharmony_ci		if (writen(output_fd, buf, len) != len) {
6762306a36Sopenharmony_ci			ret = Z_DATA_ERROR;
6862306a36Sopenharmony_ci			goto out;
6962306a36Sopenharmony_ci		}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	} while (ret != Z_STREAM_END);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ciout:
7462306a36Sopenharmony_ci	inflateEnd(&zs);
7562306a36Sopenharmony_ciout_unmap:
7662306a36Sopenharmony_ci	munmap(ptr, stbuf.st_size);
7762306a36Sopenharmony_ciout_close:
7862306a36Sopenharmony_ci	close(input_fd);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	return ret == Z_STREAM_END ? 0 : -1;
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cibool gzip_is_compressed(const char *input)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	int fd = open(input, O_RDONLY);
8662306a36Sopenharmony_ci	const uint8_t magic[2] = { 0x1f, 0x8b };
8762306a36Sopenharmony_ci	char buf[2] = { 0 };
8862306a36Sopenharmony_ci	ssize_t rc;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	if (fd < 0)
9162306a36Sopenharmony_ci		return -1;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	rc = read(fd, buf, sizeof(buf));
9462306a36Sopenharmony_ci	close(fd);
9562306a36Sopenharmony_ci	return rc == sizeof(buf) ?
9662306a36Sopenharmony_ci	       memcmp(buf, magic, sizeof(buf)) == 0 : false;
9762306a36Sopenharmony_ci}
98