Import libarchive 2.4.0 which brings some performance enhancements.
authorPeter Avalos <pavalos@dragonflybsd.org>
Sat, 3 Nov 2007 20:03:46 +0000 (20:03 +0000)
committerPeter Avalos <pavalos@dragonflybsd.org>
Sat, 3 Nov 2007 20:03:46 +0000 (20:03 +0000)
18 files changed:
contrib/libarchive-2/NEWS
contrib/libarchive-2/README
contrib/libarchive-2/libarchive/archive_platform.h
contrib/libarchive-2/libarchive/archive_read.c
contrib/libarchive-2/libarchive/archive_read_support_compression_none.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_iso9660.c
contrib/libarchive-2/libarchive/archive_read_support_format_mtree.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_write_set_compression_none.c
contrib/libarchive-2/libarchive/archive_write_set_format_cpio.c
contrib/libarchive-2/libarchive/archive_write_set_format_cpio_newc.c
contrib/libarchive-2/libarchive/cpio.5
contrib/libarchive-2/libarchive/libarchive_internals.3
contrib/libarchive-2/tar/bsdtar_platform.h
contrib/libarchive-2/version

index 2714249..d6de374 100644 (file)
@@ -1,4 +1,24 @@
 
+Oct 30, 2007: libarchive 2.4.0 released
+Oct 30, 2007: Minor compile fix thanks to Joerg Schilling.
+Oct 30, 2007: Only run the format auction once at the beginning of the
+       archive.  This is simpler and supports better error recovery.
+Oct 29, 2007: Test support for very large entries in tar archives:
+       libarchive_test now exercises entries from 2GB up to 1TB.
+
+Oct 27, 2007: libarchive 2.3.5 released
+Oct 27, 2007: Correct some unnecessary internal data copying in the
+       "compression none" reader and writer; this reduces user time
+       by up to 2/3 in some tests.  (Thanks to Jan Psota for
+       publishing his performance test results to GNU tar's bug-tar
+       mailing list; those results pointed me towards this problem.)
+Oct 27, 2007: Fix for skipping archive entries that are exactly
+       a multiple of 4G on 32-bit platforms.
+Oct 25, 2007: Fix for reading very large (>8G) tar archives; this was
+       broken when I put in support for new GNU tar sparse formats.
+Oct 20, 2007: Initial work on new pattern-matching code for cpio; I
+       hope this eventually replaces the code currently in bsdtar.
+
 Oct 08, 2007: libarchive 2.3.4 released
 Oct 05, 2007: Continuing work on bsdcpio test suite.
 Oct 05, 2007: New cpio.5 manpage, updates to "History" of bsdcpio.1 and
index bcc4143..3652503 100644 (file)
@@ -5,7 +5,14 @@ This distribution bundle includes the following components:
    * libarchive: a library for reading and writing streaming archives
    * tar: the 'bsdtar' program is a full-featured 'tar'
           replacement built on libarchive
-   * minitar: a compact sample demonstrating use of libarchive
+   * cpio: the 'bsdcpio' program is a different interface to
+          essentially the same functionality
+   * examples: Some small example programs that you may find useful.
+   * examples/minitar: a compact sample demonstrating use of libarchive.
+          I use this for testing link pollution; it should produce a very
+          small executable file on most systems.
+   * contrib:  Various items sent to me by third parties;
+          please contact the authors with any questions.
 
 The top-level directory contains the following information files:
    * NEWS - highlights of recent changes
@@ -25,13 +32,17 @@ The following files in the top-level directory are used by the
 
 Guide to Documentation installed by this system:
  * bsdtar.1 explains the use of the bsdtar program
+ * bsdcpio.1 explains the use of the bsdcpio program
  * libarchive.3 gives an overview of the library as a whole
  * archive_read.3, archive_write.3, and archive_write_disk.3 provide
    detailed calling sequences for the read and write APIs
  * archive_entry.3 details the "struct archive_entry" utility class
+ * archive_internals.3 provides some insight into libarchive's
+   internal structure and operation.
  * libarchive-formats.5 documents the file formats supported by the library
- * tar.5 provides some detailed information about a variety of different
-   "tar" formats.
+ * cpio.5, mtree.5, and tar.5 provide detailed information about a
+   variety of different archive formats, including hard-to-find details
+   about modern cpio and tar variants.
 
 You should also read the copious comments in "archive.h" and the source
 code for the sample "bsdtar" program for more details.  Please let me know
@@ -53,6 +64,7 @@ Currently, the library automatically detects and reads the following:
   * ISO9660 CD-ROM images (with optional Rockridge extensions)
   * ZIP archives (with uncompressed or "deflate" compressed entries)
   * GNU and BSD 'ar' archives
+  * 'mtree' format
 
 The library can write:
   * gzip compression
@@ -62,6 +74,7 @@ The library can write:
   * "restricted" pax format, which will create ustar archives except for
     entries that require pax extensions (for long filenames, ACLs, etc).
   * POSIX octet-oriented cpio
+  * SVR4 "newc" cpio
   * shar archives
   * GNU and BSD 'ar' archives
 
@@ -89,10 +102,9 @@ Notes about the library architecture:
    environments where that matters.
 
  * On read, the library accepts whatever blocks you hand it.
-   Your read callback is free to pass the library a byte at a time
+   Your read callback is free to pass the library a byte at a time[1]
    or mmap the entire archive and give it to the library at once.
-   On write, the library always produces correctly-blocked
-   output.
+   On write, the library always produces correctly-blocked output.
 
  * The object-style approach allows you to have multiple archive streams
    open at once.  bsdtar uses this in its "@archive" extension.
@@ -112,3 +124,11 @@ Notes about the library architecture:
 
  * Note: "pax interchange format" is really an extended tar format,
    despite what the name says.
