static int consume_block_info(struct archive_read_filter *self) { struct read_lzop *state = (struct read_lzop *)self->data; const unsigned char *p; unsigned flags = state->flags; p = __archive_read_filter_ahead(self->upstream, 4, NULL); if (p == NULL) goto truncated; state->uncompressed_size = archive_be32dec(p); __archive_read_filter_consume(self->upstream, 4); if (state->uncompressed_size == 0) return (ARCHIVE_EOF); if (state->uncompressed_size > MAX_BLOCK_SIZE) goto corrupted; p = __archive_read_filter_ahead(self->upstream, 4, NULL); if (p == NULL) goto truncated; state->compressed_size = archive_be32dec(p); __archive_read_filter_consume(self->upstream, 4); if (state->compressed_size > state->uncompressed_size) goto corrupted; if (flags & (CRC32_UNCOMPRESSED | ADLER32_UNCOMPRESSED)) { p = __archive_read_filter_ahead(self->upstream, 4, NULL); if (p == NULL) goto truncated; state->compressed_cksum = state->uncompressed_cksum = archive_be32dec(p); __archive_read_filter_consume(self->upstream, 4); } if ((flags & (CRC32_COMPRESSED | ADLER32_COMPRESSED)) && state->compressed_size < state->uncompressed_size) { p = __archive_read_filter_ahead(self->upstream, 4, NULL); if (p == NULL) goto truncated; state->compressed_cksum = archive_be32dec(p); __archive_read_filter_consume(self->upstream, 4); } return (ARCHIVE_OK); truncated: archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data"); return (ARCHIVE_FAILED); corrupted: archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header"); return (ARCHIVE_FAILED); }
/* * Return next 'n' bits from stream. * * -1 indicates end of available data. */ static int getbits(struct archive_read_filter *self, int n) { struct private_data *state = (struct private_data *)self->data; int code; ssize_t ret; static const int mask[] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff }; while (state->bits_avail < n) { if (state->avail_in <= 0) { state->next_in = __archive_read_filter_ahead(self->upstream, 1, &ret); if (ret == 0) return (-1); if (ret < 0 || state->next_in == NULL) return (ARCHIVE_FATAL); state->avail_in = ret; __archive_read_filter_consume(self->upstream, ret); } state->bit_buffer |= *state->next_in++ << state->bits_avail; state->avail_in--; state->bits_avail += 8; state->bytes_in_section++; } code = state->bit_buffer; state->bit_buffer >>= n; state->bits_avail -= n; return (code & mask[n]); }
/* * Mark the appropriate data as used. Note that the request here will * often be much smaller than the size of the previous read_ahead * request. */ ssize_t __archive_read_consume(struct archive_read *a, size_t request) { ssize_t r; r = __archive_read_filter_consume(a->filter, request); a->archive.file_position += r; return (r); }
/* * Return the next block of decompressed data. */ static ssize_t lzma_filter_read(struct archive_read_filter *self, const void **p) { struct private_data *state; size_t decompressed; ssize_t avail_in, ret; state = (struct private_data *)self->data; /* Empty our output buffer. */ state->stream.next_out = state->out_block; state->stream.avail_out = state->out_block_size; /* Try to fill the output buffer. */ while (state->stream.avail_out > 0 && !state->eof) { state->stream.next_in = (unsigned char *)(uintptr_t) __archive_read_filter_ahead(self->upstream, 1, &avail_in); if (state->stream.next_in == NULL && avail_in < 0) return (ARCHIVE_FATAL); state->stream.avail_in = avail_in; /* Decompress as much as we can in one pass. */ ret = lzmadec_decode(&(state->stream), avail_in == 0); switch (ret) { case LZMADEC_STREAM_END: /* Found end of stream. */ state->eof = 1; /* FALL THROUGH */ case LZMADEC_OK: /* Decompressor made some progress. */ __archive_read_filter_consume(self->upstream, avail_in - state->stream.avail_in); break; case LZMADEC_BUF_ERROR: /* Insufficient input data? */ tk_archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Insufficient compressed data"); return (ARCHIVE_FATAL); default: /* Return an error. */ tk_archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Lzma decompression failed"); return (ARCHIVE_FATAL); } } decompressed = state->stream.next_out - state->out_block; state->total_out += decompressed; if (decompressed == 0) *p = NULL; else *p = state->out_block; return (decompressed); }
static ssize_t zstd_filter_read(struct archive_read_filter *self, const void **p) { struct private_data *state; size_t decompressed; ssize_t avail_in; ZSTD_outBuffer out; ZSTD_inBuffer in; state = (struct private_data *)self->data; out = (ZSTD_outBuffer) { state->out_block, state->out_block_size, 0 }; /* Try to fill the output buffer. */ while (out.pos < out.size && !state->eof) { if (!state->in_frame) { const size_t ret = ZSTD_initDStream(state->dstream); if (ZSTD_isError(ret)) { archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Error initializing zstd decompressor: %s", ZSTD_getErrorName(ret)); return (ARCHIVE_FATAL); } } in.src = __archive_read_filter_ahead(self->upstream, 1, &avail_in); if (avail_in < 0) { return avail_in; } if (in.src == NULL && avail_in == 0) { if (!state->in_frame) { /* end of stream */ state->eof = 1; break; } else { archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Truncated zstd input"); return (ARCHIVE_FATAL); } } in.size = avail_in; in.pos = 0; { const size_t ret = ZSTD_decompressStream(state->dstream, &out, &in); if (ZSTD_isError(ret)) { archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Zstd decompression failed: %s", ZSTD_getErrorName(ret)); return (ARCHIVE_FATAL); } /* Decompressor made some progress */ __archive_read_filter_consume(self->upstream, in.pos); /* ret guaranteed to be > 0 if frame isn't done yet */ state->in_frame = (ret != 0); } } decompressed = out.pos; state->total_out += decompressed; if (decompressed == 0) *p = NULL; else *p = state->out_block; return (decompressed); }
/* * Move the file pointer forward. */ int64_t __archive_read_consume(struct archive_read *a, int64_t request) { return (__archive_read_filter_consume(a->filter, request)); }
static ssize_t uudecode_filter_read(struct archive_read_filter *self, const void **buff) { struct uudecode *uudecode; const unsigned char *b, *d; unsigned char *out; ssize_t avail_in, ravail; ssize_t used; ssize_t total; ssize_t len, llen, nl; uudecode = (struct uudecode *)self->data; read_more: d = __archive_read_filter_ahead(self->upstream, 1, &avail_in); if (d == NULL && avail_in < 0) return (ARCHIVE_FATAL); /* Quiet a code analyzer; make sure avail_in must be zero * when d is NULL. */ if (d == NULL) avail_in = 0; used = 0; total = 0; out = uudecode->out_buff; ravail = avail_in; if (uudecode->state == ST_IGNORE) { used = avail_in; goto finish; } if (uudecode->in_cnt) { /* * If there is remaining data which is saved by * previous calling, use it first. */ if (ensure_in_buff_size(self, uudecode, avail_in + uudecode->in_cnt) != ARCHIVE_OK) return (ARCHIVE_FATAL); memcpy(uudecode->in_buff + uudecode->in_cnt, d, avail_in); d = uudecode->in_buff; avail_in += uudecode->in_cnt; uudecode->in_cnt = 0; } for (;used < avail_in; d += llen, used += llen) { int64_t l, body; b = d; len = get_line(b, avail_in - used, &nl); if (len < 0) { /* Non-ascii character is found. */ if (uudecode->state == ST_FIND_HEAD && (uudecode->total > 0 || total > 0)) { uudecode->state = ST_IGNORE; used = avail_in; goto finish; } archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Insufficient compressed data"); return (ARCHIVE_FATAL); } llen = len; if (nl == 0) { /* * Save remaining data which does not contain * NL('\n','\r'). */ if (ensure_in_buff_size(self, uudecode, len) != ARCHIVE_OK) return (ARCHIVE_FATAL); if (uudecode->in_buff != b) memmove(uudecode->in_buff, b, len); uudecode->in_cnt = (int)len; if (total == 0) { /* Do not return 0; it means end-of-file. * We should try to read bytes more. */ __archive_read_filter_consume( self->upstream, ravail); goto read_more; } break; } switch (uudecode->state) { default: case ST_FIND_HEAD: /* Do not read more than UUENCODE_BID_MAX_READ bytes */ if (total + len >= UUENCODE_BID_MAX_READ) { archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Invalid format data"); return (ARCHIVE_FATAL); } if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0) l = 6; else if (len - nl >= 18 && memcmp(b, "begin-base64 ", 13) == 0) l = 13; else l = 0; if (l != 0 && b[l] >= '0' && b[l] <= '7' && b[l+1] >= '0' && b[l+1] <= '7' && b[l+2] >= '0' && b[l+2] <= '7' && b[l+3] == ' ') { if (l == 6) uudecode->state = ST_READ_UU; else uudecode->state = ST_READ_BASE64; } break; case ST_READ_UU: if (total + len * 2 > OUT_BUFF_SIZE) goto finish; body = len - nl; if (!uuchar[*b] || body <= 0) { archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Insufficient compressed data"); return (ARCHIVE_FATAL); } /* Get length of undecoded bytes of curent line. */ l = UUDECODE(*b++); body--; if (l > body) { archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Insufficient compressed data"); return (ARCHIVE_FATAL); } if (l == 0) { uudecode->state = ST_UUEND; break; } while (l > 0) { int n = 0; if (l > 0) { if (!uuchar[b[0]] || !uuchar[b[1]]) break; n = UUDECODE(*b++) << 18; n |= UUDECODE(*b++) << 12; *out++ = n >> 16; total++; --l; } if (l > 0) { if (!uuchar[b[0]]) break; n |= UUDECODE(*b++) << 6; *out++ = (n >> 8) & 0xFF; total++; --l; } if (l > 0) { if (!uuchar[b[0]]) break; n |= UUDECODE(*b++); *out++ = n & 0xFF; total++; --l; } } if (l) { archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Insufficient compressed data"); return (ARCHIVE_FATAL); } break; case ST_UUEND: if (len - nl == 3 && memcmp(b, "end ", 3) == 0) uudecode->state = ST_FIND_HEAD; else { archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Insufficient compressed data"); return (ARCHIVE_FATAL); } break; case ST_READ_BASE64: if (total + len * 2 > OUT_BUFF_SIZE) goto finish; l = len - nl; if (l >= 3 && b[0] == '=' && b[1] == '=' && b[2] == '=') { uudecode->state = ST_FIND_HEAD; break; } while (l > 0) { int n = 0; if (l > 0) { if (!base64[b[0]] || !base64[b[1]]) break; n = base64num[*b++] << 18; n |= base64num[*b++] << 12; *out++ = n >> 16; total++; l -= 2; } if (l > 0) { if (*b == '=') break; if (!base64[*b]) break; n |= base64num[*b++] << 6; *out++ = (n >> 8) & 0xFF; total++; --l; } if (l > 0) { if (*b == '=') break; if (!base64[*b]) break; n |= base64num[*b++]; *out++ = n & 0xFF; total++; --l; } } if (l && *b != '=') { archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Insufficient compressed data"); return (ARCHIVE_FATAL); } break; } } finish: if (ravail < avail_in) used -= avail_in - ravail; __archive_read_filter_consume(self->upstream, used); *buff = uudecode->out_buff; uudecode->total += total; return (total); }
int64_t __archive_read_filter_skip(struct archive_read_filter *filter, int64_t request) { int64_t bytes_skipped, total_bytes_skipped = 0; size_t min; if (filter->fatal) return (-1); /* * If there is data in the buffers already, use that first. */ if (filter->avail > 0) { min = minimum(request, (off_t)filter->avail); bytes_skipped = __archive_read_filter_consume(filter, min); request -= bytes_skipped; total_bytes_skipped += bytes_skipped; } if (filter->client_avail > 0) { min = minimum(request, (int64_t)filter->client_avail); bytes_skipped = __archive_read_filter_consume(filter, min); request -= bytes_skipped; total_bytes_skipped += bytes_skipped; } if (request == 0) return (total_bytes_skipped); /* * If a client_skipper was provided, try that first. */ #if ARCHIVE_API_VERSION < 2 if ((filter->skip != NULL) && (request < SSIZE_MAX)) { #else if (filter->skip != NULL) { #endif bytes_skipped = (filter->skip)(filter, request); if (bytes_skipped < 0) { /* error */ filter->client_total = filter->client_avail = 0; filter->client_next = filter->client_buff = NULL; filter->fatal = 1; return (bytes_skipped); } total_bytes_skipped += bytes_skipped; request -= bytes_skipped; filter->client_next = filter->client_buff; filter->client_avail = filter->client_total = 0; } /* * Note that client_skipper will usually not satisfy the * full request (due to low-level blocking concerns), * so even if client_skipper is provided, we may still * have to use ordinary reads to finish out the request. */ while (request > 0) { ssize_t bytes_read; (void)__archive_read_filter_ahead(filter, 1, &bytes_read); if (bytes_read < 0) return (bytes_read); if (bytes_read == 0) { return (total_bytes_skipped); } min = (size_t)(minimum(bytes_read, request)); bytes_read = __archive_read_filter_consume(filter, min); total_bytes_skipped += bytes_read; request -= bytes_read; } return (total_bytes_skipped); }
/* * Return the next block of decompressed data. */ static ssize_t bzip2_filter_read(struct archive_read_filter *self, const void **p) { struct private_data *state; size_t decompressed; const char *read_buf; ssize_t ret; state = (struct private_data *)self->data; if (state->eof) { *p = NULL; return (0); } /* Empty our output buffer. */ state->stream.next_out = state->out_block; state->stream.avail_out = state->out_block_size; /* Try to fill the output buffer. */ for (;;) { if (!state->valid) { if (bzip2_reader_bid(self->bidder, self->upstream) == 0) { state->eof = 1; *p = state->out_block; decompressed = state->stream.next_out - state->out_block; return (decompressed); } /* Initialize compression library. */ ret = BZ2_bzDecompressInit(&(state->stream), 0 /* library verbosity */, 0 /* don't use low-mem algorithm */); /* If init fails, try low-memory algorithm instead. */ if (ret == BZ_MEM_ERROR) ret = BZ2_bzDecompressInit(&(state->stream), 0 /* library verbosity */, 1 /* do use low-mem algo */); if (ret != BZ_OK) { const char *detail = NULL; int err = ARCHIVE_ERRNO_MISC; switch (ret) { case BZ_PARAM_ERROR: detail = "invalid setup parameter"; break; case BZ_MEM_ERROR: err = ENOMEM; detail = "out of memory"; break; case BZ_CONFIG_ERROR: detail = "mis-compiled library"; break; } archive_set_error(&self->archive->archive, err, "Internal error initializing decompressor%s%s", detail == NULL ? "" : ": ", detail); return (ARCHIVE_FATAL); } state->valid = 1; } /* stream.next_in is really const, but bzlib * doesn't declare it so. <sigh> */ read_buf = __archive_read_filter_ahead(self->upstream, 1, &ret); if (read_buf == NULL) return (ARCHIVE_FATAL); state->stream.next_in = (char *)(uintptr_t)read_buf; state->stream.avail_in = ret; /* There is no more data, return whatever we have. */ if (ret == 0) { state->eof = 1; *p = state->out_block; decompressed = state->stream.next_out - state->out_block; return (decompressed); } /* Decompress as much as we can in one pass. */ ret = BZ2_bzDecompress(&(state->stream)); __archive_read_filter_consume(self->upstream, state->stream.next_in - read_buf); switch (ret) { case BZ_STREAM_END: /* Found end of stream. */ switch (BZ2_bzDecompressEnd(&(state->stream))) { case BZ_OK: break; default: archive_set_error(&(self->archive->archive), ARCHIVE_ERRNO_MISC, "Failed to clean up decompressor"); return (ARCHIVE_FATAL); } state->valid = 0; /* FALLTHROUGH */ case BZ_OK: /* Decompressor made some progress. */ /* If we filled our buffer, update stats and return. */ if (state->stream.avail_out == 0) { *p = state->out_block; decompressed = state->stream.next_out - state->out_block; return (decompressed); } break; default: /* Return an error. */ archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "bzip decompression failed"); return (ARCHIVE_FATAL); } } }
/* * Use select() to decide whether the child is ready for read or write. */ static ssize_t child_read(struct archive_read_filter *self, char *buf, size_t buf_len) { struct program_filter *state = self->data; ssize_t ret, requested, avail; const char *p; requested = buf_len > SSIZE_MAX ? SSIZE_MAX : buf_len; for (;;) { do { ret = read(state->child_stdout, buf, requested); } while (ret == -1 && errno == EINTR); if (ret > 0) return (ret); if (ret == 0 || (ret == -1 && errno == EPIPE)) /* Child has closed its output; reap the child * and return the status. */ return (child_stop(self, state)); if (ret == -1 && errno != EAGAIN) return (-1); if (state->child_stdin == -1) { /* Block until child has some I/O ready. */ __archive_check_child(state->child_stdin, state->child_stdout); continue; } /* Get some more data from upstream. */ p = __archive_read_filter_ahead(self->upstream, 1, &avail); if (p == NULL) { close(state->child_stdin); state->child_stdin = -1; fcntl(state->child_stdout, F_SETFL, 0); if (avail < 0) return (avail); continue; } do { ret = write(state->child_stdin, p, avail); } while (ret == -1 && errno == EINTR); if (ret > 0) { /* Consume whatever we managed to write. */ __archive_read_filter_consume(self->upstream, ret); } else if (ret == -1 && errno == EAGAIN) { /* Block until child has some I/O ready. */ __archive_check_child(state->child_stdin, state->child_stdout); } else { /* Write failed. */ close(state->child_stdin); state->child_stdin = -1; fcntl(state->child_stdout, F_SETFL, 0); /* If it was a bad error, we're done; otherwise * it was EPIPE or EOF, and we can still read * from the child. */ if (ret == -1 && errno != EPIPE) return (-1); } } }
/* * Setup the callbacks. */ static int lzma_bidder_init(struct archive_read_filter *self) { static const size_t out_block_size = 64 * 1024; void *out_block; struct private_data *state; ssize_t ret, avail_in; self->code = ARCHIVE_COMPRESSION_LZMA; self->name = "lzma"; state = (struct private_data *)calloc(sizeof(*state), 1); out_block = (unsigned char *)malloc(out_block_size); if (state == NULL || out_block == NULL) { tk_archive_set_error(&self->archive->archive, ENOMEM, "Can't allocate data for lzma decompression"); free(out_block); free(state); return (ARCHIVE_FATAL); } self->data = state; state->out_block_size = out_block_size; state->out_block = out_block; self->read = lzma_filter_read; self->skip = NULL; /* not supported */ self->close = lzma_filter_close; /* Prime the lzma library with 18 bytes of input. */ state->stream.next_in = (unsigned char *)(uintptr_t) __archive_read_filter_ahead(self->upstream, 18, &avail_in); if (state->stream.next_in == NULL) return (ARCHIVE_FATAL); state->stream.avail_in = avail_in; state->stream.next_out = state->out_block; state->stream.avail_out = state->out_block_size; /* Initialize compression library. */ ret = lzmadec_init(&(state->stream)); __archive_read_filter_consume(self->upstream, avail_in - state->stream.avail_in); if (ret == LZMADEC_OK) return (ARCHIVE_OK); /* Library setup failed: Clean up. */ tk_archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Internal error initializing lzma library"); /* Override the error message if we know what really went wrong. */ switch (ret) { case LZMADEC_HEADER_ERROR: tk_archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Internal error initializing compression library: " "invalid header"); break; case LZMADEC_MEM_ERROR: tk_archive_set_error(&self->archive->archive, ENOMEM, "Internal error initializing compression library: " "out of memory"); break; } free(state->out_block); free(state); self->data = NULL; return (ARCHIVE_FATAL); }
/* * Return the next block of decompressed data. */ static ssize_t xz_filter_read(struct archive_read_filter *self, const void **p) { struct private_data *state; size_t decompressed; ssize_t avail_in; int ret; state = (struct private_data *)self->data; /* Empty our output buffer. */ state->stream.next_out = state->out_block; state->stream.avail_out = state->out_block_size; /* Try to fill the output buffer. */ while (state->stream.avail_out > 0 && !state->eof) { state->stream.next_in = __archive_read_filter_ahead(self->upstream, 1, &avail_in); if (state->stream.next_in == NULL && avail_in < 0) return (ARCHIVE_FATAL); state->stream.avail_in = avail_in; /* Decompress as much as we can in one pass. */ ret = lzma_code(&(state->stream), (state->stream.avail_in == 0)? LZMA_FINISH: LZMA_RUN); switch (ret) { case LZMA_STREAM_END: /* Found end of stream. */ state->eof = 1; /* FALL THROUGH */ case LZMA_OK: /* Decompressor made some progress. */ __archive_read_filter_consume(self->upstream, avail_in - state->stream.avail_in); break; case LZMA_MEM_ERROR: tk_archive_set_error(&self->archive->archive, ENOMEM, "Lzma library error: Cannot allocate memory"); return (ARCHIVE_FATAL); case LZMA_MEMLIMIT_ERROR: tk_archive_set_error(&self->archive->archive, ENOMEM, "Lzma library error: Out of memory"); return (ARCHIVE_FATAL); case LZMA_FORMAT_ERROR: tk_archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Lzma library error: format not recognized"); return (ARCHIVE_FATAL); case LZMA_OPTIONS_ERROR: tk_archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Lzma library error: Invalid options"); return (ARCHIVE_FATAL); case LZMA_DATA_ERROR: tk_archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Lzma library error: Corrupted input data"); return (ARCHIVE_FATAL); case LZMA_BUF_ERROR: tk_archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Lzma library error: No progress is possible"); return (ARCHIVE_FATAL); default: /* Return an error. */ tk_archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Lzma decompression failed: Unknown error"); return (ARCHIVE_FATAL); } } decompressed = state->stream.next_out - state->out_block; state->total_out += decompressed; if (decompressed == 0) *p = NULL; else *p = state->out_block; return (decompressed); }
static ssize_t lzop_filter_read(struct archive_read_filter *self, const void **p) { struct read_lzop *state = (struct read_lzop *)self->data; const void *b; lzo_uint out_size; uint32_t cksum; int ret, r; if (state->unconsumed_bytes) { __archive_read_filter_consume(self->upstream, state->unconsumed_bytes); state->unconsumed_bytes = 0; } if (state->eof) return (0); for (;;) { if (!state->in_stream) { ret = consume_header(self); if (ret < ARCHIVE_OK) return (ret); if (ret == ARCHIVE_EOF) { state->eof = 1; return (0); } } ret = consume_block_info(self); if (ret < ARCHIVE_OK) return (ret); if (ret == ARCHIVE_EOF) state->in_stream = 0; else break; } if (state->out_block == NULL || state->out_block_size < state->uncompressed_size) { void *new_block; new_block = realloc(state->out_block, state->uncompressed_size); if (new_block == NULL) { archive_set_error(&self->archive->archive, ENOMEM, "Can't allocate data for lzop decompression"); return (ARCHIVE_FATAL); } state->out_block = new_block; state->out_block_size = state->uncompressed_size; } b = __archive_read_filter_ahead(self->upstream, state->compressed_size, NULL); if (b == NULL) { archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data"); return (ARCHIVE_FATAL); } if (state->flags & CRC32_COMPRESSED) cksum = crc32(crc32(0, NULL, 0), b, state->compressed_size); else if (state->flags & ADLER32_COMPRESSED) cksum = adler32(adler32(0, NULL, 0), b, state->compressed_size); else cksum = state->compressed_cksum; if (cksum != state->compressed_cksum) { archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Corrupted data"); return (ARCHIVE_FATAL); } /* * If the both uncompressed size and compressed size are the same, * we do not decompress this block. */ if (state->uncompressed_size == state->compressed_size) { *p = b; state->total_out += state->compressed_size; state->unconsumed_bytes = state->compressed_size; return ((ssize_t)state->uncompressed_size); } /* * Drive lzo uncompresison. */ out_size = (lzo_uint)state->uncompressed_size; r = lzo1x_decompress_safe(b, (lzo_uint)state->compressed_size, state->out_block, &out_size, NULL); switch (r) { case LZO_E_OK: if (out_size == state->uncompressed_size) break; archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Corrupted data"); return (ARCHIVE_FATAL); case LZO_E_OUT_OF_MEMORY: archive_set_error(&self->archive->archive, ENOMEM, "lzop decompression failed: out of memory"); return (ARCHIVE_FATAL); default: archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "lzop decompression failed: %d", r); return (ARCHIVE_FATAL); } if (state->flags & CRC32_UNCOMPRESSED) cksum = crc32(crc32(0, NULL, 0), state->out_block, state->uncompressed_size); else if (state->flags & ADLER32_UNCOMPRESSED) cksum = adler32(adler32(0, NULL, 0), state->out_block, state->uncompressed_size); else cksum = state->uncompressed_cksum; if (cksum != state->uncompressed_cksum) { archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Corrupted data"); return (ARCHIVE_FATAL); } __archive_read_filter_consume(self->upstream, state->compressed_size); *p = state->out_block; state->total_out += out_size; return ((ssize_t)out_size); }
static int consume_header(struct archive_read_filter *self) { struct read_lzop *state = (struct read_lzop *)self->data; const unsigned char *p, *_p; unsigned checksum, flags, len, method, version; /* * Check LZOP magic code. */ p = __archive_read_filter_ahead(self->upstream, LZOP_HEADER_MAGIC_LEN, NULL); if (p == NULL) return (ARCHIVE_EOF); if (memcmp(p, LZOP_HEADER_MAGIC, LZOP_HEADER_MAGIC_LEN)) return (ARCHIVE_EOF); __archive_read_filter_consume(self->upstream, LZOP_HEADER_MAGIC_LEN); p = __archive_read_filter_ahead(self->upstream, 29, NULL); if (p == NULL) goto truncated; _p = p; version = archive_be16dec(p); p += 4;/* version(2 bytes) + library version(2 bytes) */ if (version >= 0x940) { unsigned reqversion = archive_be16dec(p); p += 2; if (reqversion < 0x900) { archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Invalid required version"); return (ARCHIVE_FAILED); } } method = *p++; if (method < 1 || method > 3) { archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Unsupported method"); return (ARCHIVE_FAILED); } if (version >= 0x940) { unsigned level = *p++; if (method == 1 && level == 0) level = 3; if (method == 2 && level == 0) level = 1; if (method == 3 && level == 0) level = 9; if (level < 1 && level > 9) { archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, "Invalid level"); return (ARCHIVE_FAILED); } } flags = archive_be32dec(p); p += 4; if (flags & FILTER) p += 4; /* Skip filter */ p += 4; /* Skip mode */ if (version >= 0x940) p += 8; /* Skip mtime */ else p += 4; /* Skip mtime */ len = *p++; /* Read filename length */ len += p - _p; /* Make sure we have all bytes we need to calculate checksum. */ p = __archive_read_filter_ahead(self->upstream, len + 4, NULL); if (p == NULL) goto truncated; if (flags & CRC32_HEADER) checksum = crc32(crc32(0, NULL, 0), p, len); else checksum = adler32(adler32(0, NULL, 0), p, len); if (archive_be32dec(p + len) != checksum) goto corrupted; __archive_read_filter_consume(self->upstream, len + 4); if (flags & EXTRA_FIELD) { /* Skip extra field */ p = __archive_read_filter_ahead(self->upstream, 4, NULL); if (p == NULL) goto truncated; len = archive_be32dec(p); __archive_read_filter_consume(self->upstream, len + 4 + 4); } state->flags = flags; state->in_stream = 1; return (ARCHIVE_OK); truncated: archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data"); return (ARCHIVE_FAILED); corrupted: archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header"); return (ARCHIVE_FAILED); }
/* * Use select() to decide whether the child is ready for read or write. */ static ssize_t child_read(struct archive_read_filter *self, char *buf, size_t buf_len) { struct program_filter *state = self->data; ssize_t ret, requested, avail; const char *p; #if defined(_WIN32) && !defined(__CYGWIN__) HANDLE handle = (HANDLE)_get_osfhandle(state->child_stdout); #endif requested = buf_len > SSIZE_MAX ? SSIZE_MAX : buf_len; for (;;) { do { #if defined(_WIN32) && !defined(__CYGWIN__) /* Avoid infinity wait. * Note: If there is no data in the pipe, ReadFile() * called in read() never returns and so we won't * write remaining encoded data to the pipe. * Note: This way may cause performance problem. * we are looking forward to great code to resolve * this. */ DWORD pipe_avail = -1; int cnt = 2; while (PeekNamedPipe(handle, NULL, 0, NULL, &pipe_avail, NULL) != 0 && pipe_avail == 0 && cnt--) Sleep(5); if (pipe_avail == 0) { ret = -1; errno = EAGAIN; break; } #endif ret = read(state->child_stdout, buf, requested); } while (ret == -1 && errno == EINTR); if (ret > 0) return (ret); if (ret == 0 || (ret == -1 && errno == EPIPE)) /* Child has closed its output; reap the child * and return the status. */ return (child_stop(self, state)); if (ret == -1 && errno != EAGAIN) return (-1); if (state->child_stdin == -1) { /* Block until child has some I/O ready. */ __archive_check_child(state->child_stdin, state->child_stdout); continue; } /* Get some more data from upstream. */ p = __archive_read_filter_ahead(self->upstream, 1, &avail); if (p == NULL) { close(state->child_stdin); state->child_stdin = -1; fcntl(state->child_stdout, F_SETFL, 0); if (avail < 0) return (avail); continue; } do { ret = write(state->child_stdin, p, avail); } while (ret == -1 && errno == EINTR); if (ret > 0) { /* Consume whatever we managed to write. */ __archive_read_filter_consume(self->upstream, ret); } else if (ret == -1 && errno == EAGAIN) { /* Block until child has some I/O ready. */ __archive_check_child(state->child_stdin, state->child_stdout); } else { /* Write failed. */ close(state->child_stdin); state->child_stdin = -1; fcntl(state->child_stdout, F_SETFL, 0); /* If it was a bad error, we're done; otherwise * it was EPIPE or EOF, and we can still read * from the child. */ if (ret == -1 && errno != EPIPE) return (-1); } } }
static ssize_t rpm_filter_read(struct archive_read_filter *self, const void **buff) { struct rpm *rpm; const unsigned char *b; ssize_t avail_in, total; size_t used, n; uint32_t section; uint32_t bytes; rpm = (struct rpm *)self->data; *buff = NULL; total = avail_in = 0; b = NULL; used = 0; do { if (b == NULL) { b = __archive_read_filter_ahead(self->upstream, 1, &avail_in); if (b == NULL) { if (avail_in < 0) return (ARCHIVE_FATAL); else break; } } switch (rpm->state) { case ST_LEAD: if (rpm->total_in + avail_in < RPM_LEAD_SIZE) used += avail_in; else { n = (size_t)(RPM_LEAD_SIZE - rpm->total_in); used += n; b += n; rpm->state = ST_HEADER; rpm->hpos = 0; rpm->hlen = 0; rpm->first_header = 1; } break; case ST_HEADER: n = 16 - rpm->hpos; if (n > avail_in - used) n = avail_in - used; memcpy(rpm->header+rpm->hpos, b, n); b += n; used += n; rpm->hpos += n; if (rpm->hpos == 16) { if (rpm->header[0] != 0x8e || rpm->header[1] != 0xad || rpm->header[2] != 0xe8 || rpm->header[3] != 0x01) { if (rpm->first_header) { archive_set_error( &self->archive->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Unrecoginized rpm header"); return (ARCHIVE_FATAL); } rpm->state = ST_ARCHIVE; *buff = rpm->header; total = rpm->hpos; break; } /* Calculate 'Header' length. */ section = archive_be32dec(rpm->header+8); bytes = archive_be32dec(rpm->header+12); rpm->hlen = 16 + section * 16 + bytes; rpm->state = ST_HEADER_DATA; rpm->first_header = 0; } break; case ST_HEADER_DATA: n = rpm->hlen - rpm->hpos; if (n > avail_in - used) n = avail_in - used; b += n; used += n; rpm->hpos += n; if (rpm->hpos == rpm->hlen) rpm->state = ST_PADDING; break; case ST_PADDING: while (used < (size_t)avail_in) { if (*b != 0) { /* Read next header. */ rpm->state = ST_HEADER; rpm->hpos = 0; rpm->hlen = 0; break; } b++; used++; } break; case ST_ARCHIVE: *buff = b; total = avail_in; used = avail_in; break; } if (used == (size_t)avail_in) { rpm->total_in += used; __archive_read_filter_consume(self->upstream, used); b = NULL; used = 0; } } while (total == 0 && avail_in > 0); if (used > 0 && b != NULL) { rpm->total_in += used; __archive_read_filter_consume(self->upstream, used); } return (total); }