Merge from vendor branch LIBARCHIVE:
authorPeter Avalos <pavalos@dragonflybsd.org>
Sat, 7 Apr 2007 14:04:55 +0000 (14:04 +0000)
committerPeter Avalos <pavalos@dragonflybsd.org>
Sat, 7 Apr 2007 14:04:55 +0000 (14:04 +0000)
Import libarchive 2.0.28.

18 files changed:
contrib/libarchive-2.0/NEWS
contrib/libarchive-2.0/libarchive/archive.h.in
contrib/libarchive-2.0/libarchive/archive_entry.c
contrib/libarchive-2.0/libarchive/archive_read.3
contrib/libarchive-2.0/libarchive/archive_read.c
contrib/libarchive-2.0/libarchive/archive_read_extract.c
contrib/libarchive-2.0/libarchive/archive_read_support_compression_bzip2.c
contrib/libarchive-2.0/libarchive/archive_read_support_compression_compress.c
contrib/libarchive-2.0/libarchive/archive_read_support_compression_gzip.c
contrib/libarchive-2.0/libarchive/archive_read_support_compression_none.c
contrib/libarchive-2.0/libarchive/archive_read_support_format_all.c
contrib/libarchive-2.0/libarchive/archive_read_support_format_ar.c [new file with mode: 0644]
contrib/libarchive-2.0/libarchive/archive_read_support_format_tar.c
contrib/libarchive-2.0/libarchive/archive_write_disk.3 [new file with mode: 0644]
contrib/libarchive-2.0/libarchive/archive_write_set_format_ar.c [new file with mode: 0644]
contrib/libarchive-2.0/libarchive/libarchive-formats.5
contrib/libarchive-2.0/tar/read.c
contrib/libarchive-2.0/version

index a9c8dba..50249fc 100644 (file)
@@ -1,4 +1,7 @@
 
+Apr 06, 2007: libarchive 2.0.28 released
+Apr 06, 2007: 'ar' format read/write support thanks to Kai Wang.
+
 Apr 01, 2007: libarchive 2.0.27 released
 
 Apr 01, 2007: libarchive 2.0.26 released
index a9ba787..874bda7 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.40 2007/03/11 10:29:52 kientzle Exp $
+ * $FreeBSD: src/lib/libarchive/archive.h.in,v 1.41 2007/04/03 05:34:36 kientzle Exp $
  */
 
 #ifndef ARCHIVE_H_INCLUDED
@@ -177,6 +177,9 @@ typedef int archive_close_callback(struct archive *, void *_client_data);
 #define        ARCHIVE_FORMAT_ISO9660_ROCKRIDGE        (ARCHIVE_FORMAT_ISO9660 | 1)
 #define        ARCHIVE_FORMAT_ZIP                      0x50000
 #define        ARCHIVE_FORMAT_EMPTY                    0x60000
+#define        ARCHIVE_FORMAT_AR                       0x70000
+#define        ARCHIVE_FORMAT_AR_SVR4                  (ARCHIVE_FORMAT_AR | 1)
+#define        ARCHIVE_FORMAT_AR_BSD                   (ARCHIVE_FORMAT_AR | 2)
 
 /*-
  * Basic outline for reading an archive:
@@ -206,6 +209,7 @@ int          archive_read_support_compression_gzip(struct archive *);
 int             archive_read_support_compression_none(struct archive *);
 
 int             archive_read_support_format_all(struct archive *);
+int             archive_read_support_format_ar(struct archive *);
 int             archive_read_support_format_cpio(struct archive *);
 int             archive_read_support_format_empty(struct archive *);
 int             archive_read_support_format_gnutar(struct archive *);
@@ -374,6 +378,8 @@ int          archive_write_set_format(struct archive *, int format_code);
 int             archive_write_set_format_by_name(struct archive *,
                     const char *name);
 /* To minimize link pollution, use one or more of the following. */
+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 *);
 /* TODO: int archive_write_set_format_old_tar(struct archive *); */
 int             archive_write_set_format_pax(struct archive *);
index 4564767..0cdd2b0 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_entry.c,v 1.40 2007/03/11 10:29:52 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_entry.c,v 1.41 2007/04/05 05:20:13 kientzle Exp $");
 
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
@@ -250,7 +250,8 @@ aes_get_mbs(struct aes *aes)
                 * chars encode to no more than 3 bytes.  There must
                 * be a better way... XXX
                 */
-               int mbs_length = wcslen(aes->aes_wcs) * 3 + 64;
+               size_t mbs_length = wcslen(aes->aes_wcs) * 3 + 64;
+
                aes->aes_mbs_alloc = (char *)malloc(mbs_length);
                aes->aes_mbs = aes->aes_mbs_alloc;
                if (aes->aes_mbs == NULL)
@@ -271,7 +272,8 @@ aes_get_wcs(struct aes *aes)
                 * No single byte will be more than one wide character,
                 * so this length estimate will always be big enough.
                 */
-               int wcs_length = strlen(aes->aes_mbs);
+               size_t wcs_length = strlen(aes->aes_mbs);
+
                aes->aes_wcs_alloc
                    = (wchar_t *)malloc((wcs_length + 1) * sizeof(wchar_t));
                aes->aes_wcs = aes->aes_wcs_alloc;
@@ -1207,14 +1209,14 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
        case ARCHIVE_ENTRY_ACL_USER_OBJ:
                wname = NULL;
                id = -1;
-               /* FALL THROUGH */
+               /* FALLTHROUGH */
        case ARCHIVE_ENTRY_ACL_USER:
                wcscpy(*wp, L"user");
                break;
        case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
                wname = NULL;
                id = -1;
-               /* FALL THROUGH */
+               /* FALLTHROUGH */
        case ARCHIVE_ENTRY_ACL_GROUP:
                wcscpy(*wp, L"group");
                break;
@@ -1648,7 +1650,7 @@ ae_fflagstostr(unsigned long bitset, unsigned long bitclear)
        const char *sp;
        unsigned long bits;
        struct flag *flag;
-       int     length;
+       size_t  length;
 
        bits = bitset | bitclear;
        length = 0;
index 1a83ff4..e50a28e 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.31 2007/03/03 07:37:36 kientzle Exp $
+.\" $FreeBSD: src/lib/libarchive/archive_read.3,v 1.33 2007/04/07 05:53:11 kientzle Exp $
 .\"
 .Dd August 19, 2006
 .Dt archive_read 3
@@ -50,7 +50,9 @@
 .Nm archive_read_data ,
 .Nm archive_read_data_block ,
 .Nm archive_read_data_skip ,
+.\" #if ARCHIVE_API_VERSION < 3
 .Nm archive_read_data_into_buffer ,
+.\" #endif
 .Nm archive_read_data_into_fd ,
 .Nm archive_read_extract ,
 .Nm archive_read_extract_set_progress_callback ,
 .Fn archive_read_data_block "struct archive *" "const void **buff" "size_t *len" "off_t *offset"
 .Ft int
 .Fn archive_read_data_skip "struct archive *"
+.\" #if ARCHIVE_API_VERSION < 3
 .Ft int
 .Fn archive_read_data_into_buffer "struct archive *" "void *" "ssize_t len"
+.\" #endif
 .Ft int
 .Fn archive_read_data_into_fd "struct archive *" "int fd"
 .Ft int
@@ -224,11 +228,13 @@ and internal buffer optimizations.
 A convenience function that repeatedly calls
 .Fn archive_read_data_block
 to skip all of the data for this archive entry.
+.\" #if ARCHIVE_API_VERSION < 3
 .It Fn archive_read_data_into_buffer
-A convenience function that repeatedly calls
-.Fn archive_read_data_block
-to copy the entire entry into the client-supplied buffer.
-Note that the client is responsible for sizing the buffer appropriately.
+This function is deprecated and will be removed.
+Use
+.Fn archive_read_data
+instead.
+.\" #endif
 .It Fn archive_read_data_into_fd
 A convenience function that repeatedly calls
 .Fn archive_read_data_block
index 82b0e50..5c9938f 100644 (file)
@@ -32,7 +32,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read.c,v 1.32 2007/04/02 00:41:37 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read.c,v 1.34 2007/04/05 15:51:19 cperciva Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
@@ -274,8 +274,8 @@ dummy_skip(struct archive_read * a, off_t request)
                        return (ARCHIVE_FATAL);
                }
                if (bytes_read > request)
-                       bytes_read = request;
-               (a->compression_read_consume)(a, bytes_read);
+                       bytes_read = (ssize_t)request;
+               (a->compression_read_consume)(a, (size_t)bytes_read);
                request -= bytes_read;
                bytes_skipped += bytes_read;
        }
