]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Stackable write filter support. This ended up touching an awful lot
authorTim Kientzle <kientzle@gmail.com>
Sat, 20 Feb 2010 05:53:11 +0000 (00:53 -0500)
committerTim Kientzle <kientzle@gmail.com>
Sat, 20 Feb 2010 05:53:11 +0000 (00:53 -0500)
of files.  But, the old API is supported almost entirely unchanged, which
I wasn't certain would be possible.

Big changes:
  * You can add more than one write filter by using
    archive_write_add_filter_{bzip2,compress,gzip,lzma,xz}.
    This will be more interesting when we have uuencode, RPM, encryption.
  * The old archive_write_set_compression_XXXX are shorthands for
    "remove all the current filters and add this one."  They're
    deprecated and scheduled to be removed in libarchive 4.0.
  * The internal API and life cycle for write filters has been
    rationalized: create, set options, open, write, close, free.
  * New utility functions provide information about each filter
    when there's more than one:  code, name, and number of bytes processed
  * Old archive_bytes_compressed(), etc, are implemented in terms of
    the more generic new functions.
  * The read side was generalized to also support the new utility
    functions.

In particular, the write filters are much simpler since each
one doesn't have to deal with blocking.  In this version, there's
still a "write_add_filter_none" that handles blocking, but I
think I'll soon fold that down into the client wrapper and
add_filter_none will become a no-op.  I think this also gets
us a big step closer to multi-volume support on the write side.

SVN-Revision: 1920

35 files changed:
Makefile.am
build/autogen.sh
libarchive/CMakeLists.txt
libarchive/archive.h
libarchive/archive_entry.h
libarchive/archive_entry_copy_stat.c
libarchive/archive_private.h
libarchive/archive_read.c
libarchive/archive_read_private.h
libarchive/archive_read_support_compression_bzip2.c
libarchive/archive_read_support_format_ar.c
libarchive/archive_util.3
libarchive/archive_util.c
libarchive/archive_virtual.c
libarchive/archive_write.c
libarchive/archive_write_add_filter_bzip2.c [new file with mode: 0644]
libarchive/archive_write_add_filter_compress.c [moved from libarchive/archive_write_set_compression_compress.c with 70% similarity]
libarchive/archive_write_add_filter_gzip.c [new file with mode: 0644]
libarchive/archive_write_add_filter_none.c [moved from libarchive/archive_write_set_compression_none.c with 57% similarity]
libarchive/archive_write_add_filter_program.c [new file with mode: 0644]
libarchive/archive_write_add_filter_xz.c [new file with mode: 0644]
libarchive/archive_write_disk.c
libarchive/archive_write_private.h
libarchive/archive_write_set_compression_bzip2.c [deleted file]
libarchive/archive_write_set_compression_gzip.c [deleted file]
libarchive/archive_write_set_compression_program.c [deleted file]
libarchive/archive_write_set_compression_xz.c [deleted file]
libarchive/archive_write_set_format_ar.c
libarchive/archive_write_set_format_cpio.c
libarchive/archive_write_set_format_cpio_newc.c
libarchive/archive_write_set_format_mtree.c
libarchive/archive_write_set_format_pax.c
libarchive/archive_write_set_format_shar.c
libarchive/archive_write_set_format_ustar.c
libarchive/archive_write_set_format_zip.c

index 3ad407d088bcccf3c17445577819209c0dc2405e..e59e7c1138a39fed71db371e751adfbd1e8d588b 100644 (file)
@@ -151,12 +151,12 @@ libarchive_la_SOURCES=                                            \
        libarchive/archive_write_open_filename.c                \
        libarchive/archive_write_open_memory.c                  \
        libarchive/archive_write_private.h                      \
-       libarchive/archive_write_set_compression_bzip2.c        \
-       libarchive/archive_write_set_compression_compress.c     \
-       libarchive/archive_write_set_compression_gzip.c         \
-       libarchive/archive_write_set_compression_none.c         \
-       libarchive/archive_write_set_compression_program.c      \
-       libarchive/archive_write_set_compression_xz.c           \
+       libarchive/archive_write_add_filter_bzip2.c     \
+       libarchive/archive_write_add_filter_compress.c  \
+       libarchive/archive_write_add_filter_gzip.c              \
+       libarchive/archive_write_add_filter_none.c              \
+       libarchive/archive_write_add_filter_program.c   \
+       libarchive/archive_write_add_filter_xz.c                \
        libarchive/archive_write_set_format.c                   \
        libarchive/archive_write_set_format_ar.c                \
        libarchive/archive_write_set_format_by_name.c           \
index 8a9c9deb96c8839986d62ff2334ae1c6f3bbf6ee..dde976fcd72263e97d7ff21aeb22503eea0573b7 100755 (executable)
@@ -40,8 +40,9 @@ cd ..
 # Clean up the source dir as much as we can.
 /bin/sh build/clean.sh
 
-# Substitute the integer version into Libarchive's archive.h
+# Substitute the versions into Libarchive's archive.h and archive_entry.h
 perl -p -i -e "s/^(#define\tARCHIVE_VERSION_NUMBER).*/\$1 $VN/" libarchive/archive.h
+perl -p -i -e "s/^(#define\tARCHIVE_VERSION_NUMBER).*/\$1 $VN/" libarchive/archive_entry.h
 perl -p -i -e "s/^(#define\tARCHIVE_VERSION_STRING).*/\$1 \"libarchive $VS\"/" libarchive/archive.h
 # Substitute versions into configure.ac as well
 perl -p -i -e 's/(m4_define\(\[LIBARCHIVE_VERSION_S\]),.*\)/$1,['"$VS"'])/' configure.ac
