]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Introduce b64encode filter.
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Mon, 8 Oct 2012 03:38:04 +0000 (12:38 +0900)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Mon, 8 Oct 2012 04:06:57 +0000 (13:06 +0900)
17 files changed:
Makefile.am
cpio/cmdline.c
cpio/cpio.c
cpio/cpio.h
cpio/test/CMakeLists.txt
cpio/test/test_option_b64encode.c [new file with mode: 0644]
libarchive/CMakeLists.txt
libarchive/archive.h
libarchive/archive_write_add_filter_b64encode.c [new file with mode: 0644]
libarchive/test/CMakeLists.txt
libarchive/test/test_write_filter_b64encode.c [new file with mode: 0644]
tar/bsdtar.c
tar/bsdtar.h
tar/cmdline.c
tar/test/CMakeLists.txt
tar/test/test_option_b64encode.c [new file with mode: 0644]
tar/write.c

index c4c0f9ca961b44db5d57dde7f2716f11bd609bd8..4c408efbefd0d2f5cf7e40f4653c76e3163f49f9 100644 (file)
@@ -173,6 +173,7 @@ libarchive_la_SOURCES=                                              \
        libarchive/archive_write_open_memory.c                  \
        libarchive/archive_write_private.h                      \
        libarchive/archive_write_add_filter.c                   \
+       libarchive/archive_write_add_filter_b64encode.c         \
        libarchive/archive_write_add_filter_bzip2.c     \
        libarchive/archive_write_add_filter_compress.c  \
        libarchive/archive_write_add_filter_gzip.c              \
@@ -420,6 +421,7 @@ libarchive_test_SOURCES=                                    \
        libarchive/test/test_write_disk_sparse.c                \
        libarchive/test/test_write_disk_symlink.c               \
        libarchive/test/test_write_disk_times.c                 \
+       libarchive/test/test_write_filter_b64encode.c           \
        libarchive/test/test_write_filter_uuencode.c            \
        libarchive/test/test_write_format_7zip.c                \
        libarchive/test/test_write_format_ar.c                  \
@@ -724,6 +726,7 @@ bsdtar_test_SOURCES=                                                \
        tar/test/test_option_U_upper.c                          \
        tar/test/test_option_X_upper.c                          \
        tar/test/test_option_b.c                                \
+       tar/test/test_option_b64encode.c                        \
        tar/test/test_option_exclude.c                          \
        tar/test/test_option_gid_gname.c                        \
        tar/test/test_option_k.c                                \
@@ -848,6 +851,7 @@ bsdcpio_test_SOURCES=                                               \
        cpio/test/test_option_L_upper.c                         \
        cpio/test/test_option_Z_upper.c                         \
        cpio/test/test_option_a.c                               \
+       cpio/test/test_option_b64encode.c                       \
        cpio/test/test_option_c.c                               \
        cpio/test/test_option_d.c                               \
        cpio/test/test_option_f.c                               \