@@ -448,7 +448,7 @@ archive_read_data(struct archive *_a, void *buff, size_t s)
        dest = (char *)buff;
 
        while (s > 0) {
-               if (a->read_data_remaining <= 0) {
+               if (a->read_data_remaining == 0) {
                        read_buf = a->read_data_block;
                        r = archive_read_data_block(&a->archive, &read_buf,
                            &a->read_data_remaining, &a->read_data_offset);
@@ -506,6 +506,22 @@ archive_read_data(struct archive *_a, void *buff, size_t s)
        return (bytes_read);
 }
 
+#if ARCHIVE_API_VERSION < 3
+/*
+ * Obsolete function provided for compatibility only.  Note that the API
+ * of this function doesn't allow the caller to detect if the remaining
+ * data from the archive entry is shorter than the buffer provided, or
+ * even if an error occurred while reading data.
+ */
+int
+archive_read_data_into_buffer(struct archive *a, void *d, ssize_t len)
+{
+
+       archive_read_data(a, d, len);
+       return (ARCHIVE_OK);
+}
+#endif
+
 /*
  * Skip over all remaining data in this entry.
  */
index a06671e..08804d4 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_extract.c,v 1.54 2007/03/11 10:29:52 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_extract.c,v 1.55 2007/04/07 03:37:59 cperciva Exp $");
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
@@ -98,10 +98,6 @@ archive_read_extract(struct archive *_a, struct archive_entry *entry, int flags)
        if (r == ARCHIVE_OK)
                /* If there's an FD, pour data into it. */
                r = copy_data(_a, a->extract->ad);
-       if (r != ARCHIVE_OK)
-               archive_set_error(&a->archive,
-                   archive_errno(extract->ad),
-                   "%s", archive_error_string(extract->ad));
        r2 = archive_write_finish_entry(a->extract->ad);
        /* Use the first message. */
        if (r2 != ARCHIVE_OK && r == ARCHIVE_OK)
@@ -141,8 +137,11 @@ copy_data(struct archive *ar, struct archive *aw)
                if (r != ARCHIVE_OK)
                        return (r);
                r = archive_write_data_block(aw, buff, size, offset);
-               if (r != ARCHIVE_OK)
+               if (r != ARCHIVE_OK) {
+                       archive_set_error(ar, archive_errno(aw),
+                           "%s", archive_error_string(aw));
                        return (r);
+               }
        }
 }
 
