]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Improve archive_write_filter_program handing to be able to
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Wed, 10 Oct 2012 22:33:00 +0000 (07:33 +0900)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Wed, 10 Oct 2012 22:33:00 +0000 (07:33 +0900)
use options for an external program from
archive_write_filter_{grzip,lrzip,lzop}.

libarchive/archive_write_add_filter_grzip.c
libarchive/archive_write_add_filter_lrzip.c
libarchive/archive_write_add_filter_lzop.c
libarchive/archive_write_add_filter_program.c
libarchive/archive_write_private.h

index 6c0478c3447d55ff57fbc084767eaa1eb7d8f128..b5255903a9beed4b48b685f1d8c0681ebee37f80 100644 (file)
 
 __FBSDID("$FreeBSD$");
 
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
 #include "archive.h"
 #include "archive_write_private.h"
 
+struct write_grzip {
+       struct archive_write_program_data *pdata;
+};
+
+static int archive_write_grzip_open(struct archive_write_filter *);
+static int archive_write_grzip_options(struct archive_write_filter *,
+                   const char *, const char *);
+static int archive_write_grzip_write(struct archive_write_filter *,
+                   const void *, size_t);
+static int archive_write_grzip_close(struct archive_write_filter *);
+static int archive_write_grzip_free(struct archive_write_filter *);
+
 int
-archive_write_add_filter_grzip(struct archive *a)
+archive_write_add_filter_grzip(struct archive *_a)
+{
+       struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+       struct write_grzip *data;
+
+       archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+           ARCHIVE_STATE_NEW, "archive_write_add_filter_grzip");
+
+       data = calloc(1, sizeof(*data));
+       if (data == NULL) {
+               archive_set_error(_a, ENOMEM, "Can't allocate memory");
+               return (ARCHIVE_FATAL);
+       }
+       data->pdata = __archive_write_program_allocate();
+       if (data->pdata == NULL) {
+               free(data);
+               archive_set_error(_a, ENOMEM, "Can't allocate memory");
+               return (ARCHIVE_FATAL);
+       }
+
+       f->name = "grzip";
+       f->code = ARCHIVE_FILTER_GRZIP;
+       f->data = data;
+       f->open = archive_write_grzip_open;
+       f->options = archive_write_grzip_options;
+       f->write = archive_write_grzip_write;
+       f->close = archive_write_grzip_close;
+       f->free = archive_write_grzip_free;
+
+       /* Note: This filter always uses an external program, so we
+        * return "warn" to inform of the fact. */
+       return (ARCHIVE_WARN);
+}
+
+static int
+archive_write_grzip_options(struct archive_write_filter *f, const char *key,
+    const char *value)
+{
+       (void)f; /* UNUSED */
+       (void)key; /* UNUSED */
+       (void)value; /* UNUSED */
+       /* Note: The "warn" return is just to inform the options
+        * supervisor that we didn't handle it.  It will generate
+        * a suitable error if no one used this option. */
+       return (ARCHIVE_WARN);
+}
+
+static int
+archive_write_grzip_open(struct archive_write_filter *f)
 {
-       char * const argv[] = { "grzip", NULL };
+       struct write_grzip *data = (struct write_grzip *)f->data;
        int r;
 
-       r = __archive_write_programv(a, "grzip", ARCHIVE_FILTER_GRZIP,
-               "grzip", argv);
-       if (r == ARCHIVE_OK)
-               /* This filter always uses an external program. */
-               r = ARCHIVE_WARN;
+       r = __archive_write_program_set_cmd(data->pdata, "grzip");
+       if (r != ARCHIVE_OK)
+               goto memerr;
+       r = __archive_write_program_add_arg(data->pdata, "grzip");
+       if (r != ARCHIVE_OK)
+               goto memerr;
+       r = __archive_write_program_open(f, data->pdata);
        return (r);
+memerr:
+       archive_set_error(f->archive, ENOMEM, "Can't allocate memory");
+       return (ARCHIVE_FATAL);
+}
+
+static int
+archive_write_grzip_write(struct archive_write_filter *f,
+    const void *buff, size_t length)
+{
+       struct write_grzip *data = (struct write_grzip *)f->data;
+
+       return __archive_write_program_write(f, data->pdata, buff, length);
+}
+
+static int
+archive_write_grzip_close(struct archive_write_filter *f)
+{
+       struct write_grzip *data = (struct write_grzip *)f->data;
+
+       return __archive_write_program_close(f, data->pdata);
+}
+
+static int
+archive_write_grzip_free(struct archive_write_filter *f)
+{
+       struct write_grzip *data = (struct write_grzip *)f->data;
+
+       __archive_write_program_free(data->pdata);
+       free(data);
+       return (ARCHIVE_OK);
 }
