Merge r491,493,500,507,510,530,543 from libarchive.googlecode.com:

This implements the new generic options framework that provides a way
to override format- and compression-specific parameters.
This commit is contained in:
Tim Kientzle 2009-03-06 05:58:56 +00:00
parent ce54c7c56a
commit 634fb9dd48
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=189438
26 changed files with 508 additions and 5 deletions

View File

@ -384,6 +384,19 @@ __LA_DECL int archive_read_data_into_buffer(struct archive *,
void *buffer, __LA_SSIZE_T len);
__LA_DECL int archive_read_data_into_fd(struct archive *, int fd);
/*
* Set read options.
*/
/* Apply option string to the format only. */
__LA_DECL int archive_read_set_format_options(struct archive *_a,
const char *s);
/* Apply option string to the filter only. */
__LA_DECL int archive_read_set_filter_options(struct archive *_a,
const char *s);
/* Apply option string to both the format and the filter. */
__LA_DECL int archive_read_set_options(struct archive *_a,
const char *s);
/*-
* Convenience function to recreate the current entry (whose header
* has just been read) on disk.
@ -552,6 +565,20 @@ __LA_DECL void archive_write_finish(struct archive *);
__LA_DECL int archive_write_finish(struct archive *);
#endif
/*
* Set write options.
*/
/* Apply option string to the format only. */
__LA_DECL int archive_write_set_format_options(struct archive *_a,
const char *s);
/* Apply option string to the compressor only. */
__LA_DECL int archive_write_set_compressor_options(struct archive *_a,
const char *s);
/* Apply option string to both the format and the compressor. */
__LA_DECL int archive_write_set_options(struct archive *_a,
const char *s);
/*-
* To create objects on disk:
* 1) Ask archive_write_disk_new for a new archive_write_disk object.

View File

@ -102,6 +102,9 @@ void __archive_check_magic(struct archive *, unsigned int magic,
void __archive_errx(int retvalue, const char *msg) __LA_DEAD;
int __archive_parse_options(const char *p, const char *fn,
int keysize, char *key, int valsize, char *val);
#define err_combine(a,b) ((a) < (b) ? (a) : (b))
#endif

View File

@ -108,6 +108,95 @@ archive_read_extract_set_skip_file(struct archive *_a, dev_t d, ino_t i)
a->skip_file_ino = i;
}
/*
* Set read options for the format.
*/
int
archive_read_set_format_options(struct archive *_a, const char *s)
{
struct archive_read *a;
char key[64], val[64];
int len, r;
a = (struct archive_read *)_a;
if (a->format == NULL || a->format->options == NULL ||
a->format->name == NULL)
/* This format does not support option. */
return (ARCHIVE_OK);
while ((len = __archive_parse_options(s, a->format->name,
sizeof(key), key, sizeof(val), val)) > 0) {
if (val[0] == '\0')
r = a->format->options(a, key, NULL);
else
r = a->format->options(a, key, val);
if (r == ARCHIVE_FATAL)
return (r);
s += len;
}
if (len < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Illegal format options.");
return (ARCHIVE_WARN);
}
return (ARCHIVE_OK);
}
/*
* Set read options for the filter.
*/
int
archive_read_set_filter_options(struct archive *_a, const char *s)
{
struct archive_read *a;
struct archive_read_filter *filter;
struct archive_read_filter_bidder *bidder;
char key[64], val[64];
int len, r;
a = (struct archive_read *)_a;
filter = a->filter;
len = 0;
for (filter = a->filter; filter != NULL; filter = filter->upstream) {
bidder = filter->bidder;
if (bidder->options == NULL)
/* This bidder does not support option */
continue;
while ((len = __archive_parse_options(s, filter->name,
sizeof(key), key, sizeof(val), val)) > 0) {
if (val[0] == '\0')
r = bidder->options(bidder, key, NULL);
else
r = bidder->options(bidder, key, val);
if (r == ARCHIVE_FATAL)
return (r);
s += len;
}
}
if (len < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Illegal format options.");
return (ARCHIVE_WARN);
}
return (ARCHIVE_OK);
}
/*
* Set read options for the format and the filter.
*/
int
archive_read_set_options(struct archive *_a, const char *s)
{
int r;
r = archive_read_set_format_options(_a, s);
if (r != ARCHIVE_OK)
return (r);
r = archive_read_set_filter_options(_a, s);
if (r != ARCHIVE_OK)
return (r);
return (ARCHIVE_OK);
}
/*
* Open the archive
@ -658,7 +747,9 @@ _archive_read_finish(struct archive *_a)
int
__archive_read_register_format(struct archive_read *a,
void *format_data,
const char *name,
int (*bid)(struct archive_read *),
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 *, off_t *),
int (*read_data_skip)(struct archive_read *),
@ -677,11 +768,13 @@ __archive_read_register_format(struct archive_read *a,
return (ARCHIVE_WARN); /* We've already installed */
if (a->formats[i].bid == NULL) {
a->formats[i].bid = bid;
a->formats[i].options = options;
a->formats[i].read_header = read_header;
a->formats[i].read_data = read_data;
a->formats[i].read_data_skip = read_data_skip;
a->formats[i].cleanup = cleanup;
a->formats[i].data = format_data;
a->formats[i].name = name;
return (ARCHIVE_OK);
}
}