+
+[1]  Gzip and compress formats are identical in the first byte.
+For that reason, the first block must be at least two bytes if
+you have both of these formats enabled at read time.  This is
+currently the only restriction on block size.  (This restriction
+could be lifted by buffering the initial blocks prior to the
+compression tasting step, but it doesn't really seem worth the
+effort.)
index 70cc037..193a52c 100644 (file)
@@ -57,7 +57,8 @@
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>  /* For __FBSDID */
 #else
-#define        __FBSDID(a)     /* null */
+/* Just leaving this macro replacement empty leads to a dangling semicolon. */
+#define        __FBSDID(a)     struct _undefined_hack
 #endif
 
 /* Try to get standard C99-style integer type definitions. */
index 5433097..7803fd2 100644 (file)
@@ -306,6 +306,18 @@ archive_read_next_header(struct archive *_a, struct archive_entry **entryp)
        archive_entry_clear(entry);
        archive_clear_error(&a->archive);
 
+       /*
+        * If no format has yet been chosen, choose one.
+        */
+       if (a->format == NULL) {
+               slot = choose_format(a);
+               if (slot < 0) {
+                       a->archive.state = ARCHIVE_STATE_FATAL;
+                       return (ARCHIVE_FATAL);
+               }
+               a->format = &(a->formats[slot]);
+       }
+
        /*
         * If client didn't consume entire data, skip any remainder
         * (This is especially important for GNU incremental directories.)
@@ -324,12 +336,6 @@ archive_read_next_header(struct archive *_a, struct archive_entry **entryp)
        /* Record start-of-header. */
        a->header_position = a->archive.file_position;
 
-       slot = choose_format(a);
-       if (slot < 0) {
-               a->archive.state = ARCHIVE_STATE_FATAL;
-               return (ARCHIVE_FATAL);
-       }
-       a->format = &(a->formats[slot]);
        ret = (a->format->read_header)(a, entry);
 
        /*
index 58a5559..1cafd83 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_none.c,v 1.17 2007/05/29 01:00:19 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_none.c,v 1.18 2007/10/27 22:45:40 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
@@ -170,56 +170,45 @@ archive_decompressor_none_read_ahead(struct archive_read *a, const void **buff,
                min = state->buffer_size;
 
        /*
-        * Try to satisfy the request directly from the client
-        * buffer.  We can do this if all of the data in the copy
-        * buffer was copied from the current client buffer.  This
-        * also covers the case where the copy buffer is empty and
-        * the client buffer has all the data we need.
+        * Keep pulling more data until we can satisfy the request.
         */
