svn commit: r189438 - head/lib/libarchive

Tim Kientzle kientzle at FreeBSD.org
Thu Mar 5 21:58:58 PST 2009


Author: kientzle
Date: Fri Mar  6 05:58:56 2009
New Revision: 189438
URL: http://svn.freebsd.org/changeset/base/189438

Log:
  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.

Modified:
  head/lib/libarchive/archive.h
  head/lib/libarchive/archive_private.h
  head/lib/libarchive/archive_read.c
  head/lib/libarchive/archive_read_private.h
  head/lib/libarchive/archive_read_support_compression_bzip2.c
  head/lib/libarchive/archive_read_support_compression_compress.c
  head/lib/libarchive/archive_read_support_compression_gzip.c
  head/lib/libarchive/archive_read_support_compression_program.c
  head/lib/libarchive/archive_read_support_format_ar.c
  head/lib/libarchive/archive_read_support_format_cpio.c
  head/lib/libarchive/archive_read_support_format_empty.c
  head/lib/libarchive/archive_read_support_format_iso9660.c
  head/lib/libarchive/archive_read_support_format_mtree.c
  head/lib/libarchive/archive_read_support_format_tar.c
  head/lib/libarchive/archive_read_support_format_zip.c
  head/lib/libarchive/archive_util.c
  head/lib/libarchive/archive_write.c
  head/lib/libarchive/archive_write_private.h
  head/lib/libarchive/archive_write_set_compression_gzip.c
  head/lib/libarchive/archive_write_set_format_ar.c
  head/lib/libarchive/archive_write_set_format_cpio.c
  head/lib/libarchive/archive_write_set_format_cpio_newc.c
  head/lib/libarchive/archive_write_set_format_mtree.c
  head/lib/libarchive/archive_write_set_format_pax.c
  head/lib/libarchive/archive_write_set_format_shar.c
  head/lib/libarchive/archive_write_set_format_ustar.c

Modified: head/lib/libarchive/archive.h
==============================================================================
--- head/lib/libarchive/archive.h	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive.h	Fri Mar  6 05:58:56 2009	(r189438)
@@ -384,6 +384,19 @@ __LA_DECL int		 archive_read_data_into_b
 			    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(st
 __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.

Modified: head/lib/libarchive/archive_private.h
==============================================================================
--- head/lib/libarchive/archive_private.h	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_private.h	Fri Mar  6 05:58:56 2009	(r189438)
@@ -102,6 +102,9 @@ void	__archive_check_magic(struct archiv
 
 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

Modified: head/lib/libarchive/archive_read.c
==============================================================================
--- head/lib/libarchive/archive_read.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_read.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -108,6 +108,95 @@ archive_read_extract_set_skip_file(struc
 	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 ar
 			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);
 		}
 	}

Modified: head/lib/libarchive/archive_read_private.h
==============================================================================
--- head/lib/libarchive/archive_read_private.h	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_read_private.h	Fri Mar  6 05:58:56 2009	(r189438)
@@ -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 *),

Modified: head/lib/libarchive/archive_read_support_compression_bzip2.c
==============================================================================
--- head/lib/libarchive/archive_read_support_compression_bzip2.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_read_support_compression_bzip2.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -84,6 +84,7 @@ archive_read_support_compression_bzip2(s
 	reader->data = NULL;
 	reader->bid = bzip2_reader_bid;
 	reader->init = bzip2_reader_init;
+	reader->options = NULL;
 	reader->free = bzip2_reader_free;
 	return (ARCHIVE_OK);
 }

Modified: head/lib/libarchive/archive_read_support_compression_compress.c
==============================================================================
--- head/lib/libarchive/archive_read_support_compression_compress.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_read_support_compression_compress.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -152,6 +152,7 @@ archive_read_support_compression_compres
 	bidder->data = NULL;
 	bidder->bid = compress_bidder_bid;
 	bidder->init = compress_bidder_init;
+	bidder->options = NULL;
 	bidder->free = compress_bidder_free;
 	return (ARCHIVE_OK);
 }

Modified: head/lib/libarchive/archive_read_support_compression_gzip.c
==============================================================================
--- head/lib/libarchive/archive_read_support_compression_gzip.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_read_support_compression_gzip.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -90,7 +90,8 @@ archive_read_support_compression_gzip(st
 	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);
 }
 

Modified: head/lib/libarchive/archive_read_support_compression_program.c
==============================================================================
--- head/lib/libarchive/archive_read_support_compression_program.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_read_support_compression_program.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -122,6 +122,7 @@ archive_read_support_compression_program
 	bidder->data = state;
 	bidder->bid = program_bidder_bid;
 	bidder->init = program_bidder_init;
+	bidder->options = NULL;
 	bidder->free = program_bidder_free;
 	return (ARCHIVE_OK);
 }

