1 2 #include <stdarg.h> 3 #include <errno.h> 4 #include <stdio.h> 5 #include <unistd.h> 6 #include <lzma.h> 7 8 static off_t 9 unxz(int i, int o, char *pre, size_t prelen, off_t *bytes_in) 10 { 11 lzma_stream strm = LZMA_STREAM_INIT; 12 static const int flags = LZMA_TELL_UNSUPPORTED_CHECK|LZMA_CONCATENATED; 13 lzma_ret ret; 14 lzma_action action = LZMA_RUN; 15 off_t bytes_out, bp; 16 uint8_t ibuf[BUFSIZ]; 17 uint8_t obuf[BUFSIZ]; 18 19 if (bytes_in == NULL) 20 bytes_in = &bp; 21 22 strm.next_in = ibuf; 23 memcpy(ibuf, pre, prelen); 24 strm.avail_in = read(i, ibuf + prelen, sizeof(ibuf) - prelen); 25 if (strm.avail_in == (size_t)-1) 26 maybe_err("read failed"); 27 strm.avail_in += prelen; 28 *bytes_in = strm.avail_in; 29 30 if ((ret = lzma_stream_decoder(&strm, UINT64_MAX, flags)) != LZMA_OK) 31 maybe_errx("Can't initialize decoder (%d)", ret); 32 33 strm.next_out = NULL; 34 strm.avail_out = 0; 35 if ((ret = lzma_code(&strm, LZMA_RUN)) != LZMA_OK) 36 maybe_errx("Can't read headers (%d)", ret); 37 38 bytes_out = 0; 39 strm.next_out = obuf; 40 strm.avail_out = sizeof(obuf); 41 42 for (;;) { 43 if (strm.avail_in == 0) { 44 strm.next_in = ibuf; 45 strm.avail_in = read(i, ibuf, sizeof(ibuf)); 46 switch (strm.avail_in) { 47 case (size_t)-1: 48 maybe_err("read failed"); 49 /*NOTREACHED*/ 50 case 0: 51 action = LZMA_FINISH; 52 break; 53 default: 54 *bytes_in += strm.avail_in; 55 break; 56 } 57 } 58 59 ret = lzma_code(&strm, action); 60 61 // Write and check write error before checking decoder error. 62 // This way as much data as possible gets written to output 63 // even if decoder detected an error. 64 if (strm.avail_out == 0 || ret != LZMA_OK) { 65 const size_t write_size = sizeof(obuf) - strm.avail_out; 66 67 if (write(o, obuf, write_size) != (ssize_t)write_size) 68 maybe_err("write failed"); 69 70 strm.next_out = obuf; 71 strm.avail_out = sizeof(obuf); 72 bytes_out += write_size; 73 } 74 75 if (ret != LZMA_OK) { 76 if (ret == LZMA_STREAM_END) { 77 // Check that there's no trailing garbage. 78 if (strm.avail_in != 0 || read(i, ibuf, 1)) 79 ret = LZMA_DATA_ERROR; 80 else { 81 lzma_end(&strm); 82 return bytes_out; 83 } 84 } 85 86 const char *msg; 87 switch (ret) { 88 case LZMA_MEM_ERROR: 89 msg = strerror(ENOMEM); 90 break; 91 92 case LZMA_FORMAT_ERROR: 93 msg = "File format not recognized"; 94 break; 95 96 case LZMA_OPTIONS_ERROR: 97 // FIXME: Better message? 98 msg = "Unsupported compression options"; 99 break; 100 101 case LZMA_DATA_ERROR: 102 msg = "File is corrupt"; 103 break; 104 105 case LZMA_BUF_ERROR: 106 msg = "Unexpected end of input"; 107 break; 108 109 case LZMA_MEMLIMIT_ERROR: 110 msg = "Reached memory limit"; 111 break; 112 113 default: 114 msg = "Unknown error (%d)"; 115 break; 116 } 117 118 maybe_errx(msg, ret); 119 } 120 } 121 } 122