View File

@ -54,6 +54,9 @@ struct archive_read_filter_bidder {
struct archive_read_filter *);
/* Initialize a newly-created filter. */
int (*init)(struct archive_read_filter *);
/* Set an option for the filter bidder. */
int (*options)(struct archive_read_filter_bidder *,
const char *key, const char *value);
/* Release the bidder's configuration data. */
int (*free)(struct archive_read_filter_bidder *);
};
@ -149,7 +152,10 @@ struct archive_read {
struct archive_format_descriptor {
void *data;
const char *name;
int (*bid)(struct archive_read *);
int (*options)(struct archive_read *, const char *key,
const char *value);
int (*read_header)(struct archive_read *, struct archive_entry *);
int (*read_data)(struct archive_read *, const void **, size_t *, off_t *);
int (*read_data_skip)(struct archive_read *);
@ -166,7 +172,9 @@ struct archive_read {
int __archive_read_register_format(struct archive_read *a,
void *format_data,
const char *name,
int (*bid)(struct archive_read *),
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 *, off_t *),
int (*read_data_skip)(struct archive_read *),

View File

@ -84,6 +84,7 @@ archive_read_support_compression_bzip2(struct archive *_a)
reader->data = NULL;
reader->bid = bzip2_reader_bid;
reader->init = bzip2_reader_init;
reader->options = NULL;
reader->free = bzip2_reader_free;
return (ARCHIVE_OK);
}

View File

@ -152,6 +152,7 @@ archive_read_support_compression_compress(struct archive *_a)
bidder->data = NULL;
bidder->bid = compress_bidder_bid;
bidder->init = compress_bidder_init;
bidder->options = NULL;
bidder->free = compress_bidder_free;
return (ARCHIVE_OK);
}

View File

@ -90,7 +90,8 @@ archive_read_support_compression_gzip(struct archive *_a)
bidder->data = NULL;
bidder->bid = gzip_bidder_bid;
bidder->init = gzip_bidder_init;
bidder->free = NULL; /* No data, so no cleanup necessary. */
bidder->options = NULL;
bidder->free = NULL;
return (ARCHIVE_OK);
}

View File

@ -122,6 +122,7 @@ archive_read_support_compression_program(struct archive *_a, const char *cmd)
bidder->data = state;
bidder->bid = program_bidder_bid;
bidder->init = program_bidder_init;
bidder->options = NULL;
bidder->free = program_bidder_free;
return (ARCHIVE_OK);
}

View File