index 232aed6b8bc34a9ff0dce7c42ddeb8c0bda452df..3dff0b6b377aff034872c831b4e0f976aa53d335 100644 (file)
@@ -61,6 +61,7 @@ static const struct option {
        int required;   /* 1 if this option requires an argument */
        int equivalent; /* Equivalent short option. */
 } cpio_longopts[] = {
+       { "b64encode",                  0, OPTION_B64ENCODE },
        { "create",                     0, 'o' },
        { "dot",                        0, 'V' },
        { "extract",                    0, 'i' },
index 9feb5e3e28acf82da3e3345d0e75451b7e878874..89fc25bd08a4282f3c35e33b1e8f1270a1408e52 100644 (file)
@@ -207,6 +207,9 @@ main(int argc, char *argv[])
                case 'B': /* POSIX 1997 */
                        cpio->bytes_per_block = 5120;
                        break;
+               case OPTION_B64ENCODE:
+                       cpio->add_filter = opt;
+                       break;
                case 'C': /* NetBSD/OpenBSD */
                        cpio->bytes_per_block = atoi(cpio->argument);
                        if (cpio->bytes_per_block <= 0)
@@ -553,6 +556,9 @@ mode_out(struct cpio *cpio)
        case 0:
                r = ARCHIVE_OK;
                break;
+       case OPTION_B64ENCODE:
+               r = archive_write_add_filter_b64encode(cpio->archive);
+               break;
        case OPTION_UUENCODE:
                r = archive_write_add_filter_uuencode(cpio->archive);
                break;
index 31f038b7d9c8751c145c2a9dbf5f310f11194237..b1d89427fa0e2da0babf3011ae7fdffdd14c54c5 100644 (file)
@@ -97,7 +97,8 @@ const char *owner_parse(const char *, int *, int *);
 
 /* Fake short equivalents for long options that otherwise lack them. */
 enum {
-       OPTION_INSECURE = 1,
+       OPTION_B64ENCODE = 1,
+       OPTION_INSECURE,
        OPTION_LRZIP,
        OPTION_LZMA,
        OPTION_LZOP,
index 1c1ac89def50a9539fd1b9d05ffdbd5196fe9031..55a12e7a915e1d3caf876088efe43860affcc567 100644 (file)
@@ -22,6 +22,7 @@ IF(ENABLE_CPIO AND ENABLE_TEST)
     test_option_L_upper.c
     test_option_Z_upper.c
     test_option_a.c
+    test_option_b64encode.c
     test_option_c.c
     test_option_d.c
     test_option_f.c
diff --git a/cpio/test/test_option_b64encode.c b/cpio/test/test_option_b64encode.c
new file mode 100644 (file)
index 0000000..8f6b415
--- /dev/null
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2012 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+DEFINE_TEST(test_option_b64encode)
+{
+       char *p;
+       size_t s;
+
+       /* Create a file. */
+       assertMakeFile("f", 0644, "a");
+
+       /* Archive it with compress compression and uuencode. */
+       assertEqualInt(0,
+           systemf("echo f | %s -o -Z --b64encode >archive.out 2>archive.err",
+           testprog));
+       /* Check that the archive file has an uuencode signature. */
+       p = slurpfile(&s, "archive.out");
+       assert(s > 2);
+       assertEqualMem(p, "begin-base64 644", 16);
+
+       /* Archive it with uuencode only. */
+       assertEqualInt(0,
+           systemf("echo f | %s -o --b64encode >archive.out 2>archive.err",
+           testprog));
+       /* Check that the archive file has an uuencode signature. */
+       p = slurpfile(&s, "archive.out");
+       assert(s > 2);
+       assertEqualMem(p, "begin-base64 644", 16);
+}
index 14c77e2e8b37cf365c279e65ecc1951271991cbd..de2a40aa6c884660c81a969735a0aa9ce4e92dd9 100644 (file)
@@ -97,6 +97,7 @@ SET(libarchive_SOURCES
   archive_write_open_filename.c
   archive_write_open_memory.c
   archive_write_add_filter.c
+  archive_write_add_filter_b64encode.c
   archive_write_add_filter_bzip2.c
   archive_write_add_filter_compress.c
   archive_write_add_filter_gzip.c
index 3922bfa509275993c75ed0c3cdaa6a911e9e55f1..ae19c2505487696ffb3b6af7bebb2c6ae9b0a005 100644 (file)
@@ -613,6 +613,7 @@ __LA_DECL int archive_write_set_compression_xz(struct archive *);
 
 /* A convenience function to set the filter based on the code. */
 __LA_DECL int archive_write_add_filter(struct archive *, int filter_code);
+__LA_DECL int archive_write_add_filter_b64encode(struct archive *);
 __LA_DECL int archive_write_add_filter_bzip2(struct archive *);
 __LA_DECL int archive_write_add_filter_compress(struct archive *);
 __LA_DECL int archive_write_add_filter_gzip(struct archive *);
diff --git a/libarchive/archive_write_add_filter_b64encode.c b/libarchive/archive_write_add_filter_b64encode.c
new file mode 100644 (file)
index 0000000..85eb087
--- /dev/null
@@ -0,0 +1,314 @@
+/*-
+ * Copyright (c) 2012 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_string.h"
+#include "archive_write_private.h"
+
+#define LBYTES 57
+
+struct private_b64encode {
+       int                     mode;
+       struct archive_string   name;
+       struct archive_string   encoded_buff;
+       size_t                  bs;
+       size_t                  hold_len;
+       unsigned char           hold[LBYTES];
+};
+
+static int archive_filter_b64encode_options(struct archive_write_filter *,
+    const char *, const char *);
+static int archive_filter_b64encode_open(struct archive_write_filter *);
+static int archive_filter_b64encode_write(struct archive_write_filter *,
+    const void *, size_t);
+static int archive_filter_b64encode_close(struct archive_write_filter *);
+static int archive_filter_b64encode_free(struct archive_write_filter *);
+static void b64_encode(struct archive_string *, const unsigned char *, size_t);
+static int64_t atol8(const char *, size_t);
+
+static const char base64[] = {
+       'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+       'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+       'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+       'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+       'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+       'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+       'w', 'x', 'y', 'z', '0', '1', '2', '3',
+       '4', '5', '6', '7', '8', '9', '+', '/'
+};
+
+/*
+ * Add a compress filter to this write handle.
+ */
+int
+archive_write_add_filter_b64encode(struct archive *_a)
+{
+       struct archive_write *a = (struct archive_write *)_a;
+       struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+       struct private_b64encode *state;
+
+       archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+           ARCHIVE_STATE_NEW, "archive_write_add_filter_uu");
+
+       state = (struct private_b64encode *)calloc(1, sizeof(*state));
+       if (state == NULL) {
+               archive_set_error(f->archive, ENOMEM,
+                   "Can't allocate data for b64encode filter");
+               return (ARCHIVE_FATAL);
+       }
+       archive_strcpy(&state->name, "-");
+       state->mode = 0644;
+
+       f->data = state;
+       f->name = "b64encode";
+       f->code = ARCHIVE_FILTER_UU;
+       f->open = archive_filter_b64encode_open;
+       f->options = archive_filter_b64encode_options;
+       f->write = archive_filter_b64encode_write;
+       f->close = archive_filter_b64encode_close;
+       f->free = archive_filter_b64encode_free;
+
+       return (ARCHIVE_OK);
+}
+
+/*
+ * Set write options.
+ */
+static int
+archive_filter_b64encode_options(struct archive_write_filter *f, const char *key,
+    const char *value)
+{
+       struct private_b64encode *state = (struct private_b64encode *)f->data;
+
+       if (strcmp(key, "mode") == 0) {
+               if (value == NULL) {
+                       archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+                           "mode option requires octal digits");
+                       return (ARCHIVE_FAILED);
+               }
+               state->mode = (int)atol8(value, strlen(value)) & 0777;
+               return (ARCHIVE_OK);
+       } else if (strcmp(key, "name") == 0) {
+               if (value == NULL) {
+                       archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+                           "name option requires a string");
+                       return (ARCHIVE_FAILED);
+               }
+               archive_strcpy(&state->name, value);
+               return (ARCHIVE_OK);
+       }
+
+       /* 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);
+}
+
+/*
+ * Setup callback.
+ */
+static int
+archive_filter_b64encode_open(struct archive_write_filter *f)
+{
+       struct private_b64encode *state = (struct private_b64encode *)f->data;
+       size_t bs = 65536, bpb;
+       int ret;
+
+       ret = __archive_write_open_filter(f->next_filter);
+       if (ret != ARCHIVE_OK)
+               return (ret);
+
+       if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
+               /* Buffer size should be a multiple number of the of bytes
+                * per block for performance. */
+               bpb = archive_write_get_bytes_per_block(f->archive);
+               if (bpb > bs)
+                       bs = bpb;
+               else if (bpb != 0)
+                       bs -= bs % bpb;
+       }
+
+       state->bs = bs;
+       if (archive_string_ensure(&state->encoded_buff, bs + 512) == NULL) {
+               archive_set_error(f->archive, ENOMEM,
+                   "Can't allocate data for b64encode buffer");
+               return (ARCHIVE_FATAL);
+       }
+
+       archive_string_sprintf(&state->encoded_buff, "begin-base64 %o %s\n",
+           state->mode, state->name.s);
+
+       f->data = state;
+       return (0);
+}
+
+static void
+b64_encode(struct archive_string *as, const unsigned char *p, size_t len)
+{
+       int c;
+
+       for (; len >= 3; p += 3, len -= 3) {
+               c = p[0] >> 2;
+               archive_strappend_char(as, base64[c]);
+               c = ((p[0] & 0x03) << 4) | ((p[1] & 0xf0) >> 4);
+               archive_strappend_char(as, base64[c]);
+               c = ((p[1] & 0x0f) << 2) | ((p[2] & 0xc0) >> 6);
+               archive_strappend_char(as, base64[c]);
+               c = p[2] & 0x3f;
+               archive_strappend_char(as, base64[c]);
+       }
+       if (len > 0) {
+               c = p[0] >> 2;
+               archive_strappend_char(as, base64[c]);
+               c = (p[0] & 0x03) << 4;
+               if (len == 1) {
+                       archive_strappend_char(as, base64[c]);
+                       archive_strappend_char(as, '=');
+                       archive_strappend_char(as, '=');
+               } else {
+                       c |= (p[1] & 0xf0) >> 4;
+                       archive_strappend_char(as, base64[c]);
+                       c = (p[1] & 0x0f) << 2;
+                       archive_strappend_char(as, base64[c]);
+                       archive_strappend_char(as, '=');
+               }
+       }
+       archive_strappend_char(as, '\n');
+}
+
+/*
+ * Write data to the encoded stream.
+ */
+static int
+archive_filter_b64encode_write(struct archive_write_filter *f, const void *buff,
+    size_t length)
+{
+       struct private_b64encode *state = (struct private_b64encode *)f->data;
+       const unsigned char *p = buff;
+       int ret = ARCHIVE_OK;
+
+       if (length == 0)
+               return (ret);
+
+       if (state->hold_len) {
+               while (state->hold_len < LBYTES && length > 0) {
+                       state->hold[state->hold_len++] = *p++;
+                       length--;
+               }
+               if (state->hold_len < LBYTES)
+                       return (ret);
+               b64_encode(&state->encoded_buff, state->hold, LBYTES);
+               state->hold_len = 0;
+       }
+
+       for (; length >= LBYTES; length -= LBYTES, p += LBYTES)
+               b64_encode(&state->encoded_buff, p, LBYTES);
+
+       /* Save remaining bytes. */
+       if (length > 0) {
+               memcpy(state->hold, p, length);
+               state->hold_len = length;
+       }
+       while (archive_strlen(&state->encoded_buff) >= state->bs) {
+               ret = __archive_write_filter(f->next_filter,
+                   state->encoded_buff.s, state->bs);
+               memmove(state->encoded_buff.s,
+                   state->encoded_buff.s + state->bs,
+                   state->encoded_buff.length - state->bs);
+               state->encoded_buff.length -= state->bs;
+       }
+
+       return (ret);
+}
+
+
+/*
+ * Finish the compression...
+ */
+static int
+archive_filter_b64encode_close(struct archive_write_filter *f)
+{
+       struct private_b64encode *state = (struct private_b64encode *)f->data;
+       int ret, ret2;
+
+       /* Flush remaining bytes. */
+       if (state->hold_len != 0)
+               b64_encode(&state->encoded_buff, state->hold, state->hold_len);
+       archive_string_sprintf(&state->encoded_buff, "====\n");
+       /* Write the last block */
+       archive_write_set_bytes_in_last_block(f->archive, 1);
+       ret = __archive_write_filter(f->next_filter,
+           state->encoded_buff.s, archive_strlen(&state->encoded_buff));
+       ret2 = __archive_write_close_filter(f->next_filter);
+       if (ret > ret2)
+               ret = ret2;
+       return (ret);
+}
+
+static int
+archive_filter_b64encode_free(struct archive_write_filter *f)
+{
+       struct private_b64encode *state = (struct private_b64encode *)f->data;
+
+       archive_string_free(&state->name);
+       archive_string_free(&state->encoded_buff);
+       free(state);
+       return (ARCHIVE_OK);
+}
+
+static int64_t
+atol8(const char *p, size_t char_cnt)
+{
+       int64_t l;
+       int digit;
+        
+       l = 0;
+       while (char_cnt-- > 0) {
+               if (*p >= '0' && *p <= '7')
+                       digit = *p - '0';
+               else
+                       break;
+               p++;
+               l <<= 3;
+               l |= digit;
+       }
+       return (l);
+}
+
index ed14646851f4f1e3c5b126957e0505b0982c7498..5cd6bb2cd5eb841a20e31b5fb4026a31ff6cdd30 100644 (file)
@@ -162,6 +162,7 @@ IF(ENABLE_TEST)
     test_write_disk_sparse.c
     test_write_disk_symlink.c
     test_write_disk_times.c
