Synchronous libarchive to 2.2.4 from FreeBSD, including fixes related to
authorMatthew Dillon <dillon@dragonflybsd.org>
Fri, 13 Jul 2007 06:59:51 +0000 (06:59 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Fri, 13 Jul 2007 06:59:51 +0000 (06:59 +0000)
FreeBSD Security Advisory FreeBSD-SA-07:05.libarchive.

52 files changed:
contrib/libarchive-2/libarchive/archive.h.in
contrib/libarchive-2/libarchive/archive_entry.3
contrib/libarchive-2/libarchive/archive_entry.c
contrib/libarchive-2/libarchive/archive_entry.h
contrib/libarchive-2/libarchive/archive_entry_copy_stat.c
contrib/libarchive-2/libarchive/archive_entry_private.h
contrib/libarchive-2/libarchive/archive_entry_stat.c
contrib/libarchive-2/libarchive/archive_platform.h
contrib/libarchive-2/libarchive/archive_read.3
contrib/libarchive-2/libarchive/archive_read.c
contrib/libarchive-2/libarchive/archive_read_extract.c
contrib/libarchive-2/libarchive/archive_read_open_fd.c
contrib/libarchive-2/libarchive/archive_read_open_file.c
contrib/libarchive-2/libarchive/archive_read_open_filename.c
contrib/libarchive-2/libarchive/archive_read_open_memory.c
contrib/libarchive-2/libarchive/archive_read_private.h
contrib/libarchive-2/libarchive/archive_read_support_compression_bzip2.c
contrib/libarchive-2/libarchive/archive_read_support_compression_compress.c
contrib/libarchive-2/libarchive/archive_read_support_compression_gzip.c
contrib/libarchive-2/libarchive/archive_read_support_compression_none.c
contrib/libarchive-2/libarchive/archive_read_support_compression_program.c
contrib/libarchive-2/libarchive/archive_read_support_format_ar.c
contrib/libarchive-2/libarchive/archive_read_support_format_cpio.c
contrib/libarchive-2/libarchive/archive_read_support_format_empty.c
contrib/libarchive-2/libarchive/archive_read_support_format_iso9660.c
contrib/libarchive-2/libarchive/archive_read_support_format_tar.c
contrib/libarchive-2/libarchive/archive_read_support_format_zip.c
contrib/libarchive-2/libarchive/archive_string.c
contrib/libarchive-2/libarchive/archive_string.h
contrib/libarchive-2/libarchive/archive_util.3
contrib/libarchive-2/libarchive/archive_util.c
contrib/libarchive-2/libarchive/archive_write.3
contrib/libarchive-2/libarchive/archive_write.c
contrib/libarchive-2/libarchive/archive_write_disk.c
contrib/libarchive-2/libarchive/archive_write_disk_set_standard_lookup.c
contrib/libarchive-2/libarchive/archive_write_private.h
contrib/libarchive-2/libarchive/archive_write_set_compression_bzip2.c
contrib/libarchive-2/libarchive/archive_write_set_compression_gzip.c
contrib/libarchive-2/libarchive/archive_write_set_compression_none.c
contrib/libarchive-2/libarchive/archive_write_set_compression_program.c
contrib/libarchive-2/libarchive/archive_write_set_format.c
contrib/libarchive-2/libarchive/archive_write_set_format_ar.c
contrib/libarchive-2/libarchive/archive_write_set_format_by_name.c
contrib/libarchive-2/libarchive/archive_write_set_format_cpio.c
contrib/libarchive-2/libarchive/archive_write_set_format_cpio_newc.c [copied from contrib/libarchive-2/libarchive/archive_write_set_format_cpio.c with 56% similarity]
contrib/libarchive-2/libarchive/archive_write_set_format_pax.c
contrib/libarchive-2/libarchive/archive_write_set_format_shar.c
contrib/libarchive-2/libarchive/archive_write_set_format_ustar.c
contrib/libarchive-2/libarchive/filter_fork.c
contrib/libarchive-2/libarchive/filter_fork.h
contrib/libarchive-2/libarchive/libarchive_internals.3
contrib/libarchive-2/tar/bsdtar.1

index 7a085d0..843276f 100644 (file)
@@ -22,7 +22,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/lib/libarchive/archive.h.in,v 1.43 2007/05/02 05:29:55 cperciva Exp $
+ * $FreeBSD: src/lib/libarchive/archive.h.in,v 1.46 2007/07/06 15:36:37 kientzle Exp $
  */
 
 #ifndef ARCHIVE_H_INCLUDED
@@ -50,31 +50,68 @@ typedef unsigned short mode_t;
 extern "C" {
 #endif
 
+/*
+ * Each of the version identifiers comes as a macro and a function.
+ * The macro identifies the installed header; the function identifies
+ * the library version (which may not be the same if you're using a
+ * dynamically-linked version of the library).
+ */
 
 /*
- * If ARCHIVE_API_VERSION != archive_api_version(), then the library you
- * were linked with is using an incompatible API to the one you were
- * compiled with.  This is almost certainly a fatal problem.
- *
- * ARCHIVE_API_FEATURE is incremented with each significant feature
- * addition, so you can test (at compile or run time) if a particular
- * feature is implemented.  It's no big deal if ARCHIVE_API_FEATURE !=
- * archive_api_feature(), as long as both are high enough to include
- * the features you're relying on.  Specific values of FEATURE are
- * documented here:
+ * Textual name/version of the library, useful for version displays.
+ */
+#define        ARCHIVE_LIBRARY_VERSION "libarchive @ARCHIVE_VERSION@"
+const char *   archive_version(void);
+
+/*
+ * Major version number: If ARCHIVE_API_VERSION !=
+ * archive_api_version(), then the library you were linked with is
+ * using an incompatible API to the one you were compiled with.  This
+ * is almost certainly a fatal problem.
+ */
+#define        ARCHIVE_API_VERSION     @ARCHIVE_API_MAJOR@
+int            archive_api_version(void);
+
+/*
+ * Minor version number: ARCHIVE_API_FEATURE is incremented with each
+ * significant feature addition, so you can test (at compile or run
+ * time) if a particular feature is implemented.  It's no big deal if
+ * ARCHIVE_API_FEATURE != archive_api_feature(), as long as both are
+ * high enough to include the features you're relying on.  Specific
+ * values of FEATURE are documented here:
  *
  *    1 - Version tests are available.
  *    2 - archive_{read,write}_close available separately from _finish.
  *    3 - open_memory, open_memory2, open_FILE, open_fd available
  *    5 - archive_write_disk interface available
+ *
+ * Unfortunately, this count resets whenever ARCHIVE_API_VERSION changes,
+ * making it awkward to use in practice.  For that reason, it is deprecated
+ * in favor of the more-accurate version stamp below.  It will eventually
+ * be removed.
  */
-#define        ARCHIVE_API_VERSION     @ARCHIVE_API_MAJOR@
-int            archive_api_version(void);
 #define        ARCHIVE_API_FEATURE     @ARCHIVE_API_MINOR@
 int            archive_api_feature(void);
-/* Textual name/version of the library. */
-#define        ARCHIVE_LIBRARY_VERSION "libarchive @ARCHIVE_VERSION@"
-const char *   archive_version(void);
+
+/*
+ * The "version stamp" is a single integer that makes it easy to check
+ * the exact version: for version a.b.c, the version stamp is
+ * printf("%d%03d%03d",a,b,c).  For example, version 2.12.108 has
+ * version stamp 2012108.
+ *
+ * This was introduced with libarchive 1.9.0 in the libarchive 1.x family
+ * and libarchive 2.2.4 in the libarchive 2.x family.  The following
+ * may be useful if you really want to do feature detection for earlier
+ * libarchive versions:
+ *
+ * #ifndef ARCHIVE_VERSION_STAMP
+ * #define ARCHIVE_VERSION_STAMP       \
+ *             (ARCHIVE_API_VERSION * 1000000 + ARCHIVE_API_FEATURE * 1000)
+ * #endif
+ */
+#define ARCHIVE_VERSION_STAMP  @ARCHIVE_VERSION_STAMP@
+int            archive_version_stamp(void);
+
 
 #define        ARCHIVE_BYTES_PER_RECORD          512
 #define        ARCHIVE_DEFAULT_BYTES_PER_BLOCK 10240
@@ -390,6 +427,7 @@ int          archive_write_set_format_by_name(struct archive *,
 int             archive_write_set_format_ar_bsd(struct archive *);
 int             archive_write_set_format_ar_svr4(struct archive *);
 int             archive_write_set_format_cpio(struct archive *);
+int             archive_write_set_format_cpio_newc(struct archive *);
 /* TODO: int archive_write_set_format_old_tar(struct archive *); */
 int             archive_write_set_format_pax(struct archive *);
 int             archive_write_set_format_pax_restricted(struct archive *);
index ff6066f..11b9356 100644 (file)
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: src/lib/libarchive/archive_entry.3,v 1.13 2007/03/03 07:37:36 kientzle Exp $
+.\" $FreeBSD: src/lib/libarchive/archive_entry.3,v 1.14 2007/05/29 01:00:18 kientzle Exp $
 .\"
 .Dd December 15, 2003
 .Dt archive_entry 3
index 908987d..6772d7f 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_entry.c,v 1.42 2007/04/14 02:37:22 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_entry.c,v 1.43 2007/05/29 01:00:18 kientzle Exp $");
 
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
index 3c42f16..6946751 100644 (file)
@@ -22,7 +22,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/lib/libarchive/archive_entry.h,v 1.21 2007/03/01 06:22:34 kientzle Exp $
+ * $FreeBSD: src/lib/libarchive/archive_entry.h,v 1.22 2007/05/29 01:00:18 kientzle Exp $
  */
 
 #ifndef ARCHIVE_ENTRY_H_INCLUDED
index 5b3d35e..514db02 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_entry_copy_stat.c,v 1.1 2007/05/29 01:00:18 kientzle Exp $");
 
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
index 34b8e26..234ba47 100644 (file)
@@ -22,7 +22,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: src/lib/libarchive/archive_entry_private.h,v 1.1 2007/05/29 01:00:18 kientzle Exp $
  */
 
 #ifndef ARCHIVE_ENTRY_PRIVATE_H_INCLUDED
index d06ee2c..6ef5b37 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_entry_stat.c,v 1.1 2007/05/29 01:00:18 kientzle Exp $");
 
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
index b6815f5..0f8a170 100644 (file)
@@ -22,7 +22,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/lib/libarchive/archive_platform.h,v 1.26 2007/04/15 00:53:38 kientzle Exp $
+ * $FreeBSD: src/lib/libarchive/archive_platform.h,v 1.27 2007/05/29 01:00:18 kientzle Exp $
  */
 
 /*
index e6955da..9e4f878 100644 (file)
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: src/lib/libarchive/archive_read.3,v 1.33 2007/04/07 05:53:11 kientzle Exp $
+.\" $FreeBSD: src/lib/libarchive/archive_read.3,v 1.34 2007/05/29 01:00:18 kientzle Exp $
 .\"
 .Dd August 19, 2006
 .Dt archive_read 3
index 9eab499..5433097 100644 (file)
@@ -32,7 +32,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read.c,v 1.34 2007/04/05 15:51:19 cperciva Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read.c,v 1.35 2007/05/29 01:00:18 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
index a317ca9..423ff7d 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_extract.c,v 1.58 2007/04/16 04:04:49 cperciva Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_extract.c,v 1.59 2007/05/29 01:00:18 kientzle Exp $");
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
index 4db681c..2ebd46d 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_open_fd.c,v 1.11 2007/01/09 08:05:55 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_open_fd.c,v 1.13 2007/06/26 03:06:48 kientzle Exp $");
 
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
@@ -47,6 +47,7 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_open_fd.c,v 1.11 2007/01/09
 struct read_fd_data {
        int      fd;
        size_t   block_size;
+       char     can_skip;
        void    *buffer;
 };
 
@@ -77,6 +78,8 @@ archive_read_open_fd(struct archive *a, int fd, size_t block_size)
                return (ARCHIVE_FATAL);
        }
        mine->fd = fd;
+       /* lseek() hardly ever works, so disable it by default.  See below. */
+       mine->can_skip = 0;
        return (archive_read_open2(a, mine, file_open, file_read, file_skip, file_close));
 }
 
@@ -91,8 +94,18 @@ file_open(struct archive *a, void *client_data)
                return (ARCHIVE_FATAL);
        }
 
-       if (S_ISREG(st.st_mode))
+       if (S_ISREG(st.st_mode)) {
                archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
+               /*
+                * Enabling skip here is a performance optimization for
+                * anything that supports lseek().  On FreeBSD, only
+                * regular files and raw disk devices support lseek() and
+                * there's no portable way to determine if a device is
+                * a raw disk device, so we only enable this optimization
+                * for regular files.
+                */
+               mine->can_skip = 1;
+       }
        return (ARCHIVE_OK);
 }
 