index 0ca57e616124974d8f41f9d19f163f9e826b7393..82b921b2244ecaca44b7c954434e1061c56ae4b4 100644 (file)
@@ -72,12 +72,12 @@ SET(libarchive_SOURCES
   archive_write_open_file.c
   archive_write_open_filename.c
   archive_write_open_memory.c
-  archive_write_set_compression_bzip2.c
-  archive_write_set_compression_compress.c
-  archive_write_set_compression_gzip.c
-  archive_write_set_compression_none.c
-  archive_write_set_compression_program.c
-  archive_write_set_compression_xz.c
+  archive_write_add_filter_bzip2.c
+  archive_write_add_filter_compress.c
+  archive_write_add_filter_gzip.c
+  archive_write_add_filter_none.c
+  archive_write_add_filter_program.c
+  archive_write_add_filter_xz.c
   archive_write_set_format.c
   archive_write_set_format_ar.c
   archive_write_set_format_by_name.c
index e2c8b8c1f16319fecfe2a797c29ca83dfab004af..40bdbdf70099411f5929e6af8287e048d312023d 100644 (file)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2003-2010 Tim Kientzle
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -129,13 +129,13 @@ extern "C" {
  *             (ARCHIVE_API_VERSION * 1000000 + ARCHIVE_API_FEATURE * 1000)
  * #endif
  */
-#define        ARCHIVE_VERSION_NUMBER 2007902
+#define        ARCHIVE_VERSION_NUMBER 3000000
 __LA_DECL int          archive_version_number(void);
 
 /*
  * Textual name/version of the library, useful for version displays.
  */
-#define        ARCHIVE_VERSION_STRING "libarchive 2.7.902a"
+#define        ARCHIVE_VERSION_STRING "libarchive 3.0.0a"
 __LA_DECL const char * archive_version_string(void);
 
 #if ARCHIVE_VERSION_NUMBER < 3000000
@@ -221,25 +221,34 @@ typedef __LA_SSIZE_T      archive_write_callback(struct archive *,
                            void *_client_data,
                            const void *_buffer, size_t _length);
 
-#if ARCHIVE_VERSION_NUMBER < 3000000
-/* Open callback is actually never needed; remove it in libarchive 3.0. */
 typedef int    archive_open_callback(struct archive *, void *_client_data);
-#endif
 
 typedef int    archive_close_callback(struct archive *, void *_client_data);
 
 /*
- * Codes for archive_compression.
+ * Codes to identify various stream filters.
  */
-#define        ARCHIVE_COMPRESSION_NONE        0
-#define        ARCHIVE_COMPRESSION_GZIP        1
-#define        ARCHIVE_COMPRESSION_BZIP2       2
-#define        ARCHIVE_COMPRESSION_COMPRESS    3
-#define        ARCHIVE_COMPRESSION_PROGRAM     4
-#define        ARCHIVE_COMPRESSION_LZMA        5
-#define        ARCHIVE_COMPRESSION_XZ          6
-#define        ARCHIVE_COMPRESSION_UU          7
-#define        ARCHIVE_COMPRESSION_RPM         8
+#define        ARCHIVE_FILTER_NONE     0
+#define        ARCHIVE_FILTER_GZIP     1
+#define        ARCHIVE_FILTER_BZIP2    2
+#define        ARCHIVE_FILTER_COMPRESS 3
+#define        ARCHIVE_FILTER_PROGRAM  4
+#define        ARCHIVE_FILTER_LZMA     5
+#define        ARCHIVE_FILTER_XZ       6
+#define        ARCHIVE_FILTER_UU       7
+#define        ARCHIVE_FILTER_RPM      8
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+#define        ARCHIVE_COMPRESSION_NONE        ARCHIVE_FILTER_NONE
+#define        ARCHIVE_COMPRESSION_GZIP        ARCHIVE_FILTER_GZIP
+#define        ARCHIVE_COMPRESSION_BZIP2       ARCHIVE_FILTER_BZIP2
+#define        ARCHIVE_COMPRESSION_COMPRESS    ARCHIVE_FILTER_COMPRESS
+#define        ARCHIVE_COMPRESSION_PROGRAM     ARCHIVE_FILTER_PROGRAM
+#define        ARCHIVE_COMPRESSION_LZMA        ARCHIVE_FILTER_LZMA
+#define        ARCHIVE_COMPRESSION_XZ          ARCHIVE_FILTER_XZ
+#define        ARCHIVE_COMPRESSION_UU          ARCHIVE_FILTER_UU
+#define        ARCHIVE_COMPRESSION_RPM         ARCHIVE_FILTER_RPM
+#endif
 
 /*
  * Codes returned by archive_format.
@@ -305,40 +314,43 @@ __LA_DECL struct archive  *archive_read_new(void);
  * support_compression_bzip2().  The "all" functions provide the
  * obvious shorthand.
  */
-__LA_DECL int           archive_read_support_compression_all(struct archive *);
-__LA_DECL int           archive_read_support_compression_bzip2(struct archive *);
-__LA_DECL int           archive_read_support_compression_compress(struct archive *);
-__LA_DECL int           archive_read_support_compression_gzip(struct archive *);
-__LA_DECL int           archive_read_support_compression_lzma(struct archive *);
-__LA_DECL int           archive_read_support_compression_none(struct archive *);
-__LA_DECL int           archive_read_support_compression_program(struct archive *,
+/* TODO: Rename 'compression' here to 'filter' for libarchive 3.0, deprecate
+ * the old names. */
+
+__LA_DECL int archive_read_support_compression_all(struct archive *);
+__LA_DECL int archive_read_support_compression_bzip2(struct archive *);
+__LA_DECL int archive_read_support_compression_compress(struct archive *);
+__LA_DECL int archive_read_support_compression_gzip(struct archive *);
+__LA_DECL int archive_read_support_compression_lzma(struct archive *);
+__LA_DECL int archive_read_support_compression_none(struct archive *);
+__LA_DECL int archive_read_support_compression_program(struct archive *,
                     const char *command);
-__LA_DECL int           archive_read_support_compression_program_signature
-                               (struct archive *, const char *,
+__LA_DECL int archive_read_support_compression_program_signature
+               (struct archive *, const char *,
                                    const void * /* match */, size_t);
 
-__LA_DECL int           archive_read_support_compression_rpm(struct archive *);
-__LA_DECL int           archive_read_support_compression_uu(struct archive *);
-__LA_DECL int           archive_read_support_compression_xz(struct archive *);
+__LA_DECL int archive_read_support_compression_rpm(struct archive *);
+__LA_DECL int archive_read_support_compression_uu(struct archive *);
+__LA_DECL int archive_read_support_compression_xz(struct archive *);
 
-__LA_DECL int           archive_read_support_format_all(struct archive *);
-__LA_DECL int           archive_read_support_format_ar(struct archive *);
-__LA_DECL int           archive_read_support_format_cpio(struct archive *);
-__LA_DECL int           archive_read_support_format_empty(struct archive *);
-__LA_DECL int           archive_read_support_format_gnutar(struct archive *);
-__LA_DECL int           archive_read_support_format_iso9660(struct archive *);
-__LA_DECL int           archive_read_support_format_mtree(struct archive *);
-__LA_DECL int           archive_read_support_format_raw(struct archive *);
-__LA_DECL int           archive_read_support_format_tar(struct archive *);
-__LA_DECL int           archive_read_support_format_xar(struct archive *);
-__LA_DECL int           archive_read_support_format_zip(struct archive *);
+__LA_DECL int archive_read_support_format_all(struct archive *);
+__LA_DECL int archive_read_support_format_ar(struct archive *);
+__LA_DECL int archive_read_support_format_cpio(struct archive *);
+__LA_DECL int archive_read_support_format_empty(struct archive *);
+__LA_DECL int archive_read_support_format_gnutar(struct archive *);
+__LA_DECL int archive_read_support_format_iso9660(struct archive *);
+__LA_DECL int archive_read_support_format_mtree(struct archive *);
+__LA_DECL int archive_read_support_format_raw(struct archive *);
+__LA_DECL int archive_read_support_format_tar(struct archive *);
+__LA_DECL int archive_read_support_format_xar(struct archive *);
+__LA_DECL int archive_read_support_format_zip(struct archive *);
 
 
 /* Open the archive using callbacks for archive I/O. */
-__LA_DECL int           archive_read_open(struct archive *, void *_client_data,
+__LA_DECL int archive_read_open(struct archive *, void *_client_data,
                     archive_open_callback *, archive_read_callback *,
                     archive_close_callback *);
-__LA_DECL int           archive_read_open2(struct archive *, void *_client_data,
+__LA_DECL int archive_read_open2(struct archive *, void *_client_data,
                     archive_open_callback *, archive_read_callback *,
                     archive_skip_callback *, archive_close_callback *);
 
@@ -348,30 +360,30 @@ __LA_DECL int              archive_read_open2(struct archive *, void *_client_data,
  * accept a block size handle tape blocking correctly.
  */
 /* Use this if you know the filename.  Note: NULL indicates stdin. */
-__LA_DECL int           archive_read_open_filename(struct archive *,
+__LA_DECL int archive_read_open_filename(struct archive *,
                     const char *_filename, size_t _block_size);
 /* archive_read_open_file() is a deprecated synonym for ..._open_filename(). */
-__LA_DECL int           archive_read_open_file(struct archive *,
+__LA_DECL int archive_read_open_file(struct archive *,
                     const char *_filename, size_t _block_size);
 /* Read an archive that's stored in memory. */
-__LA_DECL int           archive_read_open_memory(struct archive *,
+__LA_DECL int archive_read_open_memory(struct archive *,
                     void * buff, size_t size);
 /* A more involved version that is only used for internal testing. */
-__LA_DECL int          archive_read_open_memory2(struct archive *a, void *buff,
+__LA_DECL int archive_read_open_memory2(struct archive *a, void *buff,
                     size_t size, size_t read_size);
 /* Read an archive that's already open, using the file descriptor. */
-__LA_DECL int           archive_read_open_fd(struct archive *, int _fd,
+__LA_DECL int archive_read_open_fd(struct archive *, int _fd,
                     size_t _block_size);
 /* Read an archive that's already open, using a FILE *. */
 /* Note: DO NOT use this with tape drives. */
-__LA_DECL int           archive_read_open_FILE(struct archive *, FILE *_file);
+__LA_DECL int archive_read_open_FILE(struct archive *, FILE *_file);
 
 /* Parses and returns next entry header. */
-__LA_DECL int           archive_read_next_header(struct archive *,
+__LA_DECL int archive_read_next_header(struct archive *,
                     struct archive_entry **);
 
 /* Parses and returns next entry header using the archive_entry passed in */
-__LA_DECL int           archive_read_next_header2(struct archive *,
+__LA_DECL int archive_read_next_header2(struct archive *,
                     struct archive_entry *);
 
 /*
@@ -391,12 +403,11 @@ __LA_DECL __LA_SSIZE_T             archive_read_data(struct archive *,
  * be strictly increasing and that returned blocks will not overlap.
  */
 #if ARCHIVE_VERSION_NUMBER < 3000000
-__LA_DECL int           archive_read_data_block(struct archive *a,
-                           const void **buff, size_t *size, off_t *offset);
+__LA_DECL int archive_read_data_block(struct archive *a,
+                   const void **buff, size_t *size, off_t *offset);
 #else
-__LA_DECL int           archive_read_data_block(struct archive *a,
-                           const void **buff, size_t *size,
-                           __LA_INT64_T *offset);
+__LA_DECL int archive_read_data_block(struct archive *a,
+                   const void **buff, size_t *size, __LA_INT64_T *offset);
 #endif
 
 /*-
@@ -405,22 +416,22 @@ __LA_DECL int              archive_read_data_block(struct archive *a,
  *  'into_buffer': writes data into memory buffer that you provide
  *  'into_fd': writes data to specified filedes
  */
-__LA_DECL int           archive_read_data_skip(struct archive *);
-__LA_DECL int           archive_read_data_into_buffer(struct archive *,
+__LA_DECL int archive_read_data_skip(struct archive *);
+__LA_DECL int archive_read_data_into_buffer(struct archive *,
                            void *buffer, __LA_SSIZE_T len);
-__LA_DECL int           archive_read_data_into_fd(struct archive *, int fd);
+__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,
+__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,
+__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,
+__LA_DECL int archive_read_set_options(struct archive *_a,
                            const char *s);
 
 /*-
@@ -467,9 +478,9 @@ __LA_DECL int               archive_read_set_options(struct archive *_a,
 /* Detect blocks of 0 and write holes instead. */
 #define        ARCHIVE_EXTRACT_SPARSE                  (0x1000)
 
-__LA_DECL int   archive_read_extract(struct archive *, struct archive_entry *,
+__LA_DECL int archive_read_extract(struct archive *, struct archive_entry *,
                     int flags);
-__LA_DECL int   archive_read_extract2(struct archive *, struct archive_entry *,
+__LA_DECL int archive_read_extract2(struct archive *, struct archive_entry *,
                     struct archive * /* dest */);
 __LA_DECL void  archive_read_extract_set_progress_callback(struct archive *,
                     void (*_progress_func)(void *), void *_user_data);
@@ -505,64 +516,76 @@ __LA_DECL int              archive_read_finish(struct archive *);
  *   6) archive_write_free to cleanup the writer and release resources
  */
 __LA_DECL struct archive       *archive_write_new(void);
-__LA_DECL int           archive_write_set_bytes_per_block(struct archive *,
+__LA_DECL int archive_write_set_bytes_per_block(struct archive *,
                     int bytes_per_block);
-__LA_DECL int           archive_write_get_bytes_per_block(struct archive *);
+__LA_DECL int archive_write_get_bytes_per_block(struct archive *);
 /* XXX This is badly misnamed; suggestions appreciated. XXX */
-__LA_DECL int           archive_write_set_bytes_in_last_block(struct archive *,
+__LA_DECL int archive_write_set_bytes_in_last_block(struct archive *,
                     int bytes_in_last_block);
-__LA_DECL int           archive_write_get_bytes_in_last_block(struct archive *);
+__LA_DECL int archive_write_get_bytes_in_last_block(struct archive *);
 
 /* The dev/ino of a file that won't be archived.  This is used
  * to avoid recursively adding an archive to itself. */
-__LA_DECL int           archive_write_set_skip_file(struct archive *, dev_t, ino_t);
-
-__LA_DECL int           archive_write_set_compression_bzip2(struct archive *);
-__LA_DECL int           archive_write_set_compression_compress(struct archive *);
-__LA_DECL int           archive_write_set_compression_gzip(struct archive *);
-__LA_DECL int           archive_write_set_compression_lzma(struct archive *);
-__LA_DECL int           archive_write_set_compression_none(struct archive *);
-__LA_DECL int           archive_write_set_compression_program(struct archive *,
+__LA_DECL int archive_write_set_skip_file(struct archive *, dev_t, ino_t);
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+__LA_DECL int archive_write_set_compression_bzip2(struct archive *);
+__LA_DECL int archive_write_set_compression_compress(struct archive *);
+__LA_DECL int archive_write_set_compression_gzip(struct archive *);
+__LA_DECL int archive_write_set_compression_lzma(struct archive *);
+__LA_DECL int archive_write_set_compression_none(struct archive *);
+__LA_DECL int archive_write_set_compression_program(struct archive *,
+                    const char *cmd);
+__LA_DECL int archive_write_set_compression_xz(struct archive *);
+#endif
+
+__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 *);
+__LA_DECL int archive_write_add_filter_lzma(struct archive *);
+__LA_DECL int archive_write_add_filter_none(struct archive *);
+__LA_DECL int archive_write_add_filter_program(struct archive *,
                     const char *cmd);
-__LA_DECL int           archive_write_set_compression_xz(struct archive *);
+__LA_DECL int archive_write_add_filter_xz(struct archive *);
+
+
 /* A convenience function to set the format based on the code or name. */
-__LA_DECL int           archive_write_set_format(struct archive *, int format_code);
-__LA_DECL int           archive_write_set_format_by_name(struct archive *,
+__LA_DECL int archive_write_set_format(struct archive *, int format_code);
+__LA_DECL int archive_write_set_format_by_name(struct archive *,
                     const char *name);
 /* To minimize link pollution, use one or more of the following. */
-__LA_DECL int           archive_write_set_format_ar_bsd(struct archive *);
-__LA_DECL int           archive_write_set_format_ar_svr4(struct archive *);
-__LA_DECL int           archive_write_set_format_cpio(struct archive *);
-__LA_DECL int           archive_write_set_format_cpio_newc(struct archive *);
-__LA_DECL int           archive_write_set_format_mtree(struct archive *);
+__LA_DECL int archive_write_set_format_ar_bsd(struct archive *);
+__LA_DECL int archive_write_set_format_ar_svr4(struct archive *);
+__LA_DECL int archive_write_set_format_cpio(struct archive *);
+__LA_DECL int archive_write_set_format_cpio_newc(struct archive *);
+__LA_DECL int archive_write_set_format_mtree(struct archive *);
 /* TODO: int archive_write_set_format_old_tar(struct archive *); */
-__LA_DECL int           archive_write_set_format_pax(struct archive *);
-__LA_DECL int           archive_write_set_format_pax_restricted(struct archive *);
-__LA_DECL int           archive_write_set_format_shar(struct archive *);
-__LA_DECL int           archive_write_set_format_shar_dump(struct archive *);
-__LA_DECL int           archive_write_set_format_ustar(struct archive *);
-__LA_DECL int           archive_write_set_format_zip(struct archive *);
-__LA_DECL int           archive_write_open(struct archive *, void *,
+__LA_DECL int archive_write_set_format_pax(struct archive *);
+__LA_DECL int archive_write_set_format_pax_restricted(struct archive *);
+__LA_DECL int archive_write_set_format_shar(struct archive *);
+__LA_DECL int archive_write_set_format_shar_dump(struct archive *);
+__LA_DECL int archive_write_set_format_ustar(struct archive *);
+__LA_DECL int archive_write_set_format_zip(struct archive *);
+__LA_DECL int archive_write_open(struct archive *, void *,
                     archive_open_callback *, archive_write_callback *,
                     archive_close_callback *);
-__LA_DECL int           archive_write_open_fd(struct archive *, int _fd);
-__LA_DECL int           archive_write_open_filename(struct archive *, const char *_file);
+__LA_DECL int archive_write_open_fd(struct archive *, int _fd);
+__LA_DECL int archive_write_open_filename(struct archive *, const char *_file);
 /* A deprecated synonym for archive_write_open_filename() */
-__LA_DECL int           archive_write_open_file(struct archive *, const char *_file);
-__LA_DECL int           archive_write_open_FILE(struct archive *, FILE *);
+__LA_DECL int archive_write_open_file(struct archive *, const char *_file);
+__LA_DECL int archive_write_open_FILE(struct archive *, FILE *);
 /* _buffSize is the size of the buffer, _used refers to a variable that
  * will be updated after each write into the buffer. */
-__LA_DECL int           archive_write_open_memory(struct archive *,
+__LA_DECL int archive_write_open_memory(struct archive *,
                        void *_buffer, size_t _buffSize, size_t *_used);
 
 /*
  * Note that the library will truncate writes beyond the size provided
  * to archive_write_header or pad if the provided data is short.
  */
-__LA_DECL int           archive_write_header(struct archive *,
+__LA_DECL int archive_write_header(struct archive *,
                     struct archive_entry *);
-/* Libarchive 2.0 and later return ssize_t here. */
-__LA_DECL __LA_SSIZE_T  archive_write_data(struct archive *,
+__LA_DECL __LA_SSIZE_T archive_write_data(struct archive *,
                            const void *, size_t);
 
 #if ARCHIVE_VERSION_NUMBER < 3000000
@@ -598,7 +621,6 @@ __LA_DECL int               archive_write_set_compressor_options(struct archive *_a,
 __LA_DECL int          archive_write_set_options(struct archive *_a,
                            const char *s);
 
-
 /*-
  * ARCHIVE_WRITE_DISK API
  *
@@ -693,13 +715,29 @@ __LA_DECL int     archive_read_disk_set_uname_lookup(struct archive *,
  * Accessor functions to read/set various information in
  * the struct archive object:
  */
-/* Bytes written after compression or read before decompression. */
+
+/* Number of filters in the current filter pipeline. */
+/* Filter #0 is the one closest to the format, -1 is a synonym for the
+ * last filter, which is always the pseudo-filter that wraps the
+ * client callbacks. */
+__LA_DECL int           archive_filter_count(struct archive *);
+__LA_DECL __LA_INT64_T  archive_filter_bytes(struct archive *, int);
+__LA_DECL int           archive_filter_code(struct archive *, int);
+__LA_DECL const char *  archive_filter_name(struct archive *, int);
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+/* These don't properly handle multiple filters, so are deprecated and
+ * will eventually be removed. */
+/* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, -1); */
 __LA_DECL __LA_INT64_T  archive_position_compressed(struct archive *);
-/* Bytes written to compressor or read from decompressor. */
+/* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, 0); */
 __LA_DECL __LA_INT64_T  archive_position_uncompressed(struct archive *);
-
+/* As of libarchive 3.0, this is an alias for archive_filter_name(a, 0); */
 __LA_DECL const char   *archive_compression_name(struct archive *);
+/* As of libarchive 3.0, this is an alias for archive_filter_code(a, 0); */
 __LA_DECL int           archive_compression(struct archive *);
+#endif
+
 __LA_DECL int           archive_errno(struct archive *);
 __LA_DECL const char   *archive_error_string(struct archive *);
 __LA_DECL const char   *archive_format_name(struct archive *);
index c74bcca292c32f5b9f678c9bd9852f6622469a6d..da6ac884908136e57146b8de8e58689b0a5fea19 100644 (file)
 #ifndef ARCHIVE_ENTRY_H_INCLUDED
 #define        ARCHIVE_ENTRY_H_INCLUDED
 
+/* Needed if archive_entry.h is used without archive.h */
+#ifndef ARCHIVE_VERSION_NUMBER
+#define        ARCHIVE_VERSION_NUMBER 3000000
+#endif
+
 /*
  * Note: archive_entry.h is for use outside of libarchive; the
  * configuration headers (config.h, archive_platform.h, etc.) are
@@ -272,11 +277,10 @@ __LA_DECL void    archive_entry_set_hardlink(struct archive_entry *, const char *);
 __LA_DECL void archive_entry_copy_hardlink(struct archive_entry *, const char *);
 __LA_DECL void archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *);
 __LA_DECL int  archive_entry_update_hardlink_utf8(struct archive_entry *, const char *);
-#if ARCHIVE_VERSION_NUMBER >= 3000000
-/* Starting with libarchive 3.0, this will be synonym for ino64. */
-__LA_DECL void archive_entry_set_ino(struct archive_entry *, __LA_INT64_T);
-#else
+#if ARCHIVE_VERSION_NUMBER < 3000000
 __LA_DECL void archive_entry_set_ino(struct archive_entry *, unsigned long);
+#else
+__LA_DECL void archive_entry_set_ino(struct archive_entry *, __LA_INT64_T);
 #endif
 __LA_DECL void archive_entry_set_ino64(struct archive_entry *, __LA_INT64_T);
 __LA_DECL void archive_entry_set_link(struct archive_entry *, const char *);
index ef59a5e78a04666d5e221ef3cf95369ca28f55b1..1a049ba3ba69dff58868aa4bc93e834aad17bce7 100644 (file)
@@ -30,6 +30,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_entry_copy_stat.c 189466 2009-03
 #include <sys/stat.h>
 #endif
 
+#include "archive.h"
 #include "archive_entry.h"
 
 void
index dc8857a3b8eadd3364af2b3505b343e4b419ca5e..ea9f205282824cfb9f6f2212e6de5dc214ba1e36 100644 (file)
@@ -51,7 +51,6 @@
 #define        ARCHIVE_STATE_NEW       1U
 #define        ARCHIVE_STATE_HEADER    2U
 #define        ARCHIVE_STATE_DATA      4U
-#define        ARCHIVE_STATE_DATA_END  8U
 #define        ARCHIVE_STATE_EOF       0x10U
 #define        ARCHIVE_STATE_CLOSED    0x20U
 #define        ARCHIVE_STATE_FATAL     0x8000U
@@ -66,6 +65,11 @@ struct archive_vtable {
            const void *, size_t);
        ssize_t (*archive_write_data_block)(struct archive *,
            const void *, size_t, off_t);
+
+       int     (*archive_filter_count)(struct archive *);
+       int64_t (*archive_filter_bytes)(struct archive *, int);
+       int     (*archive_filter_code)(struct archive *, int);
+       const char * (*archive_filter_name)(struct archive *, int);
 };
 
 struct archive {
@@ -90,10 +94,6 @@ struct archive {
        int       compression_code;     /* Currently active compression. */
        const char *compression_name;
 
-       /* Position in UNCOMPRESSED data stream. */
-       int64_t           file_position;
-       /* Position in COMPRESSED data stream. */
-       int64_t           raw_position;
        /* Number of file entries processed. */
        int               file_count;
 
index 9ed61efb923fce20715b33472432cda3bf783ade..4edbf2bc114fc45fb659b4718005696fb01c26b7 100644 (file)
@@ -57,8 +57,12 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read.c 201157 2009-12-29 05:30:2
 
 static int     build_stream(struct archive_read *);
 static int     choose_format(struct archive_read *);
-static int     cleanup_filters(struct archive_read *);
+static void    free_filters(struct archive_read *);
+static int     close_filters(struct archive_read *);
 static struct archive_vtable *archive_read_vtable(void);
+static int64_t _archive_filter_bytes(struct archive *, int);
+static int     _archive_filter_code(struct archive *, int);
+static const char *_archive_filter_name(struct archive *, int);
 static int     _archive_read_close(struct archive *);
 static int     _archive_read_free(struct archive *);
 
@@ -69,6 +73,9 @@ archive_read_vtable(void)
        static int inited = 0;
 
        if (!inited) {
+               av.archive_filter_bytes = _archive_filter_bytes;
+               av.archive_filter_code = _archive_filter_code;
+               av.archive_filter_name = _archive_filter_name;
                av.archive_free = _archive_read_free;
                av.archive_close = _archive_read_close;
        }
@@ -245,7 +252,6 @@ client_read_proxy(struct archive_read_filter *self, const void **buff)
        ssize_t r;
        r = (self->archive->client.reader)(&self->archive->archive,
            self->data, buff);
-       self->archive->archive.raw_position += r;
        return (r);
 }
 
@@ -269,7 +275,6 @@ client_skip_proxy(struct archive_read_filter *self, int64_t request)
                if (get == 0)
                        return (total);
                request -= get;
-               self->archive->archive.raw_position += get;
                total += get;
        }
 }
@@ -398,7 +403,8 @@ build_stream(struct archive_read *a)
                /* Verify the filter by asking it for some data. */
                __archive_read_filter_ahead(filter, 1, &avail);
                if (avail < 0) {
-                       cleanup_filters(a);
+                       close_filters(a);
+                       free_filters(a);
                        return (ARCHIVE_FATAL);
                }
        }
@@ -448,8 +454,8 @@ archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
                        return (ret);
        }
 
-       /* Record start-of-header. */
-       a->header_position = a->archive.file_position;
+       /* Record start-of-header offset in uncompressed stream. */
+       a->header_position = a->filter->bytes_consumed;
 
        ret = (a->format->read_header)(a, entry);
 
@@ -712,69 +718,60 @@ archive_read_data_block(struct archive *_a,
        return (a->format->read_data)(a, buff, size, offset);
 }
 
+static int
+close_filters(struct archive_read *a)
+{
+       struct archive_read_filter *f = a->filter;
+       int r = ARCHIVE_OK;
+       /* Close each filter in the pipeline. */
+       while (f != NULL) {
+               struct archive_read_filter *t = f->upstream;
+               if (f->close != NULL) {
+                       int r1 = (f->close)(f);
+                       if (r1 < r)
+                               r = r1;
+               }
+               free(f->buffer);
+               f->buffer = NULL;
+               f = t;
+       }
+       return r;
+}
+
+static void
+free_filters(struct archive_read *a)
+{
+       while (a->filter != NULL) {
+               struct archive_read_filter *t = a->filter->upstream;
+               free(a->filter);
+               a->filter = t;
+       }
+}
+
 /*
- * Close the file and release most resources.
- *
- * Be careful: client might just call read_new and then read_finish.
- * Don't assume we actually read anything or performed any non-trivial
- * initialization.
+ * Close the file and all I/O.
  */
 static int
 _archive_read_close(struct archive *_a)
 {
        struct archive_read *a = (struct archive_read *)_a;
        int r = ARCHIVE_OK, r1 = ARCHIVE_OK;
-       size_t i, n;
 
        __archive_check_magic(&a->archive, ARCHIVE_READ_MAGIC,
            ARCHIVE_STATE_ANY, "archive_read_close");
        archive_clear_error(&a->archive);
        a->archive.state = ARCHIVE_STATE_CLOSED;
 
-
-       /* Call cleanup functions registered by optional components. */
-       if (a->cleanup_archive_extract != NULL)
-               r = (a->cleanup_archive_extract)(a);
-
        /* TODO: Clean up the formatters. */
 
        /* Release the filter objects. */
-       r1 = cleanup_filters(a);
+       r1 = close_filters(a);
        if (r1 < r)
                r = r1;
 
-       /* Release the bidder objects. */
-       n = sizeof(a->bidders)/sizeof(a->bidders[0]);
-       for (i = 0; i < n; i++) {
-               if (a->bidders[i].free != NULL) {
-                       r1 = (a->bidders[i].free)(&a->bidders[i]);
-                       if (r1 < r)
-                               r = r1;
-               }
-       }
-
        return (r);
 }
 
-static int
-cleanup_filters(struct archive_read *a)
-{
-       int r = ARCHIVE_OK;
-       /* Clean up the filter pipeline. */
-       while (a->filter != NULL) {
-               struct archive_read_filter *t = a->filter->upstream;
-               if (a->filter->close != NULL) {
-                       int r1 = (a->filter->close)(a->filter);
-                       if (r1 < r)
-                               r = r1;
-               }
-               free(a->filter->buffer);
-               free(a->filter);
-               a->filter = t;
-       }
-       return r;
-}
-
 /*
  * Release memory and other resources.
  */
@@ -782,7 +779,7 @@ static int
 _archive_read_free(struct archive *_a)
 {
        struct archive_read *a = (struct archive_read *)_a;
-       int i;
+       int i, n;
        int slots;
        int r = ARCHIVE_OK;
 
@@ -791,6 +788,10 @@ _archive_read_free(struct archive *_a)
        if (a->archive.state != ARCHIVE_STATE_CLOSED)
                r = archive_read_close(&a->archive);
 
+       /* Call cleanup functions registered by optional components. */
+       if (a->cleanup_archive_extract != NULL)
+               r = (a->cleanup_archive_extract)(a);
+
        /* Cleanup format-specific data. */
        slots = sizeof(a->formats) / sizeof(a->formats[0]);
        for (i = 0; i < slots; i++) {
@@ -799,6 +800,19 @@ _archive_read_free(struct archive *_a)
                        (a->formats[i].cleanup)(a);
        }
 
+       /* Free the filters */
+       free_filters(a);
+
+       /* Release the bidder objects. */
+       n = sizeof(a->bidders)/sizeof(a->bidders[0]);
+       for (i = 0; i < n; i++) {
+               if (a->bidders[i].free != NULL) {
+                       int r1 = (a->bidders[i].free)(&a->bidders[i]);
+                       if (r1 < r)
+                               r = r1;
+               }
+       }
+
        archive_string_free(&a->archive.error_string);
        if (a->entry)
                archive_entry_free(a->entry);
@@ -807,6 +821,42 @@ _archive_read_free(struct archive *_a)
        return (r);
 }
 
+static struct archive_read_filter *
+get_filter(struct archive *_a, int n)
+{
+       struct archive_read *a = (struct archive_read *)_a;
+       struct archive_read_filter *f = a->filter;
+       /* XXX handle n == -1 */
+       if (n < 0)
+               return NULL;
+       while (n > 0 && f != NULL) {
+               f = f->upstream;
+               --n;
+       }
+       return (f);
+}
+
+static int
+_archive_filter_code(struct archive *_a, int n)
+{
+       struct archive_read_filter *f = get_filter(_a, n);
+       return f == NULL ? -1 : f->code;
+}
+
+static const char *
+_archive_filter_name(struct archive *_a, int n)
+{
+       struct archive_read_filter *f = get_filter(_a, n);
+       return f == NULL ? NULL : f->name;
+}
+
+static int64_t
+_archive_filter_bytes(struct archive *_a, int n)
+{
+       struct archive_read_filter *f = get_filter(_a, n);
+       return f == NULL ? -1 : f->bytes_consumed;
+}
+
 /*
  * Used internally by read format handlers to register their bid and
  * initialization functions.
@@ -1125,10 +1175,7 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
 ssize_t
 __archive_read_consume(struct archive_read *a, size_t request)
 {
-       ssize_t r;
-       r = __archive_read_filter_consume(a->filter, request);
-       a->archive.file_position += r;
-       return (r);
+       return (__archive_read_filter_consume(a->filter, request));
 }
 
 ssize_t
@@ -1144,6 +1191,7 @@ __archive_read_filter_consume(struct archive_read_filter * filter,
                filter->client_next += request;
                filter->client_avail -= request;
        }
+       filter->bytes_consumed += request;
        return (request);
 }
 
@@ -1173,10 +1221,7 @@ __archive_read_skip(struct archive_read *a, int64_t request)
 int64_t
 __archive_read_skip_lenient(struct archive_read *a, int64_t request)
 {
-       int64_t skipped = __archive_read_filter_skip(a->filter, request);
-       if (skipped > 0)
-               a->archive.file_position += skipped;
-       return (skipped);
+       return (__archive_read_filter_skip(a->filter, request));
 }
 
 int64_t
@@ -1204,6 +1249,7 @@ __archive_read_filter_skip(struct archive_read_filter *filter, int64_t request)
        }
        if (request == 0)
                return (total_bytes_skipped);
+
        /*
         * If a client_skipper was provided, try that first.
         */
@@ -1215,6 +1261,7 @@ __archive_read_filter_skip(struct archive_read_filter *filter, int64_t request)
                        filter->fatal = 1;
                        return (bytes_skipped);
                }
+               filter->bytes_consumed += bytes_skipped;
                total_bytes_skipped += bytes_skipped;
                request -= bytes_skipped;
                filter->client_next = filter->client_buff;
index 5a850189042ac6f8307ab29a182d59938d7a4330..53d9b654555066a516bce1e077878f5cd320880c 100644 (file)
@@ -42,13 +42,18 @@ struct archive_read_filter;
 
 /*
  * How bidding works for filters:
- *   * The bid manager reads the first block from the current source.
- *   * It shows that block to each registered bidder.
+ *   * The bid manager initializes the client-provided reader as the
+ *     first filter.
+ *   * It invokes the bidder for each registered filter with the
+ *     current head filter.
+ *   * The bidders can use archive_read_filter_ahead() to peek ahead
+ *     at the incoming data to compose their bids.
  *   * The bid manager creates a new filter structure for the winning
  *     bidder and gives the winning bidder a chance to initialize it.
- *   * The new filter becomes the top filter in the archive_read structure
- *     and we repeat the process.
- * This ends only when no bidder provides a non-zero bid.
+ *   * The new filter becomes the new top filter and we repeat the
+ *     process.
+ * This ends only when no bidder provides a non-zero bid.  Then
+ * we perform a similar dance with the registered format handlers.
  */
 struct archive_read_filter_bidder {
        /* Configuration data for the bidder. */
@@ -71,6 +76,7 @@ struct archive_read_filter_bidder {
  * corresponding bidder above.
  */
 struct archive_read_filter {
+       int64_t bytes_consumed;
        /* Essentially all filters will need these values, so
         * just declare them here. */
        struct archive_read_filter_bidder *bidder; /* My bidder. */
index 1e45f22023c4a9472a594f0715260ff4eb128237..d08488950b937017d071c26b7cffc06ce8ed4c83 100644 (file)
@@ -343,6 +343,7 @@ bzip2_filter_close(struct archive_read_filter *self)
                                          "Failed to clean up decompressor");
                        ret = ARCHIVE_FATAL;
                }
+               state->valid = 0;
        }
 
        free(state->out_block);
index 7c1ca3a0c876cbfa01d4878d6d50be1fb4e33500..80c014a1fe4ab3e42164bb6d1638fe51ab769f35 100644 (file)
@@ -55,6 +55,7 @@ struct ar {
        off_t    entry_padding;
        char    *strtab;
        size_t   strtab_size;
+       char     read_global_header;
 };
 
 /*
@@ -172,12 +173,13 @@ archive_read_format_ar_read_header(struct archive_read *a,
 
        ar = (struct ar*)(a->format->data);
 
-       if (a->archive.file_position == 0) {
+       if (!ar->read_global_header) {
                /*
                 * We are now at the beginning of the archive,
                 * so we need first consume the ar global header.
                 */
                __archive_read_consume(a, 8);
+               ar->read_global_header = 1;
                /* Set a default format code for now. */
                a->archive.archive_format = ARCHIVE_FORMAT_AR;
        }
index 98609e565a71e5f9412797218c6d179b5c647595..fb04c4fbdf53cb7fbe59929873bfb6c49f8e831f 100644 (file)
 .Nm archive_errno ,
 .Nm archive_error_string ,
 .Nm archive_file_count ,
+.Nm archive_filter_code ,
+.Nm archive_filter_count ,
+.Nm archive_filter_name ,
 .Nm archive_format ,
 .Nm archive_format_name ,
+.Nm archive_position ,
 .Nm archive_set_error
 .Nd libarchive utility functions
 .Sh SYNOPSIS
 .Ft int
 .Fn archive_file_count "struct archive *"
 .Ft int
+.Fn archive_filter_code "struct archive *" "int"
+.Ft int
+.Fn archive_filter_count "struct archive *" "int"
+.Ft const char *
+.Fn archive_filter_name "struct archive *" "int"
+.Ft int
 .Fn archive_format "struct archive *"
 .Ft const char *
 .Fn archive_format_name "struct archive *"
+.Ft int64_t
+.Fn archive_position "struct archive *" "int"
 .Ft void
 .Fo archive_set_error
 .Fa "struct archive *"
@@ -77,11 +89,11 @@ library.
 Clears any error information left over from a previous call.
 Not generally used in client code.
 .It Fn archive_compression
-Returns a numeric code indicating the current compression.
-This value is set by
-.Fn archive_read_open .
+Synonym for
+.Fn archive_filter_code(a, 0) .
 .It Fn archive_compression_name
-Returns a text description of the current compression suitable for display.
+Synonym for
+.Fn archive_filter_name(a, 0) .
 .It Fn archive_copy_error
 Copies error information from one archive to another.
 .It Fn archive_errno
@@ -101,6 +113,42 @@ The count is incremented by calls to
 .Xr archive_write_header
 or
 .Xr archive_read_next_header .
+.It Fn archive_filter_code
+Returns a numeric code identifying the indicated filter.
+See
+.Fn archive_filter_count
+for details of the numbering.
+.It Fn archive_filter_count
+Returns the number of filters in the current pipeline.
+For read archive handles, these filters are added automatically
+by the automatic format detection.
+For write archive handles, these filters are added by calls to the various
+.Fn archive_write_add_filter_XXX
+functions.
+Filters in the resulting pipeline are numbered so that filter 0
+is the filter closest to the format handler.
+As a convenience, functions that expect a filter number will
+accept -1 as a synonym for the highest-numbered filter.
+.Pp
+For example, when reading a uuencoded gzipped tar archive, there
+are three filters:
+filter 0 is the gunzip filter,
+filter 1 is the uudecode filter,
+and filter 2 is the pseudo-filter that wraps the archive read functions.
+In this case, requesting
+.Fn archive_position(a, -1)
+would be a synonym for
+.Fn archive_position(a, 2)
+which would return the number of bytes currently read from the archive, while
+.Fn archive_position(a, 1)
+would return the number of bytes after uudecoding, and
+.Fn archive_position(a, 0)
+would return the number of bytes after decompression.
+.It Fn archive_filter_name
+Returns a textual name identifying the indicated filter.
+See
+.Fn archive_filter_count
+for details of the numbering.
 .It Fn archive_format
 Returns a numeric code indicating the format of the current
 archive entry.
@@ -113,6 +161,16 @@ utilize GNU tar extensions and several entries that do not.
 These entries will have different format codes.
 .It Fn archive_format_name
 A textual description of the format of the current entry.
+.It Fn archive_position
+Returns the number of bytes read from or written to the indicated filter.
+In particular,
+.Fn archive_position(a, 0)
+returns the number of bytes read or written by the format handler, while
+.Fn archive_position(a, -1)
+returns the number of bytes read or written to the archive.
+See
+.Fn archive_filter_count
+for details of the numbering here.
 .It Fn archive_set_error
 Sets the numeric error code and error description that will be returned
 by
index d00e0b6e54cbf85fe2d379c11ec2f11576ef5d38..4cf4de6f76bbc92459d0ed30db19e2a53971c0eb 100644 (file)
@@ -128,13 +128,13 @@ archive_format_name(struct archive *a)
 int
 archive_compression(struct archive *a)
 {
-       return (a->compression_code);
+       return archive_filter_code(a, 0);
 }
 
 const char *
 archive_compression_name(struct archive *a)
 {
-       return (a->compression_name);
+       return archive_filter_name(a, 0);
 }
 
 
@@ -144,7 +144,7 @@ archive_compression_name(struct archive *a)
 int64_t
 archive_position_compressed(struct archive *a)
 {
-       return (a->raw_position);
+       return archive_filter_bytes(a, -1);
 }
 
 /*
@@ -153,7 +153,7 @@ archive_position_compressed(struct archive *a)
 int64_t
 archive_position_uncompressed(struct archive *a)
 {
-       return (a->file_position);
+       return archive_filter_bytes(a, 0);
 }
 
 void
index 836886270f9f926a0b2e04b4a18d08a1bdd6fee3..db50a244945d98799946652ce678238e65852c67 100644 (file)
@@ -30,6 +30,30 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_virtual.c 201098 2009-12-28 02:5
 #include "archive_entry.h"
 #include "archive_private.h"
 
+int
+archive_filter_code(struct archive *a, int n)
+{
+       return ((a->vtable->archive_filter_code)(a, n));
+}
+
+int
+archive_filter_count(struct archive *a)
+{
+       return ((a->vtable->archive_filter_count)(a));
+}
+
+const char *
+archive_filter_name(struct archive *a, int n)
+{
+       return ((a->vtable->archive_filter_name)(a, n));
+}
+
+int64_t
+archive_filter_bytes(struct archive *a, int n)
+{
+       return ((a->vtable->archive_filter_bytes)(a, n));
+}
+
 int
 archive_write_close(struct archive *a)
 {
index eba7227221a2af8776e283aaca50ac47477cffde..26df292c7d9dac532e3a67570e72439896c85dbd 100644 (file)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2003-2010 Tim Kientzle
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -59,6 +59,9 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write.c 201099 2009-12-28 03:03:
 
 static struct archive_vtable *archive_write_vtable(void);
 
+static int     _archive_filter_code(struct archive *, int);
+static const char *_archive_filter_name(struct archive *, int);
+static int64_t _archive_filter_bytes(struct archive *, int);
 static int     _archive_write_close(struct archive *);
 static int     _archive_write_free(struct archive *);
 static int     _archive_write_header(struct archive *, struct archive_entry *);
@@ -73,6 +76,9 @@ archive_write_vtable(void)
 
        if (!inited) {
                av.archive_close = _archive_write_close;
+               av.archive_filter_bytes = _archive_filter_bytes;
+               av.archive_filter_code = _archive_filter_code;
+               av.archive_filter_name = _archive_filter_name;
                av.archive_free = _archive_write_free;
                av.archive_write_header = _archive_write_header;
                av.archive_write_finish_entry = _archive_write_finish_entry;
@@ -114,13 +120,6 @@ archive_write_new(void)
        }
        memset(nulls, 0, a->null_length);
        a->nulls = nulls;
-       /*
-        * Set default compression, but don't set a default format.
-        * Were we to set a default format here, we would force every
-        * client to link in support for that format, even if they didn't
-        * ever use it.
-        */
-       archive_write_set_compression_none(&a->archive);
        return (&a->archive);
 }
 
@@ -174,6 +173,7 @@ int
 archive_write_set_compressor_options(struct archive *_a, const char *s)
 {
        struct archive_write *a = (struct archive_write *)_a;
+       struct archive_write_filter *filter;
        char key[64], val[64];
        int len, r;
        int ret = ARCHIVE_OK;
@@ -184,27 +184,27 @@ archive_write_set_compressor_options(struct archive *_a, const char *s)
 
        if (s == NULL || *s == '\0')
                return (ARCHIVE_OK);
-       if (a->compressor.options == NULL) {
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                   "Unsupported option ``%s''", s);
-               /* This compressor does not support option. */
-               return (ARCHIVE_WARN);
-       }
-
-       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);
-               if (r < ARCHIVE_OK) {
-                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                           "Unsupported option ``%s''", key);
-                       ret = ARCHIVE_WARN;
+       for (filter = a->filter_first; filter != NULL; filter = filter->next_filter) {
+               if (filter->options == NULL)
+                       /* This filter does not have any options */
+                       continue;
+               while ((len = __archive_parse_options(s,
+                           a->archive.compression_name,
+                           sizeof(key), key, sizeof(val), val)) > 0) {
+                       if (val[0] == '\0')
+                               r = filter->options(filter, key, NULL);
+                       else
+                               r = filter->options(filter, key, val);
+                       if (r == ARCHIVE_FATAL)
+                               return (r);
+                       if (r < ARCHIVE_OK) {
+                               archive_set_error(&a->archive,
+                                   ARCHIVE_ERRNO_MISC,
+                                   "Unsupported option ``%s''", key);
+                               ret = ARCHIVE_WARN;
+                       }
+                       s += len;
                }
-               s += len;
        }
        if (len < 0) {
                archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
@@ -300,6 +300,107 @@ archive_write_set_skip_file(struct archive *_a, dev_t d, ino_t i)
        return (ARCHIVE_OK);
 }
 
+/*
+ * Allocate and return the next filter structure.
+ */
+struct archive_write_filter *
+__archive_write_allocate_filter(struct archive *_a)
+{
+       struct archive_write *a = (struct archive_write *)_a;
+       struct archive_write_filter *f;
+       __archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+           ARCHIVE_STATE_NEW, "archive_write_allocate_filter");
+       f = calloc(1, sizeof(*f));
+       f->archive = _a;
+       if (a->filter_first == NULL)
+               a->filter_first = f;
+       else
+               a->filter_last->next_filter = f;
+       a->filter_last = f;
+       return f;
+}
+
+/*
+ * Write data to a particular filter.
+ */
+int
+__archive_write_filter(struct archive_write_filter *f,
+    const void *buff, size_t length)
+{
+       int r;
+       r = (f->write)(f, buff, length);
+       f->bytes_written += length;
+//     fprintf(stdout, "__archive_write_filter(%s, %d) = %d\n", f->name, (int)length, r);
+       return (r);
+}
+
+/*
+ * Open a filter.
+ */
+int
+__archive_write_open_filter(struct archive_write_filter *f)
+{
+       if (f->open == NULL)
+               return (ARCHIVE_OK);
+       return (f->open)(f);
+}
+
+/*
+ * Close a filter.
+ */
+int
+__archive_write_close_filter(struct archive_write_filter *f)
+{
+       if (f->close == NULL)
+               return (ARCHIVE_OK);
+       return (f->close)(f);
+}
+
+int
+__archive_write_output(struct archive_write *a, const void *buff, size_t length)
+{
+//     fprintf(stdout, "__archive_write_output(%d)\n", (int)length);
+       return (__archive_write_filter(a->filter_first, buff, length));
+}
+
+static int
+archive_write_client_open(struct archive_write_filter *f)
+{
+       struct archive_write *a = (struct archive_write *)f->archive;
+       if (a->client_opener == NULL)
+               return (ARCHIVE_OK);
+       return (a->client_opener(f->archive, f->data));
+}
+
+static int
+archive_write_client_write(struct archive_write_filter *f,
+    const void *_buff, size_t length)
+{
+       struct archive_write *a = (struct archive_write *)f->archive;
+       const char *buff = _buff;
+
+       while (length > 0) {
+               ssize_t written
+                   = (a->client_writer(f->archive, f->data, buff, length));
+//             fprintf(stdout, "__archive_write_client_write(%d): written=%d\n", (int)length, (int)written);
+               if (written < 0)
+                       return ((int)written);
+               if (written == 0)
+                       return (ARCHIVE_FATAL);
+               buff += written;
+               length -= written;
+       }
+       return (ARCHIVE_OK);
+}
+
+static int
+archive_write_client_close(struct archive_write_filter *f)
+{
+       struct archive_write *a = (struct archive_write *)f->archive;
+       if (a->client_closer == NULL)
+               return (ARCHIVE_OK);
+       return (a->client_closer(f->archive, f->data));
+}
 
 /*
  * Open the archive using the current settings.
@@ -310,29 +411,37 @@ archive_write_open(struct archive *_a, void *client_data,
     archive_close_callback *closer)
 {
        struct archive_write *a = (struct archive_write *)_a;
+       struct archive_write_filter *client_filter;
        int ret;
 
        __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
            ARCHIVE_STATE_NEW, "archive_write_open");
        archive_clear_error(&a->archive);
-       a->archive.state = ARCHIVE_STATE_HEADER;
-       a->client_data = client_data;
+
+       if (a->filter_first == NULL)
+               archive_write_set_compression_none(_a);
+
        a->client_writer = writer;
        a->client_opener = opener;
        a->client_closer = closer;
-       ret = (a->compressor.init)(a);
+
+       client_filter = __archive_write_allocate_filter(_a);
+       client_filter->data = client_data;
+       client_filter->open = archive_write_client_open;
+       client_filter->write = archive_write_client_write;
+       client_filter->close = archive_write_client_close;
+
+       ret = __archive_write_open_filter(a->filter_first);
+
+       a->archive.state = ARCHIVE_STATE_HEADER;
+
        if (a->format_init && ret == ARCHIVE_OK)
                ret = (a->format_init)(a);
        return (ret);
 }
 
-
 /*
  * Close out the archive.
- *
- * Be careful: user might just call write_new and then write_finish.
- * Don't assume we actually wrote anything or performed any non-trivial
- * initialization.
  */
 static int
 _archive_write_close(struct archive *_a)
@@ -340,59 +449,93 @@ _archive_write_close(struct archive *_a)
        struct archive_write *a = (struct archive_write *)_a;
        int r = ARCHIVE_OK, r1 = ARCHIVE_OK;
 
-       __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
-           ARCHIVE_STATE_ANY, "archive_write_close");
+       /*
+        * It's perfectly reasonable to call close() as part of
+        * routine cleanup, even after an error, so we're a little
+        * tolerant of being called in odd states.
+        */
+       if (a->archive.state & ARCHIVE_STATE_FATAL)
+               return (ARCHIVE_FATAL);
+       archive_clear_error(&a->archive);
+       if (a->archive.state & (ARCHIVE_STATE_NEW | ARCHIVE_STATE_CLOSED))
+               return (ARCHIVE_OK);
+
+       __archive_check_magic(&a->archive,
+           ARCHIVE_WRITE_MAGIC,
+           ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
+           "archive_write_close");
 
        /* Finish the last entry. */
        if (a->archive.state & ARCHIVE_STATE_DATA)
                r = ((a->format_finish_entry)(a));
 
        /* Finish off the archive. */
+       /* TODO: Rename format_finish to format_close, have
+        * format closers invoke compression close. */
        if (a->format_finish != NULL) {
                r1 = (a->format_finish)(a);
                if (r1 < r)
                        r = r1;
        }
 
-       /* Release format resources. */
-       if (a->format_destroy != NULL) {
-               r1 = (a->format_destroy)(a);
-               if (r1 < r)
-                       r = r1;
-       }
-
        /* Finish the compression and close the stream. */
-       if (a->compressor.finish != NULL) {
-               r1 = (a->compressor.finish)(a);
-               if (r1 < r)
-                       r = r1;
-       }
-
-       /* Close out the client stream. */
-       if (a->client_closer != NULL) {
-               r1 = (a->client_closer)(&a->archive, a->client_data);
-               if (r1 < r)
-                       r = r1;
-       }
+       r1 = __archive_write_close_filter(a->filter_first);
+       if (r1 < r)
+               r = r1;
 
        a->archive.state = ARCHIVE_STATE_CLOSED;
        return (r);
 }
 
+void
+__archive_write_filters_free(struct archive *_a)
+{
+       struct archive_write *a = (struct archive_write *)_a;
+       int r = ARCHIVE_OK, r1;
+
+       while (a->filter_first != NULL) {
+               struct archive_write_filter *next
+                   = a->filter_first->next_filter;
+               if (a->filter_first->free != NULL) {
+                       r1 = (*a->filter_first->free)(a->filter_first);
+                       if (r > r1)
+                               r = r1;
+               }
+               free(a->filter_first);
+               a->filter_first = next;
+       }
+       a->filter_last = NULL;
+}
+
 /*
  * Destroy the archive structure.
+ *
+ * Be careful: user might just call write_new and then write_free.
+ * Don't assume we actually wrote anything or performed any non-trivial
+ * initialization.
  */
 static int
 _archive_write_free(struct archive *_a)
 {
        struct archive_write *a = (struct archive_write *)_a;
-       int r = ARCHIVE_OK;
+       int r = ARCHIVE_OK, r1;
 
        __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
            ARCHIVE_STATE_ANY, "archive_write_free");
-       if (a->archive.state != ARCHIVE_STATE_CLOSED)
+       if (a->archive.state != ARCHIVE_STATE_CLOSED
+           && a->archive.state != ARCHIVE_STATE_FATAL)
                r = archive_write_close(&a->archive);
 
+       /* Release format resources. */
+       /* TODO: Rename format_destroy to format_free */
+       if (a->format_destroy != NULL) {
+               r1 = (a->format_destroy)(a);
+               if (r1 < r)
+                       r = r1;
+       }
+
+       __archive_write_filters_free(_a);
+
        /* Release various dynamic buffers. */
        free((void *)(uintptr_t)(const void *)a->nulls);
        archive_string_free(&a->archive.error_string);
@@ -416,6 +559,10 @@ _archive_write_header(struct archive *_a, struct archive_entry *entry)
 
        /* In particular, "retry" and "fatal" get returned immediately. */
        ret = archive_write_finish_entry(&a->archive);
+       if (ret == ARCHIVE_FATAL) {
+               a->archive.state = ARCHIVE_STATE_FATAL;
+               return (ARCHIVE_FATAL);
+       }
        if (ret < ARCHIVE_OK && ret != ARCHIVE_WARN)
                return (ret);
 
@@ -430,6 +577,10 @@ _archive_write_header(struct archive *_a, struct archive_entry *entry)
 
        /* Format and write header. */
        r2 = ((a->format_write_header)(a, entry));
+       if (r2 == ARCHIVE_FATAL) {
+               a->archive.state = ARCHIVE_STATE_FATAL;
+               return (ARCHIVE_FATAL);
+       }
        if (r2 < ret)
                ret = r2;
 
@@ -464,3 +615,40 @@ _archive_write_data(struct archive *_a, const void *buff, size_t s)
        archive_clear_error(&a->archive);
        return ((a->format_write_data)(a, buff, s));
 }
+
+static struct archive_write_filter *
+filter_lookup(struct archive *_a, int n)
+{
+       struct archive_write *a = (struct archive_write *)_a;
+       struct archive_write_filter *f = a->filter_first;
+       if (n == -1)
+               return a->filter_last;
+       if (n < 0)
+               return NULL;
+       while (n > 0 && f != NULL) {
+               f = f->next_filter;
+               --n;
+       }
+       return f;
+}
+
+static int
+_archive_filter_code(struct archive *_a, int n)
+{
+       struct archive_write_filter *f = filter_lookup(_a, n);
+       return f == NULL ? -1 : f->code;
+}
+
+static const char *
+_archive_filter_name(struct archive *_a, int n)
+{
+       struct archive_write_filter *f = filter_lookup(_a, n);
+       return f == NULL ? NULL : f->name;
+}
+
+static int64_t
+_archive_filter_bytes(struct archive *_a, int n)
+{
+       struct archive_write_filter *f = filter_lookup(_a, n);
+       return f == NULL ? -1 : f->bytes_written;
+}
diff --git a/libarchive/archive_write_add_filter_bzip2.c b/libarchive/archive_write_add_filter_bzip2.c
new file mode 100644 (file)
index 0000000..9bb1908
--- /dev/null
@@ -0,0 +1,348 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * 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: head/lib/libarchive/archive_write_set_compression_bzip2.c 201091 2009-12-28 02:22:41Z kientzle $");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_BZLIB_H
+#include <bzlib.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_write_private.h"
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+int
+archive_write_set_compression_bzip2(struct archive *a)
+{
+       __archive_write_filters_free(a);
+       return (archive_write_add_filter_bzip2(a));
+}
+#endif
+
+#ifndef HAVE_BZLIB_H
+int
+archive_write_add_filter_bzip2(struct archive *a)
+{
+       archive_set_error(a, ARCHIVE_ERRNO_MISC,
+           "bzip2 compression not supported on this platform");
+       return (ARCHIVE_FATAL);
+}
+#else
+/* Don't compile this if we don't have bzlib. */
+
+struct private_data {
+       int              compression_level;
+       bz_stream        stream;
+       int64_t          total_in;
+       char            *compressed;
+       size_t           compressed_buffer_size;
+};
+
+/*
+ * Yuck.  bzlib.h is not const-correct, so I need this one bit
+ * of ugly hackery to convert a const * pointer to a non-const pointer.
+ */
+#define        SET_NEXT_IN(st,src)                                     \
+       (st)->stream.next_in = (char *)(uintptr_t)(const void *)(src)
+
+static int archive_compressor_bzip2_close(struct archive_write_filter *);
+static int archive_compressor_bzip2_free(struct archive_write_filter *);
+static int archive_compressor_bzip2_open(struct archive_write_filter *);
+static int archive_compressor_bzip2_options(struct archive_write_filter *,
+                   const char *, const char *);
+static int archive_compressor_bzip2_write(struct archive_write_filter *,
+                   const void *, size_t);
+static int drive_compressor(struct archive_write_filter *,
+                   struct private_data *, int finishing);
+
+/*
+ * Add a bzip2 compression filter to this write handle.
+ */
+int
+archive_write_add_filter_bzip2(struct archive *_a)
+{
+       struct archive_write *a = (struct archive_write *)_a;
+       struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+       struct private_data *data;
+
+       __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+           ARCHIVE_STATE_NEW, "archive_write_set_compression_bzip2");
+
+       data = calloc(1, sizeof(*data));
+       if (data == NULL) {
+               archive_set_error(&a->archive, ENOMEM, "Out of memory");
+               return (ARCHIVE_FATAL);
+       }
+       data->compression_level = 9; /* default */
+
+       f->data = data;
+       f->options = &archive_compressor_bzip2_options;
+       f->close = &archive_compressor_bzip2_close;
+       f->free = &archive_compressor_bzip2_free;
+       f->open = &archive_compressor_bzip2_open;
+       f->code = ARCHIVE_COMPRESSION_BZIP2;
+       f->name = "bzip2";
+       return (ARCHIVE_OK);
+}
+
+/*
+ * Setup callback.
+ */
+static int
+archive_compressor_bzip2_open(struct archive_write_filter *f)
+{
+       struct private_data *data = (struct private_data *)f->data;
+       int ret;
+
+       ret = __archive_write_open_filter(f->next_filter);
+       if (ret != 0)
+               return (ret);
+
+       // TODO: Find a better way to size this.  (Maybe look at the
+       // block size expected by the following filter?)
+       if (data->compressed == NULL) {
+               data->compressed_buffer_size = 65536;
+               data->compressed
+                   = (char *)malloc(data->compressed_buffer_size);
+               if (data->compressed == NULL) {
+                       archive_set_error(f->archive, ENOMEM,
+                           "Can't allocate data for compression buffer");
+                       return (ARCHIVE_FATAL);
+               }
+       }
+
+       memset(&data->stream, 0, sizeof(data->stream));
+       data->stream.next_out = data->compressed;
+       data->stream.avail_out = data->compressed_buffer_size;
+       f->write = archive_compressor_bzip2_write;
+
+       /* Initialize compression library */
+       ret = BZ2_bzCompressInit(&(data->stream),
+           data->compression_level, 0, 30);
+       if (ret == BZ_OK) {
+               f->data = data;
+               return (ARCHIVE_OK);
+       }
+
+       /* Library setup failed: clean up. */
+       archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+           "Internal error initializing compression library");
+
+       /* Override the error message if we know what really went wrong. */
+       switch (ret) {
+       case BZ_PARAM_ERROR:
+               archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+                   "Internal error initializing compression library: "
+                   "invalid setup parameter");
+               break;
+       case BZ_MEM_ERROR:
+               archive_set_error(f->archive, ENOMEM,
+                   "Internal error initializing compression library: "
+                   "out of memory");
+               break;
+       case BZ_CONFIG_ERROR:
+               archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+                   "Internal error initializing compression library: "
+                   "mis-compiled library");
+               break;
+       }
+
+       return (ARCHIVE_FATAL);
+
+}
+
+/*
+ * Set write options.
+ */
+static int
+archive_compressor_bzip2_options(struct archive_write_filter *f,
+    const char *key, const char *value)
+{
+       struct private_data *data = (struct private_data *)f->data;
+
+       if (strcmp(key, "compression-level") == 0) {
+               if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
+                   value[1] != '\0')
+                       return (ARCHIVE_WARN);
+               data->compression_level = value[0] - '0';
+               /* Make '0' be a synonym for '1'. */
+               /* This way, bzip2 compressor supports the same 0..9
+                * range of levels as gzip. */
+               if (data->compression_level < 1)
+                       data->compression_level = 1;
+               return (ARCHIVE_OK);
+       }
+
+       return (ARCHIVE_WARN);
+}
+
+/*
+ * Write data to the compressed stream.
+ *
+ * Returns ARCHIVE_OK if all data written, error otherwise.
+ */
+static int
+archive_compressor_bzip2_write(struct archive_write_filter *f,
+    const void *buff, size_t length)
+{
+       struct private_data *data = (struct private_data *)f->data;
+
+       /* Update statistics */
+       data->total_in += length;
+
+       /* Compress input data to output buffer */
+       SET_NEXT_IN(data, buff);
+       data->stream.avail_in = length;
+       if (drive_compressor(f, data, 0))
+               return (ARCHIVE_FATAL);
+       return (ARCHIVE_OK);
+}
+
+
+/*
+ * Finish the compression.
+ */
+static int
+archive_compressor_bzip2_close(struct archive_write_filter *f)
+{
+       struct private_data *data = (struct private_data *)f->data;
+       ssize_t bytes_written;
+       int ret;
+
+       if (data == NULL)
+               return (ARCHIVE_OK);
+
+       /* Finish compression cycle. */
+       ret = drive_compressor(f, data, 1);
+       if (ret == ARCHIVE_OK) {
+               /* Write the last block */
+               bytes_written = __archive_write_filter(f->next_filter,
+                   data->compressed,
+                   data->compressed_buffer_size - data->stream.avail_out);
+               if (bytes_written <= 0)
+                       ret = ARCHIVE_FATAL;
+       }
+
+       switch (BZ2_bzCompressEnd(&(data->stream))) {
+       case BZ_OK:
+               break;
+       default:
+               archive_set_error(f->archive, ARCHIVE_ERRNO_PROGRAMMER,
+                   "Failed to clean up compressor");
+               ret = ARCHIVE_FATAL;
+       }
+       return (ARCHIVE_OK);
+}
+
+static int
+archive_compressor_bzip2_free(struct archive_write_filter *f)
+{
+       struct private_data *data = (struct private_data *)f->data;
+       free(data->compressed);
+       free(data);
+       f->data = NULL;
+       return (ARCHIVE_OK);
+}
+
+/*
+ * Utility function to push input data through compressor, writing
+ * full output blocks as necessary.
+ *
+ * Note that this handles both the regular write case (finishing ==
+ * false) and the end-of-archive case (finishing == true).
+ */
+static int
+drive_compressor(struct archive_write_filter *f,
+    struct private_data *data, int finishing)
+{
+       ssize_t bytes_written;
+       int ret;
+
+       for (;;) {
+               if (data->stream.avail_out == 0) {
+                       bytes_written = __archive_write_filter(f->next_filter,
+                           data->compressed,
+                           data->compressed_buffer_size);
+                       if (bytes_written <= 0) {
+                               /* TODO: Handle this write failure */
+                               return (ARCHIVE_FATAL);
+                       } else if ((size_t)bytes_written < data->compressed_buffer_size) {
+                               /* Short write: Move remainder to
+                                * front and keep filling */
+                               memmove(data->compressed,
+                                   data->compressed + bytes_written,
+                                   data->compressed_buffer_size - bytes_written);
+                       }
+
+                       data->stream.next_out = data->compressed +
+                           data->compressed_buffer_size - bytes_written;
+                       data->stream.avail_out = bytes_written;
+               }
+
+               /* If there's nothing to do, we're done. */
+               if (!finishing && data->stream.avail_in == 0)
+                       return (ARCHIVE_OK);
+
+               ret = BZ2_bzCompress(&(data->stream),
+                   finishing ? BZ_FINISH : BZ_RUN);
+
+               switch (ret) {
+               case BZ_RUN_OK:
+                       /* In non-finishing case, did compressor
+                        * consume everything? */
+                       if (!finishing && data->stream.avail_in == 0)
+                               return (ARCHIVE_OK);
+                       break;
+               case BZ_FINISH_OK:  /* Finishing: There's more work to do */
+                       break;
+               case BZ_STREAM_END: /* Finishing: all done */
+                       /* Only occurs in finishing case */
+                       return (ARCHIVE_OK);
+               default:
+                       /* Any other return value indicates an error */
+                       archive_set_error(f->archive,
+                           ARCHIVE_ERRNO_PROGRAMMER,
+                           "Bzip2 compression failed;"
+                           " BZ2_bzCompress() returned %d",
+                           ret);
+                       return (ARCHIVE_FATAL);
+               }
+       }
+}
+
+#endif /* HAVE_BZLIB_H */
similarity index 70%
rename from libarchive/archive_write_set_compression_compress.c
rename to libarchive/archive_write_add_filter_compress.c
index 77c73ee5f270bf45cd022e8460eb5894691d005a..e8d6344fd74bd1f36fb23d60c8d8bff9bf195228 100644 (file)
@@ -108,23 +108,35 @@ struct private_data {
        size_t           compressed_offset;
 };
 
-static int     archive_compressor_compress_finish(struct archive_write *);
-static int     archive_compressor_compress_init(struct archive_write *);
-static int     archive_compressor_compress_write(struct archive_write *,
+static int archive_compressor_compress_open(struct archive_write_filter *);
+static int archive_compressor_compress_write(struct archive_write_filter *,
                    const void *, size_t);
+static int archive_compressor_compress_close(struct archive_write_filter *);
+static int archive_compressor_compress_free(struct archive_write_filter *);
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+int
+archive_write_set_compression_compress(struct archive *a)
+{
+       __archive_write_filters_free(a);
+       return (archive_write_add_filter_compress(a));
+}
+#endif
 
 /*
- * Allocate, initialize and return a archive object.
+ * Add a compress filter to this write handle.
  */
 int
-archive_write_set_compression_compress(struct archive *_a)
+archive_write_add_filter_compress(struct archive *_a)
 {
        struct archive_write *a = (struct archive_write *)_a;
+       struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+
        __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
            ARCHIVE_STATE_NEW, "archive_write_set_compression_compress");
-       a->compressor.init = &archive_compressor_compress_init;
-       a->archive.compression_code = ARCHIVE_COMPRESSION_COMPRESS;
-       a->archive.compression_name = "compress";
+       f->open = &archive_compressor_compress_open;
+       f->code = ARCHIVE_COMPRESSION_COMPRESS;
+       f->name = "compress";
        return (ARCHIVE_OK);
 }
 
@@ -132,46 +144,38 @@ archive_write_set_compression_compress(struct archive *_a)
  * Setup callback.
  */
 static int
-archive_compressor_compress_init(struct archive_write *a)
+archive_compressor_compress_open(struct archive_write_filter *f)
 {
        int ret;
        struct private_data *state;
 
-       a->archive.compression_code = ARCHIVE_COMPRESSION_COMPRESS;
-       a->archive.compression_name = "compress";
-
-       if (a->bytes_per_block < 4) {
-               archive_set_error(&a->archive, EINVAL,
-                   "Can't write Compress header as single block");
-               return (ARCHIVE_FATAL);
-       }
+       f->code = ARCHIVE_COMPRESSION_COMPRESS;
+       f->name = "compress";
 
-       if (a->client_opener != NULL) {
-               ret = (a->client_opener)(&a->archive, a->client_data);
-               if (ret != ARCHIVE_OK)
-                       return (ret);
-       }
+       ret = __archive_write_open_filter(f->next_filter);
+       if (ret != ARCHIVE_OK)
+               return (ret);
 
-       state = (struct private_data *)malloc(sizeof(*state));
+       state = (struct private_data *)calloc(1, sizeof(*state));
        if (state == NULL) {
-               archive_set_error(&a->archive, ENOMEM,
+               archive_set_error(f->archive, ENOMEM,
                    "Can't allocate data for compression");
                return (ARCHIVE_FATAL);
        }
-       memset(state, 0, sizeof(*state));
 
-       state->compressed_buffer_size = a->bytes_per_block;
+       state->compressed_buffer_size = 65536;
        state->compressed = malloc(state->compressed_buffer_size);
 
        if (state->compressed == NULL) {
-               archive_set_error(&a->archive, ENOMEM,
+               archive_set_error(f->archive, ENOMEM,
                    "Can't allocate data for compression buffer");
                free(state);
                return (ARCHIVE_FATAL);
        }
 
-       a->compressor.write = archive_compressor_compress_write;
-       a->compressor.finish = archive_compressor_compress_finish;
+       f->write = archive_compressor_compress_write;
+       f->close = archive_compressor_compress_close;
+       f->free = archive_compressor_compress_free;
 
        state->max_maxcode = 0x10000;   /* Should NEVER generate this code. */
        state->in_count = 0;            /* Length of input. */
@@ -192,7 +196,7 @@ archive_compressor_compress_init(struct archive_write *a)
        state->compressed[2] = 0x90; /* Block mode, 16bit max */
        state->compressed_offset = 3;
 
-       a->compressor.data = state;
+       f->data = state;
        return (0);
 }
 
@@ -215,21 +219,19 @@ static unsigned char rmask[9] =
        {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
 
 static int
-output_byte(struct archive_write *a, unsigned char c)
+output_byte(struct archive_write_filter *f, unsigned char c)
 {
-       struct private_data *state = a->compressor.data;
+       struct private_data *state = f->data;
        ssize_t bytes_written;
 
        state->compressed[state->compressed_offset++] = c;
        ++state->out_count;
 
        if (state->compressed_buffer_size == state->compressed_offset) {
-               bytes_written = (a->client_writer)(&a->archive,
-                   a->client_data,
+               bytes_written = __archive_write_filter(f->next_filter,
                    state->compressed, state->compressed_buffer_size);
                if (bytes_written <= 0)
                        return ARCHIVE_FATAL;
-               a->archive.raw_position += bytes_written;
                state->compressed_offset = 0;
        }
 
@@ -237,9 +239,9 @@ output_byte(struct archive_write *a, unsigned char c)
 }
 
 static int
-output_code(struct archive_write *a, int ocode)
+output_code(struct archive_write_filter *f, int ocode)
 {
-       struct private_data *state = a->compressor.data;
+       struct private_data *state = f->data;
        int bits, ret, clear_flg, bit_offset;
 
        clear_flg = ocode == CLEAR;
@@ -250,13 +252,13 @@ output_code(struct archive_write *a, int ocode)
         */
        bit_offset = state->bit_offset % 8;
        state->bit_buf |= (ocode << bit_offset) & 0xff;
-       output_byte(a, state->bit_buf);
+       output_byte(f, state->bit_buf);
 
        bits = state->code_len - (8 - bit_offset);
        ocode >>= 8 - bit_offset;
        /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
        if (bits >= 8) {
-               output_byte(a, ocode & 0xff);
+               output_byte(f, ocode & 0xff);
                ocode >>= 8;
                bits -= 8;
        }
@@ -277,7 +279,7 @@ output_code(struct archive_write *a, int ocode)
                */
                if (state->bit_offset > 0) {
                        while (state->bit_offset < state->code_len * 8) {
-                               ret = output_byte(a, state->bit_buf);
+                               ret = output_byte(f, state->bit_buf);
                                if (ret != ARCHIVE_OK)
                                        return ret;
                                state->bit_offset += 8;
@@ -303,15 +305,15 @@ output_code(struct archive_write *a, int ocode)
 }
 
 static int
-output_flush(struct archive_write *a)
+output_flush(struct archive_write_filter *f)
 {
-       struct private_data *state = a->compressor.data;
+       struct private_data *state = f->data;
        int ret;
 
        /* At EOF, write the rest of the buffer. */
        if (state->bit_offset % 8) {
                state->code_len = (state->bit_offset % 8 + 7) / 8;
-               ret = output_byte(a, state->bit_buf);
+               ret = output_byte(f, state->bit_buf);
                if (ret != ARCHIVE_OK)
                        return ret;
        }
@@ -323,23 +325,15 @@ output_flush(struct archive_write *a)
  * Write data to the compressed stream.
  */
 static int
-archive_compressor_compress_write(struct archive_write *a, const void *buff,
-    size_t length)
+archive_compressor_compress_write(struct archive_write_filter *f,
+    const void *buff, size_t length)
 {
-       struct private_data *state;
+       struct private_data *state = (struct private_data *)f->data;
        int i;
        int ratio;
        int c, disp, ret;
        const unsigned char *bp;
 
-       state = (struct private_data *)a->compressor.data;
-       if (a->client_writer == NULL) {
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
-                   "No write callback is registered?  "
-                   "This is probably an internal programming error.");
-               return (ARCHIVE_FATAL);
-       }
-
        if (length == 0)
                return ARCHIVE_OK;
 
@@ -368,7 +362,7 @@ archive_compressor_compress_write(struct archive_write *a, const void *buff,
                        disp = 1;
                else
                        disp = HSIZE - i;
- probe:                
+ probe:
                if ((i -= disp) < 0)
                        i += HSIZE;
 
@@ -378,8 +372,8 @@ archive_compressor_compress_write(struct archive_write *a, const void *buff,
                }
                if (state->hashtab[i] >= 0)
                        goto probe;
- nomatch:      
-               ret = output_code(a, state->cur_code);
+ nomatch:
+               ret = output_code(f, state->cur_code);
                if (ret != ARCHIVE_OK)
                        return ret;
                state->cur_code = c;
@@ -406,7 +400,7 @@ archive_compressor_compress_write(struct archive_write *a, const void *buff,
                        state->compress_ratio = 0;
                        memset(state->hashtab, 0xff, sizeof(state->hashtab));
                        state->first_free = FIRST;
-                       ret = output_code(a, CLEAR);
+                       ret = output_code(f, CLEAR);
                        if (ret != ARCHIVE_OK)
                                return ret;
                }
@@ -420,73 +414,30 @@ archive_compressor_compress_write(struct archive_write *a, const void *buff,
  * Finish the compression...
  */
 static int
-archive_compressor_compress_finish(struct archive_write *a)
+archive_compressor_compress_close(struct archive_write_filter *f)
 {
-       ssize_t block_length, target_block_length, bytes_written;
+       struct private_data *state = (struct private_data *)f->data;
        int ret;
-       struct private_data *state;
-       size_t tocopy;
-
-       state = (struct private_data *)a->compressor.data;
-       if (a->client_writer == NULL) {
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
-                   "No write callback is registered?  "
-                   "This is probably an internal programming error.");
-               ret = ARCHIVE_FATAL;
-               goto cleanup;
-       }
-
-       /* By default, always pad the uncompressed data. */
-       if (a->pad_uncompressed) {
-               while (state->in_count % a->bytes_per_block != 0) {
-                       tocopy = a->bytes_per_block -
-                           (state->in_count % a->bytes_per_block);
-                       if (tocopy > a->null_length)
-                               tocopy = a->null_length;
-                       ret = archive_compressor_compress_write(a, a->nulls,
-                           tocopy);
-                       if (ret != ARCHIVE_OK)
-                               goto cleanup;
-               }
-       }
 
-       ret = output_code(a, state->cur_code);
+       ret = output_code(f, state->cur_code);
        if (ret != ARCHIVE_OK)
                goto cleanup;
-       ret = output_flush(a);
+       ret = output_flush(f);
        if (ret != ARCHIVE_OK)
                goto cleanup;
 
-       /* Optionally, pad the final compressed block. */
-       block_length = state->compressed_offset;
-
-       /* Tricky calculation to determine size of last block. */
-       if (a->bytes_in_last_block <= 0)
-               /* Default or Zero: pad to full block */
-               target_block_length = a->bytes_per_block;
-       else
-               /* Round length to next multiple of bytes_in_last_block. */
-               target_block_length = a->bytes_in_last_block *
-                   ( (block_length + a->bytes_in_last_block - 1) /
-                       a->bytes_in_last_block);
-       if (target_block_length > a->bytes_per_block)
-               target_block_length = a->bytes_per_block;
-       if (block_length < target_block_length) {
-               memset(state->compressed + state->compressed_offset, 0,
-                   target_block_length - block_length);
-               block_length = target_block_length;
-       }
-
        /* Write the last block */
-       bytes_written = (a->client_writer)(&a->archive, a->client_data,
-           state->compressed, block_length);
-       if (bytes_written <= 0)
-               ret = ARCHIVE_FATAL;
-       else
-               a->archive.raw_position += bytes_written;
-
+       ret = __archive_write_filter(f->next_filter,
+           state->compressed, state->compressed_offset);
 cleanup:
        free(state->compressed);
        free(state);
        return (ret);
 }
+
+static int
+archive_compressor_compress_free(struct archive_write_filter *f)
+{
+       (void)f; /* UNUSED */
+       return (ARCHIVE_OK);
+}
diff --git a/libarchive/archive_write_add_filter_gzip.c b/libarchive/archive_write_add_filter_gzip.c
new file mode 100644 (file)
index 0000000..0499bd1
--- /dev/null
@@ -0,0 +1,365 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * 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: head/lib/libarchive/archive_write_set_compression_gzip.c 201081 2009-12-28 02:04:42Z kientzle $");
+
+#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 <time.h>
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_write_private.h"
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+int
+archive_write_set_compression_gzip(struct archive *a)
+{
+       __archive_write_filters_free(a);
+       return (archive_write_add_filter_gzip(a));
+}
+#endif
+
+#ifndef HAVE_ZLIB_H
+int
+archive_write_add_filter_gzip(struct archive *a)
+{
+       archive_set_error(a, ARCHIVE_ERRNO_MISC,
+           "gzip compression not supported on this platform");
+       return (ARCHIVE_FATAL);
+}
+#else
+/* Don't compile this if we don't have zlib. */
+
+struct private_data {
+       int              compression_level;
+       z_stream         stream;
+       int64_t          total_in;
+       unsigned char   *compressed;
+       size_t           compressed_buffer_size;
+       unsigned long    crc;
+};
+
+/*
+ * Yuck.  zlib.h is not const-correct, so I need this one bit
+ * of ugly hackery to convert a const * pointer to a non-const pointer.
+ */
+#define        SET_NEXT_IN(st,src)                                     \
+       (st)->stream.next_in = (Bytef *)(uintptr_t)(const void *)(src)
+
+static int archive_compressor_gzip_options(struct archive_write_filter *,
+                   const char *, const char *);
+static int archive_compressor_gzip_open(struct archive_write_filter *);
+static int archive_compressor_gzip_write(struct archive_write_filter *,
+                   const void *, size_t);
+static int archive_compressor_gzip_close(struct archive_write_filter *);
+static int archive_compressor_gzip_free(struct archive_write_filter *);
+static int drive_compressor(struct archive_write_filter *,
+                   struct private_data *, int finishing);
+
+
+/*
+ * Add a gzip compression filter to this write handle.
+ */
+int
+archive_write_add_filter_gzip(struct archive *_a)
+{
+       struct archive_write *a = (struct archive_write *)_a;
+       struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+       struct private_data *data;
+       __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+           ARCHIVE_STATE_NEW, "archive_write_set_compression_gzip");
+
+       data = calloc(1, sizeof(*data));
+       if (data == NULL) {
+               archive_set_error(&a->archive, ENOMEM, "Out of memory");
+               return (ARCHIVE_FATAL);
+       }
+       f->data = data;
+       data->compression_level = Z_DEFAULT_COMPRESSION;
+       f->open = &archive_compressor_gzip_open;
+       f->options = &archive_compressor_gzip_options;
+       f->close = &archive_compressor_gzip_close;
+       f->free = &archive_compressor_gzip_free;
+       f->code = ARCHIVE_COMPRESSION_GZIP;
+       f->name = "gzip";
+       return (ARCHIVE_OK);
+}
+
+/*
+ * Setup callback.
+ */
+static int
+archive_compressor_gzip_open(struct archive_write_filter *f)
+{
+       struct private_data *data = (struct private_data *)f->data;
+       int ret;
+       time_t t;
+
+       ret = __archive_write_open_filter(f->next_filter);
+       if (ret != ARCHIVE_OK)
+               return (ret);
+
+       if (data->compressed == NULL) {
+               data->compressed_buffer_size = 65536;
+               data->compressed
+                   = (unsigned char *)malloc(data->compressed_buffer_size);
+               if (data->compressed == NULL) {
+                       archive_set_error(f->archive, ENOMEM,
+                           "Can't allocate data for compression buffer");
+                       return (ARCHIVE_FATAL);
+               }
+       }
+
+       data->crc = crc32(0L, NULL, 0);
+       data->stream.next_out = data->compressed;
+       data->stream.avail_out = data->compressed_buffer_size;
+
+       /* Prime output buffer with a gzip header. */
+       t = time(NULL);
+       data->compressed[0] = 0x1f; /* GZip signature bytes */
+       data->compressed[1] = 0x8b;
+       data->compressed[2] = 0x08; /* "Deflate" compression */
+       data->compressed[3] = 0; /* No options */
+       data->compressed[4] = (t)&0xff;  /* Timestamp */
+       data->compressed[5] = (t>>8)&0xff;
+       data->compressed[6] = (t>>16)&0xff;
+       data->compressed[7] = (t>>24)&0xff;
+       data->compressed[8] = 0; /* No deflate options */
+       data->compressed[9] = 3; /* OS=Unix */
+       data->stream.next_out += 10;
+       data->stream.avail_out -= 10;
+
+       f->write = archive_compressor_gzip_write;
+
+       /* Initialize compression library. */
+       ret = deflateInit2(&(data->stream),
+           data->compression_level,
+           Z_DEFLATED,
+           -15 /* < 0 to suppress zlib header */,
+           8,
+           Z_DEFAULT_STRATEGY);
+
+       if (ret == Z_OK) {
+               f->data = data;
+               return (ARCHIVE_OK);
+       }
+
+       /* Library setup failed: clean up. */
+       archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, "Internal error "
+           "initializing compression library");
+
+       /* Override the error message if we know what really went wrong. */
+       switch (ret) {
+       case Z_STREAM_ERROR:
+               archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+                   "Internal error initializing "
+                   "compression library: invalid setup parameter");
+               break;
+       case Z_MEM_ERROR:
+               archive_set_error(f->archive, ENOMEM, "Internal error initializing "
+                   "compression library");
+               break;
+       case Z_VERSION_ERROR:
+               archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+                   "Internal error initializing "
+                   "compression library: invalid library version");
+               break;
+       }
+
+       return (ARCHIVE_FATAL);
+}
+
+/*
+ * Set write options.
+ */
+static int
+archive_compressor_gzip_options(struct archive_write_filter *f, const char *key,
+    const char *value)
+{
+       struct private_data *data = (struct private_data *)f->data;
+
+       if (strcmp(key, "compression-level") == 0) {
+               if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
+                   value[1] != '\0')
+                       return (ARCHIVE_WARN);
+               data->compression_level = value[0] - '0';
+               return (ARCHIVE_OK);
+       }
+       return (ARCHIVE_WARN);
+}
+
+/*
+ * Write data to the compressed stream.
+ */
+static int
+archive_compressor_gzip_write(struct archive_write_filter *f, const void *buff,
+    size_t length)
+{
+       struct private_data *data = (struct private_data *)f->data;
+       int ret;
+
+       /* Update statistics */
+       data->crc = crc32(data->crc, (const Bytef *)buff, length);
+       data->total_in += length;
+
+       /* Compress input data to output buffer */
+       SET_NEXT_IN(data, buff);
+       data->stream.avail_in = length;
+       if ((ret = drive_compressor(f, data, 0)) != ARCHIVE_OK)
+               return (ret);
+
+       return (ARCHIVE_OK);
+}
+
+/*
+ * Finish the compression...
+ */
+static int
+archive_compressor_gzip_close(struct archive_write_filter *f)
+{
+       unsigned char trailer[8];
+       struct private_data *data = (struct private_data *)f->data;
+       int ret;
+
+       ret = 0;
+       if (data != NULL) {
+               /* Finish compression cycle */
+               ret = drive_compressor(f, data, 1);
+               if (ret != ARCHIVE_OK)
+                       goto cleanup;
+
+               /* Write the last compressed data. */
+               ret = __archive_write_filter(f->next_filter,
+                   data->compressed,
+                   data->compressed_buffer_size - data->stream.avail_out);
+               if (ret != ARCHIVE_OK) {
+                       ret = ARCHIVE_FATAL;
+                       goto cleanup;
+               }
+
+               /* Build and write out 8-byte trailer. */
+               trailer[0] = (data->crc)&0xff;
+               trailer[1] = (data->crc >> 8)&0xff;
+               trailer[2] = (data->crc >> 16)&0xff;
+               trailer[3] = (data->crc >> 24)&0xff;
+               trailer[4] = (data->total_in)&0xff;
+               trailer[5] = (data->total_in >> 8)&0xff;
+               trailer[6] = (data->total_in >> 16)&0xff;
+               trailer[7] = (data->total_in >> 24)&0xff;
+               ret = __archive_write_filter(f->next_filter, trailer, 8);
+               if (ret != ARCHIVE_OK)
+                       ret = ARCHIVE_FATAL;
+
+       cleanup:
+               switch (deflateEnd(&(data->stream))) {
+               case Z_OK:
+                       break;
+               default:
+                       archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+                           "Failed to clean up compressor");
+                       ret = ARCHIVE_FATAL;
+               }
+       }
+       return (ret);
+}
+
+static int
+archive_compressor_gzip_free(struct archive_write_filter *f)
+{
+       struct private_data *data = (struct private_data *)f->data;
+       free(data->compressed);
+       free(data);
+       f->data = NULL;
+       return (ARCHIVE_OK);
+}
+
+/*
+ * Utility function to push input data through compressor,
+ * writing full output blocks as necessary.
+ *
+ * Note that this handles both the regular write case (finishing ==
+ * false) and the end-of-archive case (finishing == true).
+ */
+static int
+drive_compressor(struct archive_write_filter *f,
+    struct private_data *data, int finishing)
+{
+       int ret;
+
+       for (;;) {
+               if (data->stream.avail_out == 0) {
+                       ret = __archive_write_filter(f->next_filter,
+                           data->compressed,
+                           data->compressed_buffer_size);
+                       if (ret != ARCHIVE_OK)
+                               return (ARCHIVE_FATAL);
+                       data->stream.next_out = data->compressed;
+                       data->stream.avail_out = data->compressed_buffer_size;
+               }
+
+               /* If there's nothing to do, we're done. */
+               if (!finishing && data->stream.avail_in == 0)
+                       return (ARCHIVE_OK);
+
+               ret = deflate(&(data->stream),
+                   finishing ? Z_FINISH : Z_NO_FLUSH );
+
+               switch (ret) {
+               case Z_OK:
+                       /* In non-finishing case, check if compressor
+                        * consumed everything */
+                       if (!finishing && data->stream.avail_in == 0)
+                               return (ARCHIVE_OK);
+                       /* In finishing case, this return always means
+                        * there's more work */
+                       break;
+               case Z_STREAM_END:
+                       /* This return can only occur in finishing case. */
+                       return (ARCHIVE_OK);
+               default:
+                       /* Any other return value indicates an error. */
+                       archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+                           "GZip compression failed:"
+                           " deflate() call returned status %d",
+                           ret);
+                       return (ARCHIVE_FATAL);
+               }
+       }
+}
+
+#endif /* HAVE_ZLIB_H */
similarity index 57%
rename from libarchive/archive_write_set_compression_none.c
rename to libarchive/archive_write_add_filter_none.c
index e0216d9e12260b5d05cb8c39e6d85b1e818d5bf9..80747a4ccf75bfc129f133d972a9ba8c2884040e 100644 (file)
@@ -40,10 +40,20 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_none.c 201
 #include "archive_private.h"
 #include "archive_write_private.h"
 
-static int     archive_compressor_none_finish(struct archive_write *a);
-static int     archive_compressor_none_init(struct archive_write *);
-static int     archive_compressor_none_write(struct archive_write *,
+
+int
+archive_write_set_compression_none(struct archive *a)
+{
+       __archive_write_filters_free(a);
+       return (archive_write_add_filter_none(a));
+}
+
+
+static int archive_compressor_none_open(struct archive_write_filter *);
+static int archive_compressor_none_write(struct archive_write_filter *,
                    const void *, size_t);
+static int archive_compressor_none_close(struct archive_write_filter *);
+static int archive_compressor_none_free(struct archive_write_filter *);
 
 struct archive_none {
        char    *buffer;
@@ -52,47 +62,51 @@ struct archive_none {
        ssize_t  avail;         /* Free space left in buffer */
 };
 
+/*
+ * TODO: A little refactoring will turn this into a true no-op.
+ */
 int
-archive_write_set_compression_none(struct archive *_a)
+archive_write_add_filter_none(struct archive *_a)
 {
        struct archive_write *a = (struct archive_write *)_a;
+       struct archive_write_filter *f = __archive_write_allocate_filter(_a);
        __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
            ARCHIVE_STATE_NEW, "archive_write_set_compression_none");
-       a->compressor.init = &archive_compressor_none_init;
-       return (0);
+       f->open = &archive_compressor_none_open;
+       f->code = ARCHIVE_COMPRESSION_NONE;
+       f->name = "none";
+
+       return (ARCHIVE_OK);
 }
 
 /*
  * Setup callback.
  */
 static int
-archive_compressor_none_init(struct archive_write *a)
+archive_compressor_none_open(struct archive_write_filter *f)
 {
        int ret;
        struct archive_none *state;
 
-       a->archive.compression_code = ARCHIVE_COMPRESSION_NONE;
-       a->archive.compression_name = "none";
+       ret = __archive_write_open_filter(f->next_filter);
+       if (ret != 0)
+               return (ret);
 
-       if (a->client_opener != NULL) {
-               ret = (a->client_opener)(&a->archive, a->client_data);
-               if (ret != 0)
-                       return (ret);
-       }
+       f->bytes_per_block = archive_write_get_bytes_per_block(f->archive);
+       f->bytes_in_last_block = archive_write_get_bytes_in_last_block(f->archive);
 
-       state = (struct archive_none *)malloc(sizeof(*state));
+       state = (struct archive_none *)calloc(1, sizeof(*state));
        if (state == NULL) {
-               archive_set_error(&a->archive, ENOMEM,
+               archive_set_error(f->archive, ENOMEM,
                    "Can't allocate data for output buffering");
                return (ARCHIVE_FATAL);
        }
-       memset(state, 0, sizeof(*state));
 
-       state->buffer_size = a->bytes_per_block;
+       state->buffer_size = f->bytes_per_block;
        if (state->buffer_size != 0) {
                state->buffer = (char *)malloc(state->buffer_size);
                if (state->buffer == NULL) {
-                       archive_set_error(&a->archive, ENOMEM,
+                       archive_set_error(f->archive, ENOMEM,
                            "Can't allocate output buffer");
                        free(state);
                        return (ARCHIVE_FATAL);
@@ -102,9 +116,10 @@ archive_compressor_none_init(struct archive_write *a)
        state->next = state->buffer;
        state->avail = state->buffer_size;
 
-       a->compressor.data = state;
-       a->compressor.write = archive_compressor_none_write;
-       a->compressor.finish = archive_compressor_none_finish;
+       f->data = state;
+       f->write = archive_compressor_none_write;
+       f->close = archive_compressor_none_close;
+       f->free = archive_compressor_none_free;
        return (ARCHIVE_OK);
 }
 
@@ -112,24 +127,13 @@ archive_compressor_none_init(struct archive_write *a)
  * Write data to the stream.
  */
 static int
-archive_compressor_none_write(struct archive_write *a, const void *vbuff,
-    size_t length)
+archive_compressor_none_write(struct archive_write_filter *f,
+    const void *vbuff, size_t length)
 {
+       struct archive_none *state = (struct archive_none *)f->data;
        const char *buff;
        ssize_t remaining, to_copy;
-       ssize_t bytes_written;
-       struct archive_none *state;
-
-       state = (struct archive_none *)a->compressor.data;
-       buff = (const char *)vbuff;
-       if (a->client_writer == NULL) {
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
-                   "No write callback is registered?  "
-                   "This is probably an internal programming error.");
-               return (ARCHIVE_FATAL);
-       }
-
-       remaining = length;
+       int ret;
 
        /*
         * If there is no buffer for blocking, just pass the data
@@ -137,19 +141,12 @@ archive_compressor_none_write(struct archive_write *a, const void *vbuff,
         * particular, this supports "no write delay" operation for
         * special applications.  Just set the block size to zero.
         */
-       if (state->buffer_size == 0) {
-               while (remaining > 0) {
-                       bytes_written = (a->client_writer)(&a->archive,
-                           a->client_data, buff, remaining);
-                       if (bytes_written <= 0)
-                               return (ARCHIVE_FATAL);
-                       a->archive.raw_position += bytes_written;
-                       remaining -= bytes_written;
-                       buff += bytes_written;
-               }
-               a->archive.file_position += length;
-               return (ARCHIVE_OK);
-       }
+       if (state->buffer_size == 0)
+               return (__archive_write_filter(f->next_filter,
+                       vbuff, length));
+
+       buff = (const char *)vbuff;
+       remaining = length;
 
        /* If the copy buffer isn't empty, try to fill it. */
        if (state->avail < state->buffer_size) {
@@ -164,26 +161,23 @@ archive_compressor_none_write(struct archive_write *a, const void *vbuff,
                remaining -= to_copy;
                /* ... if it's full, write it out. */
                if (state->avail == 0) {
-                       bytes_written = (a->client_writer)(&a->archive,
-                           a->client_data, state->buffer, state->buffer_size);
-                       if (bytes_written <= 0)
+                       ret = __archive_write_filter(f->next_filter,
+                           state->buffer, state->buffer_size);
+                       if (ret != ARCHIVE_OK)
                                return (ARCHIVE_FATAL);
-                       /* XXX TODO: if bytes_written < state->buffer_size */
-                       a->archive.raw_position += bytes_written;
                        state->next = state->buffer;
                        state->avail = state->buffer_size;
                }
        }
 
+       /* Write out full blocks directly to client. */
        while (remaining > state->buffer_size) {
-               /* Write out full blocks directly to client. */
-               bytes_written = (a->client_writer)(&a->archive,
-                   a->client_data, buff, state->buffer_size);
-               if (bytes_written <= 0)
+               ret = __archive_write_filter(f->next_filter,
+                   buff, state->buffer_size);
+               if (ret != ARCHIVE_OK)
                        return (ARCHIVE_FATAL);
-               a->archive.raw_position += bytes_written;
-               buff += bytes_written;
-               remaining -= bytes_written;
+               buff += state->buffer_size;
+               remaining -= state->buffer_size;
        }
 
        if (remaining > 0) {
@@ -193,7 +187,6 @@ archive_compressor_none_write(struct archive_write *a, const void *vbuff,
                state->avail -= remaining;
        }
 
-       a->archive.file_position += length;
        return (ARCHIVE_OK);
 }
 
@@ -202,56 +195,49 @@ archive_compressor_none_write(struct archive_write *a, const void *vbuff,
  * Finish the compression.
  */
 static int
-archive_compressor_none_finish(struct archive_write *a)
+archive_compressor_none_close(struct archive_write_filter *f)
 {
+       struct archive_none *state = (struct archive_none *)f->data;
        ssize_t block_length;
        ssize_t target_block_length;
-       ssize_t bytes_written;
        int ret;
-       struct archive_none *state;
 
-       state = (struct archive_none *)a->compressor.data;
        ret = ARCHIVE_OK;
-       if (a->client_writer == NULL) {
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
-                   "No write callback is registered?  "
-                   "This is probably an internal programming error.");
-               return (ARCHIVE_FATAL);
-       }
 
        /* If there's pending data, pad and write the last block */
        if (state->next != state->buffer) {
                block_length = state->buffer_size - state->avail;
 
                /* Tricky calculation to determine size of last block */
-               if (a->bytes_in_last_block <= 0)
+               if (f->bytes_in_last_block <= 0)
                        /* Default or Zero: pad to full block */
-                       target_block_length = a->bytes_per_block;
+                       target_block_length = f->bytes_per_block;
                else
                        /* Round to next multiple of bytes_in_last_block. */
-                       target_block_length = a->bytes_in_last_block *
-                           ( (block_length + a->bytes_in_last_block - 1) /
-                               a->bytes_in_last_block);
-               if (target_block_length > a->bytes_per_block)
-                       target_block_length = a->bytes_per_block;
+                       target_block_length = f->bytes_in_last_block *
+                           ( (block_length + f->bytes_in_last_block - 1) /
+                               f->bytes_in_last_block);
+               if (target_block_length > f->bytes_per_block)
+                       target_block_length = f->bytes_per_block;
                if (block_length < target_block_length) {
                        memset(state->next, 0,
                            target_block_length - block_length);
                        block_length = target_block_length;
                }
-               bytes_written = (a->client_writer)(&a->archive,
-                   a->client_data, state->buffer, block_length);
-               if (bytes_written <= 0)
-                       ret = ARCHIVE_FATAL;
-               else {
-                       a->archive.raw_position += bytes_written;
-                       ret = ARCHIVE_OK;
-               }
+               ret = __archive_write_filter(f->next_filter,
+                   state->buffer, block_length);
        }
        if (state->buffer)
                free(state->buffer);
        free(state);
-       a->compressor.data = NULL;
+       f->data = NULL;
 
        return (ret);
 }
+
+static int
+archive_compressor_none_free(struct archive_write_filter *f)
+{
+       (void)f; /* UNUSED */
+       return (ARCHIVE_OK);
+}
diff --git a/libarchive/archive_write_add_filter_program.c b/libarchive/archive_write_add_filter_program.c
new file mode 100644 (file)
index 0000000..0efeb7c
--- /dev/null
@@ -0,0 +1,326 @@
+/*-
+ * Copyright (c) 2007 Joerg Sonnenberger
+ * 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: head/lib/libarchive/archive_write_set_compression_program.c 201104 2009-12-28 03:14:30Z kientzle $");
+
+#ifdef HAVE_SYS_WAIT_H
+#  include <sys/wait.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#  include <errno.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#  include <fcntl.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_write_private.h"
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+int
+archive_write_set_compression_program(struct archive *a, const char *cmd)
+{
+       __archive_write_filters_free(a);
+       return (archive_write_add_filter_program(a, cmd));
+}
+#endif
+
+/* This capability is only available on POSIX systems. */
+#if (!defined(HAVE_PIPE) || !defined(HAVE_FCNTL) || \
+    !(defined(HAVE_FORK) || defined(HAVE_VFORK))) && (!defined(_WIN32) || defined(__CYGWIN__))
+
+/*
+ * On non-Posix systems, allow the program to build, but choke if
+ * this function is actually invoked.
+ */
+int
+archive_write_add_filter_program(struct archive *_a, const char *cmd)
+{
+       archive_set_error(_a, -1,
+           "External compression programs not supported on this platform");
+       return (ARCHIVE_FATAL);
+}
+
+#else
+
+#include "filter_fork.h"
+
+struct private_data {
+       char            *cmd;
+       char            *description;
+       pid_t            child;
+       int              child_stdin, child_stdout;
+
+       char            *child_buf;
+       size_t           child_buf_len, child_buf_avail;
+};
+
+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 *);
+
+/*
+ * Add a filter to this write handle that passes all data through an
+ * external program.
+ */
+int
+archive_write_add_filter_program(struct archive *_a, const char *cmd)
+{
+       struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+       struct archive_write *a = (struct archive_write *)_a;
+       struct private_data *data;
+       static const char *prefix = "Program: ";
+       __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+           ARCHIVE_STATE_NEW, "archive_write_set_compression_program");
+       data = calloc(1, sizeof(*data));
+       if (data == NULL) {
+               archive_set_error(&a->archive, ENOMEM, "Out of memory");
+               return (ARCHIVE_FATAL);
+       }
+       data->cmd = strdup(cmd);
+       data->description = (char *)malloc(strlen(prefix) + strlen(cmd) + 1);
+       strcpy(data->description, prefix);
+       strcat(data->description, cmd);
+
+       f->name = data->description;
+       f->data = data;
+       f->open = &archive_compressor_program_open;
+       f->code = ARCHIVE_COMPRESSION_PROGRAM;
+       return (ARCHIVE_OK);
+}
+
+/*
+ * Setup callback.
+ */
+static int
+archive_compressor_program_open(struct archive_write_filter *f)
+{
+       struct private_data *data = (struct private_data *)f->data;
+       int ret;
+
+       ret = __archive_write_open_filter(f->next_filter);
+       if (ret != ARCHIVE_OK)
+               return (ret);
+
+       if (data->child_buf == NULL) {
+               data->child_buf_len = 65536;
+               data->child_buf_avail = 0;
+               data->child_buf = malloc(data->child_buf_len);
+
+               if (data->child_buf == NULL) {
+                       archive_set_error(f->archive, ENOMEM,
+                           "Can't allocate compression buffer");
+                       return (ARCHIVE_FATAL);
+               }
+       }
+
+       if ((data->child = __archive_create_child(data->cmd,
+                &data->child_stdin, &data->child_stdout)) == -1) {
+               archive_set_error(f->archive, EINVAL,
+                   "Can't initialise filter");
+               return (ARCHIVE_FATAL);
+       }
+
+       f->write = archive_compressor_program_write;
+       f->close = archive_compressor_program_close;
+       f->free = archive_compressor_program_free;
+       return (0);
+}
+
+static ssize_t
+child_write(struct archive_write_filter *f, const char *buf, size_t buf_len)
+{
+       struct private_data *data = f->data;
+       ssize_t ret;
+
+       if (data->child_stdin == -1)
+               return (-1);
+
+       if (buf_len == 0)
+               return (-1);
+
+restart_write:
+       do {
+               ret = write(data->child_stdin, buf, buf_len);
+       } while (ret == -1 && errno == EINTR);
+
+       if (ret > 0)
+               return (ret);
+       if (ret == 0) {
+               close(data->child_stdin);
+               data->child_stdin = -1;
+               fcntl(data->child_stdout, F_SETFL, 0);
+               return (0);
+       }
+       if (ret == -1 && errno != EAGAIN)
+               return (-1);
+
+       if (data->child_stdout == -1) {
+               fcntl(data->child_stdin, F_SETFL, 0);
+               __archive_check_child(data->child_stdin, data->child_stdout);
+               goto restart_write;
+       }
+
+       do {
+               ret = read(data->child_stdout,
+                   data->child_buf + data->child_buf_avail,
+                   data->child_buf_len - data->child_buf_avail);
+       } while (ret == -1 && errno == EINTR);
+
+       if (ret == 0 || (ret == -1 && errno == EPIPE)) {
+               close(data->child_stdout);
+               data->child_stdout = -1;
+               fcntl(data->child_stdin, F_SETFL, 0);
+               goto restart_write;
+       }
+       if (ret == -1 && errno == EAGAIN) {
+               __archive_check_child(data->child_stdin, data->child_stdout);
+               goto restart_write;
+       }
+       if (ret == -1)
+               return (-1);
+
+       data->child_buf_avail += ret;
+
+       ret = __archive_write_filter(f->next_filter,
+           data->child_buf, data->child_buf_avail);
+       if (ret <= 0)
+               return (-1);
+
+       if ((size_t)ret < data->child_buf_avail) {
+               memmove(data->child_buf, data->child_buf + ret,
+                   data->child_buf_avail - ret);
+       }
+       data->child_buf_avail -= ret;
+       goto restart_write;
+}
+
+/*
+ * Write data to the compressed stream.
+ */
+static int
+archive_compressor_program_write(struct archive_write_filter *f,
+    const void *buff, size_t length)
+{
+       ssize_t ret;
+       const char *buf;
+
+       buf = buff;
+       while (length > 0) {
+               ret = child_write(f, buf, length);
+               if (ret == -1 || ret == 0) {
+                       archive_set_error(f->archive, EIO,
+                           "Can't write to filter");
+                       return (ARCHIVE_FATAL);
+               }
+               length -= ret;
+               buf += ret;
+       }
+       return (ARCHIVE_OK);
+}
+
+
+/*
+ * Finish the compression...
+ */
+static int
+archive_compressor_program_close(struct archive_write_filter *f)
+{
+       struct private_data *data = (struct private_data *)f->data;
+       int ret, status;
+       ssize_t bytes_read;
+
+       ret = 0;
+       close(data->child_stdin);
+       data->child_stdin = -1;
+       fcntl(data->child_stdout, F_SETFL, 0);
+
+       for (;;) {
+               do {
+                       bytes_read = read(data->child_stdout,
+                           data->child_buf + data->child_buf_avail,
+                           data->child_buf_len - data->child_buf_avail);
+               } while (bytes_read == -1 && errno == EINTR);
+
+               if (bytes_read == 0 || (bytes_read == -1 && errno == EPIPE))
+                       break;
+
+               if (bytes_read == -1) {
+                       archive_set_error(f->archive, errno,
+                           "Read from filter failed unexpectedly.");
+                       ret = ARCHIVE_FATAL;
+                       goto cleanup;
+               }
+               data->child_buf_avail += bytes_read;
+
+               ret = __archive_write_filter(f->next_filter,
+                   data->child_buf, data->child_buf_avail);
+               if (ret != ARCHIVE_OK) {
+                       ret = ARCHIVE_FATAL;
+                       goto cleanup;
+               }
+               data->child_buf_avail = 0;
+       }
+
+cleanup:
+       /* Shut down the child. */
+       if (data->child_stdin != -1)
+               close(data->child_stdin);
+       if (data->child_stdout != -1)
+               close(data->child_stdout);
+       while (waitpid(data->child, &status, 0) == -1 && errno == EINTR)
+               continue;
+
+       if (status != 0) {
+               archive_set_error(f->archive, EIO,
+                   "Filter exited with failure.");
+               ret = ARCHIVE_FATAL;
+       }
+       return (ret);
+}
+
+static int
+archive_compressor_program_free(struct archive_write_filter *f)
+{
+       struct private_data *data = (struct private_data *)f->data;
+       free(data->cmd);
+       free(data->description);
+       free(data->child_buf);
+       free(data);
+       f->data = NULL;
+       return (ARCHIVE_OK);
+}
+
+#endif /* !defined(HAVE_PIPE) || !defined(HAVE_VFORK) || !defined(HAVE_FCNTL) */
diff --git a/libarchive/archive_write_add_filter_xz.c b/libarchive/archive_write_add_filter_xz.c
new file mode 100644 (file)
index 0000000..a54d3a4
--- /dev/null
@@ -0,0 +1,371 @@
+/*-
+ * Copyright (c) 2009 Michihiro NAKAJIMA
+ * Copyright (c) 2003-2010 Tim Kientzle
+ * 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: head/lib/libarchive/archive_write_set_compression_xz.c 201108 2009-12-28 03:28:21Z kientzle $");
+
+#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 <time.h>
+#ifdef HAVE_LZMA_H
+#include <lzma.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_write_private.h"
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+int
+archive_write_set_compression_lzma(struct archive *a)
+{
+       __archive_write_filters_free(a);
+       return (archive_write_add_filter_lzma(a));
+}
+
+int
+archive_write_set_compression_xz(struct archive *a)
+{
+       __archive_write_filters_free(a);
+       return (archive_write_add_filter_xz(a));
+}
+#endif
+
+#ifndef HAVE_LZMA_H
+int
+archive_write_add_filter_xz(struct archive *a)
+{
+       archive_set_error(a, ARCHIVE_ERRNO_MISC,
+           "xz compression not supported on this platform");
+       return (ARCHIVE_FATAL);
+}
+
+int
+archive_write_add_filter_lzma(struct archive *a)
+{
+       archive_set_error(a, ARCHIVE_ERRNO_MISC,
+           "lzma compression not supported on this platform");
+       return (ARCHIVE_FATAL);
+}
+#else
+/* Don't compile this if we don't have liblzma. */
+
+struct private_data {
+       int              compression_level;
+       lzma_stream      stream;
+       lzma_filter      lzmafilters[2];
+       lzma_options_lzma lzma_opt;
+       int64_t          total_in;
+       unsigned char   *compressed;
+       size_t           compressed_buffer_size;
+};
+
+static int     archive_compressor_xz_options(struct archive_write_filter *,
+                   const char *, const char *);
+static int     archive_compressor_xz_open(struct archive_write_filter *);
+static int     archive_compressor_xz_write(struct archive_write_filter *,
+                   const void *, size_t);
+static int     archive_compressor_xz_close(struct archive_write_filter *);
+static int     archive_compressor_xz_free(struct archive_write_filter *);
+static int     drive_compressor(struct archive_write_filter *,
+                   struct private_data *, int finishing);
+
+
+static int
+common_setup(struct archive_write_filter *f)
+{
+       struct private_data *data;
+       struct archive_write *a = (struct archive_write *)f->archive;
+       __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+           ARCHIVE_STATE_NEW, "archive_write_add_filter_xz");
+       data = calloc(1, sizeof(*data));
+       if (data == NULL) {
+               archive_set_error(&a->archive, ENOMEM, "Out of memory");
+               return (ARCHIVE_FATAL);
+       }
+       f->data = data;
+       data->compression_level = LZMA_PRESET_DEFAULT;
+       f->open = &archive_compressor_xz_open;
+       f->close = archive_compressor_xz_close;
+       f->free = archive_compressor_xz_free;
+       f->options = &archive_compressor_xz_options;
+       return (ARCHIVE_OK);
+}
+
+/*
+ * Add an xz compression filter to this write handle.
+ */
+int
+archive_write_add_filter_xz(struct archive *_a)
+{
+       struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+       int r = common_setup(f);
+       if (r == ARCHIVE_OK) {
+               f->code = ARCHIVE_COMPRESSION_XZ;
+               f->name = "xz";
+       }
+       return (r);
+}
+
+/* LZMA is handled identically, we just need a different compression
+ * code set.  (The liblzma setup looks at the code to determine
+ * the one place that XZ and LZMA require different handling.) */
+int
+archive_write_add_filter_lzma(struct archive *_a)
+{
+       struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+       int r = common_setup(f);
+       if (r == ARCHIVE_OK) {
+               f->code = ARCHIVE_COMPRESSION_LZMA;
+               f->name = "lzma";
+       }
+       return (r);
+}
+
+static int
+archive_compressor_xz_init_stream(struct archive_write_filter *f,
+    struct private_data *data)
+{
+       int ret;
+
+       data->stream = (lzma_stream)LZMA_STREAM_INIT;
+       data->stream.next_out = data->compressed;
+       data->stream.avail_out = data->compressed_buffer_size;
+       if (f->code == ARCHIVE_COMPRESSION_XZ)
+               ret = lzma_stream_encoder(&(data->stream),
+                   data->lzmafilters, LZMA_CHECK_CRC64);
+       else
+               ret = lzma_alone_encoder(&(data->stream), &data->lzma_opt);
+       if (ret == LZMA_OK)
+               return (ARCHIVE_OK);
+
+       switch (ret) {
+       case LZMA_MEM_ERROR:
+               archive_set_error(f->archive, ENOMEM,
+                   "Internal error initializing compression library: "
+                   "Cannot allocate memory");
+               break;
+       default:
+               archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+                   "Internal error initializing compression library: "
+                   "It's a bug in liblzma");
+               break;
+       }
+       return (ARCHIVE_FATAL);
+}
+
+/*
+ * Setup callback.
+ */
+static int
+archive_compressor_xz_open(struct archive_write_filter *f)
+{
+       struct private_data *data = f->data;
+       int ret;
+
+       ret = __archive_write_open_filter(f->next_filter);
+       if (ret != ARCHIVE_OK)
+               return (ret);
+
+       if (data->compressed == NULL) {
+               data->compressed_buffer_size = 65536;
+               data->compressed
+                   = (unsigned char *)malloc(data->compressed_buffer_size);
+               if (data->compressed == NULL) {
+                       archive_set_error(f->archive, ENOMEM,
+                           "Can't allocate data for compression buffer");
+                       return (ARCHIVE_FATAL);
+               }
+       }
+
+       f->write = archive_compressor_xz_write;
+
+       /* Initialize compression library. */
+       if (lzma_lzma_preset(&data->lzma_opt, data->compression_level)) {
+               archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+                   "Internal error initializing compression library");
+       }
+       data->lzmafilters[0].id = LZMA_FILTER_LZMA2;
+       data->lzmafilters[0].options = &data->lzma_opt;
+       data->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
+       ret = archive_compressor_xz_init_stream(f, data);
+       if (ret == LZMA_OK) {
+               f->data = data;
+               return (0);
+       }
+       return (ARCHIVE_FATAL);
+}
+
+/*
+ * Set write options.
+ */
+static int
+archive_compressor_xz_options(struct archive_write_filter *f,
+    const char *key, const char *value)
+{
+       struct private_data *data = (struct private_data *)f->data;
+
+       if (strcmp(key, "compression-level") == 0) {
+               if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
+                   value[1] != '\0')
+                       return (ARCHIVE_WARN);
+               data->compression_level = value[0] - '0';
+               if (data->compression_level > 6)
+                       data->compression_level = 6;
+               return (ARCHIVE_OK);
+       }
+
+       return (ARCHIVE_WARN);
+}
+
+/*
+ * Write data to the compressed stream.
+ */
+static int
+archive_compressor_xz_write(struct archive_write_filter *f,
+    const void *buff, size_t length)
+{
+       struct private_data *data = (struct private_data *)f->data;
+       int ret;
+
+       /* Update statistics */
+       data->total_in += length;
+
+       /* Compress input data to output buffer */
+       data->stream.next_in = buff;
+       data->stream.avail_in = length;
+       if ((ret = drive_compressor(f, data, 0)) != ARCHIVE_OK)
+               return (ret);
+
+       return (ARCHIVE_OK);
+}
+
+
+/*
+ * Finish the compression...
+ */
+static int
+archive_compressor_xz_close(struct archive_write_filter *f)
+{
+       struct private_data *data = (struct private_data *)f->data;
+       int ret;
+
+       if (data == NULL)
+               return (ARCHIVE_OK);
+       ret = drive_compressor(f, data, 1);
+       if (ret == ARCHIVE_OK) {
+               ret = __archive_write_filter(f->next_filter,
+                   data->compressed,
+                   data->compressed_buffer_size - data->stream.avail_out);
+       }
+       lzma_end(&(data->stream));
+       return (ret);
+}
+
+static int
+archive_compressor_xz_free(struct archive_write_filter *f)
+{
+       struct private_data *data = (struct private_data *)f->data;
+       free(data->compressed);
+       free(data);
+       f->data = NULL;
+       return (ARCHIVE_OK);
+}
+
+/*
+ * Utility function to push input data through compressor,
+ * writing full output blocks as necessary.
+ *
+ * Note that this handles both the regular write case (finishing ==
+ * false) and the end-of-archive case (finishing == true).
+ */
+static int
+drive_compressor(struct archive_write_filter *f,
+    struct private_data *data, int finishing)
+{
+       int ret;
+
+       for (;;) {
+               if (data->stream.avail_out == 0) {
+                       ret = __archive_write_filter(f->next_filter,
+                           data->compressed,
+                           data->compressed_buffer_size);
+                       if (ret != ARCHIVE_OK)
+                               return (ARCHIVE_FATAL);
+                       data->stream.next_out = data->compressed;
+                       data->stream.avail_out = data->compressed_buffer_size;
+               }
+
+               /* If there's nothing to do, we're done. */
+               if (!finishing && data->stream.avail_in == 0)
+                       return (ARCHIVE_OK);
+
+               ret = lzma_code(&(data->stream),
+                   finishing ? LZMA_FINISH : LZMA_RUN );
+
+               switch (ret) {
+               case LZMA_OK:
+                       /* In non-finishing case, check if compressor
+                        * consumed everything */
+                       if (!finishing && data->stream.avail_in == 0)
+                               return (ARCHIVE_OK);
+                       /* In finishing case, this return always means
+                        * there's more work */
+                       break;
+               case LZMA_STREAM_END:
+                       /* This return can only occur in finishing case. */
+                       if (finishing)
+                               return (ARCHIVE_OK);
+                       archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+                           "lzma compression data error");
+                       return (ARCHIVE_FATAL);
+               case LZMA_MEMLIMIT_ERROR:
+                       archive_set_error(f->archive, ENOMEM,
+                           "lzma compression error: "
+                           "%ju MiB would have been needed",
+                           (lzma_memusage(&(data->stream)) + 1024 * 1024 -1)
+                           / (1024 * 1024));
+                       return (ARCHIVE_FATAL);
+               default:
+                       /* Any other return value indicates an error. */
+                       archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+                           "lzma compression failed:"
+                           " lzma_code() call returned status %d",
+                           ret);
+                       return (ARCHIVE_FATAL);
+               }
+       }
+}
+
+#endif /* HAVE_LZMA_H */
index f734037cb54bdc9211d9e4f421dc5944513d61b4..ee3ad66ffe4f09d93f3f7c9fb08fdec8a791b4bb 100644 (file)
@@ -192,11 +192,13 @@ struct archive_write_disk {
        /* Handle for the file we're restoring. */
        int                      fd;
        /* Current offset for writing data to the file. */
-       off_t                    offset;
+       int64_t                  offset;
        /* Last offset actually written to disk. */
-       off_t                    fd_offset;
+       int64_t                  fd_offset;
+       /* Total bytes actually written to files. */
+       int64_t                  total_bytes_written;
        /* Maximum size of file, -1 if unknown. */
-       off_t                    filesize;
+       int64_t                  filesize;
        /* Dir we were in before this restore; only for deep paths. */
        int                      restore_pwd;
        /* Mode we should use for this entry; affected by _PERM and umask. */
@@ -254,15 +256,16 @@ static ssize_t    write_data_block(struct archive_write_disk *,
 
 static struct archive_vtable *archive_write_disk_vtable(void);
 
-static int     _archive_write_close(struct archive *);
-static int     _archive_write_free(struct archive *);
-static int     _archive_write_header(struct archive *, struct archive_entry *);
-static int     _archive_write_finish_entry(struct archive *);
-static ssize_t _archive_write_data(struct archive *, const void *, size_t);
-static ssize_t _archive_write_data_block(struct archive *, const void *, size_t, off_t);
+static int     _archive_write_disk_close(struct archive *);
+static int     _archive_write_disk_free(struct archive *);
+static int     _archive_write_disk_header(struct archive *, struct archive_entry *);
+static int64_t _archive_write_disk_filter_bytes(struct archive *, int);
+static int     _archive_write_disk_finish_entry(struct archive *);
+static ssize_t _archive_write_disk_data(struct archive *, const void *, size_t);
+static ssize_t _archive_write_disk_data_block(struct archive *, const void *, size_t, off_t);
 
 static int
-_archive_write_disk_lazy_stat(struct archive_write_disk *a)
+lazy_stat(struct archive_write_disk *a)
 {
        if (a->pst != NULL) {
                /* Already have stat() data available. */
@@ -293,16 +296,29 @@ archive_write_disk_vtable(void)
        static int inited = 0;
 
        if (!inited) {
-               av.archive_close = _archive_write_close;
-               av.archive_free = _archive_write_free;
-               av.archive_write_header = _archive_write_header;
-               av.archive_write_finish_entry = _archive_write_finish_entry;
-               av.archive_write_data = _archive_write_data;
-               av.archive_write_data_block = _archive_write_data_block;
+               av.archive_close = _archive_write_disk_close;
+               av.archive_filter_bytes = _archive_write_disk_filter_bytes;
+               av.archive_free = _archive_write_disk_free;
+               av.archive_write_header = _archive_write_disk_header;
+               av.archive_write_finish_entry
+                   = _archive_write_disk_finish_entry;
+               av.archive_write_data = _archive_write_disk_data;
+               av.archive_write_data_block = _archive_write_disk_data_block;
        }
        return (&av);
 }
 
+static int64_t
+_archive_write_disk_filter_bytes(struct archive *_a, int n)
+{
+       (void)n; /* UNUSED */
+       struct archive_write_disk *a = (struct archive_write_disk *)_a;
+//     fprintf(stderr, "archive_write_disk_filter_bytes(%d)=%d\n", n, (int)a->fd_offset);
+       if (n == -1 || n == 0)
+               return (a->total_bytes_written);
+       return (-1);
+}
+
 
 int
 archive_write_disk_set_options(struct archive *_a, int flags)
@@ -326,7 +342,7 @@ archive_write_disk_set_options(struct archive *_a, int flags)
  *
  */
 static int
-_archive_write_header(struct archive *_a, struct archive_entry *entry)
+_archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
 {
        struct archive_write_disk *a = (struct archive_write_disk *)_a;
        struct fixup_entry *fe;
@@ -337,7 +353,7 @@ _archive_write_header(struct archive *_a, struct archive_entry *entry)
            "archive_write_disk_header");
        archive_clear_error(&a->archive);
        if (a->archive.state & ARCHIVE_STATE_DATA) {
-               r = _archive_write_finish_entry(&a->archive);
+               r = _archive_write_disk_finish_entry(&a->archive);
                if (r == ARCHIVE_FATAL)
                        return (r);
        }
@@ -591,7 +607,7 @@ write_data_block(struct archive_write_disk *a, const char *buff, size_t size)
        if (a->flags & ARCHIVE_EXTRACT_SPARSE) {
 #if HAVE_STRUCT_STAT_ST_BLKSIZE
                int r;
-               if ((r = _archive_write_disk_lazy_stat(a)) != ARCHIVE_OK)
+               if ((r = lazy_stat(a)) != ARCHIVE_OK)
                        return (r);
                block_size = a->pst->st_blksize;
 #else
@@ -602,7 +618,7 @@ write_data_block(struct archive_write_disk *a, const char *buff, size_t size)
        }
 
        /* If this write would run beyond the file size, truncate it. */
-       if (a->filesize >= 0 && (off_t)(a->offset + size) > a->filesize)
+       if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize)
                start_size = size = (size_t)(a->filesize - a->offset);
 
        /* Write the data. */
@@ -612,7 +628,7 @@ write_data_block(struct archive_write_disk *a, const char *buff, size_t size)
                } else {
                        /* We're sparsifying the file. */
                        const char *p, *end;
-                       off_t block_end;
+                       int64_t block_end;
 
                        /* Skip leading zero bytes. */
                        for (p = buff, end = buff + size; p < end; ++p) {
@@ -643,8 +659,6 @@ write_data_block(struct archive_write_disk *a, const char *buff, size_t size)
                                return (ARCHIVE_FATAL);
                        }
                        a->fd_offset = a->offset;
-                       a->archive.file_position = a->offset;
-                       a->archive.raw_position = a->offset;
                }
                bytes_written = write(a->fd, buff, bytes_to_write);
                if (bytes_written < 0) {
@@ -653,23 +667,22 @@ write_data_block(struct archive_write_disk *a, const char *buff, size_t size)
                }
                buff += bytes_written;
                size -= bytes_written;
+               a->total_bytes_written += bytes_written;
                a->offset += bytes_written;
-               a->archive.file_position += bytes_written;
-               a->archive.raw_position += bytes_written;
                a->fd_offset = a->offset;
        }
        return (start_size - size);
 }
 
 static ssize_t
-_archive_write_data_block(struct archive *_a,
+_archive_write_disk_data_block(struct archive *_a,
     const void *buff, size_t size, off_t offset)
 {
        struct archive_write_disk *a = (struct archive_write_disk *)_a;
        ssize_t r;
 
        __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
-           ARCHIVE_STATE_DATA, "archive_write_disk_block");
+           ARCHIVE_STATE_DATA, "archive_write_data_block");
 
        a->offset = offset;
        r = write_data_block(a, buff, size);
@@ -684,7 +697,7 @@ _archive_write_data_block(struct archive *_a,
 }
 
 static ssize_t
-_archive_write_data(struct archive *_a, const void *buff, size_t size)
+_archive_write_disk_data(struct archive *_a, const void *buff, size_t size)
 {
        struct archive_write_disk *a = (struct archive_write_disk *)_a;
 
@@ -695,7 +708,7 @@ _archive_write_data(struct archive *_a, const void *buff, size_t size)
 }
 
 static int
-_archive_write_finish_entry(struct archive *_a)
+_archive_write_disk_finish_entry(struct archive *_a)
 {
        struct archive_write_disk *a = (struct archive_write_disk *)_a;
        int ret = ARCHIVE_OK;
@@ -730,7 +743,7 @@ _archive_write_finish_entry(struct archive *_a)
                 * to see what happened.
                 */
                a->pst = NULL;
-               if ((ret = _archive_write_disk_lazy_stat(a)) != ARCHIVE_OK)
+               if ((ret = lazy_stat(a)) != ARCHIVE_OK)
                        return (ret);
                /* We can use lseek()/write() to extend the file if
                 * ftruncate didn't work or isn't available. */
@@ -1257,7 +1270,7 @@ create_filesystem_object(struct archive_write_disk *a)
  * reason we set directory perms here. XXX
  */
 static int
-_archive_write_close(struct archive *_a)
+_archive_write_disk_close(struct archive *_a)
 {
        struct archive_write_disk *a = (struct archive_write_disk *)_a;
        struct fixup_entry *next, *p;
@@ -1266,7 +1279,7 @@ _archive_write_close(struct archive *_a)
        __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
            ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
            "archive_write_disk_close");
-       ret = _archive_write_finish_entry(&a->archive);
+       ret = _archive_write_disk_finish_entry(&a->archive);
 
        /* Sort dir list so directories are fixed up in depth-first order. */
        p = sort_dir_list(a->fixup_list);
@@ -1325,11 +1338,11 @@ _archive_write_close(struct archive *_a)
 }
 
 static int
-_archive_write_free(struct archive *_a)
+_archive_write_disk_free(struct archive *_a)
 {
        struct archive_write_disk *a = (struct archive_write_disk *)_a;
        int ret;
-       ret = _archive_write_close(&a->archive);
+       ret = _archive_write_disk_close(&a->archive);
        if (a->cleanup_gid != NULL && a->lookup_gid_data != NULL)
                (a->cleanup_gid)(a->lookup_gid_data);
        if (a->cleanup_uid != NULL && a->lookup_uid_data != NULL)
@@ -2031,7 +2044,7 @@ set_mode(struct archive_write_disk *a, int mode)
                 * process, since systems sometimes set GID from
                 * the enclosing dir or based on ACLs.
                 */
-               if ((r = _archive_write_disk_lazy_stat(a)) != ARCHIVE_OK)
+               if ((r = lazy_stat(a)) != ARCHIVE_OK)
                        return (r);
                if (a->pst->st_gid != a->gid) {
                        mode &= ~ S_ISGID;
@@ -2216,7 +2229,7 @@ set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
         * about the correct approach if we're overwriting an existing
         * file that already has flags on it. XXX
         */
-       if ((r = _archive_write_disk_lazy_stat(a)) != ARCHIVE_OK)
+       if ((r = lazy_stat(a)) != ARCHIVE_OK)
                return (r);
 
        a->st.st_flags &= ~clear;
index f9b656555b3cfeab14c950f662d5fcd193a93ab7..ae5adfc0909325753c00818932be5c55490bfd34 100644 (file)
 #include "archive_string.h"
 #include "archive_private.h"
 
+struct archive_write;
+
+struct archive_write_filter {
+       int64_t bytes_written;
+       struct archive *archive; /* Associated archive. */
+       struct archive_write_filter *next_filter; /* Who I write to. */
+       int     (*options)(struct archive_write_filter *,
+           const char *key, const char *value);
+       int     (*open)(struct archive_write_filter *);
+       int     (*write)(struct archive_write_filter *, const void *, size_t);
+       int     (*close)(struct archive_write_filter *);
+       int     (*free)(struct archive_write_filter *);
+       void     *data;
+       const char *name;
+       int       code;
+       int       bytes_per_block;
+       int       bytes_in_last_block;
+};
+
+#if ARCHIVE_VERSION < 4000000
+void __archive_write_filters_free(struct archive *);
+#endif
+
+struct archive_write_filter *__archive_write_allocate_filter(struct archive *);
+
+int __archive_write_output(struct archive_write *, const void *, size_t);
+int __archive_write_filter(struct archive_write_filter *, const void *, size_t);
+int __archive_write_open_filter(struct archive_write_filter *);
+int __archive_write_close_filter(struct archive_write_filter *);
+
 struct archive_write {
        struct archive  archive;
 
@@ -71,21 +101,12 @@ struct archive_write {
         * effect on compression "none."
         */
        int               pad_uncompressed;
-       int               pad_uncompressed_byte; /* TODO: Support this. */
 
        /*
-        * On write, the client just invokes an archive_write_set function
-        * which sets up the data here directly.
+        * First and last write filters in the pipeline.
         */
-       struct {
-               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;
+       struct archive_write_filter *filter_first;
+       struct archive_write_filter *filter_last;
 
        /*
         * Pointers to format-specific functions for writing.  They're
diff --git a/libarchive/archive_write_set_compression_bzip2.c b/libarchive/archive_write_set_compression_bzip2.c
deleted file mode 100644 (file)
index beb2379..0000000
+++ /dev/null
@@ -1,408 +0,0 @@
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * 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: head/lib/libarchive/archive_write_set_compression_bzip2.c 201091 2009-12-28 02:22:41Z kientzle $");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#include <stdio.h>
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_BZLIB_H
-#include <bzlib.h>
-#endif
-
-#include "archive.h"
-#include "archive_private.h"
-#include "archive_write_private.h"
-
-#ifndef HAVE_BZLIB_H
-int
-archive_write_set_compression_bzip2(struct archive *a)
-{
-       archive_set_error(a, ARCHIVE_ERRNO_MISC,
-           "bzip2 compression not supported on this platform");
-       return (ARCHIVE_FATAL);
-}
-#else
-/* Don't compile this if we don't have bzlib. */
-
-struct private_data {
-       bz_stream        stream;
-       int64_t          total_in;
-       char            *compressed;
-       size_t           compressed_buffer_size;
-};
-
-struct private_config {
-       int              compression_level;
-};
-
-/*
- * Yuck.  bzlib.h is not const-correct, so I need this one bit
- * of ugly hackery to convert a const * pointer to a non-const pointer.
- */
-#define        SET_NEXT_IN(st,src)                                     \
-       (st)->stream.next_in = (char *)(uintptr_t)(const void *)(src)
-
-static int     archive_compressor_bzip2_finish(struct archive_write *);
-static int     archive_compressor_bzip2_init(struct archive_write *);
-static int     archive_compressor_bzip2_options(struct archive_write *,
-                   const char *, const char *);
-static int     archive_compressor_bzip2_write(struct archive_write *,
-                   const void *, size_t);
-static int     drive_compressor(struct archive_write *, struct private_data *,
-                   int finishing);
-
-/*
- * Allocate, initialize and return an archive object.
- */
-int
-archive_write_set_compression_bzip2(struct archive *_a)
-{
-       struct archive_write *a = (struct archive_write *)_a;
-       struct private_config *config;
-       __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
-           ARCHIVE_STATE_NEW, "archive_write_set_compression_bzip2");
-       config = malloc(sizeof(*config));
-       if (config == NULL) {
-               archive_set_error(&a->archive, ENOMEM, "Out of memory");
-               return (ARCHIVE_FATAL);
-       }
-       a->compressor.config = config;
-       a->compressor.finish = archive_compressor_bzip2_finish;
-       config->compression_level = 9; /* default */
-       a->compressor.init = &archive_compressor_bzip2_init;
-       a->compressor.options = &archive_compressor_bzip2_options;
-       a->archive.compression_code = ARCHIVE_COMPRESSION_BZIP2;
-       a->archive.compression_name = "bzip2";
-       return (ARCHIVE_OK);
-}
-
-/*
- * Setup callback.
- */
-static int
-archive_compressor_bzip2_init(struct archive_write *a)
-{
-       int ret;
-       struct private_data *state;
-       struct private_config *config;
-
-       config = (struct private_config *)a->compressor.config;
-       if (a->client_opener != NULL) {
-               ret = (a->client_opener)(&a->archive, a->client_data);
-               if (ret != 0)
-                       return (ret);
-       }
-
-       state = (struct private_data *)malloc(sizeof(*state));
-       if (state == NULL) {
-               archive_set_error(&a->archive, ENOMEM,
-                   "Can't allocate data for compression");
-               return (ARCHIVE_FATAL);
-       }
-       memset(state, 0, sizeof(*state));
-
-       state->compressed_buffer_size = a->bytes_per_block;
-       state->compressed = (char *)malloc(state->compressed_buffer_size);
-
-       if (state->compressed == NULL) {
-               archive_set_error(&a->archive, ENOMEM,
-                   "Can't allocate data for compression buffer");
-               free(state);
-               return (ARCHIVE_FATAL);
-       }
-
-       state->stream.next_out = state->compressed;
-       state->stream.avail_out = state->compressed_buffer_size;
-       a->compressor.write = archive_compressor_bzip2_write;
-
-       /* Initialize compression library */
-       ret = BZ2_bzCompressInit(&(state->stream),
-           config->compression_level, 0, 30);
-       if (ret == BZ_OK) {
-               a->compressor.data = state;
-               return (ARCHIVE_OK);
-       }
-
-       /* Library setup failed: clean up. */
-       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-           "Internal error initializing compression library");
-       free(state->compressed);
-       free(state);
-
-       /* Override the error message if we know what really went wrong. */
-       switch (ret) {
-       case BZ_PARAM_ERROR:
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                   "Internal error initializing compression library: "
-                   "invalid setup parameter");
-               break;
-       case BZ_MEM_ERROR:
-               archive_set_error(&a->archive, ENOMEM,
-                   "Internal error initializing compression library: "
-                   "out of memory");
-               break;
-       case BZ_CONFIG_ERROR:
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                   "Internal error initializing compression library: "
-                   "mis-compiled library");
-               break;
-       }
-
-       return (ARCHIVE_FATAL);
-
-}
-
-/*
- * Set write options.
- */
-static int
-archive_compressor_bzip2_options(struct archive_write *a, const char *key,
-    const char *value)
-{
-       struct private_config *config;
-
-       config = (struct private_config *)a->compressor.config;
-       if (strcmp(key, "compression-level") == 0) {
-               if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
-                   value[1] != '\0')
-                       return (ARCHIVE_WARN);
-               config->compression_level = value[0] - '0';
-               /* Make '0' be a synonym for '1'. */
-               /* This way, bzip2 compressor supports the same 0..9
-                * range of levels as gzip. */
-               if (config->compression_level < 1)
-                       config->compression_level = 1;
-               return (ARCHIVE_OK);
-       }
-
-       return (ARCHIVE_WARN);
-}
-
-/*
- * Write data to the compressed stream.
- *
- * Returns ARCHIVE_OK if all data written, error otherwise.
- */
-static int
-archive_compressor_bzip2_write(struct archive_write *a, const void *buff,
-    size_t length)
-{
-       struct private_data *state;
-
-       state = (struct private_data *)a->compressor.data;
-       if (a->client_writer == NULL) {
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
-                   "No write callback is registered?  "
-                   "This is probably an internal programming error.");
-               return (ARCHIVE_FATAL);
-       }
-
-       /* Update statistics */
-       state->total_in += length;
-
-       /* Compress input data to output buffer */
-       SET_NEXT_IN(state, buff);
-       state->stream.avail_in = length;
-       if (drive_compressor(a, state, 0))
-               return (ARCHIVE_FATAL);
-       a->archive.file_position += length;
-       return (ARCHIVE_OK);
-}
-
-
-/*
- * Finish the compression.
- */
-static int
-archive_compressor_bzip2_finish(struct archive_write *a)
-{
-       ssize_t block_length;
-       int ret;
-       struct private_data *state;
-       ssize_t target_block_length;
-       ssize_t bytes_written;
-       unsigned tocopy;
-
-       ret = ARCHIVE_OK;
-       state = (struct private_data *)a->compressor.data;
-       if (state != NULL) {
-               if (a->client_writer == NULL) {
-                       archive_set_error(&a->archive,
-                           ARCHIVE_ERRNO_PROGRAMMER,
-                           "No write callback is registered?\n"
-                           "This is probably an internal programming error.");
-                       ret = ARCHIVE_FATAL;
-                       goto cleanup;
-               }
-
-               /* By default, always pad the uncompressed data. */
-               if (a->pad_uncompressed) {
-                       tocopy = a->bytes_per_block -
-                           (state->total_in % a->bytes_per_block);
-                       while (tocopy > 0 && tocopy < (unsigned)a->bytes_per_block) {
-                               SET_NEXT_IN(state, a->nulls);
-                               state->stream.avail_in = tocopy < a->null_length ?
-                                   tocopy : a->null_length;
-                               state->total_in += state->stream.avail_in;
-                               tocopy -= state->stream.avail_in;
-                               ret = drive_compressor(a, state, 0);
-                               if (ret != ARCHIVE_OK)
-                                       goto cleanup;
-                       }
-               }
-
-               /* Finish compression cycle. */
-               if ((ret = drive_compressor(a, state, 1)))
-                       goto cleanup;
-
-               /* Optionally, pad the final compressed block. */
-               block_length = state->stream.next_out - state->compressed;
-
-               /* Tricky calculation to determine size of last block. */
-               if (a->bytes_in_last_block <= 0)
-                       /* Default or Zero: pad to full block */
-                       target_block_length = a->bytes_per_block;
-               else
-                       /* Round length to next multiple of bytes_in_last_block. */
-                       target_block_length = a->bytes_in_last_block *
-                           ( (block_length + a->bytes_in_last_block - 1) /
-                               a->bytes_in_last_block);
-               if (target_block_length > a->bytes_per_block)
-                       target_block_length = a->bytes_per_block;
-               if (block_length < target_block_length) {
-                       memset(state->stream.next_out, 0,
-                           target_block_length - block_length);
-                       block_length = target_block_length;
-               }
-
-               /* Write the last block */
-               bytes_written = (a->client_writer)(&a->archive, a->client_data,
-                   state->compressed, block_length);
-
-               /* TODO: Handle short write of final block. */
-               if (bytes_written <= 0)
-                       ret = ARCHIVE_FATAL;
-               else {
-                       a->archive.raw_position += ret;
-                       ret = ARCHIVE_OK;
-               }
-
-               /* Cleanup: shut down compressor, release memory, etc. */
-cleanup:
-               switch (BZ2_bzCompressEnd(&(state->stream))) {
-               case BZ_OK:
-                       break;
-               default:
-                       archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
-                           "Failed to clean up compressor");
-                       ret = ARCHIVE_FATAL;
-               }
-
-               free(state->compressed);
-               free(state);
-       }
-       /* Free configuration data even if we were never fully initialized. */
-       free(a->compressor.config);
-       a->compressor.config = NULL;
-       return (ret);
-}
-
-/*
- * Utility function to push input data through compressor, writing
- * full output blocks as necessary.
- *
- * Note that this handles both the regular write case (finishing ==
- * false) and the end-of-archive case (finishing == true).
- */
-static int
-drive_compressor(struct archive_write *a, struct private_data *state, int finishing)
-{
-       ssize_t bytes_written;
-       int ret;
-
-       for (;;) {
-               if (state->stream.avail_out == 0) {
-                       bytes_written = (a->client_writer)(&a->archive,
-                           a->client_data, state->compressed,
-                           state->compressed_buffer_size);
-                       if (bytes_written <= 0) {
-                               /* TODO: Handle this write failure */
-                               return (ARCHIVE_FATAL);
-                       } else if ((size_t)bytes_written < state->compressed_buffer_size) {
-                               /* Short write: Move remainder to
-                                * front and keep filling */
-                               memmove(state->compressed,
-                                   state->compressed + bytes_written,
-                                   state->compressed_buffer_size - bytes_written);
-                       }
-
-                       a->archive.raw_position += bytes_written;
-                       state->stream.next_out = state->compressed +
-                           state->compressed_buffer_size - bytes_written;
-                       state->stream.avail_out = bytes_written;
-               }
-
-               /* If there's nothing to do, we're done. */
-               if (!finishing && state->stream.avail_in == 0)
-                       return (ARCHIVE_OK);
-
-               ret = BZ2_bzCompress(&(state->stream),
-                   finishing ? BZ_FINISH : BZ_RUN);
-
-               switch (ret) {
-               case BZ_RUN_OK:
-                       /* In non-finishing case, did compressor
-                        * consume everything? */
-                       if (!finishing && state->stream.avail_in == 0)
-                               return (ARCHIVE_OK);
-                       break;
-               case BZ_FINISH_OK:  /* Finishing: There's more work to do */
-                       break;
-               case BZ_STREAM_END: /* Finishing: all done */
-                       /* Only occurs in finishing case */
-                       return (ARCHIVE_OK);
-               default:
-                       /* Any other return value indicates an error */
-                       archive_set_error(&a->archive,
-                           ARCHIVE_ERRNO_PROGRAMMER,
-                           "Bzip2 compression failed;"
-                           " BZ2_bzCompress() returned %d",
-                           ret);
-                       return (ARCHIVE_FATAL);
-               }
-       }
-}
-
-#endif /* HAVE_BZLIB_H */
diff --git a/libarchive/archive_write_set_compression_gzip.c b/libarchive/archive_write_set_compression_gzip.c
deleted file mode 100644 (file)
index f0176e2..0000000
+++ /dev/null
@@ -1,477 +0,0 @@
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * 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: head/lib/libarchive/archive_write_set_compression_gzip.c 201081 2009-12-28 02:04:42Z kientzle $");
-
-#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 <time.h>
-#ifdef HAVE_ZLIB_H
-#include <zlib.h>
-#endif
-
-#include "archive.h"
-#include "archive_private.h"
-#include "archive_write_private.h"
-
-#ifndef HAVE_ZLIB_H
-int
-archive_write_set_compression_gzip(struct archive *a)
-{
-       archive_set_error(a, ARCHIVE_ERRNO_MISC,
-           "gzip compression not supported on this platform");
-       return (ARCHIVE_FATAL);
-}
-#else
-/* Don't compile this if we don't have zlib. */
-
-struct private_data {
-       z_stream         stream;
-       int64_t          total_in;
-       unsigned char   *compressed;
-       size_t           compressed_buffer_size;
-       unsigned long    crc;
-};
-
-struct private_config {
-       int              compression_level;
-};
-
-
-/*
- * Yuck.  zlib.h is not const-correct, so I need this one bit
- * of ugly hackery to convert a const * pointer to a non-const pointer.
- */
-#define        SET_NEXT_IN(st,src)                                     \
-       (st)->stream.next_in = (Bytef *)(uintptr_t)(const void *)(src)
-
-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 *,
-                   int finishing);
-
-
-/*
- * Allocate, initialize and return a archive object.
- */
-int
-archive_write_set_compression_gzip(struct archive *_a)
-{
-       struct archive_write *a = (struct archive_write *)_a;
-       struct private_config *config;
-       __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
-           ARCHIVE_STATE_NEW, "archive_write_set_compression_gzip");
-       config = malloc(sizeof(*config));
-       if (config == NULL) {
-               archive_set_error(&a->archive, ENOMEM, "Out of memory");
-               return (ARCHIVE_FATAL);
-       }
-       a->compressor.config = config;
-       a->compressor.finish = &archive_compressor_gzip_finish;
-       config->compression_level = Z_DEFAULT_COMPRESSION;
-       a->compressor.init = &archive_compressor_gzip_init;
-       a->compressor.options = &archive_compressor_gzip_options;
-       a->archive.compression_code = ARCHIVE_COMPRESSION_GZIP;
-       a->archive.compression_name = "gzip";
-       return (ARCHIVE_OK);
-}
-
-/*
- * Setup callback.
- */
-static int
-archive_compressor_gzip_init(struct archive_write *a)
-{
-       int ret;
-       struct private_data *state;
-       struct private_config *config;
-       time_t t;
-
-       config = (struct private_config *)a->compressor.config;
-
-       if (a->client_opener != NULL) {
-               ret = (a->client_opener)(&a->archive, a->client_data);
-               if (ret != ARCHIVE_OK)
-                       return (ret);
-       }
-
-       /*
-        * The next check is a temporary workaround until the gzip
-        * code can be overhauled some.  The code should not require
-        * that compressed_buffer_size == bytes_per_block.  Removing
-        * this assumption will allow us to compress larger chunks at
-        * a time, which should improve overall performance
-        * marginally.  As a minor side-effect, such a cleanup would
-        * allow us to support truly arbitrary block sizes.
-        */
-       if (a->bytes_per_block < 10) {
-               archive_set_error(&a->archive, EINVAL,
-                   "GZip compressor requires a minimum 10 byte block size");
-               return (ARCHIVE_FATAL);
-       }
-
-       state = (struct private_data *)malloc(sizeof(*state));
-       if (state == NULL) {
-               archive_set_error(&a->archive, ENOMEM,
-                   "Can't allocate data for compression");
-               return (ARCHIVE_FATAL);
-       }
-       memset(state, 0, sizeof(*state));
-
-       /*
-        * See comment above.  We should set compressed_buffer_size to
-        * max(bytes_per_block, 65536), but the code can't handle that yet.
-        */
-       state->compressed_buffer_size = a->bytes_per_block;
-       state->compressed = (unsigned char *)malloc(state->compressed_buffer_size);
-       state->crc = crc32(0L, NULL, 0);
-
-       if (state->compressed == NULL) {
-               archive_set_error(&a->archive, ENOMEM,
-                   "Can't allocate data for compression buffer");
-               free(state);
-               return (ARCHIVE_FATAL);
-       }
-
-       state->stream.next_out = state->compressed;
-       state->stream.avail_out = state->compressed_buffer_size;
-
-       /* Prime output buffer with a gzip header. */
-       t = time(NULL);
-       state->compressed[0] = 0x1f; /* GZip signature bytes */
-       state->compressed[1] = 0x8b;
-       state->compressed[2] = 0x08; /* "Deflate" compression */
-       state->compressed[3] = 0; /* No options */
-       state->compressed[4] = (t)&0xff;  /* Timestamp */
-       state->compressed[5] = (t>>8)&0xff;
-       state->compressed[6] = (t>>16)&0xff;
-       state->compressed[7] = (t>>24)&0xff;
-       state->compressed[8] = 0; /* No deflate options */
-       state->compressed[9] = 3; /* OS=Unix */
-       state->stream.next_out += 10;
-       state->stream.avail_out -= 10;
-
-       a->compressor.write = archive_compressor_gzip_write;
-
-       /* Initialize compression library. */
-       ret = deflateInit2(&(state->stream),
-           config->compression_level,
-           Z_DEFLATED,
-           -15 /* < 0 to suppress zlib header */,
-           8,
-           Z_DEFAULT_STRATEGY);
-
-       if (ret == Z_OK) {
-               a->compressor.data = state;
-               return (0);
-       }
-
-       /* Library setup failed: clean up. */
-       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Internal error "
-           "initializing compression library");
-       free(state->compressed);
-       free(state);
-
-       /* Override the error message if we know what really went wrong. */
-       switch (ret) {
-       case Z_STREAM_ERROR:
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                   "Internal error initializing "
-                   "compression library: invalid setup parameter");
-               break;
-       case Z_MEM_ERROR:
-               archive_set_error(&a->archive, ENOMEM, "Internal error initializing "
-                   "compression library");
-               break;
-       case Z_VERSION_ERROR:
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                   "Internal error initializing "
-                   "compression library: invalid library version");
-               break;
-       }
-
-       return (ARCHIVE_FATAL);
-}
-
-/*
- * Set write options.
- */
-static int
-archive_compressor_gzip_options(struct archive_write *a, const char *key,
-    const char *value)
-{
-       struct private_config *config;
-
-       config = (struct private_config *)a->compressor.config;
-       if (strcmp(key, "compression-level") == 0) {
-               if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
-                   value[1] != '\0')
-                       return (ARCHIVE_WARN);
-               config->compression_level = value[0] - '0';
-               return (ARCHIVE_OK);
-       }
-
-       return (ARCHIVE_WARN);
-}
-
-/*
- * Write data to the compressed stream.
- */
-static int
-archive_compressor_gzip_write(struct archive_write *a, const void *buff,
-    size_t length)
-{
-       struct private_data *state;
-       int ret;
-
-       state = (struct private_data *)a->compressor.data;
-       if (a->client_writer == NULL) {
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
-                   "No write callback is registered?  "
-                   "This is probably an internal programming error.");
-               return (ARCHIVE_FATAL);
-       }
-
-       /* Update statistics */
-       state->crc = crc32(state->crc, (const Bytef *)buff, length);
-       state->total_in += length;
-
-       /* Compress input data to output buffer */
-       SET_NEXT_IN(state, buff);
-       state->stream.avail_in = length;
-       if ((ret = drive_compressor(a, state, 0)) != ARCHIVE_OK)
-               return (ret);
-
-       a->archive.file_position += length;
-       return (ARCHIVE_OK);
-}
-
-/*
- * Finish the compression...
- */
-static int
-archive_compressor_gzip_finish(struct archive_write *a)
-{
-       ssize_t block_length, target_block_length, bytes_written;
-       int ret;
-       struct private_data *state;
-       unsigned tocopy;
-       unsigned char trailer[8];
-
-       state = (struct private_data *)a->compressor.data;
-       ret = 0;
-       if (state != NULL) {
-               if (a->client_writer == NULL) {
-                       archive_set_error(&a->archive,
-                           ARCHIVE_ERRNO_PROGRAMMER,
-                           "No write callback is registered?  "
-                           "This is probably an internal programming error.");
-                       ret = ARCHIVE_FATAL;
-                       goto cleanup;
-               }
-
-               /* By default, always pad the uncompressed data. */
-               if (a->pad_uncompressed) {
-                       tocopy = a->bytes_per_block -
-                           (state->total_in % a->bytes_per_block);
-                       while (tocopy > 0 && tocopy < (unsigned)a->bytes_per_block) {
-                               SET_NEXT_IN(state, a->nulls);
-                               state->stream.avail_in = tocopy < a->null_length ?
-                                   tocopy : a->null_length;
-                               state->crc = crc32(state->crc, a->nulls,
-                                   state->stream.avail_in);
-                               state->total_in += state->stream.avail_in;
-                               tocopy -= state->stream.avail_in;
-                               ret = drive_compressor(a, state, 0);
-                               if (ret != ARCHIVE_OK)
-                                       goto cleanup;
-                       }
-               }
-
-               /* Finish compression cycle */
-               if (((ret = drive_compressor(a, state, 1))) != ARCHIVE_OK)
-                       goto cleanup;
-
-               /* Build trailer: 4-byte CRC and 4-byte length. */
-               trailer[0] = (state->crc)&0xff;
-               trailer[1] = (state->crc >> 8)&0xff;
-               trailer[2] = (state->crc >> 16)&0xff;
-               trailer[3] = (state->crc >> 24)&0xff;
-               trailer[4] = (state->total_in)&0xff;
-               trailer[5] = (state->total_in >> 8)&0xff;
-               trailer[6] = (state->total_in >> 16)&0xff;
-               trailer[7] = (state->total_in >> 24)&0xff;
-
-               /* Add trailer to current block. */
-               tocopy = 8;
-               if (tocopy > state->stream.avail_out)
-                       tocopy = state->stream.avail_out;
-               memcpy(state->stream.next_out, trailer, tocopy);
-               state->stream.next_out += tocopy;
-               state->stream.avail_out -= tocopy;
-
-               /* If it overflowed, flush and start a new block. */
-               if (tocopy < 8) {
-                       bytes_written = (a->client_writer)(&a->archive, a->client_data,
-                           state->compressed, state->compressed_buffer_size);
-                       if (bytes_written <= 0) {
-                               ret = ARCHIVE_FATAL;
-                               goto cleanup;
-                       }
-                       a->archive.raw_position += bytes_written;
-                       state->stream.next_out = state->compressed;
-                       state->stream.avail_out = state->compressed_buffer_size;
-                       memcpy(state->stream.next_out, trailer + tocopy, 8-tocopy);
-                       state->stream.next_out += 8-tocopy;
-                       state->stream.avail_out -= 8-tocopy;
-               }
-
-               /* Optionally, pad the final compressed block. */
-               block_length = state->stream.next_out - state->compressed;
-
-               /* Tricky calculation to determine size of last block. */
-               if (a->bytes_in_last_block <= 0)
-                       /* Default or Zero: pad to full block */
-                       target_block_length = a->bytes_per_block;
-               else
-                       /* Round length to next multiple of bytes_in_last_block. */
-                       target_block_length = a->bytes_in_last_block *
-                           ( (block_length + a->bytes_in_last_block - 1) /
-                               a->bytes_in_last_block);
-               if (target_block_length > a->bytes_per_block)
-                       target_block_length = a->bytes_per_block;
-               if (block_length < target_block_length) {
-                       memset(state->stream.next_out, 0,
-                           target_block_length - block_length);
-                       block_length = target_block_length;
-               }
-
-               /* Write the last block */
-               bytes_written = (a->client_writer)(&a->archive, a->client_data,
-                   state->compressed, block_length);
-               if (bytes_written <= 0) {
-                       ret = ARCHIVE_FATAL;
-                       goto cleanup;
-               }
-               a->archive.raw_position += bytes_written;
-
-               /* Cleanup: shut down compressor, release memory, etc. */
-       cleanup:
-               switch (deflateEnd(&(state->stream))) {
-               case Z_OK:
-                       break;
-               default:
-                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                           "Failed to clean up compressor");
-                       ret = ARCHIVE_FATAL;
-               }
-               free(state->compressed);
-               free(state);
-       }
-       /* Clean up config area even if we never initialized. */
-       free(a->compressor.config);
-       a->compressor.config = NULL;
-       return (ret);
-}
-
-/*
- * Utility function to push input data through compressor,
- * writing full output blocks as necessary.
- *
- * Note that this handles both the regular write case (finishing ==
- * false) and the end-of-archive case (finishing == true).
- */
-static int
-drive_compressor(struct archive_write *a, struct private_data *state, int finishing)
-{
-       ssize_t bytes_written;
-       int ret;
-
-       for (;;) {
-               if (state->stream.avail_out == 0) {
-                       bytes_written = (a->client_writer)(&a->archive,
-                           a->client_data, state->compressed,
-                           state->compressed_buffer_size);
-                       if (bytes_written <= 0) {
-                               /* TODO: Handle this write failure */
-                               return (ARCHIVE_FATAL);
-                       } else if ((size_t)bytes_written < state->compressed_buffer_size) {
-                               /* Short write: Move remaining to
-                                * front of block and keep filling */
-                               memmove(state->compressed,
-                                   state->compressed + bytes_written,
-                                   state->compressed_buffer_size - bytes_written);
-                       }
-                       a->archive.raw_position += bytes_written;
-                       state->stream.next_out
-                           = state->compressed +
-                           state->compressed_buffer_size - bytes_written;
-                       state->stream.avail_out = bytes_written;
-               }
-
-               /* If there's nothing to do, we're done. */
-               if (!finishing && state->stream.avail_in == 0)
-                       return (ARCHIVE_OK);
-
-               ret = deflate(&(state->stream),
-                   finishing ? Z_FINISH : Z_NO_FLUSH );
-
-               switch (ret) {
-               case Z_OK:
-                       /* In non-finishing case, check if compressor
-                        * consumed everything */
-                       if (!finishing && state->stream.avail_in == 0)
-                               return (ARCHIVE_OK);
-                       /* In finishing case, this return always means
-                        * there's more work */
-                       break;
-               case Z_STREAM_END:
-                       /* This return can only occur in finishing case. */
-                       return (ARCHIVE_OK);
-               default:
-                       /* Any other return value indicates an error. */
-                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                           "GZip compression failed:"
-                           " deflate() call returned status %d",
-                           ret);
-                       return (ARCHIVE_FATAL);
-               }
-       }
-}
-
-#endif /* HAVE_ZLIB_H */
diff --git a/libarchive/archive_write_set_compression_program.c b/libarchive/archive_write_set_compression_program.c
deleted file mode 100644 (file)
index 475ba35..0000000
+++ /dev/null
@@ -1,347 +0,0 @@
-/*-
- * Copyright (c) 2007 Joerg Sonnenberger
- * 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: head/lib/libarchive/archive_write_set_compression_program.c 201104 2009-12-28 03:14:30Z kientzle $");
-
-/* This capability is only available on POSIX systems. */
-#if (!defined(HAVE_PIPE) || !defined(HAVE_FCNTL) || \
-    !(defined(HAVE_FORK) || defined(HAVE_VFORK))) && (!defined(_WIN32) || defined(__CYGWIN__))
-#include "archive.h"
-
-/*
- * On non-Posix systems, allow the program to build, but choke if
- * this function is actually invoked.
- */
-int
-archive_write_set_compression_program(struct archive *_a, const char *cmd)
-{
-       archive_set_error(_a, -1,
-           "External compression programs not supported on this platform");
-       return (ARCHIVE_FATAL);
-}
-
-#else
-
-#ifdef HAVE_SYS_WAIT_H
-#  include <sys/wait.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#  include <errno.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#  include <fcntl.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_write_private.h"
-
-#include "filter_fork.h"
-
-struct private_data {
-       char            *description;
-       pid_t            child;
-       int              child_stdin, child_stdout;
-
-       char            *child_buf;
-       size_t           child_buf_len, child_buf_avail;
-};
-
-static int     archive_compressor_program_finish(struct archive_write *);
-static int     archive_compressor_program_init(struct archive_write *);
-static int     archive_compressor_program_write(struct archive_write *,
-                   const void *, size_t);
-
-/*
- * Allocate, initialize and return a archive object.
- */
-int
-archive_write_set_compression_program(struct archive *_a, const char *cmd)
-{
-       struct archive_write *a = (struct archive_write *)_a;
-       __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
-           ARCHIVE_STATE_NEW, "archive_write_set_compression_program");
-       a->compressor.init = &archive_compressor_program_init;
-       a->compressor.config = strdup(cmd);
-       return (ARCHIVE_OK);
-}
-
-/*
- * Setup callback.
- */
-static int
-archive_compressor_program_init(struct archive_write *a)
-{
-       int ret;
-       struct private_data *state;
-       static const char *prefix = "Program: ";
-       char *cmd = a->compressor.config;
-
-       if (a->client_opener != NULL) {
-               ret = (a->client_opener)(&a->archive, a->client_data);
-               if (ret != ARCHIVE_OK)
-                       return (ret);
-       }
-
-       state = (struct private_data *)malloc(sizeof(*state));
-       if (state == NULL) {
-               archive_set_error(&a->archive, ENOMEM,
-                   "Can't allocate data for compression");
-               return (ARCHIVE_FATAL);
-       }
-       memset(state, 0, sizeof(*state));
-
-       a->archive.compression_code = ARCHIVE_COMPRESSION_PROGRAM;
-       state->description = (char *)malloc(strlen(prefix) + strlen(cmd) + 1);
-       strcpy(state->description, prefix);
-       strcat(state->description, cmd);
-       a->archive.compression_name = state->description;
-
-       state->child_buf_len = a->bytes_per_block;
-       state->child_buf_avail = 0;
-       state->child_buf = malloc(state->child_buf_len);
-
-       if (state->child_buf == NULL) {
-               archive_set_error(&a->archive, ENOMEM,
-                   "Can't allocate data for compression buffer");
-               free(state);
-               return (ARCHIVE_FATAL);
-       }
-
-       if ((state->child = __archive_create_child(cmd,
-                &state->child_stdin, &state->child_stdout)) == -1) {
-               archive_set_error(&a->archive, EINVAL,
-                   "Can't initialise filter");
-               free(state->child_buf);
-               free(state);
-               return (ARCHIVE_FATAL);
-       }
-
-       a->compressor.write = archive_compressor_program_write;
-       a->compressor.finish = archive_compressor_program_finish;
-
-       a->compressor.data = state;
-       return (0);
-}
-
-static ssize_t
-child_write(struct archive_write *a, const char *buf, size_t buf_len)
-{
-       struct private_data *state = a->compressor.data;
-       ssize_t ret;
-
-       if (state->child_stdin == -1)
-               return (-1);
-
-       if (buf_len == 0)
-               return (-1);
-
-restart_write:
-       do {
-               ret = write(state->child_stdin, buf, buf_len);
-       } while (ret == -1 && errno == EINTR);
-
-       if (ret > 0)
-               return (ret);
-       if (ret == 0) {
-               close(state->child_stdin);
-               state->child_stdin = -1;
-               fcntl(state->child_stdout, F_SETFL, 0);
-               return (0);
-       }
-       if (ret == -1 && errno != EAGAIN)
-               return (-1);
-
-       if (state->child_stdout == -1) {
-               fcntl(state->child_stdin, F_SETFL, 0);
-               __archive_check_child(state->child_stdin, state->child_stdout);
-               goto restart_write;
-       }
-
-       do {
-               ret = read(state->child_stdout,
-                   state->child_buf + state->child_buf_avail,
-                   state->child_buf_len - state->child_buf_avail);
-       } while (ret == -1 && errno == EINTR);
-
-       if (ret == 0 || (ret == -1 && errno == EPIPE)) {
-               close(state->child_stdout);
-               state->child_stdout = -1;
-               fcntl(state->child_stdin, F_SETFL, 0);
-               goto restart_write;
-       }
-       if (ret == -1 && errno == EAGAIN) {
-               __archive_check_child(state->child_stdin, state->child_stdout);
-               goto restart_write;
-       }
-       if (ret == -1)
-               return (-1);
-
-       state->child_buf_avail += ret;
-
-       ret = (a->client_writer)(&a->archive, a->client_data,
-           state->child_buf, state->child_buf_avail);
-       if (ret <= 0)
-               return (-1);
-
-       if ((size_t)ret < state->child_buf_avail) {
-               memmove(state->child_buf, state->child_buf + ret,
-                   state->child_buf_avail - ret);
-       }
-       state->child_buf_avail -= ret;
-       a->archive.raw_position += ret;
-       goto restart_write;
-}
-
-/*
- * Write data to the compressed stream.
- */
-static int
-archive_compressor_program_write(struct archive_write *a, const void *buff,
-    size_t length)
-{
-       ssize_t ret;
-       const char *buf;
-
-       if (a->client_writer == NULL) {
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
-                   "No write callback is registered?  "
-                   "This is probably an internal programming error.");
-               return (ARCHIVE_FATAL);
-       }
-
-       buf = buff;
-       while (length > 0) {
-               ret = child_write(a, buf, length);
-               if (ret == -1 || ret == 0) {
-                       archive_set_error(&a->archive, EIO,
-                           "Can't write to filter");
-                       return (ARCHIVE_FATAL);
-               }
-               length -= ret;
-               buf += ret;
-       }
-
-       a->archive.file_position += length;
-       return (ARCHIVE_OK);
-}
-
-
-/*
- * Finish the compression...
- */
-static int
-archive_compressor_program_finish(struct archive_write *a)
-{
-       int ret, status;
-       ssize_t bytes_read, bytes_written;
-       struct private_data *state;
-
-       state = (struct private_data *)a->compressor.data;
-       ret = 0;
-       if (a->client_writer == NULL) {
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
-                   "No write callback is registered?  "
-                   "This is probably an internal programming error.");
-               ret = ARCHIVE_FATAL;
-               goto cleanup;
-       }
-
-       /* XXX pad compressed data. */
-
-       close(state->child_stdin);
-       state->child_stdin = -1;
-       fcntl(state->child_stdout, F_SETFL, 0);
-
-       for (;;) {
-               do {
-                       bytes_read = read(state->child_stdout,
-                           state->child_buf + state->child_buf_avail,
-                           state->child_buf_len - state->child_buf_avail);
-               } while (bytes_read == -1 && errno == EINTR);
-
-               if (bytes_read == 0 || (bytes_read == -1 && errno == EPIPE))
-                       break;
-
-               if (bytes_read == -1) {
-                       archive_set_error(&a->archive, errno,
-                           "Read from filter failed unexpectedly.");
-                       ret = ARCHIVE_FATAL;
-                       goto cleanup;
-               }
-               state->child_buf_avail += bytes_read;
-
-               bytes_written = (a->client_writer)(&a->archive, a->client_data,
-                   state->child_buf, state->child_buf_avail);
-               if (bytes_written <= 0) {
-                       ret = ARCHIVE_FATAL;
-                       goto cleanup;
-               }
-               if ((size_t)bytes_written < state->child_buf_avail) {
-                       memmove(state->child_buf,
-                           state->child_buf + bytes_written,
-                           state->child_buf_avail - bytes_written);
-               }
-               state->child_buf_avail -= bytes_written;
-               a->archive.raw_position += bytes_written;
-       }
-
-       /* XXX pad final compressed block. */
-
-cleanup:
-       /* Shut down the child. */
-       if (state->child_stdin != -1)
-               close(state->child_stdin);
-       if (state->child_stdout != -1)
-               close(state->child_stdout);
-       while (waitpid(state->child, &status, 0) == -1 && errno == EINTR)
-               continue;
-
-       if (status != 0) {
-               archive_set_error(&a->archive, EIO,
-                   "Filter exited with failure.");
-               ret = ARCHIVE_FATAL;
-       }
-
-       /* Release our configuration data. */
-       free(a->compressor.config);
-       a->compressor.config = NULL;
-
-       /* Release our private state data. */
-       free(state->child_buf);
-       free(state->description);
-       free(state);
-       return (ret);
-}
-
-#endif /* !defined(HAVE_PIPE) || !defined(HAVE_VFORK) || !defined(HAVE_FCNTL) */
diff --git a/libarchive/archive_write_set_compression_xz.c b/libarchive/archive_write_set_compression_xz.c
deleted file mode 100644 (file)
index f82f6db..0000000
+++ /dev/null
@@ -1,438 +0,0 @@
-/*-
- * Copyright (c) 2009 Michihiro NAKAJIMA
- * Copyright (c) 2003-2007 Tim Kientzle
- * 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: head/lib/libarchive/archive_write_set_compression_xz.c 201108 2009-12-28 03:28:21Z kientzle $");
-
-#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 <time.h>
-#ifdef HAVE_LZMA_H
-#include <lzma.h>
-#endif
-
-#include "archive.h"
-#include "archive_private.h"
-#include "archive_write_private.h"
-
-#ifndef HAVE_LZMA_H
-int
-archive_write_set_compression_xz(struct archive *a)
-{
-       archive_set_error(a, ARCHIVE_ERRNO_MISC,
-           "xz compression not supported on this platform");
-       return (ARCHIVE_FATAL);
-}
-
-int
-archive_write_set_compression_lzma(struct archive *a)
-{
-       archive_set_error(a, ARCHIVE_ERRNO_MISC,
-           "lzma compression not supported on this platform");
-       return (ARCHIVE_FATAL);
-}
-#else
-/* Don't compile this if we don't have liblzma. */
-
-struct private_data {
-       lzma_stream      stream;
-       lzma_filter      lzmafilters[2];
-       lzma_options_lzma lzma_opt;
-       int64_t          total_in;
-       unsigned char   *compressed;
-       size_t           compressed_buffer_size;
-};
-
-struct private_config {
-       int              compression_level;
-};
-
-static int     archive_compressor_xz_init(struct archive_write *);
-static int     archive_compressor_xz_options(struct archive_write *,
-                   const char *, const char *);
-static int     archive_compressor_xz_finish(struct archive_write *);
-static int     archive_compressor_xz_write(struct archive_write *,
-                   const void *, size_t);
-static int     drive_compressor(struct archive_write *, struct private_data *,
-                   int finishing);
-
-
-/*
- * Allocate, initialize and return a archive object.
- */
-int
-archive_write_set_compression_xz(struct archive *_a)
-{
-       struct private_config *config;
-       struct archive_write *a = (struct archive_write *)_a;
-       __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
-           ARCHIVE_STATE_NEW, "archive_write_set_compression_xz");
-       config = calloc(1, sizeof(*config));
-       if (config == NULL) {
-               archive_set_error(&a->archive, ENOMEM, "Out of memory");
-               return (ARCHIVE_FATAL);
-       }
-       a->compressor.config = config;
-       a->compressor.finish = archive_compressor_xz_finish;
-       config->compression_level = LZMA_PRESET_DEFAULT;
-       a->compressor.init = &archive_compressor_xz_init;
-       a->compressor.options = &archive_compressor_xz_options;
-       a->archive.compression_code = ARCHIVE_COMPRESSION_XZ;
-       a->archive.compression_name = "xz";
-       return (ARCHIVE_OK);
-}
-
-/* LZMA is handled identically, we just need a different compression
- * code set.  (The liblzma setup looks at the code to determine
- * the one place that XZ and LZMA require different handling.) */
-int
-archive_write_set_compression_lzma(struct archive *_a)
-{
-       struct archive_write *a = (struct archive_write *)_a;
-       int r = archive_write_set_compression_xz(_a);
-       if (r != ARCHIVE_OK)
-               return (r);
-       a->archive.compression_code = ARCHIVE_COMPRESSION_LZMA;
-       a->archive.compression_name = "lzma";
-       return (ARCHIVE_OK);
-}
-
-static int
-archive_compressor_xz_init_stream(struct archive_write *a,
-    struct private_data *state)
-{
-       int ret;
-
-       state->stream = (lzma_stream)LZMA_STREAM_INIT;
-       state->stream.next_out = state->compressed;
-       state->stream.avail_out = state->compressed_buffer_size;
-       if (a->archive.compression_code == ARCHIVE_COMPRESSION_XZ)
-               ret = lzma_stream_encoder(&(state->stream),
-                   state->lzmafilters, LZMA_CHECK_CRC64);
-       else
-               ret = lzma_alone_encoder(&(state->stream), &state->lzma_opt);
-       if (ret == LZMA_OK)
-               return (ARCHIVE_OK);
-
-       switch (ret) {
-       case LZMA_MEM_ERROR:
-               archive_set_error(&a->archive, ENOMEM,
-                   "Internal error initializing compression library: "
-                   "Cannot allocate memory");
-               break;
-       default:
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                   "Internal error initializing compression library: "
-                   "It's a bug in liblzma");
-               break;
-       }
-       return (ARCHIVE_FATAL);
-}
-
-/*
- * Setup callback.
- */
-static int
-archive_compressor_xz_init(struct archive_write *a)
-{
-       int ret;
-       struct private_data *state;
-       struct private_config *config;
-
-       if (a->client_opener != NULL) {
-               ret = (a->client_opener)(&a->archive, a->client_data);
-               if (ret != ARCHIVE_OK)
-                       return (ret);
-       }
-
-       state = (struct private_data *)malloc(sizeof(*state));
-       if (state == NULL) {
-               archive_set_error(&a->archive, ENOMEM,
-                   "Can't allocate data for compression");
-               return (ARCHIVE_FATAL);
-       }
-       memset(state, 0, sizeof(*state));
-       config = a->compressor.config;
-
-       /*
-        * See comment above.  We should set compressed_buffer_size to
-        * max(bytes_per_block, 65536), but the code can't handle that yet.
-        */
-       state->compressed_buffer_size = a->bytes_per_block;
-       state->compressed = (unsigned char *)malloc(state->compressed_buffer_size);
-       if (state->compressed == NULL) {
-               archive_set_error(&a->archive, ENOMEM,
-                   "Can't allocate data for compression buffer");
-               free(state);
-               return (ARCHIVE_FATAL);
-       }
-       a->compressor.write = archive_compressor_xz_write;
-
-       /* Initialize compression library. */
-       if (lzma_lzma_preset(&state->lzma_opt, config->compression_level)) {
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                   "Internal error initializing compression library");
-               free(state->compressed);
-               free(state);
-       }
-       state->lzmafilters[0].id = LZMA_FILTER_LZMA2;
-       state->lzmafilters[0].options = &state->lzma_opt;
-       state->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
-       ret = archive_compressor_xz_init_stream(a, state);
-       if (ret == LZMA_OK) {
-               a->compressor.data = state;
-               return (0);
-       }
-       /* Library setup failed: clean up. */
-       free(state->compressed);
-       free(state);
-
-       return (ARCHIVE_FATAL);
-}
-
-/*
- * Set write options.
- */
-static int
-archive_compressor_xz_options(struct archive_write *a, const char *key,
-    const char *value)
-{
-       struct private_config *config;
-
-       config = (struct private_config *)a->compressor.config;
-       if (strcmp(key, "compression-level") == 0) {
-               if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
-                   value[1] != '\0')
-                       return (ARCHIVE_WARN);
-               config->compression_level = value[0] - '0';
-               if (config->compression_level > 6)
-                       config->compression_level = 6;
-               return (ARCHIVE_OK);
-       }
-
-       return (ARCHIVE_WARN);
-}
-
-/*
- * Write data to the compressed stream.
- */
-static int
-archive_compressor_xz_write(struct archive_write *a, const void *buff,
-    size_t length)
-{
-       struct private_data *state;
-       int ret;
-
-       state = (struct private_data *)a->compressor.data;
-       if (a->client_writer == NULL) {
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
-                   "No write callback is registered?  "
-                   "This is probably an internal programming error.");
-               return (ARCHIVE_FATAL);
-       }
-
-       /* Update statistics */
-       state->total_in += length;
-
-       /* Compress input data to output buffer */
-       state->stream.next_in = buff;
-       state->stream.avail_in = length;
-       if ((ret = drive_compressor(a, state, 0)) != ARCHIVE_OK)
-               return (ret);
-
-       a->archive.file_position += length;
-       return (ARCHIVE_OK);
-}
-
-
-/*
- * Finish the compression...
- */
-static int
-archive_compressor_xz_finish(struct archive_write *a)
-{
-       ssize_t block_length, target_block_length, bytes_written;
-       int ret;
-       struct private_data *state;
-       unsigned tocopy;
-
-       ret = ARCHIVE_OK;
-       state = (struct private_data *)a->compressor.data;
-       if (state != NULL) {
-               if (a->client_writer == NULL) {
-                       archive_set_error(&a->archive,
-                           ARCHIVE_ERRNO_PROGRAMMER,
-                           "No write callback is registered?  "
-                           "This is probably an internal programming error.");
-                       ret = ARCHIVE_FATAL;
-                       goto cleanup;
-               }
-
-               /* By default, always pad the uncompressed data. */
-               if (a->pad_uncompressed) {
-                       tocopy = a->bytes_per_block -
-                           (state->total_in % a->bytes_per_block);
-                       while (tocopy > 0 && tocopy < (unsigned)a->bytes_per_block) {
-                               state->stream.next_in = a->nulls;
-                               state->stream.avail_in = tocopy < a->null_length ?
-                                   tocopy : a->null_length;
-                               state->total_in += state->stream.avail_in;
-                               tocopy -= state->stream.avail_in;
-                               ret = drive_compressor(a, state, 0);
-                               if (ret != ARCHIVE_OK)
-                                       goto cleanup;
-                       }
-               }
-
-               /* Finish compression cycle */
-               if (((ret = drive_compressor(a, state, 1))) != ARCHIVE_OK)
-                       goto cleanup;
-
-               /* Optionally, pad the final compressed block. */
-               block_length = state->stream.next_out - state->compressed;
-
-               /* Tricky calculation to determine size of last block. */
-               if (a->bytes_in_last_block <= 0)
-                       /* Default or Zero: pad to full block */
-                       target_block_length = a->bytes_per_block;
-               else
-                       /* Round length to next multiple of bytes_in_last_block. */
-                       target_block_length = a->bytes_in_last_block *
-                           ( (block_length + a->bytes_in_last_block - 1) /
-                               a->bytes_in_last_block);
-               if (target_block_length > a->bytes_per_block)
-                       target_block_length = a->bytes_per_block;
-               if (block_length < target_block_length) {
-                       memset(state->stream.next_out, 0,
-                           target_block_length - block_length);
-                       block_length = target_block_length;
-               }
-
-               /* Write the last block */
-               bytes_written = (a->client_writer)(&a->archive, a->client_data,
-                   state->compressed, block_length);
-               if (bytes_written <= 0) {
-                       ret = ARCHIVE_FATAL;
-                       goto cleanup;
-               }
-               a->archive.raw_position += bytes_written;
-
-               /* Cleanup: shut down compressor, release memory, etc. */
-       cleanup:
-               lzma_end(&(state->stream));
-               free(state->compressed);
-               free(state);
-       }
-       free(a->compressor.config);
-       a->compressor.config = NULL;
-       return (ret);
-}
-
-/*
- * Utility function to push input data through compressor,
- * writing full output blocks as necessary.
- *
- * Note that this handles both the regular write case (finishing ==
- * false) and the end-of-archive case (finishing == true).
- */
-static int
-drive_compressor(struct archive_write *a, struct private_data *state, int finishing)
-{
-       ssize_t bytes_written;
-       int ret;
-
-       for (;;) {
-               if (state->stream.avail_out == 0) {
-                       bytes_written = (a->client_writer)(&a->archive,
-                           a->client_data, state->compressed,
-                           state->compressed_buffer_size);
-                       if (bytes_written <= 0) {
-                               /* TODO: Handle this write failure */
-                               return (ARCHIVE_FATAL);
-                       } else if ((size_t)bytes_written < state->compressed_buffer_size) {
-                               /* Short write: Move remaining to
-                                * front of block and keep filling */
-                               memmove(state->compressed,
-                                   state->compressed + bytes_written,
-                                   state->compressed_buffer_size - bytes_written);
-                       }
-                       a->archive.raw_position += bytes_written;
-                       state->stream.next_out
-                           = state->compressed +
-                           state->compressed_buffer_size - bytes_written;
-                       state->stream.avail_out = bytes_written;
-               }
-
-               /* If there's nothing to do, we're done. */
-               if (!finishing && state->stream.avail_in == 0)
-                       return (ARCHIVE_OK);
-
-               ret = lzma_code(&(state->stream),
-                   finishing ? LZMA_FINISH : LZMA_RUN );
-
-               switch (ret) {
-               case LZMA_OK:
-                       /* In non-finishing case, check if compressor
-                        * consumed everything */
-                       if (!finishing && state->stream.avail_in == 0)
-                               return (ARCHIVE_OK);
-                       /* In finishing case, this return always means
-                        * there's more work */
-                       break;
-               case LZMA_STREAM_END:
-                       /* This return can only occur in finishing case. */
-                       if (finishing)
-                               return (ARCHIVE_OK);
-                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                           "lzma compression data error");
-                       return (ARCHIVE_FATAL);
-               case LZMA_MEMLIMIT_ERROR:
-                       archive_set_error(&a->archive, ENOMEM,
-                           "lzma compression error: "
-                           "%ju MiB would have been needed",
-                           (lzma_memusage(&(state->stream)) + 1024 * 1024 -1)
-                           / (1024 * 1024));
-                       return (ARCHIVE_FATAL);
-               default:
-                       /* Any other return value indicates an error. */
-                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                           "lzma compression failed:"
-                           " lzma_code() call returned status %d",
-                           ret);
-                       return (ARCHIVE_FATAL);
-               }
-       }
-}
-
-#endif /* HAVE_LZMA_H */
index b492ceaa56b6da0cf72c668de820ae10c8bf83b7..00c9c7b8727ce9f00e70ca8116b6c1242da5f0ff 100644 (file)
@@ -48,6 +48,7 @@ struct ar_w {
        uint64_t         entry_padding;
        int              is_strtab;
        int              has_strtab;
+       char             wrote_global_header;
        char            *strtab;
 };
 
