18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <fcntl.h>
38c2ecf20Sopenharmony_ci#include <stdio.h>
48c2ecf20Sopenharmony_ci#include <string.h>
58c2ecf20Sopenharmony_ci#include <unistd.h>
68c2ecf20Sopenharmony_ci#include <sys/stat.h>
78c2ecf20Sopenharmony_ci#include <sys/mman.h>
88c2ecf20Sopenharmony_ci#include <zlib.h>
98c2ecf20Sopenharmony_ci#include <linux/compiler.h>
108c2ecf20Sopenharmony_ci#include <internal/lib.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include "util/compress.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define CHUNK_SIZE  16384
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ciint gzip_decompress_to_file(const char *input, int output_fd)
178c2ecf20Sopenharmony_ci{
188c2ecf20Sopenharmony_ci	int ret = Z_STREAM_ERROR;
198c2ecf20Sopenharmony_ci	int input_fd;
208c2ecf20Sopenharmony_ci	void *ptr;
218c2ecf20Sopenharmony_ci	int len;
228c2ecf20Sopenharmony_ci	struct stat stbuf;
238c2ecf20Sopenharmony_ci	unsigned char buf[CHUNK_SIZE];
248c2ecf20Sopenharmony_ci	z_stream zs = {
258c2ecf20Sopenharmony_ci		.zalloc		= Z_NULL,
268c2ecf20Sopenharmony_ci		.zfree		= Z_NULL,
278c2ecf20Sopenharmony_ci		.opaque		= Z_NULL,
288c2ecf20Sopenharmony_ci		.avail_in	= 0,
298c2ecf20Sopenharmony_ci		.next_in	= Z_NULL,
308c2ecf20Sopenharmony_ci	};
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	input_fd = open(input, O_RDONLY);
338c2ecf20Sopenharmony_ci	if (input_fd < 0)
348c2ecf20Sopenharmony_ci		return -1;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	if (fstat(input_fd, &stbuf) < 0)
378c2ecf20Sopenharmony_ci		goto out_close;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	ptr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_PRIVATE, input_fd, 0);
408c2ecf20Sopenharmony_ci	if (ptr == MAP_FAILED)
418c2ecf20Sopenharmony_ci		goto out_close;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	if (inflateInit2(&zs, 16 + MAX_WBITS) != Z_OK)
448c2ecf20Sopenharmony_ci		goto out_unmap;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	zs.next_in = ptr;
478c2ecf20Sopenharmony_ci	zs.avail_in = stbuf.st_size;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	do {
508c2ecf20Sopenharmony_ci		zs.next_out = buf;
518c2ecf20Sopenharmony_ci		zs.avail_out = CHUNK_SIZE;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci		ret = inflate(&zs, Z_NO_FLUSH);
548c2ecf20Sopenharmony_ci		switch (ret) {
558c2ecf20Sopenharmony_ci		case Z_NEED_DICT:
568c2ecf20Sopenharmony_ci			ret = Z_DATA_ERROR;
578c2ecf20Sopenharmony_ci			/* fall through */
588c2ecf20Sopenharmony_ci		case Z_DATA_ERROR:
598c2ecf20Sopenharmony_ci		case Z_MEM_ERROR:
608c2ecf20Sopenharmony_ci			goto out;
618c2ecf20Sopenharmony_ci		default:
628c2ecf20Sopenharmony_ci			break;
638c2ecf20Sopenharmony_ci		}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci		len = CHUNK_SIZE - zs.avail_out;
668c2ecf20Sopenharmony_ci		if (writen(output_fd, buf, len) != len) {
678c2ecf20Sopenharmony_ci			ret = Z_DATA_ERROR;
688c2ecf20Sopenharmony_ci			goto out;
698c2ecf20Sopenharmony_ci		}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	} while (ret != Z_STREAM_END);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ciout:
748c2ecf20Sopenharmony_ci	inflateEnd(&zs);
758c2ecf20Sopenharmony_ciout_unmap:
768c2ecf20Sopenharmony_ci	munmap(ptr, stbuf.st_size);
778c2ecf20Sopenharmony_ciout_close:
788c2ecf20Sopenharmony_ci	close(input_fd);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	return ret == Z_STREAM_END ? 0 : -1;
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cibool gzip_is_compressed(const char *input)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	int fd = open(input, O_RDONLY);
868c2ecf20Sopenharmony_ci	const uint8_t magic[2] = { 0x1f, 0x8b };
878c2ecf20Sopenharmony_ci	char buf[2] = { 0 };
888c2ecf20Sopenharmony_ci	ssize_t rc;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	if (fd < 0)
918c2ecf20Sopenharmony_ci		return -1;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	rc = read(fd, buf, sizeof(buf));
948c2ecf20Sopenharmony_ci	close(fd);
958c2ecf20Sopenharmony_ci	return rc == sizeof(buf) ?
968c2ecf20Sopenharmony_ci	       memcmp(buf, magic, sizeof(buf)) == 0 : false;
978c2ecf20Sopenharmony_ci}
98