-       if (state->client_total >= state->client_avail + state->avail
-           && state->client_avail + state->avail >= min) {
-               state->client_avail += state->avail;
-               state->client_next -= state->avail;
-               state->avail = 0;
-               state->next = state->buffer;
-               *buff = state->client_next;
-               return (state->client_avail);
-       }
+       for (;;) {
 
-       /*
-        * If we can't use client buffer, we'll have to use copy buffer.
-        */
+               /*
+                * If we can satisfy from the copy buffer, we're done.
+                */
+               if (state->avail >= min) {
+                       *buff = state->next;
+                       return (state->avail);
+               }
 
-       /* Move data forward in copy buffer if necessary. */
-       if (state->next > state->buffer &&
-           state->next + min > state->buffer + state->buffer_size) {
-               if (state->avail > 0)
-                       memmove(state->buffer, state->next, state->avail);
-               state->next = state->buffer;
-       }
+               /*
+                * We can satisfy directly from client buffer if everything
+                * currently in the copy buffer is still in the client buffer.
+                */
+               if (state->client_total >= state->client_avail + state->avail
+                   && state->client_avail + state->avail >= min) {
+                       /* "Roll back" to client buffer. */
+                       state->client_avail += state->avail;
+                       state->client_next -= state->avail;
+                       /* Copy buffer is now empty. */
+                       state->avail = 0;
+                       state->next = state->buffer;
+                       /* Return data from client buffer. */
+                       *buff = state->client_next;
+                       return (state->client_avail);
+               }
 
-       /* Collect data in copy buffer to fulfill request. */
-       while (state->avail < min) {
-               /* Copy data from client buffer to our copy buffer. */
-               if (state->client_avail > 0) {
-                       /* First estimate: copy to fill rest of buffer. */
-                       size_t tocopy = (state->buffer + state->buffer_size)
-                           - (state->next + state->avail);
-                       /* Don't copy more than is available. */
-                       if (tocopy > state->client_avail)
-                               tocopy = state->client_avail;
-                       memcpy(state->next + state->avail, state->client_next,
-                           tocopy);
-                       state->client_next += tocopy;
-                       state->client_avail -= tocopy;
-                       state->avail += tocopy;
-               } else {
-                       /* There is no more client data: fetch more. */
-                       /*
-                        * It seems to me that const void ** and const
-                        * char ** should be compatible, but they
-                        * aren't, hence the cast.
-                        */
+               /* Move data forward in copy buffer if necessary. */
+               if (state->next > state->buffer &&
+                   state->next + min > state->buffer + state->buffer_size) {
+                       if (state->avail > 0)
+                               memmove(state->buffer, state->next, state->avail);
+                       state->next = state->buffer;
+               }
+
+               /* If we've used up the client data, get more. */
+               if (state->client_avail <= 0) {
                        bytes_read = (a->client_reader)(&a->archive,
                            a->client_data, &state->client_buff);
                        if (bytes_read < 0) {           /* Read error. */
@@ -232,17 +221,33 @@ archive_decompressor_none_read_ahead(struct archive_read *a, const void **buff,
                                state->client_total = state->client_avail = 0;
                                state->client_next = state->client_buff = NULL;
                                state->end_of_file = 1;
-                               break;
+                               /* Return whatever we do have. */
+                               *buff = state->next;
+                               return (state->avail);
                        }
                        a->archive.raw_position += bytes_read;
                        state->client_total = bytes_read;
                        state->client_avail = state->client_total;
                        state->client_next = state->client_buff;
                }
+               else
+               {
+                       /* We can add client data to copy buffer. */
+                       /* First estimate: copy to fill rest of buffer. */
+                       size_t tocopy = (state->buffer + state->buffer_size)
+                           - (state->next + state->avail);
+                       /* Don't copy more than is available. */
+                       if (tocopy > state->client_avail)
+                               tocopy = state->client_avail;
+                       memcpy(state->next + state->avail, state->client_next,
+                           tocopy);
+                       /* Remove this data from client buffer. */
+                       state->client_next += tocopy;
+                       state->client_avail -= tocopy;
+                       /* add it to copy buffer. */
+                       state->avail += tocopy;
+               }
        }
-
-       *buff = state->next;
-       return (state->avail);
 }
 
 /*
@@ -334,7 +339,7 @@ archive_decompressor_none_skip(struct archive_read *a, off_t request)
                const void* dummy_buffer;
                ssize_t bytes_read;
                bytes_read = archive_decompressor_none_read_ahead(a,
-                   &dummy_buffer, request);
+                   &dummy_buffer, 1);
                if (bytes_read < 0)
                        return (bytes_read);
                if (bytes_read == 0) {
index 97ed28a..5fad4ae 100644 (file)
@@ -47,7 +47,6 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_ar.c,v 1.6 20
 #include "archive_read_private.h"
 
 struct ar {
-       int      bid;
        off_t    entry_bytes_remaining;
        off_t    entry_offset;
        off_t    entry_padding;
@@ -103,7 +102,6 @@ archive_read_support_format_ar(struct archive *_a)
                return (ARCHIVE_FATAL);
        }
        memset(ar, 0, sizeof(*ar));
-       ar->bid = -1;
        ar->strtab = NULL;
 
        r = __archive_read_register_format(a,
@@ -148,9 +146,6 @@ archive_read_format_ar_bid(struct archive_read *a)
 
        ar = (struct ar *)(a->format->data);
 
-       if (ar->bid > 0)
-               return (ar->bid);
-
        /*
         * Verify the 8-byte file signature.
         * TODO: Do we need to check more than this?
@@ -159,8 +154,7 @@ archive_read_format_ar_bid(struct archive_read *a)
        if (bytes_read < 8)
                return (-1);
        if (strncmp((const char*)h, "!<arch>\n", 8) == 0) {
-               ar->bid = 64;
-               return (ar->bid);
+               return (64);
        }
        return (-1);
 }
index 7a056b9..1ede8b6 100644 (file)
@@ -118,6 +118,8 @@ static int  archive_read_format_cpio_read_data(struct archive_read *,
 static int     archive_read_format_cpio_read_header(struct archive_read *,
                    struct archive_entry *);
 static int     be4(const unsigned char *);
+static int     find_odc_header(struct archive_read *);
+static int     find_newc_header(struct archive_read *);
 static int     header_bin_be(struct archive_read *, struct cpio *,
                    struct archive_entry *, size_t *, size_t *);
 static int     header_bin_le(struct archive_read *, struct cpio *,
@@ -126,6 +128,8 @@ static int  header_newc(struct archive_read *, struct cpio *,
                    struct archive_entry *, size_t *, size_t *);
 static int     header_odc(struct archive_read *, struct cpio *,
                    struct archive_entry *, size_t *, size_t *);
+static int     is_octal(const char *, size_t);
+static int     is_hex(const char *, size_t);
 static int     le4(const unsigned char *);
 static void    record_hardlink(struct cpio *cpio, struct archive_entry *entry);
 
@@ -161,13 +165,14 @@ archive_read_support_format_cpio(struct archive *_a)
 static int
 archive_read_format_cpio_bid(struct archive_read *a)
 {
-       int bid, bytes_read;
+       int bytes_read;
        const void *h;
        const unsigned char *p;
        struct cpio *cpio;
+       int bid;
 
        cpio = (struct cpio *)(a->format->data);
-       bid = 0;
+
        bytes_read = (a->decompressor->read_ahead)(a, &h, 6);
        /* Convert error code into error return. */
        if (bytes_read < 0)
@@ -176,6 +181,7 @@ archive_read_format_cpio_bid(struct archive_read *a)
                return (-1);
 
        p = (const unsigned char *)h;
+       bid = 0;
        if (memcmp(p, "070707", 6) == 0) {
                /* ASCII cpio archive (odc, POSIX.1) */
                cpio->read_header = header_odc;
@@ -231,7 +237,7 @@ archive_read_format_cpio_read_header(struct archive_read *a,
        cpio = (struct cpio *)(a->format->data);
        r = (cpio->read_header(a, cpio, entry, &namelength, &name_pad));
 
-       if (r != ARCHIVE_OK)
+       if (r < ARCHIVE_WARN)
                return (r);
 
        /* Read name from buffer. */
@@ -266,7 +272,7 @@ archive_read_format_cpio_read_header(struct archive_read *a,
        /* Detect and record hardlinks to previously-extracted entries. */
        record_hardlink(cpio, entry);
 
-       return (ARCHIVE_OK);
+       return (r);
 }
 
 static int
@@ -306,6 +312,82 @@ archive_read_format_cpio_read_data(struct archive_read *a,
        }
 }
 
+/*
+ * Skip forward to the next cpio newc header by searching for the
+ * 07070[12] string.  This should be generalized and merged with
+ * find_odc_header below.
+ */
+static int
+is_hex(const char *p, size_t len)
+{
+       while (len-- > 0) {
+               if (*p < '0' || (*p > '9' && *p < 'a') || *p > 'f') {
+                       return (0);
+               }
+               ++p;
+       }
+       return (1);
+}
+
+static int
+find_newc_header(struct archive_read *a)
+{
+       const void *h;
+       const char *p, *q;
+       size_t skip, bytes, skipped = 0;
+
+       for (;;) {
+               bytes = (a->decompressor->read_ahead)(a, &h, 2048);
+               if (bytes < sizeof(struct cpio_newc_header))
+                       return (ARCHIVE_FATAL);
+               p = h;
+               q = p + bytes;
+
+               /* Try the typical case first, then go into the slow search.*/
+               if (memcmp("07070", p, 5) == 0
+                   && (p[5] == '1' || p[5] == '2')
+                   && is_hex(p, sizeof(struct cpio_newc_header)))
+                       return (ARCHIVE_OK);
+
+               /*
+                * Scan ahead until we find something that looks
+                * like an odc header.
+                */
+               while (p + sizeof(struct cpio_newc_header) < q) {
+                       switch (p[5]) {
+                       case '1':
+                       case '2':
+                               if (memcmp("07070", p, 5) == 0
+                                       && is_hex(p, sizeof(struct cpio_newc_header))) {
+                                       skip = p - (const char *)h;
+                                       (a->decompressor->consume)(a, skip);
+                                       skipped += skip;
+                                       if (skipped > 0) {
+                                               archive_set_error(&a->archive,
+                                                   0,
+                                                   "Skipped %d bytes before "
+                                                   "finding valid header",
+                                                   (int)skipped);
+                                               return (ARCHIVE_WARN);
+                                       }
+                                       return (ARCHIVE_OK);
+                               }
+                               p += 2;
+                               break;
+                       case '0':
+                               p++;
+                               break;
+                       default:
+                               p += 6;
+                               break;
+                       }
+               }
+               skip = p - (const char *)h;
+               (a->decompressor->consume)(a, skip);
+               skipped += skip;
+       }
+}
+
 static int
 header_newc(struct archive_read *a, struct cpio *cpio,
     struct archive_entry *entry, size_t *namelength, size_t *name_pad)
@@ -313,6 +395,11 @@ header_newc(struct archive_read *a, struct cpio *cpio,
        const void *h;
        const struct cpio_newc_header *header;
        size_t bytes;
+       int r;
+
+       r = find_newc_header(a);
+       if (r < ARCHIVE_WARN)
+               return (r);
 
        /* Read fixed-size portion of header. */
        bytes = (a->decompressor->read_ahead)(a, &h, sizeof(struct cpio_newc_header));
@@ -357,7 +444,81 @@ header_newc(struct archive_read *a, struct cpio *cpio,
        archive_entry_set_size(entry, cpio->entry_bytes_remaining);
        /* Pad file contents to a multiple of 4. */
        cpio->entry_padding = 3 & -cpio->entry_bytes_remaining;
-       return (ARCHIVE_OK);
+       return (r);
+}
+
+/*
+ * Skip forward to the next cpio odc header by searching for the
+ * 070707 string.  This is a hand-optimized search that could
+ * probably be easily generalized to handle all character-based
+ * cpio variants.
+ */
+static int
+is_octal(const char *p, size_t len)
+{
+       while (len-- > 0) {
+               if (*p < '0' || *p > '7')
+                       return (0);
+               ++p;
+       }
+       return (1);
+}
+
+static int
+find_odc_header(struct archive_read *a)
+{
+       const void *h;
+       const char *p, *q;
+       size_t skip, bytes, skipped = 0;
+
+       for (;;) {
+               bytes = (a->decompressor->read_ahead)(a, &h, 512);
+               if (bytes < sizeof(struct cpio_odc_header))
+                       return (ARCHIVE_FATAL);
+               p = h;
+               q = p + bytes;
+
+               /* Try the typical case first, then go into the slow search.*/
+               if (memcmp("070707", p, 6) == 0
+                   && is_octal(p, sizeof(struct cpio_odc_header)))
+                       return (ARCHIVE_OK);
+
+               /*
+                * Scan ahead until we find something that looks
+                * like an odc header.
+                */
+               while (p + sizeof(struct cpio_odc_header) < q) {
+                       switch (p[5]) {
+                       case '7':
+                               if (memcmp("070707", p, 6) == 0
+                                       && is_octal(p, sizeof(struct cpio_odc_header))) {
+                                       skip = p - (const char *)h;
+                                       (a->decompressor->consume)(a, skip);
+                                       skipped += skip;
+                                       if (skipped > 0) {
+                                               archive_set_error(&a->archive,
+                                                   0,
+                                                   "Skipped %d bytes before "
+                                                   "finding valid header",
+                                                   (int)skipped);
+                                               return (ARCHIVE_WARN);
+                                       }
+                                       return (ARCHIVE_OK);
+                               }
+                               p += 2;
+                               break;
+                       case '0':
+                               p++;
+                               break;
+                       default:
+                               p += 6;
+                               break;
+                       }
+               }
+               skip = p - (const char *)h;
+               (a->decompressor->consume)(a, skip);
+               skipped += skip;
+       }
 }
 
 static int
@@ -365,12 +526,18 @@ header_odc(struct archive_read *a, struct cpio *cpio,
     struct archive_entry *entry, size_t *namelength, size_t *name_pad)
 {
        const void *h;
+       int r;
        const struct cpio_odc_header *header;
        size_t bytes;
 
        a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
        a->archive.archive_format_name = "POSIX octet-oriented cpio";
 
+       /* Find the start of the next header. */
+       r = find_odc_header(a);
+       if (r < ARCHIVE_WARN)
+               return (r);
+
        /* Read fixed-size portion of header. */
        bytes = (a->decompressor->read_ahead)(a, &h, sizeof(struct cpio_odc_header));
        if (bytes < sizeof(struct cpio_odc_header))
@@ -400,7 +567,7 @@ header_odc(struct archive_read *a, struct cpio *cpio,
            atol8(header->c_filesize, sizeof(header->c_filesize));
        archive_entry_set_size(entry, cpio->entry_bytes_remaining);
        cpio->entry_padding = 0;
-       return (ARCHIVE_OK);
+       return (r);
 }
 
 static int
index d77bd87..d2419ea 100644 (file)
@@ -194,7 +194,6 @@ struct file_info {
 struct iso9660 {
        int     magic;
 #define ISO9660_MAGIC   0x96609660
-       int     bid; /* If non-zero, return this as our bid. */
        struct archive_string pathname;
        char    seenRockridge; /* Set true if RR extensions are used. */
        unsigned char   suspOffset;
@@ -255,7 +254,6 @@ archive_read_support_format_iso9660(struct archive *_a)
        }
        memset(iso9660, 0, sizeof(*iso9660));
        iso9660->magic = ISO9660_MAGIC;
-       iso9660->bid = -1; /* We haven't yet bid. */
 
        r = __archive_read_register_format(a,
            iso9660,
@@ -280,12 +278,10 @@ archive_read_format_iso9660_bid(struct archive_read *a)
        ssize_t bytes_read;
        const void *h;
        const unsigned char *p;
+       int bid;
 
        iso9660 = (struct iso9660 *)(a->format->data);
 
-       if (iso9660->bid >= 0)
-               return (iso9660->bid);
-
        /*
         * Skip the first 32k (reserved area) and get the first
         * 8 sectors of the volume descriptor table.  Of course,
@@ -293,7 +289,7 @@ archive_read_format_iso9660_bid(struct archive_read *a)
         */
        bytes_read = (a->decompressor->read_ahead)(a, &h, 32768 + 8*2048);
        if (bytes_read < 32768 + 8*2048)
-           return (iso9660->bid = -1);
+           return (-1);
        p = (const unsigned char *)h;
 
        /* Skip the reserved area. */
@@ -302,16 +298,15 @@ archive_read_format_iso9660_bid(struct archive_read *a)
 
        /* Check each volume descriptor to locate the PVD. */
        for (; bytes_read > 2048; bytes_read -= 2048, p += 2048) {
-               iso9660->bid = isPVD(iso9660, p);
-               if (iso9660->bid > 0)
-                       return (iso9660->bid);
+               bid = isPVD(iso9660, p);
+               if (bid > 0)
+                       return (bid);
                if (*p == '\177') /* End-of-volume-descriptor marker. */
                        break;
        }
 
        /* We didn't find a valid PVD; return a bid of zero. */
-       iso9660->bid = 0;
-       return (iso9660->bid);
+       return (0);
 }
 
 static int
index 6b6ca92..e6ac99f 100644 (file)
@@ -65,7 +65,6 @@ struct mtree {
        char                    *buff;
        off_t                    offset;
        int                      fd;
-       int                      bid;
        int                      filetype;
        int                      archive_format;
        const char              *archive_format_name;
@@ -75,8 +74,8 @@ struct mtree {
        struct archive_string    contents_name;
 };
 
-static int     bid(struct archive_read *);
 static int     cleanup(struct archive_read *);
+static int     mtree_bid(struct archive_read *);
 static void    parse_escapes(char *, struct mtree_entry *);
 static int     parse_setting(struct archive_read *, struct mtree *,
                    struct archive_entry *, char *, char *);
@@ -103,11 +102,10 @@ archive_read_support_format_mtree(struct archive *_a)
                return (ARCHIVE_FATAL);
        }
        memset(mtree, 0, sizeof(*mtree));
-       mtree->bid = -1;
        mtree->fd = -1;
 
        r = __archive_read_register_format(a, mtree,
-           bid, read_header, read_data, skip, cleanup);
+           mtree_bid, read_header, read_data, skip, cleanup);
 
        if (r != ARCHIVE_OK)
                free(mtree);
@@ -144,17 +142,16 @@ cleanup(struct archive_read *a)
 
 
 static int
-bid(struct archive_read *a)
+mtree_bid(struct archive_read *a)
 {
        struct mtree *mtree;
        ssize_t bytes_read;
        const void *h;
        const char *signature = "#mtree";
        const char *p;
+       int bid;
 
        mtree = (struct mtree *)(a->format->data);
-       if (mtree->bid != -1)
-               return (mtree->bid);
 
        /* Now let's look at the actual header and see if it matches. */
        bytes_read = (a->decompressor->read_ahead)(a, &h, strlen(signature));
@@ -163,16 +160,16 @@ bid(struct archive_read *a)
                return (bytes_read);
 
        p = h;
-       mtree->bid = 0;
+       bid = 0;
        while (bytes_read > 0 && *signature != '\0') {
                if (*p != *signature)
-                       return (mtree->bid = 0);
-               mtree->bid += 8;
+                       return (bid = 0);
+               bid += 8;
                p++;
                signature++;
                bytes_read--;
        }
-       return (mtree->bid);
+       return (bid);
 }
 
 /*
index 5e7748e..6d6ee30 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_tar.c,v 1.61 2007/08/18 21:53:25 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_tar.c,v 1.62 2007/10/24 04:01:31 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
@@ -128,8 +128,8 @@ struct archive_entry_header_gnutar {
        char    isextended[1];
        char    realsize[12];
        /*
-        * GNU doesn't use POSIX 'prefix' field; they use the 'L' (longname)
-        * entry instead.
+        * Old GNU format doesn't use POSIX 'prefix' field; they use
+        * the 'L' (longname) entry instead.
         */
 };
 
@@ -318,23 +318,8 @@ archive_read_format_tar_bid(struct archive_read *a)
                bytes_read = 0; /* Empty file. */
        if (bytes_read < 0)
                return (ARCHIVE_FATAL);
-       if (bytes_read == 0  &&  bid > 0) {
-               /* An archive without a proper end-of-archive marker. */
-               /* Hold our nose and bid 1 anyway. */
-               return (1);
-       }
-       if (bytes_read < 512) {
-               /* If it's a new archive, then just return a zero bid. */
-               if (bid == 0)
-                       return (0);
-               /*
-                * If we already know this is a tar archive,
-                * then we have a problem.
-                */
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                   "Truncated tar archive");
-               return (ARCHIVE_FATAL);
-       }
+       if (bytes_read < 512)
+               return (0);
 
        /* If it's an end-of-archive mark, we can handle it. */
        if ((*(const char *)h) == 0 && archive_block_is_null((const unsigned char *)h)) {
@@ -440,6 +425,7 @@ archive_read_format_tar_read_header(struct archive_read *a,
                free(sp);
        }
        tar->sparse_last = NULL;
+       tar->realsize = -1; /* Mark this as "unset" */
 
        r = tar_read_header(a, tar, entry);
 
@@ -450,8 +436,6 @@ archive_read_format_tar_read_header(struct archive_read *a,
        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
@@ -579,16 +563,24 @@ tar_read_header(struct archive_read *a, struct tar *tar,
 
        /* Read 512-byte header record */
        bytes = (a->decompressor->read_ahead)(a, &h, 512);
-       if (bytes < 512) {
+       if (bytes < 0)
+               return (bytes);
+       if (bytes == 0) {
                /*
-                * If we're here, it's becase the _bid function accepted
-                * this file.  So just call a short read end-of-archive
-                * and be done with it.
+                * An archive that just ends without a proper
+                * end-of-archive marker.  Yes, there are tar programs
+                * that do this; hold our nose and accept it.
                 */
                return (ARCHIVE_EOF);
        }
+       if (bytes < 512) {
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+                   "Truncated tar archive");
+               return (ARCHIVE_FATAL);
+       }
        (a->decompressor->consume)(a, 512);
 
+
        /* Check for end-of-archive mark. */
        if (((*(const char *)h)==0) && archive_block_is_null((const unsigned char *)h)) {
                /* Try to consume a second all-null record, as well. */
@@ -934,6 +926,7 @@ header_common(struct archive_read *a, struct tar *tar,
        archive_entry_set_uid(entry, tar_atol(header->uid, sizeof(header->uid)));
        archive_entry_set_gid(entry, tar_atol(header->gid, sizeof(header->gid)));
        tar->entry_bytes_remaining = tar_atol(header->size, sizeof(header->size));
+       tar->realsize = tar->entry_bytes_remaining;
        archive_entry_set_size(entry, tar->entry_bytes_remaining);
        archive_entry_set_mtime(entry, tar_atol(header->mtime, sizeof(header->mtime)), 0);
 
@@ -1365,9 +1358,10 @@ pax_attribute(struct tar *tar, struct archive_entry *entry,
                                tar->sparse_numbytes = -1;
                        }
                }
-               if (wcscmp(key, L"GNU.sparse.size") == 0)
-                       archive_entry_set_size(entry,
-                           tar_atol10(value, wcslen(value)));
+               if (wcscmp(key, L"GNU.sparse.size") == 0) {
+                       tar->realsize = tar_atol10(value, wcslen(value));
+                       archive_entry_set_size(entry, tar->realsize);
+               }
 
                /* GNU "0.1" sparse pax format. */
                if (wcscmp(key, L"GNU.sparse.map") == 0) {
@@ -1388,9 +1382,10 @@ pax_attribute(struct tar *tar, struct archive_entry *entry,
                }
                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)));
+               if (wcscmp(key, L"GNU.sparse.realsize") == 0) {
+                       tar->realsize = tar_atol10(value, wcslen(value));
+                       archive_entry_set_size(entry, tar->realsize);
+               }
                break;
        case 'L':
                /* Our extensions */
@@ -1422,6 +1417,10 @@ pax_attribute(struct tar *tar, struct archive_entry *entry,
                        archive_entry_set_ino(entry, tar_atol10(value, wcslen(value)));
                else if (wcscmp(key, L"SCHILY.nlink")==0)
                        archive_entry_set_nlink(entry, tar_atol10(value, wcslen(value)));
+               else if (wcscmp(key, L"SCHILY.realsize")==0) {
+                       tar->realsize = tar_atol10(value, wcslen(value));
+                       archive_entry_set_size(entry, tar->realsize);
+               }
                break;
        case 'a':
                if (wcscmp(key, L"atime")==0) {
@@ -1471,11 +1470,24 @@ pax_attribute(struct tar *tar, struct archive_entry *entry,
                /* POSIX has reserved 'security.*' */
                /* Someday: if (wcscmp(key, L"security.acl")==0) { ... } */
                if (wcscmp(key, L"size")==0) {
-                       tar->entry_bytes_remaining = tar_atol10(value, wcslen(value));
-                       archive_entry_set_size(entry, tar->entry_bytes_remaining);
+                       /* "size" is the size of the data in the entry. */
+                       tar->entry_bytes_remaining
+                           = tar_atol10(value, wcslen(value));
+                       /*
+                        * But, "size" is not necessarily the size of
+                        * the file on disk; if this is a sparse file,
+                        * the disk size may have already been set from
+                        * GNU.sparse.realsize or GNU.sparse.size or
+                        * an old GNU header field or SCHILY.realsize
+                        * or ....
+                        */
+                       if (tar->realsize < 0) {
+                               archive_entry_set_size(entry,
+                                   tar->entry_bytes_remaining);
+                               tar->realsize
+                                   = tar->entry_bytes_remaining;
+                       }
                }
-               tar->entry_bytes_remaining = 0;
-
                break;
        case 'u':
                if (wcscmp(key, L"uid")==0)
@@ -1594,8 +1606,9 @@ header_gnutar(struct archive_read *a, struct tar *tar,
        archive_entry_set_ctime(entry,
            tar_atol(header->ctime, sizeof(header->ctime)), 0);
        if (header->realsize[0] != 0) {
-               archive_entry_set_size(entry,
-                   tar_atol(header->realsize, sizeof(header->realsize)));
+               tar->realsize
+                   = tar_atol(header->realsize, sizeof(header->realsize));
+               archive_entry_set_size(entry, tar->realsize);
        }
 
        if (header->sparse[0].offset[0] != 0) {
index 9d3dad6..f5d97ad 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_zip.c,v 1.14 2007/07/15 19:13:59 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_zip.c,v 1.15 2007/10/12 04:08:28 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
@@ -179,18 +179,19 @@ archive_read_format_zip_bid(struct archive_read *a)
            return (-1);
        p = (const char *)h;
 
+       /*
+        * Bid of 30 here is: 16 bits for "PK",
+        * next 16-bit field has four options (-2 bits).
+        * 16 + 16-2 = 30.
+        */
        if (p[0] == 'P' && p[1] == 'K') {
-               bid += 16;
-               if (p[2] == '\001' && p[3] == '\002')
-                       bid += 16;
-               else if (p[2] == '\003' && p[3] == '\004')
-                       bid += 16;
-               else if (p[2] == '\005' && p[3] == '\006')
-                       bid += 16;
-               else if (p[2] == '\007' && p[3] == '\010')
-                       bid += 16;
+               if ((p[2] == '\001' && p[3] == '\002')
+                   || (p[2] == '\003' && p[3] == '\004')
+                   || (p[2] == '\005' && p[3] == '\006')
+                   || (p[2] == '\007' && p[3] == '\010'))
+                       return (30);
        }
-       return (bid);
+       return (0);
 }
 
 static int
index 0ad962a..bb8555e 100644 (file)
@@ -151,11 +151,18 @@ archive_compressor_none_write(struct archive_write *a, const void *vbuff,
                return (ARCHIVE_OK);
        }
 
-       while ((remaining > 0) || (state->avail == 0)) {
-               /*
-                * If we have a full output block, write it and reset the
-                * output buffer.
-                */
+       /* If the copy buffer isn't empty, try to fill it. */
+       if (state->avail < state->buffer_size) {
+               /* If buffer is not empty... */
+               /* ... copy data into buffer ... */
+               to_copy = (remaining > state->avail) ?
+                   state->avail : remaining;
+               memcpy(state->next, buff, to_copy);
+               state->next += to_copy;
+               state->avail -= to_copy;
+               buff += to_copy;
+               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);
@@ -166,16 +173,26 @@ archive_compressor_none_write(struct archive_write *a, const void *vbuff,
                        state->next = state->buffer;
                        state->avail = state->buffer_size;
                }
+       }
 
-               /* Now we have space in the buffer; copy new data into it. */
-               to_copy = (remaining > state->avail) ?
-                   state->avail : remaining;
-               memcpy(state->next, buff, to_copy);
-               state->next += to_copy;
-               state->avail -= to_copy;
-               buff += to_copy;
-               remaining -= to_copy;
+       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)
+                       return (ARCHIVE_FATAL);
+               a->archive.raw_position += bytes_written;
+               buff += bytes_written;
+               remaining -= bytes_written;
        }
+
+       if (remaining > 0) {
+               /* Copy last bit into copy buffer. */
+               memcpy(state->next, buff, remaining);
+               state->next += remaining;
+               state->avail -= remaining;
+       }
+
        a->archive.file_position += length;
        return (ARCHIVE_OK);
 }
index 645b0b2..c8a6a7a 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio.c,v 1.11 2007/05/29 01:00:19 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio.c,v 1.12 2007/10/12 04:11:31 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
@@ -228,7 +228,7 @@ archive_write_cpio_finish(struct archive_write *a)
 
        cpio = (struct cpio *)a->format_data;
        trailer = archive_entry_new();
-       /* Why is this set to 1? */
+       /* nlink = 1 here for GNU cpio compat. */
        archive_entry_set_nlink(trailer, 1);
        archive_entry_set_pathname(trailer, "TRAILER!!!");
        er = archive_write_cpio_header(a, trailer);
index 436a0ef..e50544b 100644 (file)
@@ -25,7 +25,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio_newc.c,v 1.1 2007/06/22 05:47:00 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio_newc.c,v 1.2 2007/10/12 04:11:31 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
index 58ac3be..2f29833 100644 (file)
@@ -72,9 +72,9 @@ struct header_old_cpio {
         unsigned short   c_gid;
         unsigned short   c_nlink;
         unsigned short   c_rdev;
-       unsigned int     c_mtime;
+       unsigned short   c_mtime[2];
         unsigned short   c_namesize;
-       unsigned int     c_filesize;
+       unsigned short   c_filesize[2];
 };
 .Ed
 .Pp
@@ -149,29 +149,37 @@ followed by the least-significant 16 bits.
 Each of the two 16 bit values are stored in machine-native byte order.
 .It Va namesize
 The number of bytes in the pathname that follows the header.
+This count includes the trailing NULL byte.
 .It Va filesize
 The size of the file.
 Note that this archive format is limited to
 four gigabyte file sizes.
 See
 .Va mtime
-above for notes on the storage of four-byte integers.
+above for a description of the storage of four-byte integers.
 .El
 .Pp
 The pathname immediately follows the fixed header.
-If the pathname has an odd length, an additional NULL
-byte is added after the pathname.
+If the
+.Cm namesize
+is odd, an additional NULL byte is added after the pathname.
 The file data is then appended, padded with NULL
 bytes to an even length.
+.Pp
+Hardlinked files are not given special treatment;
+the full file contents are included with each copy of the
+file.
 .Ss Portable ASCII Format
 .St -susv2
 standardized an ASCII variant that is portable across all
 platforms.
 It is commonly known as the
+.Dq old character
+format or as the
 .Dq odc
 format.
-It stores the numeric fields as 6-character or 11-character
-octal values.
+It stores the same numeric fields as the old binary format, but
+represents them as 6-character or 11-character octal values.
 .Bd -literal -offset indent
 struct cpio_odc_header {
         char    c_magic[6];
@@ -188,17 +196,10 @@ struct cpio_odc_header {
 };
 .Ed
 .Pp
-Except as specified below, the fields here match those specified
-for the old binary format above.
-.Bl -tag -width indent
-.It Va magic
-The string
-.Dq 070707 .
-.It Va namesize
-The count here includes a terminating NULL byte.
-.El
-.Pp
+The fields are identical to those in the old binary format.
 The name and file body follow the fixed header.
+Unlike the old binary format, there is no additional padding
+after the pathname or file contents.
 If the files being archived are themselves entirely ASCII, then
 the resulting archive will be entirely ASCII, except for the
 NULL byte that terminates the name field.
@@ -241,6 +242,10 @@ of the fixed header plus pathname is a multiple of four.
 Likewise, the file data is padded to a multiple of four bytes.
 Note that this format supports only 4 gigabyte files (unlike the
 older ASCII format, which supports 8 gigabyte files).
+.Pp
+In this format, hardlinked files are handled by setting the
+filesize to zero for each entry except the last one that
+appears in the archive.
 .Ss New CRC Format
 The CRC format is identical to the new ASCII format described
 in the previous section except that the magic field is set
@@ -305,10 +310,16 @@ utility.
 .Sh HISTORY
 The original cpio utility was written by Dick Haight
 while working in AT&T's Unix Support Group.
-It was first available in PWB/UNIX 1.0, the
+It appeared in 1977 as part of PWB/UNIX 1.0, the
 .Dq Programmer's Work Bench
 derived from
 .At v6
 that was used internally at AT&T.
-It became more generally available as part of
-.At v7 .
+Both the old binary and old character formats were in use
+by 1980, according to the System III source released
+by SCO under their
+.Dq Ancient Unix
+license.
+The character format was adopted as part of
+.St -p1003.1-88 .
+XXX when did "newc" appear?  Who invented it?  When did HP come out with their variant?  When did Sun introduce ACLs and extended attributes? XXX
\ No newline at end of file
index 1161f65..a84c940 100644 (file)
@@ -96,12 +96,9 @@ When opening the archive, it reads an initial block of data
 and offers it to each registered compression handler.
 The one with the highest bid is initialized with the first block.
 Similarly, the format handlers are polled to see which handler
-is the best for each header request.
-(Note that a single file can have entries handled by different
-format handlers;
-this allows a simple handler for a generic version of a format
-with more complex handlers implemented independently for
-extended sub-formats.)
+is the best for each archive.
+(Prior to 2.4.0, the format bidders were invoked for each
+entry, but this design hindered error recovery.)
 .Ss I/O Layer and Client Callbacks
 The read API goes to some lengths to be nice to clients.
 As a result, there are few restrictions on the behavior of
@@ -116,6 +113,8 @@ In particular, blocks may be of different sizes.
 The client skip callback returns the number of bytes actually
 skipped, which may be much smaller than the skip requested.
 The only requirement is that the skip not be larger.
+In particular, clients are allowed to return zero for any
+skip that they don't want to handle.
 The skip callback must never be invoked with a negative value.
 .Pp
 Keep in mind that not all clients are reading from disk:
@@ -242,21 +241,12 @@ decompression method but not calling the
 method.
 This allows each bidder to look ahead in the input stream.
 Bidders should not look further ahead than necessary, as long
-look aheads put pressure on the compression layer to buffer
+look aheads put pressure on the decompression layer to buffer
 lots of data.
 Most formats only require a few hundred bytes of look ahead;
 look aheads of a few kilobytes are reasonable.
 (The ISO9660 reader sometimes looks ahead by 48k, which
 should be considered an upper limit.)
-Note that the bidder is invoked for every entry.
-For many formats, this is inappropriate; if you can only bid at
-the beginning of the file, store your bid value and check that
-each time your bid function is called.
-For example, the ISO9660 reader initializes a
-.Va bid
-value to -1 at registration time;
-each time the bid function is called, the bid value is returned
-immediately if it is zero or larger.
 .It Read header
 The header read is usually the most complex part of any format.
 There are a few strategies worth mentioning:
index 707abcb..66852ca 100644 (file)
@@ -49,7 +49,8 @@
 #ifdef __FreeBSD__
 #include <sys/cdefs.h>  /* For __FBSDID */
 #else
-#define        __FBSDID(a)     /* null */
+/* Just leaving this macro replacement empty leads to a dangling semicolon. */
+#define        __FBSDID(a)     struct _undefined_hack
 #endif
 
 #ifdef HAVE_LIBARCHIVE
index fd06a92..9183195 100644 (file)
@@ -1 +1 @@
-2.3.4
\ No newline at end of file
+2.4.0
\ No newline at end of file