Skip to content

Commit

Permalink
Implement functions to manually set the format and filters used.
Browse files Browse the repository at this point in the history
  • Loading branch information
amejia1 committed Dec 7, 2012
1 parent 5fbef6a commit 82b5d8d
Show file tree
Hide file tree
Showing 14 changed files with 507 additions and 15 deletions.
1 change: 1 addition & 0 deletions Makefile.am
Expand Up @@ -409,6 +409,7 @@ libarchive_test_SOURCES= \
libarchive/test/test_read_large.c \ libarchive/test/test_read_large.c \
libarchive/test/test_read_pax_truncated.c \ libarchive/test/test_read_pax_truncated.c \
libarchive/test/test_read_position.c \ libarchive/test/test_read_position.c \
libarchive/test/test_read_set_format.c \
libarchive/test/test_read_truncated.c \ libarchive/test/test_read_truncated.c \
libarchive/test/test_read_truncated_filter.c \ libarchive/test/test_read_truncated_filter.c \
libarchive/test/test_sparse_basic.c \ libarchive/test/test_sparse_basic.c \
Expand Down
11 changes: 11 additions & 0 deletions libarchive/archive.h
Expand Up @@ -372,6 +372,17 @@ __LA_DECL int archive_read_support_format_tar(struct archive *);
__LA_DECL int archive_read_support_format_xar(struct archive *); __LA_DECL int archive_read_support_format_xar(struct archive *);
__LA_DECL int archive_read_support_format_zip(struct archive *); __LA_DECL int archive_read_support_format_zip(struct archive *);


/* Functions to manually set the format and filters to be used. This is
* useful to bypass the bidding process when the format and filters to use
* is known in advance.
*/
__LA_DECL int archive_read_set_format(struct archive *, int);
__LA_DECL int archive_read_append_filter(struct archive *, int);
__LA_DECL int archive_read_append_filter_program(struct archive *,
const char *);
__LA_DECL int archive_read_append_filter_program_signature
(struct archive *, const char *, const void * /* match */, size_t);

/* Set various callbacks. */ /* Set various callbacks. */
__LA_DECL int archive_read_set_open_callback(struct archive *, __LA_DECL int archive_read_set_open_callback(struct archive *,
archive_open_callback *); archive_open_callback *);
Expand Down
275 changes: 260 additions & 15 deletions libarchive/archive_read.c
Expand Up @@ -455,7 +455,7 @@ int
archive_read_open1(struct archive *_a) archive_read_open1(struct archive *_a)
{ {
struct archive_read *a = (struct archive_read *)_a; struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter *filter; struct archive_read_filter *filter, *tmp;
int slot, e; int slot, e;
unsigned int i; unsigned int i;


Expand Down Expand Up @@ -499,25 +499,37 @@ archive_read_open1(struct archive *_a)
filter->sswitch = client_switch_proxy; filter->sswitch = client_switch_proxy;
filter->name = "none"; filter->name = "none";
filter->code = ARCHIVE_FILTER_NONE; filter->code = ARCHIVE_FILTER_NONE;
a->filter = filter;


client_switch_proxy(a->filter, 0);
a->client.dataset[0].begin_position = 0; a->client.dataset[0].begin_position = 0;

if (!a->filter || !a->bypass_filter_bidding)
/* Build out the input pipeline. */ {
e = choose_filters(a); a->filter = filter;
if (e < ARCHIVE_WARN) { /* Build out the input pipeline. */
a->archive.state = ARCHIVE_STATE_FATAL; e = choose_filters(a);
return (ARCHIVE_FATAL); if (e < ARCHIVE_WARN) {
a->archive.state = ARCHIVE_STATE_FATAL;
return (ARCHIVE_FATAL);
}
}
else
{
/* Need to add "NONE" type filter at the end of the filter chain */
tmp = a->filter;
while (tmp->upstream)
tmp = tmp->upstream;
tmp->upstream = filter;
} }


slot = choose_format(a); if (!a->format)
if (slot < 0) { {
close_filters(a); slot = choose_format(a);
a->archive.state = ARCHIVE_STATE_FATAL; if (slot < 0) {
return (ARCHIVE_FATAL); close_filters(a);
a->archive.state = ARCHIVE_STATE_FATAL;
return (ARCHIVE_FATAL);
}
a->format = &(a->formats[slot]);
} }
a->format = &(a->formats[slot]);


a->archive.state = ARCHIVE_STATE_HEADER; a->archive.state = ARCHIVE_STATE_HEADER;


Expand Down Expand Up @@ -1622,3 +1634,236 @@ __archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,
} }
return r; return r;
} }