Modified: head/lib/libarchive/archive_read_support_format_ar.c
==============================================================================
--- head/lib/libarchive/archive_read_support_format_ar.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_read_support_format_ar.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -105,7 +105,9 @@ archive_read_support_format_ar(struct ar
 
 	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,

Modified: head/lib/libarchive/archive_read_support_format_cpio.c
==============================================================================
--- head/lib/libarchive/archive_read_support_format_cpio.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_read_support_format_cpio.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -150,7 +150,9 @@ archive_read_support_format_cpio(struct 
 
 	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,

Modified: head/lib/libarchive/archive_read_support_format_empty.c
==============================================================================
--- head/lib/libarchive/archive_read_support_format_empty.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_read_support_format_empty.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -44,7 +44,9 @@ archive_read_support_format_empty(struct
 
 	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,

Modified: head/lib/libarchive/archive_read_support_format_iso9660.c
==============================================================================
--- head/lib/libarchive/archive_read_support_format_iso9660.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_read_support_format_iso9660.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -279,7 +279,9 @@ archive_read_support_format_iso9660(stru
 
 	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,

Modified: head/lib/libarchive/archive_read_support_format_mtree.c
==============================================================================
--- head/lib/libarchive/archive_read_support_format_mtree.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_read_support_format_mtree.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -148,8 +148,8 @@ archive_read_support_format_mtree(struct
 	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);

Modified: head/lib/libarchive/archive_read_support_format_tar.c
==============================================================================
--- head/lib/libarchive/archive_read_support_format_tar.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_read_support_format_tar.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -253,8 +253,9 @@ archive_read_support_format_tar(struct 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,

Modified: head/lib/libarchive/archive_read_support_format_zip.c
==============================================================================
--- head/lib/libarchive/archive_read_support_format_zip.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_read_support_format_zip.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -153,7 +153,9 @@ archive_read_support_format_zip(struct 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,

Modified: head/lib/libarchive/archive_util.c
==============================================================================
--- head/lib/libarchive/archive_util.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_util.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -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 
 	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));
+}

Modified: head/lib/libarchive/archive_write.c
==============================================================================
--- head/lib/libarchive/archive_write.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_write.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -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

Modified: head/lib/libarchive/archive_write_private.h
==============================================================================
--- head/lib/libarchive/archive_write_private.h	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_write_private.h	Fri Mar  6 05:58:56 2009	(r189438)
@@ -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 *);

Modified: head/lib/libarchive/archive_write_set_compression_gzip.c
==============================================================================
--- head/lib/libarchive/archive_write_set_compression_gzip.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_write_set_compression_gzip.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -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 arch
 	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 arch
 	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 arch
 }
 
 /*
+ * 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

Modified: head/lib/libarchive/archive_write_set_format_ar.c
==============================================================================
--- head/lib/libarchive/archive_write_set_format_ar.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_write_set_format_ar.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -125,6 +125,7 @@ archive_write_set_format_ar(struct archi
 	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;

Modified: head/lib/libarchive/archive_write_set_format_cpio.c
==============================================================================
--- head/lib/libarchive/archive_write_set_format_cpio.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_write_set_format_cpio.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -92,6 +92,7 @@ archive_write_set_format_cpio(struct arc
 	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;

Modified: head/lib/libarchive/archive_write_set_format_cpio_newc.c
==============================================================================
--- head/lib/libarchive/archive_write_set_format_cpio_newc.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_write_set_format_cpio_newc.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -97,6 +97,7 @@ archive_write_set_format_cpio_newc(struc
 	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;

Modified: head/lib/libarchive/archive_write_set_format_mtree.c
==============================================================================
--- head/lib/libarchive/archive_write_set_format_mtree.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_write_set_format_mtree.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -107,6 +107,20 @@ archive_write_mtree_header(struct archiv
 	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 ar
 	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;

Modified: head/lib/libarchive/archive_write_set_format_pax.c
==============================================================================
--- head/lib/libarchive/archive_write_set_format_pax.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_write_set_format_pax.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -111,6 +111,7 @@ archive_write_set_format_pax(struct arch
 	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;

Modified: head/lib/libarchive/archive_write_set_format_shar.c
==============================================================================
--- head/lib/libarchive/archive_write_set_format_shar.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_write_set_format_shar.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -121,6 +121,7 @@ archive_write_set_format_shar(struct arc
 	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;

Modified: head/lib/libarchive/archive_write_set_format_ustar.c
==============================================================================
--- head/lib/libarchive/archive_write_set_format_ustar.c	Fri Mar  6 05:40:09 2009	(r189437)
+++ head/lib/libarchive/archive_write_set_format_ustar.c	Fri Mar  6 05:58:56 2009	(r189438)
@@ -181,6 +181,7 @@ archive_write_set_format_ustar(struct ar
 	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;


More information about the svn-src-all mailing list