summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2009-03-06 05:58:56 +0000
committerkientzle <kientzle@FreeBSD.org>2009-03-06 05:58:56 +0000
commita6d71699e11ca2aa4e0f92a369ac8071b9eb85c0 (patch)
tree5d87f6f3a950ec9ead6d49f3895b6b060a82f0b7 /lib
parent1c1c217183280235637a950efa5a836ddab91b71 (diff)
downloadFreeBSD-src-a6d71699e11ca2aa4e0f92a369ac8071b9eb85c0.zip
FreeBSD-src-a6d71699e11ca2aa4e0f92a369ac8071b9eb85c0.tar.gz
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.
Diffstat (limited to 'lib')
-rw-r--r--lib/libarchive/archive.h27
-rw-r--r--lib/libarchive/archive_private.h3
-rw-r--r--lib/libarchive/archive_read.c93
-rw-r--r--lib/libarchive/archive_read_private.h8
-rw-r--r--lib/libarchive/archive_read_support_compression_bzip2.c1
-rw-r--r--lib/libarchive/archive_read_support_compression_compress.c1
-rw-r--r--lib/libarchive/archive_read_support_compression_gzip.c3
-rw-r--r--lib/libarchive/archive_read_support_compression_program.c1
-rw-r--r--lib/libarchive/archive_read_support_format_ar.c2
-rw-r--r--lib/libarchive/archive_read_support_format_cpio.c2
-rw-r--r--lib/libarchive/archive_read_support_format_empty.c2
-rw-r--r--lib/libarchive/archive_read_support_format_iso9660.c2
-rw-r--r--lib/libarchive/archive_read_support_format_mtree.c4
-rw-r--r--lib/libarchive/archive_read_support_format_tar.c3
-rw-r--r--lib/libarchive/archive_read_support_format_zip.c2
-rw-r--r--lib/libarchive/archive_util.c193
-rw-r--r--lib/libarchive/archive_write.c81
-rw-r--r--lib/libarchive/archive_write_private.h5
-rw-r--r--lib/libarchive/archive_write_set_compression_gzip.c59
-rw-r--r--lib/libarchive/archive_write_set_format_ar.c1
-rw-r--r--lib/libarchive/archive_write_set_format_cpio.c1
-rw-r--r--lib/libarchive/archive_write_set_format_cpio_newc.c1
-rw-r--r--lib/libarchive/archive_write_set_format_mtree.c15
-rw-r--r--lib/libarchive/archive_write_set_format_pax.c1
-rw-r--r--lib/libarchive/archive_write_set_format_shar.c1
-rw-r--r--lib/libarchive/archive_write_set_format_ustar.c1
26 files changed, 508 insertions, 5 deletions
diff --git a/lib/libarchive/archive.h b/lib/libarchive/archive.h
index 72bd8a0..ad4b1af 100644
--- a/lib/libarchive/archive.h
+++ b/lib/libarchive/archive.h
@@ -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.
diff --git a/lib/libarchive/archive_private.h b/lib/libarchive/archive_private.h
index a93344d..7d6f727 100644
--- a/lib/libarchive/archive_private.h
+++ b/lib/libarchive/archive_private.h
@@ -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
diff --git a/lib/libarchive/archive_read.c b/lib/libarchive/archive_read.c
index dcf1746..8346f6a 100644
--- a/lib/libarchive/archive_read.c
+++ b/lib/libarchive/archive_read.c
@@ -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);
}
}
diff --git a/lib/libarchive/archive_read_private.h b/lib/libarchive/archive_read_private.h
index f1438a17..91a1c5e 100644
--- a/lib/libarchive/archive_read_private.h
+++ b/lib/libarchive/archive_read_private.h
@@ -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 *),
diff --git a/lib/libarchive/archive_read_support_compression_bzip2.c b/lib/libarchive/archive_read_support_compression_bzip2.c
index 9a1d70e..fa4168c 100644
--- a/lib/libarchive/archive_read_support_compression_bzip2.c
+++ b/lib/libarchive/archive_read_support_compression_bzip2.c
@@ -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);
}
diff --git a/lib/libarchive/archive_read_support_compression_compress.c b/lib/libarchive/archive_read_support_compression_compress.c
index fb65abd5..a5c5f79 100644
--- a/lib/libarchive/archive_read_support_compression_compress.c
+++ b/lib/libarchive/archive_read_support_compression_compress.c
@@ -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);
}
diff --git a/lib/libarchive/archive_read_support_compression_gzip.c b/lib/libarchive/archive_read_support_compression_gzip.c
index 91ba270..9d06bf6 100644
--- a/lib/libarchive/archive_read_support_compression_gzip.c
+++ b/lib/libarchive/archive_read_support_compression_gzip.c
@@ -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);
}
diff --git a/lib/libarchive/archive_read_support_compression_program.c b/lib/libarchive/archive_read_support_compression_program.c
index 05dbc32..efcc292 100644
--- a/lib/libarchive/archive_read_support_compression_program.c
+++ b/lib/libarchive/archive_read_support_compression_program.c
@@ -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);
}
diff --git a/lib/libarchive/archive_read_support_format_ar.c b/lib/libarchive/archive_read_support_format_ar.c
index 0201364..3bd13b1 100644
--- a/lib/libarchive/archive_read_support_format_ar.c
+++ b/lib/libarchive/archive_read_support_format_ar.c
@@ -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,
diff --git a/lib/libarchive/archive_read_support_format_cpio.c b/lib/libarchive/archive_read_support_format_cpio.c
index fd1c01f..ba42cac 100644
--- a/lib/libarchive/archive_read_support_format_cpio.c
+++ b/lib/libarchive/archive_read_support_format_cpio.c
@@ -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,
diff --git a/lib/libarchive/archive_read_support_format_empty.c b/lib/libarchive/archive_read_support_format_empty.c
index 5850320..bdecd65 100644
--- a/lib/libarchive/archive_read_support_format_empty.c
+++ b/lib/libarchive/archive_read_support_format_empty.c
@@ -44,7 +44,9 @@ archive_read_support_format_empty(struct archive *_a)
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,
diff --git a/lib/libarchive/archive_read_support_format_iso9660.c b/lib/libarchive/archive_read_support_format_iso9660.c
index c124c71..73b8146 100644
--- a/lib/libarchive/archive_read_support_format_iso9660.c
+++ b/lib/libarchive/archive_read_support_format_iso9660.c
@@ -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,
diff --git a/lib/libarchive/archive_read_support_format_mtree.c b/lib/libarchive/archive_read_support_format_mtree.c
index 7617d04..ac615c7 100644
--- a/lib/libarchive/archive_read_support_format_mtree.c
+++ b/lib/libarchive/archive_read_support_format_mtree.c
@@ -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);
diff --git a/lib/libarchive/archive_read_support_format_tar.c b/lib/libarchive/archive_read_support_format_tar.c
index ae0c528..a2d08ea 100644
--- a/lib/libarchive/archive_read_support_format_tar.c
+++ b/lib/libarchive/archive_read_support_format_tar.c
@@ -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,
diff --git a/lib/libarchive/archive_read_support_format_zip.c b/lib/libarchive/archive_read_support_format_zip.c
index aead1c4..cc7a33d 100644
--- a/lib/libarchive/archive_read_support_format_zip.c
+++ b/lib/libarchive/archive_read_support_format_zip.c
@@ -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,
diff --git a/lib/libarchive/archive_util.c b/lib/libarchive/archive_util.c
index bc39a4d..1c171b9 100644
--- a/lib/libarchive/archive_util.c
+++ b/lib/libarchive/archive_util.c
@@ -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));
+}
diff --git a/lib/libarchive/archive_write.c b/lib/libarchive/archive_write.c
index f1c3d23..54018e7 100644
--- a/lib/libarchive/archive_write.c
+++ b/lib/libarchive/archive_write.c
@@ -125,6 +125,87 @@ archive_write_new(void)
}
/*
+ * 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.
*/
int
diff --git a/lib/libarchive/archive_write_private.h b/lib/libarchive/archive_write_private.h
index 8deabbf..0f7215f 100644
--- a/lib/libarchive/archive_write_private.h
+++ b/lib/libarchive/archive_write_private.h
@@ -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 *);
diff --git a/lib/libarchive/archive_write_set_compression_gzip.c b/lib/libarchive/archive_write_set_compression_gzip.c
index 807d54e..1588c9e 100644
--- a/lib/libarchive/archive_write_set_compression_gzip.c
+++ b/lib/libarchive/archive_write_set_compression_gzip.c
@@ -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,
@@ -213,6 +219,57 @@ archive_compressor_gzip_init(struct archive_write *a)
}
/*
+ * 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.
*/
static int
diff --git a/lib/libarchive/archive_write_set_format_ar.c b/lib/libarchive/archive_write_set_format_ar.c
index 453cf3c..f9dd546 100644
--- a/lib/libarchive/archive_write_set_format_ar.c
+++ b/lib/libarchive/archive_write_set_format_ar.c
@@ -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;
diff --git a/lib/libarchive/archive_write_set_format_cpio.c b/lib/libarchive/archive_write_set_format_cpio.c
index c500e52..ef88375 100644
--- a/lib/libarchive/archive_write_set_format_cpio.c
+++ b/lib/libarchive/archive_write_set_format_cpio.c
@@ -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;
diff --git a/lib/libarchive/archive_write_set_format_cpio_newc.c b/lib/libarchive/archive_write_set_format_cpio_newc.c
index f9d89e5..9df79e7 100644
--- a/lib/libarchive/archive_write_set_format_cpio_newc.c
+++ b/lib/libarchive/archive_write_set_format_cpio_newc.c
@@ -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;
diff --git a/lib/libarchive/archive_write_set_format_mtree.c b/lib/libarchive/archive_write_set_format_mtree.c
index ff01aa1..12d2edb 100644
--- a/lib/libarchive/archive_write_set_format_mtree.c
+++ b/lib/libarchive/archive_write_set_format_mtree.c
@@ -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;
diff --git a/lib/libarchive/archive_write_set_format_pax.c b/lib/libarchive/archive_write_set_format_pax.c
index 24d611c..6ea8f5e 100644
--- a/lib/libarchive/archive_write_set_format_pax.c
+++ b/lib/libarchive/archive_write_set_format_pax.c
@@ -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;
diff --git a/lib/libarchive/archive_write_set_format_shar.c b/lib/libarchive/archive_write_set_format_shar.c
index f3664a8..6cb58e8 100644
--- a/lib/libarchive/archive_write_set_format_shar.c
+++ b/lib/libarchive/archive_write_set_format_shar.c
@@ -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;
diff --git a/lib/libarchive/archive_write_set_format_ustar.c b/lib/libarchive/archive_write_set_format_ustar.c
index 665d080..ad7e842 100644
--- a/lib/libarchive/archive_write_set_format_ustar.c
+++ b/lib/libarchive/archive_write_set_format_ustar.c
@@ -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;
OpenPOWER on IntegriCloud