@@ -166,8 +167,10 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
         * If we are now at the beginning of the archive,
         * we need first write the ar global header.
         */
-       if (a->archive.file_position == 0)
-               (a->compressor.write)(a, "!<arch>\n", 8);
+       if (!ar->wrote_global_header) {
+               __archive_write_output(a, "!<arch>\n", 8);
+               ar->wrote_global_header = 1;
+       }
 
        memset(buff, ' ', 60);
        strncpy(&buff[AR_fmag_offset], "`\n", 2);
@@ -330,7 +333,7 @@ size:
                return (ARCHIVE_WARN);
        }
 
-       ret = (a->compressor.write)(a, buff, 60);
+       ret = __archive_write_output(a, buff, 60);
        if (ret != ARCHIVE_OK)
                return (ret);
 
@@ -338,7 +341,7 @@ size:
        ar->entry_padding = ar->entry_bytes_remaining % 2;
 
        if (append_fn > 0) {
-               ret = (a->compressor.write)(a, filename, strlen(filename));
+               ret = __archive_write_output(a, filename, strlen(filename));
                if (ret != ARCHIVE_OK)
                        return (ret);
                ar->entry_bytes_remaining -= strlen(filename);
@@ -374,7 +377,7 @@ archive_write_ar_data(struct archive_write *a, const void *buff, size_t s)
                ar->has_strtab = 1;
        }
 
