static int choose_filters(struct archive_read *a) { int number_bidders, i, bid, best_bid, number_filters; struct archive_read_filter_bidder *bidder, *best_bidder; struct archive_read_filter *filter; ssize_t avail; int r; for (number_filters = 0; number_filters < MAX_NUMBER_FILTERS; ++number_filters) { number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]); best_bid = 0; best_bidder = NULL; bidder = a->bidders; for (i = 0; i < number_bidders; i++, bidder++) { if (bidder->bid != NULL) { bid = (bidder->bid)(bidder, a->filter); if (bid > best_bid) { best_bid = bid; best_bidder = bidder; } } } /* If no bidder, we're done. */ if (best_bidder == NULL) { /* Verify the filter by asking it for some data. */ __archive_read_filter_ahead(a->filter, 1, &avail); if (avail < 0) { __archive_read_free_filters(a); return (ARCHIVE_FATAL); } a->archive.compression_name = a->filter->name; a->archive.compression_code = a->filter->code; return (ARCHIVE_OK); } filter = (struct archive_read_filter *)calloc(1, sizeof(*filter)); if (filter == NULL) return (ARCHIVE_FATAL); filter->bidder = best_bidder; filter->archive = a; filter->upstream = a->filter; a->filter = filter; r = (best_bidder->init)(a->filter); if (r != ARCHIVE_OK) { __archive_read_free_filters(a); return (ARCHIVE_FATAL); } } archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Input requires too many filters for decoding"); return (ARCHIVE_FATAL); }
/* * Allow each registered stream transform to bid on whether * it wants to handle this stream. Repeat until we've finished * building the pipeline. */ static int choose_filters(struct archive_read *a) { int number_bidders, i, bid, best_bid; struct archive_read_filter_bidder *bidder, *best_bidder; struct archive_read_filter *filter; ssize_t avail; int r; for (;;) { number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]); best_bid = 0; best_bidder = NULL; bidder = a->bidders; for (i = 0; i < number_bidders; i++, bidder++) { if (bidder->bid != NULL) { bid = (bidder->bid)(bidder, a->filter); if (bid > best_bid) { best_bid = bid; best_bidder = bidder; } } } /* If no bidder, we're done. */ if (best_bidder == NULL) { /* Verify the filter by asking it for some data. */ __archive_read_filter_ahead(a->filter, 1, &avail); if (avail < 0) { __archive_read_close_filters(a); __archive_read_free_filters(a); return (ARCHIVE_FATAL); } a->archive.compression_name = a->filter->name; a->archive.compression_code = a->filter->code; return (ARCHIVE_OK); } filter = (struct archive_read_filter *)calloc(1, sizeof(*filter)); if (filter == NULL) return (ARCHIVE_FATAL); filter->bidder = best_bidder; filter->archive = a; filter->upstream = a->filter; a->filter = filter; r = (best_bidder->init)(a->filter); if (r != ARCHIVE_OK) { __archive_read_close_filters(a); __archive_read_free_filters(a); return (ARCHIVE_FATAL); } } }
int archive_read_append_filter_program_signature(struct archive *_a, const char *cmd, const void *signature, size_t signature_len) { int r, number_bidders, i; struct archive_read_filter_bidder *bidder; struct archive_read_filter *filter; struct archive_read *a = (struct archive_read *)_a; if (archive_read_support_filter_program_signature(_a, cmd, signature, signature_len) != (ARCHIVE_OK)) return (ARCHIVE_FATAL); number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]); bidder = a->bidders; for (i = 0; i < number_bidders; i++, bidder++) { /* Program bidder name set to filter name after initialization */ if (bidder->data && !bidder->name) break; } if (!bidder->data) { archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, "Internal error: Unable to append program filter"); return (ARCHIVE_FATAL); } filter = (struct archive_read_filter *)calloc(1, sizeof(*filter)); if (filter == NULL) { archive_set_error(&a->archive, ENOMEM, "Out of memory"); return (ARCHIVE_FATAL); } filter->bidder = bidder; filter->archive = a; filter->upstream = a->filter; a->filter = filter; r = (bidder->init)(a->filter); if (r != ARCHIVE_OK) { __archive_read_close_filters(a); __archive_read_free_filters(a); return (ARCHIVE_FATAL); } bidder->name = a->filter->name; a->bypass_filter_bidding = 1; return r; }
/* * Release memory and other resources. */ static int _archive_read_free(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; int i, n; int slots; int r = ARCHIVE_OK; if (_a == NULL) return (ARCHIVE_OK); archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_free"); if (a->archive.state != ARCHIVE_STATE_CLOSED && a->archive.state != ARCHIVE_STATE_FATAL) r = archive_read_close(&a->archive); /* Call cleanup functions registered by optional components. */ if (a->cleanup_archive_extract != NULL) r = (a->cleanup_archive_extract)(a); /* Cleanup format-specific data. */ slots = sizeof(a->formats) / sizeof(a->formats[0]); for (i = 0; i < slots; i++) { a->format = &(a->formats[i]); if (a->formats[i].cleanup) (a->formats[i].cleanup)(a); } /* Free the filters */ __archive_read_free_filters(a); /* Release the bidder objects. */ n = sizeof(a->bidders)/sizeof(a->bidders[0]); for (i = 0; i < n; i++) { if (a->bidders[i].free != NULL) { int r1 = (a->bidders[i].free)(&a->bidders[i]); if (r1 < r) r = r1; } } archive_string_free(&a->archive.error_string); if (a->entry) archive_entry_free(a->entry); a->archive.magic = 0; __archive_clean(&a->archive); free(a->client.dataset); free(a); return (r); }
int archive_read_append_filter(struct archive *_a, int code) { int r1, r2, number_bidders, i; char str[20]; struct archive_read_filter_bidder *bidder; struct archive_read_filter *filter; struct archive_read *a = (struct archive_read *)_a; r1 = r2 = (ARCHIVE_OK); switch (code) { case ARCHIVE_FILTER_NONE: /* No filter to add, so do nothing. * NOTE: An initial "NONE" type filter is always set at the end of the * filter chain. */ r1 = (ARCHIVE_OK); break; case ARCHIVE_FILTER_GZIP: strcpy(str, "gzip"); r1 = archive_read_support_filter_gzip(_a); break; case ARCHIVE_FILTER_BZIP2: strcpy(str, "bzip2"); r1 = archive_read_support_filter_bzip2(_a); break; case ARCHIVE_FILTER_COMPRESS: strcpy(str, "compress (.Z)"); r1 = archive_read_support_filter_compress(_a); break; case ARCHIVE_FILTER_PROGRAM: archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, "Cannot append program filter using archive_read_append_filter"); return (ARCHIVE_FATAL); case ARCHIVE_FILTER_LZMA: strcpy(str, "lzma"); r1 = archive_read_support_filter_lzma(_a); break; case ARCHIVE_FILTER_XZ: strcpy(str, "xz"); r1 = archive_read_support_filter_xz(_a); break; case ARCHIVE_FILTER_UU: strcpy(str, "uu"); r1 = archive_read_support_filter_uu(_a); break; case ARCHIVE_FILTER_RPM: strcpy(str, "rpm"); r1 = archive_read_support_filter_rpm(_a); break; case ARCHIVE_FILTER_LZIP: strcpy(str, "lzip"); r1 = archive_read_support_filter_lzip(_a); break; case ARCHIVE_FILTER_LRZIP: strcpy(str, "lrzip"); r1 = archive_read_support_filter_lrzip(_a); break; default: archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, "Invalid filter code specified"); return (ARCHIVE_FATAL); } if (code != ARCHIVE_FILTER_NONE) { number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]); bidder = a->bidders; for (i = 0; i < number_bidders; i++, bidder++) { if (!bidder->name || !strcmp(bidder->name, str)) break; } if (!bidder->name || strcmp(bidder->name, str)) { archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, "Internal error: Unable to append filter"); return (ARCHIVE_FATAL); } filter = (struct archive_read_filter *)calloc(1, sizeof(*filter)); if (filter == NULL) { archive_set_error(&a->archive, ENOMEM, "Out of memory"); return (ARCHIVE_FATAL); } filter->bidder = bidder; filter->archive = a; filter->upstream = a->filter; a->filter = filter; r2 = (bidder->init)(a->filter); if (r2 != ARCHIVE_OK) { __archive_read_close_filters(a); __archive_read_free_filters(a); return (ARCHIVE_FATAL); } } a->bypass_filter_bidding = 1; return (r1 < r2) ? r1 : r2; }