index 82c7d7d..8651c98 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "archive_platform.h"
 
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_bzip2.c,v 1.14 2007/03/24 03:23:26 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_bzip2.c,v 1.15 2007/04/05 05:18:16 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
@@ -253,10 +253,10 @@ static ssize_t
 read_ahead(struct archive_read *a, const void **p, size_t min)
 {
        struct private_data *state;
-       int read_avail, was_avail, ret;
+       size_t read_avail, was_avail;
+       int ret;
 
        state = (struct private_data *)a->compression_data;
-       was_avail = -1;
        if (!a->client_reader) {
                archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
                    "No read callback is registered?  "
@@ -275,13 +275,14 @@ read_ahead(struct archive_read *a, const void **p, size_t min)
                    = state->uncompressed_buffer_size - read_avail;
        }
 
-       while (was_avail < read_avail &&        /* Made some progress. */
-           read_avail < (int)min &&            /* Haven't satisfied min. */
-           read_avail < (int)state->uncompressed_buffer_size) { /* !full */
+       while (read_avail < min &&              /* Haven't satisfied min. */
+           read_avail < state->uncompressed_buffer_size) { /* !full */
+               was_avail = read_avail;
                if ((ret = drive_decompressor(a, state)) != ARCHIVE_OK)
                        return (ret);
-               was_avail = read_avail;
                read_avail = state->stream.next_out - state->read_next;
+               if (was_avail == read_avail) /* No progress? */
+                       break;
        }
 
        *p = state->read_next;
@@ -346,12 +347,15 @@ drive_decompressor(struct archive_read *a, struct private_data *state)
        ssize_t ret;
        int decompressed, total_decompressed;
        char *output;
+       const void *read_buf;
 
        total_decompressed = 0;
        for (;;) {
                if (state->stream.avail_in == 0) {
+                       read_buf = state->stream.next_in;
                        ret = (a->client_reader)(&a->archive, a->client_data,
-                           (const void **)&state->stream.next_in);
+                           &read_buf);
+                       state->stream.next_in = (void *)(uintptr_t)read_buf;
                        if (ret < 0) {
                                /*
                                 * TODO: Find a better way to handle
index 6f801d3..6064389 100644 (file)
@@ -64,7 +64,7 @@
 
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_compress.c,v 1.8 2007/03/03 07:37:36 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_compress.c,v 1.9 2007/04/05 05:18:16 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
@@ -275,10 +275,10 @@ static ssize_t
 read_ahead(struct archive_read *a, const void **p, size_t min)
 {
        struct private_data *state;
-       int read_avail, was_avail, ret;
+       size_t read_avail;
+       int ret;
 
        state = (struct private_data *)a->compression_data;
-       was_avail = -1;
        if (!a->client_reader) {
                archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
                    "No read callback is registered?  "
@@ -288,14 +288,14 @@ read_ahead(struct archive_read *a, const void **p, size_t min)
 
        read_avail = state->next_out - state->read_next;
 
-       if (read_avail < (int)min  &&  state->end_of_stream) {
+       if (read_avail < min  &&  state->end_of_stream) {
                if (state->end_of_stream == ARCHIVE_EOF)
                        return (0);
                else
                        return (-1);
        }
 
-       if (read_avail < (int)min) {
+       if (read_avail < min) {
                memmove(state->uncompressed_buffer, state->read_next,
                    read_avail);
                state->read_next = (unsigned char *)state->uncompressed_buffer;
@@ -303,7 +303,7 @@ read_ahead(struct archive_read *a, const void **p, size_t min)
                state->avail_out
                    = state->uncompressed_buffer_size - read_avail;
 
-               while (read_avail < (int)state->uncompressed_buffer_size
+               while (read_avail < state->uncompressed_buffer_size
                        && !state->end_of_stream) {
                        if (state->stackp > state->stack) {
                                *state->next_out++ = *--state->stackp;
@@ -465,12 +465,14 @@ getbits(struct archive_read *a, struct private_data *state, int n)
                0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff,
                0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff
        };
-
+       const void *read_buf;
 
        while (state->bits_avail < n) {
                if (state->avail_in <= 0) {
+                       read_buf = state->next_in;
                        ret = (a->client_reader)(&a->archive, a->client_data,
-                           (const void **)&state->next_in);
+                           &read_buf);
+                       state->next_in = read_buf;
                        if (ret < 0)
                                return (ARCHIVE_FATAL);
                        if (ret == 0)
index ccda36e..7386c9b 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "archive_platform.h"
 
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_gzip.c,v 1.13 2007/03/03 07:37:36 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_gzip.c,v 1.14 2007/04/05 05:18:16 kientzle Exp $");
 
 
 #ifdef HAVE_ERRNO_H
@@ -258,10 +258,10 @@ static ssize_t
 read_ahead(struct archive_read *a, const void **p, size_t min)
 {
        struct private_data *state;
-       int read_avail, was_avail, ret;
+       size_t read_avail, was_avail;
+       int ret;
 
        state = (struct private_data *)a->compression_data;
-       was_avail = -1;
        if (!a->client_reader) {
                archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
                    "No read callback is registered?  "
@@ -280,13 +280,14 @@ read_ahead(struct archive_read *a, const void **p, size_t min)
                    = state->uncompressed_buffer_size - read_avail;
        }
 
-       while (was_avail < read_avail &&        /* Made some progress. */
-           read_avail < (int)min &&            /* Haven't satisfied min. */
-           read_avail < (int)state->uncompressed_buffer_size) { /* !full */
+       while (read_avail < min &&              /* Haven't satisfied min. */
+           read_avail < state->uncompressed_buffer_size) { /* !full */
+               was_avail = read_avail;
                if ((ret = drive_decompressor(a, state)) != ARCHIVE_OK)
                        return (ret);
-               was_avail = read_avail;
                read_avail = state->stream.next_out - state->read_next;
+               if (was_avail == read_avail) /* No progress? */
+                       break;
        }
 
        *p = state->read_next;
@@ -349,10 +350,11 @@ static int
 drive_decompressor(struct archive_read *a, struct private_data *state)
 {
        ssize_t ret;
-       int decompressed, total_decompressed;
+       size_t decompressed, total_decompressed;
        int count, flags, header_state;
        unsigned char *output;
        unsigned char b;
+       const void *read_buf;
 
        flags = 0;
        count = 0;
@@ -360,8 +362,10 @@ drive_decompressor(struct archive_read *a, struct private_data *state)
        total_decompressed = 0;
        for (;;) {
                if (state->stream.avail_in == 0) {
+                       read_buf = state->stream.next_in;
                        ret = (a->client_reader)(&a->archive, a->client_data,
-                           (const void **)&state->stream.next_in);
+                           &read_buf);
+                       state->stream.next_in = (unsigned char *)(uintptr_t)read_buf;
                        if (ret < 0) {
                                /*
                                 * TODO: Find a better way to handle
index dde0aee..6a3a245 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_none.c,v 1.15 2007/03/03 07:37:36 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_none.c,v 1.16 2007/04/05 05:18:16 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
@@ -51,7 +51,7 @@ struct archive_decompress_none {
        size_t           buffer_size;
        char            *next;          /* Current read location. */
        size_t           avail;         /* Bytes in my buffer. */
-       const char      *client_buff;   /* Client buffer information. */
+       const void      *client_buff;   /* Client buffer information. */
        size_t           client_total;
        const char      *client_next;
        size_t           client_avail;
@@ -130,7 +130,7 @@ archive_decompressor_none_init(struct archive_read *a, const void *buff, size_t
        }
 
        /* Save reference to first block of data. */
-       state->client_buff = (const char *)buff;
+       state->client_buff = buff;
        state->client_total = n;
        state->client_next = state->client_buff;
        state->client_avail = state->client_total;
@@ -219,8 +219,7 @@ archive_decompressor_none_read_ahead(struct archive_read *a, const void **buff,
                         * aren't, hence the cast.
                         */
                        bytes_read = (a->client_reader)(&a->archive,
-                           a->client_data,
-                           (const void **)&state->client_buff);
+                           a->client_data, &state->client_buff);
                        if (bytes_read < 0) {           /* Read error. */
                                state->client_total = state->client_avail = 0;
                                state->client_next = state->client_buff = NULL;
index 281e98c..3fdfa05 100644 (file)
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_all.c,v 1.8 2007/02/01 06:18:16 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_all.c,v 1.9 2007/04/07 05:54:23 kientzle Exp $");
 
 #include "archive.h"
 
 int
 archive_read_support_format_all(struct archive *a)
 {
+       archive_read_support_format_ar(a);
        archive_read_support_format_cpio(a);
        archive_read_support_format_empty(a);
        archive_read_support_format_iso9660(a);
diff --git a/contrib/libarchive-2.0/libarchive/archive_read_support_format_ar.c b/contrib/libarchive-2.0/libarchive/archive_read_support_format_ar.c
new file mode 100644 (file)
index 0000000..b5ced66
--- /dev/null
@@ -0,0 +1,585 @@
+/*-
+ * Copyright (c) 2007 Kai Wang
+ * Copyright (c) 2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_ar.c,v 1.1 2007/04/03 05:34:36 kientzle Exp $");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+struct ar {
+       int      bid;
+       int      has_strtab;
+       off_t    entry_bytes_remaining;
+       off_t    entry_offset;
+       off_t    entry_padding;
+       char    *strtab;
+};
+
+/*
+ * Define structure of the "ar" header.
+ */
+#define AR_name_offset 0
+#define AR_name_size 16
+#define AR_date_offset 16
+#define AR_date_size 12
+#define AR_uid_offset 28
+#define AR_uid_size 6
+#define AR_gid_offset 34
+#define AR_gid_size 6
+#define AR_mode_offset 40
+#define AR_mode_size 8
+#define AR_size_offset 48
+#define AR_size_size 10
+#define AR_fmag_offset 58
+#define AR_fmag_size 2
+
+/*
+ * "ar" magic numbers.
+ */
+#define        ARMAG           "!<arch>\n"
+#define        SARMAG          8               /* strlen(ARMAG); */
+#define        AR_EFMT1        "#1/"
+#define        SAR_EFMT1       3               /* strlen(AR_EFMT1); */
+#define        ARFMAG          "`\n"
+#define        SARFMAG         2               /* strlen(ARFMAG); */
+
+#define isdigit(x)     (x) >= '0' && (x) <= '9'
+
+static int     archive_read_format_ar_bid(struct archive_read *a);
+static int     archive_read_format_ar_cleanup(struct archive_read *a);
+static int     archive_read_format_ar_read_data(struct archive_read *a,
+                   const void **buff, size_t *size, off_t *offset);
+static int     archive_read_format_ar_skip(struct archive_read *a);
+static int     archive_read_format_ar_read_header(struct archive_read *a,
+                   struct archive_entry *e);
+static int64_t ar_atol8(const char *p, unsigned char_cnt);
+static int64_t ar_atol10(const char *p, unsigned char_cnt);
+static int     ar_parse_string_table(struct archive_read *, struct ar *,
+                   const void *, ssize_t);
+
+/*
+ * ANSI C99 defines constants for these, but not everyone supports
+ * those constants, so I define a couple of static variables here and
+ * compute the values.  These calculations should be portable to any
+ * 2s-complement architecture.
+ */
+#ifdef UINT64_MAX
+static const uint64_t max_uint64 = UINT64_MAX;
+#else
+static const uint64_t max_uint64 = ~(uint64_t)0;
+#endif
+#ifdef INT64_MAX
+static const int64_t max_int64 = INT64_MAX;
+#else
+static const int64_t max_int64 = (int64_t)((~(uint64_t)0) >> 1);
+#endif
+#ifdef INT64_MIN
+static const int64_t min_int64 = INT64_MIN;
+#else
+static const int64_t min_int64 = (int64_t)(~((~(uint64_t)0) >> 1));
+#endif
+
+int
+archive_read_support_format_ar(struct archive *_a)
+{
+       struct archive_read *a = (struct archive_read *)_a;
+       struct ar *ar;
+       int r;
+
+       ar = (struct ar *)malloc(sizeof(*ar));
+       if (ar == NULL) {
+               archive_set_error(&a->archive, ENOMEM,
+                   "Can't allocate ar data");
+               return (ARCHIVE_FATAL);
+       }
+       memset(ar, 0, sizeof(*ar));
+       ar->bid = -1;
+
+       r = __archive_read_register_format(a,
+           ar,
+           archive_read_format_ar_bid,
+           archive_read_format_ar_read_header,
+           archive_read_format_ar_read_data,
+           archive_read_format_ar_skip,
+           archive_read_format_ar_cleanup);
+
+       if (r != ARCHIVE_OK) {
+               free(ar);
+               return (r);
+       }
+       return (ARCHIVE_OK);
+}
+
+static int
+archive_read_format_ar_cleanup(struct archive_read *a)
+{
+       struct ar *ar;
+
+       ar = (struct ar *)*(a->pformat_data);
+       if (ar->has_strtab > 0)
+               free(ar->strtab);
+       free(ar);
+       *(a->pformat_data) = NULL;
+       return (ARCHIVE_OK);
+}
+
+static int
+archive_read_format_ar_bid(struct archive_read *a)
+{
+       struct ar *ar;
+       ssize_t bytes_read;
+       const void *h;
+
+       if (a->archive.archive_format != 0 &&
+           (a->archive.archive_format & ARCHIVE_FORMAT_BASE_MASK) !=
+           ARCHIVE_FORMAT_AR)
+               return(0);
+
+       ar = (struct ar *)*(a->pformat_data);
+
+       if (ar->bid > 0)
+               return (ar->bid);
+
+       bytes_read = (a->compression_read_ahead)(a, &h, SARMAG);
+       if (bytes_read < SARMAG)
+               return (-1);
+
+       /*
+        * Verify the global header.
+        * TODO: Do we need to check more than this?
+        */
+       if (strncmp((const char*)h, ARMAG, SARMAG) == 0) {
+               ar->bid = SARMAG;
+               return (ar->bid);
+       }
+       return (-1);
+}
+
+static int
+archive_read_format_ar_read_header(struct archive_read *a,
+    struct archive_entry *entry)
+{
+       int r, bsd_append;
+       ssize_t bytes;
+       int64_t nval;
+       char *fname, *p;
+       struct ar *ar;
+       const void *b;
+       const char *h;
+
+       bsd_append = 0;
+
+       if (!a->archive.archive_format) {
+               a->archive.archive_format = ARCHIVE_FORMAT_AR;
+               a->archive.archive_format_name = "Unix Archiver";
+       }
+
+       if (a->archive.file_position == 0) {
+               /*
+                * We are now at the beginning of the archive,
+                * so we need first consume the ar global header.
+                */
+               (a->compression_read_consume)(a, SARMAG);
+       }
+
+       /* Read 60-byte header */
+       bytes = (a->compression_read_ahead)(a, &b, 60);
+       if (bytes < 60) {
+               /*
+                * We just encountered an incomplete ar file,
+                * though the _bid function accepted it.
+                */
+               return (ARCHIVE_EOF);
+       }
+       (a->compression_read_consume)(a, 60);
+
+       h = (const char *)b;
+
+       /* Consistency check */
+       if (strncmp(h + AR_fmag_offset, ARFMAG, SARFMAG) != 0) {
+               archive_set_error(&a->archive, EINVAL,
+                   "Consistency check failed");
+               return (ARCHIVE_WARN);
+       }
+
+       ar = (struct ar*)*(a->pformat_data);
+
+       if (strncmp(h + AR_name_offset, "//", 2) == 0) {
+               /*
+                * An archive member with ar_name "//" is an archive
+                * string table.
+                */
+               nval = ar_atol10(h + AR_size_offset, AR_size_size);
+               bytes = (a->compression_read_ahead)(a, &b, nval);
+               if (bytes <= 0)
+                       return (ARCHIVE_FATAL);
+               if (bytes < nval) {
+                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                           "Truncated input file");
+                       return (ARCHIVE_FATAL);
+               }
+
+               r = ar_parse_string_table(a, ar, b, nval);
+               if (r == ARCHIVE_OK) {
+                       /*
+                        * Archive string table only have ar_name and ar_size fileds
+                        * in its header.
+                        */
+                       archive_entry_copy_pathname(entry, "//");
+                       nval = ar_atol10(h + AR_size_offset, AR_size_size);
+                       archive_entry_set_size(entry, nval);
+
+                       ar->entry_offset = 0;
+                       ar->entry_bytes_remaining = nval;
+                       ar->entry_padding = ar->entry_bytes_remaining % 2;
+               }
+               return (r);
+       }
+
+       if (h[AR_name_offset] == '/' && isdigit(h[AR_name_offset + 1])) {
+               /*
+                * Archive member is common format with SVR4/GNU variant.
+                * "/" followed by one or more digit(s) in the ar_name
+                * filed indicates an index to the string table.
+                */
+               if (ar->has_strtab > 0) {
+                       nval = ar_atol10(h + AR_name_offset + 1,
+                           AR_name_size - 1);
+                       archive_entry_copy_pathname(entry, &ar->strtab[nval]);
+               } else {
+                       archive_set_error(&a->archive, EINVAL,
+                           "String table does not exist");
+                       return (ARCHIVE_WARN);
+               }
+               goto remain;
+       }
+
+       if (strncmp(h + AR_name_offset, AR_EFMT1, SAR_EFMT1) == 0) {
+               /*
+                * Archive member is common format with BSD variant.
+                * AR_EFMT1 is followed by one or more digit(s) indicating
+                * the length of the real filename which is appended
+                * to the header.
+                */
+               nval = ar_atol10(h + AR_name_offset + SAR_EFMT1,
+                   AR_name_size - SAR_EFMT1);
+               bytes = (a->compression_read_ahead)(a, &b, nval);
+               if (bytes <= 0)
+                       return (ARCHIVE_FATAL);
+               if (bytes < nval) {
+                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                           "Truncated input file");
+                       return (ARCHIVE_FATAL);
+               }
+
+               (a->compression_read_consume)(a, nval);
+
+               fname = (char *)malloc(nval + 1);
+               if (fname == NULL) {
+                       archive_set_error(&a->archive, ENOMEM,
+                           "Can't allocate fname buffer");
+                       return (ARCHIVE_FATAL);
+               }
+               strncpy(fname, b, nval);
+               fname[nval] = '\0';
+               archive_entry_copy_pathname(entry, fname);
+               free(fname);
+               fname = NULL;
+
+               bsd_append = nval;
+               goto remain;
+       }
+
+       /*
+        * "/" followed by one or more spaces indicate a
+        * SVR4/GNU archive symbol table.
+        *
+        */
+       if (strncmp(h + AR_name_offset, "/ ", 2) == 0) {
+               archive_entry_copy_pathname(entry, "/");
+               goto remain;
+       }
+       /*
+        * "__.SYMDEF" indicates a BSD archive symbol table.
+        */
+       if (strncmp(h + AR_name_offset, "__.SYMDEF", 9) == 0) {
+               archive_entry_copy_pathname(entry, "__.SYMDEF");
+               goto remain;
+       }
+
+       /*
+        * Otherwise, the ar_name fields stores the real
+        * filename.
+        * SVR4/GNU variant append a '/' to mark the end of
+        * filename, while BSD variant use a space.
+        */
+       fname = (char *)malloc(AR_name_size + 1);
+       strncpy(fname, h + AR_name_offset, AR_name_size);
+       fname[AR_name_size] = '\0';
+
+       if ((p = strchr(fname, '/')) != NULL) {
+               /* SVR4/GNU format */
+               *p = '\0';
+               archive_entry_copy_pathname(entry, fname);
+               free(fname);
+               fname = NULL;
+               goto remain;
+       }
+
+       /* BSD format */
+       if ((p = strchr(fname, ' ')) != NULL)
+               *p = '\0';
+       archive_entry_copy_pathname(entry, fname);
+       free(fname);
+       fname = NULL;
+
+remain:
+       /* Copy remaining header */
+       archive_entry_set_mtime(entry,
+           ar_atol10(h + AR_date_offset, AR_date_size), 0);
+       archive_entry_set_uid(entry,
+           ar_atol10(h + AR_uid_offset, AR_uid_size));
+       archive_entry_set_gid(entry,
+           ar_atol10(h + AR_gid_offset, AR_gid_size));
+       archive_entry_set_mode(entry,
+           ar_atol8(h + AR_mode_offset, AR_mode_size));
+       nval = ar_atol10(h + AR_size_offset, AR_size_size);
+
+       ar->entry_offset = 0;
+       ar->entry_padding = nval % 2;
+
+       /*
+        * For BSD variant, we should subtract the length of
+        * the appended filename string from ar_size to get the
+        * real file size. But remember we should do this only
+        * after we had calculated the padding.
+        */
+       if (bsd_append > 0)
+               nval -= bsd_append;
+
+       archive_entry_set_size(entry, nval);
+       ar->entry_bytes_remaining = nval;
+
+       return (ARCHIVE_OK);
+}
+
+static int
+archive_read_format_ar_read_data(struct archive_read *a,
+    const void **buff, size_t *size, off_t *offset)
+{
+       ssize_t bytes_read;
+       struct ar *ar;
+
+       ar = (struct ar *)*(a->pformat_data);
+
+       if (ar->entry_bytes_remaining > 0) {
+               bytes_read = (a->compression_read_ahead)(a, buff, 1);
+               if (bytes_read == 0) {
+                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                           "Truncated ar archive");
+                       return (ARCHIVE_FATAL);
+               }
+               if (bytes_read < 0)
+                       return (ARCHIVE_FATAL);
+               if (bytes_read > ar->entry_bytes_remaining)
+                       bytes_read = ar->entry_bytes_remaining;
+               *size = bytes_read;
+               *offset = ar->entry_offset;
+               ar->entry_offset += bytes_read;
+               ar->entry_bytes_remaining -= bytes_read;
+               (a->compression_read_consume)(a, bytes_read);
+               return (ARCHIVE_OK);
+       } else {
+               while (ar->entry_padding > 0) {
+                       bytes_read = (a->compression_read_ahead)(a, buff, 1);
+                       if (bytes_read <= 0)
+                               return (ARCHIVE_FATAL);
+                       if (bytes_read > ar->entry_padding)
+                               bytes_read = ar->entry_padding;
+                       (a->compression_read_consume)(a, bytes_read);
+                       ar->entry_padding -= bytes_read;
+               }
+               *buff = NULL;
+               *size = 0;
+               *offset = ar->entry_offset;
+               return (ARCHIVE_EOF);
+       }
+}
+
+static int
+archive_read_format_ar_skip(struct archive_read *a)
+{
+       off_t bytes_skipped;
+       struct ar* ar;
+       int r = ARCHIVE_OK;
+       const void *b;          /* Dummy variables */
+       size_t s;
+       off_t o;
+
+       ar = (struct ar *)*(a->pformat_data);
+       if (a->compression_skip == NULL) {
+               while (r == ARCHIVE_OK)
+                       r = archive_read_format_ar_read_data(a, &b, &s, &o);
+               return (r);
+       }
+
+       bytes_skipped = (a->compression_skip)(a, ar->entry_bytes_remaining +
+           ar->entry_padding);
+       if (bytes_skipped < 0)
+               return (ARCHIVE_FATAL);
+
+       ar->entry_bytes_remaining = 0;
+       ar->entry_padding = 0;
+
+       return (ARCHIVE_OK);
+}
+
+static int
+ar_parse_string_table(struct archive_read *a, struct ar *ar,
+    const void *h, ssize_t size)
+{
+       char *p;
+
+       if (ar->has_strtab > 0) {
+               archive_set_error(&a->archive, EINVAL,
+                   "More than one string tables exist");
+               return (ARCHIVE_WARN);
+       }
+
+       ar->strtab = (char *)malloc(size);
+       if (ar->strtab == NULL) {
+               archive_set_error(&a->archive, ENOMEM,
+                   "Can't allocate string table buffer");
+               return (ARCHIVE_FATAL);
+       }
+
+       (void)memcpy(ar->strtab, h, size);
+       p = ar->strtab;
+       while (p < ar->strtab + size - 1) {
+               if (*p == '/') {
+                       *p++ = '\0';
+                       if (*p == '\n')
+                               *p++ = '\0';
+                       else {
+                               archive_set_error(&a->archive, EINVAL,
+                                   "Invalid string table");
+                               free(ar->strtab);
+                               return (ARCHIVE_WARN);
+                       }
+               } else
+                       p++;
+       }
+       /*
+        * Sanity check, last two chars must be `/\n' or '\n\n',
+        * depending on whether the string table is padded by a '\n'
+        * (string table produced by GNU ar always has a even size).
+        */
+       if (p != ar->strtab + size && *p != '\n') {
+               archive_set_error(&a->archive, EINVAL,
+                   "Invalid string table");
+               free(ar->strtab);
+               return (ARCHIVE_WARN);
+       }
+
+       ar->has_strtab = 1;
+       return (ARCHIVE_OK);
+}
+
+static int64_t
+ar_atol8(const char *p, unsigned char_cnt)
+{
+       int64_t l, limit, last_digit_limit;
+       int digit, sign, base;
+
+       base = 8;
+       limit = max_int64 / base;
+       last_digit_limit = max_int64 % base;
+
+       while (*p == ' ' || *p == '\t')
+               p++;
+       if (*p == '-') {
+               sign = -1;
+               p++;
+       } else
+               sign = 1;
+
+       l = 0;
+       digit = *p - '0';
+       while (digit >= 0 && digit < base  && char_cnt-- > 0) {
+               if (l>limit || (l == limit && digit > last_digit_limit)) {
+                       l = max_uint64; /* Truncate on overflow. */
+                       break;
+               }
+               l = (l * base) + digit;
+               digit = *++p - '0';
+       }
+       return (sign < 0) ? -l : l;
+}
+
+static int64_t
+ar_atol10(const char *p, unsigned char_cnt)
+{
+       int64_t l, limit, last_digit_limit;
+       int base, digit, sign;
+
+       base = 10;
+       limit = max_int64 / base;
+       last_digit_limit = max_int64 % base;
+
+       while (*p == ' ' || *p == '\t')
+               p++;
+       if (*p == '-') {
+               sign = -1;
+               p++;
+       } else
+               sign = 1;
+
+       l = 0;
+       digit = *p - '0';
+       while (digit >= 0 && digit < base  && char_cnt-- > 0) {
+               if (l > limit || (l == limit && digit > last_digit_limit)) {
+                       l = max_uint64; /* Truncate on overflow. */
+                       break;
+               }
+               l = (l * base) + digit;
+               digit = *++p - '0';
+       }
+       return (sign < 0) ? -l : l;
+}
index c053797..b57ac56 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_tar.c,v 1.50 2007/03/31 22:59:43 cperciva Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_tar.c,v 1.52 2007/04/03 23:53:55 cperciva Exp $");
 
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
@@ -524,15 +524,9 @@ archive_read_format_tar_read_data(struct archive_read *a,
                (a->compression_read_consume)(a, bytes_read);
                return (ARCHIVE_OK);
        } else {
-               while (tar->entry_padding > 0) {
-                       bytes_read = (a->compression_read_ahead)(a, buff, 1);
-                       if (bytes_read <= 0)
-                               return (ARCHIVE_FATAL);
-                       if (bytes_read > tar->entry_padding)
-                               bytes_read = tar->entry_padding;
-                       (a->compression_read_consume)(a, bytes_read);
-                       tar->entry_padding -= bytes_read;
-               }
+               if ((a->compression_skip)(a, tar->entry_padding) < 0)
+                       return (ARCHIVE_FATAL);
+               tar->entry_padding = 0;
                *buff = NULL;
                *size = 0;
                *offset = tar->entry_offset;
@@ -1301,6 +1295,10 @@ pax_attribute(struct archive_entry *entry, struct stat *st,
                            tar_atol10(value, wcslen(value)));
                else if (wcscmp(key, L"SCHILY.fflags")==0)
                        archive_entry_copy_fflags_text_w(entry, value);
+               else if (wcscmp(key, L"SCHILY.dev")==0)
+                       st->st_dev = tar_atol10(value, wcslen(value));
+               else if (wcscmp(key, L"SCHILY.ino")==0)
+                       st->st_ino = tar_atol10(value, wcslen(value));
                else if (wcscmp(key, L"SCHILY.nlink")==0)
                        st->st_nlink = tar_atol10(value, wcslen(value));
                break;
diff --git a/contrib/libarchive-2.0/libarchive/archive_write_disk.3 b/contrib/libarchive-2.0/libarchive/archive_write_disk.3
new file mode 100644 (file)
index 0000000..880a399
--- /dev/null
@@ -0,0 +1,358 @@
+.\" Copyright (c) 2003-2007 Tim Kientzle
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libarchive/archive_write_disk.3,v 1.1 2007/03/03 07:37:36 kientzle Exp $
+.\"
+.Dd March 2, 2007
+.Dt archive_write_disk 3
+.Os
+.Sh NAME
+.Nm archive_write_disk_new ,
+.Nm archive_write_disk_set_options ,
+.Nm archive_write_disk_set_skip_file ,
+.Nm archive_write_disk_set_group_lookup ,
+.Nm archive_write_disk_set_standard_lookup ,
+.Nm archive_write_disk_set_user_lookup ,
+.Nm archive_write_header ,
+.Nm archive_write_data ,
+.Nm archive_write_finish_entry ,
+.Nm archive_write_close ,
+.Nm archive_write_finish
+.Nd functions for creating objects on disk
+.Sh SYNOPSIS
+.In archive.h
+.Ft struct archive *
+.Fn archive_write_disk_new "void"
+.Ft int
+.Fn archive_write_disk_set_options "struct archive *" "int flags"
+.Ft int
+.Fn archive_write_disk_set_skip_file "struct archive *" "dev_t" "ino_t"
+.Ft int
+.Fn archive_write_disk_set_group_lookup "struct archive *" "void *" "gid_t (*)(void *, const char *gname, gid_t gid)" "void (*cleanup)(void *)"
+.Ft int
+.Fn archive_write_disk_set_standard_lookup "struct archive *"
+.Ft int
+.Fn archive_write_disk_set_user_lookup "struct archive *" "void *" "uid_t (*)(void *, const char *uname, uid_t uid)" "void (*cleanup)(void *)"
+.Ft int
+.Fn archive_write_header "struct archive *" "struct archive_entry *"
+.Ft ssize_t
+.Fn archive_write_data "struct archive *" "const void *" "size_t"
+.Ft int
+.Fn archive_write_finish_entry "struct archive *"
+.Ft int
+.Fn archive_write_close "struct archive *"
+.Ft int
+.Fn archive_write_finish "struct archive *"
+.Sh DESCRIPTION
+These functions provide a complete API for creating objects on
+disk from
+.Tn struct archive_entry
+descriptions.
+They are most naturally used when extracting objects from an archive
+using the
+.Fn archive_read
+interface.
+The general process is to read
+.Tn struct archive_entry
+objects from an archive, then write those objects to a
+.Tn struct archive
+object created using the
+.Fn archive_write_disk
+family functions.
+This interface is deliberately very similar to the
+.Fn archive_write
+interface used to write objects to a streaming archive.
+.Bl -tag -width indent
+.It Fn archive_write_disk_new
+Allocates and initializes a
+.Tn struct archive
+object suitable for writing objects to disk.
+.It Fn archive_write_disk_set_skip_file
+Records the device and inode numbers of a file that should not be
+overwritten.
+This is typically used to ensure that an extraction process does not
+overwrite the archive from which objects are being read.
+This capability is technically unnecessary but can be a significant
+performance optimization in practice.
+.It Fn archive_write_disk_set_options
+The options field consists of a bitwise OR of one or more of the
+following values:
+.Bl -tag -compact -width "indent"
+.It Cm ARCHIVE_EXTRACT_OWNER
+The user and group IDs should be set on the restored file.
+By default, the user and group IDs are not restored.
+.It Cm ARCHIVE_EXTRACT_PERM
+Full permissions (including SGID, SUID, and sticky bits) should
+be restored exactly as specified, without obeying the
+current umask.
+Note that SUID and SGID bits can only be restored if the
+user and group ID of the object on disk are correct.
+If
+.Cm ARCHIVE_EXTRACT_OWNER
+is not specified, then SUID and SGID bits will only be restored
+if the default user and group IDs of newly-created objects on disk
+happen to match those specified in the archive entry.
+By default, only basic permissions are restored, and umask is obeyed.
+.It Cm ARCHIVE_EXTRACT_TIME
+The timestamps (mtime, ctime, and atime) should be restored.
+By default, they are ignored.
+Note that restoring of atime is not currently supported.
+.It Cm ARCHIVE_EXTRACT_NO_OVERWRITE
+Existing files on disk will not be overwritten.
+By default, existing regular files are truncated and overwritten;
+existing directories will have their permissions updated;
+other pre-existing objects are unlinked and recreated from scratch.
+.It Cm ARCHIVE_EXTRACT_UNLINK
+Existing files on disk will be unlinked before any attempt to
+create them.
+In some cases, this can prove to be a significant performance improvement.
+By default, existing files are truncated and rewritten, but
+the file is not recreated.
+In particular, the default behavior does not break existing hard links.
+.It Cm ARCHIVE_EXTRACT_ACL
+Attempt to restore ACLs.
+By default, extended ACLs are ignored.
+.It Cm ARCHIVE_EXTRACT_FFLAGS
+Attempt to restore extended file flags.
+By default, file flags are ignored.
+.It Cm ARCHIVE_EXTRACT_XATTR
+Attempt to restore POSIX.1e extended attributes.
+By default, they are ignored.
+.It Cm ARCHIVE_EXTRACT_SECURE_SYMLINKS
+Refuse to extract any object whose final location would be altered
+by a symlink on disk.
+This is intended to help guard against a variety of mischief
+caused by archives that (deliberately or otherwise) extract
+files outside of the current directory.
+The default is not to perform this check.
+If
+.Cm ARCHIVE_EXTRACT_UNLINK
+is specified together with this option, the library will
+remove any intermediate symlinks it finds and return an
+error only if such symlink could not be removed.
+.It Cm ARCHIVE_EXTRACT_SECURE_NODOTDOT
+Refuse to extract a path that contains a
+.Pa ..
+element anywhere within it.
+The default is to not refuse such paths.
+Note that paths ending in
+.Pa ..
+always cause an error, regardless of this flag.
+.El
+.It Fn archive_write_disk_set_group_lookup , Fn archive_write_disk_set_user_lookup
+The
+.Tn struct archive_entry
+objects contain both names and ids that can be used to identify users
+and groups.
+These names and ids describe the ownership of the file itself and
+also appear in ACL lists.
+By default, the library uses the ids and ignores the names, but
+this can be overridden by registering user and group lookup functions.
+To register, you must provide a lookup function which
+accepts both a name and id and returns a suitable id.
+You may also provide a
+.Tn void *
+pointer to a private data structure and a cleanup function for
+that data.
+The cleanup function will be invoked when the
+.Tn struct archive
+object is destroyed.
+.It Fn archive_write_disk_set_standard_lookup
+This convenience function installs a standard set of user
+and group lookup functions.
+These functions use
+.Xr getpwnam 3
+and
+.Xr getgrnam 3
+to convert names to ids, defaulting to the ids if the names cannot
+be looked up.
+These functions also implement a simple memory cache to reduce
+the number of calls to
+.Xr getpwnam 3
+and
+.Xr getgrnam 3 .
+.It Fn archive_write_header
+Build and write a header using the data in the provided
+.Tn struct archive_entry
+structure.
+See
+.Xr archive_entry 3
+for information on creating and populating
+.Tn struct archive_entry
+objects.
+.It Fn archive_write_data
+Write data corresponding to the header just written.
+Returns number of bytes written or -1 on error.
+.It Fn archive_write_finish_entry
+Close out the entry just written.
+Ordinarily, clients never need to call this, as it
+is called automatically by
+.Fn archive_write_next_header
+and
+.Fn archive_write_close
+as needed.
+.It Fn archive_write_close
+Set any attributes that could not be set during the initial restore.
+For example, directory timestamps are not restored initially because
+restoring a subsequent file would alter that timestamp.
+Similarly, non-writable directories are initially created with
+write permissions (so that their contents can be restored).
+The
+.Nm
+library maintains a list of all such deferred attributes and
+sets them when this function is invoked.
+.It Fn archive_write_finish
+Invokes
+.Fn archive_write_close
+if it was not invoked manually, then releases all resources.
+.El
+More information about the
+.Va struct archive
+object and the overall design of the library can be found in the
+.Xr libarchive 3
+overview.
+Many of these functions are also documented under
+.Xr archive_write 3 .
+.Sh RETURN VALUES
+Most functions return
+.Cm ARCHIVE_OK
+(zero) on success, or one of several non-zero
+error codes for errors.
+Specific error codes include:
+.Cm ARCHIVE_RETRY
+for operations that might succeed if retried,
+.Cm ARCHIVE_WARN
+for unusual conditions that do not prevent further operations, and
+.Cm ARCHIVE_FATAL
+for serious errors that make remaining operations impossible.
+The
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions can be used to retrieve an appropriate error code and a
+textual error message.
+.Pp
+.Fn archive_write_disk_new
+returns a pointer to a newly-allocated
+.Tn struct archive
+object.
+.Pp
+.Fn archive_write_data
+returns a count of the number of bytes actually written.
+On error, -1 is returned and the
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions will return appropriate values.
+.Sh SEE ALSO
+.Xr archive_read 3 ,
+.Xr archive_write 3 ,
+.Xr tar 1 ,
+.Xr libarchive 3
+.Sh HISTORY
+The
+.Nm libarchive
+library first appeared in
+.Fx 5.3 .
+The
+.Nm archive_write_disk
+interface was added to
+.Nm libarchive 2.0
+and first appeared in
+.Fx 6.3 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm libarchive
+library was written by
+.An Tim Kientzle Aq kientzle@acm.org .
+.Sh BUGS
+Directories are actually extracted in two distinct phases.
+Directories are created during
+.Fn archive_write_header ,
+but final permissions are not set until
+.Fn archive_write_close .
+This separation is necessary to correctly handle borderline
+cases such as a non-writable directory containing
+files, but can cause unexpected results.
+In particular, directory permissions are not fully
+restored until the archive is closed.
+If you use
+.Xr chdir 2
+to change the current directory between calls to
+.Fn archive_read_extract
+or before calling
+.Fn archive_read_close ,
+you may confuse the permission-setting logic with
+the result that directory permissions are restored
+incorrectly.
+.Pp
+The library attempts to create objects with filenames longer than
+.Cm PATH_MAX
+by creating prefixes of the full path and changing the current directory.
+Currently, this logic is limited in scope; the fixup pass does
+not work correctly for such objects and the symlink security check
+option disables the support for very long pathnames.
+.Pp
+Restoring the path
+.Pa aa/../bb
+does create each intermediate directory.
+In particular, the directory
+.Pa aa
+is created as well as the final object
+.Pa bb .
+In theory, this can be exploited to create an entire directory heirarchy
+with a single request.
+Of course, this does not work if the
+.Cm ARCHIVE_EXTRACT_NODOTDOT
+option is specified.
+.Pp
+Implicit directories are always created obeying the current umask.
+Explicit objects are created obeying the current umask unless
+.Cm ARCHIVE_EXTRACT_PERM
+is specified, in which case they current umask is ignored.
+.Pp
+SGID and SUID bits are restored only if the correct user and
+group could be set.
+If
+.Cm ARCHIVE_EXTRACT_OWNER
+is not specified, then no attempt is made to set the ownership.
+In this case, SGID and SUID bits are restored only if the
+user and group of the final object happen to match those specified
+in the entry.
+.Pp
+The
+.Dq standard
+user-id and group-id lookup functions are not the defaults because
+.Xr getgrnam 3
+and
+.Xr getpwnam 3
+are sometimes too large for particular applications.
+The current design allows the application author to use a more
+compact implementation when appropriate.
+.Pp
+There should be a corresponding
+.Nm archive_read_disk
+interface that walks a directory heirarchy and returns archive
+entry objects.
\ No newline at end of file
diff --git a/contrib/libarchive-2.0/libarchive/archive_write_set_format_ar.c b/contrib/libarchive-2.0/libarchive/archive_write_set_format_ar.c
new file mode 100644 (file)
index 0000000..714b489
--- /dev/null
@@ -0,0 +1,492 @@
+/*-
+ * Copyright (c) 2007 Kai Wang
+ * Copyright (c) 2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_ar.c,v 1.1 2007/04/03 05:34:36 kientzle Exp $");
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+#include "archive_write_private.h"
+
+struct ar_w {
+       uint64_t         entry_bytes_remaining;
+       uint64_t         entry_padding;
+       int              is_strtab;
+       int              has_strtab;
+       char            *strtab;
+};
+
+/*
+ * Define structure of the "ar" header.
+ */
+#define AR_name_offset 0
+#define AR_name_size 16
+#define AR_date_offset 16
+#define AR_date_size 12
+#define AR_uid_offset 28
+#define AR_uid_size 6
+#define AR_gid_offset 34
+#define AR_gid_size 6
+#define AR_mode_offset 40
+#define AR_mode_size 8
+#define AR_size_offset 48
+#define AR_size_size 10
+#define AR_fmag_offset 58
+#define AR_fmag_size 2
+
+/*
+ * "ar" magic numbers.
+ */
+#define        ARMAG           "!<arch>\n"
+#define        SARMAG          8               /* strlen(ARMAG); */
+#define        AR_EFMT1        "#1/"
+#define        SAR_EFMT1       3               /* strlen(AR_EFMT1); */
+#define        ARFMAG          "`\n"
+#define        SARFMAG         2               /* strlen(ARFMAG); */
+
+static int     __archive_write_set_format_ar(struct archive_write *);
+static int     archive_write_ar_header(struct archive_write *,
+                   struct archive_entry *);
+static ssize_t archive_write_ar_data(struct archive_write *, const void *buff,
+                   size_t s);
+static int     archive_write_ar_destroy(struct archive_write *);
+static int     archive_write_ar_finish_entry(struct archive_write *);
+static int     format_octal(int64_t v, char *p, int s);
+static int     format_decimal(int64_t v, char *p, int s);
+
+int
+archive_write_set_format_ar_bsd(struct archive *_a)
+{
+       struct archive_write *a = (struct archive_write *)_a;
+       int r = __archive_write_set_format_ar(a);
+       if (r == ARCHIVE_OK) {
+               a->archive_format = ARCHIVE_FORMAT_AR_BSD;
+               a->archive_format_name = "ar (BSD)";
+       }
+       return (r);
+}
+
+int
+archive_write_set_format_ar_svr4(struct archive *_a)
+{
+       struct archive_write *a = (struct archive_write *)_a;
+       int r = __archive_write_set_format_ar(a);
+       if (r == ARCHIVE_OK) {
+               a->archive_format = ARCHIVE_FORMAT_AR_SVR4;
+               a->archive_format_name = "ar (GNU/SVR4)";
+       }
+       return (r);
+}
+
+/*
+ * Generic initialization.
+ */
+static int
+__archive_write_set_format_ar(struct archive_write *a)
+{
+       struct ar_w *ar;
+
+       /* If someone else was already registered, unregister them. */
+       if (a->format_destroy != NULL)
+               (a->format_destroy)(a);
+
+       ar = (struct ar_w *)malloc(sizeof(*ar));
+       if (ar == NULL) {
+               archive_set_error(&a->archive, ENOMEM, "Can't allocate ar data");
+               return (ARCHIVE_FATAL);
+       }
+       memset(ar, 0, sizeof(*ar));
+       a->format_data = ar;
+
+       a->format_write_header = archive_write_ar_header;
+       a->format_write_data = archive_write_ar_data;
+       a->format_finish = NULL;
+       a->format_destroy = archive_write_ar_destroy;
+       a->format_finish_entry = archive_write_ar_finish_entry;
+       return (ARCHIVE_OK);
+}
+
+static int
+archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
+{
+       int ret, append_fn;
+       char buff[60];
+       char *ss, *se;
+       struct ar_w *ar;
+       const char *pp;
+       const struct stat *st;
+
+       ret = 0;
+       append_fn = 0;
+       ar = (struct ar_w *)a->format_data;
+       ar->is_strtab = 0;
+
+       if (a->archive.file_position == 0) {
+               /*
+                * We are now at the beginning of the archive,
+                * so we need first write the ar global header.
+                */
+               (a->compression_write)(a, ARMAG, SARMAG);
+       }
+
+       memset(buff, ' ', 60);
+       strncpy(&buff[AR_fmag_offset], ARFMAG, SARFMAG);
+
+       pp = archive_entry_pathname(entry);
+
+       if (strcmp(pp, "/") == 0 ) {
+               /* Entry is archive symbol table in GNU format */
+               buff[AR_name_offset] = '/';
+               goto stat;
+       }
+       if (strcmp(pp, "__.SYMDEF") == 0) {
+               /* Entry is archive symbol table in BSD format */
+               strncpy(buff + AR_name_offset, "__.SYMDEF", 9);
+               goto stat;
+       }
+       if (strcmp(pp, "//") == 0) {
+               /*
+                * Entry is archive string table, inform that we should
+                * collect strtab in next _data call.
+                */
+               ar->is_strtab = 1;
+               buff[AR_name_offset] = buff[AR_name_offset + 1] = '/';
+               /*
+                * For archive string table, only ar_size filed should
+                * be set.
+                */
+               goto size;
+       }
+
+       /* Otherwise, entry is a normal archive member. */
+       if (a->archive_format == ARCHIVE_FORMAT_AR_SVR4) {
+               /*
+                * SVR4/GNU variant use a "/" to mark then end of the filename,
+                * make it possible to have embedded spaces in the filename.
+                * So, the longest filename here (without extension) is
+                * actually 15 bytes.
+                */
+               if (strlen(pp) <= 15) {
+                       strncpy(&buff[AR_name_offset], pp, strlen(pp));
+                       buff[AR_name_offset + strlen(pp)] = '/';
+               } else {
+                       /*
+                        * For filename longer than 15 bytes, GNU variant
+                        * makes use of a string table and instead stores the
+                        * offset of the real filename to in the ar_name field.
+                        * The string table should have been written before.
+                        */
+                       if (ar->has_strtab <= 0) {
+                               archive_set_error(&a->archive, EINVAL,
+                                   "Can't find string table");
+                               return (ARCHIVE_WARN);
+                       }
+
+                       se = (char *)malloc(strlen(pp) + 3);
+                       if (se == NULL) {
+                               archive_set_error(&a->archive, ENOMEM,
+                                   "Can't allocate filename buffer");
+                               return (ARCHIVE_FATAL);
+                       }
+
+                       strncpy(se, pp, strlen(pp));
+                       strcpy(se + strlen(pp), "/\n");
+
+                       ss = strstr(ar->strtab, se);
+                       free(se);
+
+                       if (ss == NULL) {
+                               archive_set_error(&a->archive, EINVAL,
+                                   "Invalid string table");
+                               return (ARCHIVE_WARN);
+                       }
+
+                       /*
+                        * GNU variant puts "/" followed by digits into
+                        * ar_name field. These digits indicates the real
+                        * filename string's offset to the string table.
+                        */
+                       buff[AR_name_offset] = '/';
+                       if (format_decimal(ss - ar->strtab,
+                           buff + AR_name_offset + 1,
+                           AR_name_size - 1)) {
+                               archive_set_error(&a->archive, ERANGE,
+                                   "string table offset too large");
+                               return (ARCHIVE_WARN);
+                       }
+               }
+       } else if (a->archive_format == ARCHIVE_FORMAT_AR_BSD) {
+               /*
+                * BSD variant: for any file name which is more than
+                * 16 chars or contains one or more embedded space(s), the
+                * string "#1/" followed by the ASCII length of the name is
+                * put into the ar_name field. The file size (stored in the
+                * ar_size field) is incremented by the length of the name.
+                * The name is then written immediately following the
+                * archive header.
+                */
+               if (strlen(pp) <= 16 && strchr(pp, ' ') == NULL) {
+                       strncpy(&buff[AR_name_offset], pp, strlen(pp));
+                       buff[AR_name_offset + strlen(pp)] = ' ';
+               }
+               else {
+                       strncpy(buff + AR_name_offset, AR_EFMT1, SAR_EFMT1);
+                       if (format_decimal(strlen(pp),
+                           buff + AR_name_offset + SAR_EFMT1,
+                           AR_name_size - SAR_EFMT1)) {
+                               archive_set_error(&a->archive, ERANGE,
+                                   "File name too long");
+                               return (ARCHIVE_WARN);
+                       }
+                       append_fn = 1;
+                       archive_entry_set_size(entry,
+                           archive_entry_size(entry) + strlen(pp));
+               }
+       }
+
+stat:
+       st = archive_entry_stat(entry);
+       if (format_decimal(st->st_mtime, buff + AR_date_offset, AR_date_size)) {
+               archive_set_error(&a->archive, ERANGE,
+                   "File modification time too large");
+               return (ARCHIVE_WARN);
+       }
+       if (format_decimal(st->st_uid, buff + AR_uid_offset, AR_uid_size)) {
+               archive_set_error(&a->archive, ERANGE,
+                   "Numeric user ID too large");
+               return (ARCHIVE_WARN);
+       }
+       if (format_decimal(st->st_gid, buff + AR_gid_offset, AR_gid_size)) {
+               archive_set_error(&a->archive, ERANGE,
+                   "Numeric group ID too large");
+               return (ARCHIVE_WARN);
+       }
+       if (format_octal(st->st_mode, buff + AR_mode_offset, AR_mode_size)) {
+               archive_set_error(&a->archive, ERANGE,
+                   "Numeric mode too large");
+               return (ARCHIVE_WARN);
+       }
+
+size:
+       if (format_decimal(archive_entry_size(entry), buff + AR_size_offset,
+           AR_size_size)) {
+               archive_set_error(&a->archive, ERANGE,
+                   "File size out of range");
+               return (ARCHIVE_WARN);
+       }
+
+       ret = (a->compression_write)(a, buff, 60);
+       if (ret != ARCHIVE_OK)
+               return (ret);
+
+       ar->entry_bytes_remaining = archive_entry_size(entry);
+       ar->entry_padding = ar->entry_bytes_remaining % 2;
+
+       if (append_fn > 0) {
+               ret = (a->compression_write)(a, pp, strlen(pp));
+               if (ret != ARCHIVE_OK)
+                       return (ret);
+               ar->entry_bytes_remaining -= strlen(pp);
+       }
+
+       return (ARCHIVE_OK);
+}
+
+static ssize_t
+archive_write_ar_data(struct archive_write *a, const void *buff, size_t s)
+{
+       struct ar_w *ar;
+       int ret;
+
+       ar = (struct ar_w *)a->format_data;
+       if (s > ar->entry_bytes_remaining)
+               s = ar->entry_bytes_remaining;
+
+       if (ar->is_strtab > 0) {
+               if (ar->has_strtab > 0) {
+                       archive_set_error(&a->archive, EINVAL,
+                           "More than one string tables exist");
+                       return (ARCHIVE_WARN);
+               }
+
+               ar->strtab = (char *)malloc(s);
+               if (ar->strtab == NULL) {
+                       archive_set_error(&a->archive, ENOMEM,
+                           "Can't allocate strtab buffer");
+                       return (ARCHIVE_FATAL);
+               }
+               strncpy(ar->strtab, buff, s);
+               ar->has_strtab = 1;
+       }
+
+       ret = (a->compression_write)(a, buff, s);
+       if (ret != ARCHIVE_OK)
+               return (ret);
+
+       ar->entry_bytes_remaining -= s;
+       return (s);
+}
+
+static int
+archive_write_ar_destroy(struct archive_write *a)
+{
+       struct ar_w *ar;
+
+       ar = (struct ar_w *)a->format_data;
+
+       if (ar->has_strtab > 0) {
+               free(ar->strtab);
+               ar->strtab = NULL;
+       }
+
+       free(ar);
+       a->format_data = NULL;
+       return (ARCHIVE_OK);
+}
+
+static int
+archive_write_ar_finish_entry(struct archive_write *a)
+{
+       struct ar_w *ar;
+       int ret;
+
+       ar = (struct ar_w *)a->format_data;
+
+       if (ar->entry_bytes_remaining != 0) {
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                   "Entry remaining bytes larger than 0");
+               return (ARCHIVE_WARN);
+       }
+
+       if (ar->entry_padding == 0) {
+               return (ARCHIVE_OK);
+       }
+
+       if (ar->entry_padding != 1) {
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                   "Padding wrong size: %d should be 1 or 0",
+                   ar->entry_padding);
+               return (ARCHIVE_WARN);
+       }
+
+       ret = (a->compression_write)(a, "\n", 1);
+       return (ret);
+}
+
+/*
+ * Format a number into the specified field using base-8.
+ * NB: This version is slightly different from the one in
+ * _ustar.c
+ */
+static int
+format_octal(int64_t v, char *p, int s)
+{
+       int len;
+       char *h;
+
+       len = s;
+       h = p;
+
+       /* Octal values can't be negative, so use 0. */
+       if (v < 0) {
+               while (len-- > 0)
+                       *p++ = '0';
+               return (-1);
+       }
+
+       p += s;         /* Start at the end and work backwards. */
+       do {
+               *--p = (char)('0' + (v & 7));
+               v >>= 3;
+       } while (--s > 0 && v > 0);
+
+       if (v == 0) {
+               memmove(h, p, len - s);
+               p = h + len - s;
+               while (s-- > 0)
+                       *p++ = ' ';
+               return (0);
+       }
+       /* If it overflowed, fill field with max value. */
+       while (len-- > 0)
+               *p++ = '7';
+
+       return (-1);
+}
+
+/*
+ * Format a number into the specified field using base-10.
+ */
+static int
+format_decimal(int64_t v, char *p, int s)
+{
+       int len;
+       char *h;
+
+       len = s;
+       h = p;
+
+       /* Negative values in ar header are meaningless , so use 0. */
+       if (v < 0) {
+               while (len-- > 0)
+                       *p++ = '0';
+               return (-1);
+       }
+
+       p += s;
+       do {
+               *--p = (char)('0' + (v % 10));
+               v /= 10;
+       } while (--s > 0 && v > 0);
+
+       if (v == 0) {
+               memmove(h, p, len - s);
+               p = h + len - s;
+               while (s-- > 0)
+                       *p++ = ' ';
+               return (0);
+       }
+       /* If it overflowed, fill field with max value. */
+       while (len-- > 0)
+               *p++ = '9';
+
+       return (-1);
+}
index 1b134e6..cd34622 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/libarchive-formats.5,v 1.12 2007/01/09 08:05:56 kientzle Exp $
+.\" $FreeBSD: src/lib/libarchive/libarchive-formats.5,v 1.14 2007/04/05 05:07:53 kientzle Exp $
 .\"
 .Dd April 27, 2004
 .Dt libarchive-formats 3
@@ -235,7 +235,20 @@ compressed with the
 .Dq deflate
 algorithm.
 Older zip compression algorithms are not supported.
+.Ss Archive (library) file format
+The Unix archive format (commonly created by the
+.Xr ar 1
+archiver) is a general-purpose format which is
+used almost exclusively for object files to be
+read by the link editor
+.Xr ld 1 .
+The ar format has never been standardised.
+There are two common variants:
+the GNU format derived from SVR4,
+and the BSD format, which first appeared in 4.4BSD.
+Libarchive provides read and write support for both variants.
 .Sh SEE ALSO
+.Xr ar 1 ,
 .Xr cpio 1 ,
 .Xr mkisofs 1 ,
 .Xr shar 1 ,
index 1a141bb..8649dcf 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "bsdtar_platform.h"
-__FBSDID("$FreeBSD: src/usr.bin/tar/read.c,v 1.28 2007/03/11 10:36:42 kientzle Exp $");
+__FBSDID("$FreeBSD: src/usr.bin/tar/read.c,v 1.29 2007/04/07 05:56:40 kientzle Exp $");
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
@@ -122,19 +122,17 @@ read_archive(struct bsdtar *bsdtar, char mode)
                r = archive_read_next_header(a, &entry);
                if (r == ARCHIVE_EOF)
                        break;
-               if (r == ARCHIVE_WARN)
+               if (r < ARCHIVE_OK)
                        bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a));
-               if (r == ARCHIVE_FATAL) {
-                       bsdtar->return_value = 1;
-                       bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a));
-                       break;
-               }
                if (r == ARCHIVE_RETRY) {
                        /* Retryable error: try again */
-                       bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a));
                        bsdtar_warnc(bsdtar, 0, "Retrying...");
                        continue;
                }
+               if (r != ARCHIVE_OK) {
+                       bsdtar->return_value = 1;
+                       break;
+               }
 
                /*
                 * Exclude entries that are too old.
index 7cc919f..650a6a5 100644 (file)
@@ -1 +1 @@
-2.0.27
\ No newline at end of file
+2.0.28
\ No newline at end of file