-       ret = (a->compressor.write)(a, buff, s);
+       ret = __archive_write_output(a, buff, s);
        if (ret != ARCHIVE_OK)
                return (ret);
 
@@ -405,14 +408,17 @@ archive_write_ar_destroy(struct archive_write *a)
 static int
 archive_write_ar_finish(struct archive_write *a)
 {
+       struct ar_w *ar;
        int ret;
 
        /*
         * If we haven't written anything yet, we need to write
         * the ar global header now to make it a valid ar archive.
         */
-       if (a->archive.file_position == 0) {
-               ret = (a->compressor.write)(a, "!<arch>\n", 8);
+       ar = (struct ar_w *)a->format_data;
+       if (!ar->wrote_global_header) {
+               ar->wrote_global_header = 1;
+               ret = __archive_write_output(a, "!<arch>\n", 8);
                return (ret);
        }
 
@@ -444,7 +450,7 @@ archive_write_ar_finish_entry(struct archive_write *a)
                return (ARCHIVE_WARN);
        }
 
-       ret = (a->compressor.write)(a, "\n", 1);
+       ret = __archive_write_output(a, "\n", 1);
        return (ret);
 }
 
index 4e8e1e0bdcab266209493d34ab2e23a478f66e95..29a6fb6e02b3eec31f1b95c8e61af48e7e5e6388 100644 (file)
@@ -229,11 +229,11 @@ archive_write_cpio_header(struct archive_write *a, struct archive_entry *entry)
                format_octal(archive_entry_size(entry),
                    &h.c_filesize, sizeof(h.c_filesize));
 
