xref: /openbmc/linux/tools/perf/util/lzma.c (revision 7a46404b)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2a43783aeSArnaldo Carvalho de Melo #include <errno.h>
380a32e5bSJiri Olsa #include <lzma.h>
480a32e5bSJiri Olsa #include <stdio.h>
580a32e5bSJiri Olsa #include <linux/compiler.h>
64b57fd44SJiri Olsa #include <sys/types.h>
74b57fd44SJiri Olsa #include <sys/stat.h>
84b57fd44SJiri Olsa #include <fcntl.h>
9611f0afeSArnaldo Carvalho de Melo #include "compress.h"
1080a32e5bSJiri Olsa #include "debug.h"
118520a98dSArnaldo Carvalho de Melo #include <string.h>
124b57fd44SJiri Olsa #include <unistd.h>
13fb71c86cSArnaldo Carvalho de Melo #include <internal/lib.h>
1480a32e5bSJiri Olsa 
1580a32e5bSJiri Olsa #define BUFSIZE 8192
1680a32e5bSJiri Olsa 
lzma_strerror(lzma_ret ret)1780a32e5bSJiri Olsa static const char *lzma_strerror(lzma_ret ret)
1880a32e5bSJiri Olsa {
1980a32e5bSJiri Olsa 	switch ((int) ret) {
2080a32e5bSJiri Olsa 	case LZMA_MEM_ERROR:
2180a32e5bSJiri Olsa 		return "Memory allocation failed";
2280a32e5bSJiri Olsa 	case LZMA_OPTIONS_ERROR:
2380a32e5bSJiri Olsa 		return "Unsupported decompressor flags";
2480a32e5bSJiri Olsa 	case LZMA_FORMAT_ERROR:
2580a32e5bSJiri Olsa 		return "The input is not in the .xz format";
2680a32e5bSJiri Olsa 	case LZMA_DATA_ERROR:
2780a32e5bSJiri Olsa 		return "Compressed file is corrupt";
2880a32e5bSJiri Olsa 	case LZMA_BUF_ERROR:
2980a32e5bSJiri Olsa 		return "Compressed file is truncated or otherwise corrupt";
3080a32e5bSJiri Olsa 	default:
3180a32e5bSJiri Olsa 		return "Unknown error, possibly a bug";
3280a32e5bSJiri Olsa 	}
3380a32e5bSJiri Olsa }
3480a32e5bSJiri Olsa 
lzma_decompress_to_file(const char * input,int output_fd)3580a32e5bSJiri Olsa int lzma_decompress_to_file(const char *input, int output_fd)
3680a32e5bSJiri Olsa {
3780a32e5bSJiri Olsa 	lzma_action action = LZMA_RUN;
3880a32e5bSJiri Olsa 	lzma_stream strm   = LZMA_STREAM_INIT;
3980a32e5bSJiri Olsa 	lzma_ret ret;
40ffe67c2fSShawn Lin 	int err = -1;
4180a32e5bSJiri Olsa 
4280a32e5bSJiri Olsa 	u8 buf_in[BUFSIZE];
4380a32e5bSJiri Olsa 	u8 buf_out[BUFSIZE];
4480a32e5bSJiri Olsa 	FILE *infile;
4580a32e5bSJiri Olsa 
4680a32e5bSJiri Olsa 	infile = fopen(input, "rb");
4780a32e5bSJiri Olsa 	if (!infile) {
48*7a46404bSArnaldo Carvalho de Melo 		pr_debug("lzma: fopen failed on %s: '%s'\n", input, strerror(errno));
4980a32e5bSJiri Olsa 		return -1;
5080a32e5bSJiri Olsa 	}
5180a32e5bSJiri Olsa 
5280a32e5bSJiri Olsa 	ret = lzma_stream_decoder(&strm, UINT64_MAX, LZMA_CONCATENATED);
5380a32e5bSJiri Olsa 	if (ret != LZMA_OK) {
54*7a46404bSArnaldo Carvalho de Melo 		pr_debug("lzma: lzma_stream_decoder failed %s (%d)\n", lzma_strerror(ret), ret);
55ffe67c2fSShawn Lin 		goto err_fclose;
5680a32e5bSJiri Olsa 	}
5780a32e5bSJiri Olsa 
5880a32e5bSJiri Olsa 	strm.next_in   = NULL;
5980a32e5bSJiri Olsa 	strm.avail_in  = 0;
6080a32e5bSJiri Olsa 	strm.next_out  = buf_out;
6180a32e5bSJiri Olsa 	strm.avail_out = sizeof(buf_out);
6280a32e5bSJiri Olsa 
6380a32e5bSJiri Olsa 	while (1) {
6480a32e5bSJiri Olsa 		if (strm.avail_in == 0 && !feof(infile)) {
6580a32e5bSJiri Olsa 			strm.next_in  = buf_in;
6680a32e5bSJiri Olsa 			strm.avail_in = fread(buf_in, 1, sizeof(buf_in), infile);
6780a32e5bSJiri Olsa 
6880a32e5bSJiri Olsa 			if (ferror(infile)) {
69*7a46404bSArnaldo Carvalho de Melo 				pr_debug("lzma: read error: %s\n", strerror(errno));
70f8cbb0f9SRiccardo Mancini 				goto err_lzma_end;
7180a32e5bSJiri Olsa 			}
7280a32e5bSJiri Olsa 
7380a32e5bSJiri Olsa 			if (feof(infile))
7480a32e5bSJiri Olsa 				action = LZMA_FINISH;
7580a32e5bSJiri Olsa 		}
7680a32e5bSJiri Olsa 
7780a32e5bSJiri Olsa 		ret = lzma_code(&strm, action);
7880a32e5bSJiri Olsa 
7980a32e5bSJiri Olsa 		if (strm.avail_out == 0 || ret == LZMA_STREAM_END) {
8080a32e5bSJiri Olsa 			ssize_t write_size = sizeof(buf_out) - strm.avail_out;
8180a32e5bSJiri Olsa 
8280a32e5bSJiri Olsa 			if (writen(output_fd, buf_out, write_size) != write_size) {
83*7a46404bSArnaldo Carvalho de Melo 				pr_debug("lzma: write error: %s\n", strerror(errno));
84f8cbb0f9SRiccardo Mancini 				goto err_lzma_end;
8580a32e5bSJiri Olsa 			}
8680a32e5bSJiri Olsa 
8780a32e5bSJiri Olsa 			strm.next_out  = buf_out;
8880a32e5bSJiri Olsa 			strm.avail_out = sizeof(buf_out);
8980a32e5bSJiri Olsa 		}
9080a32e5bSJiri Olsa 
9180a32e5bSJiri Olsa 		if (ret != LZMA_OK) {
9280a32e5bSJiri Olsa 			if (ret == LZMA_STREAM_END)
93ffe67c2fSShawn Lin 				break;
9480a32e5bSJiri Olsa 
95*7a46404bSArnaldo Carvalho de Melo 			pr_debug("lzma: failed %s\n", lzma_strerror(ret));
96f8cbb0f9SRiccardo Mancini 			goto err_lzma_end;
9780a32e5bSJiri Olsa 		}
9880a32e5bSJiri Olsa 	}
9980a32e5bSJiri Olsa 
100ffe67c2fSShawn Lin 	err = 0;
101f8cbb0f9SRiccardo Mancini err_lzma_end:
102f8cbb0f9SRiccardo Mancini 	lzma_end(&strm);
103ffe67c2fSShawn Lin err_fclose:
10480a32e5bSJiri Olsa 	fclose(infile);
105ffe67c2fSShawn Lin 	return err;
10680a32e5bSJiri Olsa }
1078b42b7e5SJiri Olsa 
lzma_is_compressed(const char * input)1084b57fd44SJiri Olsa bool lzma_is_compressed(const char *input)
1098b42b7e5SJiri Olsa {
1104b57fd44SJiri Olsa 	int fd = open(input, O_RDONLY);
1114b57fd44SJiri Olsa 	const uint8_t magic[6] = { 0xFD, '7', 'z', 'X', 'Z', 0x00 };
1124b57fd44SJiri Olsa 	char buf[6] = { 0 };
1134b57fd44SJiri Olsa 	ssize_t rc;
1144b57fd44SJiri Olsa 
1154b57fd44SJiri Olsa 	if (fd < 0)
1164b57fd44SJiri Olsa 		return -1;
1174b57fd44SJiri Olsa 
1184b57fd44SJiri Olsa 	rc = read(fd, buf, sizeof(buf));
1194b57fd44SJiri Olsa 	close(fd);
1204b57fd44SJiri Olsa 	return rc == sizeof(buf) ?
1214b57fd44SJiri Olsa 	       memcmp(buf, magic, sizeof(buf)) == 0 : false;
1228b42b7e5SJiri Olsa }
123