int
archive_read_set_format(struct archive *_a, int code)
{
int r1, r2, slots, i;
char str[10];
struct archive_read *a = (struct archive_read *)_a;

if ((r1 = archive_read_support_format_by_code(_a, code)) < (ARCHIVE_OK))
return r1;

r1 = r2 = (ARCHIVE_OK);
if (a->format)
r2 = (ARCHIVE_WARN);
switch (code & ARCHIVE_FORMAT_BASE_MASK)
{
case ARCHIVE_FORMAT_7ZIP:
strcpy(str, "7zip");
break;
case ARCHIVE_FORMAT_AR:
strcpy(str, "ar");
break;
case ARCHIVE_FORMAT_CAB:
strcpy(str, "cab");
break;
case ARCHIVE_FORMAT_CPIO:
strcpy(str, "cpio");
break;
case ARCHIVE_FORMAT_ISO9660:
strcpy(str, "iso9660");
break;
case ARCHIVE_FORMAT_LHA:
strcpy(str, "lha");
break;
case ARCHIVE_FORMAT_MTREE:
strcpy(str, "mtree");
break;
case ARCHIVE_FORMAT_RAR:
strcpy(str, "rar");
break;
case ARCHIVE_FORMAT_TAR:
strcpy(str, "tar");
break;
case ARCHIVE_FORMAT_XAR:
strcpy(str, "xar");
break;
case ARCHIVE_FORMAT_ZIP:
strcpy(str, "zip");
break;
default:
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Invalid format code specified");
return (ARCHIVE_FATAL);
}

slots = sizeof(a->formats) / sizeof(a->formats[0]);
a->format = &(a->formats[0]);
for (i = 0; i < slots; i++, a->format++) {
if (!a->format->name || !strcmp(a->format->name, str))
break;
}
if (!a->format->name || strcmp(a->format->name, str))
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Internal error: Unable to set format");
r1 = (ARCHIVE_FATAL);
}

return (r1 < r2) ? r1 : r2;
}

int
archive_read_append_filter(struct archive *_a, int code)
{
int r1, r2, number_bidders, i;
char str[10];
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) {
close_filters(a);
free_filters(a);
return (ARCHIVE_FATAL);
}
}

a->bypass_filter_bidding = 1;
return (r1 < r2) ? r1 : r2;
}

int
archive_read_append_filter_program(struct archive *_a, const char *cmd)
{
return (archive_read_append_filter_program_signature(_a, cmd, NULL, 0));
}

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) {
close_filters(a);
free_filters(a);
return (ARCHIVE_FATAL);
}
bidder->name = a->filter->name;