index 917b2b83e47dbf0de491bf6aedf6d058bb676bb9..1f27f686d14c105d7c9ba548d258dbde36799699 100644 (file)
 
 __FBSDID("$FreeBSD$");
 
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
 #include "archive.h"
 #include "archive_write_private.h"
 
+struct write_lrzip {
+       struct archive_write_program_data *pdata;
+};
+
+static int archive_write_lrzip_open(struct archive_write_filter *);
+static int archive_write_lrzip_options(struct archive_write_filter *,
+                   const char *, const char *);
+static int archive_write_lrzip_write(struct archive_write_filter *,
+                   const void *, size_t);
+static int archive_write_lrzip_close(struct archive_write_filter *);
+static int archive_write_lrzip_free(struct archive_write_filter *);
+
 int
-archive_write_add_filter_lrzip(struct archive *a)
+archive_write_add_filter_lrzip(struct archive *_a)
+{
+       struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+       struct write_lrzip *data;
+
+       archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+           ARCHIVE_STATE_NEW, "archive_write_add_filter_lrzip");
+
+       data = calloc(1, sizeof(*data));
+       if (data == NULL) {
+               archive_set_error(_a, ENOMEM, "Can't allocate memory");
+               return (ARCHIVE_FATAL);
+       }
+       data->pdata = __archive_write_program_allocate();
+       if (data->pdata == NULL) {
+               free(data);
+               archive_set_error(_a, ENOMEM, "Can't allocate memory");
+               return (ARCHIVE_FATAL);
+       }
+
+       f->name = "lrzip";
+       f->code = ARCHIVE_FILTER_LRZIP;
+       f->data = data;
+       f->open = archive_write_lrzip_open;
+       f->options = archive_write_lrzip_options;
+       f->write = archive_write_lrzip_write;
+       f->close = archive_write_lrzip_close;
+       f->free = archive_write_lrzip_free;
+
+       /* Note: This filter always uses an external program, so we
+        * return "warn" to inform of the fact. */
+       return (ARCHIVE_WARN);
+}
+
+static int
+archive_write_lrzip_options(struct archive_write_filter *f, const char *key,
+    const char *value)
+{
+       (void)f; /* UNUSED */
+       (void)key; /* UNUSED */
+       (void)value; /* UNUSED */
+       /* Note: The "warn" return is just to inform the options
+        * supervisor that we didn't handle it.  It will generate
+        * a suitable error if no one used this option. */
+       return (ARCHIVE_WARN);
+}
+
+static int
+archive_write_lrzip_open(struct archive_write_filter *f)
 {
-       char * const argv[] = { "lrzip", "-q", NULL };
+       struct write_lrzip *data = (struct write_lrzip *)f->data;
        int r;
 
-       r = __archive_write_programv(a, "lrzip", ARCHIVE_FILTER_LRZIP,
-               "lrzip", argv);
-       if (r == ARCHIVE_OK)
-               /* This filter always uses an external program. */
-               r = ARCHIVE_WARN;
+       r = __archive_write_program_set_cmd(data->pdata, "lrzip");
+       if (r != ARCHIVE_OK)
+               goto memerr;
+       r = __archive_write_program_add_arg(data->pdata, "lrzip");
+       if (r != ARCHIVE_OK)
+               goto memerr;
+       r = __archive_write_program_add_arg(data->pdata, "-q");
+       if (r != ARCHIVE_OK)
+               goto memerr;
+
+       r = __archive_write_program_open(f, data->pdata);
        return (r);
+memerr:
+       archive_set_error(f->archive, ENOMEM, "Can't allocate memory");
+       return (ARCHIVE_FATAL);
+}
+
+static int
+archive_write_lrzip_write(struct archive_write_filter *f,
+    const void *buff, size_t length)
+{
+       struct write_lrzip *data = (struct write_lrzip *)f->data;
+
+       return __archive_write_program_write(f, data->pdata, buff, length);
+}
+
+static int
+archive_write_lrzip_close(struct archive_write_filter *f)
+{
+       struct write_lrzip *data = (struct write_lrzip *)f->data;
+
+       return __archive_write_program_close(f, data->pdata);
+}
+
+static int
+archive_write_lrzip_free(struct archive_write_filter *f)
+{
+       struct write_lrzip *data = (struct write_lrzip *)f->data;
+
+       __archive_write_program_free(data->pdata);
+       free(data);
+       return (ARCHIVE_OK);
 }