@@ -121,8 +134,14 @@ file_skip(struct archive *a, void *client_data, off_t request)
        struct read_fd_data *mine = (struct read_fd_data *)client_data;
        off_t old_offset, new_offset;
 
+       if (!mine->can_skip)
+               return (0);
+
        /* Reduce request to the next smallest multiple of block_size */
        request = (request / mine->block_size) * mine->block_size;
+       if (request == 0)
+               return (0);
+
        /*
         * Hurray for lazy evaluation: if the first lseek fails, the second
         * one will not be executed.
@@ -130,6 +149,9 @@ file_skip(struct archive *a, void *client_data, off_t request)
        if (((old_offset = lseek(mine->fd, 0, SEEK_CUR)) < 0) ||
            ((new_offset = lseek(mine->fd, request, SEEK_CUR)) < 0))
        {
+               /* If seek failed once, it will probably fail again. */
+               mine->can_skip = 0;
+
                if (errno == ESPIPE)
                {
                        /*
index 6d83955..55c431c 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_open_file.c,v 1.19 2007/01/09 08:05:55 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_open_file.c,v 1.20 2007/06/26 03:06:48 kientzle Exp $");
 
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
@@ -51,6 +51,7 @@ struct read_FILE_data {
        FILE    *f;
        size_t   block_size;
        void    *buffer;
+       char     can_skip;
 };
 
 static int     file_close(struct archive *, void *);
@@ -80,6 +81,8 @@ archive_read_open_FILE(struct archive *a, FILE *f)
                return (ARCHIVE_FATAL);
        }
        mine->f = f;
+       /* Suppress skip by default. See below. */
+       mine->can_skip = 0;
        return (archive_read_open2(a, mine, file_open, file_read,
                    file_skip, file_close));
 }
@@ -95,8 +98,11 @@ file_open(struct archive *a, void *client_data)
         * it's not a file.  (FILE * objects can wrap many kinds
         * of I/O streams.)
         */
-       if (fstat(fileno(mine->f), &st) == 0 && S_ISREG(st.st_mode))
+       if (fstat(fileno(mine->f), &st) == 0 && S_ISREG(st.st_mode)) {
                archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
+               /* Enable the seek optimization for regular files. */
+               mine->can_skip = 1;
+       }
 
        return (ARCHIVE_OK);
 }
@@ -125,21 +131,25 @@ file_skip(struct archive *a, void *client_data, off_t request)
 {
        struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
 
+       (void)a; /* UNUSED */
+
        /*
-        * Note: the 'fd' and 'filename' versions round the request
-        * down to a multiple of the block size to ensure proper
-        * operation on block-oriented media such as tapes.  But stdio
-        * doesn't work with such media (it doesn't ensure blocking),
-        * so we don't need to bother.
+        * If we can't skip, return 0 as the amount we did step and
+        * the caller will work around by reading and discarding.
         */
+       if (!mine->can_skip)
+               return (0);
+       if (request == 0)
+               return (0);
+
 #if HAVE_FSEEKO
        if (fseeko(mine->f, request, SEEK_CUR) != 0)
 #else
        if (fseek(mine->f, request, SEEK_CUR) != 0)
 #endif
        {
-               archive_set_error(a, errno, "Error skipping forward");
-               return (ARCHIVE_FATAL);
+               mine->can_skip = 0;
+               return (0);
        }
        return (request);
 }
index 47bc4ef..02e7902 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_open_filename.c,v 1.18 2007/01/09 08:05:55 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_open_filename.c,v 1.20 2007/06/26 03:06:48 kientzle Exp $");
 
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
@@ -52,6 +52,7 @@ struct read_file_data {
        size_t   block_size;
        void    *buffer;
        mode_t   st_mode;  /* Mode bits for opened file. */
+       char     can_skip; /* This file supports skipping. */
        char     filename[1]; /* Must be last! */
 };
 
@@ -95,6 +96,8 @@ archive_read_open_filename(struct archive *a, const char *filename,
        mine->block_size = block_size;
        mine->buffer = NULL;
        mine->fd = -1;
+       /* lseek() almost never works; disable it by default.  See below. */
+       mine->can_skip = 0;
        return (archive_read_open2(a, mine, file_open, file_read, file_skip, file_close));
 }
 