a->bypass_filter_bidding = 1;
return r;
}
5 changes: 5 additions & 0 deletions libarchive/archive_read_private.h
Expand Up @@ -58,6 +58,8 @@ struct archive_read_filter;
struct archive_read_filter_bidder { struct archive_read_filter_bidder {
/* Configuration data for the bidder. */ /* Configuration data for the bidder. */
void *data; void *data;
/* Name of the filter */
const char *name;
/* Taste the upstream filter to see if we handle this. */ /* Taste the upstream filter to see if we handle this. */
int (*bid)(struct archive_read_filter_bidder *, int (*bid)(struct archive_read_filter_bidder *,
struct archive_read_filter *); struct archive_read_filter *);
Expand Down Expand Up @@ -168,6 +170,9 @@ struct archive_read {
/* Last filter in chain */ /* Last filter in chain */
struct archive_read_filter *filter; struct archive_read_filter *filter;


/* Whether to bypass filter bidding process */
int bypass_filter_bidding;

/* File offset of beginning of most recently-read header. */ /* File offset of beginning of most recently-read header. */
int64_t header_position; int64_t header_position;


Expand Down
1 change: 1 addition & 0 deletions libarchive/archive_read_support_filter_bzip2.c
Expand Up @@ -94,6 +94,7 @@ archive_read_support_filter_bzip2(struct archive *_a)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);


reader->data = NULL; reader->data = NULL;
reader->name = "bzip2";
reader->bid = bzip2_reader_bid; reader->bid = bzip2_reader_bid;
reader->init = bzip2_reader_init; reader->init = bzip2_reader_init;
reader->options = NULL; reader->options = NULL;
Expand Down
1 change: 1 addition & 0 deletions libarchive/archive_read_support_filter_compress.c
Expand Up @@ -163,6 +163,7 @@ archive_read_support_filter_compress(struct archive *_a)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);


bidder->data = NULL; bidder->data = NULL;
bidder->name = "compress (.Z)";
bidder->bid = compress_bidder_bid; bidder->bid = compress_bidder_bid;
bidder->init = compress_bidder_init; bidder->init = compress_bidder_init;
bidder->options = NULL; bidder->options = NULL;
Expand Down
1 change: 1 addition & 0 deletions libarchive/archive_read_support_filter_gzip.c
Expand Up @@ -100,6 +100,7 @@ archive_read_support_filter_gzip(struct archive *_a)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);


bidder->data = NULL; bidder->data = NULL;
bidder->name = "gzip";
bidder->bid = gzip_bidder_bid; bidder->bid = gzip_bidder_bid;
bidder->init = gzip_bidder_init; bidder->init = gzip_bidder_init;
bidder->options = NULL; bidder->options = NULL;
Expand Down
1 change: 1 addition & 0 deletions libarchive/archive_read_support_filter_lrzip.c
Expand Up @@ -73,6 +73,7 @@ archive_read_support_filter_lrzip(struct archive *_a)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);


reader->data = NULL; reader->data = NULL;
reader->name = "lrzip";
reader->bid = lrzip_bidder_bid; reader->bid = lrzip_bidder_bid;
reader->init = lrzip_bidder_init; reader->init = lrzip_bidder_init;
reader->options = NULL; reader->options = NULL;
Expand Down
1 change: 1 addition & 0 deletions libarchive/archive_read_support_filter_program.c
Expand Up @@ -88,6 +88,7 @@ archive_read_support_filter_program(struct archive *a, const char *cmd)
* bid twice in the same pipeline. * bid twice in the same pipeline.
*/ */
struct program_bidder { struct program_bidder {
char *description;
char *cmd; char *cmd;
void *signature; void *signature;
size_t signature_len; size_t signature_len;
Expand Down
1 change: 1 addition & 0 deletions libarchive/archive_read_support_filter_rpm.c
Expand Up @@ -85,6 +85,7 @@ archive_read_support_filter_rpm(struct archive *_a)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);


bidder->data = NULL; bidder->data = NULL;
bidder->name = "rpm";
bidder->bid = rpm_bidder_bid; bidder->bid = rpm_bidder_bid;
bidder->init = rpm_bidder_init; bidder->init = rpm_bidder_init;
bidder->options = NULL; bidder->options = NULL;
Expand Down
1 change: 1 addition & 0 deletions libarchive/archive_read_support_filter_uu.c
Expand Up @@ -89,6 +89,7 @@ archive_read_support_filter_uu(struct archive *_a)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);


bidder->data = NULL; bidder->data = NULL;
bidder->name = "uu";
bidder->bid = uudecode_bidder_bid; bidder->bid = uudecode_bidder_bid;
bidder->init = uudecode_bidder_init; bidder->init = uudecode_bidder_init;
bidder->options = NULL; bidder->options = NULL;
Expand Down

0 comments on commit 82b5d8d

Please sign in to comment.