index d453438f3851c756318f010e04c76a400559945e..59ab993150dd1ed50ced2c4ebbcb7d1502bb306d 100644 (file)
 
 __FBSDID("$FreeBSD$");
 
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
 #include "archive.h"
 #include "archive_write_private.h"
 
+struct write_lzop {
+       struct archive_write_program_data *pdata;
+};
+
+static int archive_write_lzop_open(struct archive_write_filter *);
+static int archive_write_lzop_options(struct archive_write_filter *,
+                   const char *, const char *);
+static int archive_write_lzop_write(struct archive_write_filter *,
+                   const void *, size_t);
+static int archive_write_lzop_close(struct archive_write_filter *);
+static int archive_write_lzop_free(struct archive_write_filter *);
+
 int
-archive_write_add_filter_lzop(struct archive *a)
+archive_write_add_filter_lzop(struct archive *_a)
+{
+       struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+       struct write_lzop *data;
+
+       archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+           ARCHIVE_STATE_NEW, "archive_write_add_filter_lzop");
+
+       data = calloc(1, sizeof(*data));
+       if (data == NULL) {
+               archive_set_error(_a, ENOMEM, "Can't allocate memory");
+               return (ARCHIVE_FATAL);
+       }
+       data->pdata = __archive_write_program_allocate();
+       if (data->pdata == NULL) {
+               free(data);
+               archive_set_error(_a, ENOMEM, "Can't allocate memory");
+               return (ARCHIVE_FATAL);
+       }
+
+       f->name = "lzop";
+       f->code = ARCHIVE_FILTER_LZOP;
+       f->data = data;
+       f->open = archive_write_lzop_open;
+       f->options = archive_write_lzop_options;
+       f->write = archive_write_lzop_write;
+       f->close = archive_write_lzop_close;
+       f->free = archive_write_lzop_free;
+
+       /* Note: This filter always uses an external program, so we
+        * return "warn" to inform of the fact. */
+       return (ARCHIVE_WARN);
+}
+
+static int
+archive_write_lzop_options(struct archive_write_filter *f, const char *key,
+    const char *value)
+{
+       (void)f; /* UNUSED */
+       (void)key; /* UNUSED */
+       (void)value; /* UNUSED */
+       /* Note: The "warn" return is just to inform the options
+        * supervisor that we didn't handle it.  It will generate
+        * a suitable error if no one used this option. */
+       return (ARCHIVE_WARN);
+}
+
+static int
+archive_write_lzop_open(struct archive_write_filter *f)
 {
-       char * const argv[] = { "lzop", NULL };
+       struct write_lzop *data = (struct write_lzop *)f->data;
        int r;
 
-       r = __archive_write_programv(a, "lzop", ARCHIVE_FILTER_LZOP,
-               "lzop", argv);
-       /* Return ARCHIVE_WARN since this always uses an external program. */
-       if (r == ARCHIVE_OK)
-               r = ARCHIVE_WARN;
+       r = __archive_write_program_set_cmd(data->pdata, "lzop");
+       if (r != ARCHIVE_OK)
+               goto memerr;
+       r = __archive_write_program_add_arg(data->pdata, "lzop");
+       if (r != ARCHIVE_OK)
+               goto memerr;
+       r = __archive_write_program_open(f, data->pdata);
        return (r);
+memerr:
+       archive_set_error(f->archive, ENOMEM, "Can't allocate memory");
+       return (ARCHIVE_FATAL);
+}
+
+static int
+archive_write_lzop_write(struct archive_write_filter *f,
+    const void *buff, size_t length)
+{
+       struct write_lzop *data = (struct write_lzop *)f->data;
+
+       return __archive_write_program_write(f, data->pdata, buff, length);
+}
+
+static int
+archive_write_lzop_close(struct archive_write_filter *f)
+{
+       struct write_lzop *data = (struct write_lzop *)f->data;
+
+       return __archive_write_program_close(f, data->pdata);
+}
+
+static int
+archive_write_lzop_free(struct archive_write_filter *f)
+{
+       struct write_lzop *data = (struct write_lzop *)f->data;
+
+       __archive_write_program_free(data->pdata);
+       free(data);
+       return (ARCHIVE_OK);
 }