@@ -121,8 +124,19 @@ file_open(struct archive *a, void *client_data)
        if (fstat(mine->fd, &st) == 0) {
                /* If we're reading a file from disk, ensure that we don't
                   overwrite it with an extracted file. */
-               if (S_ISREG(st.st_mode))
+               if (S_ISREG(st.st_mode)) {
                        archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
+                       /*
+                        * Enabling skip here is a performance
+                        * optimization for anything that supports
+                        * lseek().  On FreeBSD, only regular files
+                        * and raw disk devices support lseek() and
+                        * there's no portable way to determine if a
+                        * device is a raw disk device, so we only
+                        * enable this optimization for regular files.
+                        */
+                       mine->can_skip = 1;
+               }
                /* Remember mode so close can decide whether to flush. */
                mine->st_mode = st.st_mode;
        } else {
@@ -165,8 +179,14 @@ file_skip(struct archive *a, void *client_data, off_t request)
        struct read_file_data *mine = (struct read_file_data *)client_data;
        off_t old_offset, new_offset;
 
+       if (!mine->can_skip) /* We can't skip, so ... */
+               return (0); /* ... skip zero bytes. */
+
        /* Reduce request to the next smallest multiple of block_size */
        request = (request / mine->block_size) * mine->block_size;
+       if (request == 0)
+               return (0);
+
        /*
         * Hurray for lazy evaluation: if the first lseek fails, the second
         * one will not be executed.
@@ -174,6 +194,9 @@ file_skip(struct archive *a, void *client_data, off_t request)
        if (((old_offset = lseek(mine->fd, 0, SEEK_CUR)) < 0) ||
            ((new_offset = lseek(mine->fd, request, SEEK_CUR)) < 0))
        {
+               /* If skip failed once, it will probably fail again. */
+               mine->can_skip = 0;
+
                if (errno == ESPIPE)
                {
                        /*
index 3fc8522..61f574f 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_open_memory.c,v 1.4 2007/04/02 00:25:11 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_open_memory.c,v 1.6 2007/07/06 15:51:59 kientzle Exp $");
 
 #include <errno.h>
 #include <stdlib.h>
@@ -134,7 +134,7 @@ memory_read_skip(struct archive *a, void *client_data, off_t skip)
        struct read_memory_data *mine = (struct read_memory_data *)client_data;
 
        (void)a; /* UNUSED */
-       if (skip > mine->end - mine->buffer)
+       if ((off_t)skip > (off_t)(mine->end - mine->buffer))
                skip = mine->end - mine->buffer;
        /* Round down to block size. */
        skip /= mine->read_size;
index d8cfa75..f0f5202 100644 (file)
@@ -22,7 +22,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/lib/libarchive/archive_read_private.h,v 1.2 2007/04/02 00:11:54 kientzle Exp $
+ * $FreeBSD: src/lib/libarchive/archive_read_private.h,v 1.3 2007/05/29 01:00:18 kientzle Exp $
  */
 
 #ifndef ARCHIVE_READ_PRIVATE_H_INCLUDED
index c924940..aa664d1 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "archive_platform.h"
 
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_bzip2.c,v 1.15 2007/04/05 05:18:16 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_bzip2.c,v 1.16 2007/05/29 01:00:18 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
index cb43410..050099b 100644 (file)
@@ -64,7 +64,7 @@
 
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_compress.c,v 1.9 2007/04/05 05:18:16 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_compress.c,v 1.10 2007/05/29 01:00:19 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
index b2e0d8b..89784b8 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "archive_platform.h"
 
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_gzip.c,v 1.14 2007/04/05 05:18:16 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_gzip.c,v 1.15 2007/05/29 01:00:19 kientzle Exp $");
 
 
 #ifdef HAVE_ERRNO_H
index e976398..58a5559 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_none.c,v 1.16 2007/04/05 05:18:16 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_none.c,v 1.17 2007/05/29 01:00:19 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
index d406797..6815a3b 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_program.c,v 1.1 2007/05/29 01:00:19 kientzle Exp $");
 
 #ifdef HAVE_SYS_WAIT_H
 #  include <sys/wait.h>
index 4ffc1cd..97ed28a 100644 (file)
@@ -26,7 +26,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_ar.c,v 1.5 2007/04/15 00:53:38 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_ar.c,v 1.6 2007/05/29 01:00:19 kientzle Exp $");
 
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
index d816e9e..7a056b9 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_cpio.c,v 1.23 2007/04/13 16:07:25 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_cpio.c,v 1.24 2007/05/29 01:00:19 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
index f664b87..837fdef 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_empty.c,v 1.2 2007/03/03 07:37:36 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_empty.c,v 1.3 2007/05/29 01:00:19 kientzle Exp $");
 
 #include "archive.h"
 #include "archive_entry.h"
index fbc4c89..d77bd87 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_iso9660.c,v 1.22 2007/04/02 00:29:52 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_iso9660.c,v 1.23 2007/05/29 01:00:19 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
index 14c5535..f01015c 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_tar.c,v 1.55 2007/05/21 04:45:24 cperciva Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_tar.c,v 1.58 2007/07/12 15:00:28 cperciva Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
@@ -150,22 +150,34 @@ struct tar {
        struct archive_string    longname;
        struct archive_string    pax_header;
        struct archive_string    pax_global;
+       struct archive_string    line;
        wchar_t                 *pax_entry;
        size_t                   pax_entry_length;
        int                      header_recursion_depth;
        off_t                    entry_bytes_remaining;
        off_t                    entry_offset;
        off_t                    entry_padding;
+       off_t                    realsize;
        struct sparse_block     *sparse_list;
+       struct sparse_block     *sparse_last;
+       int64_t                  sparse_offset;
+       int64_t                  sparse_numbytes;
+       int                      sparse_gnu_major;
+       int                      sparse_gnu_minor;
+       char                     sparse_gnu_pending;
 };
 
 static size_t  UTF8_mbrtowc(wchar_t *pwc, const char *s, size_t n);
 static int     archive_block_is_null(const unsigned char *p);
 static char    *base64_decode(const wchar_t *, size_t, size_t *);
-static int     gnu_read_sparse_data(struct archive_read *, struct tar *,
+static void     gnu_add_sparse_entry(struct tar *,
+                   off_t offset, off_t remaining);
+static int     gnu_sparse_old_read(struct archive_read *, struct tar *,
                    const struct archive_entry_header_gnutar *header);
-static void    gnu_parse_sparse_data(struct archive_read *, struct tar *,
+static void    gnu_sparse_old_parse(struct tar *,
                    const struct gnu_sparse *sparse, int length);
+static int     gnu_sparse_01_parse(struct tar *, const wchar_t *);
+static ssize_t gnu_sparse_10_read(struct archive_read *, struct tar *);
 static int     header_Solaris_ACL(struct archive_read *,  struct tar *,
                    struct archive_entry *, const void *);
 static int     header_common(struct archive_read *,  struct tar *,
@@ -194,11 +206,12 @@ static int        archive_read_format_tar_skip(struct archive_read *a);
 static int     archive_read_format_tar_read_header(struct archive_read *,
                    struct archive_entry *);
 static int     checksum(struct archive_read *, const void *);
-static int     pax_attribute(struct archive_entry *,
+static int     pax_attribute(struct tar *, struct archive_entry *,
                    wchar_t *key, wchar_t *value);
 static int     pax_header(struct archive_read *, struct tar *,
                    struct archive_entry *, char *attr);
 static void    pax_time(const wchar_t *, int64_t *sec, long *nanos);
+static ssize_t readline(struct archive_read *, struct tar *, const char **);
 static int     read_body_to_string(struct archive_read *, struct tar *,
                    struct archive_string *, const void *h);
 static int64_t tar_atol(const char *, unsigned);
@@ -250,17 +263,23 @@ static int
 archive_read_format_tar_cleanup(struct archive_read *a)
 {
        struct tar *tar;
+       struct sparse_block *p;
 
        tar = (struct tar *)(a->format->data);
+       while (tar->sparse_list != NULL) {
+               p = tar->sparse_list;
+               tar->sparse_list = p->next;
+               free(p);
+       }
        archive_string_free(&tar->acl_text);
        archive_string_free(&tar->entry_name);
        archive_string_free(&tar->entry_linkname);
        archive_string_free(&tar->entry_uname);
        archive_string_free(&tar->entry_gname);
+       archive_string_free(&tar->line);
        archive_string_free(&tar->pax_global);
        archive_string_free(&tar->pax_header);
-       if (tar->pax_entry != NULL)
-               free(tar->pax_entry);
+       free(tar->pax_entry);
        free(tar);
        (a->format->data) = NULL;
        return (ARCHIVE_OK);
@@ -400,9 +419,11 @@ archive_read_format_tar_read_header(struct archive_read *a,
        static int default_inode;
        static int default_dev;
        struct tar *tar;
+       struct sparse_block *sp;
        const char *p;
        int r;
        size_t l;
+       ssize_t size;
 
        /* Assign default device/inode values. */
        archive_entry_set_dev(entry, 1 + default_dev); /* Don't use zero. */
@@ -415,9 +436,40 @@ archive_read_format_tar_read_header(struct archive_read *a,
 
        tar = (struct tar *)(a->format->data);
        tar->entry_offset = 0;
+       while (tar->sparse_list != NULL) {
+               sp = tar->sparse_list;
+               tar->sparse_list = sp->next;
+               free(sp);
+       }
+       tar->sparse_last = NULL;
 
        r = tar_read_header(a, tar, entry);
 
+       /*
+        * Yuck.  See comments for gnu_sparse_10_read for why this
+        * is here and not in _read_data where it "should" go.
+        */
+       if (tar->sparse_gnu_pending
+           && tar->sparse_gnu_major == 1
+           && tar->sparse_gnu_minor == 0) {
+               tar->sparse_gnu_pending = 0;
+               /* Read initial sparse map. */
+               size = gnu_sparse_10_read(a, tar);
+               if (size < 0)
+                       return (size);
+               tar->entry_bytes_remaining -= size;
+               tar->entry_padding += size;
+       }
+
+       /*
+        * "non-sparse" files are really just sparse files with
+        * a single block.
+        */
+       if (tar->sparse_list == NULL)
+               gnu_add_sparse_entry(tar, 0, tar->entry_bytes_remaining);
+
+       tar->realsize = archive_entry_size(entry);
+
        if (r == ARCHIVE_OK) {
                /*
                 * "Regular" entry with trailing '/' is really
@@ -442,55 +494,64 @@ archive_read_format_tar_read_data(struct archive_read *a,
        struct sparse_block *p;
 
        tar = (struct tar *)(a->format->data);
-       if (tar->sparse_list != NULL) {
-               /* Remove exhausted entries from sparse list. */
-               while (tar->sparse_list != NULL &&
-                   tar->sparse_list->remaining == 0) {
-                       p = tar->sparse_list;
-                       tar->sparse_list = p->next;
-                       free(p);
-               }
-               if (tar->sparse_list == NULL) {
-                       /* We exhausted the entire sparse list. */
-                       tar->entry_bytes_remaining = 0;
-               }
-       }
 
-       if (tar->entry_bytes_remaining > 0) {
-               bytes_read = (a->decompressor->read_ahead)(a, buff, 1);
-               if (bytes_read == 0) {
+       if (tar->sparse_gnu_pending) {
+               if (tar->sparse_gnu_major == 1 && tar->sparse_gnu_minor == 0) {
+                       /*
+                        * <sigh> We should parse the sparse data
+                        * here, but have to parse it as part of the
+                        * header because of a bug in GNU tar 1.16.1.
+                        */
+               } else {
+                       *size = 0;
+                       *offset = 0;
                        archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                           "Truncated tar archive");
-                       return (ARCHIVE_FATAL);
-               }
-               if (bytes_read < 0)
-                       return (ARCHIVE_FATAL);
-               if (bytes_read > tar->entry_bytes_remaining)
-                       bytes_read = tar->entry_bytes_remaining;
-               if (tar->sparse_list != NULL) {
-                       /* Don't read more than is available in the
-                        * current sparse block. */
-                       if (tar->sparse_list->remaining < bytes_read)
-                               bytes_read = tar->sparse_list->remaining;
-                       tar->entry_offset = tar->sparse_list->offset;
-                       tar->sparse_list->remaining -= bytes_read;
-                       tar->sparse_list->offset += bytes_read;
+                           "Unrecognized GNU sparse file format");
+                       return (ARCHIVE_WARN);
                }
-               *size = bytes_read;
-               *offset = tar->entry_offset;
-               tar->entry_offset += bytes_read;
-               tar->entry_bytes_remaining -= bytes_read;
-               (a->decompressor->consume)(a, bytes_read);
-               return (ARCHIVE_OK);
-       } else {
+               tar->sparse_gnu_pending = 0;
+       }
+
+       /* Remove exhausted entries from sparse list. */
+       while (tar->sparse_list != NULL &&
+           tar->sparse_list->remaining == 0) {
+               p = tar->sparse_list;
+               tar->sparse_list = p->next;
+               free(p);
+       }
+
+       /* If we're at end of file, return EOF. */
+       if (tar->sparse_list == NULL || tar->entry_bytes_remaining == 0) {
                if ((a->decompressor->skip)(a, tar->entry_padding) < 0)
                        return (ARCHIVE_FATAL);
                tar->entry_padding = 0;
                *buff = NULL;
                *size = 0;
-               *offset = tar->entry_offset;
+               *offset = tar->realsize;
                return (ARCHIVE_EOF);
        }
+
+       bytes_read = (a->decompressor->read_ahead)(a, buff, 1);
+       if (bytes_read == 0) {
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                   "Truncated tar archive");
+               return (ARCHIVE_FATAL);
+       }
+       if (bytes_read < 0)
+               return (ARCHIVE_FATAL);
+       if (bytes_read > tar->entry_bytes_remaining)
+               bytes_read = tar->entry_bytes_remaining;
+       /* Don't read more than is available in the
+        * current sparse block. */
+       if (tar->sparse_list->remaining < bytes_read)
+               bytes_read = tar->sparse_list->remaining;
+       *size = bytes_read;
+       *offset = tar->sparse_list->offset;
+       tar->sparse_list->remaining -= bytes_read;
+       tar->sparse_list->offset += bytes_read;
+       tar->entry_bytes_remaining -= bytes_read;
+       (a->decompressor->consume)(a, bytes_read);
+       return (ARCHIVE_OK);
 }
 
 static int
@@ -521,6 +582,7 @@ archive_read_format_tar_skip(struct archive_read *a)
                tar->sparse_list = p->next;
                free(p);
        }
+       tar->sparse_last = NULL;
 
        return (ARCHIVE_OK);
 }
@@ -628,7 +690,13 @@ tar_read_header(struct archive_read *a, struct tar *tar,
                }
        }
        --tar->header_recursion_depth;
-       return (err);
+       /* We return warnings or success as-is.  Anything else is fatal. */
+       if (err == ARCHIVE_WARN || err == ARCHIVE_OK)
+               return (err);
+       if (err == ARCHIVE_EOF)
+               /* EOF when recursively reading a header is bad. */
+               archive_set_error(&a->archive, EINVAL, "Damaged tar archive");
+       return (ARCHIVE_FATAL);
 }
 
 /*
@@ -699,32 +767,55 @@ static int
 header_Solaris_ACL(struct archive_read *a, struct tar *tar,
     struct archive_entry *entry, const void *h)
 {
-       int err, err2;
-       char *p;
+       const struct archive_entry_header_ustar *header;
+       size_t size;
+       int err;
+       char *acl, *p;
        wchar_t *wp;
 
+       /*
+        * read_body_to_string adds a NUL terminator, but we need a little
+        * more to make sure that we don't overrun acl_text later.
+        */
+       header = (const struct archive_entry_header_ustar *)h;
+       size = tar_atol(header->size, sizeof(header->size));
        err = read_body_to_string(a, tar, &(tar->acl_text), h);
-       err2 = tar_read_header(a, tar, entry);
-       err = err_combine(err, err2);
-
-       /* XXX Ensure p doesn't overrun acl_text */
+       if (err != ARCHIVE_OK)
+               return (err);
+       err = tar_read_header(a, tar, entry);
+       if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN))
+               return (err);
 
        /* Skip leading octal number. */
        /* XXX TODO: Parse the octal number and sanity-check it. */
-       p = tar->acl_text.s;
-       while (*p != '\0')
+       p = acl = tar->acl_text.s;
+       while (*p != '\0' && p < acl + size)
                p++;
        p++;
 
-       wp = (wchar_t *)malloc((strlen(p) + 1) * sizeof(wchar_t));
-       if (wp != NULL) {
-               utf8_decode(wp, p, strlen(p));
-               err2 = __archive_entry_acl_parse_w(entry, wp,
-                   ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
-               err = err_combine(err, err2);
-               free(wp);
+       if (p >= acl + size) {
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                   "Malformed Solaris ACL attribute");
+               return(ARCHIVE_WARN);
        }
 
+       /* Skip leading octal number. */
+       size -= (p - acl);
+       acl = p;
+
+       while (*p != '\0' && p < acl + size)
+               p++;
+
+       wp = (wchar_t *)malloc((p - acl + 1) * sizeof(wchar_t));
+       if (wp == NULL) {
+               archive_set_error(&a->archive, ENOMEM,
+                   "Can't allocate work buffer for ACL parsing");
+               return (ARCHIVE_FATAL);
+       }
+       utf8_decode(wp, acl, p - acl);
+       err = __archive_entry_acl_parse_w(entry, wp,
+           ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+       free(wp);
        return (err);
 }
 
@@ -735,15 +826,17 @@ static int
 header_longlink(struct archive_read *a, struct tar *tar,
     struct archive_entry *entry, const void *h)
 {
-       int err, err2;
+       int err;
 
        err = read_body_to_string(a, tar, &(tar->longlink), h);
-       err2 = tar_read_header(a, tar, entry);
-       if (err == ARCHIVE_OK && err2 == ARCHIVE_OK) {
-               /* Set symlink if symlink already set, else hardlink. */
-               archive_entry_set_link(entry, tar->longlink.s);
-       }
-       return (err_combine(err, err2));
+       if (err != ARCHIVE_OK)
+               return (err);
+       err = tar_read_header(a, tar, entry);
+       if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN))
+               return (err);
+       /* Set symlink if symlink already set, else hardlink. */
+       archive_entry_set_link(entry, tar->longlink.s);
+       return (ARCHIVE_OK);
 }
 
 /*
@@ -753,14 +846,17 @@ static int
 header_longname(struct archive_read *a, struct tar *tar,
     struct archive_entry *entry, const void *h)
 {
-       int err, err2;
+       int err;
 
        err = read_body_to_string(a, tar, &(tar->longname), h);
+       if (err != ARCHIVE_OK)
+               return (err);
        /* Read and parse "real" header, then override name. */
