a->format = &(a->formats[0]);
for (i = 0; i < slots; i++, a->format++) {
if (a->format->bid) {
- bid = (a->format->bid)(a);
+ bid = (a->format->bid)(a, best_bid);
if (bid == ARCHIVE_FATAL)
return (ARCHIVE_FATAL);
if (a->filter->position != 0)
__archive_read_register_format(struct archive_read *a,
void *format_data,
const char *name,
- int (*bid)(struct archive_read *),
+ int (*bid)(struct archive_read *, int),
int (*options)(struct archive_read *, const char *, const char *),
int (*read_header)(struct archive_read *, struct archive_entry *),
int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *),
struct archive_format_descriptor {
void *data;
const char *name;
- int (*bid)(struct archive_read *);
+ int (*bid)(struct archive_read *, int best_bid);
int (*options)(struct archive_read *, const char *key,
const char *value);
int (*read_header)(struct archive_read *, struct archive_entry *);
int __archive_read_register_format(struct archive_read *a,
void *format_data,
const char *name,
- int (*bid)(struct archive_read *),
+ int (*bid)(struct archive_read *, int),
int (*options)(struct archive_read *, const char *, const char *),
int (*read_header)(struct archive_read *, struct archive_entry *),
int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *),
archive_check_magic(a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_format_all");
+ /* TODO: It would be nice to compute the ordering
+ * here automatically so that people who enable just
+ * a few formats can still get the benefits. That
+ * may just require the format registration to include
+ * a "maximum read-ahead" value (anything that uses seek
+ * would be essentially infinite read-ahead). The core
+ * bid management can then sort the bidders before calling
+ * them.
+ *
+ * If you implement the above, please return the list below
+ * to alphabetic order.
+ */
+
+ /*
+ * These bidders are all pretty cheap; they just examine a
+ * small initial part of the archive. If one of these bids
+ * high, we can maybe avoid running any of the more expensive
+ * bidders below.
+ */
archive_read_support_format_ar(a);
- archive_read_support_format_cab(a);
archive_read_support_format_cpio(a);
archive_read_support_format_empty(a);
- archive_read_support_format_iso9660(a);
archive_read_support_format_lha(a);
archive_read_support_format_mtree(a);
- archive_read_support_format_rar(a);
archive_read_support_format_tar(a);
archive_read_support_format_xar(a);
+
+ /*
+ * Install expensive bidders last. By doing them last, we
+ * increase the chance that a high bid from someone else will
+ * make it unnecessary for these to do anything at all.
+ */
+ /* These three have potentially large look-ahead. */
+ archive_read_support_format_cab(a);
+ archive_read_support_format_rar(a);
+ archive_read_support_format_iso9660(a);
+ /* Seek is really bad, since it forces the read-ahead
+ * logic to discard buffered data. */
archive_read_support_format_zip(a);
/* Note: We always return ARCHIVE_OK here, even if some of the
#define AR_fmag_offset 58
#define AR_fmag_size 2
-static int archive_read_format_ar_bid(struct archive_read *a);
+static int archive_read_format_ar_bid(struct archive_read *a, int);
static int archive_read_format_ar_cleanup(struct archive_read *a);
static int archive_read_format_ar_read_data(struct archive_read *a,
const void **buff, size_t *size, int64_t *offset);
}
static int
-archive_read_format_ar_bid(struct archive_read *a)
+archive_read_format_ar_bid(struct archive_read *a, int best_bid)
{
const void *h;
- if (a->archive.archive_format != 0 &&
- (a->archive.archive_format & ARCHIVE_FORMAT_BASE_MASK) !=
- ARCHIVE_FORMAT_AR)
- return(0);
+ (void)best_bid; /* UNUSED */
/*
* Verify the 8-byte file signature.
struct lzx_stream xstrm;
};
-static int archive_read_format_cab_bid(struct archive_read *);
+static int archive_read_format_cab_bid(struct archive_read *, int);
static int archive_read_format_cab_options(struct archive_read *,
const char *, const char *);
static int archive_read_format_cab_read_header(struct archive_read *,
}
static int
-archive_read_format_cab_bid(struct archive_read *a)
+archive_read_format_cab_bid(struct archive_read *a, int best_bid)
{
const char *p;
ssize_t bytes_avail, offset, window;
+ /* If there's already a better bid than we can ever
+ make, don't bother testing. */
+ if (best_bid > 64)
+ return (-1);
+
if ((p = __archive_read_ahead(a, 8, NULL)) == NULL)
return (-1);
static int64_t atol16(const char *, unsigned);
static int64_t atol8(const char *, unsigned);
-static int archive_read_format_cpio_bid(struct archive_read *);
+static int archive_read_format_cpio_bid(struct archive_read *, int);
static int archive_read_format_cpio_options(struct archive_read *,
const char *, const char *);
static int archive_read_format_cpio_cleanup(struct archive_read *);
static int
-archive_read_format_cpio_bid(struct archive_read *a)
+archive_read_format_cpio_bid(struct archive_read *a, int best_bid)
{
const unsigned char *p;
struct cpio *cpio;
int bid;
+ (void)best_bid; /* UNUSED */
+
cpio = (struct cpio *)(a->format->data);
if ((p = __archive_read_ahead(a, 6, NULL)) == NULL)
#include "archive_private.h"
#include "archive_read_private.h"
-static int archive_read_format_empty_bid(struct archive_read *);
+static int archive_read_format_empty_bid(struct archive_read *, int);
static int archive_read_format_empty_read_data(struct archive_read *,
const void **, size_t *, int64_t *);
static int archive_read_format_empty_read_header(struct archive_read *,
static int
-archive_read_format_empty_bid(struct archive_read *a)
+archive_read_format_empty_bid(struct archive_read *a, int best_bid)
{
- ssize_t avail;
-
- (void)__archive_read_ahead(a, 1, &avail);
- if (avail != 0)
- return (-1);
- return (1);
+ if (best_bid < 1 && __archive_read_ahead(a, 1, NULL) == NULL)
+ return (1);
+ return (-1);
}
static int
size_t utf16be_previous_path_len;
};
-static int archive_read_format_iso9660_bid(struct archive_read *);
+static int archive_read_format_iso9660_bid(struct archive_read *, int);
static int archive_read_format_iso9660_options(struct archive_read *,
const char *, const char *);
static int archive_read_format_iso9660_cleanup(struct archive_read *);
static int
-archive_read_format_iso9660_bid(struct archive_read *a)
+archive_read_format_iso9660_bid(struct archive_read *a, int best_bid)
{
struct iso9660 *iso9660;
ssize_t bytes_read;
const unsigned char *p;
int seenTerminator;
+ /* If there's already a better bid than we can ever
+ make, don't bother testing. */
+ if (best_bid > 48)
+ return (-1);
+
iso9660 = (struct iso9660 *)(a->format->data);
/*
0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040
};
-static int archive_read_format_lha_bid(struct archive_read *);
+static int archive_read_format_lha_bid(struct archive_read *, int);
static int archive_read_format_lha_options(struct archive_read *,
const char *, const char *);
static int archive_read_format_lha_read_header(struct archive_read *,
}
static int
-archive_read_format_lha_bid(struct archive_read *a)
+archive_read_format_lha_bid(struct archive_read *a, int best_bid)
{
const char *p;
const void *buff;
ssize_t bytes_avail, offset, window;
size_t next;
+ /* If there's already a better bid than we can ever
+ make, don't bother testing. */
+ if (best_bid > 30)
+ return (-1);
+
if ((p = __archive_read_ahead(a, H_SIZE, NULL)) == NULL)
return (-1);
};
static int cleanup(struct archive_read *);
-static int mtree_bid(struct archive_read *);
+static int mtree_bid(struct archive_read *, int);
static int parse_file(struct archive_read *, struct archive_entry *,
struct mtree *, struct mtree_entry *, int *);
static void parse_escapes(char *, struct mtree_entry *);
#define MAX_BID_ENTRY 3
static int
-mtree_bid(struct archive_read *a)
+mtree_bid(struct archive_read *a, int best_bid)
{
const char *signature = "#mtree";
const char *p;
ssize_t len, nl;
int detected_bytes = 0, entry_cnt = 0, multiline = 0;
+ (void)best_bid; /* UNUSED */
+
/* Now let's look at the actual header and see if it matches. */
p = __archive_read_ahead(a, strlen(signature), &avail);
if (p == NULL)
} br;
};
-static int archive_read_format_rar_bid(struct archive_read *);
+static int archive_read_format_rar_bid(struct archive_read *, int);
static int archive_read_format_rar_options(struct archive_read *,
const char *, const char *);
static int archive_read_format_rar_read_header(struct archive_read *,
}
static int
-archive_read_format_rar_bid(struct archive_read *a)
+archive_read_format_rar_bid(struct archive_read *a, int best_bid)
{
const char *p;
+ /* If there's already a bid > 30, we'll never win. */
+ if (best_bid > 30)
+ return (-1);
+
if ((p = __archive_read_ahead(a, 7, NULL)) == NULL)
return (-1);
int end_of_file;
};
-static int archive_read_format_raw_bid(struct archive_read *);
+static int archive_read_format_raw_bid(struct archive_read *, int);
static int archive_read_format_raw_cleanup(struct archive_read *);
static int archive_read_format_raw_read_data(struct archive_read *,
const void **, size_t *, int64_t *);
* include "raw" as part of support_format_all().
*/
static int
-archive_read_format_raw_bid(struct archive_read *a)
+archive_read_format_raw_bid(struct archive_read *a, int best_bid)
{
-
- if (__archive_read_ahead(a, 1, NULL) == NULL)
- return (-1);
- return (1);
+ if (best_bid < 1 && __archive_read_ahead(a, 1, NULL) != NULL)
+ return (1);
+ return (-1);
}
/*
struct archive_entry *, const void *h);
static int header_gnutar(struct archive_read *, struct tar *,
struct archive_entry *, const void *h, size_t *);
-static int archive_read_format_tar_bid(struct archive_read *);
+static int archive_read_format_tar_bid(struct archive_read *, int);
static int archive_read_format_tar_options(struct archive_read *,
const char *, const char *);
static int archive_read_format_tar_cleanup(struct archive_read *);
static int
-archive_read_format_tar_bid(struct archive_read *a)
+archive_read_format_tar_bid(struct archive_read *a, int best_bid)
{
int bid;
const char *h;
const struct archive_entry_header_ustar *header;
+ (void)best_bid; /* UNUSED */
+
bid = 0;
/* Now let's look at the actual header and see if it matches. */
/* Old-style or GNU tar: we must ignore the size. */
archive_entry_set_size(entry, 0);
tar->entry_bytes_remaining = 0;
- } else if (archive_read_format_tar_bid(a) > 50) {
+ } else if (archive_read_format_tar_bid(a, 50) > 50) {
/*
* We don't know if it's pax: If the bid
* function sees a valid ustar header
struct xmlattr **last;
};
-static int xar_bid(struct archive_read *);
+static int xar_bid(struct archive_read *, int);
static int xar_read_header(struct archive_read *,
struct archive_entry *);
static int xar_read_data(struct archive_read *,
}
static int
-xar_bid(struct archive_read *a)
+xar_bid(struct archive_read *a, int best_bid)
{
const unsigned char *b;
int bid;
+ (void)best_bid; /* UNUSED */
+
b = __archive_read_ahead(a, HEADER_SIZE, NULL);
if (b == NULL)
return (-1);
#define ZIP_LENGTH_AT_END 8
#define ZIP_UTF8_NAME (1<<11)
-static int archive_read_format_zip_streamable_bid(struct archive_read *);
-static int archive_read_format_zip_seekable_bid(struct archive_read *);
+static int archive_read_format_zip_streamable_bid(struct archive_read *, int);
+static int archive_read_format_zip_seekable_bid(struct archive_read *, int);
static int archive_read_format_zip_options(struct archive_read *,
const char *, const char *);
static int archive_read_format_zip_cleanup(struct archive_read *);
* seeking if it knows it's going to lose anyway.
*/
static int
-archive_read_format_zip_seekable_bid(struct archive_read *a)
+archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid)
{
struct zip *zip = (struct zip *)a->format->data;
int64_t filesize;
const char *p;
+ /* If someone has already bid more than 32, then avoid
+ trashing the look-ahead buffers with a seek. */
+ if (best_bid > 32)
+ return (-1);
+
filesize = __archive_read_seek(a, -22, SEEK_END);
/* If we can't seek, then we can't bid. */
if (filesize <= 0)
}
static int
-archive_read_format_zip_streamable_bid(struct archive_read *a)
+archive_read_format_zip_streamable_bid(struct archive_read *a, int best_bid)
{
const char *p;
+ (void)best_bid; /* UNUSED */
+
if ((p = __archive_read_ahead(a, 4, NULL)) == NULL)
return (-1);