// don't inline, to be friendly to js engine osr void __attribute__ ((noinline)) doit(char *buffer, int size, int i) { static char *buffer2 = NULL; static char *buffer3 = NULL; unsigned long maxCompressedSize = lzma_stream_buffer_bound(size); if (!buffer2) buffer2 = (char*)malloc(maxCompressedSize); if (!buffer3) buffer3 = (char*)malloc(size); size_t compressedSize = 0; int ret = lzma_easy_buffer_encode(LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC64, NULL, (const uint8_t*)buffer, size, (uint8_t*)buffer2, &compressedSize, maxCompressedSize); assert(ret == LZMA_OK); if (i == 0) printf("sizes: %d,%d\n", size, compressedSize); lzma_stream strm = LZMA_STREAM_INIT; ret = lzma_stream_decoder(&strm, UINT64_MAX, 0); assert(ret == LZMA_OK); strm.next_in = (const uint8_t*)buffer2; strm.avail_in = compressedSize; strm.next_out = (uint8_t*)buffer3; strm.avail_out = size; ret = lzma_code (&strm, LZMA_FINISH); assert(ret == LZMA_OK || ret == LZMA_STREAM_END); size_t decompressedSize = size - strm.avail_out; assert(decompressedSize == size); if (i == 0) assert(strcmp(buffer, buffer3) == 0); }
static int php_xz_init_decoder(struct php_xz_stream_data_t *self) { lzma_stream *strm = &self->strm; lzma_ret ret = lzma_stream_decoder(strm, UINT64_MAX, LZMA_CONCATENATED); if (ret == LZMA_OK) { self->in_buf_sz = XZ_INBUF_SIZE; self->out_buf_sz = XZ_OUTBUF_SIZE; self->in_buf = emalloc(self->in_buf_sz); self->out_buf = emalloc(self->out_buf_sz); self->out_buf_idx = self->out_buf; strm->next_in = self->in_buf; strm->avail_in = 0; strm->next_out = self->out_buf; strm->avail_out = self->out_buf_sz; return 1; } /*const char *msg; switch(ret) { case LZMA_MEM_ERROR: msg = "Memory allocation"; break; case LZMA_OPTIONS_ERROR: msg = "Unsupported decompress flags"; break; default: msg = "Unknown"; break; }*/ return 0; }
static MojoInput *make_xz_input(MojoInput *origio) { MojoInput *io = NULL; XZinfo *info = (XZinfo *) xmalloc(sizeof (XZinfo)); lzma_stream *strm = &info->stream; // UINT64_MAX is the memory usage limit (so basically, no artificial // limit here). Internally, this holds its entire dictionary in // RAM (8 megabytes by default), plus a few other structures, so we // shouldn't eat tons of memory in the normal case. Note that the // dictionary can max out at _four gigabytes_, but obviously no one does // that. initializeXZStream(strm); if (lzma_stream_decoder(strm, UINT64_MAX, LZMA_CONCATENATED) != LZMA_OK) { free(info); return NULL; } // if info->origio = origio; io = (MojoInput *) xmalloc(sizeof (MojoInput)); io->ready = MojoInput_xz_ready; io->read = MojoInput_xz_read; io->seek = MojoInput_xz_seek; io->tell = MojoInput_xz_tell; io->length = MojoInput_xz_length; io->duplicate = MojoInput_xz_duplicate; io->close = MojoInput_xz_close; io->opaque = info; return io; } // make_xz_input
/* * Setup state for decoding a strip. */ static int LZMAPreDecode(TIFF* tif, uint16 s) { static const char module[] = "LZMAPreDecode"; LZMAState* sp = DecoderState(tif); lzma_ret ret; (void) s; assert(sp != NULL); if( (sp->state & LSTATE_INIT_DECODE) == 0 ) tif->tif_setupdecode(tif); sp->stream.next_in = tif->tif_rawdata; sp->stream.avail_in = (size_t) tif->tif_rawcc; if ((tmsize_t)sp->stream.avail_in != tif->tif_rawcc) { TIFFErrorExt(tif->tif_clientdata, module, "Liblzma cannot deal with buffers this size"); return 0; } /* * Disable memory limit when decoding. UINT64_MAX is a flag to disable * the limit, we are passing (uint64_t)-1 which should be the same. */ ret = lzma_stream_decoder(&sp->stream, (uint64_t)-1, 0); if (ret != LZMA_OK) { TIFFErrorExt(tif->tif_clientdata, module, "Error initializing the stream decoder, %s", LZMAStrerror(ret)); return 0; } return 1; }
static int xz_open(struct zstream *z, int fd, char *mode) { lzma_ret ret; z->xz.eof = 0; z->xz.fd = fd; if(*mode == 'w') { ret = lzma_easy_encoder(&z->xz.stream, 5, LZMA_CHECK_CRC64); if (ret == LZMA_OK) return 0; return -1; } if(*mode == 'r') { z->xz.stream.next_in = NULL; z->xz.stream.avail_in = 0; z->xz.stream.next_out = z->xz.outbuf; z->xz.stream.avail_out = z->xz.bufsize; ret = lzma_stream_decoder(&z->xz.stream, UINT64_MAX, LZMA_CONCATENATED); if (ret == LZMA_OK) return 0; return -1; } return -1; }
int decompress_blob_xz(const void *src, uint64_t src_size, void **dst, size_t *dst_alloc_size, size_t* dst_size, size_t dst_max) { #ifdef HAVE_XZ _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT; lzma_ret ret; size_t space; assert(src); assert(src_size > 0); assert(dst); assert(dst_alloc_size); assert(dst_size); assert(*dst_alloc_size == 0 || *dst); ret = lzma_stream_decoder(&s, UINT64_MAX, 0); if (ret != LZMA_OK) return -ENOMEM; space = MIN(src_size * 2, dst_max ?: (size_t) -1); if (!greedy_realloc(dst, dst_alloc_size, space, 1)) return -ENOMEM; s.next_in = src; s.avail_in = src_size; s.next_out = *dst; s.avail_out = space; for (;;) { size_t used; ret = lzma_code(&s, LZMA_FINISH); if (ret == LZMA_STREAM_END) break; else if (ret != LZMA_OK) return -ENOMEM; if (dst_max > 0 && (space - s.avail_out) >= dst_max) break; else if (dst_max > 0 && space == dst_max) return -ENOBUFS; used = space - s.avail_out; space = MIN(2 * space, dst_max ?: (size_t) -1); if (!greedy_realloc(dst, dst_alloc_size, space, 1)) return -ENOMEM; s.avail_out = space - used; s.next_out = *dst + used; } *dst_size = space - s.avail_out; return 0; #else return -EPROTONOSUPPORT; #endif }
struct lzma_filter *lzma_decoder(void) { lzma_stream strm = LZMA_STREAM_INIT; if (lzma_stream_decoder(&strm, UINT64_MAX, 0) != LZMA_OK) return NULL; return _lzma_filter_new(&strm); }
int main(void) { lzma_stream strm = LZMA_STREAM_INIT; int ret; ret = lzma_stream_decoder(&strm, UINT64_MAX, LZMA_CONCATENATED); return ret ? -1 : 0; }
int decompress_startswith_xz(const void *src, uint64_t src_size, void **buffer, size_t *buffer_size, const void *prefix, size_t prefix_len, uint8_t extra) { #ifdef HAVE_XZ _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT; lzma_ret ret; /* Checks whether the decompressed blob starts with the * mentioned prefix. The byte extra needs to follow the * prefix */ assert(src); assert(src_size > 0); assert(buffer); assert(buffer_size); assert(prefix); assert(*buffer_size == 0 || *buffer); ret = lzma_stream_decoder(&s, UINT64_MAX, 0); if (ret != LZMA_OK) return -EBADMSG; if (!(greedy_realloc(buffer, buffer_size, ALIGN_8(prefix_len + 1), 1))) return -ENOMEM; s.next_in = src; s.avail_in = src_size; s.next_out = *buffer; s.avail_out = *buffer_size; for (;;) { ret = lzma_code(&s, LZMA_FINISH); if (ret != LZMA_STREAM_END && ret != LZMA_OK) return -EBADMSG; if (*buffer_size - s.avail_out >= prefix_len + 1) return memcmp(*buffer, prefix, prefix_len) == 0 && ((const uint8_t*) *buffer)[prefix_len] == extra; if (ret == LZMA_STREAM_END) return 0; s.avail_out += *buffer_size; if (!(greedy_realloc(buffer, buffer_size, *buffer_size * 2, 1))) return -ENOMEM; s.next_out = *buffer + *buffer_size - s.avail_out; } #else return -EPROTONOSUPPORT; #endif }
static void io_do_decompress(io_private_t *io_ptr) { lzma_stream l = LZMA_STREAM_INIT; io_ptr->lzma_handle = l; if (lzma_stream_decoder(&io_ptr->lzma_handle, UINT64_MAX, 0/*LZMA_CONCATENATED*/) != LZMA_OK) return; io_ptr->lzma_init = true; return; }
int import_uncompress_detect(ImportCompress *c, const void *data, size_t size) { static const uint8_t xz_signature[] = { 0xfd, '7', 'z', 'X', 'Z', 0x00 }; static const uint8_t gzip_signature[] = { 0x1f, 0x8b }; static const uint8_t bzip2_signature[] = { 'B', 'Z', 'h' }; int r; assert(c); if (c->type != IMPORT_COMPRESS_UNKNOWN) return 1; if (size < MAX3(sizeof(xz_signature), sizeof(gzip_signature), sizeof(bzip2_signature))) return 0; assert(data); if (memcmp(data, xz_signature, sizeof(xz_signature)) == 0) { lzma_ret xzr; xzr = lzma_stream_decoder(&c->xz, UINT64_MAX, LZMA_TELL_UNSUPPORTED_CHECK); if (xzr != LZMA_OK) return -EIO; c->type = IMPORT_COMPRESS_XZ; } else if (memcmp(data, gzip_signature, sizeof(gzip_signature)) == 0) { r = inflateInit2(&c->gzip, 15+16); if (r != Z_OK) return -EIO; c->type = IMPORT_COMPRESS_GZIP; } else if (memcmp(data, bzip2_signature, sizeof(bzip2_signature)) == 0) { r = BZ2_bzDecompressInit(&c->bzip2, 0, 0); if (r != BZ_OK) return -EIO; c->type = IMPORT_COMPRESS_BZIP2; } else c->type = IMPORT_COMPRESS_UNCOMPRESSED; c->encoding = false; return 1; }
void lzma_base::do_init( const lzma_params &p, bool compress, lzma::alloc_func alloc, lzma::free_func free, void *derived ) { lzma_stream *s = static_cast<lzma_stream *>( stream_ ); memset( s, 0, sizeof( *s ) ); lzma_error::check( compress ? lzma_easy_encoder( s, p.level, LZMA_CHECK_CRC32 ) : lzma_stream_decoder( s, 100 * 1024 * 1024, 0 ) ); }
static void filter_unxz_init(struct io_lzma *io, lzma_stream *s) { uint64_t memlimit = UINT64_MAX; lzma_ret ret; io->status |= DPKG_STREAM_DECOMPRESS; ret = lzma_stream_decoder(s, memlimit, 0); if (ret != LZMA_OK) filter_lzma_error(io, ret); }
int LzmaConnectorReader::resetConnectorReader (void) { lzma_end (&_lzmaDecompStream); resetDecompStream(); if (LZMA_OK != lzma_stream_decoder (&_lzmaDecompStream, lzma_easy_decoder_memusage (getCompressionLevel()), DECODER_FLAGS)) { return -1; } return 0; }
static int xc_try_xz_decode( struct xc_dom_image *dom, void **blob, size_t *size) { lzma_stream stream = LZMA_STREAM_INIT; if ( lzma_stream_decoder(&stream, LZMA_BLOCK_SIZE, 0) != LZMA_OK ) { DOMPRINTF("XZ: Failed to init decoder"); return -1; } return _xc_try_lzma_decode(dom, blob, size, &stream, "XZ"); }
static void i_stream_lzma_init(struct lzma_istream *zstream) { lzma_ret ret; ret = lzma_stream_decoder(&zstream->strm, LZMA_MEMORY_LIMIT, LZMA_CONCATENATED); switch (ret) { case LZMA_OK: break; case LZMA_MEM_ERROR: i_fatal_status(FATAL_OUTOFMEM, "lzma: Out of memory"); default: i_fatal("lzma_stream_decoder() failed with ret=%d", ret); } }
LzmaConnectorReader::LzmaConnectorReader (const CompressionSettings & compressionSettings, unsigned int ulInBufSize, unsigned int ulOutBufSize) : ConnectorReader{compressionSettings} { if ((ulOutBufSize == 0) || (ulInBufSize == 0) || (nullptr == (_pOutputBuffer = new unsigned char[ulOutBufSize])) || (nullptr == (_pInputBuffer = new unsigned char[ulInBufSize]))) { // throw a c++ exception here } _ulInBufSize = ulInBufSize; _ulOutBufSize = ulOutBufSize; resetDecompStream(); if (LZMA_OK != lzma_stream_decoder (&_lzmaDecompStream, lzma_easy_decoder_memusage (getCompressionLevel()), DECODER_FLAGS)) { // throw a c++ exception here } }
static int load_xz(struct kmod_file *file) { lzma_stream strm = LZMA_STREAM_INIT; lzma_ret lzret; int ret; lzret = lzma_stream_decoder(&strm, UINT64_MAX, LZMA_CONCATENATED); if (lzret == LZMA_MEM_ERROR) { ERR(file->ctx, "xz: %s\n", strerror(ENOMEM)); return -ENOMEM; } else if (lzret != LZMA_OK) { ERR(file->ctx, "xz: Internal error (bug)\n"); return -EINVAL; } ret = xz_uncompress(&strm, file); lzma_end(&strm); return ret; }
static readstat_error_t init_lzma_stream(rdata_ctx_t *ctx) { readstat_error_t retval = READSTAT_OK; ctx->lzma_strm = calloc(1, sizeof(lzma_stream)); ctx->strm_buffer = malloc(STREAM_BUFFER_SIZE); if (lzma_stream_decoder(ctx->lzma_strm, UINT64_MAX, 0) != LZMA_OK) { retval = READSTAT_ERROR_MALLOC; goto cleanup; } int bytes_read = read(ctx->fd, ctx->strm_buffer, STREAM_BUFFER_SIZE); if (bytes_read <= 0) { retval = READSTAT_ERROR_READ; goto cleanup; } ctx->lzma_strm->next_in = ctx->strm_buffer; ctx->lzma_strm->avail_in = bytes_read; cleanup: return retval; }
static void read_xz(int f, int fd, const char *arg) { uint8_t inbuf[BUFFER_SIZE], outbuf[BUFFER_SIZE]; lzma_stream xz = LZMA_STREAM_INIT; if (lzma_stream_decoder(&xz, UINT64_MAX, LZMA_CONCATENATED) != LZMA_OK) goto xz_read_end; xz.avail_in = 0; while (xz.avail_in || (xz.avail_in = read(f, (uint8_t*)(xz.next_in = inbuf), BUFFER_SIZE)) > 0) { xz.next_out = outbuf; xz.avail_out = sizeof(outbuf); if (lzma_code(&xz, LZMA_RUN) != LZMA_OK) goto xz_read_lzma_end; if (write(fd, outbuf, xz.next_out - outbuf) != xz.next_out - outbuf) goto xz_read_lzma_end; } // Flush the stream lzma_ret ret; do { xz.next_out = outbuf; xz.avail_out = sizeof(outbuf); ret = lzma_code(&xz, LZMA_FINISH); if (write(fd, outbuf, xz.next_out - outbuf) != xz.next_out - outbuf) goto xz_read_lzma_end; } while (ret == LZMA_OK); xz_read_lzma_end: lzma_end(&xz); xz_read_end: close(f); close(fd); }
static int tiff_uncompress_lzma(uint8_t *dst, uint64_t *len, const uint8_t *src, int size) { lzma_stream stream = LZMA_STREAM_INIT; lzma_ret ret; stream.next_in = (uint8_t *)src; stream.avail_in = size; stream.next_out = dst; stream.avail_out = *len; ret = lzma_stream_decoder(&stream, UINT64_MAX, 0); if (ret != LZMA_OK) { av_log(NULL, AV_LOG_ERROR, "LZMA init error: %d\n", ret); return ret; } ret = lzma_code(&stream, LZMA_RUN); lzma_end(&stream); *len = stream.total_out; return ret == LZMA_STREAM_END ? LZMA_OK : ret; }
static boolean MojoInput_xz_seek(MojoInput *io, uint64 offset) { // This is all really expensive. XZinfo *info = (XZinfo *) io->opaque; /* * If seeking backwards, we need to redecode the file * from the start and throw away the compressed bits until we hit * the offset we need. If seeking forward, we still need to * decode, but we don't rewind first. */ if (offset < info->uncompressed_position) { lzma_stream *strm = &info->stream; if (!info->origio->seek(info->origio, 0)) return false; lzma_end(strm); initializeXZStream(strm); if (lzma_stream_decoder(strm, UINT64_MAX, LZMA_CONCATENATED) != LZMA_OK) return false; info->uncompressed_position = 0; } // if while (info->uncompressed_position != offset) { uint8 buf[512]; uint32 maxread; int64 br; maxread = (uint32) (offset - info->uncompressed_position); if (maxread > sizeof (buf)) maxread = sizeof (buf); br = io->read(io, buf, maxread); if (br != maxread) return false; } /* while */ return true; } // MojoInput_xz_seek
GSDumpLzma::GSDumpLzma(char* filename) : GSDumpFile(filename) { memset(&m_strm, 0, sizeof(lzma_stream)); lzma_ret ret = lzma_stream_decoder(&m_strm, UINT32_MAX, 0); if (ret != LZMA_OK) { fprintf(stderr, "Error initializing the decoder! (error code %u)\n", ret); throw "BAD"; // Just exit the program } m_buff_size = 1024*1024; m_area = (uint8_t*)_aligned_malloc(m_buff_size, 32); m_inbuf = (uint8_t*)_aligned_malloc(BUFSIZ, 32); m_avail = 0; m_start = 0; m_strm.avail_in = 0; m_strm.next_in = m_inbuf; m_strm.avail_out = m_buff_size; m_strm.next_out = m_area; }
static int LZMADecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s) { static const char module[] = "LZMADecode"; LZMAState* sp = DecoderState(tif); (void) s; assert(sp != NULL); assert(sp->state == LSTATE_INIT_DECODE); sp->stream.next_in = tif->tif_rawcp; sp->stream.avail_in = (size_t) tif->tif_rawcc; sp->stream.next_out = op; sp->stream.avail_out = (size_t) occ; if ((tmsize_t)sp->stream.avail_out != occ) { TIFFErrorExt(tif->tif_clientdata, module, "Liblzma cannot deal with buffers this size"); return 0; } do { /* * Save the current stream state to properly recover from the * decoding errors later. */ const uint8_t *next_in = sp->stream.next_in; size_t avail_in = sp->stream.avail_in; lzma_ret ret = lzma_code(&sp->stream, LZMA_RUN); if (ret == LZMA_STREAM_END) break; if (ret == LZMA_MEMLIMIT_ERROR) { lzma_ret r = lzma_stream_decoder(&sp->stream, lzma_memusage(&sp->stream), 0); if (r != LZMA_OK) { TIFFErrorExt(tif->tif_clientdata, module, "Error initializing the stream decoder, %s", LZMAStrerror(r)); break; } sp->stream.next_in = next_in; sp->stream.avail_in = avail_in; continue; } if (ret != LZMA_OK) { TIFFErrorExt(tif->tif_clientdata, module, "Decoding error at scanline %lu, %s", (unsigned long) tif->tif_row, LZMAStrerror(ret)); break; } } while (sp->stream.avail_out > 0); if (sp->stream.avail_out != 0) { TIFFErrorExt(tif->tif_clientdata, module, "Not enough data at scanline %lu (short %lu bytes)", (unsigned long) tif->tif_row, (unsigned long) sp->stream.avail_out); return 0; } tif->tif_rawcp = (uint8 *)sp->stream.next_in; /* cast away const */ tif->tif_rawcc = sp->stream.avail_in; return 1; }
static off_t unxz(int i, int o, char *pre, size_t prelen, off_t *bytes_in) { lzma_stream strm = LZMA_STREAM_INIT; static const int flags = LZMA_TELL_UNSUPPORTED_CHECK|LZMA_CONCATENATED; lzma_ret ret; lzma_action action = LZMA_RUN; off_t bytes_out, bp; uint8_t ibuf[BUFSIZ]; uint8_t obuf[BUFSIZ]; if (bytes_in == NULL) bytes_in = &bp; strm.next_in = ibuf; memcpy(ibuf, pre, prelen); strm.avail_in = read(i, ibuf + prelen, sizeof(ibuf) - prelen); if (strm.avail_in == (size_t)-1) maybe_err("read failed"); strm.avail_in += prelen; *bytes_in = strm.avail_in; if ((ret = lzma_stream_decoder(&strm, UINT64_MAX, flags)) != LZMA_OK) maybe_errx("Can't initialize decoder (%d)", ret); strm.next_out = NULL; strm.avail_out = 0; if ((ret = lzma_code(&strm, LZMA_RUN)) != LZMA_OK) maybe_errx("Can't read headers (%d)", ret); bytes_out = 0; strm.next_out = obuf; strm.avail_out = sizeof(obuf); for (;;) { if (strm.avail_in == 0) { strm.next_in = ibuf; strm.avail_in = read(i, ibuf, sizeof(ibuf)); switch (strm.avail_in) { case (size_t)-1: maybe_err("read failed"); /*NOTREACHED*/ case 0: action = LZMA_FINISH; break; default: *bytes_in += strm.avail_in; break; } } ret = lzma_code(&strm, action); // Write and check write error before checking decoder error. // This way as much data as possible gets written to output // even if decoder detected an error. if (strm.avail_out == 0 || ret != LZMA_OK) { const size_t write_size = sizeof(obuf) - strm.avail_out; if (write(o, obuf, write_size) != (ssize_t)write_size) maybe_err("write failed"); strm.next_out = obuf; strm.avail_out = sizeof(obuf); bytes_out += write_size; } if (ret != LZMA_OK) { if (ret == LZMA_STREAM_END) { // Check that there's no trailing garbage. if (strm.avail_in != 0 || read(i, ibuf, 1)) ret = LZMA_DATA_ERROR; else { lzma_end(&strm); return bytes_out; } } const char *msg; switch (ret) { case LZMA_MEM_ERROR: msg = strerror(ENOMEM); break; case LZMA_FORMAT_ERROR: msg = "File format not recognized"; break; case LZMA_OPTIONS_ERROR: // FIXME: Better message? msg = "Unsupported compression options"; break; case LZMA_DATA_ERROR: msg = "File is corrupt"; break; case LZMA_BUF_ERROR: msg = "Unexpected end of input"; break; case LZMA_MEMLIMIT_ERROR: msg = "Reached memory limit"; break; default: maybe_errx("Unknown error (%d)", ret); break; } maybe_errx("%s", msg); } } }
void PsUpdateDownloader::unpackUpdate() { QByteArray packed; if (!outputFile.open(QIODevice::ReadOnly)) { LOG(("Update Error: cant read updates file!")); return fatalFail(); } #ifdef Q_OS_WIN // use Lzma SDK for win const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header #else const int32 hSigLen = 128, hShaLen = 20, hPropsLen = 0, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hOriginalSizeLen; // header #endif QByteArray compressed = outputFile.readAll(); int32 compressedLen = compressed.size() - hSize; if (compressedLen <= 0) { LOG(("Update Error: bad compressed size: %1").arg(compressed.size())); return fatalFail(); } outputFile.close(); QString tempDirPath = cWorkingDir() + qsl("tupdates/temp"), readyDirPath = cWorkingDir() + qsl("tupdates/ready"); deleteDir(tempDirPath); deleteDir(readyDirPath); QDir tempDir(tempDirPath), readyDir(readyDirPath); if (tempDir.exists() || readyDir.exists()) { LOG(("Update Error: cant clear tupdates/temp or tupdates/ready dir!")); return fatalFail(); } uchar sha1Buffer[20]; bool goodSha1 = !memcmp(compressed.constData() + hSigLen, hashSha1(compressed.constData() + hSigLen + hShaLen, compressedLen + hPropsLen + hOriginalSizeLen, sha1Buffer), hShaLen); if (!goodSha1) { LOG(("Update Error: bad SHA1 hash of update file!")); return fatalFail(); } RSA *pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast<char*>(UpdatesPublicKey), -1), 0, 0, 0); if (!pbKey) { LOG(("Update Error: cant read public rsa key!")); return fatalFail(); } if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), hSigLen, pbKey) != 1) { // verify signature RSA_free(pbKey); LOG(("Update Error: bad RSA signature of update file!")); return fatalFail(); } RSA_free(pbKey); QByteArray uncompressed; int32 uncompressedLen; memcpy(&uncompressedLen, compressed.constData() + hSigLen + hShaLen + hPropsLen, hOriginalSizeLen); uncompressed.resize(uncompressedLen); size_t resultLen = uncompressed.size(); #ifdef Q_OS_WIN // use Lzma SDK for win SizeT srcLen = compressedLen; int uncompressRes = LzmaUncompress((uchar*)uncompressed.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE); if (uncompressRes != SZ_OK) { LOG(("Update Error: could not uncompress lzma, code: %1").arg(uncompressRes)); return fatalFail(); } #else lzma_stream stream = LZMA_STREAM_INIT; lzma_ret ret = lzma_stream_decoder(&stream, UINT64_MAX, LZMA_CONCATENATED); if (ret != LZMA_OK) { const char *msg; switch (ret) { case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; case LZMA_OPTIONS_ERROR: msg = "Specified preset is not supported"; break; case LZMA_UNSUPPORTED_CHECK: msg = "Specified integrity check is not supported"; break; default: msg = "Unknown error, possibly a bug"; break; } LOG(("Error initializing the decoder: %1 (error code %2)").arg(msg).arg(ret)); return fatalFail(); } stream.avail_in = compressedLen; stream.next_in = (uint8_t*)(compressed.constData() + hSize); stream.avail_out = resultLen; stream.next_out = (uint8_t*)uncompressed.data(); lzma_ret res = lzma_code(&stream, LZMA_FINISH); if (stream.avail_in) { LOG(("Error in decompression, %1 bytes left in _in of %2 whole.").arg(stream.avail_in).arg(compressedLen)); return fatalFail(); } else if (stream.avail_out) { LOG(("Error in decompression, %1 bytes free left in _out of %2 whole.").arg(stream.avail_out).arg(resultLen)); return fatalFail(); } lzma_end(&stream); if (res != LZMA_OK && res != LZMA_STREAM_END) { const char *msg; switch (res) { case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; case LZMA_FORMAT_ERROR: msg = "The input data is not in the .xz format"; break; case LZMA_OPTIONS_ERROR: msg = "Unsupported compression options"; break; case LZMA_DATA_ERROR: msg = "Compressed file is corrupt"; break; case LZMA_BUF_ERROR: msg = "Compressed data is truncated or otherwise corrupt"; break; default: msg = "Unknown error, possibly a bug"; break; } LOG(("Error in decompression: %1 (error code %2)").arg(msg).arg(res)); return fatalFail(); } #endif tempDir.mkdir(tempDir.absolutePath()); quint32 version; { QBuffer buffer(&uncompressed); buffer.open(QIODevice::ReadOnly); QDataStream stream(&buffer); stream.setVersion(QDataStream::Qt_5_1); stream >> version; if (stream.status() != QDataStream::Ok) { LOG(("Update Error: cant read version from downloaded stream, status: %1").arg(stream.status())); return fatalFail(); } if (version <= AppVersion) { LOG(("Update Error: downloaded version %1 is not greater, than mine %2").arg(version).arg(AppVersion)); return fatalFail(); } quint32 filesCount; stream >> filesCount; if (stream.status() != QDataStream::Ok) { LOG(("Update Error: cant read files count from downloaded stream, status: %1").arg(stream.status())); return fatalFail(); } if (!filesCount) { LOG(("Update Error: update is empty!")); return fatalFail(); } for (uint32 i = 0; i < filesCount; ++i) { QString relativeName; quint32 fileSize; QByteArray fileInnerData; bool executable = false; stream >> relativeName >> fileSize >> fileInnerData; #if defined Q_OS_MAC || defined Q_OS_LINUX stream >> executable; #endif if (stream.status() != QDataStream::Ok) { LOG(("Update Error: cant read file from downloaded stream, status: %1").arg(stream.status())); return fatalFail(); } if (fileSize != quint32(fileInnerData.size())) { LOG(("Update Error: bad file size %1 not matching data size %2").arg(fileSize).arg(fileInnerData.size())); return fatalFail(); } QFile f(tempDirPath + '/' + relativeName); if (!QDir().mkpath(QFileInfo(f).absolutePath())) { LOG(("Update Error: cant mkpath for file '%1'").arg(tempDirPath + '/' + relativeName)); return fatalFail(); } if (!f.open(QIODevice::WriteOnly)) { LOG(("Update Error: cant open file '%1' for writing").arg(tempDirPath + '/' + relativeName)); return fatalFail(); } if (f.write(fileInnerData) != fileSize) { f.close(); LOG(("Update Error: cant write file '%1'").arg(tempDirPath + '/' + relativeName)); return fatalFail(); } f.close(); if (executable) { QFileDevice::Permissions p = f.permissions(); p |= QFileDevice::ExeOwner | QFileDevice::ExeUser | QFileDevice::ExeGroup | QFileDevice::ExeOther; f.setPermissions(p); } } // create tdata/version file tempDir.mkdir(QDir(tempDirPath + qsl("/tdata")).absolutePath()); std::wstring versionString = ((version % 1000) ? QString("%1.%2.%3").arg(int(version / 1000000)).arg(int((version % 1000000) / 1000)).arg(int(version % 1000)) : QString("%1.%2").arg(int(version / 1000000)).arg(int((version % 1000000) / 1000))).toStdWString(); VerInt versionNum = VerInt(version), versionLen = VerInt(versionString.size() * sizeof(VerChar)); VerChar versionStr[32]; memcpy(versionStr, versionString.c_str(), versionLen); QFile fVersion(tempDirPath + qsl("/tdata/version")); if (!fVersion.open(QIODevice::WriteOnly)) { LOG(("Update Error: cant write version file '%1'").arg(tempDirPath + qsl("/version"))); return fatalFail(); } fVersion.write((const char*)&versionNum, sizeof(VerInt)); fVersion.write((const char*)&versionLen, sizeof(VerInt)); fVersion.write((const char*)&versionStr[0], versionLen); fVersion.close(); } if (!tempDir.rename(tempDir.absolutePath(), readyDir.absolutePath())) { LOG(("Update Error: cant rename temp dir '%1' to ready dir '%2'").arg(tempDir.absolutePath()).arg(readyDir.absolutePath())); return fatalFail(); } deleteDir(tempDirPath); outputFile.remove(); emit App::app()->updateReady(); }
int decompress_stream_xz(int fdf, int fdt, off_t max_bytes) { #ifdef HAVE_XZ _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT; lzma_ret ret; uint8_t buf[BUFSIZ], out[BUFSIZ]; lzma_action action = LZMA_RUN; assert(fdf >= 0); assert(fdt >= 0); ret = lzma_stream_decoder(&s, UINT64_MAX, 0); if (ret != LZMA_OK) { log_error("Failed to initialize XZ decoder: code %u", ret); return -ENOMEM; } for (;;) { if (s.avail_in == 0 && action == LZMA_RUN) { ssize_t n; n = read(fdf, buf, sizeof(buf)); if (n < 0) return -errno; if (n == 0) action = LZMA_FINISH; else { s.next_in = buf; s.avail_in = n; } } if (s.avail_out == 0) { s.next_out = out; s.avail_out = sizeof(out); } ret = lzma_code(&s, action); if (ret != LZMA_OK && ret != LZMA_STREAM_END) { log_error("Decompression failed: code %u", ret); return -EBADMSG; } if (s.avail_out == 0 || ret == LZMA_STREAM_END) { ssize_t n, k; n = sizeof(out) - s.avail_out; if (max_bytes != -1) { if (max_bytes < n) return -EFBIG; max_bytes -= n; } k = loop_write(fdt, out, n, false); if (k < 0) return k; if (ret == LZMA_STREAM_END) { log_debug("XZ decompression finished (%"PRIu64" -> %"PRIu64" bytes, %.1f%%)", s.total_in, s.total_out, (double) s.total_out / s.total_in * 100); return 0; } } } #else log_error("Cannot decompress file. Compiled without XZ support."); return -EPROTONOSUPPORT; #endif }
int main(int argc, char *argv[]) { QString workDir; #ifdef Q_OS_MAC if (QDir(QString()).absolutePath() == "/") { QString first = argc ? QString::fromLocal8Bit(argv[0]) : QString(); if (!first.isEmpty()) { QFileInfo info(first); if (info.exists()) { QDir result(info.absolutePath() + "/../../.."); workDir = result.absolutePath() + '/'; } } } #endif QString remove; int version = 0; QFileInfoList files; for (int i = 0; i < argc; ++i) { if (string("-path") == argv[i] && i + 1 < argc) { QString path = workDir + QString(argv[i + 1]); QFileInfo info(path); files.push_back(info); if (remove.isEmpty()) remove = info.canonicalPath() + "/"; } else if (string("-version") == argv[i] && i + 1 < argc) { version = QString(argv[i + 1]).toInt(); } else if (string("-dev") == argv[i]) { DevChannel = true; } else if (string("-beta") == argv[i] && i + 1 < argc) { BetaVersion = QString(argv[i + 1]).toULongLong(); if (BetaVersion > version * 1000ULL && BetaVersion < (version + 1) * 1000ULL) { DevChannel = false; BetaSignature = countBetaVersionSignature(BetaVersion); if (BetaSignature.isEmpty()) { return -1; } } else { cout << "Bad -beta param value passed, should be for the same version: " << version << ", beta: " << BetaVersion << "\n"; return -1; } } } if (files.isEmpty() || remove.isEmpty() || version <= 1016 || version > 999999999) { #ifdef Q_OS_WIN cout << "Usage: Packer.exe -path {file} -version {version} OR Packer.exe -path {dir} -version {version}\n"; #elif defined Q_OS_MAC cout << "Usage: Packer.app -path {file} -version {version} OR Packer.app -path {dir} -version {version}\n"; #else cout << "Usage: Packer -path {file} -version {version} OR Packer -path {dir} -version {version}\n"; #endif return -1; } bool hasDirs = true; while (hasDirs) { hasDirs = false; for (QFileInfoList::iterator i = files.begin(); i != files.end(); ++i) { QFileInfo info(*i); QString fullPath = info.canonicalFilePath(); if (info.isDir()) { hasDirs = true; files.erase(i); QDir d = QDir(info.absoluteFilePath()); QString fullDir = d.canonicalPath(); QStringList entries = d.entryList(QDir::Files | QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot); files.append(d.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot)); break; } else if (!info.isReadable()) { cout << "Can't read: " << info.absoluteFilePath().toUtf8().constData() << "\n"; return -1; } else if (info.isHidden()) { hasDirs = true; files.erase(i); break; } } } for (QFileInfoList::iterator i = files.begin(); i != files.end(); ++i) { QFileInfo info(*i); if (!info.canonicalFilePath().startsWith(remove)) { cout << "Can't find '" << remove.toUtf8().constData() << "' in file '" << info.canonicalFilePath().toUtf8().constData() << "' :(\n"; return -1; } } QByteArray result; { QBuffer buffer(&result); buffer.open(QIODevice::WriteOnly); QDataStream stream(&buffer); stream.setVersion(QDataStream::Qt_5_1); if (BetaVersion) { stream << quint32(0x7FFFFFFF); stream << quint64(BetaVersion); } else { stream << quint32(version); } stream << quint32(files.size()); cout << "Found " << files.size() << " file" << (files.size() == 1 ? "" : "s") << "..\n"; for (QFileInfoList::iterator i = files.begin(); i != files.end(); ++i) { QFileInfo info(*i); QString fullName = info.canonicalFilePath(); QString name = fullName.mid(remove.length()); cout << name.toUtf8().constData() << " (" << info.size() << ")\n"; QFile f(fullName); if (!f.open(QIODevice::ReadOnly)) { cout << "Can't open '" << fullName.toUtf8().constData() << "' for read..\n"; return -1; } QByteArray inner = f.readAll(); stream << name << quint32(inner.size()) << inner; #if defined Q_OS_MAC || defined Q_OS_LINUX stream << (QFileInfo(fullName).isExecutable() ? true : false); #endif } if (stream.status() != QDataStream::Ok) { cout << "Stream status is bad: " << stream.status() << "\n"; return -1; } } int32 resultSize = result.size(); cout << "Compression start, size: " << resultSize << "\n"; QByteArray compressed, resultCheck; #ifdef Q_OS_WIN // use Lzma SDK for win const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header compressed.resize(hSize + resultSize + 1024 * 1024); // rsa signature + sha1 + lzma props + max compressed size size_t compressedLen = compressed.size() - hSize; size_t outPropsSize = LZMA_PROPS_SIZE; uchar *_dest = (uchar*)(compressed.data() + hSize); size_t *_destLen = &compressedLen; const uchar *_src = (const uchar*)(result.constData()); size_t _srcLen = result.size(); uchar *_outProps = (uchar*)(compressed.data() + hSigLen + hShaLen); int res = LzmaCompress(_dest, _destLen, _src, _srcLen, _outProps, &outPropsSize, 9, 64 * 1024 * 1024, 4, 0, 2, 273, 2); if (res != SZ_OK) { cout << "Error in compression: " << res << "\n"; return -1; } compressed.resize(int(hSize + compressedLen)); memcpy(compressed.data() + hSigLen + hShaLen + hPropsLen, &resultSize, hOriginalSizeLen); cout << "Compressed to size: " << compressedLen << "\n"; cout << "Checking uncompressed..\n"; int32 resultCheckLen; memcpy(&resultCheckLen, compressed.constData() + hSigLen + hShaLen + hPropsLen, hOriginalSizeLen); if (resultCheckLen <= 0 || resultCheckLen > 1024 * 1024 * 1024) { cout << "Bad result len: " << resultCheckLen << "\n"; return -1; } resultCheck.resize(resultCheckLen); size_t resultLen = resultCheck.size(); SizeT srcLen = compressedLen; int uncompressRes = LzmaUncompress((uchar*)resultCheck.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE); if (uncompressRes != SZ_OK) { cout << "Uncompress failed: " << uncompressRes << "\n"; return -1; } if (resultLen != size_t(result.size())) { cout << "Uncompress bad size: " << resultLen << ", was: " << result.size() << "\n"; return -1; } #else // use liblzma for others const int32 hSigLen = 128, hShaLen = 20, hPropsLen = 0, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hOriginalSizeLen; // header compressed.resize(hSize + resultSize + 1024 * 1024); // rsa signature + sha1 + lzma props + max compressed size size_t compressedLen = compressed.size() - hSize; lzma_stream stream = LZMA_STREAM_INIT; int preset = 9 | LZMA_PRESET_EXTREME; lzma_ret ret = lzma_easy_encoder(&stream, preset, LZMA_CHECK_CRC64); if (ret != LZMA_OK) { const char *msg; switch (ret) { case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; case LZMA_OPTIONS_ERROR: msg = "Specified preset is not supported"; break; case LZMA_UNSUPPORTED_CHECK: msg = "Specified integrity check is not supported"; break; default: msg = "Unknown error, possibly a bug"; break; } cout << "Error initializing the encoder: " << msg << " (error code " << ret << ")\n"; return -1; } stream.avail_in = resultSize; stream.next_in = (uint8_t*)result.constData(); stream.avail_out = compressedLen; stream.next_out = (uint8_t*)(compressed.data() + hSize); lzma_ret res = lzma_code(&stream, LZMA_FINISH); compressedLen -= stream.avail_out; lzma_end(&stream); if (res != LZMA_OK && res != LZMA_STREAM_END) { const char *msg; switch (res) { case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; case LZMA_DATA_ERROR: msg = "File size limits exceeded"; break; default: msg = "Unknown error, possibly a bug"; break; } cout << "Error in compression: " << msg << " (error code " << res << ")\n"; return -1; } compressed.resize(int(hSize + compressedLen)); memcpy(compressed.data() + hSigLen + hShaLen, &resultSize, hOriginalSizeLen); cout << "Compressed to size: " << compressedLen << "\n"; cout << "Checking uncompressed..\n"; int32 resultCheckLen; memcpy(&resultCheckLen, compressed.constData() + hSigLen + hShaLen, hOriginalSizeLen); if (resultCheckLen <= 0 || resultCheckLen > 1024 * 1024 * 1024) { cout << "Bad result len: " << resultCheckLen << "\n"; return -1; } resultCheck.resize(resultCheckLen); size_t resultLen = resultCheck.size(); stream = LZMA_STREAM_INIT; ret = lzma_stream_decoder(&stream, UINT64_MAX, LZMA_CONCATENATED); if (ret != LZMA_OK) { const char *msg; switch (ret) { case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; case LZMA_OPTIONS_ERROR: msg = "Specified preset is not supported"; break; case LZMA_UNSUPPORTED_CHECK: msg = "Specified integrity check is not supported"; break; default: msg = "Unknown error, possibly a bug"; break; } cout << "Error initializing the decoder: " << msg << " (error code " << ret << ")\n"; return -1; } stream.avail_in = compressedLen; stream.next_in = (uint8_t*)(compressed.constData() + hSize); stream.avail_out = resultLen; stream.next_out = (uint8_t*)resultCheck.data(); res = lzma_code(&stream, LZMA_FINISH); if (stream.avail_in) { cout << "Error in decompression, " << stream.avail_in << " bytes left in _in of " << compressedLen << " whole.\n"; return -1; } else if (stream.avail_out) { cout << "Error in decompression, " << stream.avail_out << " bytes free left in _out of " << resultLen << " whole.\n"; return -1; } lzma_end(&stream); if (res != LZMA_OK && res != LZMA_STREAM_END) { const char *msg; switch (res) { case LZMA_MEM_ERROR: msg = "Memory allocation failed"; break; case LZMA_FORMAT_ERROR: msg = "The input data is not in the .xz format"; break; case LZMA_OPTIONS_ERROR: msg = "Unsupported compression options"; break; case LZMA_DATA_ERROR: msg = "Compressed file is corrupt"; break; case LZMA_BUF_ERROR: msg = "Compressed data is truncated or otherwise corrupt"; break; default: msg = "Unknown error, possibly a bug"; break; } cout << "Error in decompression: " << msg << " (error code " << res << ")\n"; return -1; } #endif if (memcmp(result.constData(), resultCheck.constData(), resultLen)) { cout << "Data differ :(\n"; return -1; } /**/ result = resultCheck = QByteArray(); cout << "Counting SHA1 hash..\n"; uchar sha1Buffer[20]; memcpy(compressed.data() + hSigLen, hashSha1(compressed.constData() + hSigLen + hShaLen, uint32(compressedLen + hPropsLen + hOriginalSizeLen), sha1Buffer), hShaLen); // count sha1 uint32 siglen = 0; cout << "Signing..\n"; RSA *prKey = PEM_read_bio_RSAPrivateKey(BIO_new_mem_buf(const_cast<char*>((DevChannel || BetaVersion) ? PrivateDevKey : PrivateKey), -1), 0, 0, 0); if (!prKey) { cout << "Could not read RSA private key!\n"; return -1; } if (RSA_size(prKey) != hSigLen) { cout << "Bad private key, size: " << RSA_size(prKey) << "\n"; RSA_free(prKey); return -1; } if (RSA_sign(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (uchar*)(compressed.data()), &siglen, prKey) != 1) { // count signature cout << "Signing failed!\n"; RSA_free(prKey); return -1; } RSA_free(prKey); if (siglen != hSigLen) { cout << "Bad signature length: " << siglen << "\n"; return -1; } cout << "Checking signature..\n"; RSA *pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast<char*>((DevChannel || BetaVersion) ? PublicDevKey : PublicKey), -1), 0, 0, 0); if (!pbKey) { cout << "Could not read RSA public key!\n"; return -1; } if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), siglen, pbKey) != 1) { // verify signature RSA_free(pbKey); cout << "Signature verification failed!\n"; return -1; } cout << "Signature verified!\n"; RSA_free(pbKey); #ifdef Q_OS_WIN QString outName(QString("tupdate%1").arg(BetaVersion ? BetaVersion : version)); #elif defined Q_OS_MAC QString outName(QString("tmacupd%1").arg(BetaVersion ? BetaVersion : version)); #elif defined Q_OS_LINUX32 QString outName(QString("tlinux32upd%1").arg(BetaVersion ? BetaVersion : version)); #elif defined Q_OS_LINUX64 QString outName(QString("tlinuxupd%1").arg(BetaVersion ? BetaVersion : version)); #else #error Unknown platform! #endif if (BetaVersion) { outName += "_" + BetaSignature; } QFile out(outName); if (!out.open(QIODevice::WriteOnly)) { cout << "Can't open '" << outName.toUtf8().constData() << "' for write..\n"; return -1; } out.write(compressed); out.close(); if (BetaVersion) { QString keyName(QString("tbeta_%1_key").arg(BetaVersion)); QFile key(keyName); if (!key.open(QIODevice::WriteOnly)) { cout << "Can't open '" << keyName.toUtf8().constData() << "' for write..\n"; return -1; } key.write(BetaSignature.toUtf8()); key.close(); } cout << "Update file '" << outName.toUtf8().constData() << "' written successfully!\n"; return 0; }
static int decompress_fd_xz(int fdi, int fdo) { uint8_t buf_in[BUFSIZ]; uint8_t buf_out[BUFSIZ]; lzma_stream strm = LZMA_STREAM_INIT; lzma_ret ret = lzma_stream_decoder(&strm, UINT64_MAX, 0); if (ret != LZMA_OK) { close(fdi); close(fdo); log_error("Failed to initialize XZ decoder: code %d", ret); return -ENOMEM; } lzma_action action = LZMA_RUN; strm.next_out = buf_out; strm.avail_out = sizeof(buf_out); for (;;) { if (strm.avail_in == 0 && action == LZMA_RUN) { strm.next_in = buf_in; strm.avail_in = safe_read(fdi, buf_in, sizeof(buf_in)); if (strm.avail_in < 0) { perror_msg("Failed to read source core file"); close(fdi); close(fdo); lzma_end(&strm); return -1; } if (strm.avail_in == 0) action = LZMA_FINISH; } ret = lzma_code(&strm, action); if (strm.avail_out == 0 || ret == LZMA_STREAM_END) { const ssize_t n = sizeof(buf_out) - strm.avail_out; if (n != safe_write(fdo, buf_out, n)) { perror_msg("Failed to write decompressed data"); close(fdi); close(fdo); lzma_end(&strm); return -1; } if (ret == LZMA_STREAM_END) { log_debug("Successfully decompressed coredump."); break; } strm.next_out = buf_out; strm.avail_out = sizeof(buf_out); } } return 0; }
int xz_dec_init(lzma_stream *str) { lzma_ret ret_xz; ret_xz = lzma_stream_decoder(str, UINT64_MAX, LZMA_CONCATENATED); return ret_xz; }