+    test_write_filter_b64encode.c
     test_write_filter_uuencode.c
     test_write_format_7zip.c
     test_write_format_ar.c
diff --git a/libarchive/test/test_write_filter_b64encode.c b/libarchive/test/test_write_filter_b64encode.c
new file mode 100644 (file)
index 0000000..665087b
--- /dev/null
@@ -0,0 +1,173 @@
+/*-
+ * Copyright (c) 2012 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+/*
+ * A basic exercise of b64encode reading and writing.
+ */
+
+DEFINE_TEST(test_write_filter_b64encode)
+{
+       struct archive_entry *ae;
+       struct archive* a;
+       char *buff, *data;
+       size_t buffsize, datasize;
+       char path[16];
+       size_t used1, used2;
+       int i;
+
+       buffsize = 2000000;
+       assert(NULL != (buff = (char *)malloc(buffsize)));
+
+       datasize = 10000;
+       assert(NULL != (data = (char *)malloc(datasize)));
+       memset(data, 0, datasize);
+
+       /*
+        * Write a 100 files and read them all back.
+        */
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_b64encode(a));
+       assertEqualIntA(a, ARCHIVE_OK,
+           archive_write_set_bytes_per_block(a, 10));
+       assertEqualInt(ARCHIVE_FILTER_UU, archive_filter_code(a, 0));
+       assertEqualString("b64encode", archive_filter_name(a, 0));
+       assertEqualIntA(a, ARCHIVE_OK,
+           archive_write_open_memory(a, buff, buffsize, &used1));
+       for (i = 0; i < 99; i++) {
+               assert((ae = archive_entry_new()) != NULL);
+               archive_entry_set_filetype(ae, AE_IFREG);
+               archive_entry_set_size(ae, datasize);
+               sprintf(path, "file%03d", i);
+               archive_entry_copy_pathname(ae, path);
+               assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
+               assertA(datasize
+                   == (size_t)archive_write_data(a, data, datasize));
+               archive_entry_free(ae);
+       }
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used1));
+       for (i = 0; i < 99; i++) {
+               sprintf(path, "file%03d", i);
+               if (!assertEqualIntA(a, 0, archive_read_next_header(a, &ae)))
+                       break;
+               assertEqualString(path, archive_entry_pathname(ae));
+               assertEqualInt((int)datasize, archive_entry_size(ae));
+       }
+       assertEqualInt(ARCHIVE_FILTER_UU, archive_filter_code(a, 0));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+       assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+
+       /*
+        * Repeat the cycle again, this time setting name and mode
+        * options.
+        */
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
+       assertEqualIntA(a, ARCHIVE_OK,
+           archive_write_set_bytes_per_block(a, 10));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_b64encode(a));
+       assertEqualIntA(a, ARCHIVE_FAILED,
+           archive_write_set_filter_option(a, NULL, "nonexistent-option", "0"));
+       assertEqualIntA(a, ARCHIVE_FAILED,
+           archive_write_set_filter_option(a, NULL, "compression-level", "abc"));
+       assertEqualIntA(a, ARCHIVE_FAILED,
+           archive_write_set_filter_option(a, NULL, "compression-level", "99"));
+       assertEqualIntA(a, ARCHIVE_OK,
+           archive_write_set_filter_option(a, NULL, "name", "test.tar"));
+       assertEqualIntA(a, ARCHIVE_OK,
+           archive_write_set_filter_option(a, NULL, "mode", "0640"));
+       assertEqualIntA(a, ARCHIVE_OK,
+           archive_write_open_memory(a, buff, buffsize, &used2));
+       for (i = 0; i < 99; i++) {
+               sprintf(path, "file%03d", i);
+               assert((ae = archive_entry_new()) != NULL);
+               archive_entry_copy_pathname(ae, path);
+               archive_entry_set_size(ae, datasize);
+               archive_entry_set_filetype(ae, AE_IFREG);
+               assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
+               assertA(datasize == (size_t)archive_write_data(a, data, datasize));
+               archive_entry_free(ae);
+       }
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+       assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_read_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used2));
+       for (i = 0; i < 99; i++) {
+               sprintf(path, "file%03d", i);
+               if (!assertEqualInt(0, archive_read_next_header(a, &ae)))
+                       break;
+               assertEqualString(path, archive_entry_pathname(ae));
+               assertEqualInt((int)datasize, archive_entry_size(ae));
+       }
+       assertEqualInt(ARCHIVE_FILTER_UU, archive_filter_code(a, 0));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+       assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+
+       /*
+        * Test various premature shutdown scenarios to make sure we
+        * don't crash or leak memory.
+        */
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_b64encode(a));
+       assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_b64encode(a));
+       assertEqualInt(ARCHIVE_OK, archive_write_close(a));
+       assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_b64encode(a));
+       assertEqualInt(ARCHIVE_OK, archive_write_close(a));
+       assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+
+       assert((a = archive_write_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_b64encode(a));
+       assertEqualIntA(a, ARCHIVE_OK,
+           archive_write_open_memory(a, buff, buffsize, &used2));
+       assertEqualInt(ARCHIVE_OK, archive_write_close(a));
+       assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+
+       /*
+        * Clean up.
+        */
+       free(data);
+       free(buff);
+}
index 4b167a85e90ee67b07ddcbeb361b5e73a0f23540..2b572315f4dcc1ae4a6b717d35e815a64a2406a3 100644 (file)
@@ -267,6 +267,13 @@ main(int argc, char **argv)
                        /* Explicit -b forces last block size. */
                        bsdtar->bytes_in_last_block = bsdtar->bytes_per_block;
                        break;
