static int crypto_xz_decompress(struct crypto_tfm *tfm, const u8 *src, unsigned int slen, u8 *dst, unsigned int *dlen) { struct xz_comp_ctx *dctx = crypto_tfm_ctx(tfm); struct xz_buf *xz_buf = &dctx->decomp_buf; int ret; memset(xz_buf, '\0', sizeof(struct xz_buf)); xz_buf->in = (u8 *) src; xz_buf->in_pos = 0; xz_buf->in_size = slen; xz_buf->out = (u8 *) dst; xz_buf->out_pos = 0; xz_buf->out_size = *dlen; ret = xz_dec_run(dctx->decomp_state, xz_buf); if (ret != XZ_STREAM_END) { ret = -EINVAL; goto out; } *dlen = xz_buf->out_pos; ret = 0; out: return ret; }
/* Function xz_dec_run() should consume header and ask for more (XZ_OK) * else file is corrupted (or options not supported) or not xz. */ static int test_header (grub_file_t file) { grub_xzio_t xzio = file->data; xzio->buf.in_size = grub_file_read (xzio->file, xzio->inbuf, STREAM_HEADER_SIZE); if (xzio->buf.in_size != STREAM_HEADER_SIZE) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "no xz magic found"); return 0; } enum xz_ret ret = xz_dec_run (xzio->dec, &xzio->buf); if (ret == XZ_FORMAT_ERROR) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "no xz magic found"); return 0; } if (ret != XZ_OK) { grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "not supported xz options"); return 0; } return 1; }
int main(void) { struct xz_buf b; struct xz_dec *s; enum xz_ret ret; xz_crc32_init(); s = xz_dec_init(XZ_SINGLE, 0); if (s == NULL) { fputs("Initialization failed", stderr); return 1; } b.in = in; b.in_pos = 0; b.in_size = fread(in, 1, sizeof(in), stdin); b.out = out; b.out_pos = 0; b.out_size = sizeof(out); ret = xz_dec_run(s, &b); xz_dec_end(s); fwrite(out, 1, b.out_pos, stdout); fprintf(stderr, "%d\n", ret); return 0; }
static int decrunch_xz(FILE *in, FILE *out) { struct xz_buf b; struct xz_dec *state; unsigned char *membuf; int ret = 0; crc32_init_A(); memset(&b, 0, sizeof(b)); if ((membuf = malloc(2 * BUFFER_SIZE)) == NULL) return -1; b.in = membuf; b.out = membuf + BUFFER_SIZE; b.out_size = BUFFER_SIZE; /* Limit memory usage to 16M */ state = xz_dec_init(XZ_DYNALLOC, 16 * 1024 * 1024); while (1) { enum xz_ret r; if (b.in_pos == b.in_size) { int rd = fread(membuf, 1, BUFFER_SIZE, in); if (rd < 0) { ret = -1; break; } b.in_size = rd; b.in_pos = 0; } r = xz_dec_run(state, &b); if (b.out_pos) { fwrite(b.out, 1, b.out_pos, out); b.out_pos = 0; } if (r == XZ_STREAM_END) { break; } if (r != XZ_OK && r != XZ_UNSUPPORTED_CHECK) { ret = -1; break; } } xz_dec_end(state); free(membuf); return ret; }
size_t XzStreamReader::Read(void* buffer, size_t length) { bool freemem = false; // Flag to free buffer #ifdef _WIN64 if(length > UINT32_MAX) throw std::invalid_argument("length"); #endif if((length == 0) || (m_finished)) return 0; // Nothing to do // The caller can specify NULL if the output data is irrelevant, but xz // expects to be able to write the decompressed data somewhere ... if(!buffer) { buffer = malloc(length); if(!buffer) throw std::bad_alloc(); freemem = true; } // Set the output buffer pointer and length for xz m_buffer.out = reinterpret_cast<uint8_t*>(buffer); m_buffer.out_pos = 0; m_buffer.out_size = length; // Decompress up to the requested number of bytes from the compressed stream xz_ret result = xz_dec_run(m_decoder, &m_buffer); if(freemem) free(buffer); // Check the result from xz_dec_run for memory errors if((result == XZ_MEM_ERROR) || (result == XZ_MEMLIMIT_ERROR)) throw std::bad_alloc(); // Assume any other bad thing that happened was due to a corrupt/unsupported input file if((result != XZ_OK) && (result != XZ_STREAM_END)) throw std::exception("xz: decompression stream data is corrupt"); // XZ will raise an error on an attempt to read beyond the end if(result == XZ_STREAM_END) m_finished = true; m_position += m_buffer.out_pos; return m_buffer.out_pos; }
/* Function xz_dec_run() should consume header and ask for more (XZ_OK) * else file is corrupted (or options not supported) or not xz. */ static int test_header (grub_file_t file) { grub_xzio_t xzio = file->data; enum xz_ret ret; xzio->buf.in_size = grub_file_read (xzio->file, xzio->inbuf, STREAM_HEADER_SIZE); if (xzio->buf.in_size != STREAM_HEADER_SIZE) return 0; ret = xz_dec_run (xzio->dec, &xzio->buf); if (ret == XZ_FORMAT_ERROR) return 0; if (ret != XZ_OK) return 0; return 1; }
static grub_ssize_t grub_xzio_read (grub_file_t file, char *buf, grub_size_t len) { grub_ssize_t ret = 0; grub_ssize_t readret; enum xz_ret xzret; grub_xzio_t xzio = file->data; grub_off_t current_offset; /* If seek backward need to reset decoder and start from beginning of file. TODO Possible improvement by jumping blocks. */ if (file->offset < xzio->saved_offset) { xz_dec_reset (xzio->dec); xzio->saved_offset = 0; xzio->buf.out_pos = 0; xzio->buf.in_pos = 0; xzio->buf.in_size = 0; grub_file_seek (xzio->file, 0); } current_offset = xzio->saved_offset; while (len > 0) { xzio->buf.out_size = grub_min (file->offset + ret + len - current_offset, XZBUFSIZ); /* Feed input. */ if (xzio->buf.in_pos == xzio->buf.in_size) { readret = grub_file_read (xzio->file, xzio->inbuf, XZBUFSIZ); if (readret < 0) return -1; xzio->buf.in_size = readret; xzio->buf.in_pos = 0; } xzret = xz_dec_run (xzio->dec, &xzio->buf); switch (xzret) { case XZ_MEMLIMIT_ERROR: case XZ_FORMAT_ERROR: case XZ_OPTIONS_ERROR: case XZ_DATA_ERROR: case XZ_BUF_ERROR: grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "file corrupted or unsupported block options"); return -1; default: break; } { grub_off_t new_offset = current_offset + xzio->buf.out_pos; if (file->offset <= new_offset) /* Store first chunk of data in buffer. */ { grub_size_t delta = new_offset - (file->offset + ret); grub_memmove (buf, xzio->buf.out + (xzio->buf.out_pos - delta), delta); len -= delta; buf += delta; ret += delta; } current_offset = new_offset; } xzio->buf.out_pos = 0; if (xzret == XZ_STREAM_END) /* Stream end, EOF. */ break; } if (ret >= 0) xzio->saved_offset = file->offset + ret; return ret; }
/* * This function implements the API defined in <linux/decompress/generic.h>. * * This wrapper will automatically choose single-call or multi-call mode * of the native XZ decoder API. The single-call mode can be used only when * both input and output buffers are available as a single chunk, i.e. when * fill() and flush() won't be used. */ STATIC int decompress_unxz(unsigned char *in, int in_size, int (*fill)(void *dest, unsigned int size), int (*flush)(void *src, unsigned int size), unsigned char *out, int *in_used, void (*error)(char *x)) { struct xz_buf b; struct xz_dec *s; enum xz_ret ret; bool must_free_in = false; #if XZ_INTERNAL_CRC32 xz_crc32_init(); #endif if (in_used != NULL) *in_used = 0; if (fill == NULL && flush == NULL) s = xz_dec_init(XZ_SINGLE, 0); else s = xz_dec_init(XZ_DYNALLOC, (uint32_t)-1); if (s == NULL) goto error_alloc_state; if (flush == NULL) { b.out = out; b.out_size = (size_t)-1; } else { b.out_size = XZ_IOBUF_SIZE; b.out = MALLOC(XZ_IOBUF_SIZE); if (b.out == NULL) goto error_alloc_out; } if (in == NULL) { must_free_in = true; in = MALLOC(XZ_IOBUF_SIZE); if (in == NULL) goto error_alloc_in; } b.in = in; b.in_pos = 0; b.in_size = in_size; b.out_pos = 0; if (fill == NULL && flush == NULL) { ret = xz_dec_run(s, &b); } else { do { if (b.in_pos == b.in_size && fill != NULL) { if (in_used != NULL) *in_used += b.in_pos; b.in_pos = 0; in_size = fill(in, XZ_IOBUF_SIZE); if (in_size < 0) { /* * This isn't an optimal error code * but it probably isn't worth making * a new one either. */ ret = XZ_BUF_ERROR; break; } b.in_size = in_size; } ret = xz_dec_run(s, &b); if (flush != NULL && (b.out_pos == b.out_size || (ret != XZ_OK && b.out_pos > 0))) { /* * Setting ret here may hide an error * returned by xz_dec_run(), but probably * it's not too bad. */ if (flush(b.out, b.out_pos) != (long)b.out_pos) ret = XZ_BUF_ERROR; b.out_pos = 0; } } while (ret == XZ_OK); if (must_free_in) FREE(in); if (flush != NULL) FREE(b.out); } if (in_used != NULL) *in_used += b.in_pos; xz_dec_end(s); switch (ret) { case XZ_STREAM_END: return 0; case XZ_MEM_ERROR: /* This can occur only in multi-call mode. */ error("XZ decompressor ran out of memory"); break; case XZ_FORMAT_ERROR: error("Input is not in the XZ format (wrong magic bytes)"); break; case XZ_OPTIONS_ERROR: error("Input was encoded with settings that are not " "supported by this XZ decoder"); break; case XZ_DATA_ERROR: case XZ_BUF_ERROR: error("XZ-compressed data is corrupt"); break; default: error("Bug in the XZ decompressor"); break; } return -1; error_alloc_in: if (flush != NULL) FREE(b.out); error_alloc_out: xz_dec_end(s); error_alloc_state: error("XZ decompressor ran out of memory"); return -1; }
static errlHndl_t load_pnor_section(PNOR::SectionId i_section, uint64_t i_physAddr) { TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,ENTER_MRK"load_pnor_section()"); errlHndl_t err = nullptr; #ifdef CONFIG_SECUREBOOT // Securely load section TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,"load_pnor_section: secure section load of secId=0x%X (%s)", i_section, PNOR::SectionIdToString(i_section)); err = PNOR::loadSecureSection(i_section); if (err) { return err; } // Do not need to unload since we have plenty of memory at this point. #endif // Get the section info from PNOR. PNOR::SectionInfo_t pnorSectionInfo; err = PNOR::getSectionInfo( i_section, pnorSectionInfo ); if( err != nullptr ) { TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, "load_pnor_section: Could not get section info from %x", i_section); return err; } // XZ repository: http:git.tukaani.org/xz.git // Header specifics can be found in xz/doc/xz-file-format.txt const uint8_t HEADER_MAGIC[]= { 0xFD, '7', 'z', 'X', 'Z', 0x00 }; uint8_t* l_pnor_header = reinterpret_cast<uint8_t *>(pnorSectionInfo.vaddr); bool l_pnor_is_XZ_compressed = (0 == memcmp(l_pnor_header, HEADER_MAGIC, sizeof(HEADER_MAGIC))); TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, "load_pnor_section: is XZ_compressed: %d", l_pnor_is_XZ_compressed); // This assumes that the maximum decompression ratio will always be less // than 1:16 (compressed:uncompressed). This works because XZ compression // is usually 14.1%, the decompressor does not need the exact size, and // we have all of mainstore memory at this point. uint32_t uncompressedPayloadSize = l_pnor_is_XZ_compressed ? (pnorSectionInfo.size * 16) : pnorSectionInfo.size; const uint32_t originalPayloadSize = pnorSectionInfo.size; printk( "Loading PNOR section %d (%s) %d bytes @0x%lx\n", i_section, pnorSectionInfo.name, originalPayloadSize, i_physAddr ); void * loadAddr = NULL; // Map in the physical memory we are loading into. // If we are not xz compressed, the uncompressedSize // is equal to the original size. loadAddr = mm_block_map( reinterpret_cast<void*>( i_physAddr ), uncompressedPayloadSize ); // Print out inital progress bar. #ifdef CONFIG_CONSOLE const int progressSteps = 80; int progress = 0; for ( int i = 0; i < progressSteps; ++i ) { printk( "." ); } printk( "\r" ); #endif if(!l_pnor_is_XZ_compressed) { // Load the data block by block and update the progress bar. const uint32_t BLOCK_SIZE = 4096; for ( uint32_t i = 0; i < originalPayloadSize; i += BLOCK_SIZE ) { memcpy( reinterpret_cast<void*>( reinterpret_cast<uint64_t>(loadAddr) + i ), reinterpret_cast<void*>( pnorSectionInfo.vaddr + i ), std::min( originalPayloadSize - i, BLOCK_SIZE ) ); #ifdef CONFIG_CONSOLE for ( int new_progress = (i * progressSteps) / originalPayloadSize; progress <= new_progress; progress++ ) { printk( "=" ); } #endif } #ifdef CONFIG_CONSOLE printk( "\n" ); #endif } if(l_pnor_is_XZ_compressed) { struct xz_buf b; struct xz_dec *s; enum xz_ret ret; xz_crc32_init(); s = xz_dec_init(XZ_SINGLE, 0); if(s == NULL) { TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,ERR_MRK "load_pnor_section: XZ Embedded Initialization failed"); return err; } static const uint64_t compressed_SIZE = originalPayloadSize; static const uint64_t decompressed_SIZE = uncompressedPayloadSize; b.in = reinterpret_cast<uint8_t *>( pnorSectionInfo.vaddr); b.in_pos = 0; b.in_size = compressed_SIZE; b.out = reinterpret_cast<uint8_t *>(loadAddr); b.out_pos = 0; b.out_size = decompressed_SIZE; ret = xz_dec_run(s, &b); if(ret == XZ_STREAM_END) { TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, "load_pnor_section: The %s section was decompressed.", pnorSectionInfo.name); }else { TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,ERR_MRK "load_pnor_section: xz-embedded returned an error, ", "the ret is %d",ret); /*@ * @errortype * @reasoncode fapi::RC_INVALID_RETURN_XZ_CODE * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE * @moduleid fapi::MOD_START_XZ_PAYLOAD * @devdesc xz-embedded has returned an error. * the return code can be found in xz.h * @custdesc Error uncompressing payload image from * boot flash * @userdata1 Return code from xz-embedded * @userdata2[0:31] Original Payload Size * @userdata2[32:63] Uncompressed Payload Size */ err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, fapi::MOD_START_XZ_PAYLOAD, fapi::RC_INVALID_RETURN_XZ_CODE, ret,TWO_UINT32_TO_UINT64( originalPayloadSize, uncompressedPayloadSize)); err->addProcedureCallout(HWAS::EPUB_PRC_PHYP_CODE, HWAS::SRCI_PRIORITY_HIGH); } //Clean up memory xz_dec_end(s); } int rc = 0; rc = mm_block_unmap(reinterpret_cast<void *>(loadAddr)); if(rc) { TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,ERR_MRK "load_pnor_section: mm_block_unmap returned 1"); /*@ * @errortype * @reasoncode fapi::RC_MM_UNMAP_ERR * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE * @moduleid fapi::MOD_START_XZ_PAYLOAD * @devdesc mm_block_unmap returned incorrectly with 0 * @custdesc Error unmapping memory section */ err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, fapi::MOD_START_XZ_PAYLOAD, fapi::RC_MM_UNMAP_ERR, 0,0,0); } return err; }
/* * Decode the data given to us from the userspace. CRC32 of the uncompressed * data is calculated and is printed at the end of successful decoding. The * uncompressed data isn't stored anywhere for further use. * * The .xz file must have exactly one Stream and no Stream Padding. The data * after the first Stream is considered to be garbage. */ static ssize_t xz_dec_test_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) { size_t remaining; if (ret != XZ_OK) { if (size > 0) printk(KERN_INFO DEVICE_NAME ": %zu bytes of " "garbage at the end of the file\n", size); return -ENOSPC; } printk(KERN_INFO DEVICE_NAME ": decoding %zu bytes of input\n", size); remaining = size; while ((remaining > 0 || buffers.out_pos == buffers.out_size) && ret == XZ_OK) { if (buffers.in_pos == buffers.in_size) { buffers.in_pos = 0; buffers.in_size = min(remaining, sizeof(buffer_in)); if (copy_from_user(buffer_in, buf, buffers.in_size)) return -EFAULT; buf += buffers.in_size; remaining -= buffers.in_size; } buffers.out_pos = 0; ret = xz_dec_run(state, &buffers); crc = crc32(crc, buffer_out, buffers.out_pos); } switch (ret) { case XZ_OK: printk(KERN_INFO DEVICE_NAME ": XZ_OK\n"); return size; case XZ_STREAM_END: printk(KERN_INFO DEVICE_NAME ": XZ_STREAM_END, " "CRC32 = 0x%08X\n", ~crc); return size - remaining - (buffers.in_size - buffers.in_pos); case XZ_MEMLIMIT_ERROR: printk(KERN_INFO DEVICE_NAME ": XZ_MEMLIMIT_ERROR\n"); break; case XZ_FORMAT_ERROR: printk(KERN_INFO DEVICE_NAME ": XZ_FORMAT_ERROR\n"); break; case XZ_OPTIONS_ERROR: printk(KERN_INFO DEVICE_NAME ": XZ_OPTIONS_ERROR\n"); break; case XZ_DATA_ERROR: printk(KERN_INFO DEVICE_NAME ": XZ_DATA_ERROR\n"); break; case XZ_BUF_ERROR: printk(KERN_INFO DEVICE_NAME ": XZ_BUF_ERROR\n"); break; default: printk(KERN_INFO DEVICE_NAME ": Bug detected!\n"); break; } return -EIO; }
int main(int argc, char **argv, char *envp[]) { struct xz_buf b; struct xz_dec *s; enum xz_ret ret; const char *msg; if (argc >= 2 && strcmp(argv[1], "--help") == 0) { fputs("Uncompress a .xz file from stdin to stdout.\n" "Arguments other than `--help' are ignored.\n", stdout); return 0; } xz_crc32_init(); /* * Support up to 64 MiB dictionary. The actually needed memory * is allocated once the headers have been parsed. */ s = xz_dec_init(XZ_DYNALLOC, 1 << 26); if (s == NULL) { msg = "Memory allocation failed\n"; goto error; } b.in = in; b.in_pos = 0; b.in_size = BUFSIZ; b.out = out; b.out_pos = 0; b.out_size = BUFSIZ; // TODO add error checking char temp_dir_name[] = "/tmp/unv_installer_XXXXXX"; /* TODO: find tmpdir, don't assume it is /tmp */ mkdtemp(temp_dir_name); char temp_file_name[256]; sprintf(temp_file_name, "%s/installer", temp_dir_name); FILE* temp_fp = fopen(temp_file_name, "w"); while (true) { ret = xz_dec_run(s, &b); /*So that xz_dec_run will consume another BUFSIZ bytes (it reads from b.in_pos till b.in_size)*/ if (fwrite(b.out, 1, b.out_pos, temp_fp) != b.out_pos) { msg = "Write error\n"; goto error; } if (ret == XZ_OK){ b.in_size+=BUFSIZ; b.out_pos=0; continue; } #ifdef XZ_DEC_ANY_CHECK if (ret == XZ_UNSUPPORTED_CHECK) { fputs(argv[0], stderr); fputs(": ", stderr); fputs("Unsupported check; not verifying " "file integrity\n", stderr); continue; } #endif switch (ret) { case XZ_STREAM_END: xz_dec_end(s); chmod(temp_file_name, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); fclose(temp_fp); printf("%s\n", temp_file_name); int i = 0; while (envp[i] != NULL){ i++; } char **env = malloc((i+1)*sizeof(char *)); memcpy(env, envp, i*sizeof(char *)); char var[256]; sprintf(var, "LD_LIBRARY_PATH=%s", temp_dir_name); env[i] = var; env[i+1] = (char*) NULL; // {"LD_LIBRARY_PATH=", (char *) NULL}; execle(temp_file_name, temp_file_name, (char*) NULL, env); printf("Weird\n"); return 1; /*Will only occur if execl call failed.*/ case XZ_MEM_ERROR: msg = "Memory allocation failed\n"; goto error; case XZ_MEMLIMIT_ERROR: msg = "Memory usage limit reached\n"; goto error; case XZ_FORMAT_ERROR: msg = "Not a .xz file\n"; goto error; case XZ_OPTIONS_ERROR: msg = "Unsupported options in the .xz headers\n"; goto error; case XZ_DATA_ERROR: case XZ_BUF_ERROR: msg = "File is corrupt\n"; goto error; default: msg = "Bug!\n"; goto error; } } error: xz_dec_end(s); fputs(argv[0], stderr); fputs(": ", stderr); fputs(msg, stderr); return 1; }
/** * Compress command: tar -c car/ | xz --check=crc32 --lzma2=preset=6e,dict=512Ki > car.tar.xz * | ./iap 0.0.0.0 'target file' * * Decompress command: dxz 'src file' 'dest file' * dxz 'src file' | tar xv -C */ int dxz_file(FILE *src, FILE *dest) { struct xz_buf b; struct xz_dec *s; int ret; int show_flag = 0; xz_crc32_init(); s = xz_dec_init(XZ_PREALLOC, XZ_IN_BUFFSIZE); if (NULL == s) { DBG("Can not initialzation decompress object!\n"); return -1; } b.in = xz_ibuf; b.in_pos = 0; b.out = xz_obuf; b.out_pos = 0; b.out_size = sizeof(xz_obuf); do { if (0 == b.in_pos) { while(!CAN_READ_FILE(fileno(src), 10)); b.in_size = fread(xz_ibuf, 1, sizeof(xz_ibuf), src); if (!b.in_size) { return -1; } if (!show_flag) { show_flag = ~show_flag; disp_share_stat("正在解包."); } } ret = xz_dec_run(s, &b); disp_share_process(); if (b.in_pos == b.in_size) b.in_pos = 0; if (b.out_pos == b.out_size) { if (fwrite(xz_obuf, 1, b.out_size, dest) != b.out_size) { DBG("Write file fail!\n"); ret = -1; goto end; } b.out_pos = 0; } }while (XZ_OK == ret); if (XZ_STREAM_END == ret) { if (b.out_pos) { if (fwrite(xz_obuf, 1, b.out_pos, dest) != b.out_pos) { DBG("Write file fail!\n"); ret = -1; goto end; } } ret = 0; disp_share_stat("解包完成!\n"); } else { DBG("Decompress fail!(ret: %d)\n", ret); ret = -1; } end: xz_dec_end(s); if (ret != 0) { DBG("Processing fail!\n"); disp_share_stat("解包失败!\n"); sleep(2); } return ret; }
/* * This function implements the API defined in <linux/decompress/generic.h>. * * This wrapper will automatically choose single-call or multi-call mode * of the native XZ decoder API. The single-call mode can be used only when * both input and output buffers are available as a single chunk, i.e. when * fill() and flush() won't be used. * * This API doesn't provide a way to specify the maximum dictionary size * for the multi-call mode of the native XZ decoder API. We will use * DICT_MAX bytes, which will be allocated with vmalloc(). */ STATIC int XZ_FUNC unxz(/*const*/ unsigned char *in, int in_size, int (*fill)(void *dest, unsigned int size), int (*flush)(/*const*/ void *src, unsigned int size), unsigned char *out, int *in_used, void (*error)(/*const*/ char *x)) { struct xz_buf b; struct xz_dec *s; enum xz_ret ret; xz_crc32_init(); if (in != NULL && out != NULL) s = xz_dec_init(XZ_SINGLE, 0); else s = xz_dec_init(XZ_PREALLOC /*FIXME*/, DICT_MAX); if (s == NULL) goto error_alloc_state; b.in = in; b.in_pos = 0; b.in_size = in_size; b.out_pos = 0; if (in_used != NULL) *in_used = 0; if (fill == NULL && flush == NULL) { b.out = out; b.out_size = (size_t)-1; ret = xz_dec_run(s, &b); } else { b.out_size = XZ_IOBUF_SIZE; b.out = kmalloc(XZ_IOBUF_SIZE, GFP_KERNEL); if (b.out == NULL) goto error_alloc_out; if (fill != NULL) { in = kmalloc(XZ_IOBUF_SIZE, GFP_KERNEL); if (in == NULL) goto error_alloc_in; b.in = in; } do { if (b.in_pos == b.in_size && fill != NULL) { if (in_used != NULL) *in_used += b.in_pos; b.in_pos = 0; in_size = fill(in, XZ_IOBUF_SIZE); if (in_size < 0) { /* * This isn't an optimal error code * but it probably isn't worth making * a new one either. */ ret = XZ_BUF_ERROR; break; } b.in_size = in_size; } ret = xz_dec_run(s, &b); if (b.out_pos == b.out_size || ret != XZ_OK) { /* * Setting ret here may hide an error * returned by xz_dec_run(), but probably * it's not too bad. */ if (flush(b.out, b.out_pos) != (int)b.out_pos) ret = XZ_BUF_ERROR; b.out_pos = 0; } } while (ret == XZ_OK); if (fill != NULL) kfree(in); kfree(b.out); } if (in_used != NULL) *in_used += b.in_pos; xz_dec_end(s); switch (ret) { case XZ_STREAM_END: return 0; case XZ_MEMLIMIT_ERROR: /* This can occur only in multi-call mode. */ error("Multi-call XZ decompressor limits " "the LZMA2 dictionary to 1 MiB"); break; case XZ_FORMAT_ERROR: error("Input is not in the XZ format (wrong magic bytes)"); break; case XZ_OPTIONS_ERROR: error("Input was encoded with settings that are not " "supported by this XZ decoder"); break; case XZ_DATA_ERROR: error("XZ-compressed data is corrupt"); break; case XZ_BUF_ERROR: error("Output buffer is too small or the " "XZ-compressed data is corrupt"); break; default: error("Bug in the XZ decompressor"); break; } return -1; error_alloc_in: kfree(b.out); error_alloc_out: xz_dec_end(s); error_alloc_state: error("XZ decompressor ran out of memory"); return -1; }
static int decompressor_xz_consumebhs(struct microfs_sb_info* sbi, void* data, struct buffer_head** bhs, __u32 nbhs, __u32* length, __u32* bh, __u32* bh_offset, __u32* inflated, int* implerr) { int err = 0; struct decompressor_xz_data* xzdat = data; __u32 prev_out_pos = xzdat->xz_buf.out_pos; pr_spam("decompressor_xz_consumebhs: sbi=0x%p, bhs=0x%p, nbhs=%u\n", sbi, bhs, nbhs); pr_spam("decompressor_xz_consumebhs: xzdat=0x%p\n", xzdat); pr_spam("decompressor_xz_consumebhs: *length=%u, *bh=%u, *bh_offset=%u, *inflated=%u\n", *length, *bh, *bh_offset, *inflated); do { if (xzdat->xz_buf.in_size == xzdat->xz_buf.in_pos) { pr_spam("decompressor_xz_consumebhs: *bh=%u, bhs[*bh]=0x%p\n", *bh, bhs[*bh]); xzdat->xz_buf.in_pos = 0; xzdat->xz_buf.in_size = min_t(__u32, *length, PAGE_SIZE - *bh_offset); xzdat->xz_buf.in = bhs[*bh]->b_data + *bh_offset; *bh += 1; *length -= xzdat->xz_buf.in_size; *bh_offset = 0; } pr_spam("decompressor_xz_consumebhs: *length=%u\n", *length); pr_spam("decompressor_xz_consumebhs: pre;" " xzdat->xz_buf.out_size=%zu, xzdat->xz_buf.out=0x%p\n", xzdat->xz_buf.out_size, xzdat->xz_buf.out); pr_spam("decompressor_xz_consumebhs: pre;" " xzdat->xz_buf.in_size=%zu, xzdat->xz_buf.in=0x%p\n", xzdat->xz_buf.in_size, xzdat->xz_buf.in); pr_spam("decompressor_xz_consumebhs: pre;" " prev_out_pos=%u, xzdat->xz_totalout=%u\n", prev_out_pos, xzdat->xz_totalout); *implerr = xz_dec_run(xzdat->xz_state, &xzdat->xz_buf); xzdat->xz_totalout += xzdat->xz_buf.out_pos - prev_out_pos; prev_out_pos = xzdat->xz_buf.out_pos; pr_spam("decompressor_xz_consumebhs: post;" " xzdat->xz_buf.out_size=%zu, xzdat->xz_buf.out=0x%p\n", xzdat->xz_buf.out_size, xzdat->xz_buf.out); pr_spam("decompressor_xz_consumebhs: post;" " xzdat->xz_buf.in_size=%zu, xzdat->xz_buf.in=0x%p\n", xzdat->xz_buf.in_size, xzdat->xz_buf.in); pr_spam("decompressor_xz_consumebhs: post;" "prev_out_pos=%u, xzdat->xz_totalout=%u\n", prev_out_pos, xzdat->xz_totalout); pr_spam("decompressor_xz_consumebhs: *implerr=%d\n", *implerr); if (xzdat->xz_buf.out_size == xzdat->xz_buf.out_pos) { /* The output buffer must be refilled. */ break; } } while (*implerr == XZ_OK); if (*implerr == XZ_STREAM_END) { *inflated += xzdat->xz_totalout; pr_spam("decompressor_xz_consumebhs: at streams end, %u bytes inflated, %u bytes total", xzdat->xz_totalout, *inflated); xzdat->xz_totalout = 0; sbi->si_decompressor->dc_reset(sbi, data); } else if (*implerr != XZ_OK) { pr_err("decompressor_xz_consumebhs: failed to inflate data, implerr %d\n", *implerr); err = -EIO; } return err; }
int xz_decompress(unsigned char *encoded, int encoded_size, unsigned char **decoded, int *decoded_size) { static int xz_initialized = 0; enum xz_ret ret; struct xz_dec *xz; struct xz_buf buf; unsigned char *dec_buffer; unsigned char *temp; int dec_size; if (!xz_initialized) { xz_crc32_init(); xz_initialized = 1; } *decoded = NULL; *decoded_size = 0; buf.in = encoded; buf.in_pos = 0; buf.in_size = encoded_size; dec_size = BUFFER_INCREMENT; dec_buffer = (unsigned char *)malloc(dec_size); if (!dec_buffer) { return 0; } buf.out = dec_buffer; buf.out_pos = 0; buf.out_size = dec_size; xz = xz_dec_init(XZ_DYNALLOC, (uint32_t)-1); if (!xz) { free(dec_buffer); return 0; } do { ret = xz_dec_run(xz, &buf); if (ret == XZ_OK) { /* things are okay, but more buffer space is needed */ dec_size += BUFFER_INCREMENT; temp = realloc(dec_buffer, dec_size); if (!temp) { free(dec_buffer); xz_dec_end(xz); return 0; } else dec_buffer = temp; buf.out_size = dec_size; buf.out = dec_buffer; } else { /* any other status is an exit condition (either error or stream end) */ break; } } while (ret != XZ_STREAM_END); if (ret == XZ_STREAM_END) { /* resize the final buffer */ dec_size = buf.out_pos; temp = realloc(dec_buffer, dec_size); if (!temp) { free(dec_buffer); xz_dec_end(xz); return 0; } *decoded = temp; *decoded_size = dec_size; xz_dec_end(xz); return 1; } else { xz_dec_end(xz); free(dec_buffer); return 0; } }