-       ret = (a->compressor.write)(a, &h, sizeof(h));
+       ret = __archive_write_output(a, &h, sizeof(h));
        if (ret != ARCHIVE_OK)
                return (ARCHIVE_FATAL);
 
-       ret = (a->compressor.write)(a, path, pathlength);
+       ret = __archive_write_output(a, path, pathlength);
        if (ret != ARCHIVE_OK)
                return (ARCHIVE_FATAL);
 
@@ -241,7 +241,7 @@ archive_write_cpio_header(struct archive_write *a, struct archive_entry *entry)
 
        /* Write the symlink now. */
        if (p != NULL  &&  *p != '\0')
-               ret = (a->compressor.write)(a, p, strlen(p));
+               ret = __archive_write_output(a, p, strlen(p));
 
        if (ret == ARCHIVE_OK)
                ret = ret2;
@@ -258,7 +258,7 @@ archive_write_cpio_data(struct archive_write *a, const void *buff, size_t s)
        if (s > cpio->entry_bytes_remaining)
                s = cpio->entry_bytes_remaining;
 
-       ret = (a->compressor.write)(a, buff, s);
+       ret = __archive_write_output(a, buff, s);
        cpio->entry_bytes_remaining -= s;
        if (ret >= 0)
                return (s);
@@ -335,7 +335,7 @@ archive_write_cpio_finish_entry(struct archive_write *a)
        while (cpio->entry_bytes_remaining > 0) {
                to_write = cpio->entry_bytes_remaining < a->null_length ?
                    cpio->entry_bytes_remaining : a->null_length;
-               ret = (a->compressor.write)(a, a->nulls, to_write);
+               ret = __archive_write_output(a, a->nulls, to_write);
                if (ret != ARCHIVE_OK)
                        return (ret);
                cpio->entry_bytes_remaining -= to_write;
index 0af0890952efbe727cd6ff6f46d2a9696e296b13..bf4f7435b98c5ece24188415bb8bda5324e5532e 100644 (file)
@@ -170,17 +170,17 @@ archive_write_newc_header(struct archive_write *a, struct archive_entry *entry)
                format_hex(archive_entry_size(entry),
                    &h.c_filesize, sizeof(h.c_filesize));
 
-       ret = (a->compressor.write)(a, &h, sizeof(h));
+       ret = __archive_write_output(a, &h, sizeof(h));
        if (ret != ARCHIVE_OK)
                return (ARCHIVE_FATAL);
 
        /* Pad pathname to even length. */
-       ret = (a->compressor.write)(a, path, pathlength);
+       ret = __archive_write_output(a, path, pathlength);
        if (ret != ARCHIVE_OK)
                return (ARCHIVE_FATAL);
        pad = PAD4(pathlength + sizeof(struct cpio_header_newc));
        if (pad)
-               ret = (a->compressor.write)(a, "\0\0\0", pad);
+               ret = __archive_write_output(a, "\0\0\0", pad);
        if (ret != ARCHIVE_OK)
                return (ARCHIVE_FATAL);
 
@@ -189,11 +189,11 @@ archive_write_newc_header(struct archive_write *a, struct archive_entry *entry)
 
        /* Write the symlink now. */
        if (p != NULL  &&  *p != '\0') {
-               ret = (a->compressor.write)(a, p, strlen(p));
+               ret = __archive_write_output(a, p, strlen(p));
                if (ret != ARCHIVE_OK)
                        return (ARCHIVE_FATAL);
                pad = PAD4(strlen(p));
-               ret = (a->compressor.write)(a, "\0\0\0", pad);
+               ret = __archive_write_output(a, "\0\0\0", pad);
        }
 
        if (ret == ARCHIVE_OK)
@@ -211,7 +211,7 @@ archive_write_newc_data(struct archive_write *a, const void *buff, size_t s)
        if (s > cpio->entry_bytes_remaining)
                s = cpio->entry_bytes_remaining;
 
-       ret = (a->compressor.write)(a, buff, s);
+       ret = __archive_write_output(a, buff, s);
        cpio->entry_bytes_remaining -= s;
        if (ret >= 0)
                return (s);
@@ -285,11 +285,11 @@ archive_write_newc_finish_entry(struct archive_write *a)
        while (cpio->entry_bytes_remaining > 0) {
                to_write = cpio->entry_bytes_remaining < a->null_length ?
                    cpio->entry_bytes_remaining : a->null_length;
-               ret = (a->compressor.write)(a, a->nulls, to_write);
+               ret = __archive_write_output(a, a->nulls, to_write);
                if (ret != ARCHIVE_OK)
                        return (ret);
                cpio->entry_bytes_remaining -= to_write;
        }
-       ret = (a->compressor.write)(a, a->nulls, cpio->padding);
+       ret = __archive_write_output(a, a->nulls, cpio->padding);
        return (ret);
 }