-       err2 = tar_read_header(a, tar, entry);
-       if (err == ARCHIVE_OK && err2 == ARCHIVE_OK)
-               archive_entry_set_pathname(entry, tar->longname.s);
-       return (err_combine(err, err2));
+       err = tar_read_header(a, tar, entry);
+       if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN))
+               return (err);
+       archive_entry_set_pathname(entry, tar->longname.s);
+       return (ARCHIVE_OK);
 }
 
 
@@ -793,6 +889,11 @@ read_body_to_string(struct archive_read *a, struct tar *tar,
        (void)tar; /* UNUSED */
        header = (const struct archive_entry_header_ustar *)h;
        size  = tar_atol(header->size, sizeof(header->size));
+       if ((size > 1048576) || (size < 0)) {
+               archive_set_error(&a->archive, EINVAL,
+                   "Special header too large");
+               return (ARCHIVE_FATAL);
+       }
 
        /* Read the body into the string. */
        archive_string_ensure(as, size+1);
@@ -800,6 +901,8 @@ read_body_to_string(struct archive_read *a, struct tar *tar,
        dest = as->s;
        while (padded_size > 0) {
                bytes_read = (a->decompressor->read_ahead)(a, &src, padded_size);
+               if (bytes_read == 0)
+                       return (ARCHIVE_EOF);
                if (bytes_read < 0)
                        return (ARCHIVE_FATAL);
                if (bytes_read > padded_size)
@@ -847,7 +950,8 @@ header_common(struct archive_read *a, struct tar *tar,
        archive_entry_set_mode(entry, tar_atol(header->mode, sizeof(header->mode)));
        archive_entry_set_uid(entry, tar_atol(header->uid, sizeof(header->uid)));
        archive_entry_set_gid(entry, tar_atol(header->gid, sizeof(header->gid)));
-       archive_entry_set_size(entry, tar_atol(header->size, sizeof(header->size)));
+       tar->entry_bytes_remaining = tar_atol(header->size, sizeof(header->size));
+       archive_entry_set_size(entry, tar->entry_bytes_remaining);
        archive_entry_set_mtime(entry, tar_atol(header->mtime, sizeof(header->mtime)), 0);
 
        /* Handle the tar type flag appropriately. */
@@ -892,29 +996,35 @@ header_common(struct archive_read *a, struct tar *tar,
                 */
                if (archive_entry_size(entry) > 0  &&
                    a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE  &&
-                   archive_read_format_tar_bid(a) > 50)
+                   archive_read_format_tar_bid(a) > 50) {
                        archive_entry_set_size(entry, 0);
-               break;
+                       tar->entry_bytes_remaining = 0;
+               }
        case '2': /* Symlink */
                archive_entry_set_filetype(entry, AE_IFLNK);
                archive_entry_set_size(entry, 0);
+               tar->entry_bytes_remaining = 0;
                archive_entry_set_symlink(entry, tar->entry_linkname.s);
                break;
        case '3': /* Character device */
                archive_entry_set_filetype(entry, AE_IFCHR);
                archive_entry_set_size(entry, 0);
+               tar->entry_bytes_remaining = 0;
                break;
        case '4': /* Block device */
                archive_entry_set_filetype(entry, AE_IFBLK);
                archive_entry_set_size(entry, 0);
+               tar->entry_bytes_remaining = 0;
                break;
        case '5': /* Dir */
                archive_entry_set_filetype(entry, AE_IFDIR);
                archive_entry_set_size(entry, 0);
+               tar->entry_bytes_remaining = 0;
                break;
        case '6': /* FIFO device */
                archive_entry_set_filetype(entry, AE_IFIFO);
                archive_entry_set_size(entry, 0);
+               tar->entry_bytes_remaining = 0;
                break;
        case 'D': /* GNU incremental directory type */
                /*
@@ -972,7 +1082,6 @@ header_old_tar(struct archive_read *a, struct tar *tar,
        /* Grab rest of common fields */
        header_common(a, tar, entry, h);
 
-       tar->entry_bytes_remaining = archive_entry_size(entry);
        tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
        return (0);
 }
@@ -984,11 +1093,13 @@ static int
 header_pax_global(struct archive_read *a, struct tar *tar,
     struct archive_entry *entry, const void *h)
 {
-       int err, err2;
+       int err;
 
        err = read_body_to_string(a, tar, &(tar->pax_global), h);
-       err2 = tar_read_header(a, tar, entry);
-       return (err_combine(err, err2));
+       if (err != ARCHIVE_OK)
+               return (err);
+       err = tar_read_header(a, tar, entry);
+       return (err);
 }
 
 static int
@@ -997,10 +1108,14 @@ header_pax_extensions(struct archive_read *a, struct tar *tar,
 {
        int err, err2;
 
-       read_body_to_string(a, tar, &(tar->pax_header), h);
+       err = read_body_to_string(a, tar, &(tar->pax_header), h);
+       if (err != ARCHIVE_OK)
+               return (err);
 
        /* Parse the next header. */
        err = tar_read_header(a, tar, entry);
+       if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN))
+               return (err);
 
        /*
         * TODO: Parse global/default options into 'entry' struct here
@@ -1014,7 +1129,6 @@ header_pax_extensions(struct archive_read *a, struct tar *tar,
         */
        err2 = pax_header(a, tar, entry, tar->pax_header.s);
        err =  err_combine(err, err2);
-       tar->entry_bytes_remaining = archive_entry_size(entry);
        tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
        return (err);
 }
@@ -1065,7 +1179,6 @@ header_ustar(struct archive_read *a, struct tar *tar,
                    tar_atol(header->rdevminor, sizeof(header->rdevminor)));
        }
 
-       tar->entry_bytes_remaining = archive_entry_size(entry);
        tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
 
        return (0);
@@ -1099,8 +1212,11 @@ pax_header(struct archive_read *a, struct tar *tar,
                                l--;
                                break;
                        }
-                       if (*p < '0' || *p > '9')
-                               return (-1);
+                       if (*p < '0' || *p > '9') {
+                               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                                   "Ignoring malformed pax extended attributes");
+                               return (ARCHIVE_WARN);
+                       }
                        line_length *= 10;
                        line_length += *p - '0';
                        if (line_length > 999999) {
@@ -1112,8 +1228,19 @@ pax_header(struct archive_read *a, struct tar *tar,
                        l--;
                }
 
-               if (line_length > attr_length)
-                       return (0);
+               /*
+                * Parsed length must be no bigger than available data,
+                * at least 1, and the last character of the line must
+                * be '\n'.
+                */
+               if (line_length > attr_length
+                   || line_length < 1
+                   || attr[line_length - 1] != '\n')
+               {
+                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                           "Ignoring malformed pax extended attribute");
+                       return (ARCHIVE_WARN);
+               }
 
                /* Ensure pax_entry buffer is big enough. */
                if (tar->pax_entry_length <= line_length) {
@@ -1160,7 +1287,7 @@ pax_header(struct archive_read *a, struct tar *tar,
                value = wp + 1;
 
                /* Identify this attribute and set it in the entry. */
-               err2 = pax_attribute(entry, key, value);
+               err2 = pax_attribute(tar, entry, key, value);
                err = err_combine(err, err2);
 
                /* Skip to next line */
@@ -1215,19 +1342,72 @@ pax_attribute_xattr(struct archive_entry *entry,
  * extensions should always have keywords of the form "VENDOR.attribute"
  * In particular, it's quite feasible to support many different
  * vendor extensions here.  I'm using "LIBARCHIVE" for extensions
- * unique to this library (currently, there are none).
+ * unique to this library.
  *
- * Investigate other vendor-specific extensions, as well and see if
+ * Investigate other vendor-specific extensions and see if
  * any of them look useful.
  */
 static int
-pax_attribute(struct archive_entry *entry,
+pax_attribute(struct tar *tar, struct archive_entry *entry,
     wchar_t *key, wchar_t *value)
 {
        int64_t s;
        long n;
 
        switch (key[0]) {
+       case 'G':
+               /* GNU "0.0" sparse pax format. */
+               if (wcscmp(key, L"GNU.sparse.numblocks") == 0) {
+                       tar->sparse_offset = -1;
+                       tar->sparse_numbytes = -1;
+                       tar->sparse_gnu_major = 0;
+                       tar->sparse_gnu_minor = 0;
+               }
+               if (wcscmp(key, L"GNU.sparse.offset") == 0) {
+                       tar->sparse_offset = tar_atol10(value, wcslen(value));
+                       if (tar->sparse_numbytes != -1) {
+                               gnu_add_sparse_entry(tar,
+                                   tar->sparse_offset, tar->sparse_numbytes);
+                               tar->sparse_offset = -1;
+                               tar->sparse_numbytes = -1;
+                       }
+               }
+               if (wcscmp(key, L"GNU.sparse.numbytes") == 0) {
+                       tar->sparse_numbytes = tar_atol10(value, wcslen(value));
+                       if (tar->sparse_numbytes != -1) {
+                               gnu_add_sparse_entry(tar,
+                                   tar->sparse_offset, tar->sparse_numbytes);
+                               tar->sparse_offset = -1;
+                               tar->sparse_numbytes = -1;
+                       }
+               }
+               if (wcscmp(key, L"GNU.sparse.size") == 0)
+                       archive_entry_set_size(entry,
+                           tar_atol10(value, wcslen(value)));
+
+               /* GNU "0.1" sparse pax format. */
+               if (wcscmp(key, L"GNU.sparse.map") == 0) {
+                       tar->sparse_gnu_major = 0;
+                       tar->sparse_gnu_minor = 1;
+                       if (gnu_sparse_01_parse(tar, value) != ARCHIVE_OK)
+                               return (ARCHIVE_WARN);
+               }
+
+               /* GNU "1.0" sparse pax format */
+               if (wcscmp(key, L"GNU.sparse.major") == 0) {
+                       tar->sparse_gnu_major = tar_atol10(value, wcslen(value));
+                       tar->sparse_gnu_pending = 1;
+               }
+               if (wcscmp(key, L"GNU.sparse.minor") == 0) {
+                       tar->sparse_gnu_minor = tar_atol10(value, wcslen(value));
+                       tar->sparse_gnu_pending = 1;
+               }
+               if (wcscmp(key, L"GNU.sparse.name") == 0)
+                       archive_entry_copy_pathname_w(entry, value);
+               if (wcscmp(key, L"GNU.sparse.realsize") == 0)
+                       archive_entry_set_size(entry,
+                           tar_atol10(value, wcslen(value)));
+               break;
        case 'L':
                /* Our extensions */
 /* TODO: Handle arbitrary extended attributes... */
@@ -1306,8 +1486,12 @@ pax_attribute(struct archive_entry *entry,
        case 's':
                /* POSIX has reserved 'security.*' */
                /* Someday: if (wcscmp(key, L"security.acl")==0) { ... } */
-               if (wcscmp(key, L"size")==0)
-                       archive_entry_set_size(entry, tar_atol10(value, wcslen(value)));
+               if (wcscmp(key, L"size")==0) {
+                       tar->entry_bytes_remaining = tar_atol10(value, wcslen(value));
+                       archive_entry_set_size(entry, tar->entry_bytes_remaining);
+               }
+               tar->entry_bytes_remaining = 0;
+
                break;
        case 'u':
                if (wcscmp(key, L"uid")==0)
@@ -1418,7 +1602,6 @@ header_gnutar(struct archive_read *a, struct tar *tar,
        } else
                archive_entry_set_rdev(entry, 0);
 
-       tar->entry_bytes_remaining = archive_entry_size(entry);
        tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
 
        /* Grab GNU-specific fields. */
@@ -1432,7 +1615,7 @@ header_gnutar(struct archive_read *a, struct tar *tar,
        }
 
        if (header->sparse[0].offset[0] != 0) {
-               gnu_read_sparse_data(a, tar, header);
+               gnu_sparse_old_read(a, tar, header);
        } else {
                if (header->isextended[0] != 0) {
                        /* XXX WTF? XXX */
@@ -1442,8 +1625,38 @@ header_gnutar(struct archive_read *a, struct tar *tar,
        return (0);
 }
 
+static void
+gnu_add_sparse_entry(struct tar *tar, off_t offset, off_t remaining)
+{
+       struct sparse_block *p;
+
+       p = (struct sparse_block *)malloc(sizeof(*p));
+       if (p == NULL)
+               __archive_errx(1, "Out of memory");
+       memset(p, 0, sizeof(*p));
+       if (tar->sparse_last != NULL)
+               tar->sparse_last->next = p;
+       else
+               tar->sparse_list = p;
+       tar->sparse_last = p;
+       p->offset = offset;
+       p->remaining = remaining;
+}
+
+/*
+ * GNU tar old-format sparse data.
+ *
+ * GNU old-format sparse data is stored in a fixed-field
+ * format.  Offset/size values are 11-byte octal fields (same
+ * format as 'size' field in ustart header).  These are
+ * stored in the header, allocating subsequent header blocks
+ * as needed.  Extending the header in this way is a pretty
+ * severe POSIX violation; this design has earned GNU tar a
+ * lot of criticism.
+ */
+
 static int
-gnu_read_sparse_data(struct archive_read *a, struct tar *tar,
+gnu_sparse_old_read(struct archive_read *a, struct tar *tar,
     const struct archive_entry_header_gnutar *header)
 {
        ssize_t bytes_read;
@@ -1455,7 +1668,7 @@ gnu_read_sparse_data(struct archive_read *a, struct tar *tar,
        };
        const struct extended *ext;
 
-       gnu_parse_sparse_data(a, tar, header->sparse, 4);
+       gnu_sparse_old_parse(tar, header->sparse, 4);
        if (header->isextended[0] == 0)
                return (ARCHIVE_OK);
 
@@ -1471,7 +1684,7 @@ gnu_read_sparse_data(struct archive_read *a, struct tar *tar,
                }
                (a->decompressor->consume)(a, 512);
                ext = (const struct extended *)data;
-               gnu_parse_sparse_data(a, tar, ext->sparse, 21);
+               gnu_sparse_old_parse(tar, ext->sparse, 21);
        } while (ext->isextended[0] != 0);
        if (tar->sparse_list != NULL)
                tar->entry_offset = tar->sparse_list->offset;
@@ -1479,34 +1692,165 @@ gnu_read_sparse_data(struct archive_read *a, struct tar *tar,
 }
 
 static void
-gnu_parse_sparse_data(struct archive_read *a, struct tar *tar,
+gnu_sparse_old_parse(struct tar *tar,
     const struct gnu_sparse *sparse, int length)
 {
-       struct sparse_block *last;
-       struct sparse_block *p;
+       while (length > 0 && sparse->offset[0] != 0) {
+               gnu_add_sparse_entry(tar,
+                   tar_atol(sparse->offset, sizeof(sparse->offset)),
+                   tar_atol(sparse->numbytes, sizeof(sparse->numbytes)));
+               sparse++;
+               length--;
+       }
+}
 
-       (void)a; /* UNUSED */
+/*
+ * GNU tar sparse format 0.0
+ *
+ * Beginning with GNU tar 1.15, sparse files are stored using
+ * information in the pax extended header.  The GNU tar maintainers
+ * have gone through a number of variations in the process of working
+ * out this scheme; furtunately, they're all numbered.
+ *
+ * Sparse format 0.0 uses attribute GNU.sparse.numblocks to store the
+ * number of blocks, and GNU.sparse.offset/GNU.sparse.numbytes to
+ * store offset/size for each block.  The repeated instances of these
+ * latter fields violate the pax specification (which frowns on
+ * duplicate keys), so this format was quickly replaced.
+ */
 
-       last = tar->sparse_list;
-       while (last != NULL && last->next != NULL)
-               last = last->next;
+/*
+ * GNU tar sparse format 0.1
+ *
+ * This version replaced the offset/numbytes attributes with
+ * a single "map" attribute that stored a list of integers.  This
+ * format had two problems: First, the "map" attribute could be very
+ * long, which caused problems for some implementations.  More
+ * importantly, the sparse data was lost when extracted by archivers
+ * that didn't recognize this extension.
+ */
 
-       while (length > 0 && sparse->offset[0] != 0) {
-               p = (struct sparse_block *)malloc(sizeof(*p));
-               if (p == NULL)
-                       __archive_errx(1, "Out of memory");
-               memset(p, 0, sizeof(*p));
-               if (last != NULL)
-                       last->next = p;
+static int
+gnu_sparse_01_parse(struct tar *tar, const wchar_t *p)
+{
+       const wchar_t *e;
+       off_t offset = -1, size = -1;
+
+       for (;;) {
+               e = p;
+               while (*e != '\0' && *e != ',') {
+                       if (*e < '0' || *e > '9')
+                               return (ARCHIVE_WARN);
+                       e++;
+               }
+               if (offset < 0) {
+                       offset = tar_atol10(p, e - p);
+                       if (offset < 0)
+                               return (ARCHIVE_WARN);
+               } else {
+                       size = tar_atol10(p, e - p);
+                       if (size < 0)
+                               return (ARCHIVE_WARN);
+                       gnu_add_sparse_entry(tar, offset, size);
+                       offset = -1;
+               }
+               if (*e == '\0')
+                       return (ARCHIVE_OK);
+               p = e + 1;
+       }
+}
+
+/*
+ * GNU tar sparse format 1.0
+ *
+ * The idea: The offset/size data is stored as a series of base-10
+ * ASCII numbers prepended to the file data, so that dearchivers that
+ * don't support this format will extract the block map along with the
+ * data and a separate post-process can restore the sparseness.
+ *
+ * Unfortunately, GNU tar 1.16 adds bogus padding to the end of the
+ * entry that depends on the size of the map; this means we have to
+ * parse the sparse map when we read the header (otherwise, entry_skip
+ * will fail).  This is why sparse_10_read is called from read_header
+ * above, instead of at the beginning of read_data, where it "should"
+ * go.
+ *
+ * This variant also replaced GNU.sparse.size with GNU.sparse.realsize
+ * and introduced the GNU.sparse.major/GNU.sparse.minor attributes.
+ */
+
+/*
+ * Read the next line from the input, and parse it as a decimal
+ * integer followed by '\n'.  Returns positive integer value or
+ * negative on error.
+ */
+static int64_t
+gnu_sparse_10_atol(struct archive_read *a, struct tar *tar,
+    ssize_t *total_read)
+{
+       int64_t l, limit, last_digit_limit;
+       const char *p;
+       ssize_t bytes_read;
+       int base, digit;
+
+       base = 10;
+       limit = INT64_MAX / base;
+       last_digit_limit = INT64_MAX % base;
+
+       bytes_read = readline(a, tar, &p);
+       if (bytes_read <= 0)
+               return (ARCHIVE_FATAL);
+       *total_read += bytes_read;
+
+       l = 0;
+       while (bytes_read > 0) {
+               if (*p == '\n')
+                       return (l);
+               if (*p < '0' || *p >= '0' + base)
+                       return (ARCHIVE_WARN);
+               digit = *p - '0';
+               if (l > limit || (l == limit && digit > last_digit_limit))
+                       l = UINT64_MAX; /* Truncate on overflow. */
                else
-                       tar->sparse_list = p;
-               last = p;
-               p->offset = tar_atol(sparse->offset, sizeof(sparse->offset));
-               p->remaining =
-                   tar_atol(sparse->numbytes, sizeof(sparse->numbytes));
-               sparse++;
-               length--;
+                       l = (l * base) + digit;
+               p++;
+               bytes_read--;
+       }
+       /* TODO: Error message. */
+       return (ARCHIVE_WARN);
+}
+
+/*
+ * Returns number of bytes consumed to read the sparse block data.
+ */
+static ssize_t
+gnu_sparse_10_read(struct archive_read *a, struct tar *tar)
+{
+       ssize_t bytes_read = 0;
+       int entries;
+       off_t offset, size, to_skip;
+
+       /* Parse entries. */
+       entries = gnu_sparse_10_atol(a, tar, &bytes_read);
+       if (entries < 0)
+               return (ARCHIVE_FATAL);
+       /* Parse the individual entries. */
+       while (entries-- > 0) {
+               /* Parse offset/size */
+               offset = gnu_sparse_10_atol(a, tar, &bytes_read);
+               if (offset < 0)
+                       return (ARCHIVE_FATAL);
+               size = gnu_sparse_10_atol(a, tar, &bytes_read);
+               if (size < 0)
+                       return (ARCHIVE_FATAL);
+               /* Add a new sparse entry. */
+               gnu_add_sparse_entry(tar, offset, size);
        }
+       /* Skip rest of block... */
+       to_skip = 0x1ff & -bytes_read;
+       if (to_skip != (a->decompressor->skip)(a, to_skip))
+               return (ARCHIVE_FATAL);
+       return (bytes_read + to_skip);
 }
 
 /*-
@@ -1574,7 +1918,6 @@ tar_atol8(const char *p, unsigned char_cnt)
        return (sign < 0) ? -l : l;
 }
 
-
 /*
  * Note that this implementation does not (and should not!) obey
  * locale settings; you cannot simply substitute strtol here, since
@@ -1647,6 +1990,57 @@ tar_atol256(const char *_p, unsigned char_cnt)
        return (l);
 }
 
+/*
+ * Returns length of line (including trailing newline)
+ * or negative on error.  'start' argument is updated to
+ * point to first character of line.  This avoids copying
+ * when possible.
+ */
+static ssize_t
+readline(struct archive_read *a, struct tar *tar, const char **start)
+{
+       ssize_t bytes_read;
+       ssize_t total_size = 0;
+       const void *t;
+       const char *s;
+       void *p;
+
+       bytes_read = (a->decompressor->read_ahead)(a, &t, 1);
+       if (bytes_read <= 0)
+               return (ARCHIVE_FATAL);
+       s = t;  /* Start of line? */
+       p = memchr(t, '\n', bytes_read);
+       /* If we found '\n' in the read buffer, return pointer to that. */
+       if (p != NULL) {
+               bytes_read = 1 + ((const char *)p) - s;
+               (a->decompressor->consume)(a, bytes_read);
+               *start = s;
+               return (bytes_read);
+       }
+       /* Otherwise, we need to accumulate in a line buffer. */
+       for (;;) {
+               archive_string_ensure(&tar->line, total_size + bytes_read);
+               memcpy(tar->line.s + total_size, t, bytes_read);
+               (a->decompressor->consume)(a, bytes_read);
+               total_size += bytes_read;
+               /* If we found '\n', clean up and return. */
+               if (p != NULL) {
+                       *start = tar->line.s;
+                       return (total_size);
+               }
+               /* Read some more. */
+               bytes_read = (a->decompressor->read_ahead)(a, &t, 1);
+               if (bytes_read <= 0)
+                       return (ARCHIVE_FATAL);
+               s = t;  /* Start of line? */
+               p = memchr(t, '\n', bytes_read);
+               /* If we found '\n', trim the read. */
+               if (p != NULL) {
+                       bytes_read = 1 + ((const char *)p) - s;
+               }
+       }
+}
+
 static int
 utf8_decode(wchar_t *dest, const char *src, size_t length)
 {
index 25ec437..651e8dd 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_zip.c,v 1.12 2007/04/15 00:53:38 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_zip.c,v 1.13 2007/05/29 01:00:19 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
index e104145..eb26a74 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_string.c,v 1.9 2007/01/13 03:30:14 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_string.c,v 1.10 2007/05/29 01:00:19 kientzle Exp $");
 
 /*
  * Basic resizable string support, to simplify manipulating arbitrary-sized
index 749f591..596db9a 100644 (file)
@@ -22,7 +22,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/lib/libarchive/archive_string.h,v 1.8 2007/01/09 08:05:55 kientzle Exp $
+ * $FreeBSD: src/lib/libarchive/archive_string.h,v 1.9 2007/05/29 01:00:19 kientzle Exp $
  *
  */
 
index 1d8a356..b8a030e 100644 (file)
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: src/lib/libarchive/archive_util.3,v 1.6 2007/03/03 07:37:36 kientzle Exp $
+.\" $FreeBSD: src/lib/libarchive/archive_util.3,v 1.7 2007/05/29 01:00:19 kientzle Exp $
 .\"
 .Dd January 8, 2005
 .Dt archive_util 3
index 63bd5ae..d733663 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_util.c,v 1.13 2007/03/03 07:37:36 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_util.c,v 1.15 2007/07/06 15:36:38 kientzle Exp $");
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
@@ -51,6 +51,12 @@ archive_api_version(void)
        return (ARCHIVE_API_VERSION);
 }
 
+int
+archive_version_stamp(void)
+{
+       return (ARCHIVE_VERSION_STAMP);
+}
+
 const char *
 archive_version(void)
 {
index 07c26a0..c07b6b5 100644 (file)
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: src/lib/libarchive/archive_write.3,v 1.21 2007/03/03 07:37:36 kientzle Exp $
+.\" $FreeBSD: src/lib/libarchive/archive_write.3,v 1.22 2007/05/29 01:00:19 kientzle Exp $
 .\"
 .Dd August 19, 2006
 .Dt archive_write 3
index 77e410b..2977063 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_write.c,v 1.25 2007/03/11 10:29:52 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_write.c,v 1.26 2007/05/29 01:00:19 kientzle Exp $");
 
 /*
  * This file contains the "essential" portions of the write API, that
index ac2bcbd..691dfe4 100644 (file)
@@ -25,7 +25,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_disk.c,v 1.11 2007/05/21 04:22:38 cperciva Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_disk.c,v 1.12 2007/05/29 01:00:19 kientzle Exp $");
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
index 4448b3e..427b876 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_disk_set_standard_lookup.c,v 1.2 2007/04/20 15:32:13 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_disk_set_standard_lookup.c,v 1.4 2007/05/29 01:00:19 kientzle Exp $");
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
index 083b6ca..82935f4 100644 (file)
@@ -22,7 +22,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/lib/libarchive/archive_write_private.h,v 1.1 2007/03/03 07:37:36 kientzle Exp $
+ * $FreeBSD: src/lib/libarchive/archive_write_private.h,v 1.2 2007/05/29 01:00:19 kientzle Exp $
  */
 
 #ifndef ARCHIVE_WRITE_PRIVATE_H_INCLUDED
index 43e1d08..0883ea1 100644 (file)
@@ -28,7 +28,7 @@
 /* Don't compile this if we don't have bzlib. */
 #if HAVE_BZLIB_H
 
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_compression_bzip2.c,v 1.11 2007/03/03 07:37:36 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_compression_bzip2.c,v 1.12 2007/05/29 01:00:19 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
index 6e74048..56a0a11 100644 (file)
@@ -28,7 +28,7 @@
 /* Don't compile this if we don't have zlib. */
 #if HAVE_ZLIB_H
 
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_compression_gzip.c,v 1.13 2007/03/03 07:37:36 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_compression_gzip.c,v 1.14 2007/05/29 01:00:19 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
index 7b254a8..0ad962a 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_compression_none.c,v 1.14 2007/04/15 04:42:52 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_compression_none.c,v 1.15 2007/05/29 01:00:19 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
index 4f28a0f..fc1481d 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "archive_platform.h"
 
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_compression_program.c,v 1.1 2007/05/29 01:00:19 kientzle Exp $");
 
 #ifdef HAVE_SYS_WAIT_H
 #  include <sys/wait.h>
index b04bef7..e5f8921 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format.c,v 1.4 2007/01/09 08:05:56 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format.c,v 1.5 2007/06/22 05:47:00 kientzle Exp $");
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
@@ -42,6 +42,7 @@ static
 struct { int code; int (*setter)(struct archive *); } codes[] =
 {
        { ARCHIVE_FORMAT_CPIO,          archive_write_set_format_cpio },
+       { ARCHIVE_FORMAT_CPIO_SVR4_NOCRC,       archive_write_set_format_cpio_newc },
        { ARCHIVE_FORMAT_CPIO_POSIX,    archive_write_set_format_cpio },
        { ARCHIVE_FORMAT_SHAR,          archive_write_set_format_shar },
        { ARCHIVE_FORMAT_SHAR_BASE,     archive_write_set_format_shar },
index 52af5f9..bf3ea4d 100644 (file)
@@ -26,7 +26,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_ar.c,v 1.2 2007/04/14 22:34:10 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_ar.c,v 1.3 2007/05/29 01:00:19 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
index 1759a8f..0d7cae4 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_by_name.c,v 1.6 2007/04/14 22:34:10 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_by_name.c,v 1.7 2007/06/22 05:47:00 kientzle Exp $");
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
@@ -49,6 +49,8 @@ struct { const char *name; int (*setter)(struct archive *); } names[] =
        { "argnu",      archive_write_set_format_ar_svr4 },
        { "arsvr4",     archive_write_set_format_ar_svr4 },
        { "cpio",       archive_write_set_format_cpio },
+       { "newc",       archive_write_set_format_cpio_newc },
+       { "odc",        archive_write_set_format_cpio },
        { "pax",        archive_write_set_format_pax },
        { "posix",      archive_write_set_format_pax },
        { "shar",       archive_write_set_format_shar },
index a713bfe..6459477 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio.c,v 1.10 2007/03/03 07:37:36 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio.c,v 1.11 2007/05/29 01:00:19 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2006 Rudolf Marek SYSGO s.r.o.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -24,7 +25,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio.c,v 1.10 2007/03/03 07:37:36 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio_newc.c,v 1.1 2007/06/22 05:47:00 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
@@ -42,39 +43,43 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio.c,v 1.10 20
 #include "archive_private.h"
 #include "archive_write_private.h"
 
-static ssize_t archive_write_cpio_data(struct archive_write *,
+static ssize_t archive_write_newc_data(struct archive_write *,
                    const void *buff, size_t s);
-static int     archive_write_cpio_finish(struct archive_write *);
-static int     archive_write_cpio_destroy(struct archive_write *);
-static int     archive_write_cpio_finish_entry(struct archive_write *);
-static int     archive_write_cpio_header(struct archive_write *,
+static int     archive_write_newc_finish(struct archive_write *);
+static int     archive_write_newc_destroy(struct archive_write *);
+static int     archive_write_newc_finish_entry(struct archive_write *);
+static int     archive_write_newc_header(struct archive_write *,
                    struct archive_entry *);
-static int     format_octal(int64_t, void *, int);
-static int64_t format_octal_recursive(int64_t, char *, int);
+static int     format_hex(int64_t, void *, int);
+static int64_t format_hex_recursive(int64_t, char *, int);
 
 struct cpio {
        uint64_t          entry_bytes_remaining;
+       int               padding;
 };
 
-struct cpio_header {
+struct cpio_header_newc {
        char    c_magic[6];
-       char    c_dev[6];
-       char    c_ino[6];
-       char    c_mode[6];
-       char    c_uid[6];
-       char    c_gid[6];
-       char    c_nlink[6];
-       char    c_rdev[6];
-       char    c_mtime[11];
-       char    c_namesize[6];
-       char    c_filesize[11];
+       char    c_ino[8];
+       char    c_mode[8];
+       char    c_uid[8];
+       char    c_gid[8];
+       char    c_nlink[8];
+       char    c_mtime[8];
+       char    c_filesize[8];
+       char    c_devmajor[8];
+       char    c_devminor[8];
+       char    c_rdevmajor[8];
+       char    c_rdevminor[8];
+       char    c_namesize[8];
+       char    c_checksum[8];
 };
 
 /*
  * Set output format to 'cpio' format.
  */
 int
-archive_write_set_format_cpio(struct archive *_a)
+archive_write_set_format_cpio_newc(struct archive *_a)
 {
        struct archive_write *a = (struct archive_write *)_a;
        struct cpio *cpio;
@@ -92,23 +97,24 @@ archive_write_set_format_cpio(struct archive *_a)
        a->format_data = cpio;
 
        a->pad_uncompressed = 1;
-       a->format_write_header = archive_write_cpio_header;
-       a->format_write_data = archive_write_cpio_data;
-       a->format_finish_entry = archive_write_cpio_finish_entry;
-       a->format_finish = archive_write_cpio_finish;
-       a->format_destroy = archive_write_cpio_destroy;
-       a->archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
-       a->archive_format_name = "POSIX cpio";
+       a->format_write_header = archive_write_newc_header;
+       a->format_write_data = archive_write_newc_data;
+       a->format_finish_entry = archive_write_newc_finish_entry;
+       a->format_finish = archive_write_newc_finish;
+       a->format_destroy = archive_write_newc_destroy;
+       a->archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC;
+       a->archive_format_name = "SVR4 cpio nocrc";
        return (ARCHIVE_OK);
 }
 
 static int
-archive_write_cpio_header(struct archive_write *a, struct archive_entry *entry)
+archive_write_newc_header(struct archive_write *a, struct archive_entry *entry)
 {
        struct cpio *cpio;
        const char *p, *path;
        int pathlength, ret;
-       struct cpio_header       h;
+       struct cpio_header_newc  h;
+       int pad;
 
        cpio = (struct cpio *)a->format_data;
        ret = 0;
@@ -117,48 +123,54 @@ archive_write_cpio_header(struct archive_write *a, struct archive_entry *entry)
        pathlength = strlen(path) + 1; /* Include trailing null. */
 
        memset(&h, 0, sizeof(h));
-       format_octal(070707, &h.c_magic, sizeof(h.c_magic));
-       format_octal(archive_entry_dev(entry), &h.c_dev, sizeof(h.c_dev));
-       /*
-        * TODO: Generate artificial inode numbers rather than just
-        * re-using the ones off the disk.  That way, the 18-bit c_ino
-        * field only limits the number of files in the archive.
-        */
-       if (archive_entry_ino(entry) > 0777777) {
+       format_hex(0x070701, &h.c_magic, sizeof(h.c_magic));
+       format_hex(archive_entry_devmajor(entry), &h.c_devmajor, sizeof(h.c_devmajor));
+       format_hex(archive_entry_devminor(entry), &h.c_devminor, sizeof(h.c_devminor));
+       if (archive_entry_ino(entry) > 0xffffffff) {
                archive_set_error(&a->archive, ERANGE, "large inode number truncated");
                ret = ARCHIVE_WARN;
        }
 
-       format_octal(archive_entry_ino(entry) & 0777777, &h.c_ino, sizeof(h.c_ino));
-       format_octal(archive_entry_mode(entry), &h.c_mode, sizeof(h.c_mode));
-       format_octal(archive_entry_uid(entry), &h.c_uid, sizeof(h.c_uid));
-       format_octal(archive_entry_gid(entry), &h.c_gid, sizeof(h.c_gid));
-       format_octal(archive_entry_nlink(entry), &h.c_nlink, sizeof(h.c_nlink));
+       format_hex(archive_entry_ino(entry) & 0xffffffff, &h.c_ino, sizeof(h.c_ino));
+       format_hex(archive_entry_mode(entry), &h.c_mode, sizeof(h.c_mode));
+       format_hex(archive_entry_uid(entry), &h.c_uid, sizeof(h.c_uid));
+       format_hex(archive_entry_gid(entry), &h.c_gid, sizeof(h.c_gid));
+       format_hex(archive_entry_nlink(entry), &h.c_nlink, sizeof(h.c_nlink));
        if (archive_entry_filetype(entry) == AE_IFBLK
-           || archive_entry_filetype(entry) == AE_IFCHR)
-           format_octal(archive_entry_dev(entry), &h.c_rdev, sizeof(h.c_rdev));
-       else
-           format_octal(0, &h.c_rdev, sizeof(h.c_rdev));
-       format_octal(archive_entry_mtime(entry), &h.c_mtime, sizeof(h.c_mtime));
-       format_octal(pathlength, &h.c_namesize, sizeof(h.c_namesize));
+           || archive_entry_filetype(entry) == AE_IFCHR) {
+           format_hex(archive_entry_rdevmajor(entry), &h.c_rdevmajor, sizeof(h.c_rdevmajor));
+           format_hex(archive_entry_rdevminor(entry), &h.c_rdevminor, sizeof(h.c_rdevminor));
+       } else {
+           format_hex(0, &h.c_rdevmajor, sizeof(h.c_rdevmajor));
+           format_hex(0, &h.c_rdevminor, sizeof(h.c_rdevminor));
+       }
+       format_hex(archive_entry_mtime(entry), &h.c_mtime, sizeof(h.c_mtime));
+       format_hex(pathlength, &h.c_namesize, sizeof(h.c_namesize));
+       format_hex(0, &h.c_checksum, sizeof(h.c_checksum));
 
        /* Symlinks get the link written as the body of the entry. */
        p = archive_entry_symlink(entry);
        if (p != NULL  &&  *p != '\0')
-               format_octal(strlen(p), &h.c_filesize, sizeof(h.c_filesize));
+               format_hex(strlen(p), &h.c_filesize, sizeof(h.c_filesize));
        else
-               format_octal(archive_entry_size(entry), &h.c_filesize, sizeof(h.c_filesize));
+               format_hex(archive_entry_size(entry), &h.c_filesize, sizeof(h.c_filesize));
 
        ret = (a->compressor.write)(a, &h, sizeof(h));
        if (ret != ARCHIVE_OK)
                return (ARCHIVE_FATAL);
 
+       /* Pad pathname to even length. */
        ret = (a->compressor.write)(a, path, pathlength);
        if (ret != ARCHIVE_OK)
                return (ARCHIVE_FATAL);
+       pad = 0x3 & - (pathlength + sizeof(struct cpio_header_newc));
+       if (pad)
+               ret = (a->compressor.write)(a, "\0\0\0", pad);
+       if (ret != ARCHIVE_OK)
+               return (ARCHIVE_FATAL);
 
        cpio->entry_bytes_remaining = archive_entry_size(entry);
-
+       cpio->padding = 3 & (-cpio->entry_bytes_remaining);
        /* Write the symlink now. */
        if (p != NULL  &&  *p != '\0')
                ret = (a->compressor.write)(a, p, strlen(p));
@@ -167,7 +179,7 @@ archive_write_cpio_header(struct archive_write *a, struct archive_entry *entry)
 }
 
 static ssize_t
-archive_write_cpio_data(struct archive_write *a, const void *buff, size_t s)
+archive_write_newc_data(struct archive_write *a, const void *buff, size_t s)
 {
        struct cpio *cpio;
        int ret;
@@ -188,34 +200,34 @@ archive_write_cpio_data(struct archive_write *a, const void *buff, size_t s)
  * Format a number into the specified field.
  */
 static int
-format_octal(int64_t v, void *p, int digits)
+format_hex(int64_t v, void *p, int digits)
 {
        int64_t max;
        int     ret;
 
-       max = (((int64_t)1) << (digits * 3)) - 1;
+       max = (((int64_t)1) << (digits * 4)) - 1;
        if (v >= 0  &&  v <= max) {
-           format_octal_recursive(v, (char *)p, digits);
+           format_hex_recursive(v, (char *)p, digits);
            ret = 0;
        } else {
-           format_octal_recursive(max, (char *)p, digits);
+           format_hex_recursive(max, (char *)p, digits);
            ret = -1;
        }
        return (ret);
 }
 
 static int64_t
-format_octal_recursive(int64_t v, char *p, int s)
+format_hex_recursive(int64_t v, char *p, int s)
 {
        if (s == 0)
                return (v);
-       v = format_octal_recursive(v, p+1, s-1);
-       *p = '0' + (v & 7);
-       return (v >>= 3);
+       v = format_hex_recursive(v, p+1, s-1);
+       *p = "0123456789abcdef"[v & 0xf];
+       return (v >>= 4);
 }
 
 static int
-archive_write_cpio_finish(struct archive_write *a)
+archive_write_newc_finish(struct archive_write *a)
 {
        struct cpio *cpio;
        int er;
@@ -225,13 +237,13 @@ archive_write_cpio_finish(struct archive_write *a)
        trailer = archive_entry_new();
        archive_entry_set_nlink(trailer, 1);
        archive_entry_set_pathname(trailer, "TRAILER!!!");
-       er = archive_write_cpio_header(a, trailer);
+       er = archive_write_newc_header(a, trailer);
        archive_entry_free(trailer);
        return (er);
 }
 
 static int
-archive_write_cpio_destroy(struct archive_write *a)
+archive_write_newc_destroy(struct archive_write *a)
 {
        struct cpio *cpio;
 
@@ -242,7 +254,7 @@ archive_write_cpio_destroy(struct archive_write *a)
 }
 
 static int
-archive_write_cpio_finish_entry(struct archive_write *a)
+archive_write_newc_finish_entry(struct archive_write *a)
 {
        struct cpio *cpio;
        int to_write, ret;
@@ -257,5 +269,6 @@ archive_write_cpio_finish_entry(struct archive_write *a)
                        return (ret);
                cpio->entry_bytes_remaining -= to_write;
        }
+       ret = (a->compressor.write)(a, a->nulls, cpio->padding);
        return (ret);
 }
index 9a3f7d9..471feb8 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_pax.c,v 1.39 2007/03/03 07:37:36 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_pax.c,v 1.41 2007/05/29 01:00:19 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
index f99c305..f26ba02 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_shar.c,v 1.17 2007/05/19 05:09:09 cperciva Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_shar.c,v 1.18 2007/05/29 01:00:19 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
index 32971b5..61c90d5 100644 (file)
@@ -24,7 +24,8 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_ustar.c,v 1.21 2007/04/02 00:34:36 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_ustar.c,v 1.24 2007/06/11 05:17:30 kientzle Exp $");
+
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
@@ -277,6 +278,16 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512],
        else {
                /* Store in two pieces, splitting at a '/'. */
                p = strchr(pp + strlen(pp) - USTAR_name_size - 1, '/');
+               /*
+                * If the separator we found is the first '/', find
+                * the next one.  (This is a pathological case that
+                * occurs for paths of exactly 101 bytes that start with
+                * '/'; it occurs because the separating '/' is not
+                * stored explicitly and the reconstruction assumes that
+                * an empty prefix means there is no '/' separator.)
+                */
+               if (p == pp)
+                       p = strchr(p + 1, '/');
                /*
                 * If there is no path separator, or the prefix or
                 * remaining name are too large, return an error.
index a7ee48b..ac3f75c 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "archive_platform.h"
 
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: src/lib/libarchive/filter_fork.c,v 1.1 2007/05/29 01:00:20 kientzle Exp $");
 
 #if defined(HAVE_POLL)
 #  if defined(HAVE_POLL_H)
index c4c3c75..685efda 100644 (file)
@@ -21,6 +21,8 @@
  * 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.
+ *
+ * $FreeBSD: src/lib/libarchive/filter_fork.h,v 1.1 2007/05/29 01:00:20 kientzle Exp $
  */
 
 #ifndef FILTER_FORK_H
index c8f79ff..1161f65 100644 (file)
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD$
+.\" $FreeBSD: src/lib/libarchive/libarchive_internals.3,v 1.1 2007/05/29 01:00:20 kientzle Exp $
 .\"
 .Dd April 16, 2007
 .Dt LIBARCHIVE 3
index f2237f0..44b7909 100644 (file)
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: src/usr.bin/tar/bsdtar.1,v 1.33 2007/01/09 08:12:17 kientzle Exp $
+.\" $FreeBSD: src/usr.bin/tar/bsdtar.1,v 1.35 2007/05/29 05:39:10 kientzle Exp $
 .\"
 .Dd April 13, 2004
 .Dt BSDTAR 1
@@ -50,6 +50,9 @@
 .Sh DESCRIPTION
 .Nm
 creates and manipulates streaming archive files.
+This implementation can extract from tar, pax, cpio, zip, jar, ar,
+and ISO 9660 cdrom images and can create tar, pax, cpio, ar,
+and shar archives.
 .Pp
 The first synopsis form shows a
 .Dq bundled
@@ -464,6 +467,9 @@ To extract all entries from the archive on
 the default tape drive:
 .Dl Nm Fl x
 .Pp
+To examine the contents of an ISO 9660 cdrom image:
+.Dl Nm Fl tf Pa image.iso
+.Pp
 To move file hierarchies, invoke
 .Nm
 as