index cccf705977ea01551cc578ecfed821860903f9d7..d80442eff23a09a1d589ee560e68cd44557992e1 100644 (file)
@@ -58,10 +58,10 @@ archive_write_set_compression_program(struct archive *a, const char *cmd)
 }
 #endif
 
-struct private_data {
+struct archive_write_program_data {
        char            *cmd;
        char            **argv;
-       struct archive_string description;
+       int              argc;
 #if defined(_WIN32) && !defined(__CYGWIN__)
        HANDLE           child;
 #else
@@ -73,12 +73,19 @@ struct private_data {
        size_t           child_buf_len, child_buf_avail;
 };
 
+struct private_data {
+       struct archive_write_program_data *pdata;
+       struct archive_string description;
+};
+
 static int archive_compressor_program_open(struct archive_write_filter *);
 static int archive_compressor_program_write(struct archive_write_filter *,
                    const void *, size_t);
 static int archive_compressor_program_close(struct archive_write_filter *);
 static int archive_compressor_program_free(struct archive_write_filter *);
 
+static int init_filter_program(struct archive *,
+           struct archive_write_program_data *data);
 /*
  * Add a filter to this write handle that passes all data through an
  * external program.
@@ -86,81 +93,70 @@ static int archive_compressor_program_free(struct archive_write_filter *);
 int
 archive_write_add_filter_program(struct archive *_a, const char *cmd)
 {
-       char *argv[2];
+       struct archive_write_program_data *pdata;
        int r;
 
        archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
            ARCHIVE_STATE_NEW, "archive_write_add_filter_program");
 
-       argv[0] = strdup(cmd);
-       if (argv[0] == NULL) {
-               archive_set_error(_a, ENOMEM,
-                   "Can't allocate memory for filter program");
-               return (ARCHIVE_FATAL);
-       }
-       argv[1] = NULL;
-       r = __archive_write_programv(_a, NULL, ARCHIVE_FILTER_PROGRAM,
-               cmd, argv);
-       free(argv[0]);
-       return (r);
+       pdata = __archive_write_program_allocate();
+       if (pdata == NULL)
+               goto memerr;
+       r = __archive_write_program_set_cmd(pdata, cmd);
+       if (r != ARCHIVE_OK)
+               goto memerr;
+       r = __archive_write_program_add_arg(pdata, cmd);
+       if (r != ARCHIVE_OK)
+               goto memerr;
+       r = init_filter_program(_a, pdata);
+       if (r == ARCHIVE_OK)
+               return (r);
+memerr:
+       __archive_write_program_free(pdata);
+       archive_set_error(_a, ENOMEM,
+           "Can't allocate memory for filter program");
+       return (ARCHIVE_FATAL);
 }
 
 int
 archive_write_add_filter_programl(struct archive *_a, const char *cmd,
     const char *arg, ...)
 {
+       struct archive_write_program_data *pdata;
        va_list ap;
-       char **argv;
        char *val;
-       int i, r;
+       int r;
 
        archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
            ARCHIVE_STATE_NEW, "archive_write_add_filter_programl");
 
-       i = 2;
-       if (arg != NULL) {
-               va_start(ap, arg);
-               while (va_arg(ap, char *) != NULL)
-                       i++;
-               va_end(ap);
-       }
-       argv = malloc(i * sizeof(char *));
-       if (argv == NULL)
+       pdata = __archive_write_program_allocate();
+       if (pdata == NULL)
+               goto memerr;
+       r = __archive_write_program_set_cmd(pdata, cmd);
+       if (r != ARCHIVE_OK)
                goto memerr;
-
        if (arg != NULL) {
-               argv[0] = strdup(arg);
-               if (argv[0] == NULL)
+               r = __archive_write_program_add_arg(pdata, arg);
+               if (r != ARCHIVE_OK)
                        goto memerr;
-               i = 1;
                va_start(ap, arg);
                while ((val = va_arg(ap, char *)) != NULL) {
-                       argv[i] = strdup(val);
-                       if (argv[i] == NULL)
+                       r = __archive_write_program_add_arg(pdata, val);
+                       if (r != ARCHIVE_OK)
                                goto memerr;
-                       i++;    
                }
                va_end(ap);
-               argv[i] = NULL;
        } else {
-               argv[0] = strdup(cmd);
-               if (argv[0] == NULL)
+               r = __archive_write_program_add_arg(pdata, cmd);
+               if (r != ARCHIVE_OK)
                        goto memerr;
-               argv[1] = NULL;
        }
-
-       r = __archive_write_programv(_a, NULL, ARCHIVE_FILTER_PROGRAM,
-               cmd, argv);
-       for (i = 0; argv[i] != NULL; i++)
-               free(argv[i]);
-       free(argv);
-       return (r);
+       r = init_filter_program(_a, pdata);
+       if (r == ARCHIVE_OK)
+               return (r);
 memerr:
-       if (argv) {
-               for (i = 0; argv[i] != NULL; i++)
-                       free(argv[i]);
-               free(argv);
-       }
+       __archive_write_program_free(pdata);
        archive_set_error(_a, ENOMEM,
            "Can't allocate memory for filter program");
        return (ARCHIVE_FATAL);
@@ -170,17 +166,44 @@ int
 archive_write_add_filter_programv(struct archive *_a, const char *cmd,
     char * const argv[])
 {
+       struct archive_write_program_data *pdata;
+       int i, r;
 
        archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
            ARCHIVE_STATE_NEW, "archive_write_add_filter_programv");
 
-       return __archive_write_programv(_a, NULL, ARCHIVE_FILTER_PROGRAM,
-                  cmd, argv);
+       pdata = __archive_write_program_allocate();
+       if (pdata == NULL)
+               goto memerr;
+       r = __archive_write_program_set_cmd(pdata, cmd);
+       if (r != ARCHIVE_OK)
+               goto memerr;
+       for (i = 0; argv[i] != NULL; i++) {
+               r = __archive_write_program_add_arg(pdata, argv[i]);
+               if (r != ARCHIVE_OK)
+                       goto memerr;
+       }
+       if (i == 0) {
+               r = __archive_write_program_add_arg(pdata, cmd);
+               if (r != ARCHIVE_OK)
+                       goto memerr;
+       }
+       r = init_filter_program(_a, pdata);
+       if (r == ARCHIVE_OK)
+               return (r);
+memerr:
+       __archive_write_program_free(pdata);
+       archive_set_error(_a, ENOMEM,
+           "Can't allocate memory for filter program");
+       return (ARCHIVE_FATAL);
 }
 
-int
-__archive_write_programv(struct archive *_a, const char *name, int code,
-    const char *cmd, char * const argv[])
+/*
+ * Setup callback.
+ */
+static int
+init_filter_program(struct archive *_a,
+    struct archive_write_program_data *pdata)
 {
 
        struct archive_write_filter *f = __archive_write_allocate_filter(_a);
@@ -192,57 +215,162 @@ __archive_write_programv(struct archive *_a, const char *name, int code,
        data = calloc(1, sizeof(*data));
        if (data == NULL)
                goto memerr;
-       data->cmd = strdup(cmd);
-       if (data->cmd == NULL)
-               goto memerr;
+       l = strlen(prefix) + strlen(pdata->cmd) + 1;
+       for (i = 0; pdata->argv[i] != NULL; i++)
+               l += strlen(pdata->argv[i]) + 1;
 
-       /* Reproduce argv. */
-       for (i = 0; argv[i] != NULL; i++)
-               ;
-       data->argv = calloc(i + 1, sizeof(char *));
-       if (data->argv == NULL)
+       /* Make up a description string. */
+       if (archive_string_ensure(&data->description, l) == NULL)
                goto memerr;
-       l = strlen(prefix) + strlen(cmd) + 1;
-       for (i = 0; argv[i] != NULL; i++) {
-               data->argv[i] = strdup(argv[i]);
-               if (data->argv[i] == NULL)
-                       goto memerr;
-               l += strlen(data->argv[i]) + 1;
+       archive_strcpy(&data->description, prefix);
+       archive_strcat(&data->description, pdata->cmd);
+       for (i = 0; pdata->argv[i] != NULL; i++) {
+               archive_strappend_char(&data->description, ' ');
+               archive_strcat(&data->description, pdata->argv[i]);
        }
-
-       if (name == NULL) {
-               /* Make up a description string. */
-               if (archive_string_ensure(&data->description, l) == NULL)
-                       goto memerr;
-               archive_strcpy(&data->description, prefix);
-               archive_strcat(&data->description, cmd);
-               for (i = 0; argv[i] != NULL; i++) {
-                       archive_strappend_char(&data->description, ' ');
-                       archive_strcat(&data->description, data->argv[i]);
-               }
-               f->name = data->description.s;
-       } else
-               f->name = name;
-       f->code = code;
+       data->pdata = pdata;
+       f->name = data->description.s;
+       f->code = ARCHIVE_FILTER_PROGRAM;
        f->data = data;
-       f->open = &archive_compressor_program_open;
+       f->open = archive_compressor_program_open;
+       f->write = archive_compressor_program_write;
+       f->close = archive_compressor_program_close;
        f->free = archive_compressor_program_free;
        return (ARCHIVE_OK);
 memerr:
-       free(data);
        archive_compressor_program_free(f);
        archive_set_error(_a, ENOMEM,
            "Can't allocate memory for filter program");
        return (ARCHIVE_FATAL);
 }
 
-/*
- * Setup callback.
- */
 static int
 archive_compressor_program_open(struct archive_write_filter *f)
 {
        struct private_data *data = (struct private_data *)f->data;
+
+       return __archive_write_program_open(f, data->pdata);
+}
+
+static int
+archive_compressor_program_write(struct archive_write_filter *f,
+    const void *buff, size_t length)
+{
+       struct private_data *data = (struct private_data *)f->data;
+
+       return __archive_write_program_write(f, data->pdata, buff, length);
+}
+
+static int
+archive_compressor_program_close(struct archive_write_filter *f)
+{
+       struct private_data *data = (struct private_data *)f->data;
+
+       return __archive_write_program_close(f, data->pdata);
+}
+
+static int
+archive_compressor_program_free(struct archive_write_filter *f)
+{
+       struct private_data *data = (struct private_data *)f->data;
+
+       archive_string_free(&data->description);
+       __archive_write_program_free(data->pdata);
+       free(data);
+       return (ARCHIVE_OK);
+}
+
+/*
+ * Allocate resources for executing an external program.
+ */
+struct archive_write_program_data *
+__archive_write_program_allocate(void)
+{
+       struct archive_write_program_data *data;
+
+       data = calloc(1, sizeof(struct archive_write_program_data));
+       if (data == NULL)
+               return (data);
+       data->child_stdin = -1;
+       data->child_stdout = -1;
+       return (data);
+}
+
+/*
+ * Release the resources.
+ */
+int
+__archive_write_program_free(struct archive_write_program_data *data)
+{
+
+       if (data) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+               if (data->child)
+                       CloseHandle(data->child);
+#endif
+               free(data->cmd);
+               if (data->argv != NULL) {
+                       int i;
+                       for (i = 0; data->argv[i] != NULL; i++)
+                               free(data->argv[i]);
+                       free(data->argv);
+               }
+               free(data->child_buf);
+               free(data);
+       }
+       return (ARCHIVE_OK);
+}
+
+/*
+ * Set the program path.
+ */
+int
+__archive_write_program_set_cmd(struct archive_write_program_data *data,
+    const char *cmd)
+{
+       char *newptr;
+
+       newptr = realloc(data->cmd, strlen(cmd) + 1);
+       if (newptr == NULL)
+               return (ARCHIVE_FATAL);
+       data->cmd = newptr;
+       strcpy(data->cmd, cmd);
+       return (ARCHIVE_OK);
+}
+
+/*
+ * Add a argument for the program.
+ */
+int
+__archive_write_program_add_arg(struct archive_write_program_data *data,
+    const char *arg)
+{
+       char **newargv;
+       int i;
+
+       if (data->cmd == NULL)
+               return (ARCHIVE_FATAL);
+
+       newargv = realloc(data->argv, (data->argc + 2) * sizeof(char *));
+       if (newargv == NULL)
+               return (ARCHIVE_FATAL);
+       if (newargv != data->argv && data->argv != NULL) {
+               for (i = 0; i <= data->argc; i++)
+                       newargv[i] = data->argv[i];
+       }
+       data->argv = newargv;
+       data->argv[data->argc] = strdup(arg);
+       if (data->argv[data->argc] == NULL)
+               return (ARCHIVE_FATAL);
+       /* Set the terminator of argv. */
+       data->argv[++data->argc] = NULL;
+       return (ARCHIVE_OK);
+}
+
+int
+__archive_write_program_open(struct archive_write_filter *f,
+    struct archive_write_program_data *data)
+{
        pid_t child;
        int ret;
 
@@ -262,7 +390,7 @@ archive_compressor_program_open(struct archive_write_filter *f)
                }
        }
 
-       child = __archive_create_child(data->cmd, (char * const *)data->argv,
+       child = __archive_create_child(data->cmd, data->argv,
                 &data->child_stdin, &data->child_stdout);
        if (child == -1) {
                archive_set_error(f->archive, EINVAL,
@@ -283,16 +411,13 @@ archive_compressor_program_open(struct archive_write_filter *f)
 #else
        data->child = child;
 #endif
-
-       f->write = archive_compressor_program_write;
-       f->close = archive_compressor_program_close;
-       return (0);
+       return (ARCHIVE_OK);
 }
 
 static ssize_t
-child_write(struct archive_write_filter *f, const char *buf, size_t buf_len)
+child_write(struct archive_write_filter *f,
+    struct archive_write_program_data *data, const char *buf, size_t buf_len)
 {
-       struct private_data *data = f->data;
        ssize_t ret;
 
        if (data->child_stdin == -1)
@@ -355,18 +480,21 @@ child_write(struct archive_write_filter *f, const char *buf, size_t buf_len)
 }
 
 /*
- * Write data to the compressed stream.
+ * Write data to the filter stream.
  */
-static int
-archive_compressor_program_write(struct archive_write_filter *f,
-    const void *buff, size_t length)
+int
+__archive_write_program_write(struct archive_write_filter *f,
+    struct archive_write_program_data *data, const void *buff, size_t length)
 {
        ssize_t ret;
        const char *buf;
 
+       if (data->child == 0)
+               return (ARCHIVE_OK);
+
        buf = buff;
        while (length > 0) {
-               ret = child_write(f, buf, length);
+               ret = child_write(f, data, buf, length);
                if (ret == -1 || ret == 0) {
                        archive_set_error(f->archive, EIO,
                            "Can't write to filter");
@@ -378,17 +506,19 @@ archive_compressor_program_write(struct archive_write_filter *f,
        return (ARCHIVE_OK);
 }
 
-
 /*
- * Finish the compression...
+ * Finish the filtering...
  */
-static int
-archive_compressor_program_close(struct archive_write_filter *f)
+int
+__archive_write_program_close(struct archive_write_filter *f,
+    struct archive_write_program_data *data)
 {
-       struct private_data *data = (struct private_data *)f->data;
        int ret, r1, status;
        ssize_t bytes_read;
 
+       if (data->child == 0)
+               return (ARCHIVE_OK);
+
        ret = 0;
        close(data->child_stdin);
        data->child_stdin = -1;
@@ -443,27 +573,3 @@ cleanup:
        return (r1 < ret ? r1 : ret);
 }
 
-static int
-archive_compressor_program_free(struct archive_write_filter *f)
-{
-       struct private_data *data = (struct private_data *)f->data;
-
-       if (data) {
-#if defined(_WIN32) && !defined(__CYGWIN__)
-               if (data->child)
-                       CloseHandle(data->child);
-#endif
-               if (data->argv != NULL) {
-                       int i;
-                       for (i = 0; data->argv[i] != NULL; i++)
-                               free(data->argv[i]);
-                       free(data->argv);
-               }
-               free(data->cmd);
-               archive_string_free(&data->description);
-               free(data->child_buf);
-               free(data);
-               f->data = NULL;
-       }
-       return (ARCHIVE_OK);
-}
index 5a311f3ca11fbdcccfe185c06fcd952ab5b76f22..2f31428d4e0d1df53bb2864f98fab085934ec80a 100644 (file)
@@ -133,8 +133,17 @@ __archive_write_format_header_ustar(struct archive_write *, char buff[512],
     struct archive_entry *, int tartype, int strict,
     struct archive_string_conv *);
 
-int
-__archive_write_programv(struct archive *, const char *, int, const char *,
-    char * const *);
-
+struct archive_write_program_data;
+struct archive_write_program_data * __archive_write_program_allocate(void);
+int    __archive_write_program_free(struct archive_write_program_data *);
+int    __archive_write_program_open(struct archive_write_filter *,
+           struct archive_write_program_data *);
+int    __archive_write_program_close(struct archive_write_filter *,
+           struct archive_write_program_data *);
+int    __archive_write_program_write(struct archive_write_filter *,
+           struct archive_write_program_data *, const void *, size_t);
+int    __archive_write_program_set_cmd(struct archive_write_program_data *,
+           const char *);
+int    __archive_write_program_add_arg(struct archive_write_program_data *,
+           const char *);
 #endif