index 7feeca92e6219da9cd996190a5393113dc2216bf..988a7baa65fe1caaeb1c358bfdc4996a70da9e04 100644 (file)
@@ -821,7 +821,7 @@ archive_write_mtree_finish_entry(struct archive_write *a)
        archive_entry_free(entry);
 
        if (mtree->buf.length > 32768) {
-               ret = (a->compressor.write)(a, mtree->buf.s, mtree->buf.length);
+               ret = __archive_write_output(a, mtree->buf.s, mtree->buf.length);
                archive_string_empty(&mtree->buf);
        } else
                ret = ARCHIVE_OK;
@@ -836,7 +836,7 @@ archive_write_mtree_finish(struct archive_write *a)
 
        archive_write_set_bytes_in_last_block(&a->archive, 1);
 
-       return (a->compressor.write)(a, mtree->buf.s, mtree->buf.length);
+       return __archive_write_output(a, mtree->buf.s, mtree->buf.length);
 }
 
 static ssize_t
index 420a018f6fa06993294efde64419e2e53445c601..cab8f3756f4f2b5f6d598dd70ec5cae6e57edfb9 100644 (file)
@@ -1056,7 +1056,7 @@ archive_write_pax_header(struct archive_write *a,
                        (void)u; /* UNUSED */
                        exit(1);
                }