+               case OPTION_B64ENCODE:
+                       if (bsdtar->add_filter != '\0')
+                               lafe_errc(1, 0,
+                                   "Can't specify both --uuencode and "
+                                   "--b64encode");
+                       bsdtar->add_filter = opt;
+                       break;
                case 'C': /* GNU tar */
                        if (strlen(bsdtar->argument) == 0)
                                lafe_errc(1, 0,
@@ -573,6 +580,10 @@ main(int argc, char **argv)
                        bsdtar->uname = bsdtar->argument;
                        break;
                case OPTION_UUENCODE:
+                       if (bsdtar->add_filter != '\0')
+                               lafe_errc(1, 0,
+                                   "Can't specify both --uuencode and "
+                                   "--b64encode");
                        bsdtar->add_filter = opt;
                        break;
                case 'v': /* SUSv2 */
index 91af45214c88e870bbc95c97b92aa7bb905b3c0c..80e922ea2be95096cb25ba40e775b4adce7dc920 100644 (file)
@@ -112,7 +112,8 @@ struct bsdtar {
 
 /* Fake short equivalents for long options that otherwise lack them. */
 enum {
-       OPTION_CHECK_LINKS = 1,
+       OPTION_B64ENCODE = 1,
+       OPTION_CHECK_LINKS,
        OPTION_CHROOT,
        OPTION_DISABLE_COPYFILE,
        OPTION_EXCLUDE,
index 05d4e2616b3d75e934b09b5ddbb7f9f843d3b862..684e28bfda7840681c426ca0b4e32da8cc42310c 100644 (file)
@@ -65,6 +65,7 @@ static const struct bsdtar_option {
 } tar_longopts[] = {
        { "absolute-paths",       0, 'P' },
        { "append",               0, 'r' },
+       { "b64encode",            0, OPTION_B64ENCODE },
        { "block-size",           1, 'b' },
        { "bunzip2",              0, 'j' },
        { "bzip",                 0, 'j' },
index 6ff9036c996f4ca2b929ef4ae74b6b6c36ee96cd..03ab7c19effa3dc9d0ee6daa357c46ee22cb8fcd 100644 (file)
@@ -28,6 +28,7 @@ IF(ENABLE_TAR AND ENABLE_TEST)
     test_option_U_upper.c
     test_option_X_upper.c
     test_option_b.c
+    test_option_b64encode.c
     test_option_exclude.c
     test_option_gid_gname.c
     test_option_k.c
diff --git a/tar/test/test_option_b64encode.c b/tar/test/test_option_b64encode.c
new file mode 100644 (file)
index 0000000..1e7c571
--- /dev/null
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2012 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+DEFINE_TEST(test_option_b64encode)
+{
+       char *p;
+       size_t s;
+
+       /* Create a file. */
+       assertMakeFile("f", 0644, "a");
+
+       /* Archive it with compress compression and uuencode. */
+       assertEqualInt(0,
+           systemf("%s -cf - -Z --b64encode f >archive.out 2>archive.err",
+           testprog));
+       /* Check that the archive file has an uuencode signature. */
+       p = slurpfile(&s, "archive.out");
+       assert(s > 2);
+       assertEqualMem(p, "begin-base64 644", 16);
+
+       /* Archive it with uuencode only. */
+       assertEqualInt(0,
+           systemf("%s -cf - --b64encode f >archive.out 2>archive.err",
+           testprog));
+       /* Check that the archive file has an uuencode signature. */
+       p = slurpfile(&s, "archive.out");
+       assert(s > 2);
+       assertEqualMem(p, "begin-base64 644", 16);
+}
index 89fdc85596c835524bcc03421bf05cdd2a1453aa..5c8cffb0c92d8468af002b91c191225e517acc64 100644 (file)
@@ -168,7 +168,7 @@ tar_mode_c(struct bsdtar *bsdtar)
        if (bsdtar->compress_program) {
                archive_write_add_filter_program(a, bsdtar->compress_program);
        } else {
-               const char *name;
+               const char *name = "?";
 
                switch (bsdtar->create_compression) {
                case 0:
@@ -212,6 +212,10 @@ tar_mode_c(struct bsdtar *bsdtar)
                case 0:
                        r = ARCHIVE_OK;
                        break;
+               case OPTION_B64ENCODE:
+                       r = archive_write_add_filter_b64encode(a);
+                       name = "b64encode";
+                       break;
                case OPTION_UUENCODE:
                        r = archive_write_add_filter_uuencode(a);
                        name = "uuencode";