@ -105,7 +105,9 @@ archive_read_support_format_ar(struct archive *_a)
r = __archive_read_register_format(a,
ar,
"ar",
archive_read_format_ar_bid,
NULL,
archive_read_format_ar_read_header,
archive_read_format_ar_read_data,
archive_read_format_ar_skip,

View File

@ -150,7 +150,9 @@ archive_read_support_format_cpio(struct archive *_a)
r = __archive_read_register_format(a,
cpio,
"cpio",
archive_read_format_cpio_bid,
NULL,
archive_read_format_cpio_read_header,
archive_read_format_cpio_read_data,
NULL,

View File

@ -43,8 +43,10 @@ archive_read_support_format_empty(struct archive *_a)
int r;
r = __archive_read_register_format(a,
NULL,
NULL,
archive_read_format_empty_bid,
NULL,
archive_read_format_empty_read_header,
archive_read_format_empty_read_data,
NULL,

View File

@ -279,7 +279,9 @@ archive_read_support_format_iso9660(struct archive *_a)
r = __archive_read_register_format(a,
iso9660,
"iso9660",
archive_read_format_iso9660_bid,
NULL,
archive_read_format_iso9660_read_header,
archive_read_format_iso9660_read_data,
archive_read_format_iso9660_read_data_skip,

View File

@ -148,8 +148,8 @@ archive_read_support_format_mtree(struct archive *_a)
memset(mtree, 0, sizeof(*mtree));
mtree->fd = -1;
r = __archive_read_register_format(a, mtree,
mtree_bid, read_header, read_data, skip, cleanup);
r = __archive_read_register_format(a, mtree, "mtree",
mtree_bid, NULL, read_header, read_data, skip, cleanup);
if (r != ARCHIVE_OK)
free(mtree);

View File

@ -253,8 +253,9 @@ archive_read_support_format_tar(struct archive *_a)
}
memset(tar, 0, sizeof(*tar));
r = __archive_read_register_format(a, tar,
r = __archive_read_register_format(a, tar, "tar",
archive_read_format_tar_bid,
NULL,
archive_read_format_tar_read_header,
archive_read_format_tar_read_data,
archive_read_format_tar_skip,

View File

@ -153,7 +153,9 @@ archive_read_support_format_zip(struct archive *_a)
r = __archive_read_register_format(a,
zip,
"zip",
archive_read_format_zip_bid,
NULL,
archive_read_format_zip_read_header,
archive_read_format_zip_read_data,
archive_read_format_zip_read_data_skip,

View File

@ -1,4 +1,5 @@
/*-
* Copyright (c) 2009 Michihiro NAKAJIMA
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
@ -186,3 +187,195 @@ __archive_errx(int retvalue, const char *msg)
write(2, "\n", 1);
exit(retvalue);
}
/*
* Parse option strings
* Detail of option format.
* - The option can accept:
* "opt-name", "!opt-name", "opt-name=value".
*
* - The option entries are separated by comma.
* e.g "compression=9,opt=XXX,opt-b=ZZZ"
*
* - The name of option string consist of '-' and alphabet
* but character '-' cannot be used for the first character.
* (Regular expression is [a-z][-a-z]+)
*
* - For a specfic format/filter, using the format name with ':'.
* e.g "zip:compression=9"
* (This "compression=9" option entry is for "zip" format only)
*
* If another entries follow it, those are not for
* the specfic format/filter.
* e.g handle "zip:compression=9,opt=XXX,opt-b=ZZZ"
* "zip" format/filter handler will get "compression=9"
* all format/filter handler will get "opt=XXX"
* all format/filter handler will get "opt-b=ZZZ"
*
* - Whitespace and tab are bypassed.
*
*/
int
__archive_parse_options(const char *p, const char *fn, int keysize, char *key,
int valsize, char *val)
{
const char *p_org;
int apply;
int kidx, vidx;
int negative;
enum {
/* Requested for initialization. */
INIT,
/* Finding format/filter-name and option-name. */
F_BOTH,
/* Finding option-name only.
* (already detected format/filter-name) */
F_NAME,
/* Getting option-value. */
G_VALUE,
} state;
p_org = p;
state = INIT;
kidx = vidx = negative = 0;
apply = 1;
while (*p) {
switch (state) {
case INIT:
kidx = vidx = 0;
negative = 0;
apply = 1;
state = F_BOTH;
break;
case F_BOTH:
case F_NAME:
if ((*p >= 'a' && *p <= 'z') ||
(*p >= '0' && *p <= '9') || *p == '-') {
if (kidx == 0 && !(*p >= 'a' && *p <= 'z'))
/* Illegal sequence. */
return (-1);
if (kidx >= keysize -1)
/* Too many characters. */
return (-1);
key[kidx++] = *p++;
} else if (*p == '!') {
if (kidx != 0)
/* Illegal sequence. */
return (-1);
negative = 1;
++p;
} else if (*p == ',') {
if (kidx == 0)
/* Illegal sequence. */
return (-1);
if (!negative)
val[vidx++] = '1';
/* We have got boolean option data. */
++p;
if (apply)
goto complete;
else
/* This option does not apply to the
* format which the fn variable
* indicate. */
state = INIT;
} else if (*p == ':') {
/* obuf data is format name */
if (state == F_NAME)
/* We already found it. */
return (-1);
if (kidx == 0)
/* Illegal sequence. */
return (-1);
if (negative)
/* We cannot accept "!format-name:". */
return (-1);
key[kidx] = '\0';
if (strcmp(fn, key) != 0)
/* This option does not apply to the
* format which the fn variable
* indicate. */
apply = 0;
kidx = 0;
++p;
state = F_NAME;
} else if (*p == '=') {
if (kidx == 0)
/* Illegal sequence. */
return (-1);
if (negative)
/* We cannot accept "!opt-name=value". */
return (-1);
++p;
state = G_VALUE;
} else if (*p == ' ') {
/* Pass the space character */
++p;
} else {
/* Illegal character. */
return (-1);
}
break;
case G_VALUE:
if (*p == ',') {
if (vidx == 0)
/* Illegal sequence. */
return (-1);
/* We have got option data. */
++p;
if (apply)
goto complete;
else
/* This option does not apply to the
* format which the fn variable
* indicate. */
state = INIT;
} else if (*p == ' ') {
/* Pass the space character */
++p;
} else {
if (vidx >= valsize -1)
/* Too many characters. */
return (-1);
val[vidx++] = *p++;
}
break;
}
}
switch (state) {
case F_BOTH:
case F_NAME:
if (kidx != 0) {
if (!negative)
val[vidx++] = '1';
/* We have got boolean option. */
if (apply)
/* This option apply to the format which the
* fn variable indicate. */
goto complete;
}
break;
case G_VALUE:
if (vidx == 0)
/* Illegal sequence. */
return (-1);
/* We have got option value. */
if (apply)
/* This option apply to the format which the fn
* variable indicate. */
goto complete;
break;
case INIT:/* nothing */
break;
}
/* End of Option string. */
return (0);
complete:
key[kidx] = '\0';
val[vidx] = '\0';
/* Return a size which we've consumed for detecting option */
return ((int)(p - p_org));
}

View File

@ -124,6 +124,87 @@ archive_write_new(void)
return (&a->archive);
}
/*
* Set write options for the format. Returns 0 if successful.
*/
int
archive_write_set_format_options(struct archive *_a, const char *s)
{
struct archive_write *a = (struct archive_write *)_a;
char key[64], val[64];
int len, r;
if (a->format_options == NULL)
/* This format does not support option. */
return (ARCHIVE_OK);
while ((len = __archive_parse_options(s, a->format_name,
sizeof(key), key, sizeof(val), val)) > 0) {
if (val[0] == '\0')
r = a->format_options(a, key, NULL);
else
r = a->format_options(a, key, val);
if (r == ARCHIVE_FATAL)
return (r);
s += len;
}
if (len < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Illegal format options.");
return (ARCHIVE_WARN);
}
return (ARCHIVE_OK);
}
/*
* Set write options for the compressor. Returns 0 if successful.
*/
int
archive_write_set_compressor_options(struct archive *_a, const char *s)
{
struct archive_write *a = (struct archive_write *)_a;
char key[64], val[64];
int len, r;
if (a->compressor.options == NULL)
/* This compressor does not support option. */
return (ARCHIVE_OK);
while ((len = __archive_parse_options(s, a->archive.compression_name,
sizeof(key), key, sizeof(val), val)) > 0) {
if (val[0] == '\0')
r = a->compressor.options(a, key, NULL);
else
r = a->compressor.options(a, key, val);
if (r == ARCHIVE_FATAL)
return (r);
s += len;
}
if (len < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Illegal format options.");
return (ARCHIVE_WARN);
}
return (ARCHIVE_OK);
}
/*
* Set write options for the format and the compressor. Returns 0 if successful.
*/
int
archive_write_set_options(struct archive *_a, const char *s)
{
int r;
r = archive_write_set_format_options(_a, s);
if (r != ARCHIVE_OK)
return (r);
r = archive_write_set_compressor_options(_a, s);
if (r != ARCHIVE_OK)
return (r);
return (ARCHIVE_OK);
}
/*
* Set the block size. Returns 0 if successful.
*/

View File

@ -77,6 +77,8 @@ struct archive_write {
void *data;
void *config;
int (*init)(struct archive_write *);
int (*options)(struct archive_write *,
const char *key, const char *value);
int (*finish)(struct archive_write *);
int (*write)(struct archive_write *, const void *, size_t);
} compressor;
@ -86,7 +88,10 @@ struct archive_write {
* initialized by archive_write_set_format_XXX() calls.
*/
void *format_data;
const char *format_name;
int (*format_init)(struct archive_write *);
int (*format_options)(struct archive_write *,
const char *key, const char *value);
int (*format_finish)(struct archive_write *);
int (*format_destroy)(struct archive_write *);
int (*format_finish_entry)(struct archive_write *);

View File

@ -61,6 +61,8 @@ struct private_data {
unsigned char *compressed;
size_t compressed_buffer_size;
unsigned long crc;
/* Options */
int compression_level;
};
@ -73,6 +75,8 @@ struct private_data {
static int archive_compressor_gzip_finish(struct archive_write *);
static int archive_compressor_gzip_init(struct archive_write *);
static int archive_compressor_gzip_options(struct archive_write *,
const char *, const char *);
static int archive_compressor_gzip_write(struct archive_write *,
const void *, size_t);
static int drive_compressor(struct archive_write *, struct private_data *,
@ -143,6 +147,7 @@ archive_compressor_gzip_init(struct archive_write *a)
state->compressed_buffer_size = a->bytes_per_block;
state->compressed = (unsigned char *)malloc(state->compressed_buffer_size);
state->crc = crc32(0L, NULL, 0);
state->compression_level = Z_DEFAULT_COMPRESSION;
if (state->compressed == NULL) {
archive_set_error(&a->archive, ENOMEM,
@ -169,12 +174,13 @@ archive_compressor_gzip_init(struct archive_write *a)
state->stream.next_out += 10;
state->stream.avail_out -= 10;
a->compressor.options = archive_compressor_gzip_options;
a->compressor.write = archive_compressor_gzip_write;
a->compressor.finish = archive_compressor_gzip_finish;
/* Initialize compression library. */
ret = deflateInit2(&(state->stream),
Z_DEFAULT_COMPRESSION,
state->compression_level,
Z_DEFLATED,
-15 /* < 0 to suppress zlib header */,
8,
@ -212,6 +218,57 @@ archive_compressor_gzip_init(struct archive_write *a)
return (ARCHIVE_FATAL);
}
/*
* Set write options.
*/
static int
archive_compressor_gzip_options(struct archive_write *a, const char *key,
const char *value)
{
struct private_data *state;
int ret;
state = (struct private_data *)a->compressor.data;
if (strcmp(key, "compression-level") == 0) {
int level;
if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
value[1] != '\0')
return (ARCHIVE_WARN);
level = value[0] - '0';
if (level == state->compression_level)
return (ARCHIVE_OK);
ret = deflateParams(&(state->stream), level,
Z_DEFAULT_STRATEGY);
if (ret == Z_OK) {
state->compression_level = level;
return (ARCHIVE_OK);
}
switch (ret) {
case Z_STREAM_ERROR:
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error updating params "
"compression library: state was inconsistent "
"or parameter was invalid");
break;
case Z_BUF_ERROR:
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error updating params "
"compression library: out buffer was zero");
break;
default:
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error updatng params "
"compression library");
break;
}
return (ARCHIVE_FATAL);
}
return (ARCHIVE_WARN);
}
/*
* Write data to the compressed stream.
*/

View File

@ -125,6 +125,7 @@ archive_write_set_format_ar(struct archive_write *a)
memset(ar, 0, sizeof(*ar));
a->format_data = ar;
a->format_name = "ar";
a->format_write_header = archive_write_ar_header;
a->format_write_data = archive_write_ar_data;
a->format_finish = archive_write_ar_finish;

View File

@ -92,6 +92,7 @@ archive_write_set_format_cpio(struct archive *_a)
a->format_data = cpio;
a->pad_uncompressed = 1;
a->format_name = "cpio";
a->format_write_header = archive_write_cpio_header;
a->format_write_data = archive_write_cpio_data;
a->format_finish_entry = archive_write_cpio_finish_entry;

View File

@ -97,6 +97,7 @@ archive_write_set_format_cpio_newc(struct archive *_a)
a->format_data = cpio;
a->pad_uncompressed = 1;
a->format_name = "cpio";
a->format_write_header = archive_write_newc_header;
a->format_write_data = archive_write_newc_data;
a->format_finish_entry = archive_write_newc_finish_entry;

View File

@ -107,6 +107,20 @@ archive_write_mtree_header(struct archive_write *a,
return (ARCHIVE_OK);
}
#if 0
static void
strappend_bin(struct archive_string *s, const unsigned char *bin, int n)
{
static const char hex[] = "0123456789abcdef";
int i;
for (i = 0; i < n; i++) {
archive_strappend_char(s, hex[bin[i] >> 4]);
archive_strappend_char(s, hex[bin[i] & 0x0f]);
}
}
#endif
static int
archive_write_mtree_finish_entry(struct archive_write *a)
{
@ -248,6 +262,7 @@ archive_write_set_format_mtree(struct archive *_a)
a->format_destroy = archive_write_mtree_destroy;
a->pad_uncompressed = 0;
a->format_name = "mtree";
a->format_write_header = archive_write_mtree_header;
a->format_finish = archive_write_mtree_finish;
a->format_write_data = archive_write_mtree_data;

View File

@ -111,6 +111,7 @@ archive_write_set_format_pax(struct archive *_a)
a->format_data = pax;
a->pad_uncompressed = 1;
a->format_name = "pax";
a->format_write_header = archive_write_pax_header;
a->format_write_data = archive_write_pax_data;
a->format_finish = archive_write_pax_finish;

View File

@ -121,6 +121,7 @@ archive_write_set_format_shar(struct archive *_a)
a->format_data = shar;
a->pad_uncompressed = 0;
a->format_name = "shar";
a->format_write_header = archive_write_shar_header;
a->format_finish = archive_write_shar_finish;
a->format_destroy = archive_write_shar_destroy;

View File

@ -181,6 +181,7 @@ archive_write_set_format_ustar(struct archive *_a)
a->format_data = ustar;
a->pad_uncompressed = 1; /* Mimic gtar in this respect. */
a->format_name = "ustar";
a->format_write_header = archive_write_ustar_header;
a->format_write_data = archive_write_ustar_data;
a->format_finish = archive_write_ustar_finish;