-               r = (a->compressor.write)(a, paxbuff, 512);
+               r = __archive_write_output(a, paxbuff, 512);
                if (r != ARCHIVE_OK) {
                        sparse_list_clear(pax);
                        pax->entry_bytes_remaining = 0;
@@ -1067,7 +1067,7 @@ archive_write_pax_header(struct archive_write *a,
                pax->entry_bytes_remaining = archive_strlen(&(pax->pax_header));
                pax->entry_padding = 0x1ff & (-(int64_t)pax->entry_bytes_remaining);
 
-               r = (a->compressor.write)(a, pax->pax_header.s,
+               r = __archive_write_output(a, pax->pax_header.s,
                    archive_strlen(&(pax->pax_header)));
                if (r != ARCHIVE_OK) {
                        /* If a write fails, we're pretty much toast. */
@@ -1083,7 +1083,7 @@ archive_write_pax_header(struct archive_write *a,
        }
 
        /* Write the header for main entry. */
-       r = (a->compressor.write)(a, ustarbuff, 512);
+       r = __archive_write_output(a, ustarbuff, 512);
        if (r != ARCHIVE_OK)
                return (r);
 
@@ -1327,7 +1327,7 @@ build_pax_attribute_name(char *dest, const char *src)
  * <dir>/GNUSparseFile.<pid>/<original file name>
  *
  * This function is used for only Sparse file, a file type of which
- * is regular file. 
+ * is regular file.
  */
 static char *
 build_gnu_sparse_name(char *dest, const char *src)
@@ -1374,13 +1374,7 @@ build_gnu_sparse_name(char *dest, const char *src)
 static int
 archive_write_pax_finish(struct archive_write *a)
 {
-       int r;
-
-       if (a->compressor.write == NULL)
-               return (ARCHIVE_OK);
-
-       r = write_nulls(a, 512 * 2);
-       return (r);
+       return (write_nulls(a, 512 * 2));
 }
 
 static int
@@ -1431,7 +1425,7 @@ write_nulls(struct archive_write *a, size_t padding)
 
        while (padding > 0) {
                to_write = padding < a->null_length ? padding : a->null_length;
-               ret = (a->compressor.write)(a, a->nulls, to_write);
+               ret = __archive_write_output(a, a->nulls, to_write);
                if (ret != ARCHIVE_OK)
                        return (ret);
                padding -= to_write;
@@ -1451,10 +1445,10 @@ archive_write_pax_data(struct archive_write *a, const void *buff, size_t s)
 
        /*
         * According to GNU PAX format 1.0, write a sparse map
-        * before the body. 
+        * before the body.
         */
        if (archive_strlen(&(pax->sparse_map))) {
-               ret = (a->compressor.write)(a, pax->sparse_map.s,
+               ret = __archive_write_output(a, pax->sparse_map.s,
                    archive_strlen(&(pax->sparse_map)));
                if (ret != ARCHIVE_OK)
                        return (ret);
@@ -1491,7 +1485,7 @@ archive_write_pax_data(struct archive_write *a, const void *buff, size_t s)
                        continue;
                }
 
-               ret = (a->compressor.write)(a, p, ws);
+               ret = __archive_write_output(a, p, ws);
                pax->sparse_list->remaining -= ws;
                total += ws;
                if (ret != ARCHIVE_OK)
index 62a875b98d30a53077aaa38136393da94c8dfb6b..0348b4eb0a34691a684b88c489a398796d0e0509 100644 (file)
@@ -353,7 +353,7 @@ archive_write_shar_data_sed(struct archive_write *a, const void *buff, size_t n)
                __archive_errx(1, "Out of memory");
 
        if (shar->work.length > ensured) {
-               ret = (*a->compressor.write)(a, shar->work.s,
+               ret = __archive_write_output(a, shar->work.s,
                    shar->work.length);
                if (ret != ARCHIVE_OK)
                        return (ARCHIVE_FATAL);
@@ -377,7 +377,7 @@ archive_write_shar_data_sed(struct archive_write *a, const void *buff, size_t n)
 
                if (buf >= buf_end) {
                        shar->work.length = buf - shar->work.s;
-                       ret = (*a->compressor.write)(a, shar->work.s,
+                       ret = __archive_write_output(a, shar->work.s,
                            shar->work.length);
                        if (ret != ARCHIVE_OK)
                                return (ARCHIVE_FATAL);
@@ -478,7 +478,7 @@ archive_write_shar_data_uuencode(struct archive_write *a, const void *buff,
 
                if (shar->work.length < 65536)
                        continue;
-               ret = (*a->compressor.write)(a, shar->work.s,
+               ret = __archive_write_output(a, shar->work.s,
                    shar->work.length);
                if (ret != ARCHIVE_OK)
                        return (ARCHIVE_FATAL);
@@ -561,7 +561,7 @@ archive_write_shar_finish_entry(struct archive_write *a)
        if (shar->work.length < 65536)
                return (ARCHIVE_OK);
 
-       ret = (*a->compressor.write)(a, shar->work.s, shar->work.length);
+       ret = __archive_write_output(a, shar->work.s, shar->work.length);
        if (ret != ARCHIVE_OK)
                return (ARCHIVE_FATAL);
        archive_string_empty(&shar->work);
@@ -593,7 +593,7 @@ archive_write_shar_finish(struct archive_write *a)
 
        archive_strcat(&shar->work, "exit\n");
 
-       ret = (*a->compressor.write)(a, shar->work.s, shar->work.length);
+       ret = __archive_write_output(a, shar->work.s, shar->work.length);
        if (ret != ARCHIVE_OK)
                return (ARCHIVE_FATAL);
 
index 1de273fc2dfb78fe87c38805b2af176093985dc2..5bd038ee25fe13e7710fa18f8481612924e96e9b 100644 (file)
@@ -232,7 +232,7 @@ archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
        ret = __archive_write_format_header_ustar(a, buff, entry, -1, 1);
        if (ret < ARCHIVE_WARN)
                return (ret);
-       ret2 = (a->compressor.write)(a, buff, 512);
+       ret2 = __archive_write_output(a, buff, 512);
        if (ret2 < ARCHIVE_WARN)
                return (ret2);
        if (ret2 < ret)
@@ -521,13 +521,7 @@ format_octal(int64_t v, char *p, int s)
 static int
 archive_write_ustar_finish(struct archive_write *a)
 {
-       int r;
-
-       if (a->compressor.write == NULL)
-               return (ARCHIVE_OK);
-
-       r = write_nulls(a, 512*2);
-       return (r);
+       return (write_nulls(a, 512*2));
 }
 
 static int
@@ -562,7 +556,7 @@ write_nulls(struct archive_write *a, size_t padding)
 
        while (padding > 0) {
                to_write = padding < a->null_length ? padding : a->null_length;
-               ret = (a->compressor.write)(a, a->nulls, to_write);
+               ret = __archive_write_output(a, a->nulls, to_write);
                if (ret != ARCHIVE_OK)
                        return (ret);
                padding -= to_write;
@@ -579,7 +573,7 @@ archive_write_ustar_data(struct archive_write *a, const void *buff, size_t s)
        ustar = (struct ustar *)a->format_data;
        if (s > ustar->entry_bytes_remaining)
                s = ustar->entry_bytes_remaining;
-       ret = (a->compressor.write)(a, buff, s);
+       ret = __archive_write_output(a, buff, s);
        ustar->entry_bytes_remaining -= s;
        if (ret != ARCHIVE_OK)
                return (ret);
index 14cc6697df03c7d5829da019bbc0b8ef013e3bec..620dc08b173d6d685d613817879972710065d8da 100644 (file)
@@ -366,7 +366,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
        archive_le32enc(&e.mtime, archive_entry_mtime(entry));
        archive_le32enc(&e.atime, archive_entry_atime(entry));
        archive_le32enc(&e.ctime, archive_entry_ctime(entry));
-           
+
        archive_le16enc(&e.unix_id, ZIP_SIGNATURE_EXTRA_UNIX);
        archive_le16enc(&e.unix_size, sizeof(e.unix_uid) + sizeof(e.unix_gid));
        archive_le16enc(&e.unix_uid, archive_entry_uid(entry));
@@ -374,7 +374,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
 
        archive_le32enc(&d->uncompressed_size, size);
 
-       ret = (a->compressor.write)(a, &h, sizeof(h));
+       ret = __archive_write_output(a, &h, sizeof(h));
        if (ret != ARCHIVE_OK)
                return (ARCHIVE_FATAL);
        zip->written_bytes += sizeof(h);
@@ -384,7 +384,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
                return (ARCHIVE_FATAL);
        zip->written_bytes += ret;
 
-       ret = (a->compressor.write)(a, &e, sizeof(e));
+       ret = __archive_write_output(a, &e, sizeof(e));
        if (ret != ARCHIVE_OK)
                return (ARCHIVE_FATAL);
        zip->written_bytes += sizeof(e);
@@ -406,7 +406,7 @@ archive_write_zip_data(struct archive_write *a, const void *buff, size_t s)
 
        switch (zip->compression) {
        case COMPRESSION_STORE:
-               ret = (a->compressor.write)(a, buff, s);
+               ret = __archive_write_output(a, buff, s);
                if (ret != ARCHIVE_OK) return (ret);
                zip->written_bytes += s;
                zip->remaining_data_bytes -= s;
@@ -422,7 +422,7 @@ archive_write_zip_data(struct archive_write *a, const void *buff, size_t s)
                        if (ret == Z_STREAM_ERROR)
                                return (ARCHIVE_FATAL);
                        if (zip->stream.avail_out == 0) {
-                               ret = (a->compressor.write)(a, zip->buf, zip->len_buf);
+                               ret = __archive_write_output(a, zip->buf, zip->len_buf);
                                if (ret != ARCHIVE_OK)
                                        return (ret);
                                l->compressed_size += zip->len_buf;
@@ -466,7 +466,7 @@ archive_write_zip_finish_entry(struct archive_write *a)
                        if (ret == Z_STREAM_ERROR)
                                return (ARCHIVE_FATAL);
                        reminder = zip->len_buf - zip->stream.avail_out;
-                       ret = (a->compressor.write)(a, zip->buf, reminder);
+                       ret = __archive_write_output(a, zip->buf, reminder);
                        if (ret != ARCHIVE_OK)
                                return (ret);
                        l->compressed_size += reminder;
@@ -483,7 +483,7 @@ archive_write_zip_finish_entry(struct archive_write *a)
 
        archive_le32enc(&d->crc32, l->crc32);
        archive_le32enc(&d->compressed_size, l->compressed_size);
-       ret = (a->compressor.write)(a, d, sizeof(*d));
+       ret = __archive_write_output(a, d, sizeof(*d));
        if (ret != ARCHIVE_OK)
                return (ARCHIVE_FATAL);
        zip->written_bytes += sizeof(*d);
@@ -543,7 +543,7 @@ archive_write_zip_finish(struct archive_write *a)
                archive_le16enc(&e.unix_id, ZIP_SIGNATURE_EXTRA_UNIX);
                archive_le16enc(&e.unix_size, 0x0000);
 
-               ret = (a->compressor.write)(a, &h, sizeof(h));
+               ret = __archive_write_output(a, &h, sizeof(h));
                if (ret != ARCHIVE_OK)
                        return (ARCHIVE_FATAL);
                zip->written_bytes += sizeof(h);
@@ -553,7 +553,7 @@ archive_write_zip_finish(struct archive_write *a)
                        return (ARCHIVE_FATAL);
                zip->written_bytes += ret;
 
-               ret = (a->compressor.write)(a, &e, sizeof(e));
+               ret = __archive_write_output(a, &e, sizeof(e));
                if (ret != ARCHIVE_OK)
                        return (ARCHIVE_FATAL);
                zip->written_bytes += sizeof(e);
@@ -572,7 +572,7 @@ archive_write_zip_finish(struct archive_write *a)
        archive_le32enc(&end.offset, offset_start);
 
        /* Writing end of central directory. */
-       ret = (a->compressor.write)(a, &end, sizeof(end));
+       ret = __archive_write_output(a, &end, sizeof(end));
        if (ret != ARCHIVE_OK)
                return (ARCHIVE_FATAL);
        zip->written_bytes += sizeof(end);
@@ -650,14 +650,14 @@ write_path(struct archive_entry *entry, struct archive_write *archive)
        type = archive_entry_filetype(entry);
        written_bytes = 0;
 
-       ret = (archive->compressor.write)(archive, path, strlen(path));
+       ret = __archive_write_output(archive, path, strlen(path));
        if (ret != ARCHIVE_OK)
                return (ARCHIVE_FATAL);
        written_bytes += strlen(path);
 
        /* Folders are recognized by a traling slash. */
        if ((type == AE_IFDIR) & (path[strlen(path) - 1] != '/')) {
-               ret = (archive->compressor.write)(archive, "/", 1);
+               ret = __archive_write_output(archive, "/", 1);
                if (ret != ARCHIVE_OK)
                        return (ARCHIVE_FATAL);
                written_bytes += 1;