/* * Utility function to push input data through compressor, * writing full output blocks as necessary. * * Note that this handles both the regular write case (finishing == * false) and the end-of-archive case (finishing == true). */ static int drive_compressor(struct archive_write_filter *f, struct private_data *data, int finishing) { int ret; for (;;) { if (data->stream.avail_out == 0) { data->total_out += data->compressed_buffer_size; ret = __archive_write_filter(f->next_filter, data->compressed, data->compressed_buffer_size); if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL); data->stream.next_out = data->compressed; data->stream.avail_out = data->compressed_buffer_size; } /* If there's nothing to do, we're done. */ if (!finishing && data->stream.avail_in == 0) return (ARCHIVE_OK); ret = lzma_code(&(data->stream), finishing ? LZMA_FINISH : LZMA_RUN ); switch (ret) { case LZMA_OK: /* In non-finishing case, check if compressor * consumed everything */ if (!finishing && data->stream.avail_in == 0) return (ARCHIVE_OK); /* In finishing case, this return always means * there's more work */ break; case LZMA_STREAM_END: /* This return can only occur in finishing case. */ if (finishing) return (ARCHIVE_OK); archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, "lzma compression data error"); return (ARCHIVE_FATAL); case LZMA_MEMLIMIT_ERROR: archive_set_error(f->archive, ENOMEM, "lzma compression error: " "%ju MiB would have been needed", (uintmax_t)((lzma_memusage(&(data->stream)) + 1024 * 1024 -1) / (1024 * 1024))); return (ARCHIVE_FATAL); default: /* Any other return value indicates an error. */ archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, "lzma compression failed:" " lzma_code() call returned status %d", ret); return (ARCHIVE_FATAL); } } }
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; }
/* * Utility function to push input data through compressor, * writing full output blocks as necessary. * * Note that this handles both the regular write case (finishing == * false) and the end-of-archive case (finishing == true). */ static int drive_compressor(struct archive_write *a, struct private_data *state, int finishing) { ssize_t bytes_written; int ret; for (;;) { if (state->stream.avail_out == 0) { bytes_written = (a->client_writer)(&a->archive, a->client_data, state->compressed, state->compressed_buffer_size); if (bytes_written <= 0) { /* TODO: Handle this write failure */ return (ARCHIVE_FATAL); } else if ((size_t)bytes_written < state->compressed_buffer_size) { /* Short write: Move remaining to * front of block and keep filling */ memmove(state->compressed, state->compressed + bytes_written, state->compressed_buffer_size - bytes_written); } a->archive.raw_position += bytes_written; state->stream.next_out = state->compressed + state->compressed_buffer_size - bytes_written; state->stream.avail_out = bytes_written; } /* If there's nothing to do, we're done. */ if (!finishing && state->stream.avail_in == 0) return (ARCHIVE_OK); ret = lzma_code(&(state->stream), finishing ? LZMA_FINISH : LZMA_RUN ); switch (ret) { case LZMA_OK: /* In non-finishing case, check if compressor * consumed everything */ if (!finishing && state->stream.avail_in == 0) return (ARCHIVE_OK); /* In finishing case, this return always means * there's more work */ break; case LZMA_STREAM_END: /* This return can only occur in finishing case. */ if (finishing) return (ARCHIVE_OK); archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "lzma compression data error"); return (ARCHIVE_FATAL); case LZMA_MEMLIMIT_ERROR: archive_set_error(&a->archive, ENOMEM, "lzma compression error: " "%ju MiB would have been needed", (uintmax_t)((lzma_memusage(&(state->stream)) + 1024 * 1024 -1) / (1024 * 1024))); return (ARCHIVE_FATAL); default: /* Any other return value indicates an error. */ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "lzma compression failed:" " lzma_code() call returned status %d", ret); return (ARCHIVE_FATAL); } } }
/// \brief Parse the Index(es) from the given .xz file /// /// \param xfi Pointer to structure where the decoded information /// is stored. /// \param pair Input file /// /// \return On success, false is returned. On error, true is returned. /// // TODO: This function is pretty big. liblzma should have a function that // takes a callback function to parse the Index(es) from a .xz file to make // it easy for applications. static bool parse_indexes(xz_file_info *xfi, file_pair *pair) { if (pair->src_st.st_size <= 0) { message_error(_("%s: File is empty"), pair->src_name); return true; } if (pair->src_st.st_size < 2 * LZMA_STREAM_HEADER_SIZE) { message_error(_("%s: Too small to be a valid .xz file"), pair->src_name); return true; } io_buf buf; lzma_stream_flags header_flags; lzma_stream_flags footer_flags; lzma_ret ret; // lzma_stream for the Index decoder lzma_stream strm = LZMA_STREAM_INIT; // All Indexes decoded so far lzma_index *combined_index = NULL; // The Index currently being decoded lzma_index *this_index = NULL; // Current position in the file. We parse the file backwards so // initialize it to point to the end of the file. off_t pos = pair->src_st.st_size; // Each loop iteration decodes one Index. do { // Check that there is enough data left to contain at least // the Stream Header and Stream Footer. This check cannot // fail in the first pass of this loop. if (pos < 2 * LZMA_STREAM_HEADER_SIZE) { message_error("%s: %s", pair->src_name, message_strm(LZMA_DATA_ERROR)); goto error; } pos -= LZMA_STREAM_HEADER_SIZE; lzma_vli stream_padding = 0; // Locate the Stream Footer. There may be Stream Padding which // we must skip when reading backwards. while (true) { if (pos < LZMA_STREAM_HEADER_SIZE) { message_error("%s: %s", pair->src_name, message_strm( LZMA_DATA_ERROR)); goto error; } if (io_pread(pair, &buf, LZMA_STREAM_HEADER_SIZE, pos)) goto error; // Stream Padding is always a multiple of four bytes. int i = 2; if (buf.u32[i] != 0) break; // To avoid calling io_pread() for every four bytes // of Stream Padding, take advantage that we read // 12 bytes (LZMA_STREAM_HEADER_SIZE) already and // check them too before calling io_pread() again. do { stream_padding += 4; pos -= 4; --i; } while (i >= 0 && buf.u32[i] == 0); } // Decode the Stream Footer. ret = lzma_stream_footer_decode(&footer_flags, buf.u8); if (ret != LZMA_OK) { message_error("%s: %s", pair->src_name, message_strm(ret)); goto error; } // Check that the Stream Footer doesn't specify something // that we don't support. This can only happen if the xz // version is older than liblzma and liblzma supports // something new. // // It is enough to check Stream Footer. Stream Header must // match when it is compared against Stream Footer with // lzma_stream_flags_compare(). if (footer_flags.version != 0) { message_error("%s: %s", pair->src_name, message_strm(LZMA_OPTIONS_ERROR)); goto error; } // Check that the size of the Index field looks sane. lzma_vli index_size = footer_flags.backward_size; if ((lzma_vli)(pos) < index_size + LZMA_STREAM_HEADER_SIZE) { message_error("%s: %s", pair->src_name, message_strm(LZMA_DATA_ERROR)); goto error; } // Set pos to the beginning of the Index. pos -= index_size; // See how much memory we can use for decoding this Index. uint64_t memlimit = hardware_memlimit_get(MODE_LIST); uint64_t memused = 0; if (combined_index != NULL) { memused = lzma_index_memused(combined_index); if (memused > memlimit) message_bug(); memlimit -= memused; } // Decode the Index. ret = lzma_index_decoder(&strm, &this_index, memlimit); if (ret != LZMA_OK) { message_error("%s: %s", pair->src_name, message_strm(ret)); goto error; } do { // Don't give the decoder more input than the // Index size. strm.avail_in = my_min(IO_BUFFER_SIZE, index_size); if (io_pread(pair, &buf, strm.avail_in, pos)) goto error; pos += strm.avail_in; index_size -= strm.avail_in; strm.next_in = buf.u8; ret = lzma_code(&strm, LZMA_RUN); } while (ret == LZMA_OK); // If the decoding seems to be successful, check also that // the Index decoder consumed as much input as indicated // by the Backward Size field. if (ret == LZMA_STREAM_END) if (index_size != 0 || strm.avail_in != 0) ret = LZMA_DATA_ERROR; if (ret != LZMA_STREAM_END) { // LZMA_BUFFER_ERROR means that the Index decoder // would have liked more input than what the Index // size should be according to Stream Footer. // The message for LZMA_DATA_ERROR makes more // sense in that case. if (ret == LZMA_BUF_ERROR) ret = LZMA_DATA_ERROR; message_error("%s: %s", pair->src_name, message_strm(ret)); // If the error was too low memory usage limit, // show also how much memory would have been needed. if (ret == LZMA_MEMLIMIT_ERROR) { uint64_t needed = lzma_memusage(&strm); if (UINT64_MAX - needed < memused) needed = UINT64_MAX; else needed += memused; message_mem_needed(V_ERROR, needed); } goto error; } // Decode the Stream Header and check that its Stream Flags // match the Stream Footer. pos -= footer_flags.backward_size + LZMA_STREAM_HEADER_SIZE; if ((lzma_vli)(pos) < lzma_index_total_size(this_index)) { message_error("%s: %s", pair->src_name, message_strm(LZMA_DATA_ERROR)); goto error; } pos -= lzma_index_total_size(this_index); if (io_pread(pair, &buf, LZMA_STREAM_HEADER_SIZE, pos)) goto error; ret = lzma_stream_header_decode(&header_flags, buf.u8); if (ret != LZMA_OK) { message_error("%s: %s", pair->src_name, message_strm(ret)); goto error; } ret = lzma_stream_flags_compare(&header_flags, &footer_flags); if (ret != LZMA_OK) { message_error("%s: %s", pair->src_name, message_strm(ret)); goto error; } // Store the decoded Stream Flags into this_index. This is // needed so that we can print which Check is used in each // Stream. ret = lzma_index_stream_flags(this_index, &footer_flags); if (ret != LZMA_OK) message_bug(); // Store also the size of the Stream Padding field. It is // needed to show the offsets of the Streams correctly. ret = lzma_index_stream_padding(this_index, stream_padding); if (ret != LZMA_OK) message_bug(); if (combined_index != NULL) { // Append the earlier decoded Indexes // after this_index. ret = lzma_index_cat( this_index, combined_index, NULL); if (ret != LZMA_OK) { message_error("%s: %s", pair->src_name, message_strm(ret)); goto error; } } combined_index = this_index; this_index = NULL; xfi->stream_padding += stream_padding; } while (pos > 0); lzma_end(&strm); // All OK. Make combined_index available to the caller. xfi->idx = combined_index; return false; error: // Something went wrong, free the allocated memory. lzma_end(&strm); lzma_index_end(combined_index, NULL); lzma_index_end(this_index, NULL); return true; }