From: Peter Avalos Date: Sat, 17 May 2008 21:50:43 +0000 (+0000) Subject: Import libarchive-2.4.17. See NEWS for details. X-Git-Tag: v2.0.1~625^2 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/6ed811d1296a834a8cfceefbc894439d96863134 Import libarchive-2.4.17. See NEWS for details. --- diff --git a/contrib/libarchive-2/NEWS b/contrib/libarchive-2/NEWS index fb0e9e5004..991509e47d 100644 --- a/contrib/libarchive-2/NEWS +++ b/contrib/libarchive-2/NEWS @@ -1,3 +1,43 @@ +Mar 14, 2008: libarchive 2.4.14 released. This is identical to 2.4.13 + except it contains a one-line fix to the uname/gname problem + introduced by the Feb 25 UTF-8 fix. This bug makes libarchive + refuse to add a file to a pax archive if it has a valid gname + but not a valid uname. In some cases, it can also cause the + uname to be stored for the gname. + +Feb 26, 2008: libarchive 2.4.13 released +Feb 25, 2008: Handle path, linkname, gname, or uname that can't be converted + to/from UTF-8. Implement "hdrcharset" attribute from SUS-2008. +Feb 25, 2008: Fix name clash on NetBSD. +Feb 18, 2008: Fix writing empty 'ar' archives, per Kai Wang +Feb 18, 2008: [bsdtar] Permit appending on block devices. +Feb 09, 2008: New "linkify" resolver to help with newc hardlink writing; + bsdcpio still needs to be converted to use this. +Feb 02, 2008: Windows compatibility fixes from Ivailo Petrov, Kees Zeelenberg +Jan 30, 2008: Ignore hardlink size for non-POSIX tar archives. + +Jan 22, 2008: libarchive 2.4.12 released +Jan 22, 2008: Fix bad padding when writing symlinks to newc cpio archives. +Jan 22, 2008: Verify bsdcpio_test by getting it to work against GNU cpio 2.9. + bsdcpio_test complains about missing options (-y and -z), format + of informational messages (--version, --help), and a minor formatting + issue in odc format output. After this update, bsdcpio_test uncovered + several more cosmetic issues in bsdcpio, all now fixed. +Jan 22, 2008: Experimental support for self-extracting Zip archives. +Jan 22, 2008: Extend hardlink restore strategy to work correctly with + hardlinks extracted from newc cpio files. (Which store the body + only with the last occurrence of a link.) + +Dec 30, 2007: libarchive 2.4.11 released +Dec 30, 2007: Fixed a compile error in bsdcpio on some systems. + +Dec 29, 2007: libarchive 2.4.10 released +Dec 29, 2007: bsdcpio 0.9.0 is ready for wider use. +Dec 29, 2007: Completed initial test harness for bsdcpio. + +Dec 22, 2007: libarchive 2.4.9 released +Dec 22, 2007: Implement the remaining options for bsdcpio: -a, -q, -L, -f, + pattern selection for -i and -it. Dec 13, 2007: libarchive 2.4.8 released Dec 13, 2007: gzip and bzip2 compression now handle zero-byte writes correctly, diff --git a/contrib/libarchive-2/libarchive/archive.h.in b/contrib/libarchive-2/libarchive/archive.h.in index e21a7105e7..d76c85e51b 100644 --- a/contrib/libarchive-2/libarchive/archive.h.in +++ b/contrib/libarchive-2/libarchive/archive.h.in @@ -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.46 2007/07/06 15:36:37 kientzle Exp $ + * $FreeBSD: src/lib/libarchive/archive.h.in,v 1.47 2007/12/30 04:58:21 kientzle Exp $ */ #ifndef ARCHIVE_H_INCLUDED diff --git a/contrib/libarchive-2/libarchive/archive_endian.h b/contrib/libarchive-2/libarchive/archive_endian.h new file mode 100644 index 0000000000..259f5de91e --- /dev/null +++ b/contrib/libarchive-2/libarchive/archive_endian.h @@ -0,0 +1,142 @@ +/*- + * Copyright (c) 2002 Thomas Moestl + * 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_endian.h,v 1.2 2008/02/26 07:17:47 kientzle Exp $ + * + * Borrowed from FreeBSD's + */ + +#ifndef ARCHIVE_ENDIAN_H_INCLUDED +#define ARCHIVE_ENDIAN_H_INCLUDED + +/* Alignment-agnostic encode/decode bytestream to/from little/big endian. */ + +static inline uint16_t +archive_be16dec(const void *pp) +{ + unsigned char const *p = (unsigned char const *)pp; + + return ((p[0] << 8) | p[1]); +} + +static inline uint32_t +archive_be32dec(const void *pp) +{ + unsigned char const *p = (unsigned char const *)pp; + + return ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); +} + +static inline uint64_t +archive_be64dec(const void *pp) +{ + unsigned char const *p = (unsigned char const *)pp; + + return (((uint64_t)archive_be32dec(p) << 32) | archive_be32dec(p + 4)); +} + +static inline uint16_t +archive_le16dec(const void *pp) +{ + unsigned char const *p = (unsigned char const *)pp; + + return ((p[1] << 8) | p[0]); +} + +static inline uint32_t +archive_le32dec(const void *pp) +{ + unsigned char const *p = (unsigned char const *)pp; + + return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]); +} + +static inline uint64_t +archive_le64dec(const void *pp) +{ + unsigned char const *p = (unsigned char const *)pp; + + return (((uint64_t)archive_le32dec(p + 4) << 32) | archive_le32dec(p)); +} + +static inline void +archive_be16enc(void *pp, uint16_t u) +{ + unsigned char *p = (unsigned char *)pp; + + p[0] = (u >> 8) & 0xff; + p[1] = u & 0xff; +} + +static inline void +archive_be32enc(void *pp, uint32_t u) +{ + unsigned char *p = (unsigned char *)pp; + + p[0] = (u >> 24) & 0xff; + p[1] = (u >> 16) & 0xff; + p[2] = (u >> 8) & 0xff; + p[3] = u & 0xff; +} + +static inline void +archive_be64enc(void *pp, uint64_t u) +{ + unsigned char *p = (unsigned char *)pp; + + archive_be32enc(p, u >> 32); + archive_be32enc(p + 4, u & 0xffffffff); +} + +static inline void +archive_le16enc(void *pp, uint16_t u) +{ + unsigned char *p = (unsigned char *)pp; + + p[0] = u & 0xff; + p[1] = (u >> 8) & 0xff; +} + +static inline void +archive_le32enc(void *pp, uint32_t u) +{ + unsigned char *p = (unsigned char *)pp; + + p[0] = u & 0xff; + p[1] = (u >> 8) & 0xff; + p[2] = (u >> 16) & 0xff; + p[3] = (u >> 24) & 0xff; +} + +static inline void +archive_le64enc(void *pp, uint64_t u) +{ + unsigned char *p = (unsigned char *)pp; + + archive_le32enc(p, u & 0xffffffff); + archive_le32enc(p + 4, u >> 32); +} + +#endif diff --git a/contrib/libarchive-2/libarchive/archive_entry.c b/contrib/libarchive-2/libarchive/archive_entry.c index 5c78c92f11..a6c9b4496c 100644 --- a/contrib/libarchive-2/libarchive/archive_entry.c +++ b/contrib/libarchive-2/libarchive/archive_entry.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_entry.c,v 1.44 2007/07/15 19:10:34 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_entry.c,v 1.45 2007/12/30 04:58:21 kientzle Exp $"); #ifdef HAVE_SYS_STAT_H #include @@ -207,6 +207,8 @@ aes_get_mbs(struct aes *aes) static const wchar_t * aes_get_wcs(struct aes *aes) { + int r; + if (aes->aes_wcs == NULL && aes->aes_mbs == NULL) return NULL; if (aes->aes_wcs == NULL && aes->aes_mbs != NULL) { @@ -221,8 +223,13 @@ aes_get_wcs(struct aes *aes) aes->aes_wcs = aes->aes_wcs_alloc; if (aes->aes_wcs == NULL) __archive_errx(1, "No memory for aes_get_wcs()"); - mbstowcs(aes->aes_wcs_alloc, aes->aes_mbs, wcs_length); + r = mbstowcs(aes->aes_wcs_alloc, aes->aes_mbs, wcs_length); aes->aes_wcs_alloc[wcs_length] = 0; + if (r == -1) { + /* Conversion failed, don't lie to our clients. */ + free(aes->aes_wcs_alloc); + aes->aes_wcs = aes->aes_wcs_alloc = NULL; + } } return (aes->aes_wcs); } @@ -307,6 +314,8 @@ aes_copy_wcs_len(struct aes *aes, const wchar_t *wcs, size_t len) struct archive_entry * archive_entry_clear(struct archive_entry *entry) { + if (entry == NULL) + return (NULL); aes_clean(&entry->ae_fflags_text); aes_clean(&entry->ae_gname); aes_clean(&entry->ae_hardlink); @@ -752,6 +761,28 @@ archive_entry_set_link(struct archive_entry *entry, const char *target) aes_set_mbs(&entry->ae_hardlink, target); } +/* Set symlink if symlink is already set, else set hardlink. */ +void +archive_entry_copy_link(struct archive_entry *entry, const char *target) +{ + if (entry->ae_symlink.aes_mbs != NULL || + entry->ae_symlink.aes_wcs != NULL) + aes_copy_mbs(&entry->ae_symlink, target); + else + aes_copy_mbs(&entry->ae_hardlink, target); +} + +/* Set symlink if symlink is already set, else set hardlink. */ +void +archive_entry_copy_link_w(struct archive_entry *entry, const wchar_t *target) +{ + if (entry->ae_symlink.aes_mbs != NULL || + entry->ae_symlink.aes_wcs != NULL) + aes_copy_wcs(&entry->ae_symlink, target); + else + aes_copy_wcs(&entry->ae_hardlink, target); +} + void archive_entry_set_mode(struct archive_entry *entry, mode_t m) { @@ -1143,7 +1174,7 @@ const wchar_t * archive_entry_acl_text_w(struct archive_entry *entry, int flags) { int count; - int length; + size_t length; const wchar_t *wname; const wchar_t *prefix; wchar_t separator; diff --git a/contrib/libarchive-2/libarchive/archive_entry.h b/contrib/libarchive-2/libarchive/archive_entry.h index 33c5649a9f..cebd55ba8a 100644 --- a/contrib/libarchive-2/libarchive/archive_entry.h +++ b/contrib/libarchive-2/libarchive/archive_entry.h @@ -22,7 +22,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/lib/libarchive/archive_entry.h,v 1.23 2007/07/15 19:10:34 kientzle Exp $ + * $FreeBSD: src/lib/libarchive/archive_entry.h,v 1.24 2007/12/30 04:58:21 kientzle Exp $ */ #ifndef ARCHIVE_ENTRY_H_INCLUDED @@ -37,7 +37,6 @@ extern "C" { #endif - /* * Description of an archive entry. * @@ -57,7 +56,25 @@ extern "C" { struct archive_entry; /* - * File-type constants. These are returned from archive_entry_filetype(). + * File-type constants. These are returned from archive_entry_filetype() + * and passed to archive_entry_set_filetype(). + * + * These values match S_XXX defines on every platform I've checked, + * including Windows, AIX, Linux, Solaris, and BSD. They're + * (re)defined here because platforms generally don't define the ones + * they don't support. For example, Windows doesn't define S_IFLNK or + * S_IFBLK. Instead of having a mass of conditional logic and system + * checks to define any S_XXX values that aren't supported locally, + * I've just defined a new set of such constants so that + * libarchive-based applications can manipulate and identify archive + * entries properly even if the hosting platform can't store them on + * disk. + * + * These values are also used directly within some portable formats, + * such as cpio. If you find a platform that varies from these, the + * correct solution is to leave these alone and translate from these + * portable values to platform-native values when entries are read from + * or written to disk. */ #define AE_IFMT 0170000 #define AE_IFREG 0100000 @@ -91,7 +108,8 @@ dev_t archive_entry_devmajor(struct archive_entry *); dev_t archive_entry_devminor(struct archive_entry *); mode_t archive_entry_filetype(struct archive_entry *); void archive_entry_fflags(struct archive_entry *, - unsigned long *set, unsigned long *clear); + unsigned long * /* set */, + unsigned long * /* clear */); const char *archive_entry_fflags_text(struct archive_entry *); gid_t archive_entry_gid(struct archive_entry *); const char *archive_entry_gname(struct archive_entry *); @@ -130,7 +148,7 @@ void archive_entry_set_devmajor(struct archive_entry *, dev_t); void archive_entry_set_devminor(struct archive_entry *, dev_t); void archive_entry_set_filetype(struct archive_entry *, unsigned int); void archive_entry_set_fflags(struct archive_entry *, - unsigned long set, unsigned long clear); + unsigned long /* set */, unsigned long /* clear */); /* Returns pointer to start of first invalid token, or NULL if none. */ /* Note that all recognized tokens are processed, regardless. */ const wchar_t *archive_entry_copy_fflags_text_w(struct archive_entry *, @@ -144,6 +162,8 @@ void archive_entry_copy_hardlink(struct archive_entry *, const char *); void archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *); void archive_entry_set_ino(struct archive_entry *, unsigned long); void archive_entry_set_link(struct archive_entry *, const char *); +void archive_entry_copy_link(struct archive_entry *, const char *); +void archive_entry_copy_link_w(struct archive_entry *, const wchar_t *); void archive_entry_set_mode(struct archive_entry *, mode_t); void archive_entry_set_mtime(struct archive_entry *, time_t, long); void archive_entry_set_nlink(struct archive_entry *, unsigned int); @@ -182,6 +202,13 @@ void archive_entry_copy_stat(struct archive_entry *, const struct stat *); * = there are many different ACL text formats * = would like to be able to read/convert archives containing ACLs * on platforms that lack ACL libraries + * + * This last point, in particular, forces me to implement a reasonably + * complete set of ACL support routines. + * + * TODO: Extend this to support NFSv4/NTFS permissions. That should + * allow full ACL support on Mac OS, in particular, which uses + * POSIX.1e-style interfaces to manipulate NFSv4/NTFS permissions. */ /* @@ -216,21 +243,24 @@ void archive_entry_copy_stat(struct archive_entry *, const struct stat *); */ void archive_entry_acl_clear(struct archive_entry *); void archive_entry_acl_add_entry(struct archive_entry *, - int type, int permset, int tag, int qual, const char *name); + int /* type */, int /* permset */, int /* tag */, + int /* qual */, const char * /* name */); void archive_entry_acl_add_entry_w(struct archive_entry *, - int type, int permset, int tag, int qual, const wchar_t *name); + int /* type */, int /* permset */, int /* tag */, + int /* qual */, const wchar_t * /* name */); /* * To retrieve the ACL, first "reset", then repeatedly ask for the * "next" entry. The want_type parameter allows you to request only * access entries or only default entries. */ -int archive_entry_acl_reset(struct archive_entry *, int want_type); -int archive_entry_acl_next(struct archive_entry *, int want_type, - int *type, int *permset, int *tag, int *qual, const char **name); -int archive_entry_acl_next_w(struct archive_entry *, int want_type, - int *type, int *permset, int *tag, int *qual, - const wchar_t **name); +int archive_entry_acl_reset(struct archive_entry *, int /* want_type */); +int archive_entry_acl_next(struct archive_entry *, int /* want_type */, + int * /* type */, int * /* permset */, int * /* tag */, + int * /* qual */, const char ** /* name */); +int archive_entry_acl_next_w(struct archive_entry *, int /* want_type */, + int * /* type */, int * /* permset */, int * /* tag */, + int * /* qual */, const wchar_t ** /* name */); /* * Construct a text-format ACL. The flags argument is a bitmask that @@ -245,10 +275,11 @@ int archive_entry_acl_next_w(struct archive_entry *, int want_type, */ #define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024 #define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048 -const wchar_t *archive_entry_acl_text_w(struct archive_entry *, int flags); +const wchar_t *archive_entry_acl_text_w(struct archive_entry *, + int /* flags */); /* Return a count of entries matching 'want_type' */ -int archive_entry_acl_count(struct archive_entry *, int want_type); +int archive_entry_acl_count(struct archive_entry *, int /* want_type */); /* * Private ACL parser. This is private because it handles some @@ -259,9 +290,12 @@ int archive_entry_acl_count(struct archive_entry *, int want_type); * this interface are likely to be surprised when it changes. * * You were warned! + * + * TODO: Move this declaration out of the public header and into + * a private header. Warnings above are silly. */ int __archive_entry_acl_parse_w(struct archive_entry *, - const wchar_t *, int type); + const wchar_t *, int /* type */); /* * extended attributes @@ -269,7 +303,8 @@ int __archive_entry_acl_parse_w(struct archive_entry *, void archive_entry_xattr_clear(struct archive_entry *); void archive_entry_xattr_add_entry(struct archive_entry *, - const char *name, const void *value, size_t size); + const char * /* name */, const void * /* value */, + size_t /* size */); /* * To retrieve the xattr list, first "reset", then repeatedly ask for the @@ -279,29 +314,94 @@ void archive_entry_xattr_add_entry(struct archive_entry *, int archive_entry_xattr_count(struct archive_entry *); int archive_entry_xattr_reset(struct archive_entry *); int archive_entry_xattr_next(struct archive_entry *, - const char **name, const void **value, size_t *); + const char ** /* name */, const void ** /* value */, size_t *); /* * Utility to detect hardlinks. * - * The 'struct archive_hardlink_lookup' is a cache of entry - * names and dev/ino numbers. Here's how to use it: - * 1. Create a lookup object with archive_hardlink_lookup_new() - * 2. Hand each archive_entry to archive_hardlink_lookup(). - * That function will return NULL (this is not a hardlink to - * a previous entry) or the pathname of the first entry - * that matched this. - * 3. Use archive_hardlink_lookup_free() to release the cache. + * The 'struct archive_entry_linkresolver' is a cache of archive entries + * for files with multiple links. Here's how to use it: + * 1. Create a lookup object with archive_entry_linkresolver_new() + * 2. Set the appropriate strategy. + * 3. Hand each archive_entry to archive_entry_linkify(). + * That function will return 0, 1, or 2 entries that should + * be written. + * 4. Call archive_entry_linkify(resolver, NULL) until + * no more entries are returned. + * 5. Call archive_entry_link_resolver_free(resolver) to free resources. + * + * The entries returned have their hardlink and size fields updated + * appropriately. If an entry is passed in that does not refer to + * a file with multiple links, it is returned unchanged. The intention + * is that you should be able to simply filter all entries through + * this machine. * * To make things more efficient, be sure that each entry has a valid * nlinks value. The hardlink cache uses this to track when all links * have been found. If the nlinks value is zero, it will keep every * name in the cache indefinitely, which can use a lot of memory. + * + * Note that archive_entry_size() is reset to zero if the file + * body should not be written to the archive. Pay attention! */ struct archive_entry_linkresolver; +/* + * This machine supports three different strategies for marking + * hardlinks. The names come from the best-known + * formats that rely on each strategy: + * + * "Old cpio" is the simplest, it always returns any entry unmodified. + * As far as I know, only cpio formats use this. Old cpio archives + * store every link with the full body; the onus is on the dearchiver + * to detect and properly link the files as they are restored. + * "tar" is also pretty simple; it caches a copy the first time it sees + * any link. Subsequent appearances are modified to be hardlink + * references without any body to the first one. Used by all tar + * formats, although the newest tar formats permit the "old cpio" strategy + * as well. This strategy is very simple for the dearchiver, + * and reasonably straightforward for the archiver. + * "new cpio" is trickier. It stores the body only with the last + * occurrence. The complication is that we might not + * see every link to a particular file in a single session, so + * there's no easy way to know when we've seen the last occurrence. + * The solution here is to queue one link until we see the next. + * At the end of the session, you can enumerate any remaining + * entries by calling archive_entry_linkify(NULL) and store those + * bodies. If you have a file with three links l1, l2, and l3, + * you'll get the following behavior if you see all three links: + * linkify(l1) => NULL (the resolver stores l1 internally) + * linkify(l2) => l1 (resolver stores l2, you write l1) + * linkify(l3) => l2, l3 (all links seen, you can write both). + * If you only see l1 and l2, you'll get this behavior: + * linkify(l1) => NULL + * linkify(l2) => l1 + * linkify(NULL) => l2 (at end, you retrieve remaining links) + * As the name suggests, this strategy is used by newer cpio variants. + * It's noticably more complex for the archiver, slightly more complex + * for the dearchiver than the tar strategy, but makes it straightforward + * to restore a file using any link by simply continuing to scan until + * you see a link that is stored with a body. In contrast, the tar + * strategy requires you to rescan the archive from the beginning to + * correctly extract an arbitrary link. + */ +#define ARCHIVE_ENTRY_LINKIFY_LIKE_TAR 0 +#define ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO 1 +#define ARCHIVE_ENTRY_LINKIFY_LIKE_NEW_CPIO 2 + struct archive_entry_linkresolver *archive_entry_linkresolver_new(void); +void archive_entry_linkresolver_set_strategy( + struct archive_entry_linkresolver *, int /* strategy */); void archive_entry_linkresolver_free(struct archive_entry_linkresolver *); +void archive_entry_linkify(struct archive_entry_linkresolver *, + struct archive_entry **, struct archive_entry **); + +/* + * DEPRECATED: This will be removed in libarchive 3.0. It was an + * early attempt at providing library-level hardlink recognition + * support, but it only handles the tar strategy and cannot easily + * be extended, so it's being replaced with the "linkify" function. + */ const char *archive_entry_linkresolve(struct archive_entry_linkresolver *, struct archive_entry *); diff --git a/contrib/libarchive-2/libarchive/archive_entry_link_resolver.c b/contrib/libarchive-2/libarchive/archive_entry_link_resolver.c index 0f07e068e0..37131ff325 100644 --- a/contrib/libarchive-2/libarchive/archive_entry_link_resolver.c +++ b/contrib/libarchive-2/libarchive/archive_entry_link_resolver.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_entry_link_resolver.c,v 1.1 2007/12/30 04:58:21 kientzle Exp $"); #ifdef HAVE_SYS_STAT_H #include @@ -42,133 +42,194 @@ __FBSDID("$FreeBSD$"); #include "archive_entry.h" +/* + * This is mostly a pretty straightforward hash table implementation. + * The only interesting bit is the different strategies used to + * match up links. These strategies match those used by various + * archiving formats: + * tar - content stored with first link, remainder refer back to it. + * This requires us to match each subsequent link up with the + * first appearance. + * cpio - Old cpio just stored body with each link, match-ups were + * implicit. This is trivial. + * new cpio - New cpio only stores body with last link, match-ups + * are implicit. This is actually quite tricky; see the notes + * below. + */ + /* Initial size of link cache. */ #define links_cache_initial_size 1024 +struct links_entry { + struct links_entry *next; + struct links_entry *previous; + int links; /* # links not yet seen */ + int hash; + struct archive_entry *entry; +}; + struct archive_entry_linkresolver { - char *last_name; + struct links_entry **buckets; + struct links_entry *spare; unsigned long number_entries; size_t number_buckets; - struct links_entry **buckets; + int strategy; }; -struct links_entry { - struct links_entry *next; - struct links_entry *previous; - int links; - dev_t dev; - ino_t ino; - char *name; -}; +static struct links_entry *find_entry(struct archive_entry_linkresolver *, + struct archive_entry *); +static void grow_hash(struct archive_entry_linkresolver *); +static void insert_entry(struct archive_entry_linkresolver *, + struct archive_entry *); struct archive_entry_linkresolver * archive_entry_linkresolver_new(void) { - struct archive_entry_linkresolver *links_cache; + struct archive_entry_linkresolver *res; size_t i; - links_cache = malloc(sizeof(struct archive_entry_linkresolver)); - if (links_cache == NULL) + res = malloc(sizeof(struct archive_entry_linkresolver)); + if (res == NULL) return (NULL); - memset(links_cache, 0, sizeof(struct archive_entry_linkresolver)); - links_cache->number_buckets = links_cache_initial_size; - links_cache->buckets = malloc(links_cache->number_buckets * - sizeof(links_cache->buckets[0])); - if (links_cache->buckets == NULL) { - free(links_cache); + memset(res, 0, sizeof(struct archive_entry_linkresolver)); + res->number_buckets = links_cache_initial_size; + res->buckets = malloc(res->number_buckets * + sizeof(res->buckets[0])); + if (res->buckets == NULL) { + free(res); return (NULL); } - for (i = 0; i < links_cache->number_buckets; i++) - links_cache->buckets[i] = NULL; - return (links_cache); + for (i = 0; i < res->number_buckets; i++) + res->buckets[i] = NULL; + return (res); +} + +void +archive_entry_linkresolver_set_strategy(struct archive_entry_linkresolver *res, + int strategy) +{ + res->strategy = strategy; } void -archive_entry_linkresolver_free(struct archive_entry_linkresolver *links_cache) +archive_entry_linkresolver_free(struct archive_entry_linkresolver *res) { size_t i; - if (links_cache->buckets == NULL) + if (res->buckets == NULL) return; - for (i = 0; i < links_cache->number_buckets; i++) { - while (links_cache->buckets[i] != NULL) { - struct links_entry *lp = links_cache->buckets[i]->next; - if (links_cache->buckets[i]->name != NULL) - free(links_cache->buckets[i]->name); - free(links_cache->buckets[i]); - links_cache->buckets[i] = lp; + for (i = 0; i < res->number_buckets; i++) { + while (res->buckets[i] != NULL) { + struct links_entry *lp = res->buckets[i]->next; + archive_entry_free(res->buckets[i]->entry); + free(res->buckets[i]); + res->buckets[i] = lp; } } - free(links_cache->buckets); - links_cache->buckets = NULL; + free(res->buckets); + res->buckets = NULL; } +/* Always uses tar-like semantics. */ const char * -archive_entry_linkresolve(struct archive_entry_linkresolver *links_cache, +archive_entry_linkresolve(struct archive_entry_linkresolver *res, struct archive_entry *entry) { - struct links_entry *le, **new_buckets; - int hash; - size_t i, new_size; - dev_t dev; - ino_t ino; - int nlinks; + struct links_entry *le; + /* If it has only one link, then we're done. */ + if (archive_entry_nlink(entry) == 1) + return (NULL); - /* Free a held name. */ - free(links_cache->last_name); - links_cache->last_name = NULL; + /* Look it up in the hash. */ + le = find_entry(res, entry); + if (le != NULL) + return (archive_entry_pathname(le->entry)); + /* If it's not there, insert it. */ + insert_entry(res, entry); + return (NULL); +} - /* If the links cache overflowed and got flushed, don't bother. */ - if (links_cache->buckets == NULL) - return (NULL); +void +archive_entry_linkify(struct archive_entry_linkresolver *res, + struct archive_entry **e, struct archive_entry **f) +{ + struct links_entry *le; + struct archive_entry *t; - dev = archive_entry_dev(entry); - ino = archive_entry_ino(entry); - nlinks = archive_entry_nlink(entry); + *f = NULL; /* Default: Don't return a second entry. */ - /* An entry with one link can't be a hard link. */ - if (nlinks == 1) - return (NULL); + /* If it has only one link, then we're done. */ + if (archive_entry_nlink(*e) == 1) + return; - /* If the links cache is getting too full, enlarge the hash table. */ - if (links_cache->number_entries > links_cache->number_buckets * 2) - { - /* Try to enlarge the bucket list. */ - new_size = links_cache->number_buckets * 2; - new_buckets = malloc(new_size * sizeof(struct links_entry *)); - - if (new_buckets != NULL) { - memset(new_buckets, 0, - new_size * sizeof(struct links_entry *)); - for (i = 0; i < links_cache->number_buckets; i++) { - while (links_cache->buckets[i] != NULL) { - /* Remove entry from old bucket. */ - le = links_cache->buckets[i]; - links_cache->buckets[i] = le->next; - - /* Add entry to new bucket. */ - hash = (le->dev ^ le->ino) % new_size; - - if (new_buckets[hash] != NULL) - new_buckets[hash]->previous = - le; - le->next = new_buckets[hash]; - le->previous = NULL; - new_buckets[hash] = le; - } + switch (res->strategy) { + case ARCHIVE_ENTRY_LINKIFY_LIKE_TAR: + le = find_entry(res, *e); + if (le != NULL) { + archive_entry_set_size(*e, 0); + archive_entry_set_hardlink(*e, + archive_entry_pathname(le->entry)); + } else + insert_entry(res, *e); + return; + case ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO: + /* This one is trivial. */ + return; + case ARCHIVE_ENTRY_LINKIFY_LIKE_NEW_CPIO: + le = find_entry(res, *e); + if (le != NULL) { + t = *e; + *e = le->entry; + le->entry = t; + archive_entry_set_size(*e, 0); + archive_entry_set_hardlink(*e, + archive_entry_pathname(le->entry)); + if (le->links == 0) { + *f = le->entry; } - free(links_cache->buckets); - links_cache->buckets = new_buckets; - links_cache->number_buckets = new_size; + } else { + insert_entry(res, *e); + *e = NULL; } + return; + default: + break; } + return; +} + +static struct links_entry * +find_entry(struct archive_entry_linkresolver *res, + struct archive_entry *entry) +{ + struct links_entry *le; + int hash, bucket; + dev_t dev; + ino_t ino; + + /* Free a held entry. */ + if (res->spare != NULL) { + archive_entry_free(res->spare->entry); + free(res->spare); + res->spare = NULL; + } + + /* If the links cache overflowed and got flushed, don't bother. */ + if (res->buckets == NULL) + return (NULL); + + dev = archive_entry_dev(entry); + ino = archive_entry_ino(entry); + hash = dev ^ ino; /* Try to locate this entry in the links cache. */ - hash = ( dev ^ ino ) % links_cache->number_buckets; - for (le = links_cache->buckets[hash]; le != NULL; le = le->next) { - if (le->dev == dev && le->ino == ino) { + bucket = hash % res->number_buckets; + for (le = res->buckets[bucket]; le != NULL; le = le->next) { + if (le->hash == hash + && dev == archive_entry_dev(le->entry) + && ino == archive_entry_ino(le->entry)) { /* * Decrement link count each time and release * the entry if it hits zero. This saves @@ -177,46 +238,91 @@ archive_entry_linkresolve(struct archive_entry_linkresolver *links_cache, */ --le->links; if (le->links > 0) - return (le->name); - /* - * When we release the entry, save the name - * until the next call. - */ - links_cache->last_name = le->name; - /* - * Release the entry. - */ + return (le); + /* Remove it from this hash bucket. */ if (le->previous != NULL) le->previous->next = le->next; if (le->next != NULL) le->next->previous = le->previous; - if (links_cache->buckets[hash] == le) - links_cache->buckets[hash] = le->next; - links_cache->number_entries--; - free(le); - return (links_cache->last_name); + if (res->buckets[bucket] == le) + res->buckets[bucket] = le->next; + res->number_entries--; + /* Defer freeing this entry. */ + res->spare = le; + return (le); } } + return (NULL); +} + +static void +insert_entry(struct archive_entry_linkresolver *res, + struct archive_entry *entry) +{ + struct links_entry *le; + int hash, bucket; /* Add this entry to the links cache. */ le = malloc(sizeof(struct links_entry)); if (le == NULL) - return (NULL); - le->name = strdup(archive_entry_pathname(entry)); - if (le->name == NULL) { + return; + le->entry = archive_entry_clone(entry); + if (le->entry == NULL) { free(le); - return (NULL); + return; } + /* If the links cache is getting too full, enlarge the hash table. */ + if (res->number_entries > res->number_buckets * 2) + grow_hash(res); + + hash = archive_entry_dev(entry) ^ archive_entry_ino(entry); + bucket = hash % res->number_buckets; + /* If we could allocate the entry, record it. */ - if (links_cache->buckets[hash] != NULL) - links_cache->buckets[hash]->previous = le; - links_cache->number_entries++; - le->next = links_cache->buckets[hash]; + if (res->buckets[bucket] != NULL) + res->buckets[bucket]->previous = le; + res->number_entries++; + le->next = res->buckets[bucket]; le->previous = NULL; - links_cache->buckets[hash] = le; - le->dev = dev; - le->ino = ino; - le->links = nlinks - 1; - return (NULL); + res->buckets[bucket] = le; + le->hash = hash; + le->links = archive_entry_nlink(entry) - 1; +} + +static void +grow_hash(struct archive_entry_linkresolver *res) +{ + struct links_entry *le, **new_buckets; + size_t new_size; + size_t i, bucket; + + /* Try to enlarge the bucket list. */ + new_size = res->number_buckets * 2; + new_buckets = malloc(new_size * sizeof(struct links_entry *)); + + if (new_buckets != NULL) { + memset(new_buckets, 0, + new_size * sizeof(struct links_entry *)); + for (i = 0; i < res->number_buckets; i++) { + while (res->buckets[i] != NULL) { + /* Remove entry from old bucket. */ + le = res->buckets[i]; + res->buckets[i] = le->next; + + /* Add entry to new bucket. */ + bucket = le->hash % new_size; + + if (new_buckets[bucket] != NULL) + new_buckets[bucket]->previous = + le; + le->next = new_buckets[bucket]; + le->previous = NULL; + new_buckets[bucket] = le; + } + } + free(res->buckets); + res->buckets = new_buckets; + res->number_buckets = new_size; + } } diff --git a/contrib/libarchive-2/libarchive/archive_entry_private.h b/contrib/libarchive-2/libarchive/archive_entry_private.h index 50ad7b9064..57fe29600a 100644 --- a/contrib/libarchive-2/libarchive/archive_entry_private.h +++ b/contrib/libarchive-2/libarchive/archive_entry_private.h @@ -22,7 +22,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/lib/libarchive/archive_entry_private.h,v 1.1 2007/05/29 01:00:18 kientzle Exp $ + * $FreeBSD: src/lib/libarchive/archive_entry_private.h,v 1.2 2007/12/30 04:58:21 kientzle Exp $ */ #ifndef ARCHIVE_ENTRY_PRIVATE_H_INCLUDED diff --git a/contrib/libarchive-2/libarchive/archive_entry_strmode.c b/contrib/libarchive-2/libarchive/archive_entry_strmode.c index 1a018734bc..dc08d9721a 100644 --- a/contrib/libarchive-2/libarchive/archive_entry_strmode.c +++ b/contrib/libarchive-2/libarchive/archive_entry_strmode.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_entry_strmode.c,v 1.2 2008/02/19 05:49:02 kientzle Exp $"); #ifdef HAVE_SYS_STAT_H #include @@ -65,15 +65,15 @@ archive_entry_strmode(struct archive_entry *entry) bp[i+1] = '-'; if (mode & S_ISUID) { - if (mode & S_IXUSR) bp[3] = 's'; + if (mode & 0100) bp[3] = 's'; else bp[3] = 'S'; } if (mode & S_ISGID) { - if (mode & S_IXGRP) bp[6] = 's'; + if (mode & 0010) bp[6] = 's'; else bp[6] = 'S'; } if (mode & S_ISVTX) { - if (mode & S_IXOTH) bp[9] = 't'; + if (mode & 0001) bp[9] = 't'; else bp[9] = 'T'; } if (archive_entry_acl_count(entry, ARCHIVE_ENTRY_ACL_TYPE_ACCESS)) diff --git a/contrib/libarchive-2/libarchive/archive_platform.h b/contrib/libarchive-2/libarchive/archive_platform.h index 193a52cc67..b14ccd8206 100644 --- a/contrib/libarchive-2/libarchive/archive_platform.h +++ b/contrib/libarchive-2/libarchive/archive_platform.h @@ -22,7 +22,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/lib/libarchive/archive_platform.h,v 1.27 2007/05/29 01:00:18 kientzle Exp $ + * $FreeBSD: src/lib/libarchive/archive_platform.h,v 1.29 2008/02/19 06:06:13 kientzle Exp $ */ /* @@ -36,7 +36,10 @@ #ifndef ARCHIVE_PLATFORM_H_INCLUDED #define ARCHIVE_PLATFORM_H_INCLUDED -#if defined(PLATFORM_CONFIG_H) +#ifdef _WIN32 +#include "config_windows.h" +#include "archive_windows.h" +#elif defined(PLATFORM_CONFIG_H) /* Use hand-built config.h in environments that need it. */ #include PLATFORM_CONFIG_H #elif defined(HAVE_CONFIG_H) diff --git a/contrib/libarchive-2/libarchive/archive_read.c b/contrib/libarchive-2/libarchive/archive_read.c index 7803fd2f9f..19be77569c 100644 --- a/contrib/libarchive-2/libarchive/archive_read.c +++ b/contrib/libarchive-2/libarchive/archive_read.c @@ -32,7 +32,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_read.c,v 1.35 2007/05/29 01:00:18 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read.c,v 1.37 2008/01/03 17:54:26 des Exp $"); #ifdef HAVE_ERRNO_H #include @@ -741,3 +741,14 @@ __archive_read_register_compression(struct archive_read *a, __archive_errx(1, "Not enough slots for compression registration"); return (NULL); /* Never actually executed. */ } + +/* used internally to simplify read-ahead */ +const void * +__archive_read_ahead(struct archive_read *a, size_t len) +{ + const void *h; + + if ((a->decompressor->read_ahead)(a, &h, len) < (ssize_t)len) + return (NULL); + return (h); +} diff --git a/contrib/libarchive-2/libarchive/archive_read_extract.c b/contrib/libarchive-2/libarchive/archive_read_extract.c index 423ff7dd3c..bb5add7bbd 100644 --- a/contrib/libarchive-2/libarchive/archive_read_extract.c +++ b/contrib/libarchive-2/libarchive/archive_read_extract.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_extract.c,v 1.59 2007/05/29 01:00:18 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_extract.c,v 1.60 2008/01/18 04:53:45 kientzle Exp $"); #ifdef HAVE_SYS_TYPES_H #include @@ -67,6 +67,7 @@ get_extract(struct archive_read *a) archive_set_error(&a->archive, ENOMEM, "Can't extract"); return (NULL); } + memset(a->extract, 0, sizeof(*a->extract)); a->extract->ad = archive_write_disk_new(); if (a->extract->ad == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't extract"); @@ -130,11 +131,13 @@ archive_read_extract_set_progress_callback(struct archive *_a, static int copy_data(struct archive *ar, struct archive *aw) { - int r; + off_t offset; const void *buff; + struct extract *extract; size_t size; - off_t offset; + int r; + extract = get_extract((struct archive_read *)ar); for (;;) { r = archive_read_data_block(ar, &buff, &size, &offset); if (r == ARCHIVE_EOF) @@ -149,6 +152,9 @@ copy_data(struct archive *ar, struct archive *aw) "%s", archive_error_string(aw)); return (r); } + if (extract->extract_progress) + (extract->extract_progress) + (extract->extract_progress_user_data); } } diff --git a/contrib/libarchive-2/libarchive/archive_read_open_filename.c b/contrib/libarchive-2/libarchive/archive_read_open_filename.c index 02e7902f3a..3d6376fbcf 100644 --- a/contrib/libarchive-2/libarchive/archive_read_open_filename.c +++ b/contrib/libarchive-2/libarchive/archive_read_open_filename.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_open_filename.c,v 1.20 2007/06/26 03:06:48 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_open_filename.c,v 1.21 2008/02/19 06:10:48 kientzle Exp $"); #ifdef HAVE_SYS_STAT_H #include @@ -47,6 +47,10 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_open_filename.c,v 1.20 2007/ #include "archive.h" +#ifndef O_BINARY +#define O_BINARY 0 +#endif + struct read_file_data { int fd; size_t block_size; @@ -113,7 +117,7 @@ file_open(struct archive *a, void *client_data) return (ARCHIVE_FATAL); } if (mine->filename[0] != '\0') - mine->fd = open(mine->filename, O_RDONLY); + mine->fd = open(mine->filename, O_RDONLY | O_BINARY); else mine->fd = 0; /* Fake "open" for stdin. */ if (mine->fd < 0) { diff --git a/contrib/libarchive-2/libarchive/archive_read_private.h b/contrib/libarchive-2/libarchive/archive_read_private.h index f0f5202113..90fb7db12e 100644 --- a/contrib/libarchive-2/libarchive/archive_read_private.h +++ b/contrib/libarchive-2/libarchive/archive_read_private.h @@ -22,7 +22,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/lib/libarchive/archive_read_private.h,v 1.3 2007/05/29 01:00:18 kientzle Exp $ + * $FreeBSD: src/lib/libarchive/archive_read_private.h,v 1.4 2008/01/03 17:54:26 des Exp $ */ #ifndef ARCHIVE_READ_PRIVATE_H_INCLUDED @@ -173,4 +173,7 @@ struct decompressor_t int (*bid)(const void *, size_t), int (*init)(struct archive_read *, const void *, size_t)); +const void + *__archive_read_ahead(struct archive_read *, size_t); + #endif diff --git a/contrib/libarchive-2/libarchive/archive_read_support_compression_bzip2.c b/contrib/libarchive-2/libarchive/archive_read_support_compression_bzip2.c index aa664d10b1..372eff0954 100644 --- a/contrib/libarchive-2/libarchive/archive_read_support_compression_bzip2.c +++ b/contrib/libarchive-2/libarchive/archive_read_support_compression_bzip2.c @@ -25,7 +25,7 @@ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_bzip2.c,v 1.16 2007/05/29 01:00:18 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_bzip2.c,v 1.17 2008/02/19 05:44:59 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include @@ -145,7 +145,7 @@ init(struct archive_read *a, const void *buff, size_t n) (void)buff; /* UNUSED */ (void)n; /* UNUSED */ - archive_set_error(a, -1, + archive_set_error(&a->archive, -1, "This version of libarchive was compiled without bzip2 support"); return (ARCHIVE_FATAL); } diff --git a/contrib/libarchive-2/libarchive/archive_read_support_compression_gzip.c b/contrib/libarchive-2/libarchive/archive_read_support_compression_gzip.c index 89784b8dfc..2dac54da0c 100644 --- a/contrib/libarchive-2/libarchive/archive_read_support_compression_gzip.c +++ b/contrib/libarchive-2/libarchive/archive_read_support_compression_gzip.c @@ -25,7 +25,7 @@ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_gzip.c,v 1.15 2007/05/29 01:00:19 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_gzip.c,v 1.16 2008/02/19 05:44:59 kientzle Exp $"); #ifdef HAVE_ERRNO_H @@ -146,7 +146,7 @@ init(struct archive_read *a, const void *buff, size_t n) (void)buff; /* UNUSED */ (void)n; /* UNUSED */ - archive_set_error(a, -1, + archive_set_error(&a->archive, -1, "This version of libarchive was compiled without gzip support"); return (ARCHIVE_FATAL); } diff --git a/contrib/libarchive-2/libarchive/archive_read_support_compression_none.c b/contrib/libarchive-2/libarchive/archive_read_support_compression_none.c index 1cafd8385a..3f17756aba 100644 --- a/contrib/libarchive-2/libarchive/archive_read_support_compression_none.c +++ b/contrib/libarchive-2/libarchive/archive_read_support_compression_none.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_none.c,v 1.18 2007/10/27 22:45:40 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_none.c,v 1.19 2007/12/30 04:58:21 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include diff --git a/contrib/libarchive-2/libarchive/archive_read_support_format_all.c b/contrib/libarchive-2/libarchive/archive_read_support_format_all.c index c9165c8945..24e31ef54f 100644 --- a/contrib/libarchive-2/libarchive/archive_read_support_format_all.c +++ b/contrib/libarchive-2/libarchive/archive_read_support_format_all.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_all.c,v 1.9 2007/04/07 05:54:23 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_all.c,v 1.10 2007/12/30 04:58:21 kientzle Exp $"); #include "archive.h" diff --git a/contrib/libarchive-2/libarchive/archive_read_support_format_ar.c b/contrib/libarchive-2/libarchive/archive_read_support_format_ar.c index 5fad4aea03..a74791c6da 100644 --- a/contrib/libarchive-2/libarchive/archive_read_support_format_ar.c +++ b/contrib/libarchive-2/libarchive/archive_read_support_format_ar.c @@ -26,7 +26,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_ar.c,v 1.6 2007/05/29 01:00:19 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_ar.c,v 1.8 2008/02/19 05:54:24 kientzle Exp $"); #ifdef HAVE_SYS_STAT_H #include @@ -268,8 +268,7 @@ archive_read_format_ar_read_header(struct archive_read *a, /* This must come before any call to _read_ahead. */ ar_parse_common_header(ar, entry, h); archive_entry_copy_pathname(entry, filename); - archive_entry_set_mode(entry, - S_IFREG | (archive_entry_mode(entry) & 0777)); + archive_entry_set_filetype(entry, AE_IFREG); /* Get the size of the filename table. */ number = ar_atol10(h + AR_size_offset, AR_size_size); if (number > SIZE_MAX) { @@ -375,8 +374,7 @@ archive_read_format_ar_read_header(struct archive_read *a, /* Parse the time, owner, mode, size fields. */ r = ar_parse_common_header(ar, entry, h); /* Force the file type to a regular file. */ - archive_entry_set_mode(entry, - S_IFREG | (archive_entry_mode(entry) & 0777)); + archive_entry_set_filetype(entry, AE_IFREG); return (r); } diff --git a/contrib/libarchive-2/libarchive/archive_read_support_format_cpio.c b/contrib/libarchive-2/libarchive/archive_read_support_format_cpio.c index 8c531fa199..2c50abc6b8 100644 --- a/contrib/libarchive-2/libarchive/archive_read_support_format_cpio.c +++ b/contrib/libarchive-2/libarchive/archive_read_support_format_cpio.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_cpio.c,v 1.24 2007/05/29 01:00:19 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_cpio.c,v 1.26 2008/01/15 04:56:48 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include @@ -321,10 +321,12 @@ static int is_hex(const char *p, size_t len) { while (len-- > 0) { - if (*p < '0' || (*p > '9' && *p < 'a') || *p > 'f') { + if ((*p >= '0' && *p <= '9') + || (*p >= 'a' && *p <= 'f') + || (*p >= 'A' && *p <= 'F')) + ++p; + else return (0); - } - ++p; } return (1); } diff --git a/contrib/libarchive-2/libarchive/archive_read_support_format_iso9660.c b/contrib/libarchive-2/libarchive/archive_read_support_format_iso9660.c index d2419eac66..d333f0ccb4 100644 --- a/contrib/libarchive-2/libarchive/archive_read_support_format_iso9660.c +++ b/contrib/libarchive-2/libarchive/archive_read_support_format_iso9660.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_iso9660.c,v 1.23 2007/05/29 01:00:19 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_iso9660.c,v 1.25 2008/02/19 06:02:01 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include @@ -181,6 +181,7 @@ struct file_info { time_t mtime; /* File last modified time. */ time_t atime; /* File last accessed time. */ time_t ctime; /* File creation time. */ + uint64_t rdev; /* Device number */ mode_t mode; uid_t uid; gid_t gid; @@ -360,6 +361,8 @@ archive_read_format_iso9660_read_header(struct archive_read *a, archive_entry_set_mtime(entry, file->mtime, 0); archive_entry_set_ctime(entry, file->ctime, 0); archive_entry_set_atime(entry, file->atime, 0); + /* N.B.: Rock Ridge supports 64-bit device numbers. */ + archive_entry_set_rdev(entry, (dev_t)file->rdev); archive_entry_set_size(entry, iso9660->entry_bytes_remaining); archive_string_empty(&iso9660->pathname); archive_entry_set_pathname(entry, @@ -675,6 +678,14 @@ parse_rockridge(struct iso9660 *iso9660, struct file_info *file, */ break; } + if (p[0] == 'P' && p[1] == 'N' && version == 1) { + if (data_length == 16) { + file->rdev = toi(data,4); + file->rdev <<= 32; + file->rdev |= toi(data + 8, 4); + } + break; + } if (p[0] == 'P' && p[1] == 'X' && version == 1) { /* * PX extension comprises: @@ -1053,24 +1064,28 @@ time_from_tm(struct tm *t) if (t->tm_isdst) t->tm_hour -= 1; return (mktime(t)); /* Re-convert. */ -#else - /* - * If you don't have tm_gmtoff, let's try resetting the timezone - * (yecch!). - */ +#elif defined(HAVE_SETENV) && defined(HAVE_UNSETENV) && defined(HAVE_TZSET) + /* No timegm() and no tm_gmtoff, let's try forcing mktime() to UTC. */ time_t ret; char *tz; + /* Reset the timezone, remember the old one. */ tz = getenv("TZ"); setenv("TZ", "UTC 0", 1); tzset(); + ret = mktime(t); + + /* Restore the previous timezone. */ if (tz) setenv("TZ", tz, 1); else unsetenv("TZ"); tzset(); return ret; +#else + /* We have no choice but to use localtime instead of UTC. */ + return (mktime(t)); #endif } diff --git a/contrib/libarchive-2/libarchive/archive_read_support_format_mtree.c b/contrib/libarchive-2/libarchive/archive_read_support_format_mtree.c index e6ac99f6bf..7db6db3377 100644 --- a/contrib/libarchive-2/libarchive/archive_read_support_format_mtree.c +++ b/contrib/libarchive-2/libarchive/archive_read_support_format_mtree.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_mtree.c,v 1.2 2008/02/19 06:07:10 kientzle Exp $"); #ifdef HAVE_SYS_STAT_H #include @@ -50,6 +50,10 @@ __FBSDID("$FreeBSD$"); #include "archive_read_private.h" #include "archive_string.h" +#ifndef O_BINARY +#define O_BINARY 0 +#endif + struct mtree_entry { struct mtree_entry *next; char *name; @@ -371,7 +375,8 @@ read_header(struct archive_read *a, struct archive_entry *entry) * the contents file on disk.) */ if (archive_strlen(&mtree->contents_name) > 0) { - mtree->fd = open(mtree->contents_name.s, O_RDONLY); + mtree->fd = open(mtree->contents_name.s, + O_RDONLY | O_BINARY); if (mtree->fd < 0) { archive_set_error(&a->archive, errno, "Can't open content=\"%s\"", @@ -380,7 +385,8 @@ read_header(struct archive_read *a, struct archive_entry *entry) } } else { /* If the specified path opens, use it. */ - mtree->fd = open(mtree->current_dir.s, O_RDONLY); + mtree->fd = open(mtree->current_dir.s, + O_RDONLY | O_BINARY); /* But don't fail if it's not there. */ } diff --git a/contrib/libarchive-2/libarchive/archive_read_support_format_tar.c b/contrib/libarchive-2/libarchive/archive_read_support_format_tar.c index 7d57425c3f..26b2abbe57 100644 --- a/contrib/libarchive-2/libarchive/archive_read_support_format_tar.c +++ b/contrib/libarchive-2/libarchive/archive_read_support_format_tar.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_tar.c,v 1.62 2007/10/24 04:01:31 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_tar.c,v 1.65 2008/01/31 07:41:45 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include @@ -144,8 +144,8 @@ struct sparse_block { struct tar { struct archive_string acl_text; - struct archive_string entry_name; - struct archive_string entry_linkname; + struct archive_string entry_pathname; + struct archive_string entry_linkpath; struct archive_string entry_uname; struct archive_string entry_gname; struct archive_string longlink; @@ -153,6 +153,7 @@ struct tar { struct archive_string pax_header; struct archive_string pax_global; struct archive_string line; + int pax_hdrcharset_binary; wchar_t *pax_entry; size_t pax_entry_length; int header_recursion_depth; @@ -169,9 +170,9 @@ struct tar { char sparse_gnu_pending; }; -static size_t UTF8_mbrtowc(wchar_t *pwc, const char *s, size_t n); +static ssize_t UTF8_mbrtowc(wchar_t *pwc, const char *s, size_t n); static int archive_block_is_null(const unsigned char *p); -static char *base64_decode(const wchar_t *, size_t, size_t *); +static char *base64_decode(const char *, size_t, size_t *); static void gnu_add_sparse_entry(struct tar *, off_t offset, off_t remaining); static void gnu_clear_sparse_list(struct tar *); @@ -179,7 +180,7 @@ static int gnu_sparse_old_read(struct archive_read *, struct tar *, const struct archive_entry_header_gnutar *header); static void gnu_sparse_old_parse(struct tar *, const struct gnu_sparse *sparse, int length); -static int gnu_sparse_01_parse(struct tar *, const wchar_t *); +static int gnu_sparse_01_parse(struct tar *, const char *); static ssize_t gnu_sparse_10_read(struct archive_read *, struct tar *); static int header_Solaris_ACL(struct archive_read *, struct tar *, struct archive_entry *, const void *); @@ -210,24 +211,23 @@ static int archive_read_format_tar_read_header(struct archive_read *, struct archive_entry *); static int checksum(struct archive_read *, const void *); static int pax_attribute(struct tar *, struct archive_entry *, - wchar_t *key, wchar_t *value); + char *key, char *value); static int pax_header(struct archive_read *, struct tar *, struct archive_entry *, char *attr); -static void pax_time(const wchar_t *, int64_t *sec, long *nanos); +static void pax_time(const char *, int64_t *sec, long *nanos); static ssize_t readline(struct archive_read *, struct tar *, const char **, ssize_t limit); static int read_body_to_string(struct archive_read *, struct tar *, struct archive_string *, const void *h); static int64_t tar_atol(const char *, unsigned); -static int64_t tar_atol10(const wchar_t *, unsigned); +static int64_t tar_atol10(const char *, unsigned); static int64_t tar_atol256(const char *, unsigned); static int64_t tar_atol8(const char *, unsigned); static int tar_read_header(struct archive_read *, struct tar *, struct archive_entry *); static int tohex(int c); static char *url_decode(const char *); -static int utf8_decode(wchar_t *, const char *, size_t length); -static char *wide_to_narrow(const wchar_t *wval); +static wchar_t *utf8_decode(struct tar *, const char *, size_t length); int archive_read_support_format_gnutar(struct archive *a) @@ -271,8 +271,8 @@ archive_read_format_tar_cleanup(struct archive_read *a) tar = (struct tar *)(a->format->data); gnu_clear_sparse_list(tar); archive_string_free(&tar->acl_text); - archive_string_free(&tar->entry_name); - archive_string_free(&tar->entry_linkname); + archive_string_free(&tar->entry_pathname); + archive_string_free(&tar->entry_linkpath); archive_string_free(&tar->entry_uname); archive_string_free(&tar->entry_gname); archive_string_free(&tar->line); @@ -295,24 +295,8 @@ archive_read_format_tar_bid(struct archive_read *a) const void *h; const struct archive_entry_header_ustar *header; - /* - * If we're already reading a non-tar file, don't - * bother to bid. - */ - if (a->archive.archive_format != 0 && - (a->archive.archive_format & ARCHIVE_FORMAT_BASE_MASK) != - ARCHIVE_FORMAT_TAR) - return (0); bid = 0; - /* - * If we're already reading a tar format, start the bid at 1 as - * a failsafe. - */ - if ((a->archive.archive_format & ARCHIVE_FORMAT_BASE_MASK) == - ARCHIVE_FORMAT_TAR) - bid++; - /* Now let's look at the actual header and see if it matches. */ if (a->decompressor->read_ahead != NULL) bytes_read = (a->decompressor->read_ahead)(a, &h, 512); @@ -324,13 +308,14 @@ archive_read_format_tar_bid(struct archive_read *a) 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)) { - /* If it's a known tar file, end-of-archive is definite. */ - if ((a->archive.archive_format & ARCHIVE_FORMAT_BASE_MASK) == - ARCHIVE_FORMAT_TAR) - return (512); - /* Empty archive? */ - return (1); + if ((*(const char *)h) == 0 + && archive_block_is_null((const unsigned char *)h)) { + /* + * Usually, I bid the number of bits verified, but + * in this case, 4096 seems excessive so I picked 10 as + * an arbitrary but reasonable-seeming value. + */ + return (10); } /* If it's not an end-of-archive mark, it must have a valid checksum.*/ @@ -590,6 +575,10 @@ tar_read_header(struct archive_read *a, struct tar *tar, if (bytes > 0) (a->decompressor->consume)(a, bytes); archive_set_error(&a->archive, 0, NULL); + if (a->archive.archive_format_name == NULL) { + a->archive.archive_format = ARCHIVE_FORMAT_TAR; + a->archive.archive_format_name = "tar"; + } return (ARCHIVE_EOF); } @@ -777,16 +766,9 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar, while (*p != '\0' && p < acl + size) p++; - wp = (wchar_t *)malloc((p - acl + 1) * sizeof(wchar_t)); - if (wp == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate work buffer for ACL parsing"); - return (ARCHIVE_FATAL); - } - utf8_decode(wp, acl, p - acl); + wp = utf8_decode(tar, acl, p - acl); err = __archive_entry_acl_parse_w(entry, wp, ARCHIVE_ENTRY_ACL_TYPE_ACCESS); - free(wp); return (err); } @@ -806,7 +788,7 @@ header_longlink(struct archive_read *a, struct tar *tar, if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN)) return (err); /* Set symlink if symlink already set, else hardlink. */ - archive_entry_set_link(entry, tar->longlink.s); + archive_entry_copy_link(entry, tar->longlink.s); return (ARCHIVE_OK); } @@ -826,7 +808,7 @@ header_longname(struct archive_read *a, struct tar *tar, err = tar_read_header(a, tar, entry); if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN)) return (err); - archive_entry_set_pathname(entry, tar->longname.s); + archive_entry_copy_pathname(entry, tar->longname.s); return (ARCHIVE_OK); } @@ -918,10 +900,10 @@ header_common(struct archive_read *a, struct tar *tar, header = (const struct archive_entry_header_ustar *)h; if (header->linkname[0]) - archive_strncpy(&(tar->entry_linkname), header->linkname, + archive_strncpy(&(tar->entry_linkpath), header->linkname, sizeof(header->linkname)); else - archive_string_empty(&(tar->entry_linkname)); + archive_string_empty(&(tar->entry_linkpath)); /* Parse out the numeric fields (all are octal) */ archive_entry_set_mode(entry, tar_atol(header->mode, sizeof(header->mode))); @@ -937,7 +919,7 @@ header_common(struct archive_read *a, struct tar *tar, switch (tartype) { case '1': /* Hard link */ - archive_entry_set_hardlink(entry, tar->entry_linkname.s); + archive_entry_copy_hardlink(entry, tar->entry_linkpath.s); /* * The following may seem odd, but: Technically, tar * does not store the file type for a "hard link" @@ -954,36 +936,52 @@ header_common(struct archive_read *a, struct tar *tar, * A tricky point: Traditionally, tar readers have * ignored the size field when reading hardlink * entries, and some writers put non-zero sizes even - * though the body is empty. POSIX.1-2001 broke with - * this tradition by permitting hardlink entries to - * store valid bodies in pax interchange format, but - * not in ustar format. Since there is no hard and - * fast way to distinguish pax interchange from - * earlier archives (the 'x' and 'g' entries are - * optional, after all), we need a heuristic. Here, I - * use the bid function to test whether or not there's - * a valid header following. Of course, if we know - * this is pax interchange format, then we must obey - * the size. - * - * This heuristic will only fail for a pax interchange - * archive that is storing hardlink bodies, no pax - * extended attribute entries have yet occurred, and - * we encounter a hardlink entry for a file that is - * itself an uncompressed tar archive. + * though the body is empty. POSIX blessed this + * convention in the 1988 standard, but broke with + * this tradition in 2001 by permitting hardlink + * entries to store valid bodies in pax interchange + * format, but not in ustar format. Since there is no + * hard and fast way to distinguish pax interchange + * from earlier archives (the 'x' and 'g' entries are + * optional, after all), we need a heuristic. */ - if (archive_entry_size(entry) > 0 && - a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE && - archive_read_format_tar_bid(a) > 50) { + if (archive_entry_size(entry) == 0) { + /* If the size is already zero, we're done. */ + } else if (a->archive.archive_format + == ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE) { + /* Definitely pax extended; must obey hardlink size. */ + } else if (a->archive.archive_format == ARCHIVE_FORMAT_TAR + || a->archive.archive_format == ARCHIVE_FORMAT_TAR_GNUTAR) + { + /* Old-style or GNU tar: we must ignore the size. */ + archive_entry_set_size(entry, 0); + tar->entry_bytes_remaining = 0; + } else if (archive_read_format_tar_bid(a) > 50) { + /* + * We don't know if it's pax: If the bid + * function sees a valid ustar header + * immediately following, then let's ignore + * the hardlink size. + */ archive_entry_set_size(entry, 0); tar->entry_bytes_remaining = 0; } + /* + * TODO: There are still two cases I'd like to handle: + * = a ustar non-pax archive with a hardlink entry at + * end-of-archive. (Look for block of nulls following?) + * = a pax archive that has not seen any pax headers + * and has an entry which is a hardlink entry storing + * a body containing an uncompressed tar archive. + * The first is worth addressing; I don't see any reliable + * way to deal with the second possibility. + */ break; case '2': /* Symlink */ archive_entry_set_filetype(entry, AE_IFLNK); archive_entry_set_size(entry, 0); tar->entry_bytes_remaining = 0; - archive_entry_set_symlink(entry, tar->entry_linkname.s); + archive_entry_copy_symlink(entry, tar->entry_linkpath.s); break; case '3': /* Character device */ archive_entry_set_filetype(entry, AE_IFCHR); @@ -1055,8 +1053,8 @@ header_old_tar(struct archive_read *a, struct tar *tar, /* Copy filename over (to ensure null termination). */ header = (const struct archive_entry_header_ustar *)h; - archive_strncpy(&(tar->entry_name), header->name, sizeof(header->name)); - archive_entry_set_pathname(entry, tar->entry_name.s); + archive_strncpy(&(tar->entry_pathname), header->name, sizeof(header->name)); + archive_entry_copy_pathname(entry, tar->entry_pathname.s); /* Grab rest of common fields */ header_common(a, tar, entry, h); @@ -1127,7 +1125,7 @@ header_ustar(struct archive_read *a, struct tar *tar, header = (const struct archive_entry_header_ustar *)h; /* Copy name into an internal buffer to ensure null-termination. */ - as = &(tar->entry_name); + as = &(tar->entry_pathname); if (header->prefix[0]) { archive_strncpy(as, header->prefix, sizeof(header->prefix)); if (as->s[archive_strlen(as) - 1] != '/') @@ -1136,7 +1134,7 @@ header_ustar(struct archive_read *a, struct tar *tar, } else archive_strncpy(as, header->name, sizeof(header->name)); - archive_entry_set_pathname(entry, as->s); + archive_entry_copy_pathname(entry, as->s); /* Handle rest of common fields. */ header_common(a, tar, entry, h); @@ -1144,11 +1142,11 @@ header_ustar(struct archive_read *a, struct tar *tar, /* Handle POSIX ustar fields. */ archive_strncpy(&(tar->entry_uname), header->uname, sizeof(header->uname)); - archive_entry_set_uname(entry, tar->entry_uname.s); + archive_entry_copy_uname(entry, tar->entry_uname.s); archive_strncpy(&(tar->entry_gname), header->gname, sizeof(header->gname)); - archive_entry_set_gname(entry, tar->entry_gname.s); + archive_entry_copy_gname(entry, tar->entry_gname.s); /* Parse out device numbers only for char and block specials. */ if (header->typeflag[0] == '3' || header->typeflag[0] == '4') { @@ -1175,10 +1173,16 @@ pax_header(struct archive_read *a, struct tar *tar, { size_t attr_length, l, line_length; char *line, *p; - wchar_t *key, *wp, *value; + char *key, *value; + wchar_t *wp; int err, err2; attr_length = strlen(attr); + tar->pax_hdrcharset_binary = 0; + archive_string_empty(&(tar->entry_gname)); + archive_string_empty(&(tar->entry_linkpath)); + archive_string_empty(&(tar->entry_pathname)); + archive_string_empty(&(tar->entry_uname)); err = ARCHIVE_OK; while (attr_length > 0) { /* Parse decimal length field at start of line. */ @@ -1221,49 +1225,24 @@ pax_header(struct archive_read *a, struct tar *tar, return (ARCHIVE_WARN); } - /* Ensure pax_entry buffer is big enough. */ - if (tar->pax_entry_length <= line_length) { - wchar_t *old_entry = tar->pax_entry; - - if (tar->pax_entry_length <= 0) - tar->pax_entry_length = 1024; - while (tar->pax_entry_length <= line_length + 1) - tar->pax_entry_length *= 2; - - old_entry = tar->pax_entry; - tar->pax_entry = (wchar_t *)realloc(tar->pax_entry, - tar->pax_entry_length * sizeof(wchar_t)); - if (tar->pax_entry == NULL) { - free(old_entry); - archive_set_error(&a->archive, ENOMEM, - "No memory"); - return (ARCHIVE_FATAL); - } - } - - /* Decode UTF-8 to wchar_t, null-terminate result. */ - if (utf8_decode(tar->pax_entry, p, - line_length - (p - attr) - 1)) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Invalid UTF8 character in pax extended attribute"); - err = err_combine(err, ARCHIVE_WARN); - } + /* Null-terminate the line. */ + attr[line_length - 1] = '\0'; - /* Null-terminate 'key' value. */ - wp = key = tar->pax_entry; - if (key[0] == L'=') + /* Find end of key and null terminate it. */ + key = p; + if (key[0] == '=') return (-1); - while (*wp && *wp != L'=') - ++wp; - if (*wp == L'\0') { + while (*p && *p != '=') + ++p; + if (*p == '\0') { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Invalid pax extended attributes"); return (ARCHIVE_WARN); } - *wp = 0; + *p = '\0'; /* Identify null-terminated 'value' portion. */ - value = wp + 1; + value = p + 1; /* Identify this attribute and set it in the entry. */ err2 = pax_attribute(tar, entry, key, value); @@ -1273,33 +1252,77 @@ pax_header(struct archive_read *a, struct tar *tar, attr += line_length; attr_length -= line_length; } + if (archive_strlen(&(tar->entry_gname)) > 0) { + value = tar->entry_gname.s; + if (tar->pax_hdrcharset_binary) + archive_entry_copy_gname(entry, value); + else { + wp = utf8_decode(tar, value, strlen(value)); + if (wp == NULL) + archive_entry_copy_gname(entry, value); + else + archive_entry_copy_gname_w(entry, wp); + } + } + if (archive_strlen(&(tar->entry_linkpath)) > 0) { + value = tar->entry_linkpath.s; + if (tar->pax_hdrcharset_binary) + archive_entry_copy_link(entry, value); + else { + wp = utf8_decode(tar, value, strlen(value)); + if (wp == NULL) + archive_entry_copy_link(entry, value); + else + archive_entry_copy_link_w(entry, wp); + } + } + if (archive_strlen(&(tar->entry_pathname)) > 0) { + value = tar->entry_pathname.s; + if (tar->pax_hdrcharset_binary) + archive_entry_copy_pathname(entry, value); + else { + wp = utf8_decode(tar, value, strlen(value)); + if (wp == NULL) + archive_entry_copy_pathname(entry, value); + else + archive_entry_copy_pathname_w(entry, wp); + } + } + if (archive_strlen(&(tar->entry_uname)) > 0) { + value = tar->entry_uname.s; + if (tar->pax_hdrcharset_binary) + archive_entry_copy_uname(entry, value); + else { + wp = utf8_decode(tar, value, strlen(value)); + if (wp == NULL) + archive_entry_copy_uname(entry, value); + else + archive_entry_copy_uname_w(entry, wp); + } + } return (err); } static int pax_attribute_xattr(struct archive_entry *entry, - wchar_t *name, wchar_t *value) + char *name, char *value) { - char *name_decoded, *name_narrow; + char *name_decoded; void *value_decoded; size_t value_len; - if (wcslen(name) < 18 || (wcsncmp(name, L"LIBARCHIVE.xattr.", 17)) != 0) + if (strlen(name) < 18 || (strncmp(name, "LIBARCHIVE.xattr.", 17)) != 0) return 3; name += 17; /* URL-decode name */ - name_narrow = wide_to_narrow(name); - if (name_narrow == NULL) - return 2; - name_decoded = url_decode(name_narrow); - free(name_narrow); + name_decoded = url_decode(name); if (name_decoded == NULL) return 2; /* Base-64 decode value */ - value_decoded = base64_decode(value, wcslen(value), &value_len); + value_decoded = base64_decode(value, strlen(value), &value_len); if (value_decoded == NULL) { free(name_decoded); return 1; @@ -1328,22 +1351,23 @@ pax_attribute_xattr(struct archive_entry *entry, */ static int pax_attribute(struct tar *tar, struct archive_entry *entry, - wchar_t *key, wchar_t *value) + char *key, char *value) { int64_t s; long n; + wchar_t *wp; switch (key[0]) { case 'G': /* GNU "0.0" sparse pax format. */ - if (wcscmp(key, L"GNU.sparse.numblocks") == 0) { + if (strcmp(key, "GNU.sparse.numblocks") == 0) { tar->sparse_offset = -1; tar->sparse_numbytes = -1; tar->sparse_gnu_major = 0; tar->sparse_gnu_minor = 0; } - if (wcscmp(key, L"GNU.sparse.offset") == 0) { - tar->sparse_offset = tar_atol10(value, wcslen(value)); + if (strcmp(key, "GNU.sparse.offset") == 0) { + tar->sparse_offset = tar_atol10(value, strlen(value)); if (tar->sparse_numbytes != -1) { gnu_add_sparse_entry(tar, tar->sparse_offset, tar->sparse_numbytes); @@ -1351,8 +1375,8 @@ pax_attribute(struct tar *tar, struct archive_entry *entry, tar->sparse_numbytes = -1; } } - if (wcscmp(key, L"GNU.sparse.numbytes") == 0) { - tar->sparse_numbytes = tar_atol10(value, wcslen(value)); + if (strcmp(key, "GNU.sparse.numbytes") == 0) { + tar->sparse_numbytes = tar_atol10(value, strlen(value)); if (tar->sparse_numbytes != -1) { gnu_add_sparse_entry(tar, tar->sparse_offset, tar->sparse_numbytes); @@ -1360,13 +1384,13 @@ pax_attribute(struct tar *tar, struct archive_entry *entry, tar->sparse_numbytes = -1; } } - if (wcscmp(key, L"GNU.sparse.size") == 0) { - tar->realsize = tar_atol10(value, wcslen(value)); + if (strcmp(key, "GNU.sparse.size") == 0) { + tar->realsize = tar_atol10(value, strlen(value)); archive_entry_set_size(entry, tar->realsize); } /* GNU "0.1" sparse pax format. */ - if (wcscmp(key, L"GNU.sparse.map") == 0) { + if (strcmp(key, "GNU.sparse.map") == 0) { tar->sparse_gnu_major = 0; tar->sparse_gnu_minor = 1; if (gnu_sparse_01_parse(tar, value) != ARCHIVE_OK) @@ -1374,18 +1398,23 @@ pax_attribute(struct tar *tar, struct archive_entry *entry, } /* GNU "1.0" sparse pax format */ - if (wcscmp(key, L"GNU.sparse.major") == 0) { - tar->sparse_gnu_major = tar_atol10(value, wcslen(value)); + if (strcmp(key, "GNU.sparse.major") == 0) { + tar->sparse_gnu_major = tar_atol10(value, strlen(value)); tar->sparse_gnu_pending = 1; } - if (wcscmp(key, L"GNU.sparse.minor") == 0) { - tar->sparse_gnu_minor = tar_atol10(value, wcslen(value)); + if (strcmp(key, "GNU.sparse.minor") == 0) { + tar->sparse_gnu_minor = tar_atol10(value, strlen(value)); tar->sparse_gnu_pending = 1; } - if (wcscmp(key, L"GNU.sparse.name") == 0) - archive_entry_copy_pathname_w(entry, value); - if (wcscmp(key, L"GNU.sparse.realsize") == 0) { - tar->realsize = tar_atol10(value, wcslen(value)); + if (strcmp(key, "GNU.sparse.name") == 0) { + wp = utf8_decode(tar, value, strlen(value)); + if (wp != NULL) + archive_entry_copy_pathname_w(entry, wp); + else + archive_entry_copy_pathname(entry, value); + } + if (strcmp(key, "GNU.sparse.realsize") == 0) { + tar->realsize = tar_atol10(value, strlen(value)); archive_entry_set_size(entry, tar->realsize); } break; @@ -1396,85 +1425,107 @@ pax_attribute(struct tar *tar, struct archive_entry *entry, if (strcmp(key, "LIBARCHIVE.xxxxxxx")==0) archive_entry_set_xxxxxx(entry, value); */ - if (wcsncmp(key, L"LIBARCHIVE.xattr.", 17)==0) + if (strncmp(key, "LIBARCHIVE.xattr.", 17)==0) pax_attribute_xattr(entry, key, value); break; case 'S': /* We support some keys used by the "star" archiver */ - if (wcscmp(key, L"SCHILY.acl.access")==0) - __archive_entry_acl_parse_w(entry, value, + if (strcmp(key, "SCHILY.acl.access")==0) { + wp = utf8_decode(tar, value, strlen(value)); + /* TODO: if (wp == NULL) */ + __archive_entry_acl_parse_w(entry, wp, ARCHIVE_ENTRY_ACL_TYPE_ACCESS); - else if (wcscmp(key, L"SCHILY.acl.default")==0) - __archive_entry_acl_parse_w(entry, value, + } else if (strcmp(key, "SCHILY.acl.default")==0) { + wp = utf8_decode(tar, value, strlen(value)); + /* TODO: if (wp == NULL) */ + __archive_entry_acl_parse_w(entry, wp, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT); - else if (wcscmp(key, L"SCHILY.devmajor")==0) - archive_entry_set_rdevmajor(entry, tar_atol10(value, wcslen(value))); - else if (wcscmp(key, L"SCHILY.devminor")==0) - archive_entry_set_rdevminor(entry, 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) - archive_entry_set_dev(entry, tar_atol10(value, wcslen(value))); - else if (wcscmp(key, L"SCHILY.ino")==0) - 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)); + } else if (strcmp(key, "SCHILY.devmajor")==0) { + archive_entry_set_rdevmajor(entry, + tar_atol10(value, strlen(value))); + } else if (strcmp(key, "SCHILY.devminor")==0) { + archive_entry_set_rdevminor(entry, + tar_atol10(value, strlen(value))); + } else if (strcmp(key, "SCHILY.fflags")==0) { + wp = utf8_decode(tar, value, strlen(value)); + /* TODO: if (wp == NULL) */ + archive_entry_copy_fflags_text_w(entry, wp); + } else if (strcmp(key, "SCHILY.dev")==0) { + archive_entry_set_dev(entry, + tar_atol10(value, strlen(value))); + } else if (strcmp(key, "SCHILY.ino")==0) { + archive_entry_set_ino(entry, + tar_atol10(value, strlen(value))); + } else if (strcmp(key, "SCHILY.nlink")==0) { + archive_entry_set_nlink(entry, + tar_atol10(value, strlen(value))); + } else if (strcmp(key, "SCHILY.realsize")==0) { + tar->realsize = tar_atol10(value, strlen(value)); archive_entry_set_size(entry, tar->realsize); } break; case 'a': - if (wcscmp(key, L"atime")==0) { + if (strcmp(key, "atime")==0) { pax_time(value, &s, &n); archive_entry_set_atime(entry, s, n); } break; case 'c': - if (wcscmp(key, L"ctime")==0) { + if (strcmp(key, "ctime")==0) { pax_time(value, &s, &n); archive_entry_set_ctime(entry, s, n); - } else if (wcscmp(key, L"charset")==0) { + } else if (strcmp(key, "charset")==0) { /* TODO: Publish charset information in entry. */ - } else if (wcscmp(key, L"comment")==0) { + } else if (strcmp(key, "comment")==0) { /* TODO: Publish comment in entry. */ } break; case 'g': - if (wcscmp(key, L"gid")==0) - archive_entry_set_gid(entry, tar_atol10(value, wcslen(value))); - else if (wcscmp(key, L"gname")==0) - archive_entry_copy_gname_w(entry, value); + if (strcmp(key, "gid")==0) { + archive_entry_set_gid(entry, + tar_atol10(value, strlen(value))); + } else if (strcmp(key, "gname")==0) { + archive_strcpy(&(tar->entry_gname), value); + } + break; + case 'h': + if (strcmp(key, "hdrcharset") == 0) { + if (strcmp(value, "BINARY") == 0) + tar->pax_hdrcharset_binary = 1; + else if (strcmp(value, "ISO-IR 10646 2000 UTF-8") == 0) + tar->pax_hdrcharset_binary = 0; + else { + /* TODO: Warn about unsupported hdrcharset */ + } + } break; case 'l': /* pax interchange doesn't distinguish hardlink vs. symlink. */ - if (wcscmp(key, L"linkpath")==0) { - if (archive_entry_hardlink(entry)) - archive_entry_copy_hardlink_w(entry, value); - else - archive_entry_copy_symlink_w(entry, value); + if (strcmp(key, "linkpath")==0) { + archive_strcpy(&(tar->entry_linkpath), value); } break; case 'm': - if (wcscmp(key, L"mtime")==0) { + if (strcmp(key, "mtime")==0) { pax_time(value, &s, &n); archive_entry_set_mtime(entry, s, n); } break; case 'p': - if (wcscmp(key, L"path")==0) - archive_entry_copy_pathname_w(entry, value); + if (strcmp(key, "path")==0) { + archive_strcpy(&(tar->entry_pathname), value); + } break; case 'r': /* POSIX has reserved 'realtime.*' */ break; case 's': /* POSIX has reserved 'security.*' */ - /* Someday: if (wcscmp(key, L"security.acl")==0) { ... } */ - if (wcscmp(key, L"size")==0) { + /* Someday: if (strcmp(key, "security.acl")==0) { ... } */ + if (strcmp(key, "size")==0) { /* "size" is the size of the data in the entry. */ tar->entry_bytes_remaining - = tar_atol10(value, wcslen(value)); + = tar_atol10(value, strlen(value)); /* * But, "size" is not necessarily the size of * the file on disk; if this is a sparse file, @@ -1492,10 +1543,12 @@ pax_attribute(struct tar *tar, struct archive_entry *entry, } break; case 'u': - if (wcscmp(key, L"uid")==0) - archive_entry_set_uid(entry, tar_atol10(value, wcslen(value))); - else if (wcscmp(key, L"uname")==0) - archive_entry_copy_uname_w(entry, value); + if (strcmp(key, "uid")==0) { + archive_entry_set_uid(entry, + tar_atol10(value, strlen(value))); + } else if (strcmp(key, "uname")==0) { + archive_strcpy(&(tar->entry_uname), value); + } break; } return (0); @@ -1507,7 +1560,7 @@ pax_attribute(struct tar *tar, struct archive_entry *entry, * parse a decimal time value, which may include a fractional portion */ static void -pax_time(const wchar_t *p, int64_t *ps, long *pn) +pax_time(const char *p, int64_t *ps, long *pn) { char digit; int64_t s; @@ -1575,9 +1628,9 @@ header_gnutar(struct archive_read *a, struct tar *tar, /* Copy filename over (to ensure null termination). */ header = (const struct archive_entry_header_gnutar *)h; - archive_strncpy(&(tar->entry_name), header->name, + archive_strncpy(&(tar->entry_pathname), header->name, sizeof(header->name)); - archive_entry_set_pathname(entry, tar->entry_name.s); + archive_entry_copy_pathname(entry, tar->entry_pathname.s); /* Fields common to ustar and GNU */ /* XXX Can the following be factored out since it's common @@ -1585,11 +1638,11 @@ header_gnutar(struct archive_read *a, struct tar *tar, * header_common, perhaps? */ archive_strncpy(&(tar->entry_uname), header->uname, sizeof(header->uname)); - archive_entry_set_uname(entry, tar->entry_uname.s); + archive_entry_copy_uname(entry, tar->entry_uname.s); archive_strncpy(&(tar->entry_gname), header->gname, sizeof(header->gname)); - archive_entry_set_gname(entry, tar->entry_gname.s); + archive_entry_copy_gname(entry, tar->entry_gname.s); /* Parse out device numbers only for char and block specials */ if (header->typeflag[0] == '3' || header->typeflag[0] == '4') { @@ -1743,9 +1796,9 @@ gnu_sparse_old_parse(struct tar *tar, */ static int -gnu_sparse_01_parse(struct tar *tar, const wchar_t *p) +gnu_sparse_01_parse(struct tar *tar, const char *p) { - const wchar_t *e; + const char *e; off_t offset = -1, size = -1; for (;;) { @@ -1780,12 +1833,11 @@ gnu_sparse_01_parse(struct tar *tar, const wchar_t *p) * don't support this format will extract the block map along with the * data and a separate post-process can restore the sparseness. * - * Unfortunately, GNU tar 1.16 adds bogus padding to the end of the - * entry that depends on the size of the map; this means we have to - * parse the sparse map when we read the header (otherwise, entry_skip - * will fail). This is why sparse_10_read is called from read_header - * above, instead of at the beginning of read_data, where it "should" - * go. + * Unfortunately, GNU tar 1.16 had a bug that added unnecessary + * padding to the body of the file when using this format. GNU tar + * 1.17 corrected this bug without bumping the version number, so + * it's not possible to support both variants. This code supports + * the later variant at the expense of not supporting the former. * * This variant also replaced GNU.sparse.size with GNU.sparse.realsize * and introduced the GNU.sparse.major/GNU.sparse.minor attributes. @@ -1949,7 +2001,7 @@ tar_atol8(const char *p, unsigned char_cnt) * it does obey locale. */ static int64_t -tar_atol10(const wchar_t *p, unsigned char_cnt) +tar_atol10(const char *p, unsigned char_cnt) { int64_t l, limit, last_digit_limit; int base, digit, sign; @@ -1982,10 +2034,7 @@ tar_atol10(const wchar_t *p, unsigned char_cnt) /* * Parse a base-256 integer. This is just a straight signed binary * value in big-endian order, except that the high-order bit is - * ignored. Remember that "int64_t" may or may not be exactly 64 - * bits; the implementation here tries to avoid making any assumptions - * about the actual size of an int64_t. It does assume we're using - * twos-complement arithmetic, though. + * ignored. */ static int64_t tar_atol256(const char *_p, unsigned char_cnt) @@ -2083,15 +2132,38 @@ readline(struct archive_read *a, struct tar *tar, const char **start, } } -static int -utf8_decode(wchar_t *dest, const char *src, size_t length) +static wchar_t * +utf8_decode(struct tar *tar, const char *src, size_t length) { - size_t n; + wchar_t *dest; + ssize_t n; int err; + /* Ensure pax_entry buffer is big enough. */ + if (tar->pax_entry_length <= length) { + wchar_t *old_entry = tar->pax_entry; + + if (tar->pax_entry_length <= 0) + tar->pax_entry_length = 1024; + while (tar->pax_entry_length <= length + 1) + tar->pax_entry_length *= 2; + + old_entry = tar->pax_entry; + tar->pax_entry = (wchar_t *)realloc(tar->pax_entry, + tar->pax_entry_length * sizeof(wchar_t)); + if (tar->pax_entry == NULL) { + free(old_entry); + /* TODO: Handle this error. */ + return (NULL); + } + } + + dest = tar->pax_entry; err = 0; while (length > 0) { n = UTF8_mbrtowc(dest, src, length); + if (n < 0) + return (NULL); if (n == 0) break; dest++; @@ -2099,13 +2171,13 @@ utf8_decode(wchar_t *dest, const char *src, size_t length) length -= n; } *dest++ = L'\0'; - return (err); + return (tar->pax_entry); } /* * Copied and simplified from FreeBSD libc/locale. */ -static size_t +static ssize_t UTF8_mbrtowc(wchar_t *pwc, const char *s, size_t n) { int ch, i, len, mask; @@ -2132,22 +2204,14 @@ UTF8_mbrtowc(wchar_t *pwc, const char *s, size_t n) } else if ((ch & 0xf8) == 0xf0) { mask = 0x07; len = 4; - } else if ((ch & 0xfc) == 0xf8) { - mask = 0x03; - len = 5; - } else if ((ch & 0xfe) == 0xfc) { - mask = 0x01; - len = 6; } else { - /* Invalid first byte; convert to '?' */ - *pwc = '?'; - return (1); + /* Invalid first byte. */ + return (-1); } if (n < (size_t)len) { - /* Invalid first byte; convert to '?' */ - *pwc = '?'; - return (1); + /* Valid first byte but truncated. */ + return (-2); } /* @@ -2193,7 +2257,7 @@ UTF8_mbrtowc(wchar_t *pwc, const char *s, size_t n) * omits line breaks; RFC1341 used for MIME requires both.) */ static char * -base64_decode(const wchar_t *src, size_t len, size_t *out_len) +base64_decode(const char *s, size_t len, size_t *out_len) { static const unsigned char digits[64] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N', @@ -2203,6 +2267,7 @@ base64_decode(const wchar_t *src, size_t len, size_t *out_len) '4','5','6','7','8','9','+','/' }; static unsigned char decode_table[128]; char *out, *d; + const unsigned char *src = (const unsigned char *)s; /* If the decode table is not yet initialized, prepare it. */ if (decode_table[digits[1]] != 1) { @@ -2263,43 +2328,6 @@ base64_decode(const wchar_t *src, size_t len, size_t *out_len) return (out); } -/* - * This is a little tricky because the C99 standard wcstombs() - * function returns the number of bytes that were converted, - * not the number that should be converted. As a result, - * we can never accurately size the output buffer (without - * doing a tedious output size calculation in advance). - * This approach (try a conversion, then try again if it fails) - * will almost always succeed on the first try, and is thus - * much faster, at the cost of sometimes requiring multiple - * passes while we expand the buffer. - */ -static char * -wide_to_narrow(const wchar_t *wval) -{ - int converted_length; - /* Guess an output buffer size and try the conversion. */ - int alloc_length = wcslen(wval) * 3; - char *mbs_val = (char *)malloc(alloc_length + 1); - if (mbs_val == NULL) - return (NULL); - converted_length = wcstombs(mbs_val, wval, alloc_length); - - /* If we exhausted the buffer, resize and try again. */ - while (converted_length >= alloc_length) { - free(mbs_val); - alloc_length *= 2; - mbs_val = (char *)malloc(alloc_length + 1); - if (mbs_val == NULL) - return (NULL); - converted_length = wcstombs(mbs_val, wval, alloc_length); - } - - /* Ensure a trailing null and return the final string. */ - mbs_val[alloc_length] = '\0'; - return (mbs_val); -} - static char * url_decode(const char *in) { diff --git a/contrib/libarchive-2/libarchive/archive_read_support_format_zip.c b/contrib/libarchive-2/libarchive/archive_read_support_format_zip.c index 7dcc4ea2b1..09e7411be8 100644 --- a/contrib/libarchive-2/libarchive/archive_read_support_format_zip.c +++ b/contrib/libarchive-2/libarchive/archive_read_support_format_zip.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_zip.c,v 1.16 2007/12/04 06:32:12 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_zip.c,v 1.21 2008/02/26 07:17:47 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_zip.c,v 1.16 #include "archive_entry.h" #include "archive_private.h" #include "archive_read_private.h" +#include "archive_endian.h" struct zip { /* entry_bytes_remaining is the number of bytes we expect. */ @@ -121,11 +122,6 @@ static int archive_read_format_zip_read_data(struct archive_read *, static int archive_read_format_zip_read_data_skip(struct archive_read *a); static int archive_read_format_zip_read_header(struct archive_read *, struct archive_entry *); -static int i2(const char *); -static int i4(const char *); -static unsigned int u2(const char *); -static unsigned int u4(const char *); -static uint64_t u8(const char *); static int zip_read_data_deflate(struct archive_read *a, const void **buff, size_t *size, off_t *offset); static int zip_read_data_none(struct archive_read *a, const void **buff, @@ -166,18 +162,12 @@ archive_read_support_format_zip(struct archive *_a) static int archive_read_format_zip_bid(struct archive_read *a) { - int bytes_read; - int bid = 0; - const void *h; const char *p; + const void *buff; + size_t bytes_avail; - if (a->archive.archive_format == ARCHIVE_FORMAT_ZIP) - bid += 1; - - bytes_read = (a->decompressor->read_ahead)(a, &h, 4); - if (bytes_read < 4) - return (-1); - p = (const char *)h; + if ((p = __archive_read_ahead(a, 4)) == NULL) + return (-1); /* * Bid of 30 here is: 16 bits for "PK", @@ -188,20 +178,116 @@ archive_read_format_zip_bid(struct archive_read *a) 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')) + || (p[2] == '\007' && p[3] == '\010') + || (p[2] == '0' && p[3] == '0')) return (30); } + + /* + * Attempt to handle self-extracting archives + * by noting a PE header and searching forward + * up to 64k for a 'PK\003\004' marker. + */ + if (p[0] == 'M' && p[1] == 'Z') { + /* + * TODO: Additional checks that this really is a PE + * file before we invoke the 128k lookahead below. + * No point in allocating a bigger lookahead buffer + * if we don't need to. + */ + /* + * TODO: Of course, the compression layer lookahead + * buffers aren't dynamically sized yet; they should be. + */ + bytes_avail = (a->decompressor->read_ahead)(a, &buff, 128*1024); + p = (const char *)buff; + + /* + * TODO: Optimize by jumping forward based on values + * in the PE header. Note that we don't need to be + * exact, but we mustn't skip too far. The search + * below will compensate if we undershoot. Skipping + * will also reduce the chance of false positives + * (which is not really all that high to begin with, + * so maybe skipping isn't really necessary). + */ + + while (p < bytes_avail + (const char *)buff) { + if (p[0] == 'P' && p[1] == 'K' /* "PK" signature */ + && p[2] == 3 && p[3] == 4 /* File entry */ + && p[8] == 8 /* compression == deflate */ + && p[9] == 0 /* High byte of compression */ + ) + { + return (30); + } + ++p; + } + } + return (0); } +/* + * Search forward for a "PK\003\004" file header. This handles the + * case of self-extracting archives, where there is an executable + * prepended to the ZIP archive. + */ +static int +skip_sfx(struct archive_read *a) +{ + const void *h; + const char *p, *q; + size_t skip, bytes; + + /* + * TODO: We should be able to skip forward by a bunch + * by lifting some values from the PE header. We don't + * need to be exact (we're still going to search forward + * to find the header), but it will speed things up and + * reduce the chance of a false positive. + */ + for (;;) { + bytes = (a->decompressor->read_ahead)(a, &h, 4096); + if (bytes < 4) + return (ARCHIVE_FATAL); + p = h; + q = p + bytes; + + /* + * Scan ahead until we find something that looks + * like the zip header. + */ + while (p + 4 < q) { + switch (p[3]) { + case '\004': + /* TODO: Additional verification here. */ + if (memcmp("PK\003\004", p, 4) == 0) { + skip = p - (const char *)h; + (a->decompressor->consume)(a, skip); + return (ARCHIVE_OK); + } + p += 4; + break; + case '\003': p += 1; break; + case 'K': p += 2; break; + case 'P': p += 3; break; + default: p += 4; break; + } + } + skip = p - (const char *)h; + (a->decompressor->consume)(a, skip); + } +} + static int archive_read_format_zip_read_header(struct archive_read *a, struct archive_entry *entry) { - int bytes_read; const void *h; const char *signature; struct zip *zip; + int r = ARCHIVE_OK, r1; a->archive.archive_format = ARCHIVE_FORMAT_ZIP; if (a->archive.archive_format_name == NULL) @@ -213,17 +299,43 @@ archive_read_format_zip_read_header(struct archive_read *a, zip->end_of_entry_cleanup = 0; zip->entry_uncompressed_bytes_read = 0; zip->entry_compressed_bytes_read = 0; - bytes_read = (a->decompressor->read_ahead)(a, &h, 4); - if (bytes_read < 4) + if ((h = __archive_read_ahead(a, 4)) == NULL) return (ARCHIVE_FATAL); signature = (const char *)h; + if (signature[0] == 'M' && signature[1] == 'Z') { + /* This is an executable? Must be self-extracting... */ + r = skip_sfx(a); + if (r < ARCHIVE_WARN) + return (r); + if ((h = __archive_read_ahead(a, 4)) == NULL) + return (ARCHIVE_FATAL); + signature = (const char *)h; + } + if (signature[0] != 'P' || signature[1] != 'K') { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Bad ZIP file"); return (ARCHIVE_FATAL); } + /* + * "PK00" signature is used for "split" archives that + * only have a single segment. This means we can just + * skip the PK00; the first real file header should follow. + */ + if (signature[2] == '0' && signature[3] == '0') { + (a->decompressor->consume)(a, 4); + if ((h = __archive_read_ahead(a, 4)) == NULL) + return (ARCHIVE_FATAL); + signature = (const char *)h; + if (signature[0] != 'P' || signature[1] != 'K') { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Bad ZIP file"); + return (ARCHIVE_FATAL); + } + } + if (signature[2] == '\001' && signature[3] == '\002') { /* Beginning of central directory. */ return (ARCHIVE_EOF); @@ -231,7 +343,10 @@ archive_read_format_zip_read_header(struct archive_read *a, if (signature[2] == '\003' && signature[3] == '\004') { /* Regular file entry. */ - return (zip_read_file_header(a, entry, zip)); + r1 = zip_read_file_header(a, entry, zip); + if (r1 != ARCHIVE_OK) + return (r1); + return (r); } if (signature[2] == '\005' && signature[3] == '\006') { @@ -261,21 +376,17 @@ zip_read_file_header(struct archive_read *a, struct archive_entry *entry, { const struct zip_file_header *p; const void *h; - int bytes_read; - bytes_read = - (a->decompressor->read_ahead)(a, &h, sizeof(struct zip_file_header)); - if (bytes_read < (int)sizeof(struct zip_file_header)) { + if ((p = __archive_read_ahead(a, sizeof *p)) == NULL) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Truncated ZIP file header"); return (ARCHIVE_FATAL); } - p = (const struct zip_file_header *)h; zip->version = p->version[0]; zip->system = p->version[1]; - zip->flags = i2(p->flags); - zip->compression = i2(p->compression); + zip->flags = archive_le16dec(p->flags); + zip->compression = archive_le16dec(p->compression); if (zip->compression < sizeof(compression_names)/sizeof(compression_names[0])) zip->compression_name = compression_names[zip->compression]; @@ -287,25 +398,24 @@ zip_read_file_header(struct archive_read *a, struct archive_entry *entry, zip->mode = 0; zip->uid = 0; zip->gid = 0; - zip->crc32 = i4(p->crc32); - zip->filename_length = i2(p->filename_length); - zip->extra_length = i2(p->extra_length); - zip->uncompressed_size = u4(p->uncompressed_size); - zip->compressed_size = u4(p->compressed_size); + zip->crc32 = archive_le32dec(p->crc32); + zip->filename_length = archive_le16dec(p->filename_length); + zip->extra_length = archive_le16dec(p->extra_length); + zip->uncompressed_size = archive_le32dec(p->uncompressed_size); + zip->compressed_size = archive_le32dec(p->compressed_size); (a->decompressor->consume)(a, sizeof(struct zip_file_header)); /* Read the filename. */ - bytes_read = (a->decompressor->read_ahead)(a, &h, zip->filename_length); - if (bytes_read < zip->filename_length) { + if ((h = __archive_read_ahead(a, zip->filename_length)) == NULL) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Truncated ZIP file header"); return (ARCHIVE_FATAL); } if (archive_string_ensure(&zip->pathname, zip->filename_length) == NULL) __archive_errx(1, "Out of memory"); - archive_strncpy(&zip->pathname, (const char *)h, zip->filename_length); + archive_strncpy(&zip->pathname, h, zip->filename_length); (a->decompressor->consume)(a, zip->filename_length); archive_entry_set_pathname(entry, zip->pathname.s); @@ -315,8 +425,7 @@ zip_read_file_header(struct archive_read *a, struct archive_entry *entry, zip->mode = AE_IFREG | 0777; /* Read the extra data. */ - bytes_read = (a->decompressor->read_ahead)(a, &h, zip->extra_length); - if (bytes_read < zip->extra_length) { + if ((h = __archive_read_ahead(a, zip->extra_length)) == NULL) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Truncated ZIP file header"); return (ARCHIVE_FATAL); @@ -387,21 +496,18 @@ archive_read_format_zip_read_data(struct archive_read *a, if (zip->end_of_entry) { if (!zip->end_of_entry_cleanup) { if (zip->flags & ZIP_LENGTH_AT_END) { - const void *h; const char *p; - int bytes_read = - (a->decompressor->read_ahead)(a, &h, 16); - if (bytes_read < 16) { + + if ((p = __archive_read_ahead(a, 16)) == NULL) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Truncated ZIP end-of-file record"); return (ARCHIVE_FATAL); } - p = (const char *)h; - zip->crc32 = i4(p + 4); - zip->compressed_size = u4(p + 8); - zip->uncompressed_size = u4(p + 12); - bytes_read = (a->decompressor->consume)(a, 16); + zip->crc32 = archive_le32dec(p + 4); + zip->compressed_size = archive_le32dec(p + 8); + zip->uncompressed_size = archive_le32dec(p + 12); + (a->decompressor->consume)(a, 16); } /* Check file size, CRC against these values. */ @@ -696,37 +802,6 @@ archive_read_format_zip_cleanup(struct archive_read *a) return (ARCHIVE_OK); } -static int -i2(const char *p) -{ - return ((0xff & (int)p[0]) + 256 * (0xff & (int)p[1])); -} - - -static int -i4(const char *p) -{ - return ((0xffff & i2(p)) + 0x10000 * (0xffff & i2(p+2))); -} - -static unsigned int -u2(const char *p) -{ - return ((0xff & (unsigned int)p[0]) + 256 * (0xff & (unsigned int)p[1])); -} - -static unsigned int -u4(const char *p) -{ - return u2(p) + 0x10000 * u2(p+2); -} - -static uint64_t -u8(const char *p) -{ - return u4(p) + 0x100000000LL * u4(p+4); -} - /* * The extra data is stored as a list of * id1+size1+data1 + id2+size2+data2 ... @@ -739,8 +814,8 @@ process_extra(const void* extra, struct zip* zip) const char *p = (const char *)extra; while (offset < zip->extra_length - 4) { - unsigned short headerid = u2(p + offset); - unsigned short datasize = u2(p + offset + 2); + unsigned short headerid = archive_le16dec(p + offset); + unsigned short datasize = archive_le16dec(p + offset + 2); offset += 4; if (offset + datasize > zip->extra_length) break; @@ -752,9 +827,9 @@ process_extra(const void* extra, struct zip* zip) case 0x0001: /* Zip64 extended information extra field. */ if (datasize >= 8) - zip->uncompressed_size = u8(p + offset); + zip->uncompressed_size = archive_le64dec(p + offset); if (datasize >= 16) - zip->compressed_size = u8(p + offset + 8); + zip->compressed_size = archive_le64dec(p + offset + 8); break; case 0x5455: { @@ -767,11 +842,12 @@ process_extra(const void* extra, struct zip* zip) { #ifdef DEBUG fprintf(stderr, "mtime: %lld -> %d\n", - (long long)zip->mtime, i4(p + offset)); + (long long)zip->mtime, + archive_le32dec(p + offset)); #endif if (datasize < 4) break; - zip->mtime = i4(p + offset); + zip->mtime = archive_le32dec(p + offset); offset += 4; datasize -= 4; } @@ -779,7 +855,7 @@ process_extra(const void* extra, struct zip* zip) { if (datasize < 4) break; - zip->atime = i4(p + offset); + zip->atime = archive_le32dec(p + offset); offset += 4; datasize -= 4; } @@ -787,7 +863,7 @@ process_extra(const void* extra, struct zip* zip) { if (datasize < 4) break; - zip->ctime = i4(p + offset); + zip->ctime = archive_le32dec(p + offset); offset += 4; datasize -= 4; } @@ -797,12 +873,13 @@ process_extra(const void* extra, struct zip* zip) /* Info-ZIP Unix Extra Field (type 2) "Ux". */ #ifdef DEBUG fprintf(stderr, "uid %d gid %d\n", - i2(p + offset), i2(p + offset + 2)); + archive_le16dec(p + offset), + archive_le16dec(p + offset + 2)); #endif if (datasize >= 2) - zip->uid = i2(p + offset); + zip->uid = archive_le16dec(p + offset); if (datasize >= 4) - zip->gid = i2(p + offset + 2); + zip->gid = archive_le16dec(p + offset + 2); break; default: break; diff --git a/contrib/libarchive-2/libarchive/archive_util.c b/contrib/libarchive-2/libarchive/archive_util.c index 2bc2844abc..413199a360 100644 --- a/contrib/libarchive-2/libarchive/archive_util.c +++ b/contrib/libarchive-2/libarchive/archive_util.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_util.c,v 1.15 2007/07/06 15:36:38 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_util.c,v 1.16 2007/12/30 04:58:21 kientzle Exp $"); #ifdef HAVE_SYS_TYPES_H #include diff --git a/contrib/libarchive-2/libarchive/archive_write_disk.c b/contrib/libarchive-2/libarchive/archive_write_disk.c index ec22086907..dfb6d35aec 100644 --- a/contrib/libarchive-2/libarchive/archive_write_disk.c +++ b/contrib/libarchive-2/libarchive/archive_write_disk.c @@ -25,7 +25,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_disk.c,v 1.17 2007/09/21 04:52:42 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_disk.c,v 1.22 2008/02/19 05:39:35 kientzle Exp $"); #ifdef HAVE_SYS_TYPES_H #include @@ -45,6 +45,9 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_write_disk.c,v 1.17 2007/09/21 04 #ifdef HAVE_SYS_TIME_H #include #endif +#ifdef HAVE_SYS_UTIME_H +#include +#endif #ifdef HAVE_EXT2FS_EXT2_FS_H #include /* for Linux file flags */ @@ -89,6 +92,10 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_write_disk.c,v 1.17 2007/09/21 04 #include "archive_entry.h" #include "archive_private.h" +#ifndef O_BINARY +#define O_BINARY 0 +#endif + struct fixup_entry { struct fixup_entry *next; mode_t mode; @@ -171,6 +178,8 @@ struct archive_write_disk { int fd; /* Current offset for writing data to the file. */ off_t offset; + /* Maximum size of file. */ + off_t filesize; /* Dir we were in before this restore; only for deep paths. */ int restore_pwd; /* Mode we should use for this entry; affected by _PERM and umask. */ @@ -302,6 +311,7 @@ _archive_write_header(struct archive *_a, struct archive_entry *entry) a->offset = 0; a->uid = a->user_uid; a->mode = archive_entry_mode(a->entry); + a->filesize = archive_entry_size(a->entry); archive_strcpy(&(a->_name_data), archive_entry_pathname(a->entry)); a->name = a->_name_data.s; archive_clear_error(&a->archive); @@ -425,8 +435,10 @@ _archive_write_header(struct archive *_a, struct archive_entry *entry) * If it's not open, tell our client not to try writing. * In particular, dirs, links, etc, don't get written to. */ - if (a->fd < 0) + if (a->fd < 0) { archive_entry_set_size(entry, 0); + a->filesize = 0; + } done: /* Restore the user's umask before returning. */ umask(a->user_umask); @@ -451,6 +463,7 @@ _archive_write_data_block(struct archive *_a, { struct archive_write_disk *a = (struct archive_write_disk *)_a; ssize_t bytes_written = 0; + int r = ARCHIVE_OK; __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, ARCHIVE_STATE_DATA, "archive_write_disk_block"); @@ -470,7 +483,13 @@ _archive_write_data_block(struct archive *_a, } /* Write the data. */ - while (size > 0) { + while (size > 0 && a->offset < a->filesize) { + if ((off_t)(a->offset + size) > a->filesize) { + size = (size_t)(a->filesize - a->offset); + archive_set_error(&a->archive, errno, + "Write request too large"); + r = ARCHIVE_WARN; + } bytes_written = write(a->fd, buff, size); if (bytes_written < 0) { archive_set_error(&a->archive, errno, "Write failed"); @@ -479,13 +498,14 @@ _archive_write_data_block(struct archive *_a, size -= bytes_written; a->offset += bytes_written; } - return (ARCHIVE_OK); + return (r); } static ssize_t _archive_write_data(struct archive *_a, const void *buff, size_t size) { struct archive_write_disk *a = (struct archive_write_disk *)_a; + off_t offset; int r; __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, @@ -493,10 +513,11 @@ _archive_write_data(struct archive *_a, const void *buff, size_t size) if (a->fd < 0) return (ARCHIVE_OK); + offset = a->offset; r = _archive_write_data_block(_a, buff, size, a->offset); if (r < ARCHIVE_OK) return (r); - return (size); + return (a->offset - offset); } static int @@ -622,7 +643,9 @@ archive_write_disk_new(void) a->archive.vtable = archive_write_disk_vtable(); a->lookup_uid = trivial_lookup_uid; a->lookup_gid = trivial_lookup_gid; +#ifdef HAVE_GETEUID a->user_uid = geteuid(); +#endif /* HAVE_GETEUID */ if (archive_string_ensure(&a->path_safe, 512) == NULL) { free(a); return (NULL); @@ -653,7 +676,7 @@ edit_deep_directories(struct archive_write_disk *a) return; /* Try to record our starting dir. */ - a->restore_pwd = open(".", O_RDONLY); + a->restore_pwd = open(".", O_RDONLY | O_BINARY); if (a->restore_pwd < 0) return; @@ -691,6 +714,14 @@ restore_entry(struct archive_write_disk *a) int ret = ARCHIVE_OK, en; if (a->flags & ARCHIVE_EXTRACT_UNLINK && !S_ISDIR(a->mode)) { + /* + * TODO: Fix this. Apparently, there are platforms + * that still allow root to hose the entire filesystem + * by unlinking a dir. The S_ISDIR() test above + * prevents us from using unlink() here if the new + * object is a dir, but that doesn't mean the old + * object isn't a dir. + */ if (unlink(a->name) == 0) { /* We removed it, we're done. */ } else if (errno == ENOENT) { @@ -829,8 +860,20 @@ create_filesystem_object(struct archive_write_disk *a) /* We identify hard/symlinks according to the link names. */ /* Since link(2) and symlink(2) don't handle modes, we're done here. */ linkname = archive_entry_hardlink(a->entry); - if (linkname != NULL) - return link(linkname, a->name) ? errno : 0; + if (linkname != NULL) { + r = link(linkname, a->name) ? errno : 0; + /* + * New cpio and pax formats allow hardlink entries + * to carry data, so we may have to open the file + * for hardlink entries. + */ + if (r == 0 && a->filesize > 0) { + a->fd = open(a->name, O_WRONLY | O_TRUNC | O_BINARY); + if (a->fd < 0) + r = errno; + } + return (r); + } linkname = archive_entry_symlink(a->entry); if (linkname != NULL) return symlink(linkname, a->name) ? errno : 0; @@ -850,24 +893,38 @@ create_filesystem_object(struct archive_write_disk *a) */ mode = final_mode & 0777; - switch (a->mode & S_IFMT) { + switch (a->mode & AE_IFMT) { default: /* POSIX requires that we fall through here. */ /* FALLTHROUGH */ - case S_IFREG: + case AE_IFREG: a->fd = open(a->name, - O_WRONLY | O_CREAT | O_EXCL, mode); + O_WRONLY | O_CREAT | O_EXCL | O_BINARY, mode); r = (a->fd < 0); break; - case S_IFCHR: + case AE_IFCHR: +#ifdef HAVE_MKNOD + /* Note: we use AE_IFCHR for the case label, and + * S_IFCHR for the mknod() call. This is correct. */ r = mknod(a->name, mode | S_IFCHR, archive_entry_rdev(a->entry)); +#else + /* TODO: Find a better way to warn about our inability + * to restore a char device node. */ + return (EINVAL); +#endif /* HAVE_MKNOD */ break; - case S_IFBLK: + case AE_IFBLK: +#ifdef HAVE_MKNOD r = mknod(a->name, mode | S_IFBLK, archive_entry_rdev(a->entry)); +#else + /* TODO: Find a better way to warn about our inability + * to restore a block device node. */ + return (EINVAL); +#endif /* HAVE_MKNOD */ break; - case S_IFDIR: + case AE_IFDIR: mode = (mode | MINIMUM_DIR_MODE) & MAXIMUM_DIR_MODE; r = mkdir(a->name, mode); if (r == 0) { @@ -880,8 +937,14 @@ create_filesystem_object(struct archive_write_disk *a) a->todo &= ~TODO_MODE; } break; - case S_IFIFO: + case AE_IFIFO: +#ifdef HAVE_MKFIFO r = mkfifo(a->name, mode); +#else + /* TODO: Find a better way to warn about our inability + * to restore a fifo. */ + return (EINVAL); +#endif /* HAVE_MKFIFO */ break; } @@ -1427,28 +1490,34 @@ set_ownership(struct archive_write_disk *a) } #ifdef HAVE_FCHOWN - if (a->fd >= 0 && fchown(a->fd, a->uid, a->gid) == 0) - goto success; + /* If we have an fd, we can avoid a race. */ + if (a->fd >= 0 && fchown(a->fd, a->uid, a->gid) == 0) { + /* We've set owner and know uid/gid are correct. */ + a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); + return (ARCHIVE_OK); + } #endif + /* We prefer lchown() but will use chown() if that's all we have. */ + /* Of course, if we have neither, this will always fail. */ #ifdef HAVE_LCHOWN - if (lchown(a->name, a->uid, a->gid) == 0) - goto success; -#else - if (!S_ISLNK(a->mode) && chown(a->name, a->uid, a->gid) == 0) - goto success; + if (lchown(a->name, a->uid, a->gid) == 0) { + /* We've set owner and know uid/gid are correct. */ + a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); + return (ARCHIVE_OK); + } +#elif HAVE_CHOWN + if (!S_ISLNK(a->mode) && chown(a->name, a->uid, a->gid) == 0) { + /* We've set owner and know uid/gid are correct. */ + a->todo &= ~(TODO_OWNER | TODO_SGID_CHECK | TODO_SUID_CHECK); + return (ARCHIVE_OK); + } #endif archive_set_error(&a->archive, errno, "Can't set user=%d/group=%d for %s", a->uid, a->gid, a->name); return (ARCHIVE_WARN); -success: - a->todo &= ~TODO_OWNER; - /* We know the user/group are correct now. */ - a->todo &= ~TODO_SGID_CHECK; - a->todo &= ~TODO_SUID_CHECK; - return (ARCHIVE_OK); } #ifdef HAVE_UTIMES @@ -1786,7 +1855,7 @@ set_fflags_platform(struct archive_write_disk *a, int fd, const char *name, /* If we weren't given an fd, open it ourselves. */ if (myfd < 0) - myfd = open(name, O_RDONLY|O_NONBLOCK); + myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY); if (myfd < 0) return (ARCHIVE_OK); diff --git a/contrib/libarchive-2/libarchive/archive_write_open_filename.c b/contrib/libarchive-2/libarchive/archive_write_open_filename.c index fcaaaca4a6..72eeb54053 100644 --- a/contrib/libarchive-2/libarchive/archive_write_open_filename.c +++ b/contrib/libarchive-2/libarchive/archive_write_open_filename.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_open_filename.c,v 1.19 2007/01/09 08:05:56 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_open_filename.c,v 1.20 2008/02/19 05:46:58 kientzle Exp $"); #ifdef HAVE_SYS_STAT_H #include @@ -47,6 +47,10 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_write_open_filename.c,v 1.19 2007 #include "archive.h" +#ifndef O_BINARY +#define O_BINARY 0 +#endif + struct write_file_data { int fd; char filename[1]; @@ -95,7 +99,7 @@ file_open(struct archive *a, void *client_data) struct stat st; mine = (struct write_file_data *)client_data; - flags = O_WRONLY | O_CREAT | O_TRUNC; + flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY; /* * Open the file. diff --git a/contrib/libarchive-2/libarchive/archive_write_set_compression_bzip2.c b/contrib/libarchive-2/libarchive/archive_write_set_compression_bzip2.c index b32167c364..272ae26e52 100644 --- a/contrib/libarchive-2/libarchive/archive_write_set_compression_bzip2.c +++ b/contrib/libarchive-2/libarchive/archive_write_set_compression_bzip2.c @@ -28,7 +28,7 @@ /* Don't compile this if we don't have bzlib. */ #if HAVE_BZLIB_H -__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_compression_bzip2.c,v 1.12 2007/05/29 01:00:19 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_compression_bzip2.c,v 1.13 2007/12/30 04:58:21 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include diff --git a/contrib/libarchive-2/libarchive/archive_write_set_compression_gzip.c b/contrib/libarchive-2/libarchive/archive_write_set_compression_gzip.c index f43fa80d42..18abbdf67b 100644 --- a/contrib/libarchive-2/libarchive/archive_write_set_compression_gzip.c +++ b/contrib/libarchive-2/libarchive/archive_write_set_compression_gzip.c @@ -28,7 +28,7 @@ /* Don't compile this if we don't have zlib. */ #if HAVE_ZLIB_H -__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_compression_gzip.c,v 1.14 2007/05/29 01:00:19 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_compression_gzip.c,v 1.16 2008/02/21 03:21:50 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include @@ -106,6 +106,21 @@ archive_compressor_gzip_init(struct archive_write *a) return (ret); } + /* + * The next check is a temporary workaround until the gzip + * code can be overhauled some. The code should not require + * that compressed_buffer_size == bytes_per_block. Removing + * this assumption will allow us to compress larger chunks at + * a time, which should improve overall performance + * marginally. As a minor side-effect, such a cleanup would + * allow us to support truly arbitrary block sizes. + */ + if (a->bytes_per_block < 10) { + archive_set_error(&a->archive, EINVAL, + "GZip compressor requires a minimum 10 byte block size"); + return (ARCHIVE_FATAL); + } + state = (struct private_data *)malloc(sizeof(*state)); if (state == NULL) { archive_set_error(&a->archive, ENOMEM, @@ -114,6 +129,10 @@ archive_compressor_gzip_init(struct archive_write *a) } memset(state, 0, sizeof(*state)); + /* + * See comment above. We should set compressed_buffer_size to + * max(bytes_per_block, 65536), but the code can't handle that yet. + */ state->compressed_buffer_size = a->bytes_per_block; state->compressed = (unsigned char *)malloc(state->compressed_buffer_size); state->crc = crc32(0L, NULL, 0); diff --git a/contrib/libarchive-2/libarchive/archive_write_set_compression_none.c b/contrib/libarchive-2/libarchive/archive_write_set_compression_none.c index bb8555ef4e..bdecb240d9 100644 --- a/contrib/libarchive-2/libarchive/archive_write_set_compression_none.c +++ b/contrib/libarchive-2/libarchive/archive_write_set_compression_none.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_compression_none.c,v 1.15 2007/05/29 01:00:19 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_compression_none.c,v 1.16 2007/12/30 04:58:22 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include diff --git a/contrib/libarchive-2/libarchive/archive_write_set_format_ar.c b/contrib/libarchive-2/libarchive/archive_write_set_format_ar.c index 404b651311..2e77f1bd89 100644 --- a/contrib/libarchive-2/libarchive/archive_write_set_format_ar.c +++ b/contrib/libarchive-2/libarchive/archive_write_set_format_ar.c @@ -26,7 +26,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_ar.c,v 1.3 2007/05/29 01:00:19 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_ar.c,v 1.5 2008/01/31 08:11:01 kaiw Exp $"); #ifdef HAVE_ERRNO_H #include @@ -75,6 +75,7 @@ static int archive_write_ar_header(struct archive_write *, 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(struct archive_write *); static int archive_write_ar_finish_entry(struct archive_write *); static const char *ar_basename(const char *path); static int format_octal(int64_t v, char *p, int s); @@ -126,7 +127,7 @@ archive_write_set_format_ar(struct archive_write *a) a->format_write_header = archive_write_ar_header; a->format_write_data = archive_write_ar_data; - a->format_finish = NULL; + a->format_finish = archive_write_ar_finish; a->format_destroy = archive_write_ar_destroy; a->format_finish_entry = archive_write_ar_finish_entry; return (ARCHIVE_OK); @@ -397,6 +398,23 @@ archive_write_ar_destroy(struct archive_write *a) return (ARCHIVE_OK); } +static int +archive_write_ar_finish(struct archive_write *a) +{ + int ret; + + /* + * If we haven't written anything yet, we need to write + * the ar global header now to make it a valid ar archive. + */ + if (a->archive.file_position == 0) { + ret = (a->compressor.write)(a, "!\n", 8); + return (ret); + } + + return (ARCHIVE_OK); +} + static int archive_write_ar_finish_entry(struct archive_write *a) { diff --git a/contrib/libarchive-2/libarchive/archive_write_set_format_cpio.c b/contrib/libarchive-2/libarchive/archive_write_set_format_cpio.c index c8a6a7ac5e..45cb4e74b6 100644 --- a/contrib/libarchive-2/libarchive/archive_write_set_format_cpio.c +++ b/contrib/libarchive-2/libarchive/archive_write_set_format_cpio.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio.c,v 1.12 2007/10/12 04:11:31 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio.c,v 1.13 2007/12/30 04:58:22 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include diff --git a/contrib/libarchive-2/libarchive/archive_write_set_format_cpio_newc.c b/contrib/libarchive-2/libarchive/archive_write_set_format_cpio_newc.c index e50544b45f..d11176c1c1 100644 --- a/contrib/libarchive-2/libarchive/archive_write_set_format_cpio_newc.c +++ b/contrib/libarchive-2/libarchive/archive_write_set_format_cpio_newc.c @@ -25,7 +25,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio_newc.c,v 1.2 2007/10/12 04:11:31 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio_newc.c,v 1.3 2008/01/23 05:43:25 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include @@ -176,9 +176,15 @@ archive_write_newc_header(struct archive_write *a, struct archive_entry *entry) cpio->entry_bytes_remaining = archive_entry_size(entry); cpio->padding = 3 & (-cpio->entry_bytes_remaining); + /* Write the symlink now. */ - if (p != NULL && *p != '\0') + if (p != NULL && *p != '\0') { ret = (a->compressor.write)(a, p, strlen(p)); + if (ret != ARCHIVE_OK) + return (ARCHIVE_FATAL); + pad = 0x3 & -strlen(p); + ret = (a->compressor.write)(a, "\0\0\0", pad); + } return (ret); } diff --git a/contrib/libarchive-2/libarchive/archive_write_set_format_pax.c b/contrib/libarchive-2/libarchive/archive_write_set_format_pax.c index cedbfd75c9..a1bd688115 100644 --- a/contrib/libarchive-2/libarchive/archive_write_set_format_pax.c +++ b/contrib/libarchive-2/libarchive/archive_write_set_format_pax.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_pax.c,v 1.41 2007/05/29 01:00:19 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_pax.c,v 1.42 2007/12/30 04:58:22 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include @@ -383,19 +383,25 @@ archive_write_pax_header(struct archive_write *a, struct archive_entry *entry_original) { struct archive_entry *entry_main; - const char *linkname, *p; + const char *p; char *t; - const char *hardlink; const wchar_t *wp; const char *suffix_start; int need_extension, r, ret; struct pax *pax; + const char *hdrcharset = NULL; + const char *hardlink; + const char *path = NULL, *linkpath = NULL; + const char *uname = NULL, *gname = NULL; + const wchar_t *path_w = NULL, *linkpath_w = NULL; + const wchar_t *uname_w = NULL, *gname_w = NULL; char paxbuff[512]; char ustarbuff[512]; char ustar_entry_name[256]; char pax_entry_name[256]; + ret = ARCHIVE_OK; need_extension = 0; pax = (struct pax *)a->format_data; @@ -441,54 +447,110 @@ archive_write_pax_header(struct archive_write *a, entry_main = archive_entry_clone(entry_original); archive_string_empty(&(pax->pax_header)); /* Blank our work area. */ + /* + * First, check the name fields and see if any of them + * require binary coding. If any of them does, then all of + * them do. + */ + hdrcharset = NULL; + path = archive_entry_pathname(entry_main); + path_w = archive_entry_pathname_w(entry_main); + if (path != NULL && path_w == NULL) { + archive_set_error(&a->archive, EILSEQ, + "Can't translate pathname '%s' to UTF-8", path); + ret = ARCHIVE_WARN; + hdrcharset = "BINARY"; + } + uname = archive_entry_uname(entry_main); + uname_w = archive_entry_uname_w(entry_main); + if (uname != NULL && uname_w == NULL) { + archive_set_error(&a->archive, EILSEQ, + "Can't translate uname '%s' to UTF-8", uname); + ret = ARCHIVE_WARN; + hdrcharset = "BINARY"; + } + gname = archive_entry_gname(entry_main); + gname_w = archive_entry_gname_w(entry_main); + if (gname != NULL && gname_w == NULL) { + archive_set_error(&a->archive, EILSEQ, + "Can't translate gname '%s' to UTF-8", gname); + ret = ARCHIVE_WARN; + hdrcharset = "BINARY"; + } + linkpath = hardlink; + if (linkpath != NULL) { + linkpath_w = archive_entry_hardlink_w(entry_main); + } else { + linkpath = archive_entry_symlink(entry_main); + if (linkpath != NULL) + linkpath_w = archive_entry_symlink_w(entry_main); + } + if (linkpath != NULL && linkpath_w == NULL) { + archive_set_error(&a->archive, EILSEQ, + "Can't translate linkpath '%s' to UTF-8", linkpath); + ret = ARCHIVE_WARN; + hdrcharset = "BINARY"; + } + + /* Store the header encoding first, to be nice to readers. */ + if (hdrcharset != NULL) + add_pax_attr(&(pax->pax_header), "hdrcharset", hdrcharset); + /* * Determining whether or not the name is too big is ugly * because of the rules for dividing names between 'name' and * 'prefix' fields. Here, I pick out the longest possible * suffix, then test whether the remaining prefix is too long. */ - wp = archive_entry_pathname_w(entry_main); - p = archive_entry_pathname(entry_main); - if (strlen(p) <= 100) /* Short enough for just 'name' field */ - suffix_start = p; /* Record a zero-length prefix */ + if (strlen(path) <= 100) /* Short enough for just 'name' field */ + suffix_start = path; /* Record a zero-length prefix */ else /* Find the largest suffix that fits in 'name' field. */ - suffix_start = strchr(p + strlen(p) - 100 - 1, '/'); + suffix_start = strchr(path + strlen(path) - 100 - 1, '/'); /* * If name is too long, or has non-ASCII characters, add - * 'path' to pax extended attrs. + * 'path' to pax extended attrs. (Note that an unconvertible + * name must have non-ASCII characters.) */ - if (suffix_start == NULL || suffix_start - p > 155 || has_non_ASCII(wp)) { - add_pax_attr_w(&(pax->pax_header), "path", wp); + if (suffix_start == NULL || suffix_start - path > 155 + || path_w == NULL || has_non_ASCII(path_w)) { + if (path_w == NULL || hdrcharset != NULL) + /* Can't do UTF-8, so store it raw. */ + add_pax_attr(&(pax->pax_header), "path", path); + else + add_pax_attr_w(&(pax->pax_header), "path", path_w); archive_entry_set_pathname(entry_main, - build_ustar_entry_name(ustar_entry_name, p, strlen(p), NULL)); + build_ustar_entry_name(ustar_entry_name, + path, strlen(path), NULL)); need_extension = 1; } - /* If link name is too long or has non-ASCII characters, add - * 'linkpath' to pax extended attrs. */ - linkname = hardlink; - if (linkname == NULL) - linkname = archive_entry_symlink(entry_main); - - if (linkname != NULL) { - /* There is a link name, get the wide version as well. */ - if (hardlink != NULL) - wp = archive_entry_hardlink_w(entry_main); - else - wp = archive_entry_symlink_w(entry_main); - - /* If the link is long or has a non-ASCII character, - * store it as a pax extended attribute. */ - if (strlen(linkname) > 100 || has_non_ASCII(wp)) { - add_pax_attr_w(&(pax->pax_header), "linkpath", wp); - if (hardlink != NULL) - archive_entry_set_hardlink(entry_main, - "././@LongHardLink"); + if (linkpath != NULL) { + /* If link name is too long or has non-ASCII characters, add + * 'linkpath' to pax extended attrs. */ + if (strlen(linkpath) > 100 || linkpath_w == NULL + || linkpath_w == NULL || has_non_ASCII(linkpath_w)) { + if (linkpath_w == NULL || hdrcharset != NULL) + /* If the linkpath is not convertible + * to wide, or we're encoding in + * binary anyway, store it raw. */ + add_pax_attr(&(pax->pax_header), + "linkpath", linkpath); else - archive_entry_set_symlink(entry_main, - "././@LongSymLink"); + /* If the link is long or has a + * non-ASCII character, store it as a + * pax extended attribute. */ + add_pax_attr_w(&(pax->pax_header), + "linkpath", linkpath_w); + if (strlen(linkpath) > 100) { + if (hardlink != NULL) + archive_entry_set_hardlink(entry_main, + "././@LongHardLink"); + else + archive_entry_set_symlink(entry_main, + "././@LongSymLink"); + } need_extension = 1; } } @@ -509,12 +571,20 @@ archive_write_pax_header(struct archive_write *a, /* If group name is too large or has non-ASCII characters, add * 'gname' to pax extended attrs. */ - p = archive_entry_gname(entry_main); - wp = archive_entry_gname_w(entry_main); - if (p != NULL && (strlen(p) > 31 || has_non_ASCII(wp))) { - add_pax_attr_w(&(pax->pax_header), "gname", wp); - archive_entry_set_gname(entry_main, NULL); - need_extension = 1; + if (gname != NULL) { + if (strlen(gname) > 31 + || gname_w == NULL + || has_non_ASCII(gname_w)) + { + if (gname_w == NULL || hdrcharset != NULL) { + add_pax_attr(&(pax->pax_header), + "gname", gname); + } else { + add_pax_attr_w(&(pax->pax_header), + "gname", gname_w); + } + need_extension = 1; + } } /* If numeric UID is too large, add 'uid' to pax extended attrs. */ @@ -524,14 +594,21 @@ archive_write_pax_header(struct archive_write *a, need_extension = 1; } - /* If user name is too large, add 'uname' to pax extended attrs. */ - /* TODO: If uname has non-ASCII characters, use pax attribute. */ - p = archive_entry_uname(entry_main); - wp = archive_entry_uname_w(entry_main); - if (p != NULL && (strlen(p) > 31 || has_non_ASCII(wp))) { - add_pax_attr_w(&(pax->pax_header), "uname", wp); - archive_entry_set_uname(entry_main, NULL); - need_extension = 1; + /* Add 'uname' to pax extended attrs if necessary. */ + if (uname != NULL) { + if (strlen(uname) > 31 + || uname_w == NULL + || has_non_ASCII(uname_w)) + { + if (uname_w == NULL || hdrcharset != NULL) { + add_pax_attr(&(pax->pax_header), + "uname", uname); + } else { + add_pax_attr_w(&(pax->pax_header), + "uname", uname_w); + } + need_extension = 1; + } } /* @@ -733,7 +810,6 @@ archive_write_pax_header(struct archive_write *a, __archive_write_format_header_ustar(a, ustarbuff, entry_main, -1, 0); /* If we built any extended attributes, write that entry first. */ - ret = ARCHIVE_OK; if (archive_strlen(&(pax->pax_header)) > 0) { struct archive_entry *pax_attr_entry; time_t s; @@ -793,13 +869,13 @@ archive_write_pax_header(struct archive_write *a, /* Standard ustar doesn't support ctime. */ archive_entry_set_ctime(pax_attr_entry, 0, 0); - ret = __archive_write_format_header_ustar(a, paxbuff, + r = __archive_write_format_header_ustar(a, paxbuff, pax_attr_entry, 'x', 1); archive_entry_free(pax_attr_entry); /* Note that the 'x' header shouldn't ever fail to format */ - if (ret != 0) { + if (r != 0) { const char *msg = "archive_write_pax_header: " "'x' header failed?! This can't happen.\n"; write(2, msg, strlen(msg)); @@ -986,12 +1062,19 @@ build_ustar_entry_name(char *dest, const char *src, size_t src_length, * The ustar header for the pax extended attributes must have a * reasonable name: SUSv3 suggests 'dirname'/PaxHeader/'filename' * - * Joerg Schiling has argued that this is unnecessary because, in practice, - * if the pax extended attributes get extracted as regular files, noone is - * going to bother reading those attributes to manually restore them. - * Based on this, 'star' uses /tmp/PaxHeader/'basename' as the ustar header - * name. This is a tempting argument, but I'm not entirely convinced. - * I'm also uncomfortable with the fact that "/tmp" is a Unix-ism. + * Joerg Schilling has argued that this is unnecessary because, in + * practice, if the pax extended attributes get extracted as regular + * files, noone is going to bother reading those attributes to + * manually restore them. Based on this, 'star' uses + * /tmp/PaxHeader/'basename' as the ustar header name. This is a + * tempting argument, in part because it's simpler than the SUSv3 + * recommendation, but I'm not entirely convinced. I'm also + * uncomfortable with the fact that "/tmp" is a Unix-ism. + * + * GNU tar uses 'dirname'/PaxHeader./'filename', where the PID is + * the PID of the archiving process. This seems unnecessarily complex + * to me, as I don't see much value to separating the headers from + * extracting multiple versions of an archive. * * The following routine implements the SUSv3 recommendation, and is * much simpler because build_ustar_entry_name() above already does diff --git a/contrib/libarchive-2/libarchive/archive_write_set_format_ustar.c b/contrib/libarchive-2/libarchive/archive_write_set_format_ustar.c index 287afe0657..a7d26c9057 100644 --- a/contrib/libarchive-2/libarchive/archive_write_set_format_ustar.c +++ b/contrib/libarchive-2/libarchive/archive_write_set_format_ustar.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_ustar.c,v 1.24 2007/06/11 05:17:30 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_ustar.c,v 1.25 2007/12/30 04:58:22 kientzle Exp $"); #ifdef HAVE_ERRNO_H diff --git a/contrib/libarchive-2/libarchive/cpio.5 b/contrib/libarchive-2/libarchive/cpio.5 index 2f298332d1..9dbdc6d840 100644 --- a/contrib/libarchive-2/libarchive/cpio.5 +++ b/contrib/libarchive-2/libarchive/cpio.5 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD$ +.\" $FreeBSD: src/lib/libarchive/cpio.5,v 1.1 2007/12/30 04:58:22 kientzle Exp $ .\" .Dd October 5, 2007 .Dt CPIO 5 diff --git a/contrib/libarchive-2/libarchive/filter_fork.c b/contrib/libarchive-2/libarchive/filter_fork.c index c71cf6883f..8cad9e2f09 100644 --- a/contrib/libarchive-2/libarchive/filter_fork.c +++ b/contrib/libarchive-2/libarchive/filter_fork.c @@ -25,7 +25,7 @@ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/filter_fork.c,v 1.1 2007/05/29 01:00:20 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/filter_fork.c,v 1.2 2007/12/30 04:58:22 kientzle Exp $"); #if defined(HAVE_POLL) # if defined(HAVE_POLL_H) diff --git a/contrib/libarchive-2/libarchive/libarchive-formats.5 b/contrib/libarchive-2/libarchive/libarchive-formats.5 index 0606a5ba1d..0346d8f5af 100644 --- a/contrib/libarchive-2/libarchive/libarchive-formats.5 +++ b/contrib/libarchive-2/libarchive/libarchive-formats.5 @@ -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.14 2007/04/05 05:07:53 kientzle Exp $ +.\" $FreeBSD: src/lib/libarchive/libarchive-formats.5,v 1.15 2007/12/30 04:58:22 kientzle Exp $ .\" .Dd April 27, 2004 .Dt libarchive-formats 3 diff --git a/contrib/libarchive-2/libarchive/libarchive_internals.3 b/contrib/libarchive-2/libarchive/libarchive_internals.3 index a84c9406d3..9a42b76d4e 100644 --- a/contrib/libarchive-2/libarchive/libarchive_internals.3 +++ b/contrib/libarchive-2/libarchive/libarchive_internals.3 @@ -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_internals.3,v 1.1 2007/05/29 01:00:20 kientzle Exp $ +.\" $FreeBSD: src/lib/libarchive/libarchive_internals.3,v 1.2 2007/12/30 04:58:22 kientzle Exp $ .\" .Dd April 16, 2007 .Dt LIBARCHIVE 3 diff --git a/contrib/libarchive-2/tar/bsdtar.1 b/contrib/libarchive-2/tar/bsdtar.1 index db6a10aa1c..ec22160d99 100644 --- a/contrib/libarchive-2/tar/bsdtar.1 +++ b/contrib/libarchive-2/tar/bsdtar.1 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: src/usr.bin/tar/bsdtar.1,v 1.35 2007/05/29 05:39:10 kientzle Exp $ +.\" $FreeBSD: src/usr.bin/tar/bsdtar.1,v 1.37 2008/01/22 07:23:44 kientzle Exp $ .\" .Dd April 13, 2004 .Dt BSDTAR 1 @@ -232,16 +232,9 @@ All symbolic links will be followed. Normally, symbolic links are archived as such. With this option, the target of the link will be archived instead. .It Fl l -If -.Ev POSIXLY_CORRECT -is specified in the environment, this is a synonym for the +This is a synonym for the .Fl -check-links option. -Otherwise, an error will be displayed. -Users who desire behavior compatible with GNU tar should use -the -.Fl -one-file-system -option instead. .It Fl m (x mode only) Do not extract modification time. @@ -422,11 +415,6 @@ The locale to use. See .Xr environ 7 for more information. -.It Ev POSIXLY_CORRECT -If this environment variable is defined, the -.Fl l -option will be interpreted in accordance with -.St -p1003.1-96 . .It Ev TAPE The default tape device. The @@ -681,13 +669,16 @@ This is a complete re-implementation based on the .Xr libarchive 3 library. .Sh BUGS -POSIX and GNU violently disagree about the meaning of the +This program follows +.St -p1003.1-96 +for the definition of the .Fl l option. -Because of the potential for disaster if someone expects -one behavior and gets the other, the +Note that GNU tar prior to version 1.15 treated .Fl l -option is deliberately broken in this implementation. +as a synonym for the +.Fl -one-file-system +option. .Pp The .Fl C Pa dir diff --git a/contrib/libarchive-2/tar/bsdtar.c b/contrib/libarchive-2/tar/bsdtar.c index d20a60dffa..fbc66c1d73 100644 --- a/contrib/libarchive-2/tar/bsdtar.c +++ b/contrib/libarchive-2/tar/bsdtar.c @@ -24,7 +24,7 @@ */ #include "bsdtar_platform.h" -__FBSDID("$FreeBSD: src/usr.bin/tar/bsdtar.c,v 1.77 2007/09/09 00:07:18 kientzle Exp $"); +__FBSDID("$FreeBSD: src/usr.bin/tar/bsdtar.c,v 1.79 2008/01/22 07:23:44 kientzle Exp $"); #ifdef HAVE_SYS_PARAM_H #include @@ -391,19 +391,9 @@ main(int argc, char **argv) case 'L': /* BSD convention */ bsdtar->symlink_mode = 'L'; break; - case 'l': /* SUSv2 and GNU conflict badly here */ - if (getenv("POSIXLY_CORRECT") != NULL) { - /* User has asked for POSIX/SUS behavior. */ - bsdtar->option_warn_links = 1; - } else { - fprintf(stderr, -"Error: -l has different behaviors in different tar programs.\n"); - fprintf(stderr, -" For the GNU behavior, use --one-file-system instead.\n"); - fprintf(stderr, -" For the POSIX behavior, use --check-links instead.\n"); - usage(bsdtar); - } + case 'l': /* SUSv2 and GNU tar beginning with 1.16 */ + /* GNU tar 1.13 used -l for --one-file-system */ + bsdtar->option_warn_links = 1; break; case 'm': /* SUSv2 */ bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_TIME; diff --git a/contrib/libarchive-2/tar/bsdtar.h b/contrib/libarchive-2/tar/bsdtar.h index 50f61681a8..fb10678702 100644 --- a/contrib/libarchive-2/tar/bsdtar.h +++ b/contrib/libarchive-2/tar/bsdtar.h @@ -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/usr.bin/tar/bsdtar.h,v 1.28 2007/05/29 05:39:10 kientzle Exp $ + * $FreeBSD: src/usr.bin/tar/bsdtar.h,v 1.29 2008/01/02 00:21:27 kientzle Exp $ */ #include "bsdtar_platform.h" diff --git a/contrib/libarchive-2/tar/bsdtar_platform.h b/contrib/libarchive-2/tar/bsdtar_platform.h index 66852ca752..ccb9d3c025 100644 --- a/contrib/libarchive-2/tar/bsdtar_platform.h +++ b/contrib/libarchive-2/tar/bsdtar_platform.h @@ -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/usr.bin/tar/bsdtar_platform.h,v 1.24 2007/04/12 04:45:32 kientzle Exp $ + * $FreeBSD: src/usr.bin/tar/bsdtar_platform.h,v 1.25 2008/01/02 00:23:00 kientzle Exp $ */ /* diff --git a/contrib/libarchive-2/tar/read.c b/contrib/libarchive-2/tar/read.c index a942e85b18..edda317b6a 100644 --- a/contrib/libarchive-2/tar/read.c +++ b/contrib/libarchive-2/tar/read.c @@ -24,7 +24,7 @@ */ #include "bsdtar_platform.h" -__FBSDID("$FreeBSD: src/usr.bin/tar/read.c,v 1.34 2007/07/20 01:24:49 kientzle Exp $"); +__FBSDID("$FreeBSD: src/usr.bin/tar/read.c,v 1.35 2008/01/02 00:21:27 kientzle Exp $"); #ifdef HAVE_SYS_TYPES_H #include diff --git a/contrib/libarchive-2/tar/util.c b/contrib/libarchive-2/tar/util.c index c43e461eb2..68ff8d8f5e 100644 --- a/contrib/libarchive-2/tar/util.c +++ b/contrib/libarchive-2/tar/util.c @@ -24,7 +24,7 @@ */ #include "bsdtar_platform.h" -__FBSDID("$FreeBSD: src/usr.bin/tar/util.c,v 1.17 2007/04/18 04:36:11 kientzle Exp $"); +__FBSDID("$FreeBSD: src/usr.bin/tar/util.c,v 1.18 2008/01/02 00:21:27 kientzle Exp $"); #ifdef HAVE_SYS_STAT_H #include diff --git a/contrib/libarchive-2/tar/write.c b/contrib/libarchive-2/tar/write.c index f25b6857d4..3b8cc51585 100644 --- a/contrib/libarchive-2/tar/write.c +++ b/contrib/libarchive-2/tar/write.c @@ -24,7 +24,7 @@ */ #include "bsdtar_platform.h" -__FBSDID("$FreeBSD: src/usr.bin/tar/write.c,v 1.63 2007/05/29 05:39:10 kientzle Exp $"); +__FBSDID("$FreeBSD: src/usr.bin/tar/write.c,v 1.64 2008/02/19 05:27:17 kientzle Exp $"); #ifdef HAVE_SYS_TYPES_H #include @@ -1543,7 +1543,7 @@ test_for_append(struct bsdtar *bsdtar) if (stat(bsdtar->filename, &s) != 0) return; - if (!S_ISREG(s.st_mode)) + if (!S_ISREG(s.st_mode) && !S_ISBLK(s.st_mode)) bsdtar_errc(bsdtar, 1, 0, "Cannot append to %s: not a regular file.", bsdtar->filename); diff --git a/contrib/libarchive-2/version b/contrib/libarchive-2/version index 752a79ef36..b29b92020a 100644 --- a/contrib/libarchive-2/version +++ b/contrib/libarchive-2/version @@ -1 +1 @@ -2.4.8 \ No newline at end of file +2.4.17 \ No newline at end of file