Import libarchive-3.0.2.
authorPeter Avalos <pavalos@dragonflybsd.org>
Mon, 9 Jan 2012 02:07:11 +0000 (18:07 -0800)
committerPeter Avalos <pavalos@dragonflybsd.org>
Thu, 12 Jan 2012 23:36:28 +0000 (15:36 -0800)
*libarchive 3.0.2 released
*Various fixes merged from FreeBSD
*Symlink support in Zip reader and writer
*Robustness fixes to 7Zip reader

*libarchive 3.0.1b released
*7Zip reader
*Small fixes to ISO and Zip to improve robustness with corrupted input
*Improve streaming Zip reader's support for uncompressed entries
*New seeking Zip reader supports SFX Zip archives

*libarchive 3.0.0a released
*Update shared-library version calculations for libarchive 3.x
*Fix tar -s; follow GNU tar for controlling hardlink/symlink substitutions
*Fix reading ISO images built by NetBSD's mkisofs
*Old archive_read_support_compression_XXX functions are deprecated and
 will disappear in libarchive 4.0.
*RAR reader
*Add tar:compat-2x option to emulate broken libarchive 2.x
 handling of pax UTF-8 headers
*Refactor read_open() into a collection of single-item setters;
 support the old interfaces as wrappers
*Split disk writer into separate POSIX and Windows implementations
*More work to return errors instead of calling abort()
*Add charset option to many writers to control MBCS filenames
*Overhauled support for per-format extension options
*Track character set used for mbcs strings, support
 translating to/from user-specified locale
*Recognize mtree files without requiring a signature
*Use iconv to convert to/from Unicode instead of making bad
 assumptions about the C90 character set translation functions
*CAB reader
*LHA/LZH reader
*Many improvements to ISO reader compatibility
*Use larger buffers when copy files into an archive
*archive_read_disk now supports traversals
*XAR writer
*Fix ^T handling; don't exit on interrupted reads and writes
*Improved detection of platform-specific crypto support
*lzip read and write filters
*tar --gid --gname --uid --uname
*Use Red-black tree for ISO reader/writer to improve performance
*Minimal writer for legacy GNU tar format
*Relax handling of state failures; misuse by clients now generally
 results in a sticky ARCHIVE_FATAL rather than a visit to abort()
*ISO writer
*Split many man pages into smaller chunks.
*Cheat on block sizes when reading archives from disk.
*Use int64_t instead of off_t, dev_t, ino_t, uid_t, and gid_t
*Document new ACL functions.
*Support multiple write filters
*Remove some legacy libarchive 1.x APIs
*Read afio headers
*Archive sparse files compatibly with GNU tar
*Support cpio -V

142 files changed:
contrib/libarchive/COPYING
contrib/libarchive/NEWS
contrib/libarchive/README
contrib/libarchive/README.DELETED
contrib/libarchive/build/version
contrib/libarchive/cpio/bsdcpio.1
contrib/libarchive/cpio/cmdline.c
contrib/libarchive/cpio/cpio.c
contrib/libarchive/cpio/cpio.h
contrib/libarchive/libarchive/archive.h
contrib/libarchive/libarchive/archive_acl.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_acl_private.h [new file with mode: 0644]
contrib/libarchive/libarchive/archive_check_magic.c
contrib/libarchive/libarchive/archive_crypto.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_crypto_private.h [new file with mode: 0644]
contrib/libarchive/libarchive/archive_entry.3
contrib/libarchive/libarchive/archive_entry.c
contrib/libarchive/libarchive/archive_entry.h
contrib/libarchive/libarchive/archive_entry_acl.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_entry_copy_bhfi.c [deleted file]
contrib/libarchive/libarchive/archive_entry_copy_stat.c
contrib/libarchive/libarchive/archive_entry_link_resolver.c
contrib/libarchive/libarchive/archive_entry_linkify.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_entry_locale.h [new file with mode: 0644]
contrib/libarchive/libarchive/archive_entry_paths.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_entry_perms.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_entry_private.h
contrib/libarchive/libarchive/archive_entry_sparse.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_entry_stat.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_entry_stat.c
contrib/libarchive/libarchive/archive_entry_time.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_hash.h [deleted file]
contrib/libarchive/libarchive/archive_options.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_options_private.h [copied from contrib/libarchive/libarchive/archive_read_support_compression_none.c with 67% similarity]
contrib/libarchive/libarchive/archive_ppmd7.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_ppmd7_private.h [new file with mode: 0644]
contrib/libarchive/libarchive/archive_ppmd_private.h [new file with mode: 0644]
contrib/libarchive/libarchive/archive_private.h
contrib/libarchive/libarchive/archive_rb.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_rb.h [new file with mode: 0644]
contrib/libarchive/libarchive/archive_read.3
contrib/libarchive/libarchive/archive_read.c
contrib/libarchive/libarchive/archive_read_data_into_fd.c
contrib/libarchive/libarchive/archive_read_disk.3
contrib/libarchive/libarchive/archive_read_disk.c [deleted file]
contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c
contrib/libarchive/libarchive/archive_read_disk_posix.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_read_disk_private.h
contrib/libarchive/libarchive/archive_read_disk_set_standard_lookup.c
contrib/libarchive/libarchive/archive_read_extract.c
contrib/libarchive/libarchive/archive_read_open_fd.c
contrib/libarchive/libarchive/archive_read_open_file.c
contrib/libarchive/libarchive/archive_read_open_filename.c
contrib/libarchive/libarchive/archive_read_open_memory.c
contrib/libarchive/libarchive/archive_read_private.h
contrib/libarchive/libarchive/archive_read_set_options.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_read_set_options.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_read_support_filter_all.c [moved from contrib/libarchive/libarchive/archive_read_support_compression_all.c with 75% similarity]
contrib/libarchive/libarchive/archive_read_support_filter_bzip2.c [moved from contrib/libarchive/libarchive/archive_read_support_compression_bzip2.c with 92% similarity]
contrib/libarchive/libarchive/archive_read_support_filter_compress.c [moved from contrib/libarchive/libarchive/archive_read_support_compression_compress.c with 93% similarity]
contrib/libarchive/libarchive/archive_read_support_filter_gzip.c [moved from contrib/libarchive/libarchive/archive_read_support_compression_gzip.c with 94% similarity]
contrib/libarchive/libarchive/archive_read_support_filter_none.c [copied from contrib/libarchive/libarchive/archive_read_support_compression_none.c with 81% similarity]
contrib/libarchive/libarchive/archive_read_support_filter_program.c [moved from contrib/libarchive/libarchive/archive_read_support_compression_program.c with 93% similarity]
contrib/libarchive/libarchive/archive_read_support_filter_rpm.c [moved from contrib/libarchive/libarchive/archive_read_support_compression_rpm.c with 92% similarity]
contrib/libarchive/libarchive/archive_read_support_filter_uu.c [moved from contrib/libarchive/libarchive/archive_read_support_compression_uu.c with 87% similarity]
contrib/libarchive/libarchive/archive_read_support_filter_xz.c [moved from contrib/libarchive/libarchive/archive_read_support_compression_xz.c with 67% similarity]
contrib/libarchive/libarchive/archive_read_support_format_7zip.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_read_support_format_all.c
contrib/libarchive/libarchive/archive_read_support_format_ar.c
contrib/libarchive/libarchive/archive_read_support_format_by_code.c [copied from contrib/libarchive/libarchive/archive_read_support_compression_none.c with 52% similarity]
contrib/libarchive/libarchive/archive_read_support_format_cab.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_read_support_format_cpio.c
contrib/libarchive/libarchive/archive_read_support_format_empty.c
contrib/libarchive/libarchive/archive_read_support_format_iso9660.c
contrib/libarchive/libarchive/archive_read_support_format_lha.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_read_support_format_mtree.c
contrib/libarchive/libarchive/archive_read_support_format_rar.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_read_support_format_raw.c
contrib/libarchive/libarchive/archive_read_support_format_tar.c
contrib/libarchive/libarchive/archive_read_support_format_xar.c
contrib/libarchive/libarchive/archive_read_support_format_zip.c
contrib/libarchive/libarchive/archive_string.c
contrib/libarchive/libarchive/archive_string.h
contrib/libarchive/libarchive/archive_string_composition.h [new file with mode: 0644]
contrib/libarchive/libarchive/archive_string_sprintf.c
contrib/libarchive/libarchive/archive_util.3
contrib/libarchive/libarchive/archive_util.c
contrib/libarchive/libarchive/archive_virtual.c
contrib/libarchive/libarchive/archive_write.3
contrib/libarchive/libarchive/archive_write.c
contrib/libarchive/libarchive/archive_write_add_filter_bzip2.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_add_filter_compress.c [moved from contrib/libarchive/libarchive/archive_write_set_compression_compress.c with 68% similarity]
contrib/libarchive/libarchive/archive_write_add_filter_gzip.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_add_filter_none.c [moved from contrib/libarchive/libarchive/archive_read_support_compression_none.c with 81% similarity]
contrib/libarchive/libarchive/archive_write_add_filter_program.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_add_filter_xz.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_disk.3
contrib/libarchive/libarchive/archive_write_disk_posix.c [moved from contrib/libarchive/libarchive/archive_write_disk.c with 79% similarity]
contrib/libarchive/libarchive/archive_write_disk_set_standard_lookup.c
contrib/libarchive/libarchive/archive_write_open_filename.c
contrib/libarchive/libarchive/archive_write_open_memory.c
contrib/libarchive/libarchive/archive_write_private.h
contrib/libarchive/libarchive/archive_write_set_compression_bzip2.c [deleted file]
contrib/libarchive/libarchive/archive_write_set_compression_gzip.c [deleted file]
contrib/libarchive/libarchive/archive_write_set_compression_none.c [deleted file]
contrib/libarchive/libarchive/archive_write_set_compression_program.c [deleted file]
contrib/libarchive/libarchive/archive_write_set_compression_xz.c [deleted file]
contrib/libarchive/libarchive/archive_write_set_format.c
contrib/libarchive/libarchive/archive_write_set_format_7zip.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_set_format_ar.c
contrib/libarchive/libarchive/archive_write_set_format_by_name.c
contrib/libarchive/libarchive/archive_write_set_format_cpio.c
contrib/libarchive/libarchive/archive_write_set_format_cpio_newc.c
contrib/libarchive/libarchive/archive_write_set_format_gnutar.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_set_format_iso9660.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_set_format_mtree.c
contrib/libarchive/libarchive/archive_write_set_format_pax.c
contrib/libarchive/libarchive/archive_write_set_format_shar.c
contrib/libarchive/libarchive/archive_write_set_format_ustar.c
contrib/libarchive/libarchive/archive_write_set_format_xar.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_set_format_zip.c
contrib/libarchive/libarchive/archive_write_set_options.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_set_options.c [new file with mode: 0644]
contrib/libarchive/libarchive/cpio.5
contrib/libarchive/libarchive/libarchive-formats.5
contrib/libarchive/libarchive/libarchive.3
contrib/libarchive/libarchive/libarchive_internals.3
contrib/libarchive/libarchive/tar.5
contrib/libarchive/libarchive_fe/line_reader.c
contrib/libarchive/libarchive_fe/matching.c
contrib/libarchive/libarchive_fe/pathmatch.c
contrib/libarchive/tar/bsdtar.1
contrib/libarchive/tar/bsdtar.c
contrib/libarchive/tar/bsdtar.h
contrib/libarchive/tar/bsdtar_platform.h
contrib/libarchive/tar/cmdline.c
contrib/libarchive/tar/getdate.c
contrib/libarchive/tar/read.c
contrib/libarchive/tar/subst.c
contrib/libarchive/tar/tree.c
contrib/libarchive/tar/util.c
contrib/libarchive/tar/write.c

index 9dbf49d..b258806 100644 (file)
@@ -16,8 +16,8 @@ the actual statements in the files are controlling.
   a 3-clause UC Regents copyright; please read the individual source
   files for details:
    libarchive/archive_entry.c
-   libarchive/archive_read_support_compression_compress.c
-   libarchive/archive_write_set_compression_compress.c
+   libarchive/archive_read_support_filter_compress.c
+   libarchive/archive_write_set_filter_compress.c
    libarchive/mtree.5
    tar/matching.c
 
index 4a25fe3..72aed41 100644 (file)
@@ -1,27 +1,68 @@
-Feb 05, 2011: Fix issue 134: Improve handling of open failures
-Dec 06, 2010: Fix issue 119: Relax ISO verification
-Dec 06, 2010: Fix issue 121: mtree parsing
-Dec 05, 2010: Fix extraction of GNU tar 'D' directory entries
-Dec 05, 2010: Be less demanding in LZMA/XZ compression tests
-Jun 30, 2010: libarchive 2.8.4 released
-Jun 30, 2010: Improved reliability of hash function detection
-Jun 30, 2010: Fix issues on ancient FreeBSD, QNX, ancient NetBSD and Minix
-
-Mar 14, 2010: libarchive 2.8.3 released
-Mar 14, 2010: Symlink dereference fix for Linux broke the build there; corrected.
-
-Mar 14, 2010: libarchive 2.8.2 released
-Mar 12, 2010: Fix NULL deference for short self-extracting zip archives.
+Dec 24, 2011: libarchive 3.0.2 released
+Dec 23, 2011: Various fixes merged from FreeBSD
+Dec 23, 2011: Symlink support in Zip reader and writer
+Dec 23, 2011: Robustness fixes to 7Zip reader
+
+Nov 27, 2011: libarchive 3.0.1b released
+
+Nov 26, 2011: 7Zip reader
+Nov 26, 2011: Small fixes to ISO and Zip to improve robustness with corrupted input
+Nov 24, 2011: Improve streaming Zip reader's support for uncompressed entries
+Nov 20, 2011: New seeking Zip reader supports SFX Zip archives
+Nov 20, 2011: Build fixes on Windows
+
+Nov 13, 2011: libarchive 3.0.0a released
+
+Nov 06, 2011: Update shared-library version calculations for libarchive 3.x
+Sep 04, 2011: Fix tar -s; follow GNU tar for controlling hardlink/symlink substitutions
+Aug 18, 2011: Fix reading ISO images built by NetBSD's mkisofs
+Aug 15, 2011: Old archive_read_support_compression_XXX functions are deprecated and
+   will disappear in libarchive 4.0.
+Jun 26, 2011: RAR reader
+Jun 16, 2011: Add tar:compat-2x option to emulate broken libarchive 2.x
+   handling of pax UTF-8 headers
+Apr 25, 2011: Refactor read_open() into a collection of single-item setters;
+   support the old interfaces as wrappers
+Apr 12, 2011: Split disk writer into separate POSIX and Windows implementations
+Apr 10, 2011: Improvements to character translations on Windows.
+Mar 30, 2011: More work to return errors instead of calling abort()
+Mar 23, 2011: Add charset option to many writers to control MBCS filenames
+Mar 17, 2011: Overhauled support for per-format extension options
+Mar 17, 2011: Track character set used for mbcs strings, support
+   translating to/from user-specified locale
+Mar 09, 2011: Recognize mtree files without requiring a signature
+Mar 06, 2011: Use iconv to convert to/from Unicode instead of making bad
+   assumptions about the C90 character set translation functions
+Feb 17, 2011: Fixes for AIX, TRU64, and other platforms
+Dec 22, 2010: CAB reader
+Dec 20, 2010: LHA/LZH reader
+Jul 03, 2010: minitar example demonstrates archive_read_disk directory traversal
+Jun 29, 2010: Many improvements to ISO reader compatibility
+Jun 26, 2010: Use larger buffers when copy files into an archive
+Jun 18, 2010: Reimplement Mac OS extensions in libarchive
+Jun 09, 2010: archive_read_disk now supports traversals
+May 28, 2010: XAR writer
+May 16, 2010: Fix ^T handling; don't exit on interrupted reads and writes
+May 09, 2010: Improved detection of platform-specific crypto support
+May 04, 2010: lzip read and write filters
+May 01, 2010: New options: tar --gid --gname --uid --uname
+Apr 28, 2010: Use Red-black tree for ISO reader/writer to improve performance
+Apr 17, 2010: Minimal writer for legacy GNU tar format
 Mar 12, 2010: Don't dereference symlinks on Linux when reading ACLs.
-Mar 07, 2010: Better detection of SHA2 support for old OpenSSL versions.
-Mar 07, 2010: Fix parsing of input files for bsdtar -T.
-Mar 07, 2010: Do not leak setup_xattr into the global namespace.
-
-Mar 06, 2010: libarchive 2.8.1 released
 Mar 06, 2010: Fix build when an older libarchive is already installed
-Mar 03, 2010: Use O_BINARY opening files in bsdtar
-Mar 02, 2010: Include missing archive_crc32.h
-Mar 01, 2010: Correctly include iconv.h required by libxml2.
+Feb 28, 2010: Relax handling of state failures; misuse by clients now generally
+      results in a sticky ARCHIVE_FATAL rather than a visit to abort()
+Feb 25, 2010: ISO writer
+Feb 21, 2010: Split many man pages into smaller chunks.
+Feb 21, 2010: Performance: Cheat on block sizes when reading archives from disk.
+Feb 21, 2010: Use int64_t instead of off_t, dev_t, ino_t, uid_t, and gid_t
+Feb 20, 2010: Document new ACL functions.
+Feb 19, 2010: Support multiple write filters
+Feb 07, 2010: Remove some legacy libarchive 1.x APIs
+Feb 04, 2010: Read afio headers
+Feb 02, 2010: Archive sparse files compatibly with GNU tar
+Feb 01, 2010: Integrate Apple extensions for Mac OS extended attributes into bsdtar
+Jan 31, 2010: Support cpio -V
 
 Feb 04, 2010: libarchive 2.8.0 released
 Jan 17, 2010: Fix error handling for 'echo nonexistent | cpio -o'
index 03e47e8..6923838 100644 (file)
@@ -13,8 +13,6 @@ This distribution bundle includes the following components:
           essentially the same functionality
    * examples: Some small example programs that you may find useful.
    * examples/minitar: a compact sample demonstrating use of libarchive.
-          I use this for testing link pollution; it should produce a very
-          small executable file on most systems.
    * contrib:  Various items sent to me by third parties;
           please contact the authors with any questions.
 
@@ -51,16 +49,11 @@ The manual pages above are provided in the 'doc' directory in
 a number of different formats.
 
 You should also read the copious comments in "archive.h" and the
-source code for the sample programs for more details.  Please let me
+source code for the sample programs for more details.  Please let us
 know about any errors or omissions you find.
 
-Currently, the library automatically detects and reads the following:
-  * gzip compression
-  * bzip2 compression
-  * compress/LZW compression
-  * lzma and xz compression
-  * GNU tar format (including GNU long filenames, long link names, and
-    sparse files)
+Currently, the library automatically detects and reads the following fomats:
+  * GNU tar format (including GNU long filenames, long link names, and sparse files)
   * Solaris 9 extended tar format (including ACLs)
   * Old V7 tar archives
   * POSIX ustar
@@ -73,22 +66,40 @@ Currently, the library automatically detects and reads the following:
   * ZIP archives (with uncompressed or "deflate" compressed entries)
   * GNU and BSD 'ar' archives
   * 'mtree' format
-
-The library can write:
+  * Microsoft CAB format
+  * LHA and LZH archives
+  * RAR archives
+  * XAR archives
+
+The library also detects and handles any of the following before evaluating the archive:
+  * uuencoded files
+  * files with RPM wrapper
   * gzip compression
   * bzip2 compression
   * compress/LZW compression
-  * lzma and xz compression
+  * lzma, lzip, and xz compression
+
+The library can create archives in any of the following formats:
   * POSIX ustar
   * POSIX pax interchange format
   * "restricted" pax format, which will create ustar archives except for
     entries that require pax extensions (for long filenames, ACLs, etc).
+  * Old GNU tar format
   * POSIX octet-oriented cpio
   * SVR4 "newc" cpio
   * shar archives
   * ZIP archives (with uncompressed or "deflate" compressed entries)
   * GNU and BSD 'ar' archives
   * 'mtree' format
+  * ISO9660 format
+  * XAR archives
+
+When creating archives, the result can be filtered with any of the following:
+  * uuencode
+  * gzip compression
+  * bzip2 compression
+  * compress/LZW compression
+  * lzma, lzip, and xz compression
 
 Notes about the library architecture:
 
index bd8eb86..d5076a2 100644 (file)
@@ -22,8 +22,11 @@ doc/
 examples/
 libarchive/CMakeLists.txt
 libarchive/archive_crc32.h
+libarchive/archive_entry_copy_bhfi.c
+libarchive/archive_read_disk_windows.c
 libarchive/archive_windows.c
 libarchive/archive_windows.h
+libarchive/archive_write_disk_windows.c
 libarchive/config_freebsd.h
 libarchive/filter_fork_windows.c
 libarchive/test/
index 79b6997..f01a704 100644 (file)
@@ -25,7 +25,7 @@
 .\" $FreeBSD$
 .\"
 .Dd December 21, 2007
-.Dt BSDCPIO 1
+.Dt CPIO 1
 .Os
 .Sh NAME
 .Nm cpio
@@ -80,7 +80,7 @@ specified directory.
 Unless specifically stated otherwise, options are applicable in
 all operating modes.
 .Bl -tag -width indent
-.It Fl 0
+.It Fl 0 , Fl Fl null
 Read filenames separated by NUL characters instead of newlines.
 This is necessary if any of the filenames being read might contain newlines.
 .It Fl A
@@ -102,8 +102,8 @@ bytes.
 (o mode only)
 Use the old POSIX portable character format.
 Equivalent to
-.Fl -format Ar odc .
-.It Fl d
+.Fl Fl format Ar odc .
+.It Fl d , Fl Fl make-directories
 (i and p modes)
 Create directories as necessary.
 .It Fl E Ar file
@@ -111,14 +111,14 @@ Create directories as necessary.
 Read list of file name patterns from
 .Ar file
 to list and extract.
-.It Fl F Ar file
+.It Fl F Ar file , Fl Fl file Ar file
 Read archive from or write archive to
 .Ar file .
 .It Fl f Ar pattern
 (i mode only)
 Ignore files that match
 .Ar pattern .
-.It Fl -format Ar format
+.It Fl H Ar format , Fl Fl format Ar format
 (o mode only)
 Produce the output archive in the specified format.
 Supported formats include:
@@ -140,29 +140,26 @@ The POSIX.1 tar format.
 The default format is
 .Ar odc .
 See
-.Xr libarchive_formats 5
+.Xr libarchive-formats 5
 for more complete information about the
 formats currently supported by the underlying
 .Xr libarchive 3
 library.
-.It Fl H Ar format
-Synonym for
-.Fl -format .
-.It Fl h , Fl -help
+.It Fl h , Fl Fl help
 Print usage information.
 .It Fl I Ar file
 Read archive from
 .Ar file .
-.It Fl i
+.It Fl i , Fl Fl extract
 Input mode.
 See above for description.
-.It Fl -insecure
+.It Fl Fl insecure
 (i and p mode only)
 Disable security checks during extraction or copying.
 This allows extraction via symbolic links and path names containing
 .Sq ..
 in the name.
-.It Fl J
+.It Fl J , Fl Fl xz
 (o mode only)
 Compress the file with xz-compatible compression before writing it.
 In input mode, this option is ignored; xz compression is recognized
@@ -175,20 +172,20 @@ Synonym for
 All symbolic links will be followed.
 Normally, symbolic links are archived and copied as symbolic links.
 With this option, the target of the link will be archived or copied instead.
-.It Fl l
+.It Fl l , Fl Fl link
 (p mode only)
 Create links from the target directory to the original files,
 instead of copying.
-.It Fl lzma
+.It Fl Fl lzma
 (o mode only)
 Compress the file with lzma-compatible compression before writing it.
 In input mode, this option is ignored; lzma compression is recognized
 automatically on input.
-.It Fl m
+.It Fl m , Fl Fl preserve-modification-time
 (i and p modes)
 Set file modification time on created files to match
 those in the source.
-.It Fl n
+.It Fl n , Fl Fl numeric-uid-gid
 (i mode, only with
 .Fl t )
 Display numeric uid and gid.
@@ -197,26 +194,26 @@ By default,
 displays the user and group names when they are provided in the
 archive, or looks up the user and group names in the system
 password database.
-.It Fl no-preserve-owner
+.It Fl Fl no-preserve-owner
 (i mode only)
 Do not attempt to restore file ownership.
 This is the default when run by non-root users.
 .It Fl O Ar file
 Write archive to
 .Ar file .
-.It Fl o
+.It Fl o , Fl Fl create
 Output mode.
 See above for description.
-.It Fl p
+.It Fl p , Fl Fl pass-through
 Pass-through mode.
 See above for description.
-.It Fl preserve-owner
+.It Fl Fl preserve-owner
 (i mode only)
 Restore file ownership.
 This is the default when run by the root user.
-.It Fl -quiet
+.It Fl Fl quiet
 Suppress unnecessary messages.
-.It Fl R Oo user Oc Ns Oo : Oc Ns Oo group Oc
+.It Fl R Oo user Oc Ns Oo : Oc Ns Oo group Oc , Fl Fl owner Oo user Oc Ns Oo : Oc Ns Oo group Oc
 Set the owner and/or group on files in the output.
 If group is specified with no user
 (for example,
@@ -244,20 +241,24 @@ containing the name of the file and a line is read from
 If the line read is blank, the file is skipped.
 If the line contains a single period, the file is processed normally.
 Otherwise, the line is taken to be the new name of the file.
-.It Fl t
+.It Fl t , Fl Fl list
 (i mode only)
 List the contents of the archive to stdout;
 do not restore the contents to disk.
-.It Fl u
+.It Fl u , Fl Fl unconditional
 (i and p modes)
 Unconditionally overwrite existing files.
 Ordinarily, an older file will not overwrite a newer file on disk.
-.It Fl v
+.It Fl V , Fl Fl dot
+Print a dot to stderr for each file as it is processed.
+Superseded by
+.Fl v .
+.It Fl v , Fl Fl verbose
 Print the name of each file to stderr as it is processed.
 With
 .Fl t ,
 provide a detailed listing of each file.
-.It Fl -version
+.It Fl Fl version
 Print the program version information and exit.
 .It Fl y
 (o mode only)
@@ -275,6 +276,8 @@ Compress the archive with gzip-compatible compression before writing it.
 In input mode, this option is ignored;
 gzip compression is recognized automatically on input.
 .El
+.Sh EXIT STATUS
+.Ex -std
 .Sh ENVIRONMENT
 The following environment variables affect the execution of
 .Nm :
@@ -290,12 +293,10 @@ See
 .Xr environ 7
 for more information.
 .El
-.Sh EXIT STATUS
-.Ex -std
 .Sh EXAMPLES
 The
 .Nm
-command is traditionally used to copy file heirarchies in conjunction
+command is traditionally used to copy file hierarchies in conjunction
 with the
 .Xr find 1
 command.
index 2223798..390aebc 100644 (file)
@@ -51,7 +51,7 @@ __FBSDID("$FreeBSD: src/usr.bin/cpio/cmdline.c,v 1.5 2008/12/06 07:30:40 kientzl
 /*
  * Short options for cpio.  Please keep this sorted.
  */
-static const char *short_options = "0AaBC:cdE:F:f:H:hI:iJjLlmnO:opR:rtuvW:yZz";
+static const char *short_options = "0AaBC:cdE:F:f:H:hI:iJjLlmnO:opR:rtuVvW:yZz";
 
 /*
  * Long options for cpio.  Please keep this sorted.
@@ -62,6 +62,7 @@ static const struct option {
        int equivalent; /* Equivalent short option. */
 } cpio_longopts[] = {
        { "create",                     0, 'o' },
+       { "dot",                        0, 'V' },
        { "extract",                    0, 'i' },
        { "file",                       1, 'F' },
        { "format",                     1, 'H' },
@@ -109,7 +110,7 @@ cpio_getopt(struct cpio *cpio)
        int opt = '?';
        int required = 0;
 
-       cpio->optarg = NULL;
+       cpio->argument = NULL;
 
        /* First time through, initialize everything. */
        if (state == state_start) {
@@ -188,7 +189,7 @@ cpio_getopt(struct cpio *cpio)
                                long_prefix = "-W "; /* For clearer errors. */
                        } else {
                                state = state_next_word;
-                               cpio->optarg = opt_word;
+                               cpio->argument = opt_word;
                        }
                }
        }
@@ -202,7 +203,7 @@ cpio_getopt(struct cpio *cpio)
                p = strchr(opt_word, '=');
                if (p != NULL) {
                        optlength = (size_t)(p - opt_word);
-                       cpio->optarg = (char *)(uintptr_t)(p + 1);
+                       cpio->argument = (char *)(uintptr_t)(p + 1);
                } else {
                        optlength = strlen(opt_word);
                }
@@ -241,9 +242,9 @@ cpio_getopt(struct cpio *cpio)
                /* We've found a unique match; does it need an argument? */
                if (match->required) {
                        /* Argument required: get next word if necessary. */
-                       if (cpio->optarg == NULL) {
-                               cpio->optarg = *cpio->argv;
-                               if (cpio->optarg == NULL) {
+                       if (cpio->argument == NULL) {
+                               cpio->argument = *cpio->argv;
+                               if (cpio->argument == NULL) {
                                        lafe_warnc(0,
                                            "Option %s%s requires an argument",
                                            long_prefix, match->name);
@@ -254,7 +255,7 @@ cpio_getopt(struct cpio *cpio)
                        }
                } else {
                        /* Argument forbidden: fail if there is one. */
-                       if (cpio->optarg != NULL) {
+                       if (cpio->argument != NULL) {
                                lafe_warnc(0,
                                    "Option %s%s does not allow an argument",
                                    long_prefix, match->name);
@@ -285,6 +286,8 @@ cpio_getopt(struct cpio *cpio)
  * A period can be used instead of the colon.
  *
  * Sets uid/gid return as appropriate, -1 indicates uid/gid not specified.
+ * TODO: If the spec uses uname/gname, then return those to the caller
+ * as well.  If the spec provides uid/gid, just return names as NULL.
  *
  * Returns NULL if no error, otherwise returns error string for display.
  *
@@ -338,7 +341,7 @@ owner_parse(const char *spec, int *uid, int *gid)
                } else {
                        char *end;
                        errno = 0;
-                       *uid = strtoul(user, &end, 10);
+                       *uid = (int)strtoul(user, &end, 10);
                        if (errno || *end != '\0') {
                                snprintf(errbuff, sizeof(errbuff),
                                    "Couldn't lookup user ``%s''", user);
@@ -356,7 +359,7 @@ owner_parse(const char *spec, int *uid, int *gid)
                } else {
                        char *end;
                        errno = 0;
-                       *gid = strtoul(g, &end, 10);
+                       *gid = (int)strtoul(g, &end, 10);
                        if (errno || *end != '\0') {
                                snprintf(errbuff, sizeof(errbuff),
                                    "Couldn't lookup group ``%s''", g);
index 7d5031b..ff5a1c6 100644 (file)
@@ -50,9 +50,15 @@ __FBSDID("$FreeBSD: src/usr.bin/cpio/cpio.c,v 1.15 2008/12/06 07:30:40 kientzle
 #ifdef HAVE_GRP_H
 #include <grp.h>
 #endif
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
 #ifdef HAVE_PWD_H
 #include <pwd.h>
 #endif
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
 #ifdef HAVE_STDARG_H
 #include <stdarg.h>
 #endif
@@ -69,9 +75,6 @@ __FBSDID("$FreeBSD: src/usr.bin/cpio/cpio.c,v 1.15 2008/12/06 07:30:40 kientzle
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
 #ifdef HAVE_TIME_H
 #include <time.h>
 #endif
@@ -136,6 +139,16 @@ main(int argc, char *argv[])
        cpio->buff = buff;
        cpio->buff_size = sizeof(buff);
 
+#if defined(HAVE_SIGACTION) && defined(SIGPIPE)
+       { /* Ignore SIGPIPE signals. */
+               struct sigaction sa;
+               sigemptyset(&sa.sa_mask);
+               sa.sa_flags = 0;
+               sa.sa_handler = SIG_IGN;
+               sigaction(SIGPIPE, &sa, NULL);
+       }
+#endif
+
        /* Need lafe_progname before calling lafe_warnc. */
        if (*argv == NULL)
                lafe_progname = "bsdcpio";
@@ -150,6 +163,10 @@ main(int argc, char *argv[])
                else
                        lafe_progname = *argv;
        }
+#if HAVE_SETLOCALE
+       if (setlocale(LC_ALL, "") == NULL)
+               lafe_warnc(0, "Failed to set default locale");
+#endif
 
        cpio->uid_override = -1;
        cpio->gid_override = -1;
@@ -187,9 +204,9 @@ main(int argc, char *argv[])
                        cpio->bytes_per_block = 5120;
                        break;
                case 'C': /* NetBSD/OpenBSD */
-                       cpio->bytes_per_block = atoi(cpio->optarg);
+                       cpio->bytes_per_block = atoi(cpio->argument);
                        if (cpio->bytes_per_block <= 0)
-                               lafe_errc(1, 0, "Invalid blocksize %s", cpio->optarg);
+                               lafe_errc(1, 0, "Invalid blocksize %s", cpio->argument);
                        break;
                case 'c': /* POSIX 1997 */
                        cpio->format = "odc";
@@ -199,22 +216,22 @@ main(int argc, char *argv[])
                        break;
                case 'E': /* NetBSD/OpenBSD */
                        lafe_include_from_file(&cpio->matching,
-                           cpio->optarg, cpio->option_null);
+                           cpio->argument, cpio->option_null);
                        break;
                case 'F': /* NetBSD/OpenBSD/GNU cpio */
-                       cpio->filename = cpio->optarg;
+                       cpio->filename = cpio->argument;
                        break;
                case 'f': /* POSIX 1997 */
-                       lafe_exclude(&cpio->matching, cpio->optarg);
+                       lafe_exclude(&cpio->matching, cpio->argument);
                        break;
                case 'H': /* GNU cpio (also --format) */
-                       cpio->format = cpio->optarg;
+                       cpio->format = cpio->argument;
                        break;
                case 'h':
                        long_help();
                        break;
                case 'I': /* NetBSD/OpenBSD */
-                       cpio->filename = cpio->optarg;
+                       cpio->filename = cpio->argument;
                        break;
                case 'i': /* POSIX 1997 */
                        if (cpio->mode != '\0')
@@ -251,7 +268,7 @@ main(int argc, char *argv[])
                        cpio->extract_flags &= ~ARCHIVE_EXTRACT_OWNER;
                        break;
                case 'O': /* GNU cpio */
-                       cpio->filename = cpio->optarg;
+                       cpio->filename = cpio->argument;
                        break;
                case 'o': /* POSIX 1997 */
                        if (cpio->mode != '\0')
@@ -273,15 +290,21 @@ main(int argc, char *argv[])
                        cpio->quiet = 1;
                        break;
                case 'R': /* GNU cpio, also --owner */
-                       errmsg = owner_parse(cpio->optarg, &uid, &gid);
+                       /* TODO: owner_parse should return uname/gname
+                        * also; use that to set [ug]name_override. */
+                       errmsg = owner_parse(cpio->argument, &uid, &gid);
                        if (errmsg) {
                                lafe_warnc(-1, "%s", errmsg);
                                usage();
                        }
-                       if (uid != -1)
+                       if (uid != -1) {
                                cpio->uid_override = uid;
-                       if (gid != -1)
+                               cpio->uname_override = NULL;
+                       }
+                       if (gid != -1) {
                                cpio->gid_override = gid;
+                               cpio->gname_override = NULL;
+                       }
                        break;
                case 'r': /* POSIX 1997 */
                        cpio->option_rename = 1;
@@ -296,6 +319,9 @@ main(int argc, char *argv[])
                case 'v': /* POSIX 1997 */
                        cpio->verbose++;
                        break;
+               case 'V': /* GNU cpio */
+                       cpio->dot++;
+                       break;
                case OPTION_VERSION: /* GNU convention */
                        version();
                        break;
@@ -339,6 +365,12 @@ main(int argc, char *argv[])
        /* -l requires -p */
        if (cpio->option_link && cpio->mode != 'p')
                lafe_errc(1, 0, "Option -l requires -p");
+       /* -v overrides -V */
+       if (cpio->dot && cpio->verbose)
+               cpio->dot = 0;
+       /* -v overrides -V */
+       if (cpio->dot && cpio->verbose)
+               cpio->dot = 0;
        /* TODO: Flag other nonsensical combinations. */
 
        switch (cpio->mode) {
@@ -396,7 +428,7 @@ static const char *long_help_msg =
        "First option must be a mode specifier:\n"
        "  -i Input  -o Output  -p Pass\n"
        "Common Options:\n"
-       "  -v    Verbose\n"
+       "  -v Verbose filenames     -V  one dot per file\n"
        "Create: %p -o [options]  < [list of files] > [archive]\n"
        "  -J,-y,-z,--lzma  Compress archive with xz/bzip2/gzip/lzma\n"
        "  --format {odc|newc|ustar}  Select archive format\n"
@@ -445,7 +477,7 @@ version(void)
 {
        fprintf(stdout,"bsdcpio %s -- %s\n",
            BSDCPIO_VERSION_STRING,
-           archive_version());
+           archive_version_string());
        exit(0);
 }
 
@@ -527,6 +559,8 @@ mode_out(struct cpio *cpio)
        }
 
        r = archive_write_close(cpio->archive);
+       if (cpio->dot)
+               fprintf(stderr, "\n");
        if (r != ARCHIVE_OK)
                lafe_errc(1, 0, "%s", archive_error_string(cpio->archive));
 
@@ -537,7 +571,7 @@ mode_out(struct cpio *cpio)
                fprintf(stderr, "%lu %s\n", (unsigned long)blocks,
                    blocks == 1 ? "block" : "blocks");
        }
-       archive_write_finish(cpio->archive);
+       archive_write_free(cpio->archive);
 }
 
 /*
@@ -575,10 +609,14 @@ file_to_archive(struct cpio *cpio, const char *srcpath)
                return (r);
        }
 
-       if (cpio->uid_override >= 0)
+       if (cpio->uid_override >= 0) {
                archive_entry_set_uid(entry, cpio->uid_override);
-       if (cpio->gid_override >= 0)
+               archive_entry_set_uname(entry, cpio->uname_override);
+       }
+       if (cpio->gid_override >= 0) {
                archive_entry_set_gid(entry, cpio->gid_override);
+               archive_entry_set_gname(entry, cpio->gname_override);
+       }
 
        /*
         * Generate a destination path for this entry.
@@ -646,6 +684,8 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry)
        /* Print out the destination name to the user. */
        if (cpio->verbose)
                fprintf(stderr,"%s", destpath);
+       if (cpio->dot)
+               fprintf(stderr, ".");
 
        /*
         * Option_link only makes sense in pass mode and for
@@ -715,7 +755,7 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry)
        if (r == ARCHIVE_FATAL)
                exit(1);
 
-       if (r >= ARCHIVE_WARN && fd >= 0) {
+       if (r >= ARCHIVE_WARN && archive_entry_size(entry) > 0 && fd >= 0) {
                bytes_read = read(fd, cpio->buff, cpio->buff_size);
                while (bytes_read > 0) {
                        r = archive_write_data(cpio->archive,
@@ -815,7 +855,7 @@ mode_in(struct cpio *cpio)
        a = archive_read_new();
        if (a == NULL)
                lafe_errc(1, 0, "Couldn't allocate archive object");
-       archive_read_support_compression_all(a);
+       archive_read_support_filter_all(a);
        archive_read_support_format_all(a);
 
        if (archive_read_open_file(a, cpio->filename, cpio->bytes_per_block))
@@ -839,7 +879,9 @@ mode_in(struct cpio *cpio)
                if (destpath == NULL)
                        continue;
                if (cpio->verbose)
-                       fprintf(stdout, "%s\n", destpath);
+                       fprintf(stderr, "%s\n", destpath);
+               if (cpio->dot)
+                       fprintf(stderr, ".");
                if (cpio->uid_override >= 0)
                        archive_entry_set_uid(entry, cpio->uid_override);
                if (cpio->gid_override >= 0)
@@ -856,6 +898,8 @@ mode_in(struct cpio *cpio)
                }
        }
        r = archive_read_close(a);
+       if (cpio->dot)
+               fprintf(stderr, "\n");
        if (r != ARCHIVE_OK)
                lafe_errc(1, 0, "%s", archive_error_string(a));
        r = archive_write_close(ext);
@@ -867,8 +911,8 @@ mode_in(struct cpio *cpio)
                fprintf(stderr, "%lu %s\n", (unsigned long)blocks,
                    blocks == 1 ? "block" : "blocks");
        }
-       archive_read_finish(a);
-       archive_write_finish(ext);
+       archive_read_free(a);
+       archive_write_free(ext);
        exit(cpio->return_value);
 }
 
@@ -882,7 +926,7 @@ extract_data(struct archive *ar, struct archive *aw)
        int r;
        size_t size;
        const void *block;
-       off_t offset;
+       int64_t offset;
 
        for (;;) {
                r = archive_read_data_block(ar, &block, &size, &offset);
@@ -912,7 +956,7 @@ mode_list(struct cpio *cpio)
        a = archive_read_new();
        if (a == NULL)
                lafe_errc(1, 0, "Couldn't allocate archive object");
-       archive_read_support_compression_all(a);
+       archive_read_support_filter_all(a);
        archive_read_support_format_all(a);
 
        if (archive_read_open_file(a, cpio->filename, cpio->bytes_per_block))
@@ -942,7 +986,7 @@ mode_list(struct cpio *cpio)
                fprintf(stderr, "%lu %s\n", (unsigned long)blocks,
                    blocks == 1 ? "block" : "blocks");
        }
-       archive_read_finish(a);
+       archive_read_free(a);
        exit(0);
 }
 
@@ -979,11 +1023,11 @@ list_item_verbose(struct cpio *cpio, struct archive_entry *entry)
                /* Use uname if it's present, else lookup name from uid. */
                uname = archive_entry_uname(entry);
                if (uname == NULL)
-                       uname = lookup_uname(cpio, archive_entry_uid(entry));
+                       uname = lookup_uname(cpio, (uid_t)archive_entry_uid(entry));
                /* Use gname if it's present, else lookup name from gid. */
                gname = archive_entry_gname(entry);
                if (gname == NULL)
-                       gname = lookup_gname(cpio, archive_entry_gid(entry));
+                       gname = lookup_gname(cpio, (uid_t)archive_entry_gid(entry));
        }
 
        /* Print device number or file size. */
@@ -1065,6 +1109,8 @@ mode_pass(struct cpio *cpio, const char *destdir)
 
        archive_entry_linkresolver_free(cpio->linkresolver);
        r = archive_write_close(cpio->archive);
+       if (cpio->dot)
+               fprintf(stderr, "\n");
        if (r != ARCHIVE_OK)
                lafe_errc(1, 0, "%s", archive_error_string(cpio->archive));
 
@@ -1076,7 +1122,7 @@ mode_pass(struct cpio *cpio, const char *destdir)
                    blocks == 1 ? "block" : "blocks");
        }
 
-       archive_write_finish(cpio->archive);
+       archive_write_free(cpio->archive);
 }
 
 /*
@@ -1250,8 +1296,9 @@ lookup_gname_helper(struct cpio *cpio, const char **name, id_t id)
 const char *
 cpio_i64toa(int64_t n0)
 {
-       // 2^64 =~ 1.8 * 10^19, so 20 decimal digits suffice.
-       // We also need 1 byte for '-' and 1 for '\0'.
+       /* 2^64 =~ 1.8 * 10^19, so 20 decimal digits suffice.
+        * We also need 1 byte for '-' and 1 for '\0'.
+        */
        static char buff[22];
        int64_t n = n0 < 0 ? -n0 : n0;
        char *p = buff + sizeof(buff);
index 3eed834..dc68e66 100644 (file)
  */
 struct cpio {
        /* Option parsing */
-       const char       *optarg;
+       const char       *argument;
 
        /* Options */
        const char       *filename;
-       char              mode; /* -i -o -p */
-       char              compress; /* -j, -y, or -z */
+       int               mode; /* -i -o -p */
+       int               compress; /* -j, -y, or -z */
        const char       *format; /* -H format */
        int               bytes_per_block; /* -b block_size */
        int               verbose;   /* -v */
+       int               dot;  /* -V */
        int               quiet;   /* --quiet */
        int               extract_flags; /* Flags for extract operation */
-       char              symlink_mode; /* H or L, per BSD conventions */
        const char       *compress_program;
        int               option_append; /* -A, only relevant for -o */
        int               option_atime_restore; /* -a */
@@ -68,7 +68,9 @@ struct cpio {
        size_t            pass_destpath_alloc;
        char             *pass_destpath;
        int               uid_override;
+       char             *uname_override;
        int               gid_override;
+       char             *gname_override;
        int               day_first; /* true if locale prefers day/mon */
 
        /* If >= 0, then close this when done. */
index 140df54..13cbe79 100644 (file)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2003-2010 Tim Kientzle
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #ifndef ARCHIVE_H_INCLUDED
 #define        ARCHIVE_H_INCLUDED
 
+#include <sys/stat.h>
+#include <stddef.h>  /* for wchar_t */
+#include <stdio.h> /* For FILE * */
+
 /*
  * Note: archive.h is for use outside of libarchive; the configuration
  * headers (config.h, archive_platform.h, etc.) are purely internal.
  * platform macros.
  */
 #if defined(__BORLANDC__) && __BORLANDC__ >= 0x560
-# define __LA_STDINT_H <stdint.h>
-#elif !defined(__WATCOMC__) && !defined(_MSC_VER) && !defined(__INTERIX) && !defined(__BORLANDC__)
-# define __LA_STDINT_H <inttypes.h>
+# include <stdint.h>
+#elif !defined(__WATCOMC__) && !defined(_MSC_VER) && !defined(__INTERIX) && !defined(__BORLANDC__) && !defined(_SCO_DS)
+# include <inttypes.h>
 #endif
 
-#include <sys/stat.h>
-#include <sys/types.h>  /* Linux requires this for off_t */
-#ifdef __LA_STDINT_H
-# include __LA_STDINT_H /* int64_t, etc. */
-#endif
-#include <stdio.h> /* For FILE * */
-
 /* Get appropriate definitions of standard POSIX-style types. */
 /* These should match the types used in 'struct stat' */
 #if defined(_WIN32) && !defined(__CYGWIN__)
-#define        __LA_INT64_T    __int64
+# define       __LA_INT64_T    __int64
 # if defined(_SSIZE_T_DEFINED) || defined(_SSIZE_T_)
 #  define      __LA_SSIZE_T    ssize_t
 # elif defined(_WIN64)
 #  define      __LA_GID_T      short
 # endif
 #else
-#include <unistd.h>  /* ssize_t, uid_t, and gid_t */
-#define        __LA_INT64_T    int64_t
-#define        __LA_SSIZE_T    ssize_t
-#define        __LA_UID_T      uid_t
-#define        __LA_GID_T      gid_t
+# include <unistd.h>  /* ssize_t, uid_t, and gid_t */
+# if defined(_SCO_DS)
+#  define      __LA_INT64_T    long long
+# else
+#  define      __LA_INT64_T    int64_t
+# endif
+# define       __LA_SSIZE_T    ssize_t
+# define       __LA_UID_T      uid_t
+# define       __LA_GID_T      gid_t
 #endif
 
 /*
@@ -88,7 +89,7 @@
 #  endif
 # else
 #  ifdef __GNUC__
-#   define __LA_DECL   __attribute__((dllimport)) extern
+#   define __LA_DECL
 #  else
 #   define __LA_DECL   __declspec(dllimport)
 #  endif
@@ -98,7 +99,7 @@
 # define __LA_DECL
 #endif
 
-#if defined(__GNUC__) && __GNUC__ >= 3
+#if defined(__GNUC__) && __GNUC__ >= 3 && !defined(__MINGW32__)
 #define        __LA_PRINTF(fmtarg, firstvararg) \
        __attribute__((__format__ (__printf__, fmtarg, firstvararg)))
 #else
@@ -123,50 +124,18 @@ extern "C" {
  * easy to compare versions at build time: for version a.b.c, the
  * version number is printf("%d%03d%03d",a,b,c).  For example, if you
  * know your application requires version 2.12.108 or later, you can
- * assert that ARCHIVE_VERSION >= 2012108.
- *
- * This single-number format was introduced with libarchive 1.9.0 in
- * the libarchive 1.x family and libarchive 2.2.4 in the libarchive
- * 2.x family.  The following may be useful if you really want to do
- * feature detection for earlier libarchive versions (which defined
- * ARCHIVE_API_VERSION and ARCHIVE_API_FEATURE instead):
- *
- * #ifndef ARCHIVE_VERSION_NUMBER
- * #define ARCHIVE_VERSION_NUMBER      \
- *             (ARCHIVE_API_VERSION * 1000000 + ARCHIVE_API_FEATURE * 1000)
- * #endif
+ * assert that ARCHIVE_VERSION_NUMBER >= 2012108.
  */
-#define        ARCHIVE_VERSION_NUMBER 2008005
+/* Note: Compiler will complain if this does not match archive_entry.h! */
+#define        ARCHIVE_VERSION_NUMBER 3000002
 __LA_DECL int          archive_version_number(void);
 
 /*
  * Textual name/version of the library, useful for version displays.
  */
-#define        ARCHIVE_VERSION_STRING "libarchive 2.8.5"
+#define        ARCHIVE_VERSION_STRING "libarchive 3.0.2"
 __LA_DECL const char * archive_version_string(void);
 
-#if ARCHIVE_VERSION_NUMBER < 3000000
-/*
- * Deprecated; these are older names that will be removed in favor of
- * the simpler definitions above.
- */
-#define        ARCHIVE_VERSION_STAMP   ARCHIVE_VERSION_NUMBER
-__LA_DECL int          archive_version_stamp(void);
-#define        ARCHIVE_LIBRARY_VERSION ARCHIVE_VERSION_STRING
-__LA_DECL const char * archive_version(void);
-#define        ARCHIVE_API_VERSION     (ARCHIVE_VERSION_NUMBER / 1000000)
-__LA_DECL int          archive_api_version(void);
-#define        ARCHIVE_API_FEATURE     ((ARCHIVE_VERSION_NUMBER / 1000) % 1000)
-__LA_DECL int          archive_api_feature(void);
-#endif
-
-#if ARCHIVE_VERSION_NUMBER < 3000000
-/* This should never have been here in the first place. */
-/* Legacy of old tar assumptions, will be removed in libarchive 3.0. */
-#define        ARCHIVE_BYTES_PER_RECORD          512
-#define        ARCHIVE_DEFAULT_BYTES_PER_BLOCK 10240
-#endif
-
 /* Declare our basic types. */
 struct archive;
 struct archive_entry;
@@ -210,48 +179,56 @@ struct archive_entry;
 typedef __LA_SSIZE_T   archive_read_callback(struct archive *,
                            void *_client_data, const void **_buffer);
 
-/* Skips at most request bytes from archive and returns the skipped amount */
-#if ARCHIVE_VERSION_NUMBER < 2000000
-/* Libarchive 1.0 used ssize_t for the return, which is only 32 bits
- * on most 32-bit platforms; not large enough. */
-typedef __LA_SSIZE_T   archive_skip_callback(struct archive *,
-                           void *_client_data, size_t request);
-#elif ARCHIVE_VERSION_NUMBER < 3000000
-/* Libarchive 2.0 used off_t here, but that is a bad idea on Linux and a
- * few other platforms where off_t varies with build settings. */
-typedef off_t          archive_skip_callback(struct archive *,
-                           void *_client_data, off_t request);
-#else
-/* Libarchive 3.0 uses int64_t here, which is actually guaranteed to be
- * 64 bits on every platform. */
+/* Skips at most request bytes from archive and returns the skipped amount.
+ * This may skip fewer bytes than requested; it may even skip zero bytes.
+ * If you do skip fewer bytes than requested, libarchive will invoke your
+ * read callback and discard data as necessary to make up the full skip.
+ */
 typedef __LA_INT64_T   archive_skip_callback(struct archive *,
                            void *_client_data, __LA_INT64_T request);
-#endif
+
+/* Seeks to specified location in the file and returns the position.
+ * Whence values are SEEK_SET, SEEK_CUR, SEEK_END from stdio.h.
+ * Return ARCHIVE_FATAL if the seek fails for any reason.
+ */
+typedef __LA_INT64_T   archive_seek_callback(struct archive *,
+    void *_client_data, __LA_INT64_T offset, int whence);
 
 /* Returns size actually written, zero on EOF, -1 on error. */
 typedef __LA_SSIZE_T   archive_write_callback(struct archive *,
                            void *_client_data,
                            const void *_buffer, size_t _length);
 
-#if ARCHIVE_VERSION_NUMBER < 3000000
-/* Open callback is actually never needed; remove it in libarchive 3.0. */
 typedef int    archive_open_callback(struct archive *, void *_client_data);
-#endif
 
 typedef int    archive_close_callback(struct archive *, void *_client_data);
 
 /*
- * Codes for archive_compression.
+ * Codes to identify various stream filters.
  */
-#define        ARCHIVE_COMPRESSION_NONE        0
-#define        ARCHIVE_COMPRESSION_GZIP        1
-#define        ARCHIVE_COMPRESSION_BZIP2       2
-#define        ARCHIVE_COMPRESSION_COMPRESS    3
-#define        ARCHIVE_COMPRESSION_PROGRAM     4
-#define        ARCHIVE_COMPRESSION_LZMA        5
-#define        ARCHIVE_COMPRESSION_XZ          6
-#define        ARCHIVE_COMPRESSION_UU          7
-#define        ARCHIVE_COMPRESSION_RPM         8
+#define        ARCHIVE_FILTER_NONE     0
+#define        ARCHIVE_FILTER_GZIP     1
+#define        ARCHIVE_FILTER_BZIP2    2
+#define        ARCHIVE_FILTER_COMPRESS 3
+#define        ARCHIVE_FILTER_PROGRAM  4
+#define        ARCHIVE_FILTER_LZMA     5
+#define        ARCHIVE_FILTER_XZ       6
+#define        ARCHIVE_FILTER_UU       7
+#define        ARCHIVE_FILTER_RPM      8
+#define        ARCHIVE_FILTER_LZIP     9
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+#define        ARCHIVE_COMPRESSION_NONE        ARCHIVE_FILTER_NONE
+#define        ARCHIVE_COMPRESSION_GZIP        ARCHIVE_FILTER_GZIP
+#define        ARCHIVE_COMPRESSION_BZIP2       ARCHIVE_FILTER_BZIP2
+#define        ARCHIVE_COMPRESSION_COMPRESS    ARCHIVE_FILTER_COMPRESS
+#define        ARCHIVE_COMPRESSION_PROGRAM     ARCHIVE_FILTER_PROGRAM
+#define        ARCHIVE_COMPRESSION_LZMA        ARCHIVE_FILTER_LZMA
+#define        ARCHIVE_COMPRESSION_XZ          ARCHIVE_FILTER_XZ
+#define        ARCHIVE_COMPRESSION_UU          ARCHIVE_FILTER_UU
+#define        ARCHIVE_COMPRESSION_RPM         ARCHIVE_FILTER_RPM
+#define        ARCHIVE_COMPRESSION_LZIP        ARCHIVE_FILTER_LZIP
+#endif
 
 /*
  * Codes returned by archive_format.
@@ -265,7 +242,7 @@ typedef int archive_close_callback(struct archive *, void *_client_data);
  * will change the format code to indicate the extended format that
  * was used).  In other cases, it's because different tools have
  * modified the archive and so different parts of the archive
- * actually have slightly different formts.  (Both tar and cpio store
+ * actually have slightly different formats.  (Both tar and cpio store
  * format codes in each entry, so it is quite possible for each
  * entry to be in a different format.)
  */
@@ -276,6 +253,7 @@ typedef int archive_close_callback(struct archive *, void *_client_data);
 #define        ARCHIVE_FORMAT_CPIO_BIN_BE              (ARCHIVE_FORMAT_CPIO | 3)
 #define        ARCHIVE_FORMAT_CPIO_SVR4_NOCRC          (ARCHIVE_FORMAT_CPIO | 4)
 #define        ARCHIVE_FORMAT_CPIO_SVR4_CRC            (ARCHIVE_FORMAT_CPIO | 5)
+#define        ARCHIVE_FORMAT_CPIO_AFIO_LARGE          (ARCHIVE_FORMAT_CPIO | 6)
 #define        ARCHIVE_FORMAT_SHAR                     0x20000
 #define        ARCHIVE_FORMAT_SHAR_BASE                (ARCHIVE_FORMAT_SHAR | 1)
 #define        ARCHIVE_FORMAT_SHAR_DUMP                (ARCHIVE_FORMAT_SHAR | 2)
@@ -294,6 +272,10 @@ typedef int        archive_close_callback(struct archive *, void *_client_data);
 #define        ARCHIVE_FORMAT_MTREE                    0x80000
 #define        ARCHIVE_FORMAT_RAW                      0x90000
 #define        ARCHIVE_FORMAT_XAR                      0xA0000
+#define        ARCHIVE_FORMAT_LHA                      0xB0000
+#define        ARCHIVE_FORMAT_CAB                      0xC0000
+#define        ARCHIVE_FORMAT_RAR                      0xD0000
+#define        ARCHIVE_FORMAT_7ZIP                     0xE0000
 
 /*-
  * Basic outline for reading an archive:
@@ -316,40 +298,81 @@ __LA_DECL struct archive  *archive_read_new(void);
  * support_compression_bzip2().  The "all" functions provide the
  * obvious shorthand.
  */
-__LA_DECL int           archive_read_support_compression_all(struct archive *);
-__LA_DECL int           archive_read_support_compression_bzip2(struct archive *);
-__LA_DECL int           archive_read_support_compression_compress(struct archive *);
-__LA_DECL int           archive_read_support_compression_gzip(struct archive *);
-__LA_DECL int           archive_read_support_compression_lzma(struct archive *);
-__LA_DECL int           archive_read_support_compression_none(struct archive *);
-__LA_DECL int           archive_read_support_compression_program(struct archive *,
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+__LA_DECL int archive_read_support_compression_all(struct archive *);
+__LA_DECL int archive_read_support_compression_bzip2(struct archive *);
+__LA_DECL int archive_read_support_compression_compress(struct archive *);
+__LA_DECL int archive_read_support_compression_gzip(struct archive *);
+__LA_DECL int archive_read_support_compression_lzip(struct archive *);
+__LA_DECL int archive_read_support_compression_lzma(struct archive *);
+__LA_DECL int archive_read_support_compression_none(struct archive *);
+__LA_DECL int archive_read_support_compression_program(struct archive *,
+                    const char *command);
+__LA_DECL int archive_read_support_compression_program_signature
+               (struct archive *, const char *,
+                                   const void * /* match */, size_t);
+
+__LA_DECL int archive_read_support_compression_rpm(struct archive *);
+__LA_DECL int archive_read_support_compression_uu(struct archive *);
+__LA_DECL int archive_read_support_compression_xz(struct archive *);
+#endif
+
+__LA_DECL int archive_read_support_filter_all(struct archive *);
+__LA_DECL int archive_read_support_filter_bzip2(struct archive *);
+__LA_DECL int archive_read_support_filter_compress(struct archive *);
+__LA_DECL int archive_read_support_filter_gzip(struct archive *);
+__LA_DECL int archive_read_support_filter_lzip(struct archive *);
+__LA_DECL int archive_read_support_filter_lzma(struct archive *);
+__LA_DECL int archive_read_support_filter_none(struct archive *);
+__LA_DECL int archive_read_support_filter_program(struct archive *,
                     const char *command);
-__LA_DECL int           archive_read_support_compression_program_signature
-                               (struct archive *, const char *,
+__LA_DECL int archive_read_support_filter_program_signature
+               (struct archive *, const char *,
                                    const void * /* match */, size_t);
 
-__LA_DECL int           archive_read_support_compression_rpm(struct archive *);
-__LA_DECL int           archive_read_support_compression_uu(struct archive *);
-__LA_DECL int           archive_read_support_compression_xz(struct archive *);
-
-__LA_DECL int           archive_read_support_format_all(struct archive *);
-__LA_DECL int           archive_read_support_format_ar(struct archive *);
-__LA_DECL int           archive_read_support_format_cpio(struct archive *);
-__LA_DECL int           archive_read_support_format_empty(struct archive *);
-__LA_DECL int           archive_read_support_format_gnutar(struct archive *);
-__LA_DECL int           archive_read_support_format_iso9660(struct archive *);
-__LA_DECL int           archive_read_support_format_mtree(struct archive *);
-__LA_DECL int           archive_read_support_format_raw(struct archive *);
-__LA_DECL int           archive_read_support_format_tar(struct archive *);
-__LA_DECL int           archive_read_support_format_xar(struct archive *);
-__LA_DECL int           archive_read_support_format_zip(struct archive *);
-
-
-/* Open the archive using callbacks for archive I/O. */
-__LA_DECL int           archive_read_open(struct archive *, void *_client_data,
+__LA_DECL int archive_read_support_filter_rpm(struct archive *);
+__LA_DECL int archive_read_support_filter_uu(struct archive *);
+__LA_DECL int archive_read_support_filter_xz(struct archive *);
+
+__LA_DECL int archive_read_support_format_7zip(struct archive *);
+__LA_DECL int archive_read_support_format_all(struct archive *);
+__LA_DECL int archive_read_support_format_ar(struct archive *);
+__LA_DECL int archive_read_support_format_by_code(struct archive *, int);
+__LA_DECL int archive_read_support_format_cab(struct archive *);
+__LA_DECL int archive_read_support_format_cpio(struct archive *);
+__LA_DECL int archive_read_support_format_empty(struct archive *);
+__LA_DECL int archive_read_support_format_gnutar(struct archive *);
+__LA_DECL int archive_read_support_format_iso9660(struct archive *);
+__LA_DECL int archive_read_support_format_lha(struct archive *);
+__LA_DECL int archive_read_support_format_mtree(struct archive *);
+__LA_DECL int archive_read_support_format_rar(struct archive *);
+__LA_DECL int archive_read_support_format_raw(struct archive *);
+__LA_DECL int archive_read_support_format_tar(struct archive *);
+__LA_DECL int archive_read_support_format_xar(struct archive *);
+__LA_DECL int archive_read_support_format_zip(struct archive *);
+
+/* Set various callbacks. */
+__LA_DECL int archive_read_set_open_callback(struct archive *,
+    archive_open_callback *);
+__LA_DECL int archive_read_set_read_callback(struct archive *,
+    archive_read_callback *);
+__LA_DECL int archive_read_set_seek_callback(struct archive *,
+    archive_seek_callback *);
+__LA_DECL int archive_read_set_skip_callback(struct archive *,
+    archive_skip_callback *);
+__LA_DECL int archive_read_set_close_callback(struct archive *,
+    archive_close_callback *);
+/* The callback data is provided to all of the callbacks above. */
+__LA_DECL int archive_read_set_callback_data(struct archive *, void *);
+/* Opening freezes the callbacks. */
+__LA_DECL int archive_read_open1(struct archive *);
+
+/* Convenience wrappers around the above. */
+__LA_DECL int archive_read_open(struct archive *, void *_client_data,
                     archive_open_callback *, archive_read_callback *,
                     archive_close_callback *);
-__LA_DECL int           archive_read_open2(struct archive *, void *_client_data,
+__LA_DECL int archive_read_open2(struct archive *, void *_client_data,
                     archive_open_callback *, archive_read_callback *,
                     archive_skip_callback *, archive_close_callback *);
 
@@ -359,30 +382,32 @@ __LA_DECL int              archive_read_open2(struct archive *, void *_client_data,
  * accept a block size handle tape blocking correctly.
  */
 /* Use this if you know the filename.  Note: NULL indicates stdin. */
-__LA_DECL int           archive_read_open_filename(struct archive *,
+__LA_DECL int archive_read_open_filename(struct archive *,
                     const char *_filename, size_t _block_size);
+__LA_DECL int archive_read_open_filename_w(struct archive *,
+                    const wchar_t *_filename, size_t _block_size);
 /* archive_read_open_file() is a deprecated synonym for ..._open_filename(). */
-__LA_DECL int           archive_read_open_file(struct archive *,
+__LA_DECL int archive_read_open_file(struct archive *,
                     const char *_filename, size_t _block_size);
 /* Read an archive that's stored in memory. */
-__LA_DECL int           archive_read_open_memory(struct archive *,
+__LA_DECL int archive_read_open_memory(struct archive *,
                     void * buff, size_t size);
 /* A more involved version that is only used for internal testing. */
-__LA_DECL int          archive_read_open_memory2(struct archive *a, void *buff,
+__LA_DECL int archive_read_open_memory2(struct archive *a, void *buff,
                     size_t size, size_t read_size);
 /* Read an archive that's already open, using the file descriptor. */
-__LA_DECL int           archive_read_open_fd(struct archive *, int _fd,
+__LA_DECL int archive_read_open_fd(struct archive *, int _fd,
                     size_t _block_size);
 /* Read an archive that's already open, using a FILE *. */
 /* Note: DO NOT use this with tape drives. */
-__LA_DECL int           archive_read_open_FILE(struct archive *, FILE *_file);
+__LA_DECL int archive_read_open_FILE(struct archive *, FILE *_file);
 
 /* Parses and returns next entry header. */
-__LA_DECL int           archive_read_next_header(struct archive *,
+__LA_DECL int archive_read_next_header(struct archive *,
                     struct archive_entry **);
 
 /* Parses and returns next entry header using the archive_entry passed in */
-__LA_DECL int           archive_read_next_header2(struct archive *,
+__LA_DECL int archive_read_next_header2(struct archive *,
                     struct archive_entry *);
 
 /*
@@ -401,14 +426,8 @@ __LA_DECL __LA_SSIZE_T              archive_read_data(struct archive *,
  * the desired size of the block.  The API does guarantee that offsets will
  * be strictly increasing and that returned blocks will not overlap.
  */
-#if ARCHIVE_VERSION_NUMBER < 3000000
-__LA_DECL int           archive_read_data_block(struct archive *a,
-                           const void **buff, size_t *size, off_t *offset);
-#else
-__LA_DECL int           archive_read_data_block(struct archive *a,
-                           const void **buff, size_t *size,
-                           __LA_INT64_T *offset);
-#endif
+__LA_DECL int archive_read_data_block(struct archive *a,
+                   const void **buff, size_t *size, __LA_INT64_T *offset);
 
 /*-
  * Some convenience functions that are built on archive_read_data:
@@ -416,23 +435,27 @@ __LA_DECL int              archive_read_data_block(struct archive *a,
  *  'into_buffer': writes data into memory buffer that you provide
  *  'into_fd': writes data to specified filedes
  */
-__LA_DECL int           archive_read_data_skip(struct archive *);
-__LA_DECL int           archive_read_data_into_buffer(struct archive *,
-                           void *buffer, __LA_SSIZE_T len);
-__LA_DECL int           archive_read_data_into_fd(struct archive *, int fd);
+__LA_DECL int archive_read_data_skip(struct archive *);
+__LA_DECL int archive_read_data_into_fd(struct archive *, int fd);
 
 /*
  * Set read options.
  */
-/* Apply option string to the format only. */
-__LA_DECL int          archive_read_set_format_options(struct archive *_a,
-                           const char *s);
-/* Apply option string to the filter only. */
-__LA_DECL int          archive_read_set_filter_options(struct archive *_a,
-                           const char *s);
+/* Apply option to the format only. */
+__LA_DECL int archive_read_set_format_option(struct archive *_a,
+                           const char *m, const char *o,
+                           const char *v);
+/* Apply option to the filter only. */
+__LA_DECL int archive_read_set_filter_option(struct archive *_a,
+                           const char *m, const char *o,
+                           const char *v);
+/* Apply option to both the format and the filter. */
+__LA_DECL int archive_read_set_option(struct archive *_a,
+                           const char *m, const char *o,
+                           const char *v);
 /* Apply option string to both the format and the filter. */
-__LA_DECL int          archive_read_set_options(struct archive *_a,
-                           const char *s);
+__LA_DECL int archive_read_set_options(struct archive *_a,
+                           const char *opts);
 
 /*-
  * Convenience function to recreate the current entry (whose header
@@ -477,10 +500,13 @@ __LA_DECL int             archive_read_set_options(struct archive *_a,
 #define        ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER      (0x0800)
 /* Detect blocks of 0 and write holes instead. */
 #define        ARCHIVE_EXTRACT_SPARSE                  (0x1000)
+/* Default: Do not restore Mac extended metadata. */
+/* This has no effect except on Mac OS. */
+#define        ARCHIVE_EXTRACT_MAC_METADATA            (0x2000)
 
-__LA_DECL int   archive_read_extract(struct archive *, struct archive_entry *,
+__LA_DECL int archive_read_extract(struct archive *, struct archive_entry *,
                     int flags);
-__LA_DECL int   archive_read_extract2(struct archive *, struct archive_entry *,
+__LA_DECL int archive_read_extract2(struct archive *, struct archive_entry *,
                     struct archive * /* dest */);
 __LA_DECL void  archive_read_extract_set_progress_callback(struct archive *,
                     void (*_progress_func)(void *), void *_user_data);
@@ -488,22 +514,21 @@ __LA_DECL void     archive_read_extract_set_progress_callback(struct archive *,
 /* Record the dev/ino of a file that will not be written.  This is
  * generally set to the dev/ino of the archive being read. */
 __LA_DECL void         archive_read_extract_set_skip_file(struct archive *,
-                    dev_t, ino_t);
+                    __LA_INT64_T, __LA_INT64_T);
 
 /* Close the file and release most resources. */
 __LA_DECL int           archive_read_close(struct archive *);
 /* Release all resources and destroy the object. */
-/* Note that archive_read_finish will call archive_read_close for you. */
-#if ARCHIVE_VERSION_NUMBER < 2000000
-/* Erroneously declared to return void in libarchive 1.x */
-__LA_DECL void          archive_read_finish(struct archive *);
-#else
+/* Note that archive_read_free will call archive_read_close for you. */
+__LA_DECL int           archive_read_free(struct archive *);
+#if ARCHIVE_VERSION_NUMBER < 4000000
+/* Synonym for archive_read_free() for backwards compatibility. */
 __LA_DECL int           archive_read_finish(struct archive *);
 #endif
 
 /*-
  * To create an archive:
- *   1) Ask archive_write_new for a archive writer object.
+ *   1) Ask archive_write_new for an archive writer object.
  *   2) Set any global properties.  In particular, you should set
  *      the compression and format to use.
  *   3) Call archive_write_open to open the file (most people
@@ -514,110 +539,122 @@ __LA_DECL int            archive_read_finish(struct archive *);
  *      - archive_write_header to write the header
  *      - archive_write_data to write the entry data
  *   5) archive_write_close to close the output
- *   6) archive_write_finish to cleanup the writer and release resources
+ *   6) archive_write_free to cleanup the writer and release resources
  */
 __LA_DECL struct archive       *archive_write_new(void);
-__LA_DECL int           archive_write_set_bytes_per_block(struct archive *,
+__LA_DECL int archive_write_set_bytes_per_block(struct archive *,
                     int bytes_per_block);
-__LA_DECL int           archive_write_get_bytes_per_block(struct archive *);
+__LA_DECL int archive_write_get_bytes_per_block(struct archive *);
 /* XXX This is badly misnamed; suggestions appreciated. XXX */
-__LA_DECL int           archive_write_set_bytes_in_last_block(struct archive *,
+__LA_DECL int archive_write_set_bytes_in_last_block(struct archive *,
                     int bytes_in_last_block);
-__LA_DECL int           archive_write_get_bytes_in_last_block(struct archive *);
+__LA_DECL int archive_write_get_bytes_in_last_block(struct archive *);
 
 /* The dev/ino of a file that won't be archived.  This is used
  * to avoid recursively adding an archive to itself. */
-__LA_DECL int           archive_write_set_skip_file(struct archive *, dev_t, ino_t);
-
-__LA_DECL int           archive_write_set_compression_bzip2(struct archive *);
-__LA_DECL int           archive_write_set_compression_compress(struct archive *);
-__LA_DECL int           archive_write_set_compression_gzip(struct archive *);
-__LA_DECL int           archive_write_set_compression_lzma(struct archive *);
-__LA_DECL int           archive_write_set_compression_none(struct archive *);
-__LA_DECL int           archive_write_set_compression_program(struct archive *,
+__LA_DECL int archive_write_set_skip_file(struct archive *,
+    __LA_INT64_T, __LA_INT64_T);
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+__LA_DECL int archive_write_set_compression_bzip2(struct archive *);
+__LA_DECL int archive_write_set_compression_compress(struct archive *);
+__LA_DECL int archive_write_set_compression_gzip(struct archive *);
+__LA_DECL int archive_write_set_compression_lzip(struct archive *);
+__LA_DECL int archive_write_set_compression_lzma(struct archive *);
+__LA_DECL int archive_write_set_compression_none(struct archive *);
+__LA_DECL int archive_write_set_compression_program(struct archive *,
+                    const char *cmd);
+__LA_DECL int archive_write_set_compression_xz(struct archive *);
+#endif
+
+__LA_DECL int archive_write_add_filter_bzip2(struct archive *);
+__LA_DECL int archive_write_add_filter_compress(struct archive *);
+__LA_DECL int archive_write_add_filter_gzip(struct archive *);
+__LA_DECL int archive_write_add_filter_lzip(struct archive *);
+__LA_DECL int archive_write_add_filter_lzma(struct archive *);
+__LA_DECL int archive_write_add_filter_none(struct archive *);
+__LA_DECL int archive_write_add_filter_program(struct archive *,
                     const char *cmd);
-__LA_DECL int           archive_write_set_compression_xz(struct archive *);
+__LA_DECL int archive_write_add_filter_xz(struct archive *);
+
+
 /* A convenience function to set the format based on the code or name. */
-__LA_DECL int           archive_write_set_format(struct archive *, int format_code);
-__LA_DECL int           archive_write_set_format_by_name(struct archive *,
+__LA_DECL int archive_write_set_format(struct archive *, int format_code);
+__LA_DECL int archive_write_set_format_by_name(struct archive *,
                     const char *name);
 /* To minimize link pollution, use one or more of the following. */
-__LA_DECL int           archive_write_set_format_ar_bsd(struct archive *);
-__LA_DECL int           archive_write_set_format_ar_svr4(struct archive *);
-__LA_DECL int           archive_write_set_format_cpio(struct archive *);
-__LA_DECL int           archive_write_set_format_cpio_newc(struct archive *);
-__LA_DECL int           archive_write_set_format_mtree(struct archive *);
+__LA_DECL int archive_write_set_format_7zip(struct archive *);
+__LA_DECL int archive_write_set_format_ar_bsd(struct archive *);
+__LA_DECL int archive_write_set_format_ar_svr4(struct archive *);
+__LA_DECL int archive_write_set_format_cpio(struct archive *);
+__LA_DECL int archive_write_set_format_cpio_newc(struct archive *);
+__LA_DECL int archive_write_set_format_gnutar(struct archive *);
+__LA_DECL int archive_write_set_format_iso9660(struct archive *);
+__LA_DECL int archive_write_set_format_mtree(struct archive *);
 /* TODO: int archive_write_set_format_old_tar(struct archive *); */
-__LA_DECL int           archive_write_set_format_pax(struct archive *);
-__LA_DECL int           archive_write_set_format_pax_restricted(struct archive *);
-__LA_DECL int           archive_write_set_format_shar(struct archive *);
-__LA_DECL int           archive_write_set_format_shar_dump(struct archive *);
-__LA_DECL int           archive_write_set_format_ustar(struct archive *);
-__LA_DECL int           archive_write_set_format_zip(struct archive *);
-__LA_DECL int           archive_write_open(struct archive *, void *,
+__LA_DECL int archive_write_set_format_pax(struct archive *);
+__LA_DECL int archive_write_set_format_pax_restricted(struct archive *);
+__LA_DECL int archive_write_set_format_shar(struct archive *);
+__LA_DECL int archive_write_set_format_shar_dump(struct archive *);
+__LA_DECL int archive_write_set_format_ustar(struct archive *);
+__LA_DECL int archive_write_set_format_xar(struct archive *);
+__LA_DECL int archive_write_set_format_zip(struct archive *);
+__LA_DECL int archive_write_open(struct archive *, void *,
                     archive_open_callback *, archive_write_callback *,
                     archive_close_callback *);
-__LA_DECL int           archive_write_open_fd(struct archive *, int _fd);
-__LA_DECL int           archive_write_open_filename(struct archive *, const char *_file);
+__LA_DECL int archive_write_open_fd(struct archive *, int _fd);
+__LA_DECL int archive_write_open_filename(struct archive *, const char *_file);
+__LA_DECL int archive_write_open_filename_w(struct archive *,
+                    const wchar_t *_file);
 /* A deprecated synonym for archive_write_open_filename() */
-__LA_DECL int           archive_write_open_file(struct archive *, const char *_file);
-__LA_DECL int           archive_write_open_FILE(struct archive *, FILE *);
+__LA_DECL int archive_write_open_file(struct archive *, const char *_file);
+__LA_DECL int archive_write_open_FILE(struct archive *, FILE *);
 /* _buffSize is the size of the buffer, _used refers to a variable that
  * will be updated after each write into the buffer. */
-__LA_DECL int           archive_write_open_memory(struct archive *,
+__LA_DECL int archive_write_open_memory(struct archive *,
                        void *_buffer, size_t _buffSize, size_t *_used);
 
 /*
  * Note that the library will truncate writes beyond the size provided
  * to archive_write_header or pad if the provided data is short.
  */
-__LA_DECL int           archive_write_header(struct archive *,
+__LA_DECL int archive_write_header(struct archive *,
                     struct archive_entry *);
-#if ARCHIVE_VERSION_NUMBER < 2000000
-/* This was erroneously declared to return "int" in libarchive 1.x. */
-__LA_DECL int           archive_write_data(struct archive *,
+__LA_DECL __LA_SSIZE_T archive_write_data(struct archive *,
                            const void *, size_t);
-#else
-/* Libarchive 2.0 and later return ssize_t here. */
-__LA_DECL __LA_SSIZE_T  archive_write_data(struct archive *,
-                           const void *, size_t);
-#endif
 
-#if ARCHIVE_VERSION_NUMBER < 3000000
-/* Libarchive 1.x and 2.x use off_t for the argument, but that's not
- * stable on Linux. */
-__LA_DECL __LA_SSIZE_T  archive_write_data_block(struct archive *,
-                                   const void *, size_t, off_t);
-#else
-/* Libarchive 3.0 uses explicit int64_t to ensure consistent 64-bit support. */
+/* This interface is currently only available for archive_write_disk handles.  */
 __LA_DECL __LA_SSIZE_T  archive_write_data_block(struct archive *,
                                    const void *, size_t, __LA_INT64_T);
-#endif
+
 __LA_DECL int           archive_write_finish_entry(struct archive *);
 __LA_DECL int           archive_write_close(struct archive *);
-#if ARCHIVE_VERSION_NUMBER < 2000000
-/* Return value was incorrect in libarchive 1.x. */
-__LA_DECL void          archive_write_finish(struct archive *);
-#else
-/* Libarchive 2.x and later returns an error if this fails. */
-/* It can fail if the archive wasn't already closed, in which case
- * archive_write_finish() will implicitly call archive_write_close(). */
+/* This can fail if the archive wasn't already closed, in which case
+ * archive_write_free() will implicitly call archive_write_close(). */
+__LA_DECL int           archive_write_free(struct archive *);
+#if ARCHIVE_VERSION_NUMBER < 4000000
+/* Synonym for archive_write_free() for backwards compatibility. */
 __LA_DECL int           archive_write_finish(struct archive *);
 #endif
 
 /*
  * Set write options.
  */
-/* Apply option string to the format only. */
-__LA_DECL int          archive_write_set_format_options(struct archive *_a,
-                           const char *s);
-/* Apply option string to the compressor only. */
-__LA_DECL int          archive_write_set_compressor_options(struct archive *_a,
-                           const char *s);
-/* Apply option string to both the format and the compressor. */
-__LA_DECL int          archive_write_set_options(struct archive *_a,
-                           const char *s);
-
+/* Apply option to the format only. */
+__LA_DECL int archive_write_set_format_option(struct archive *_a,
+                           const char *m, const char *o,
+                           const char *v);
+/* Apply option to the filter only. */
+__LA_DECL int archive_write_set_filter_option(struct archive *_a,
+                           const char *m, const char *o,
+                           const char *v);
+/* Apply option to both the format and the filter. */
+__LA_DECL int archive_write_set_option(struct archive *_a,
+                           const char *m, const char *o,
+                           const char *v);
+/* Apply option string to both the format and the filter. */
+__LA_DECL int archive_write_set_options(struct archive *_a,
+                           const char *opts);
 
 /*-
  * ARCHIVE_WRITE_DISK API
@@ -630,15 +667,15 @@ __LA_DECL int             archive_write_set_options(struct archive *_a,
  *      - construct an appropriate struct archive_entry structure
  *      - archive_write_header to create the file/dir/etc on disk
  *      - archive_write_data to write the entry data
- *   4) archive_write_finish to cleanup the writer and release resources
+ *   4) archive_write_free to cleanup the writer and release resources
  *
  * In particular, you can use this in conjunction with archive_read()
  * to pull entries out of an archive and create them on disk.
  */
 __LA_DECL struct archive       *archive_write_disk_new(void);
 /* This file will not be overwritten. */
-__LA_DECL int           archive_write_disk_set_skip_file(struct archive *,
-                    dev_t, ino_t);
+__LA_DECL int archive_write_disk_set_skip_file(struct archive *,
+    __LA_INT64_T, __LA_INT64_T);
 /* Set flags to control how the next item gets created.
  * This accepts a bitmask of ARCHIVE_EXTRACT_XXX flags defined above. */
 __LA_DECL int           archive_write_disk_set_options(struct archive *,
@@ -666,14 +703,16 @@ __LA_DECL int      archive_write_disk_set_standard_lookup(struct archive *);
  * your needs, you can write your own and register them.  Be sure to
  * include a cleanup function if you have allocated private data.
  */
-__LA_DECL int   archive_write_disk_set_group_lookup(struct archive *,
-                           void * /* private_data */,
-                           __LA_GID_T (*)(void *, const char *, __LA_GID_T),
-                           void (* /* cleanup */)(void *));
-__LA_DECL int   archive_write_disk_set_user_lookup(struct archive *,
-                           void * /* private_data */,
-                           __LA_UID_T (*)(void *, const char *, __LA_UID_T),
-                           void (* /* cleanup */)(void *));
+__LA_DECL int archive_write_disk_set_group_lookup(struct archive *,
+    void * /* private_data */,
+    __LA_INT64_T (*)(void *, const char *, __LA_INT64_T),
+    void (* /* cleanup */)(void *));
+__LA_DECL int archive_write_disk_set_user_lookup(struct archive *,
+    void * /* private_data */,
+    __LA_INT64_T (*)(void *, const char *, __LA_INT64_T),
+    void (* /* cleanup */)(void *));
+__LA_DECL __LA_INT64_T archive_write_disk_gid(struct archive *, const char *, __LA_INT64_T);
+__LA_DECL __LA_INT64_T archive_write_disk_uid(struct archive *, const char *, __LA_INT64_T);
 
 /*
  * ARCHIVE_READ_DISK API
@@ -694,32 +733,64 @@ __LA_DECL int archive_read_disk_entry_from_file(struct archive *,
     struct archive_entry *, int /* fd */, const struct stat *);
 /* Look up gname for gid or uname for uid. */
 /* Default implementations are very, very stupid. */
-__LA_DECL const char *archive_read_disk_gname(struct archive *, __LA_GID_T);
-__LA_DECL const char *archive_read_disk_uname(struct archive *, __LA_UID_T);
+__LA_DECL const char *archive_read_disk_gname(struct archive *, __LA_INT64_T);
+__LA_DECL const char *archive_read_disk_uname(struct archive *, __LA_INT64_T);
 /* "Standard" implementation uses getpwuid_r, getgrgid_r and caches the
  * results for performance. */
 __LA_DECL int  archive_read_disk_set_standard_lookup(struct archive *);
 /* You can install your own lookups if you like. */
 __LA_DECL int  archive_read_disk_set_gname_lookup(struct archive *,
     void * /* private_data */,
-    const char *(* /* lookup_fn */)(void *, __LA_GID_T),
+    const char *(* /* lookup_fn */)(void *, __LA_INT64_T),
     void (* /* cleanup_fn */)(void *));
 __LA_DECL int  archive_read_disk_set_uname_lookup(struct archive *,
     void * /* private_data */,
-    const char *(* /* lookup_fn */)(void *, __LA_UID_T),
+    const char *(* /* lookup_fn */)(void *, __LA_INT64_T),
     void (* /* cleanup_fn */)(void *));
+/* Start traversal. */
+__LA_DECL int  archive_read_disk_open(struct archive *, const char *);
+__LA_DECL int  archive_read_disk_open_w(struct archive *, const wchar_t *);
+/*
+ * Request that current entry be visited.  If you invoke it on every
+ * directory, you'll get a physical traversal.  This is ignored if the
+ * current entry isn't a directory or a link to a directory.  So, if
+ * you invoke this on every returned path, you'll get a full logical
+ * traversal.
+ */
+__LA_DECL int  archive_read_disk_descend(struct archive *);
+__LA_DECL int  archive_read_disk_current_filesystem(struct archive *);
+__LA_DECL int  archive_read_disk_current_filesystem_is_synthetic(struct archive *);
+__LA_DECL int  archive_read_disk_current_filesystem_is_remote(struct archive *);
+/* Request that the access time of the entry visited by travesal be restored. */
+__LA_DECL int  archive_read_disk_set_atime_restored(struct archive *);
 
 /*
  * Accessor functions to read/set various information in
  * the struct archive object:
  */
-/* Bytes written after compression or read before decompression. */
+
+/* Number of filters in the current filter pipeline. */
+/* Filter #0 is the one closest to the format, -1 is a synonym for the
+ * last filter, which is always the pseudo-filter that wraps the
+ * client callbacks. */
+__LA_DECL int           archive_filter_count(struct archive *);
+__LA_DECL __LA_INT64_T  archive_filter_bytes(struct archive *, int);
+__LA_DECL int           archive_filter_code(struct archive *, int);
+__LA_DECL const char *  archive_filter_name(struct archive *, int);
+
+#if ARCHIVE_VERSION_NUMBER < 4000000
+/* These don't properly handle multiple filters, so are deprecated and
+ * will eventually be removed. */
+/* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, -1); */
 __LA_DECL __LA_INT64_T  archive_position_compressed(struct archive *);
-/* Bytes written to compressor or read from decompressor. */
+/* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, 0); */
 __LA_DECL __LA_INT64_T  archive_position_uncompressed(struct archive *);
-
+/* As of libarchive 3.0, this is an alias for archive_filter_name(a, 0); */
 __LA_DECL const char   *archive_compression_name(struct archive *);
+/* As of libarchive 3.0, this is an alias for archive_filter_code(a, 0); */
 __LA_DECL int           archive_compression(struct archive *);
+#endif
+
 __LA_DECL int           archive_errno(struct archive *);
 __LA_DECL const char   *archive_error_string(struct archive *);
 __LA_DECL const char   *archive_format_name(struct archive *);
diff --git a/contrib/libarchive/libarchive/archive_acl.c b/contrib/libarchive/libarchive/archive_acl.c
new file mode 100644 (file)
index 0000000..4747a4c
--- /dev/null
@@ -0,0 +1,1264 @@
+/*-
+ * Copyright (c) 2003-2010 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_WCHAR_H
+#include <wchar.h>
+#endif
+
+#include "archive_acl_private.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+
+#undef max
+#define        max(a, b)       ((a)>(b)?(a):(b))
+
+#ifndef HAVE_WMEMCMP
+/* Good enough for simple equality testing, but not for sorting. */
+#define wmemcmp(a,b,i)  memcmp((a), (b), (i) * sizeof(wchar_t))
+#endif
+
+static int     acl_special(struct archive_acl *acl,
+                   int type, int permset, int tag);
+static struct archive_acl_entry *acl_new_entry(struct archive_acl *acl,
+                   int type, int permset, int tag, int id);
+static int     isint_w(const wchar_t *start, const wchar_t *end, int *result);
+static int     ismode_w(const wchar_t *start, const wchar_t *end, int *result);
+static void    next_field_w(const wchar_t **wp, const wchar_t **start,
+                   const wchar_t **end, wchar_t *sep);
+static int     prefix_w(const wchar_t *start, const wchar_t *end,
+                   const wchar_t *test);
+static void    append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
+                   const wchar_t *wname, int perm, int id);
+static void    append_id_w(wchar_t **wp, int id);
+static int     isint(const char *start, const char *end, int *result);
+static int     ismode(const char *start, const char *end, int *result);
+static void    next_field(const char **p, const char **start,
+                   const char **end, char *sep);
+static int     prefix(const char *start, const char *end,
+                   const char *test);
+static void    append_entry(char **p, const char *prefix, int tag,
+                   const char *name, int perm, int id);
+static void    append_id(char **p, int id);
+
+void
+archive_acl_clear(struct archive_acl *acl)
+{
+       struct archive_acl_entry *ap;
+
+       while (acl->acl_head != NULL) {
+               ap = acl->acl_head->next;
+               archive_mstring_clean(&acl->acl_head->name);
+               free(acl->acl_head);
+               acl->acl_head = ap;
+       }
+       if (acl->acl_text_w != NULL) {
+               free(acl->acl_text_w);
+               acl->acl_text_w = NULL;
+       }
+       if (acl->acl_text != NULL) {
+               free(acl->acl_text);
+               acl->acl_text = NULL;
+       }
+       acl->acl_p = NULL;
+       acl->acl_state = 0; /* Not counting. */
+}
+
+void
+archive_acl_copy(struct archive_acl *dest, struct archive_acl *src)
+{
+       struct archive_acl_entry *ap, *ap2;
+
+       archive_acl_clear(dest);
+
+       dest->mode = src->mode;
+       ap = src->acl_head;
+       while (ap != NULL) {
+               ap2 = acl_new_entry(dest,
+                   ap->type, ap->permset, ap->tag, ap->id);
+               if (ap2 != NULL)
+                       archive_mstring_copy(&ap2->name, &ap->name);
+               ap = ap->next;
+       }
+}
+
+int
+archive_acl_add_entry(struct archive_acl *acl,
+    int type, int permset, int tag, int id, const char *name)
+{
+       struct archive_acl_entry *ap;
+
+       if (acl_special(acl, type, permset, tag) == 0)
+               return ARCHIVE_OK;
+       ap = acl_new_entry(acl, type, permset, tag, id);
+       if (ap == NULL) {
+               /* XXX Error XXX */
+               return ARCHIVE_FAILED;
+       }
+       if (name != NULL  &&  *name != '\0')
+               archive_mstring_copy_mbs(&ap->name, name);
+       else
+               archive_mstring_clean(&ap->name);
+       return ARCHIVE_OK;
+}
+
+int
+archive_acl_add_entry_w_len(struct archive_acl *acl,
+    int type, int permset, int tag, int id, const wchar_t *name, size_t len)
+{
+       struct archive_acl_entry *ap;
+
+       if (acl_special(acl, type, permset, tag) == 0)
+               return ARCHIVE_OK;
+       ap = acl_new_entry(acl, type, permset, tag, id);
+       if (ap == NULL) {
+               /* XXX Error XXX */
+               return ARCHIVE_FAILED;
+       }
+       if (name != NULL  &&  *name != L'\0' && len > 0)
+               archive_mstring_copy_wcs_len(&ap->name, name, len);
+       else
+               archive_mstring_clean(&ap->name);
+       return ARCHIVE_OK;
+}
+
+int
+archive_acl_add_entry_len_l(struct archive_acl *acl,
+    int type, int permset, int tag, int id, const char *name, size_t len,
+    struct archive_string_conv *sc)
+{
+       struct archive_acl_entry *ap;
+       int r;
+
+       if (acl_special(acl, type, permset, tag) == 0)
+               return ARCHIVE_OK;
+       ap = acl_new_entry(acl, type, permset, tag, id);
+       if (ap == NULL) {
+               /* XXX Error XXX */
+               return ARCHIVE_FAILED;
+       }
+       if (name != NULL  &&  *name != '\0' && len > 0) {
+               r = archive_mstring_copy_mbs_len_l(&ap->name, name, len, sc);
+       } else {
+               r = 0;
+               archive_mstring_clean(&ap->name);
+       }
+       if (r == 0)
+               return (ARCHIVE_OK);
+       else if (errno == ENOMEM)
+               return (ARCHIVE_FATAL);
+       else
+               return (ARCHIVE_WARN);
+}
+
+/*
+ * If this ACL entry is part of the standard POSIX permissions set,
+ * store the permissions in the stat structure and return zero.
+ */
+static int
+acl_special(struct archive_acl *acl, int type, int permset, int tag)
+{
+       if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS
+           && ((permset & ~007) == 0)) {
+               switch (tag) {
+               case ARCHIVE_ENTRY_ACL_USER_OBJ:
+                       acl->mode &= ~0700;
+                       acl->mode |= (permset & 7) << 6;
+                       return (0);
+               case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+                       acl->mode &= ~0070;
+                       acl->mode |= (permset & 7) << 3;
+                       return (0);
+               case ARCHIVE_ENTRY_ACL_OTHER:
+                       acl->mode &= ~0007;
+                       acl->mode |= permset & 7;
+                       return (0);
+               }
+       }
+       return (1);
+}
+
+/*
+ * Allocate and populate a new ACL entry with everything but the
+ * name.
+ */
+static struct archive_acl_entry *
+acl_new_entry(struct archive_acl *acl,
+    int type, int permset, int tag, int id)
+{
+       struct archive_acl_entry *ap, *aq;
+
+       /* Type argument must be a valid NFS4 or POSIX.1e type.
+        * The type must agree with anything already set and
+        * the permset must be compatible. */
+       if (type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+               if (acl->acl_types & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+                       return (NULL);
+               }
+               if (permset &
+                   ~(ARCHIVE_ENTRY_ACL_PERMS_NFS4
+                       | ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4)) {
+                       return (NULL);
+               }
+       } else  if (type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) {
+               if (acl->acl_types & ~ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) {
+                       return (NULL);
+               }
+               if (permset & ~ARCHIVE_ENTRY_ACL_PERMS_POSIX1E) {
+                       return (NULL);
+               }
+       } else {
+               return (NULL);
+       }
+
+       /* Verify the tag is valid and compatible with NFS4 or POSIX.1e. */
+       switch (tag) {
+       case ARCHIVE_ENTRY_ACL_USER:
+       case ARCHIVE_ENTRY_ACL_USER_OBJ:
+       case ARCHIVE_ENTRY_ACL_GROUP:
+       case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+               /* Tags valid in both NFS4 and POSIX.1e */
+               break;
+       case ARCHIVE_ENTRY_ACL_MASK:
+       case ARCHIVE_ENTRY_ACL_OTHER:
+               /* Tags valid only in POSIX.1e. */
+               if (type & ~ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) {
+                       return (NULL);
+               }
+               break;
+       case ARCHIVE_ENTRY_ACL_EVERYONE:
+               /* Tags valid only in NFS4. */
+               if (type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+                       return (NULL);
+               }
+               break;
+       default:
+               /* No other values are valid. */
+               return (NULL);
+       }
+
+       if (acl->acl_text_w != NULL) {
+               free(acl->acl_text_w);
+               acl->acl_text_w = NULL;
+       }
+       if (acl->acl_text != NULL) {
+               free(acl->acl_text);
+               acl->acl_text = NULL;
+       }
+
+       /* If there's a matching entry already in the list, overwrite it. */
+       ap = acl->acl_head;
+       aq = NULL;
+       while (ap != NULL) {
+               if (ap->type == type && ap->tag == tag && ap->id == id) {
+                       ap->permset = permset;
+                       return (ap);
+               }
+               aq = ap;
+               ap = ap->next;
+       }
+
+       /* Add a new entry to the end of the list. */
+       ap = (struct archive_acl_entry *)malloc(sizeof(*ap));
+       if (ap == NULL)
+               return (NULL);
+       memset(ap, 0, sizeof(*ap));
+       if (aq == NULL)
+               acl->acl_head = ap;
+       else
+               aq->next = ap;
+       ap->type = type;
+       ap->tag = tag;
+       ap->id = id;
+       ap->permset = permset;
+       acl->acl_types |= type;
+       return (ap);
+}
+
+/*
+ * Return a count of entries matching "want_type".
+ */
+int
+archive_acl_count(struct archive_acl *acl, int want_type)
+{
+       int count;
+       struct archive_acl_entry *ap;
+
+       count = 0;
+       ap = acl->acl_head;
+       while (ap != NULL) {
+               if ((ap->type & want_type) != 0)
+                       count++;
+               ap = ap->next;
+       }
+
+       if (count > 0 && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0))
+               count += 3;
+       return (count);
+}
+
+/*
+ * Prepare for reading entries from the ACL data.  Returns a count
+ * of entries matching "want_type", or zero if there are no
+ * non-extended ACL entries of that type.
+ */
+int
+archive_acl_reset(struct archive_acl *acl, int want_type)
+{
+       int count, cutoff;
+
+       count = archive_acl_count(acl, want_type);
+
+       /*
+        * If the only entries are the three standard ones,
+        * then don't return any ACL data.  (In this case,
+        * client can just use chmod(2) to set permissions.)
+        */
+       if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)
+               cutoff = 3;
+       else
+               cutoff = 0;
+
+       if (count > cutoff)
+               acl->acl_state = ARCHIVE_ENTRY_ACL_USER_OBJ;
+       else
+               acl->acl_state = 0;
+       acl->acl_p = acl->acl_head;
+       return (count);
+}
+
+
+/*
+ * Return the next ACL entry in the list.  Fake entries for the
+ * standard permissions and include them in the returned list.
+ */
+int
+archive_acl_next(struct archive *a, struct archive_acl *acl, int want_type, int *type,
+    int *permset, int *tag, int *id, const char **name)
+{
+       *name = NULL;
+       *id = -1;
+
+       /*
+        * The acl_state is either zero (no entries available), -1
+        * (reading from list), or an entry type (retrieve that type
+        * from ae_stat.aest_mode).
+        */
+       if (acl->acl_state == 0)
+               return (ARCHIVE_WARN);
+
+       /* The first three access entries are special. */
+       if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+               switch (acl->acl_state) {
+               case ARCHIVE_ENTRY_ACL_USER_OBJ:
+                       *permset = (acl->mode >> 6) & 7;
+                       *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+                       *tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+                       acl->acl_state = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+                       return (ARCHIVE_OK);
+               case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+                       *permset = (acl->mode >> 3) & 7;
+                       *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+                       *tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+                       acl->acl_state = ARCHIVE_ENTRY_ACL_OTHER;
+                       return (ARCHIVE_OK);
+               case ARCHIVE_ENTRY_ACL_OTHER:
+                       *permset = acl->mode & 7;
+                       *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+                       *tag = ARCHIVE_ENTRY_ACL_OTHER;
+                       acl->acl_state = -1;
+                       acl->acl_p = acl->acl_head;
+                       return (ARCHIVE_OK);
+               default:
+                       break;
+               }
+       }
+
+       while (acl->acl_p != NULL && (acl->acl_p->type & want_type) == 0)
+               acl->acl_p = acl->acl_p->next;
+       if (acl->acl_p == NULL) {
+               acl->acl_state = 0;
+               *type = 0;
+               *permset = 0;
+               *tag = 0;
+               *id = -1;
+               *name = NULL;
+               return (ARCHIVE_EOF); /* End of ACL entries. */
+       }
+       *type = acl->acl_p->type;
+       *permset = acl->acl_p->permset;
+       *tag = acl->acl_p->tag;
+       *id = acl->acl_p->id;
+       if (archive_mstring_get_mbs(a, &acl->acl_p->name, name) != 0)
+               *name = NULL;
+       acl->acl_p = acl->acl_p->next;
+       return (ARCHIVE_OK);
+}
+
+/*
+ * Generate a text version of the ACL.  The flags parameter controls
+ * the style of the generated ACL.
+ */
+const wchar_t *
+archive_acl_text_w(struct archive *a, struct archive_acl *acl, int flags)
+{
+       int count;
+       size_t length;
+       const wchar_t *wname;
+       const wchar_t *prefix;
+       wchar_t separator;
+       struct archive_acl_entry *ap;
+       int id;
+       wchar_t *wp;
+
+       if (acl->acl_text_w != NULL) {
+               free (acl->acl_text_w);
+               acl->acl_text_w = NULL;
+       }
+
+       separator = L',';
+       count = 0;
+       length = 0;
+       ap = acl->acl_head;
+       while (ap != NULL) {
+               if ((ap->type & flags) != 0) {
+                       count++;
+                       if ((flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) &&
+                           (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT))
+                               length += 8; /* "default:" */
+                       length += 5; /* tag name */
+                       length += 1; /* colon */
+                       if (archive_mstring_get_wcs(a, &ap->name, &wname) == 0 &&
+                           wname != NULL)
+                               length += wcslen(wname);
+                       else
+                               length += sizeof(uid_t) * 3 + 1;
+                       length ++; /* colon */
+                       length += 3; /* rwx */
+                       length += 1; /* colon */
+                       length += max(sizeof(uid_t), sizeof(gid_t)) * 3 + 1;
+                       length ++; /* newline */
+               }
+               ap = ap->next;
+       }
+
+       if (count > 0 && ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) {
+               length += 10; /* "user::rwx\n" */
+               length += 11; /* "group::rwx\n" */
+               length += 11; /* "other::rwx\n" */
+       }
+
+       if (count == 0)
+               return (NULL);
+
+       /* Now, allocate the string and actually populate it. */
+       wp = acl->acl_text_w = (wchar_t *)malloc(length * sizeof(wchar_t));
+       if (wp == NULL)
+               __archive_errx(1, "No memory to generate the text version of the ACL");
+       count = 0;
+       if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+               append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
+                   acl->mode & 0700, -1);
+               *wp++ = ',';
+               append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_GROUP_OBJ, NULL,
+                   acl->mode & 0070, -1);
+               *wp++ = ',';
+               append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_OTHER, NULL,
+                   acl->mode & 0007, -1);
+               count += 3;
+
+               ap = acl->acl_head;
+               while (ap != NULL) {
+                       if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0 &&
+                               archive_mstring_get_wcs(a, &ap->name, &wname) == 0) {
+                               *wp++ = separator;
+                               if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
+                                       id = ap->id;
+                               else
+                                       id = -1;
+                               append_entry_w(&wp, NULL, ap->tag, wname,
+                                   ap->permset, id);
+                               count++;
+                       }
+                       ap = ap->next;
+               }
+       }
+
+
+       if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
+               if (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT)
+                       prefix = L"default:";
+               else
+                       prefix = NULL;
+               ap = acl->acl_head;
+               count = 0;
+               while (ap != NULL) {
+                       if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0 &&
+                               archive_mstring_get_wcs(a, &ap->name, &wname) == 0) {
+                               if (count > 0)
+                                       *wp++ = separator;
+                               if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
+                                       id = ap->id;
+                               else
+                                       id = -1;
+                               append_entry_w(&wp, prefix, ap->tag,
+                                   wname, ap->permset, id);
+                               count ++;
+                       }
+                       ap = ap->next;
+               }
+       }
+
+       return (acl->acl_text_w);
+}
+
+
+static void
+append_id_w(wchar_t **wp, int id)
+{
+       if (id < 0)
+               id = 0;
+       if (id > 9)
+               append_id_w(wp, id / 10);
+       *(*wp)++ = L"0123456789"[id % 10];
+}
+
+static void
+append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
+    const wchar_t *wname, int perm, int id)
+{
+       if (prefix != NULL) {
+               wcscpy(*wp, prefix);
+               *wp += wcslen(*wp);
+       }
+       switch (tag) {
+       case ARCHIVE_ENTRY_ACL_USER_OBJ:
+               wname = NULL;
+               id = -1;
+               /* FALLTHROUGH */
+       case ARCHIVE_ENTRY_ACL_USER:
+               wcscpy(*wp, L"user");
+               break;
+       case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+               wname = NULL;
+               id = -1;
+               /* FALLTHROUGH */
+       case ARCHIVE_ENTRY_ACL_GROUP:
+               wcscpy(*wp, L"group");
+               break;
+       case ARCHIVE_ENTRY_ACL_MASK:
+               wcscpy(*wp, L"mask");
+               wname = NULL;
+               id = -1;
+               break;
+       case ARCHIVE_ENTRY_ACL_OTHER:
+               wcscpy(*wp, L"other");
+               wname = NULL;
+               id = -1;
+               break;
+       }
+       *wp += wcslen(*wp);
+       *(*wp)++ = L':';
+       if (wname != NULL) {
+               wcscpy(*wp, wname);
+               *wp += wcslen(*wp);
+       } else if (tag == ARCHIVE_ENTRY_ACL_USER
+           || tag == ARCHIVE_ENTRY_ACL_GROUP) {
+               append_id_w(wp, id);
+               id = -1;
+       }
+       *(*wp)++ = L':';
+       *(*wp)++ = (perm & 0444) ? L'r' : L'-';
+       *(*wp)++ = (perm & 0222) ? L'w' : L'-';
+       *(*wp)++ = (perm & 0111) ? L'x' : L'-';
+       if (id != -1) {
+               *(*wp)++ = L':';
+               append_id_w(wp, id);
+       }
+       **wp = L'\0';
+}
+
+int
+archive_acl_text_l(struct archive_acl *acl, int flags,
+    const char **acl_text, size_t *acl_text_len,
+    struct archive_string_conv *sc)
+{
+       int count;
+       size_t length;
+       const char *name;
+       const char *prefix;
+       char separator;
+       struct archive_acl_entry *ap;
+       size_t len;
+       int id, r;
+       char *p;
+
+       if (acl->acl_text != NULL) {
+               free (acl->acl_text);
+               acl->acl_text = NULL;
+       }
+
+       *acl_text = NULL;
+       if (acl_text_len != NULL)
+               *acl_text_len = 0;
+       separator = ',';
+       count = 0;
+       length = 0;
+       ap = acl->acl_head;
+       while (ap != NULL) {
+               if ((ap->type & flags) != 0) {
+                       count++;
+                       if ((flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) &&
+                           (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT))
+                               length += 8; /* "default:" */
+                       length += 5; /* tag name */
+                       length += 1; /* colon */
+                       r = archive_mstring_get_mbs_l(
+                           &ap->name, &name, &len, sc);
+                       if (r != 0)
+                               return (-1);
+                       if (len > 0 && name != NULL)
+                               length += len;
+                       else
+                               length += sizeof(uid_t) * 3 + 1;
+                       length ++; /* colon */
+                       length += 3; /* rwx */
+                       length += 1; /* colon */
+                       length += max(sizeof(uid_t), sizeof(gid_t)) * 3 + 1;
+                       length ++; /* newline */
+               }
+               ap = ap->next;
+       }
+
+       if (count > 0 && ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) {
+               length += 10; /* "user::rwx\n" */
+               length += 11; /* "group::rwx\n" */
+               length += 11; /* "other::rwx\n" */
+       }
+
+       if (count == 0)
+               return (0);
+
+       /* Now, allocate the string and actually populate it. */
+       p = acl->acl_text = (char *)malloc(length);
+       if (p == NULL)
+               __archive_errx(1, "No memory to generate the text version of the ACL");
+       count = 0;
+       if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+               append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
+                   acl->mode & 0700, -1);
+               *p++ = ',';
+               append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_GROUP_OBJ, NULL,
+                   acl->mode & 0070, -1);
+               *p++ = ',';
+               append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_OTHER, NULL,
+                   acl->mode & 0007, -1);
+               count += 3;
+
+               for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
+                       if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) == 0)
+                               continue;
+                       r = archive_mstring_get_mbs_l(
+                           &ap->name, &name, &len, sc);
+                       if (r != 0)
+                               return (-1);
+                       *p++ = separator;
+                       if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
+                               id = ap->id;
+                       else
+                               id = -1;
+                       append_entry(&p, NULL, ap->tag, name,
+                           ap->permset, id);
+                       count++;
+               }
+       }
+
+
+       if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
+               if (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT)
+                       prefix = "default:";
+               else
+                       prefix = NULL;
+               count = 0;
+               for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
+                       if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) == 0)
+                               continue;
+                       r = archive_mstring_get_mbs_l(
+                           &ap->name, &name, &len, sc);
+                       if (r != 0)
+                               return (-1);
+                       if (count > 0)
+                               *p++ = separator;
+                       if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
+                               id = ap->id;
+                       else
+                               id = -1;
+                       append_entry(&p, prefix, ap->tag,
+                           name, ap->permset, id);
+                       count ++;
+               }
+       }
+
+       *acl_text = acl->acl_text;
+       if (acl_text_len != NULL)
+               *acl_text_len = strlen(acl->acl_text);
+       return (0);
+}
+
+static void
+append_id(char **p, int id)
+{
+       if (id < 0)
+               id = 0;
+       if (id > 9)
+               append_id(p, id / 10);
+       *(*p)++ = "0123456789"[id % 10];
+}
+
+static void
+append_entry(char **p, const char *prefix, int tag,
+    const char *name, int perm, int id)
+{
+       if (prefix != NULL) {
+               strcpy(*p, prefix);
+               *p += strlen(*p);
+       }
+       switch (tag) {
+       case ARCHIVE_ENTRY_ACL_USER_OBJ:
+               name = NULL;
+               id = -1;
+               /* FALLTHROUGH */
+       case ARCHIVE_ENTRY_ACL_USER:
+               strcpy(*p, "user");
+               break;
+       case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+               name = NULL;
+               id = -1;
+               /* FALLTHROUGH */
+       case ARCHIVE_ENTRY_ACL_GROUP:
+               strcpy(*p, "group");
+               break;
+       case ARCHIVE_ENTRY_ACL_MASK:
+               strcpy(*p, "mask");
+               name = NULL;
+               id = -1;
+               break;
+       case ARCHIVE_ENTRY_ACL_OTHER:
+               strcpy(*p, "other");
+               name = NULL;
+               id = -1;
+               break;
+       }
+       *p += strlen(*p);
+       *(*p)++ = ':';
+       if (name != NULL) {
+               strcpy(*p, name);
+               *p += strlen(*p);
+       } else if (tag == ARCHIVE_ENTRY_ACL_USER
+           || tag == ARCHIVE_ENTRY_ACL_GROUP) {
+               append_id(p, id);
+               id = -1;
+       }
+       *(*p)++ = ':';
+       *(*p)++ = (perm & 0444) ? 'r' : '-';
+       *(*p)++ = (perm & 0222) ? 'w' : '-';
+       *(*p)++ = (perm & 0111) ? 'x' : '-';
+       if (id != -1) {
+               *(*p)++ = ':';
+               append_id(p, id);
+       }
+       **p = '\0';
+}
+
+/*
+ * Parse a textual ACL.  This automatically recognizes and supports
+ * extensions described above.  The 'type' argument is used to
+ * indicate the type that should be used for any entries not
+ * explicitly marked as "default:".
+ */
+int
+archive_acl_parse_w(struct archive_acl *acl,
+    const wchar_t *text, int default_type)
+{
+       struct {
+               const wchar_t *start;
+               const wchar_t *end;
+       } field[4], name;
+
+       int fields, n;
+       int type, tag, permset, id;
+       wchar_t sep;
+
+       while (text != NULL  &&  *text != L'\0') {
+               /*
+                * Parse the fields out of the next entry,
+                * advance 'text' to start of next entry.
+                */
+               fields = 0;
+               do {
+                       const wchar_t *start, *end;
+                       next_field_w(&text, &start, &end, &sep);
+                       if (fields < 4) {
+                               field[fields].start = start;
+                               field[fields].end = end;
+                       }
+                       ++fields;
+               } while (sep == L':');
+
+               /* Set remaining fields to blank. */
+               for (n = fields; n < 4; ++n)
+                       field[n].start = field[n].end = NULL;
+
+               /* Check for a numeric ID in field 1 or 3. */
+               id = -1;
+               isint_w(field[1].start, field[1].end, &id);
+               /* Field 3 is optional. */
+               if (id == -1 && fields > 3)
+                       isint_w(field[3].start, field[3].end, &id);
+
+               /*
+                * Solaris extension:  "defaultuser::rwx" is the
+                * default ACL corresponding to "user::rwx", etc.
+                */
+               if (field[0].end - field[0].start > 7
+                   && wmemcmp(field[0].start, L"default", 7) == 0) {
+                       type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
+                       field[0].start += 7;
+               } else
+                       type = default_type;
+
+               name.start = name.end = NULL;
+               if (prefix_w(field[0].start, field[0].end, L"user")) {
+                       if (!ismode_w(field[2].start, field[2].end, &permset))
+                               return (ARCHIVE_WARN);
+                       if (id != -1 || field[1].start < field[1].end) {
+                               tag = ARCHIVE_ENTRY_ACL_USER;
+                               name = field[1];
+                       } else
+                               tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+               } else if (prefix_w(field[0].start, field[0].end, L"group")) {
+                       if (!ismode_w(field[2].start, field[2].end, &permset))
+                               return (ARCHIVE_WARN);
+                       if (id != -1 || field[1].start < field[1].end) {
+                               tag = ARCHIVE_ENTRY_ACL_GROUP;
+                               name = field[1];
+                       } else
+                               tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+               } else if (prefix_w(field[0].start, field[0].end, L"other")) {
+                       if (fields == 2
+                           && field[1].start < field[1].end
+                           && ismode_w(field[1].start, field[1].end, &permset)) {
+                               /* This is Solaris-style "other:rwx" */
+                       } else if (fields == 3
+                           && field[1].start == field[1].end
+                           && field[2].start < field[2].end
+                           && ismode_w(field[2].start, field[2].end, &permset)) {
+                               /* This is FreeBSD-style "other::rwx" */
+                       } else
+                               return (ARCHIVE_WARN);
+                       tag = ARCHIVE_ENTRY_ACL_OTHER;
+               } else if (prefix_w(field[0].start, field[0].end, L"mask")) {
+                       if (fields == 2
+                           && field[1].start < field[1].end
+                           && ismode_w(field[1].start, field[1].end, &permset)) {
+                               /* This is Solaris-style "mask:rwx" */
+                       } else if (fields == 3
+                           && field[1].start == field[1].end
+                           && field[2].start < field[2].end
+                           && ismode_w(field[2].start, field[2].end, &permset)) {
+                               /* This is FreeBSD-style "mask::rwx" */
+                       } else
+                               return (ARCHIVE_WARN);
+                       tag = ARCHIVE_ENTRY_ACL_MASK;
+               } else
+                       return (ARCHIVE_WARN);
+
+               /* Add entry to the internal list. */
+               archive_acl_add_entry_w_len(acl, type, permset,
+                   tag, id, name.start, name.end - name.start);
+       }
+       return (ARCHIVE_OK);
+}
+
+/*
+ * Parse a string to a positive decimal integer.  Returns true if
+ * the string is non-empty and consists only of decimal digits,
+ * false otherwise.
+ */
+static int
+isint_w(const wchar_t *start, const wchar_t *end, int *result)
+{
+       int n = 0;
+       if (start >= end)
+               return (0);
+       while (start < end) {
+               if (*start < '0' || *start > '9')
+                       return (0);
+               if (n > (INT_MAX / 10) ||
+                   (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) {
+                       n = INT_MAX;
+               } else {
+                       n *= 10;
+                       n += *start - '0';
+               }
+               start++;
+       }
+       *result = n;
+       return (1);
+}
+
+/*
+ * Parse a string as a mode field.  Returns true if
+ * the string is non-empty and consists only of mode characters,
+ * false otherwise.
+ */
+static int
+ismode_w(const wchar_t *start, const wchar_t *end, int *permset)
+{
+       const wchar_t *p;
+
+       if (start >= end)
+               return (0);
+       p = start;
+       *permset = 0;
+       while (p < end) {
+               switch (*p++) {
+               case 'r': case 'R':
+                       *permset |= ARCHIVE_ENTRY_ACL_READ;
+                       break;
+               case 'w': case 'W':
+                       *permset |= ARCHIVE_ENTRY_ACL_WRITE;
+                       break;
+               case 'x': case 'X':
+                       *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
+                       break;
+               case '-':
+                       break;
+               default:
+                       return (0);
+               }
+       }
+       return (1);
+}
+
+/*
+ * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]".  *wp is updated
+ * to point to just after the separator.  *start points to the first
+ * character of the matched text and *end just after the last
+ * character of the matched identifier.  In particular *end - *start
+ * is the length of the field body, not including leading or trailing
+ * whitespace.
+ */
+static void
+next_field_w(const wchar_t **wp, const wchar_t **start,
+    const wchar_t **end, wchar_t *sep)
+{
+       /* Skip leading whitespace to find start of field. */
+       while (**wp == L' ' || **wp == L'\t' || **wp == L'\n') {
+               (*wp)++;
+       }
+       *start = *wp;
+
+       /* Scan for the separator. */
+       while (**wp != L'\0' && **wp != L',' && **wp != L':' &&
+           **wp != L'\n') {
+               (*wp)++;
+       }
+       *sep = **wp;
+
+       /* Trim trailing whitespace to locate end of field. */
+       *end = *wp - 1;
+       while (**end == L' ' || **end == L'\t' || **end == L'\n') {
+               (*end)--;
+       }
+       (*end)++;
+
+       /* Adjust scanner location. */
+       if (**wp != L'\0')
+               (*wp)++;
+}
+
+/*
+ * Return true if the characters [start...end) are a prefix of 'test'.
+ * This makes it easy to handle the obvious abbreviations: 'u' for 'user', etc.
+ */
+static int
+prefix_w(const wchar_t *start, const wchar_t *end, const wchar_t *test)
+{
+       if (start == end)
+               return (0);
+
+       if (*start++ != *test++)
+               return (0);
+
+       while (start < end  &&  *start++ == *test++)
+               ;
+
+       if (start < end)
+               return (0);
+
+       return (1);
+}
+
+/*
+ * Parse a textual ACL.  This automatically recognizes and supports
+ * extensions described above.  The 'type' argument is used to
+ * indicate the type that should be used for any entries not
+ * explicitly marked as "default:".
+ */
+int
+archive_acl_parse_l(struct archive_acl *acl,
+    const char *text, int default_type, struct archive_string_conv *sc)
+{
+       struct {
+               const char *start;
+               const char *end;
+       } field[4], name;
+
+       int fields, n, r, ret = ARCHIVE_OK;
+       int type, tag, permset, id;
+       char sep;
+
+       while (text != NULL  &&  *text != '\0') {
+               /*
+                * Parse the fields out of the next entry,
+                * advance 'text' to start of next entry.
+                */
+               fields = 0;
+               do {
+                       const char *start, *end;
+                       next_field(&text, &start, &end, &sep);
+                       if (fields < 4) {
+                               field[fields].start = start;
+                               field[fields].end = end;
+                       }
+                       ++fields;
+               } while (sep == ':');
+
+               /* Set remaining fields to blank. */
+               for (n = fields; n < 4; ++n)
+                       field[n].start = field[n].end = NULL;
+
+               /* Check for a numeric ID in field 1 or 3. */
+               id = -1;
+               isint(field[1].start, field[1].end, &id);
+               /* Field 3 is optional. */
+               if (id == -1 && fields > 3)
+                       isint(field[3].start, field[3].end, &id);
+
+               /*
+                * Solaris extension:  "defaultuser::rwx" is the
+                * default ACL corresponding to "user::rwx", etc.
+                */
+               if (field[0].end - field[0].start > 7
+                   && memcmp(field[0].start, "default", 7) == 0) {
+                       type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
+                       field[0].start += 7;
+               } else
+                       type = default_type;
+
+               name.start = name.end = NULL;
+               if (prefix(field[0].start, field[0].end, "user")) {
+                       if (!ismode(field[2].start, field[2].end, &permset))
+                               return (ARCHIVE_WARN);
+                       if (id != -1 || field[1].start < field[1].end) {
+                               tag = ARCHIVE_ENTRY_ACL_USER;
+                               name = field[1];
+                       } else
+                               tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+               } else if (prefix(field[0].start, field[0].end, "group")) {
+                       if (!ismode(field[2].start, field[2].end, &permset))
+                               return (ARCHIVE_WARN);
+                       if (id != -1 || field[1].start < field[1].end) {
+                               tag = ARCHIVE_ENTRY_ACL_GROUP;
+                               name = field[1];
+                       } else
+                               tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+               } else if (prefix(field[0].start, field[0].end, "other")) {
+                       if (fields == 2
+                           && field[1].start < field[1].end
+                           && ismode(field[1].start, field[1].end, &permset)) {
+                               /* This is Solaris-style "other:rwx" */
+                       } else if (fields == 3
+                           && field[1].start == field[1].end
+                           && field[2].start < field[2].end
+                           && ismode(field[2].start, field[2].end, &permset)) {
+                               /* This is FreeBSD-style "other::rwx" */
+                       } else
+                               return (ARCHIVE_WARN);
+                       tag = ARCHIVE_ENTRY_ACL_OTHER;
+               } else if (prefix(field[0].start, field[0].end, "mask")) {
+                       if (fields == 2
+                           && field[1].start < field[1].end
+                           && ismode(field[1].start, field[1].end, &permset)) {
+                               /* This is Solaris-style "mask:rwx" */
+                       } else if (fields == 3
+                           && field[1].start == field[1].end
+                           && field[2].start < field[2].end
+                           && ismode(field[2].start, field[2].end, &permset)) {
+                               /* This is FreeBSD-style "mask::rwx" */
+                       } else
+                               return (ARCHIVE_WARN);
+                       tag = ARCHIVE_ENTRY_ACL_MASK;
+               } else
+                       return (ARCHIVE_WARN);
+
+               /* Add entry to the internal list. */
+               r = archive_acl_add_entry_len_l(acl, type, permset,
+                   tag, id, name.start, name.end - name.start, sc);
+               if (r < ARCHIVE_WARN)
+                       return (r);
+               if (r != ARCHIVE_OK)
+                       ret = ARCHIVE_WARN;
+       }
+       return (ret);
+}
+
+/*
+ * Parse a string to a positive decimal integer.  Returns true if
+ * the string is non-empty and consists only of decimal digits,
+ * false otherwise.
+ */
+static int
+isint(const char *start, const char *end, int *result)
+{
+       int n = 0;
+       if (start >= end)
+               return (0);
+       while (start < end) {
+               if (*start < '0' || *start > '9')
+                       return (0);
+               if (n > (INT_MAX / 10) ||
+                   (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) {
+                       n = INT_MAX;
+               } else {
+                       n *= 10;
+                       n += *start - '0';
+               }
+               start++;
+       }
+       *result = n;
+       return (1);
+}
+
+/*
+ * Parse a string as a mode field.  Returns true if
+ * the string is non-empty and consists only of mode characters,
+ * false otherwise.
+ */
+static int
+ismode(const char *start, const char *end, int *permset)
+{
+       const char *p;
+
+       if (start >= end)
+               return (0);
+       p = start;
+       *permset = 0;
+       while (p < end) {
+               switch (*p++) {
+               case 'r': case 'R':
+                       *permset |= ARCHIVE_ENTRY_ACL_READ;
+                       break;
+               case 'w': case 'W':
+                       *permset |= ARCHIVE_ENTRY_ACL_WRITE;
+                       break;
+               case 'x': case 'X':
+                       *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
+                       break;
+               case '-':
+                       break;
+               default:
+                       return (0);
+               }
+       }
+       return (1);
+}
+
+/*
+ * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]".  *wp is updated
+ * to point to just after the separator.  *start points to the first
+ * character of the matched text and *end just after the last
+ * character of the matched identifier.  In particular *end - *start
+ * is the length of the field body, not including leading or trailing
+ * whitespace.
+ */
+static void
+next_field(const char **p, const char **start,
+    const char **end, char *sep)
+{
+       /* Skip leading whitespace to find start of field. */
+       while (**p == ' ' || **p == '\t' || **p == '\n') {
+               (*p)++;
+       }
+       *start = *p;
+
+       /* Scan for the separator. */
+       while (**p != '\0' && **p != ',' && **p != ':' && **p != '\n') {
+               (*p)++;
+       }
+       *sep = **p;
+
+       /* Trim trailing whitespace to locate end of field. */
+       *end = *p - 1;
+       while (**end == ' ' || **end == '\t' || **end == '\n') {
+               (*end)--;
+       }
+       (*end)++;
+
+       /* Adjust scanner location. */
+       if (**p != '\0')
+               (*p)++;
+}
+
+/*
+ * Return true if the characters [start...end) are a prefix of 'test'.
+ * This makes it easy to handle the obvious abbreviations: 'u' for 'user', etc.
+ */
+static int
+prefix(const char *start, const char *end, const char *test)
+{
+       if (start == end)
+               return (0);
+
+       if (*start++ != *test++)
+               return (0);
+
+       while (start < end  &&  *start++ == *test++)
+               ;
+
+       if (start < end)
+               return (0);
+
+       return (1);
+}
diff --git a/contrib/libarchive/libarchive/archive_acl_private.h b/contrib/libarchive/libarchive/archive_acl_private.h
new file mode 100644 (file)
index 0000000..1421adb
--- /dev/null
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2003-2010 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_ACL_PRIVATE_H_INCLUDED
+#define        ARCHIVE_ACL_PRIVATE_H_INCLUDED
+
+#include "archive_string.h"
+
+struct archive_acl_entry {
+       struct archive_acl_entry *next;
+       int     type;                   /* E.g., access or default */
+       int     tag;                    /* E.g., user/group/other/mask */
+       int     permset;                /* r/w/x bits */
+       int     id;                     /* uid/gid for user/group */
+       struct archive_mstring name;            /* uname/gname */
+};
+
+struct archive_acl {
+       mode_t          mode;
+       struct archive_acl_entry        *acl_head;
+       struct archive_acl_entry        *acl_p;
+       int              acl_state;     /* See acl_next for details. */
+       wchar_t         *acl_text_w;
+       char            *acl_text;
+       int              acl_types;
+};
+
+void archive_acl_clear(struct archive_acl *);
+void archive_acl_copy(struct archive_acl *, struct archive_acl *);
+int archive_acl_count(struct archive_acl *, int);
+int archive_acl_reset(struct archive_acl *, int);
+int archive_acl_next(struct archive *, struct archive_acl *, int,
+    int *, int *, int *, int *, const char **);
+
+int archive_acl_add_entry(struct archive_acl *, int, int, int, int, const char *);
+int archive_acl_add_entry_w_len(struct archive_acl *,
+    int, int, int, int, const wchar_t *, size_t);
+int archive_acl_add_entry_len(struct archive_acl *,
+    int, int, int, int, const char *, size_t);
+
+const wchar_t *archive_acl_text_w(struct archive *, struct archive_acl *, int);
+int archive_acl_text_l(struct archive_acl *, int, const char **, size_t *,
+    struct archive_string_conv *);
+
+/*
+ * Private ACL parser.  This is private because it handles some
+ * very weird formats that clients should not be messing with.
+ * Clients should only deal with their platform-native formats.
+ * Because of the need to support many formats cleanly, new arguments
+ * are likely to get added on a regular basis.  Clients who try to use
+ * this interface are likely to be surprised when it changes.
+ */
+int archive_acl_parse_w(struct archive_acl *,
+                   const wchar_t *, int /* type */);
+int archive_acl_parse_l(struct archive_acl *,
+                   const char *, int /* type */,
+                   struct archive_string_conv *);
+
+#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */
index e27e5d8..9122955 100644 (file)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2003-2010 Tim Kientzle
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -86,49 +86,89 @@ state_name(unsigned s)
        }
 }
 
+static const char *
+archive_handle_type_name(unsigned m)
+{
+       switch (m) {
+       case ARCHIVE_WRITE_MAGIC:       return ("archive_write");
+       case ARCHIVE_READ_MAGIC:        return ("archive_read");
+       case ARCHIVE_WRITE_DISK_MAGIC:  return ("archive_write_disk");
+       case ARCHIVE_READ_DISK_MAGIC:   return ("archive_read_disk");
+       default:                        return NULL;
+       }
+}
 
-static void
-write_all_states(unsigned int states)
+
+static char *
+write_all_states(char *buff, unsigned int states)
 {
        unsigned int lowbit;
 
+       buff[0] = '\0';
+
        /* A trick for computing the lowest set bit. */
        while ((lowbit = states & (1 + ~states)) != 0) {
                states &= ~lowbit;              /* Clear the low bit. */
-               errmsg(state_name(lowbit));
+               strcat(buff, state_name(lowbit));
                if (states != 0)
-                       errmsg("/");
+                       strcat(buff, "/");
        }
+       return buff;
 }
 
 /*
- * Check magic value and current state; bail if it isn't valid.
+ * Check magic value and current state.
+ *   Magic value mismatches are fatal and result in calls to abort().
+ *   State mismatches return ARCHIVE_FATAL.
+ *   Otherwise, returns ARCHIVE_OK.
  *
  * This is designed to catch serious programming errors that violate
  * the libarchive API.
  */
-void
+int
 __archive_check_magic(struct archive *a, unsigned int magic,
     unsigned int state, const char *function)
 {
-       if (a->magic != magic) {
-               errmsg("INTERNAL ERROR: Function ");
+       char states1[64];
+       char states2[64];
+       const char *handle_type;
+
+       /*
+        * If this isn't some form of archive handle,
+        * then the library user has screwed up so bad that
+        * we don't even have a reliable way to report an error.
+        */
+       handle_type = archive_handle_type_name(a->magic);
+
+       if (!handle_type) {
+               errmsg("PROGRAMMER ERROR: Function ");
                errmsg(function);
-               errmsg(" invoked with invalid struct archive structure.\n");
+               errmsg(" invoked with invalid archive handle.\n");
                diediedie();
        }
 
-       if (state == ARCHIVE_STATE_ANY)
-               return;
+       if (a->magic != magic) {
+               archive_set_error(a, -1,
+                   "PROGRAMMER ERROR: Function '%s' invoked"
+                   " on '%s' archive object, which is not supported.",
+                   function,
+                   handle_type);
+               a->state = ARCHIVE_STATE_FATAL;
+               return (ARCHIVE_FATAL);
+       }
 
        if ((a->state & state) == 0) {
-               errmsg("INTERNAL ERROR: Function '");
-               errmsg(function);
-               errmsg("' invoked with archive structure in state '");
-               write_all_states(a->state);
-               errmsg("', should be in state '");
-               write_all_states(state);
-               errmsg("'\n");
-               diediedie();
+               /* If we're already FATAL, don't overwrite the error. */
+               if (a->state != ARCHIVE_STATE_FATAL)
+                       archive_set_error(a, -1,
+                           "INTERNAL ERROR: Function '%s' invoked with"
+                           " archive structure in state '%s',"
+                           " should be in state '%s'",
+                           function,
+                           write_all_states(states1, a->state),
+                           write_all_states(states2, state));
+               a->state = ARCHIVE_STATE_FATAL;
+               return (ARCHIVE_FATAL);
        }
+       return ARCHIVE_OK;
 }
diff --git a/contrib/libarchive/libarchive/archive_crypto.c b/contrib/libarchive/libarchive/archive_crypto.c
new file mode 100644 (file)
index 0000000..2caf571
--- /dev/null
@@ -0,0 +1,1427 @@
+/*-
+* Copyright (c) 2003-2007 Tim Kientzle
+* Copyright (c) 2011 Andres Mejia
+* Copyright (c) 2011 Michihiro NAKAJIMA
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "archive_platform.h"
+
+#include "archive.h"
+#include "archive_crypto_private.h"
+
+/* In particular, force the configure probe to break if it tries
+ * to test a combination of OpenSSL and libmd. */
+#if defined(ARCHIVE_CRYPTO_OPENSSL) && defined(ARCHIVE_CRYPTO_LIBMD)
+#error Cannot use both OpenSSL and libmd.
+#endif
+
+/*
+ * Message digest functions for Windows platform.
+ */
+#if defined(ARCHIVE_CRYPTO_MD5_WIN)    ||\
+       defined(ARCHIVE_CRYPTO_SHA1_WIN)   ||\
+       defined(ARCHIVE_CRYPTO_SHA256_WIN) ||\
+       defined(ARCHIVE_CRYPTO_SHA384_WIN) ||\
+       defined(ARCHIVE_CRYPTO_SHA512_WIN)
+
+/*
+ * Initialize a Message digest.
+ */
+static int
+win_crypto_init(Digest_CTX *ctx, ALG_ID algId)
+{
+
+       ctx->valid = 0;
+       if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,
+           PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
+               if (GetLastError() != (DWORD)NTE_BAD_KEYSET)
+                       return (ARCHIVE_FAILED);
+               if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,
+                   PROV_RSA_FULL, CRYPT_NEWKEYSET))
+                       return (ARCHIVE_FAILED);
+       }
+
+       if (!CryptCreateHash(ctx->cryptProv, algId, 0, 0, &ctx->hash)) {
+               CryptReleaseContext(ctx->cryptProv, 0);
+               return (ARCHIVE_FAILED);
+       }
+
+       ctx->valid = 1;
+       return (ARCHIVE_OK);
+}
+
+/*
+ * Update a Message digest.
+ */
+static int
+win_crypto_Update(Digest_CTX *ctx, const unsigned char *buf, size_t len)
+{
+
+       if (!ctx->valid)
+               return (ARCHIVE_FAILED);
+
+       CryptHashData(ctx->hash,
+                     (unsigned char *)(uintptr_t)buf,
+                     (DWORD)len, 0);
+       return (ARCHIVE_OK);
+}
+
+static int
+win_crypto_Final(unsigned char *buf, size_t bufsize, Digest_CTX *ctx)
+{
+       DWORD siglen = bufsize;
+
+       if (!ctx->valid)
+               return (ARCHIVE_FAILED);
+
+       CryptGetHashParam(ctx->hash, HP_HASHVAL, buf, &siglen, 0);
+       CryptDestroyHash(ctx->hash);
+       CryptReleaseContext(ctx->cryptProv, 0);
+       ctx->valid = 0;
+       return (ARCHIVE_OK);
+}
+
+#endif /* defined(ARCHIVE_CRYPTO_*_WIN) */
+
+
+/* MD5 implementations */
+#if defined(ARCHIVE_CRYPTO_MD5_LIBC)
+
+static int
+__archive_libc_md5init(archive_md5_ctx *ctx)
+{
+  MD5Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_md5update(archive_md5_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  MD5Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_md5final(archive_md5_ctx *ctx, void *md)
+{
+  MD5Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_MD5_LIBMD)
+
+static int
+__archive_libmd_md5init(archive_md5_ctx *ctx)
+{
+  MD5Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_md5update(archive_md5_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  MD5Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_md5final(archive_md5_ctx *ctx, void *md)
+{
+  MD5Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM)
+
+static int
+__archive_libsystem_md5init(archive_md5_ctx *ctx)
+{
+  CC_MD5_Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_md5update(archive_md5_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  CC_MD5_Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_md5final(archive_md5_ctx *ctx, void *md)
+{
+  CC_MD5_Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_MD5_NETTLE)
+
+static int
+__archive_nettle_md5init(archive_md5_ctx *ctx)
+{
+  md5_init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_md5update(archive_md5_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  md5_update(ctx, insize, indata);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_md5final(archive_md5_ctx *ctx, void *md)
+{
+  md5_digest(ctx, MD5_DIGEST_SIZE, md);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_MD5_OPENSSL)
+
+static int
+__archive_openssl_md5init(archive_md5_ctx *ctx)
+{
+  EVP_DigestInit(ctx, EVP_md5());
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_md5update(archive_md5_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  EVP_DigestUpdate(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_md5final(archive_md5_ctx *ctx, void *md)
+{
+  /* HACK: archive_write_set_format_xar.c is finalizing empty contexts, so
+   * this is meant to cope with that. Real fix is probably to fix
+   * archive_write_set_format_xar.c
+   */
+  if (ctx->digest)
+    EVP_DigestFinal(ctx, md, NULL);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
+
+static int
+__archive_windowsapi_md5init(archive_md5_ctx *ctx)
+{
+  return (win_crypto_init(ctx, CALG_MD5));
+}
+
+static int
+__archive_windowsapi_md5update(archive_md5_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  return (win_crypto_Update(ctx, indata, insize));
+}
+
+static int
+__archive_windowsapi_md5final(archive_md5_ctx *ctx, void *md)
+{
+  return (win_crypto_Final(md, 16, ctx));
+}
+
+#else
+
+static int
+__archive_stub_md5init(archive_md5_ctx *ctx)
+{
+       (void)ctx; /* UNUSED */
+       return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_md5update(archive_md5_ctx *ctx, const void *indata,
+    size_t insize)
+{
+       (void)ctx; /* UNUSED */
+       (void)indata; /* UNUSED */
+       (void)insize; /* UNUSED */
+       return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_md5final(archive_md5_ctx *ctx, void *md)
+{
+       (void)ctx; /* UNUSED */
+       (void)md; /* UNUSED */
+       return (ARCHIVE_FAILED);
+}
+
+#endif
+
+/* RIPEMD160 implementations */
+#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)
+
+static int
+__archive_libc_ripemd160init(archive_rmd160_ctx *ctx)
+{
+  RMD160Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  RMD160Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+{
+  RMD160Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
+
+static int
+__archive_libmd_ripemd160init(archive_rmd160_ctx *ctx)
+{
+  RIPEMD160_Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  RIPEMD160_Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+{
+  RIPEMD160_Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
+
+static int
+__archive_nettle_ripemd160init(archive_rmd160_ctx *ctx)
+{
+  ripemd160_init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  ripemd160_update(ctx, insize, indata);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+{
+  ripemd160_digest(ctx, RIPEMD160_DIGEST_SIZE, md);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
+
+static int
+__archive_openssl_ripemd160init(archive_rmd160_ctx *ctx)
+{
+  EVP_DigestInit(ctx, EVP_ripemd160());
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  EVP_DigestUpdate(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+{
+  EVP_DigestFinal(ctx, md, NULL);
+  return (ARCHIVE_OK);
+}
+
+#else
+
+static int
+__archive_stub_ripemd160init(archive_rmd160_ctx *ctx)
+{
+       (void)ctx; /* UNUSED */
+       return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+    size_t insize)
+{
+       (void)ctx; /* UNUSED */
+       (void)indata; /* UNUSED */
+       (void)insize; /* UNUSED */
+       return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+{
+       (void)ctx; /* UNUSED */
+       (void)md; /* UNUSED */
+       return (ARCHIVE_FAILED);
+}
+
+#endif
+
+/* SHA1 implementations */
+#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)
+
+static int
+__archive_libc_sha1init(archive_sha1_ctx *ctx)
+{
+  SHA1Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha1update(archive_sha1_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  SHA1Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha1final(archive_sha1_ctx *ctx, void *md)
+{
+  SHA1Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA1_LIBMD)
+
+static int
+__archive_libmd_sha1init(archive_sha1_ctx *ctx)
+{
+  SHA1_Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_sha1update(archive_sha1_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  SHA1_Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_sha1final(archive_sha1_ctx *ctx, void *md)
+{
+  SHA1_Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM)
+
+static int
+__archive_libsystem_sha1init(archive_sha1_ctx *ctx)
+{
+  CC_SHA1_Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha1update(archive_sha1_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  CC_SHA1_Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha1final(archive_sha1_ctx *ctx, void *md)
+{
+  CC_SHA1_Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA1_NETTLE)
+
+static int
+__archive_nettle_sha1init(archive_sha1_ctx *ctx)
+{
+  sha1_init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha1update(archive_sha1_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  sha1_update(ctx, insize, indata);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha1final(archive_sha1_ctx *ctx, void *md)
+{
+  sha1_digest(ctx, SHA1_DIGEST_SIZE, md);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA1_OPENSSL)
+
+static int
+__archive_openssl_sha1init(archive_sha1_ctx *ctx)
+{
+  EVP_DigestInit(ctx, EVP_sha1());
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha1update(archive_sha1_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  EVP_DigestUpdate(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha1final(archive_sha1_ctx *ctx, void *md)
+{
+  /* HACK: archive_write_set_format_xar.c is finalizing empty contexts, so
+   * this is meant to cope with that. Real fix is probably to fix
+   * archive_write_set_format_xar.c
+   */
+  if (ctx->digest)
+    EVP_DigestFinal(ctx, md, NULL);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
+
+static int
+__archive_windowsapi_sha1init(archive_sha1_ctx *ctx)
+{
+  return (win_crypto_init(ctx, CALG_SHA1));
+}
+
+static int
+__archive_windowsapi_sha1update(archive_sha1_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  return (win_crypto_Update(ctx, indata, insize));
+}
+
+static int
+__archive_windowsapi_sha1final(archive_sha1_ctx *ctx, void *md)
+{
+  return (win_crypto_Final(md, 20, ctx));
+}
+
+#else
+
+static int
+__archive_stub_sha1init(archive_sha1_ctx *ctx)
+{
+       (void)ctx; /* UNUSED */
+       return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha1update(archive_sha1_ctx *ctx, const void *indata,
+    size_t insize)
+{
+       (void)ctx; /* UNUSED */
+       (void)indata; /* UNUSED */
+       (void)insize; /* UNUSED */
+       return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha1final(archive_sha1_ctx *ctx, void *md)
+{
+       (void)ctx; /* UNUSED */
+       (void)md; /* UNUSED */
+       return (ARCHIVE_FAILED);
+}
+
+#endif
+
+/* SHA256 implementations */
+#if defined(ARCHIVE_CRYPTO_SHA256_LIBC)
+
+static int
+__archive_libc_sha256init(archive_sha256_ctx *ctx)
+{
+  SHA256_Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha256update(archive_sha256_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  SHA256_Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+  SHA256_Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC2)
+
+static int
+__archive_libc2_sha256init(archive_sha256_ctx *ctx)
+{
+  SHA256Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc2_sha256update(archive_sha256_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  SHA256Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc2_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+  SHA256Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC3)
+
+static int
+__archive_libc3_sha256init(archive_sha256_ctx *ctx)
+{
+  SHA256Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc3_sha256update(archive_sha256_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  SHA256Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc3_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+  SHA256Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBMD)
+
+static int
+__archive_libmd_sha256init(archive_sha256_ctx *ctx)
+{
+  SHA256_Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_sha256update(archive_sha256_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  SHA256_Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+  SHA256_Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM)
+
+static int
+__archive_libsystem_sha256init(archive_sha256_ctx *ctx)
+{
+  CC_SHA256_Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha256update(archive_sha256_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  CC_SHA256_Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+  CC_SHA256_Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA256_NETTLE)
+
+static int
+__archive_nettle_sha256init(archive_sha256_ctx *ctx)
+{
+  sha256_init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha256update(archive_sha256_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  sha256_update(ctx, insize, indata);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+  sha256_digest(ctx, SHA256_DIGEST_SIZE, md);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA256_OPENSSL)
+
+static int
+__archive_openssl_sha256init(archive_sha256_ctx *ctx)
+{
+  EVP_DigestInit(ctx, EVP_sha256());
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha256update(archive_sha256_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  EVP_DigestUpdate(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+  EVP_DigestFinal(ctx, md, NULL);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
+
+static int
+__archive_windowsapi_sha256init(archive_sha256_ctx *ctx)
+{
+  return (win_crypto_init(ctx, CALG_SHA_256));
+}
+
+static int
+__archive_windowsapi_sha256update(archive_sha256_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  return (win_crypto_Update(ctx, indata, insize));
+}
+
+static int
+__archive_windowsapi_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+  return (win_crypto_Final(md, 32, ctx));
+}
+
+#else
+
+static int
+__archive_stub_sha256init(archive_sha256_ctx *ctx)
+{
+       (void)ctx; /* UNUSED */
+       return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha256update(archive_sha256_ctx *ctx, const void *indata,
+    size_t insize)
+{
+       (void)ctx; /* UNUSED */
+       (void)indata; /* UNUSED */
+       (void)insize; /* UNUSED */
+       return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+       (void)ctx; /* UNUSED */
+       (void)md; /* UNUSED */
+       return (ARCHIVE_FAILED);
+}
+
+#endif
+
+/* SHA384 implementations */
+#if defined(ARCHIVE_CRYPTO_SHA384_LIBC)
+
+static int
+__archive_libc_sha384init(archive_sha384_ctx *ctx)
+{
+  SHA384_Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha384update(archive_sha384_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  SHA384_Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+  SHA384_Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC2)
+
+static int
+__archive_libc2_sha384init(archive_sha384_ctx *ctx)
+{
+  SHA384Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc2_sha384update(archive_sha384_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  SHA384Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc2_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+  SHA384Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC3)
+
+static int
+__archive_libc3_sha384init(archive_sha384_ctx *ctx)
+{
+  SHA384Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc3_sha384update(archive_sha384_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  SHA384Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc3_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+  SHA384Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM)
+
+static int
+__archive_libsystem_sha384init(archive_sha384_ctx *ctx)
+{
+  CC_SHA384_Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha384update(archive_sha384_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  CC_SHA384_Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+  CC_SHA384_Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA384_NETTLE)
+
+static int
+__archive_nettle_sha384init(archive_sha384_ctx *ctx)
+{
+  sha384_init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha384update(archive_sha384_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  sha384_update(ctx, insize, indata);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+  sha384_digest(ctx, SHA384_DIGEST_SIZE, md);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA384_OPENSSL)
+
+static int
+__archive_openssl_sha384init(archive_sha384_ctx *ctx)
+{
+  EVP_DigestInit(ctx, EVP_sha384());
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha384update(archive_sha384_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  EVP_DigestUpdate(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+  EVP_DigestFinal(ctx, md, NULL);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
+
+static int
+__archive_windowsapi_sha384init(archive_sha384_ctx *ctx)
+{
+  return (win_crypto_init(ctx, CALG_SHA_384));
+}
+
+static int
+__archive_windowsapi_sha384update(archive_sha384_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  return (win_crypto_Update(ctx, indata, insize));
+}
+
+static int
+__archive_windowsapi_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+  return (win_crypto_Final(md, 48, ctx));
+}
+
+#else
+
+static int
+__archive_stub_sha384init(archive_sha384_ctx *ctx)
+{
+       (void)ctx; /* UNUSED */
+       return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha384update(archive_sha384_ctx *ctx, const void *indata,
+    size_t insize)
+{
+       (void)ctx; /* UNUSED */
+       (void)indata; /* UNUSED */
+       (void)insize; /* UNUSED */
+       return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+       (void)ctx; /* UNUSED */
+       (void)md; /* UNUSED */
+       return (ARCHIVE_FAILED);
+}
+
+#endif
+
+/* SHA512 implementations */
+#if defined(ARCHIVE_CRYPTO_SHA512_LIBC)
+
+static int
+__archive_libc_sha512init(archive_sha512_ctx *ctx)
+{
+  SHA512_Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha512update(archive_sha512_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  SHA512_Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+  SHA512_Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC2)
+
+static int
+__archive_libc2_sha512init(archive_sha512_ctx *ctx)
+{
+  SHA512Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc2_sha512update(archive_sha512_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  SHA512Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc2_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+  SHA512Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC3)
+
+static int
+__archive_libc3_sha512init(archive_sha512_ctx *ctx)
+{
+  SHA512Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc3_sha512update(archive_sha512_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  SHA512Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc3_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+  SHA512Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
+
+static int
+__archive_libmd_sha512init(archive_sha512_ctx *ctx)
+{
+  SHA512_Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_sha512update(archive_sha512_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  SHA512_Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+  SHA512_Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
+
+static int
+__archive_libsystem_sha512init(archive_sha512_ctx *ctx)
+{
+  CC_SHA512_Init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha512update(archive_sha512_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  CC_SHA512_Update(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+  CC_SHA512_Final(md, ctx);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
+
+static int
+__archive_nettle_sha512init(archive_sha512_ctx *ctx)
+{
+  sha512_init(ctx);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha512update(archive_sha512_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  sha512_update(ctx, insize, indata);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+  sha512_digest(ctx, SHA512_DIGEST_SIZE, md);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
+
+static int
+__archive_openssl_sha512init(archive_sha512_ctx *ctx)
+{
+  EVP_DigestInit(ctx, EVP_sha512());
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha512update(archive_sha512_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  EVP_DigestUpdate(ctx, indata, insize);
+  return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+  EVP_DigestFinal(ctx, md, NULL);
+  return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
+
+static int
+__archive_windowsapi_sha512init(archive_sha512_ctx *ctx)
+{
+  return (win_crypto_init(ctx, CALG_SHA_512));
+}
+
+static int
+__archive_windowsapi_sha512update(archive_sha512_ctx *ctx, const void *indata,
+    size_t insize)
+{
+  return (win_crypto_Update(ctx, indata, insize));
+}
+
+static int
+__archive_windowsapi_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+  return (win_crypto_Final(md, 64, ctx));
+}
+
+#else
+
+static int
+__archive_stub_sha512init(archive_sha512_ctx *ctx)
+{
+       (void)ctx; /* UNUSED */
+       return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha512update(archive_sha512_ctx *ctx, const void *indata,
+    size_t insize)
+{
+       (void)ctx; /* UNUSED */
+       (void)indata; /* UNUSED */
+       (void)insize; /* UNUSED */
+       return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+       (void)ctx; /* UNUSED */
+       (void)md; /* UNUSED */
+       return (ARCHIVE_FAILED);
+}
+
+#endif
+
+/* NOTE: Crypto functions are set based on availability and by the following
+ * order of preference.
+ * 1. libc
+ * 2. libc2
+ * 3. libc3
+ * 4. libSystem
+ * 5. OpenSSL
+ * 6. Windows API
+ */
+const struct archive_crypto __archive_crypto =
+{
+/* MD5 */
+#if defined(ARCHIVE_CRYPTO_MD5_LIBC)
+  &__archive_libc_md5init,
+  &__archive_libc_md5update,
+  &__archive_libc_md5final,
+#elif defined(ARCHIVE_CRYPTO_MD5_LIBMD)
+  &__archive_libmd_md5init,
+  &__archive_libmd_md5update,
+  &__archive_libmd_md5final,
+#elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM)
+  &__archive_libsystem_md5init,
+  &__archive_libsystem_md5update,
+  &__archive_libsystem_md5final,
+#elif defined(ARCHIVE_CRYPTO_MD5_NETTLE)
+  &__archive_nettle_md5init,
+  &__archive_nettle_md5update,
+  &__archive_nettle_md5final,
+#elif defined(ARCHIVE_CRYPTO_MD5_OPENSSL)
+  &__archive_openssl_md5init,
+  &__archive_openssl_md5update,
+  &__archive_openssl_md5final,
+#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
+  &__archive_windowsapi_md5init,
+  &__archive_windowsapi_md5update,
+  &__archive_windowsapi_md5final,
+#elif !defined(ARCHIVE_MD5_COMPILE_TEST)
+  &__archive_stub_md5init,
+  &__archive_stub_md5update,
+  &__archive_stub_md5final,
+#endif
+
+/* RIPEMD160 */
+#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)
+  &__archive_libc_ripemd160init,
+  &__archive_libc_ripemd160update,
+  &__archive_libc_ripemd160final,
+#elif defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
+  &__archive_libmd_ripemd160init,
+  &__archive_libmd_ripemd160update,
+  &__archive_libmd_ripemd160final,
+#elif defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
+  &__archive_nettle_ripemd160init,
+  &__archive_nettle_ripemd160update,
+  &__archive_nettle_ripemd160final,
+#elif defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
+  &__archive_openssl_ripemd160init,
+  &__archive_openssl_ripemd160update,
+  &__archive_openssl_ripemd160final,
+#elif !defined(ARCHIVE_RMD160_COMPILE_TEST)
+  &__archive_stub_ripemd160init,
+  &__archive_stub_ripemd160update,
+  &__archive_stub_ripemd160final,
+#endif
+
+/* SHA1 */
+#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)
+  &__archive_libc_sha1init,
+  &__archive_libc_sha1update,
+  &__archive_libc_sha1final,
+#elif defined(ARCHIVE_CRYPTO_SHA1_LIBMD)
+  &__archive_libmd_sha1init,
+  &__archive_libmd_sha1update,
+  &__archive_libmd_sha1final,
+#elif defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM)
+  &__archive_libsystem_sha1init,
+  &__archive_libsystem_sha1update,
+  &__archive_libsystem_sha1final,
+#elif defined(ARCHIVE_CRYPTO_SHA1_NETTLE)
+  &__archive_nettle_sha1init,
+  &__archive_nettle_sha1update,
+  &__archive_nettle_sha1final,
+#elif defined(ARCHIVE_CRYPTO_SHA1_OPENSSL)
+  &__archive_openssl_sha1init,
+  &__archive_openssl_sha1update,
+  &__archive_openssl_sha1final,
+#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
+  &__archive_windowsapi_sha1init,
+  &__archive_windowsapi_sha1update,
+  &__archive_windowsapi_sha1final,
+#elif !defined(ARCHIVE_SHA1_COMPILE_TEST)
+  &__archive_stub_sha1init,
+  &__archive_stub_sha1update,
+  &__archive_stub_sha1final,
+#endif
+
+/* SHA256 */
+#if defined(ARCHIVE_CRYPTO_SHA256_LIBC)
+  &__archive_libc_sha256init,
+  &__archive_libc_sha256update,
+  &__archive_libc_sha256final,
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC2)
+  &__archive_libc2_sha256init,
+  &__archive_libc2_sha256update,
+  &__archive_libc2_sha256final,
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC3)
+  &__archive_libc3_sha256init,
+  &__archive_libc3_sha256update,
+  &__archive_libc3_sha256final,
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBMD)
+  &__archive_libmd_sha256init,
+  &__archive_libmd_sha256update,
+  &__archive_libmd_sha256final,
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM)
+  &__archive_libsystem_sha256init,
+  &__archive_libsystem_sha256update,
+  &__archive_libsystem_sha256final,
+#elif defined(ARCHIVE_CRYPTO_SHA256_NETTLE)
+  &__archive_nettle_sha256init,
+  &__archive_nettle_sha256update,
+  &__archive_nettle_sha256final,
+#elif defined(ARCHIVE_CRYPTO_SHA256_OPENSSL)
+  &__archive_openssl_sha256init,
+  &__archive_openssl_sha256update,
+  &__archive_openssl_sha256final,
+#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
+  &__archive_windowsapi_sha256init,
+  &__archive_windowsapi_sha256update,
+  &__archive_windowsapi_sha256final,
+#elif !defined(ARCHIVE_SHA256_COMPILE_TEST)
+  &__archive_stub_sha256init,
+  &__archive_stub_sha256update,
+  &__archive_stub_sha256final,
+#endif
+
+/* SHA384 */
+#if defined(ARCHIVE_CRYPTO_SHA384_LIBC)
+  &__archive_libc_sha384init,
+  &__archive_libc_sha384update,
+  &__archive_libc_sha384final,
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC2)
+  &__archive_libc2_sha384init,
+  &__archive_libc2_sha384update,
+  &__archive_libc2_sha384final,
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC3)
+  &__archive_libc3_sha384init,
+  &__archive_libc3_sha384update,
+  &__archive_libc3_sha384final,
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM)
+  &__archive_libsystem_sha384init,
+  &__archive_libsystem_sha384update,
+  &__archive_libsystem_sha384final,
+#elif defined(ARCHIVE_CRYPTO_SHA384_NETTLE)
+  &__archive_nettle_sha384init,
+  &__archive_nettle_sha384update,
+  &__archive_nettle_sha384final,
+#elif defined(ARCHIVE_CRYPTO_SHA384_OPENSSL)
+  &__archive_openssl_sha384init,
+  &__archive_openssl_sha384update,
+  &__archive_openssl_sha384final,
+#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
+  &__archive_windowsapi_sha384init,
+  &__archive_windowsapi_sha384update,
+  &__archive_windowsapi_sha384final,
+#elif !defined(ARCHIVE_SHA384_COMPILE_TEST)
+  &__archive_stub_sha384init,
+  &__archive_stub_sha384update,
+  &__archive_stub_sha384final,
+#endif
+
+/* SHA512 */
+#if defined(ARCHIVE_CRYPTO_SHA512_LIBC)
+  &__archive_libc_sha512init,
+  &__archive_libc_sha512update,
+  &__archive_libc_sha512final
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC2)
+  &__archive_libc2_sha512init,
+  &__archive_libc2_sha512update,
+  &__archive_libc2_sha512final
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC3)
+  &__archive_libc3_sha512init,
+  &__archive_libc3_sha512update,
+  &__archive_libc3_sha512final
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
+  &__archive_libmd_sha512init,
+  &__archive_libmd_sha512update,
+  &__archive_libmd_sha512final
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
+  &__archive_libsystem_sha512init,
+  &__archive_libsystem_sha512update,
+  &__archive_libsystem_sha512final
+#elif defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
+  &__archive_nettle_sha512init,
+  &__archive_nettle_sha512update,
+  &__archive_nettle_sha512final,
+#elif defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
+  &__archive_openssl_sha512init,
+  &__archive_openssl_sha512update,
+  &__archive_openssl_sha512final
+#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
+  &__archive_windowsapi_sha512init,
+  &__archive_windowsapi_sha512update,
+  &__archive_windowsapi_sha512final
+#elif !defined(ARCHIVE_SHA512_COMPILE_TEST)
+  &__archive_stub_sha512init,
+  &__archive_stub_sha512update,
+  &__archive_stub_sha512final
+#endif
+};
diff --git a/contrib/libarchive/libarchive/archive_crypto_private.h b/contrib/libarchive/libarchive/archive_crypto_private.h
new file mode 100644 (file)
index 0000000..f8b1fb3
--- /dev/null
@@ -0,0 +1,376 @@
+/*-
+* Copyright (c) 2003-2007 Tim Kientzle
+* Copyright (c) 2011 Andres Mejia
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_CRYPTO_PRIVATE_H_INCLUDED
+#define ARCHIVE_CRYPTO_PRIVATE_H_INCLUDED
+
+/*
+ * Crypto support in various Operating Systems:
+ *
+ * NetBSD:
+ * - MD5 and SHA1 in libc: without _ after algorithm name
+ * - SHA2 in libc: with _ after algorithm name
+ *
+ * OpenBSD:
+ * - MD5, SHA1 and SHA2 in libc: without _ after algorithm name
+ * - OpenBSD 4.4 and earlier have SHA2 in libc with _ after algorithm name
+ *
+ * DragonFly and FreeBSD:
+ * - MD5 libmd: without _ after algorithm name
+ * - SHA1, SHA256 and SHA512 in libmd: with _ after algorithm name
+ *
+ * Mac OS X (10.4 and later):
+ * - MD5, SHA1 and SHA2 in libSystem: with CC_ prefix and _ after algorithm name
+ *
+ * OpenSSL:
+ * - MD5, SHA1 and SHA2 in libcrypto: with _ after algorithm name
+ *
+ * Windows:
+ * - MD5, SHA1 and SHA2 in archive_crypto.c using Windows crypto API
+ */
+
+/* libc crypto headers */
+#if defined(ARCHIVE_CRYPTO_MD5_LIBC)
+#include <md5.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)
+#include <rmd160.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)
+#include <sha1.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_SHA256_LIBC) ||\
+  defined(ARCHIVE_CRYPTO_SHA256_LIBC2) ||\
+  defined(ARCHIVE_CRYPTO_SHA256_LIBC3) ||\
+  defined(ARCHIVE_CRYPTO_SHA384_LIBC) ||\
+  defined(ARCHIVE_CRYPTO_SHA384_LIBC2) ||\
+  defined(ARCHIVE_CRYPTO_SHA384_LIBC3) ||\
+  defined(ARCHIVE_CRYPTO_SHA512_LIBC) ||\
+  defined(ARCHIVE_CRYPTO_SHA512_LIBC2) ||\
+  defined(ARCHIVE_CRYPTO_SHA512_LIBC3)
+#include <sha2.h>
+#endif
+
+/* libmd crypto headers */
+#if defined(ARCHIVE_CRYPTO_MD5_LIBMD) ||\
+  defined(ARCHIVE_CRYPTO_RMD160_LIBMD) ||\
+  defined(ARCHIVE_CRYPTO_SHA1_LIBMD) ||\
+  defined(ARCHIVE_CRYPTO_SHA256_LIBMD) ||\
+  defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
+#define        ARCHIVE_CRYPTO_LIBMD 1
+#endif
+
+#if defined(ARCHIVE_CRYPTO_MD5_LIBMD)
+#include <md5.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
+#include <ripemd.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_SHA1_LIBMD)
+#include <sha.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_SHA256_LIBMD)
+#include <sha256.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
+#include <sha512.h>
+#endif
+
+/* libSystem crypto headers */
+#if defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM) ||\
+  defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM) ||\
+  defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM) ||\
+  defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM) ||\
+  defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
+#include <CommonCrypto/CommonDigest.h>
+#endif
+
+/* Nettle crypto headers */
+#if defined(ARCHIVE_CRYPTO_MD5_NETTLE)
+#include <nettle/md5.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
+#include <nettle/ripemd160.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_SHA1_NETTLE) ||\
+  defined(ARCHIVE_CRYPTO_SHA256_NETTLE) ||\
+  defined(ARCHIVE_CRYPTO_SHA384_NETTLE) ||\
+  defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
+#include <nettle/sha.h>
+#endif
+
+/* OpenSSL crypto headers */
+#if defined(ARCHIVE_CRYPTO_MD5_OPENSSL) ||\
+  defined(ARCHIVE_CRYPTO_RMD160_OPENSSL) ||\
+  defined(ARCHIVE_CRYPTO_SHA1_OPENSSL) ||\
+  defined(ARCHIVE_CRYPTO_SHA256_OPENSSL) ||\
+  defined(ARCHIVE_CRYPTO_SHA384_OPENSSL) ||\
+  defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
+#define        ARCHIVE_CRYPTO_OPENSSL 1
+#include <openssl/evp.h>
+#endif
+
+/* Windows crypto headers */
+#if defined(ARCHIVE_CRYPTO_MD5_WIN)    ||\
+  defined(ARCHIVE_CRYPTO_SHA1_WIN)   ||\
+  defined(ARCHIVE_CRYPTO_SHA256_WIN) ||\
+  defined(ARCHIVE_CRYPTO_SHA384_WIN) ||\
+  defined(ARCHIVE_CRYPTO_SHA512_WIN)
+#include <wincrypt.h>
+typedef struct {
+  int   valid;
+  HCRYPTPROV  cryptProv;
+  HCRYPTHASH  hash;
+} Digest_CTX;
+#endif
+
+/* typedefs */
+#if defined(ARCHIVE_CRYPTO_MD5_LIBC)
+typedef MD5_CTX archive_md5_ctx;
+#elif defined(ARCHIVE_CRYPTO_MD5_LIBMD)
+typedef MD5_CTX archive_md5_ctx;
+#elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM)
+typedef CC_MD5_CTX archive_md5_ctx;
+#elif defined(ARCHIVE_CRYPTO_MD5_NETTLE)
+typedef struct md5_ctx archive_md5_ctx;
+#elif defined(ARCHIVE_CRYPTO_MD5_OPENSSL)
+typedef EVP_MD_CTX archive_md5_ctx;
+#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
+typedef Digest_CTX archive_md5_ctx;
+#else
+typedef unsigned char archive_md5_ctx;
+#endif
+
+#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)
+typedef RMD160_CTX archive_rmd160_ctx;
+#elif defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
+typedef RIPEMD160_CTX archive_rmd160_ctx;
+#elif defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
+typedef struct ripemd160_ctx archive_rmd160_ctx;
+#elif defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
+typedef EVP_MD_CTX archive_rmd160_ctx;
+#else
+typedef unsigned char archive_rmd160_ctx;
+#endif
+
+#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)
+typedef SHA1_CTX archive_sha1_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA1_LIBMD)
+typedef SHA1_CTX archive_sha1_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM)
+typedef CC_SHA1_CTX archive_sha1_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA1_NETTLE)
+typedef struct sha1_ctx archive_sha1_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA1_OPENSSL)
+typedef EVP_MD_CTX archive_sha1_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
+typedef Digest_CTX archive_sha1_ctx;
+#else
+typedef unsigned char archive_sha1_ctx;
+#endif
+
+#if defined(ARCHIVE_CRYPTO_SHA256_LIBC)
+typedef SHA256_CTX archive_sha256_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC2)
+typedef SHA256_CTX archive_sha256_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC3)
+typedef SHA2_CTX archive_sha256_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBMD)
+typedef SHA256_CTX archive_sha256_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM)
+typedef CC_SHA256_CTX archive_sha256_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA256_NETTLE)
+typedef struct sha256_ctx archive_sha256_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA256_OPENSSL)
+typedef EVP_MD_CTX archive_sha256_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
+typedef Digest_CTX archive_sha256_ctx;
+#else
+typedef unsigned char archive_sha256_ctx;
+#endif
+
+#if defined(ARCHIVE_CRYPTO_SHA384_LIBC)
+typedef SHA384_CTX archive_sha384_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC2)
+typedef SHA384_CTX archive_sha384_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC3)
+typedef SHA2_CTX archive_sha384_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM)
+typedef CC_SHA512_CTX archive_sha384_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA384_NETTLE)
+typedef struct sha384_ctx archive_sha384_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA384_OPENSSL)
+typedef EVP_MD_CTX archive_sha384_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
+typedef Digest_CTX archive_sha384_ctx;
+#else
+typedef unsigned char archive_sha384_ctx;
+#endif
+
+#if defined(ARCHIVE_CRYPTO_SHA512_LIBC)
+typedef SHA512_CTX archive_sha512_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC2)
+typedef SHA512_CTX archive_sha512_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC3)
+typedef SHA2_CTX archive_sha512_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
+typedef SHA512_CTX archive_sha512_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
+typedef CC_SHA512_CTX archive_sha512_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
+typedef struct sha512_ctx archive_sha512_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
+typedef EVP_MD_CTX archive_sha512_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
+typedef Digest_CTX archive_sha512_ctx;
+#else
+typedef unsigned char archive_sha512_ctx;
+#endif
+
+/* defines */
+#if defined(ARCHIVE_CRYPTO_MD5_LIBC) ||\
+  defined(ARCHIVE_CRYPTO_MD5_LIBMD) || \
+  defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM) ||\
+  defined(ARCHIVE_CRYPTO_MD5_NETTLE) ||\
+  defined(ARCHIVE_CRYPTO_MD5_OPENSSL) ||\
+  defined(ARCHIVE_CRYPTO_MD5_WIN)
+#define ARCHIVE_HAS_MD5
+#endif
+#define archive_md5_init(ctx)\
+  __archive_crypto.md5init(ctx)
+#define archive_md5_final(ctx, md)\
+  __archive_crypto.md5final(ctx, md)
+#define archive_md5_update(ctx, buf, n)\
+  __archive_crypto.md5update(ctx, buf, n)
+
+#if defined(ARCHIVE_CRYPTO_RMD160_LIBC) ||\
+  defined(ARCHIVE_CRYPTO_RMD160_NETTLE) ||\
+  defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
+#define ARCHIVE_HAS_RMD160
+#endif
+#define archive_rmd160_init(ctx)\
+  __archive_crypto.rmd160init(ctx)
+#define archive_rmd160_final(ctx, md)\
+  __archive_crypto.rmd160final(ctx, md)
+#define archive_rmd160_update(ctx, buf, n)\
+  __archive_crypto.rmd160update(ctx, buf, n)
+
+#if defined(ARCHIVE_CRYPTO_SHA1_LIBC) ||\
+  defined(ARCHIVE_CRYPTO_SHA1_LIBMD) ||        \
+  defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM) ||\
+  defined(ARCHIVE_CRYPTO_SHA1_NETTLE) ||\
+  defined(ARCHIVE_CRYPTO_SHA1_OPENSSL) ||\
+  defined(ARCHIVE_CRYPTO_SHA1_WIN)
+#define ARCHIVE_HAS_SHA1
+#endif
+#define archive_sha1_init(ctx)\
+  __archive_crypto.sha1init(ctx)
+#define archive_sha1_final(ctx, md)\
+  __archive_crypto.sha1final(ctx, md)
+#define archive_sha1_update(ctx, buf, n)\
+  __archive_crypto.sha1update(ctx, buf, n)
+
+#if defined(ARCHIVE_CRYPTO_SHA256_LIBC) ||\
+  defined(ARCHIVE_CRYPTO_SHA256_LIBC2) ||\
+  defined(ARCHIVE_CRYPTO_SHA256_LIBC3) ||\
+  defined(ARCHIVE_CRYPTO_SHA256_LIBMD) ||\
+  defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM) ||\
+  defined(ARCHIVE_CRYPTO_SHA256_NETTLE) ||\
+  defined(ARCHIVE_CRYPTO_SHA256_OPENSSL) ||\
+  defined(ARCHIVE_CRYPTO_SHA256_WIN)
+#define ARCHIVE_HAS_SHA256
+#endif
+#define archive_sha256_init(ctx)\
+  __archive_crypto.sha256init(ctx)
+#define archive_sha256_final(ctx, md)\
+  __archive_crypto.sha256final(ctx, md)
+#define archive_sha256_update(ctx, buf, n)\
+  __archive_crypto.sha256update(ctx, buf, n)
+
+#if defined(ARCHIVE_CRYPTO_SHA384_LIBC) ||\
+  defined(ARCHIVE_CRYPTO_SHA384_LIBC2) ||\
+  defined(ARCHIVE_CRYPTO_SHA384_LIBC3) ||\
+  defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM) ||\
+  defined(ARCHIVE_CRYPTO_SHA384_NETTLE) ||\
+  defined(ARCHIVE_CRYPTO_SHA384_OPENSSL) ||\
+  defined(ARCHIVE_CRYPTO_SHA384_WIN)
+#define ARCHIVE_HAS_SHA384
+#endif
+#define archive_sha384_init(ctx)\
+  __archive_crypto.sha384init(ctx)
+#define archive_sha384_final(ctx, md)\
+  __archive_crypto.sha384final(ctx, md)
+#define archive_sha384_update(ctx, buf, n)\
+  __archive_crypto.sha384update(ctx, buf, n)
+
+#if defined(ARCHIVE_CRYPTO_SHA512_LIBC) ||\
+  defined(ARCHIVE_CRYPTO_SHA512_LIBC2) ||\
+  defined(ARCHIVE_CRYPTO_SHA512_LIBC3) ||\
+  defined(ARCHIVE_CRYPTO_SHA512_LIBMD) ||\
+  defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM) ||\
+  defined(ARCHIVE_CRYPTO_SHA512_NETTLE) ||\
+  defined(ARCHIVE_CRYPTO_SHA512_OPENSSL) ||\
+  defined(ARCHIVE_CRYPTO_SHA512_WIN)
+#define ARCHIVE_HAS_SHA512
+#endif
+#define archive_sha512_init(ctx)\
+  __archive_crypto.sha512init(ctx)
+#define archive_sha512_final(ctx, md)\
+  __archive_crypto.sha512final(ctx, md)
+#define archive_sha512_update(ctx, buf, n)\
+  __archive_crypto.sha512update(ctx, buf, n)
+
+/* Minimal interface to crypto functionality for internal use in libarchive */
+struct archive_crypto
+{
+  /* Message Digest */
+  int (*md5init)(archive_md5_ctx *ctx);
+  int (*md5update)(archive_md5_ctx *, const void *, size_t);
+  int (*md5final)(archive_md5_ctx *, void *);
+  int (*rmd160init)(archive_rmd160_ctx *);
+  int (*rmd160update)(archive_rmd160_ctx *, const void *, size_t);
+  int (*rmd160final)(archive_rmd160_ctx *, void *);
+  int (*sha1init)(archive_sha1_ctx *);
+  int (*sha1update)(archive_sha1_ctx *, const void *, size_t);
+  int (*sha1final)(archive_sha1_ctx *, void *);
+  int (*sha256init)(archive_sha256_ctx *);
+  int (*sha256update)(archive_sha256_ctx *, const void *, size_t);
+  int (*sha256final)(archive_sha256_ctx *, void *);
+  int (*sha384init)(archive_sha384_ctx *);
+  int (*sha384update)(archive_sha384_ctx *, const void *, size_t);
+  int (*sha384final)(archive_sha384_ctx *, void *);
+  int (*sha512init)(archive_sha512_ctx *);
+  int (*sha512update)(archive_sha512_ctx *, const void *, size_t);
+  int (*sha512final)(archive_sha512_ctx *, void *);
+};
+
+extern const struct archive_crypto __archive_crypto;
+
+#endif
index 9ceb18b..10e3c34 100644 (file)
@@ -1,4 +1,5 @@
 .\" Copyright (c) 2003-2007 Tim Kientzle
+.\" Copyright (c) 2010 Joerg Sonnenberger
 .\" All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
 .\"
 .\" $FreeBSD: src/lib/libarchive/archive_entry.3,v 1.18 2008/05/26 17:00:22 kientzle Exp $
 .\"
-.Dd May 12, 2008
-.Dt archive_entry 3
+.Dd Feburary 22, 2010
+.Dt ARCHIVE_ENTRY 3
 .Os
 .Sh NAME
-.Nm archive_entry_acl_add_entry ,
-.Nm archive_entry_acl_add_entry_w ,
-.Nm archive_entry_acl_clear ,
-.Nm archive_entry_acl_count ,
-.Nm archive_entry_acl_next ,
-.Nm archive_entry_acl_next_w ,
-.Nm archive_entry_acl_reset ,
-.Nm archive_entry_acl_text_w ,
-.Nm archive_entry_atime ,
-.Nm archive_entry_atime_nsec ,
 .Nm archive_entry_clear ,
 .Nm archive_entry_clone ,
-.Nm archive_entry_copy_fflags_text ,
-.Nm archive_entry_copy_fflags_text_w ,
-.Nm archive_entry_copy_gname ,
-.Nm archive_entry_copy_gname_w ,
-.Nm archive_entry_copy_hardlink ,
-.Nm archive_entry_copy_hardlink_w ,
-.Nm archive_entry_copy_link ,
-.Nm archive_entry_copy_link_w ,
-.Nm archive_entry_copy_pathname_w ,
-.Nm archive_entry_copy_sourcepath ,
-.Nm archive_entry_copy_stat ,
-.Nm archive_entry_copy_symlink ,
-.Nm archive_entry_copy_symlink_w ,
-.Nm archive_entry_copy_uname ,
-.Nm archive_entry_copy_uname_w ,
-.Nm archive_entry_dev ,
-.Nm archive_entry_devmajor ,
-.Nm archive_entry_devminor ,
-.Nm archive_entry_filetype ,
-.Nm archive_entry_fflags ,
-.Nm archive_entry_fflags_text ,
 .Nm archive_entry_free ,
-.Nm archive_entry_gid ,
-.Nm archive_entry_gname ,
-.Nm archive_entry_hardlink ,
-.Nm archive_entry_ino ,
-.Nm archive_entry_mode ,
-.Nm archive_entry_mtime ,
-.Nm archive_entry_mtime_nsec ,
-.Nm archive_entry_nlink ,
 .Nm archive_entry_new ,
-.Nm archive_entry_pathname ,
-.Nm archive_entry_pathname_w ,
-.Nm archive_entry_rdev ,
-.Nm archive_entry_rdevmajor ,
-.Nm archive_entry_rdevminor ,
-.Nm archive_entry_set_atime ,
-.Nm archive_entry_set_ctime ,
-.Nm archive_entry_set_dev ,
-.Nm archive_entry_set_devmajor ,
-.Nm archive_entry_set_devminor ,
-.Nm archive_entry_set_filetype ,
-.Nm archive_entry_set_fflags ,
-.Nm archive_entry_set_gid ,
-.Nm archive_entry_set_gname ,
-.Nm archive_entry_set_hardlink ,
-.Nm archive_entry_set_link ,
-.Nm archive_entry_set_mode ,
-.Nm archive_entry_set_mtime ,
-.Nm archive_entry_set_pathname ,
-.Nm archive_entry_set_rdevmajor ,
-.Nm archive_entry_set_rdevminor ,
-.Nm archive_entry_set_size ,
-.Nm archive_entry_set_symlink ,
-.Nm archive_entry_set_uid ,
-.Nm archive_entry_set_uname ,
-.Nm archive_entry_size ,
-.Nm archive_entry_sourcepath ,
-.Nm archive_entry_stat ,
-.Nm archive_entry_symlink ,
-.Nm archive_entry_uid ,
-.Nm archive_entry_uname
-.Nd functions for manipulating archive entry descriptions
+.Nd functions for managing archive entry descriptions
 .Sh SYNOPSIS
 .In archive_entry.h
-.Ft void
-.Fo archive_entry_acl_add_entry
-.Fa "struct archive_entry *"
-.Fa "int type"
-.Fa "int permset"
-.Fa "int tag"
-.Fa "int qual"
-.Fa "const char *name"
-.Fc
-.Ft void
-.Fo archive_entry_acl_add_entry_w
-.Fa "struct archive_entry *"
-.Fa "int type"
-.Fa "int permset"
-.Fa "int tag"
-.Fa "int qual"
-.Fa "const wchar_t *name"
-.Fc
-.Ft void
-.Fn archive_entry_acl_clear "struct archive_entry *"
-.Ft int
-.Fn archive_entry_acl_count "struct archive_entry *" "int type"
-.Ft int
-.Fo archive_entry_acl_next
-.Fa "struct archive_entry *"
-.Fa "int want_type"
-.Fa "int *type"
-.Fa "int *permset"
-.Fa "int *tag"
-.Fa "int *qual"
-.Fa "const char **name"
-.Fc
-.Ft int
-.Fo archive_entry_acl_next_w
-.Fa "struct archive_entry *"
-.Fa "int want_type"
-.Fa "int *type"
-.Fa "int *permset"
-.Fa "int *tag"
-.Fa "int *qual"
-.Fa "const wchar_t **name"
-.Fc
-.Ft int
-.Fn archive_entry_acl_reset "struct archive_entry *" "int want_type"
-.Ft const wchar_t *
-.Fn archive_entry_acl_text_w "struct archive_entry *" "int flags"
-.Ft time_t
-.Fn archive_entry_atime "struct archive_entry *"
-.Ft long
-.Fn archive_entry_atime_nsec "struct archive_entry *"
 .Ft "struct archive_entry *"
 .Fn archive_entry_clear "struct archive_entry *"
 .Ft struct archive_entry *
 .Fn archive_entry_clone "struct archive_entry *"
-.Ft const char * *
-.Fn archive_entry_copy_fflags_text_w "struct archive_entry *" "const char *"
-.Ft const wchar_t *
-.Fn archive_entry_copy_fflags_text_w "struct archive_entry *" "const wchar_t *"
-.Ft void
-.Fn archive_entry_copy_gname "struct archive_entry *" "const char *"
-.Ft void
-.Fn archive_entry_copy_gname_w "struct archive_entry *" "const wchar_t *"
-.Ft void
-.Fn archive_entry_copy_hardlink "struct archive_entry *" "const char *"
-.Ft void
-.Fn archive_entry_copy_hardlink_w "struct archive_entry *" "const wchar_t *"
-.Ft void
-.Fn archive_entry_copy_sourcepath "struct archive_entry *" "const char *"
-.Ft void
-.Fn archive_entry_copy_pathname_w "struct archive_entry *" "const wchar_t *"
-.Ft void
-.Fn archive_entry_copy_stat "struct archive_entry *" "const struct stat *"
-.Ft void
-.Fn archive_entry_copy_symlink "struct archive_entry *" "const char *"
-.Ft void
-.Fn archive_entry_copy_symlink_w "struct archive_entry *" "const wchar_t *"
-.Ft void
-.Fn archive_entry_copy_uname "struct archive_entry *" "const char *"
-.Ft void
-.Fn archive_entry_copy_uname_w "struct archive_entry *" "const wchar_t *"
-.Ft dev_t
-.Fn archive_entry_dev "struct archive_entry *"
-.Ft dev_t
-.Fn archive_entry_devmajor "struct archive_entry *"
-.Ft dev_t
-.Fn archive_entry_devminor "struct archive_entry *"
-.Ft mode_t
-.Fn archive_entry_filetype "struct archive_entry *"
-.Ft void
-.Fo archive_entry_fflags
-.Fa "struct archive_entry *"
-.Fa "unsigned long *set"
-.Fa "unsigned long *clear"
-.Fc
-.Ft const char *
-.Fn archive_entry_fflags_text "struct archive_entry *"
 .Ft void
 .Fn archive_entry_free "struct archive_entry *"
-.Ft const char *
-.Fn archive_entry_gname "struct archive_entry *"
-.Ft const char *
-.Fn archive_entry_hardlink "struct archive_entry *"
-.Ft ino_t
-.Fn archive_entry_ino "struct archive_entry *"
-.Ft mode_t
-.Fn archive_entry_mode "struct archive_entry *"
-.Ft time_t
-.Fn archive_entry_mtime "struct archive_entry *"
-.Ft long
-.Fn archive_entry_mtime_nsec "struct archive_entry *"
-.Ft unsigned int
-.Fn archive_entry_nlink "struct archive_entry *"
 .Ft struct archive_entry *
 .Fn archive_entry_new "void"
-.Ft const char *
-.Fn archive_entry_pathname "struct archive_entry *"
-.Ft const wchar_t *
-.Fn archive_entry_pathname_w "struct archive_entry *"
-.Ft dev_t
-.Fn archive_entry_rdev "struct archive_entry *"
-.Ft dev_t
-.Fn archive_entry_rdevmajor "struct archive_entry *"
-.Ft dev_t
-.Fn archive_entry_rdevminor "struct archive_entry *"
-.Ft void
-.Fn archive_entry_set_dev "struct archive_entry *" "dev_t"
-.Ft void
-.Fn archive_entry_set_devmajor "struct archive_entry *" "dev_t"
-.Ft void
-.Fn archive_entry_set_devminor "struct archive_entry *" "dev_t"
-.Ft void
-.Fn archive_entry_set_filetype "struct archive_entry *" "unsigned int"
-.Ft void
-.Fo archive_entry_set_fflags
-.Fa "struct archive_entry *"
-.Fa "unsigned long set"
-.Fa "unsigned long clear"
-.Fc
-.Ft void
-.Fn archive_entry_set_gid "struct archive_entry *" "gid_t"
-.Ft void
-.Fn archive_entry_set_gname "struct archive_entry *" "const char *"
-.Ft void
-.Fn archive_entry_set_hardlink "struct archive_entry *" "const char *"
-.Ft void
-.Fn archive_entry_set_ino "struct archive_entry *" "unsigned long"
-.Ft void
-.Fn archive_entry_set_link "struct archive_entry *" "const char *"
-.Ft void
-.Fn archive_entry_set_mode "struct archive_entry *" "mode_t"
-.Ft void
-.Fn archive_entry_set_mtime "struct archive_entry *" "time_t" "long nanos"
-.Ft void
-.Fn archive_entry_set_nlink "struct archive_entry *" "unsigned int"
-.Ft void
-.Fn archive_entry_set_pathname "struct archive_entry *" "const char *"
-.Ft void
-.Fn archive_entry_set_rdev "struct archive_entry *" "dev_t"
-.Ft void
-.Fn archive_entry_set_rdevmajor "struct archive_entry *" "dev_t"
-.Ft void
-.Fn archive_entry_set_rdevminor "struct archive_entry *" "dev_t"
-.Ft void
-.Fn archive_entry_set_size "struct archive_entry *" "int64_t"
-.Ft void
-.Fn archive_entry_set_symlink "struct archive_entry *" "const char *"
-.Ft void
-.Fn archive_entry_set_uid "struct archive_entry *" "uid_t"
-.Ft void
-.Fn archive_entry_set_uname "struct archive_entry *" "const char *"
-.Ft int64_t
-.Fn archive_entry_size "struct archive_entry *"
-.Ft const char *
-.Fn archive_entry_sourcepath "struct archive_entry *"
-.Ft const struct stat *
-.Fn archive_entry_stat "struct archive_entry *"
-.Ft const char *
-.Fn archive_entry_symlink "struct archive_entry *"
-.Ft const char *
-.Fn archive_entry_uname "struct archive_entry *"
 .Sh DESCRIPTION
 These functions create and manipulate data objects that
 represent entries within an archive.
@@ -320,8 +79,24 @@ Allocate and return a blank
 .Tn struct archive_entry
 object.
 .El
-.Ss Set and Get Functions
-Most of the functions here set or read entries in an object.
+.Ss Function groups
+Due to high number of functions, the accessor functions can be found in
+man pages grouped by the purpose.
+.Bl -tag -width ".Xr archive_entry_perms 3"
+.It Xr archive_entry_acl 3
+Access Control List manipulation
+.It Xr archive_entry_paths 3
+Path name manipulation
+.It Xr archive_entry_perms 3
+User, group and mode manipulation
+.It Xr archive_entry_stat 3
+Functions not in the other groups and copying to/from
+.Vt struct stat .
+.It Xr archive_entry_time 3
+Time field manipulation
+.El
+.Pp
+Most of the functions set or read entries in an object.
 Such functions have one of the following forms:
 .Bl -tag -compact -width indent
 .It Fn archive_entry_set_XXXX
@@ -350,75 +125,15 @@ Similarly, if you store a wide string and then store a
 narrow string for the same data, the previously-set wide string will
 be discarded in favor of the new data.
 .Pp
-There are a few set/get functions that merit additional description:
-.Bl -tag -compact -width indent
-.It Fn archive_entry_set_link
-This function sets the symlink field if it is already set.
-Otherwise, it sets the hardlink field.
-.El
-.Ss File Flags
-File flags are transparently converted between a bitmap
-representation and a textual format.
-For example, if you set the bitmap and ask for text, the library
-will build a canonical text format.
-However, if you set a text format and request a text format,
-you will get back the same text, even if it is ill-formed.
-If you need to canonicalize a textual flags string, you should first set the
-text form, then request the bitmap form, then use that to set the bitmap form.
-Setting the bitmap format will clear the internal text representation
-and force it to be reconstructed when you next request the text form.
-.Pp
-The bitmap format consists of two integers, one containing bits
-that should be set, the other specifying bits that should be
-cleared.
-Bits not mentioned in either bitmap will be ignored.
-Usually, the bitmap of bits to be cleared will be set to zero.
-In unusual circumstances, you can force a fully-specified set
-of file flags by setting the bitmap of flags to clear to the complement
-of the bitmap of flags to set.
-(This differs from
-.Xr fflagstostr 3 ,
-which only includes names for set bits.)
-Converting a bitmap to a textual string is a platform-specific
-operation; bits that are not meaningful on the current platform
-will be ignored.
-.Pp
-The canonical text format is a comma-separated list of flag names.
-The
-.Fn archive_entry_copy_fflags_text
-and
-.Fn archive_entry_copy_fflags_text_w
-functions parse the provided text and sets the internal bitmap values.
-This is a platform-specific operation; names that are not meaningful
-on the current platform will be ignored.
-The function returns a pointer to the start of the first name that was not
-recognized, or NULL if every name was recognized.
-Note that every name--including names that follow an unrecognized name--will
-be evaluated, and the bitmaps will be set to reflect every name that is
-recognized.
-(In particular, this differs from
-.Xr strtofflags 3 ,
-which stops parsing at the first unrecognized name.)
-.Ss ACL Handling
-XXX This needs serious help.
-XXX
-.Pp
-An
-.Dq Access Control List
-(ACL) is a list of permissions that grant access to particular users or
-groups beyond what would normally be provided by standard POSIX mode bits.
-The ACL handling here addresses some deficiencies in the POSIX.1e draft 17 ACL
-specification.
-In particular, POSIX.1e draft 17 specifies several different formats, but
-none of those formats include both textual user/group names and numeric
-UIDs/GIDs.
-.Pp
-XXX explain ACL stuff XXX
 .\" .Sh EXAMPLE
 .\" .Sh RETURN VALUES
 .\" .Sh ERRORS
 .Sh SEE ALSO
-.Xr archive 3
+.Xr archive 3 ,
+.Xr archive_entry_acl 3 ,
+.Xr archive_entry_paths 3 ,
+.Xr archive_entry_perms 3 ,
+.Xr archive_entry_time 3
 .Sh HISTORY
 The
 .Nm libarchive
index f734b8c..cbdda8a 100644 (file)
@@ -39,6 +39,9 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_entry.c 201096 2009-12-28 02:41:
 #include <sys/sysmacros.h>
 #define HAVE_MAJOR
 #endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
 #ifdef HAVE_LIMITS_H
 #include <limits.h>
 #endif
@@ -68,13 +71,12 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_entry.c 201096 2009-12-28 02:41:
 #endif
 
 #include "archive.h"
+#include "archive_acl_private.h"
 #include "archive_entry.h"
+#include "archive_entry_locale.h"
 #include "archive_private.h"
 #include "archive_entry_private.h"
 
-#undef max
-#define        max(a, b)       ((a)>(b)?(a):(b))
-
 #if !defined(HAVE_MAJOR) && !defined(major)
 /* Replacement for major/minor/makedev. */
 #define        major(x) ((int)(0x00ff & ((x) >> 8)))
@@ -98,39 +100,26 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_entry.c 201096 2009-12-28 02:41:
 #define ae_makedev(maj, min) makedev((maj), (min))
 #endif
 
-static void    aes_clean(struct aes *);
-static void    aes_copy(struct aes *dest, struct aes *src);
-static const char *    aes_get_mbs(struct aes *);
-static const wchar_t * aes_get_wcs(struct aes *);
-static int     aes_set_mbs(struct aes *, const char *mbs);
-static int     aes_copy_mbs(struct aes *, const char *mbs);
-/* static void aes_set_wcs(struct aes *, const wchar_t *wcs); */
-static int     aes_copy_wcs(struct aes *, const wchar_t *wcs);
-static int     aes_copy_wcs_len(struct aes *, const wchar_t *wcs, size_t);
+/*
+ * This adjustment is needed to support the following idiom for adding
+ * 1000ns to the stored time:
+ * archive_entry_set_atime(archive_entry_atime(),
+ *                         archive_entry_atime_nsec() + 1000)
+ * The additional if() here compensates for ambiguity in the C standard,
+ * which permits two possible interpretations of a % b when a is negative.
+ */
+#define FIX_NS(t,ns) \
+       do {    \
+               t += ns / 1000000000; \
+               ns %= 1000000000; \
+               if (ns < 0) { --t; ns += 1000000000; } \
+       } while (0)
 
 static char *   ae_fflagstostr(unsigned long bitset, unsigned long bitclear);
 static const wchar_t   *ae_wcstofflags(const wchar_t *stringp,
                    unsigned long *setp, unsigned long *clrp);
 static const char      *ae_strtofflags(const char *stringp,
                    unsigned long *setp, unsigned long *clrp);
-static void    append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
-                   const wchar_t *wname, int perm, int id);
-static void    append_id_w(wchar_t **wp, int id);
-
-static int     acl_special(struct archive_entry *entry,
-                   int type, int permset, int tag);
-static struct ae_acl *acl_new_entry(struct archive_entry *entry,
-                   int type, int permset, int tag, int id);
-static int     isint_w(const wchar_t *start, const wchar_t *end, int *result);
-static int     ismode_w(const wchar_t *start, const wchar_t *end, int *result);
-static void    next_field_w(const wchar_t **wp, const wchar_t **start,
-                   const wchar_t **end, wchar_t *sep);
-static int     prefix_w(const wchar_t *start, const wchar_t *end,
-                   const wchar_t *test);
-static void
-archive_entry_acl_add_entry_w_len(struct archive_entry *entry, int type,
-                   int permset, int tag, int id, const wchar_t *name, size_t);
-
 
 #ifndef HAVE_WCSCPY
 static wchar_t * wcscpy(wchar_t *s1, const wchar_t *s2)
@@ -154,214 +143,6 @@ static size_t wcslen(const wchar_t *s)
 /* Good enough for simple equality testing, but not for sorting. */
 #define wmemcmp(a,b,i)  memcmp((a), (b), (i) * sizeof(wchar_t))
 #endif
-#ifndef HAVE_WMEMCPY
-#define wmemcpy(a,b,i)  (wchar_t *)memcpy((a), (b), (i) * sizeof(wchar_t))
-#endif
-
-static void
-aes_clean(struct aes *aes)
-{
-       if (aes->aes_wcs) {
-               free((wchar_t *)(uintptr_t)aes->aes_wcs);
-               aes->aes_wcs = NULL;
-       }
-       archive_string_free(&(aes->aes_mbs));
-       archive_string_free(&(aes->aes_utf8));
-       aes->aes_set = 0;
-}
-
-static void
-aes_copy(struct aes *dest, struct aes *src)
-{
-       wchar_t *wp;
-
-       dest->aes_set = src->aes_set;
-       archive_string_copy(&(dest->aes_mbs), &(src->aes_mbs));
-       archive_string_copy(&(dest->aes_utf8), &(src->aes_utf8));
-
-       if (src->aes_wcs != NULL) {
-               wp = (wchar_t *)malloc((wcslen(src->aes_wcs) + 1)
-                   * sizeof(wchar_t));
-               if (wp == NULL)
-                       __archive_errx(1, "No memory for aes_copy()");
-               wcscpy(wp, src->aes_wcs);
-               dest->aes_wcs = wp;
-       }
-}
-
-static const char *
-aes_get_utf8(struct aes *aes)
-{
-       if (aes->aes_set & AES_SET_UTF8)
-               return (aes->aes_utf8.s);
-       if ((aes->aes_set & AES_SET_WCS)
-           && archive_strappend_w_utf8(&(aes->aes_utf8), aes->aes_wcs) != NULL) {
-               aes->aes_set |= AES_SET_UTF8;
-               return (aes->aes_utf8.s);
-       }
-       return (NULL);
-}
-
-static const char *
-aes_get_mbs(struct aes *aes)
-{
-       /* If we already have an MBS form, return that immediately. */
-       if (aes->aes_set & AES_SET_MBS)
-               return (aes->aes_mbs.s);
-       /* If there's a WCS form, try converting with the native locale. */
-       if ((aes->aes_set & AES_SET_WCS)
-           && archive_strappend_w_mbs(&(aes->aes_mbs), aes->aes_wcs) != NULL) {
-               aes->aes_set |= AES_SET_MBS;
-               return (aes->aes_mbs.s);
-       }
-       /* We'll use UTF-8 for MBS if all else fails. */
-       return (aes_get_utf8(aes));
-}
-
-static const wchar_t *
-aes_get_wcs(struct aes *aes)
-{
-       wchar_t *w;
-       size_t r;
-
-       /* Return WCS form if we already have it. */
-       if (aes->aes_set & AES_SET_WCS)
-               return (aes->aes_wcs);
-
-       if (aes->aes_set & AES_SET_MBS) {
-               /* Try converting MBS to WCS using native locale. */
-               /*
-                * No single byte will be more than one wide character,
-                * so this length estimate will always be big enough.
-                */
-               size_t wcs_length = aes->aes_mbs.length;
-
-               w = (wchar_t *)malloc((wcs_length + 1) * sizeof(wchar_t));
-               if (w == NULL)
-                       __archive_errx(1, "No memory for aes_get_wcs()");
-               r = mbstowcs(w, aes->aes_mbs.s, wcs_length);
-               if (r != (size_t)-1 && r != 0) {
-                       w[r] = 0;
-                       aes->aes_set |= AES_SET_WCS;
-                       return (aes->aes_wcs = w);
-               }
-               free(w);
-       }
-
-       if (aes->aes_set & AES_SET_UTF8) {
-               /* Try converting UTF8 to WCS. */
-               aes->aes_wcs = __archive_string_utf8_w(&(aes->aes_utf8));
-               if (aes->aes_wcs != NULL)
-                       aes->aes_set |= AES_SET_WCS;
-               return (aes->aes_wcs);
-       }
-       return (NULL);
-}
-
-static int
-aes_set_mbs(struct aes *aes, const char *mbs)
-{
-       return (aes_copy_mbs(aes, mbs));
-}
-
-static int
-aes_copy_mbs(struct aes *aes, const char *mbs)
-{
-       if (mbs == NULL) {
-               aes->aes_set = 0;
-               return (0);
-       }
-       aes->aes_set = AES_SET_MBS; /* Only MBS form is set now. */
-       archive_strcpy(&(aes->aes_mbs), mbs);
-       archive_string_empty(&(aes->aes_utf8));
-       if (aes->aes_wcs) {
-               free((wchar_t *)(uintptr_t)aes->aes_wcs);
-               aes->aes_wcs = NULL;
-       }
-       return (0);
-}
-
-/*
- * The 'update' form tries to proactively update all forms of
- * this string (WCS and MBS) and returns an error if any of
- * them fail.  This is used by the 'pax' handler, for instance,
- * to detect and report character-conversion failures early while
- * still allowing clients to get potentially useful values from
- * the more tolerant lazy conversions.  (get_mbs and get_wcs will
- * strive to give the user something useful, so you can get hopefully
- * usable values even if some of the character conversions are failing.)
- */
-static int
-aes_update_utf8(struct aes *aes, const char *utf8)
-{
-       if (utf8 == NULL) {
-               aes->aes_set = 0;
-               return (1); /* Succeeded in clearing everything. */
-       }
-
-       /* Save the UTF8 string. */
-       archive_strcpy(&(aes->aes_utf8), utf8);
-
-       /* Empty the mbs and wcs strings. */
-       archive_string_empty(&(aes->aes_mbs));
-       if (aes->aes_wcs) {
-               free((wchar_t *)(uintptr_t)aes->aes_wcs);
-               aes->aes_wcs = NULL;
-       }
-
-       aes->aes_set = AES_SET_UTF8;    /* Only UTF8 is set now. */
-
-       /* TODO: We should just do a direct UTF-8 to MBS conversion
-        * here.  That would be faster, use less space, and give the
-        * same information.  (If a UTF-8 to MBS conversion succeeds,
-        * then UTF-8->WCS and Unicode->MBS conversions will both
-        * succeed.) */
-
-       /* Try converting UTF8 to WCS, return false on failure. */
-       aes->aes_wcs = __archive_string_utf8_w(&(aes->aes_utf8));
-       if (aes->aes_wcs == NULL)
-               return (0);
-       aes->aes_set = AES_SET_UTF8 | AES_SET_WCS; /* Both UTF8 and WCS set. */
-
-       /* Try converting WCS to MBS, return false on failure. */
-       if (archive_strappend_w_mbs(&(aes->aes_mbs), aes->aes_wcs) == NULL)
-               return (0);
-       aes->aes_set = AES_SET_UTF8 | AES_SET_WCS | AES_SET_MBS;
-
-       /* All conversions succeeded. */
-       return (1);
-}
-
-static int
-aes_copy_wcs(struct aes *aes, const wchar_t *wcs)
-{
-       return aes_copy_wcs_len(aes, wcs, wcs == NULL ? 0 : wcslen(wcs));
-}
-
-static int
-aes_copy_wcs_len(struct aes *aes, const wchar_t *wcs, size_t len)
-{
-       wchar_t *w;
-
-       if (wcs == NULL) {
-               aes->aes_set = 0;
-               return (0);
-       }
-       aes->aes_set = AES_SET_WCS; /* Only WCS form set. */
-       archive_string_empty(&(aes->aes_mbs));
-       archive_string_empty(&(aes->aes_utf8));
-       if (aes->aes_wcs) {
-               free((wchar_t *)(uintptr_t)aes->aes_wcs);
-               aes->aes_wcs = NULL;
-       }
-       w = (wchar_t *)malloc((len + 1) * sizeof(wchar_t));
-       if (w == NULL)
-               __archive_errx(1, "No memory for aes_copy_wcs()");
-       wmemcpy(w, wcs, len);
-       w[len] = L'\0';
-       aes->aes_wcs = w;
-       return (0);
-}
 
 /****************************************************************************
  *
@@ -374,15 +155,17 @@ 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);
-       aes_clean(&entry->ae_pathname);
-       aes_clean(&entry->ae_sourcepath);
-       aes_clean(&entry->ae_symlink);
-       aes_clean(&entry->ae_uname);
-       archive_entry_acl_clear(entry);
+       archive_mstring_clean(&entry->ae_fflags_text);
+       archive_mstring_clean(&entry->ae_gname);
+       archive_mstring_clean(&entry->ae_hardlink);
+       archive_mstring_clean(&entry->ae_pathname);
+       archive_mstring_clean(&entry->ae_sourcepath);
+       archive_mstring_clean(&entry->ae_symlink);
+       archive_mstring_clean(&entry->ae_uname);
+       archive_entry_copy_mac_metadata(entry, NULL, 0);
+       archive_acl_clear(&entry->acl);
        archive_entry_xattr_clear(entry);
+       archive_entry_sparse_clear(entry);
        free(entry->stat);
        memset(entry, 0, sizeof(*entry));
        return entry;
@@ -392,36 +175,38 @@ struct archive_entry *
 archive_entry_clone(struct archive_entry *entry)
 {
        struct archive_entry *entry2;
-       struct ae_acl *ap, *ap2;
        struct ae_xattr *xp;
+       struct ae_sparse *sp;
+       size_t s;
+       const void *p;
 
        /* Allocate new structure and copy over all of the fields. */
-       entry2 = (struct archive_entry *)malloc(sizeof(*entry2));
+       /* TODO: Should we copy the archive over?  Or require a new archive
+        * as an argument? */
+       entry2 = archive_entry_new2(entry->archive);
        if (entry2 == NULL)
                return (NULL);
-       memset(entry2, 0, sizeof(*entry2));
        entry2->ae_stat = entry->ae_stat;
        entry2->ae_fflags_set = entry->ae_fflags_set;
        entry2->ae_fflags_clear = entry->ae_fflags_clear;
 
-       aes_copy(&entry2->ae_fflags_text, &entry->ae_fflags_text);
-       aes_copy(&entry2->ae_gname, &entry->ae_gname);
-       aes_copy(&entry2->ae_hardlink, &entry->ae_hardlink);
-       aes_copy(&entry2->ae_pathname, &entry->ae_pathname);
-       aes_copy(&entry2->ae_sourcepath, &entry->ae_sourcepath);
-       aes_copy(&entry2->ae_symlink, &entry->ae_symlink);
+       /* TODO: XXX If clone can have a different archive, what do we do here if
+        * character sets are different? XXX */
+       archive_mstring_copy(&entry2->ae_fflags_text, &entry->ae_fflags_text);
+       archive_mstring_copy(&entry2->ae_gname, &entry->ae_gname);
+       archive_mstring_copy(&entry2->ae_hardlink, &entry->ae_hardlink);
+       archive_mstring_copy(&entry2->ae_pathname, &entry->ae_pathname);
+       archive_mstring_copy(&entry2->ae_sourcepath, &entry->ae_sourcepath);
+       archive_mstring_copy(&entry2->ae_symlink, &entry->ae_symlink);
        entry2->ae_set = entry->ae_set;
-       aes_copy(&entry2->ae_uname, &entry->ae_uname);
+       archive_mstring_copy(&entry2->ae_uname, &entry->ae_uname);
 
        /* Copy ACL data over. */
-       ap = entry->acl_head;
-       while (ap != NULL) {
-               ap2 = acl_new_entry(entry2,
-                   ap->type, ap->permset, ap->tag, ap->id);
-               if (ap2 != NULL)
-                       aes_copy(&ap2->name, &ap->name);
-               ap = ap->next;
-       }
+       archive_acl_copy(&entry2->acl, &entry->acl);
+
+       /* Copy Mac OS metadata. */
+       p = archive_entry_mac_metadata(entry, &s);
+       archive_entry_copy_mac_metadata(entry2, p, s);
 
        /* Copy xattr data over. */
        xp = entry->xattr_head;
@@ -431,6 +216,14 @@ archive_entry_clone(struct archive_entry *entry)
                xp = xp->next;
        }
 
+       /* Copy sparse data over. */
+       sp = entry->sparse_head;
+       while (sp != NULL) {
+               archive_entry_sparse_add_entry(entry2,
+                   sp->offset, sp->length);
+               sp = sp->next;
+       }
+
        return (entry2);
 }
 
@@ -443,6 +236,12 @@ archive_entry_free(struct archive_entry *entry)
 
 struct archive_entry *
 archive_entry_new(void)
+{
+       return archive_entry_new2(NULL);
+}
+
+struct archive_entry *
+archive_entry_new2(struct archive *a)
 {
        struct archive_entry *entry;
 
@@ -450,6 +249,7 @@ archive_entry_new(void)
        if (entry == NULL)
                return (NULL);
        memset(entry, 0, sizeof(*entry));
+       entry->archive = a;
        return (entry);
 }
 
@@ -521,6 +321,12 @@ archive_entry_dev(struct archive_entry *entry)
                return (entry->ae_stat.aest_dev);
 }
 
+int
+archive_entry_dev_is_set(struct archive_entry *entry)
+{
+       return (entry->ae_set & AE_SET_DEV);
+}
+
 dev_t
 archive_entry_devmajor(struct archive_entry *entry)
 {
@@ -542,7 +348,7 @@ archive_entry_devminor(struct archive_entry *entry)
 mode_t
 archive_entry_filetype(struct archive_entry *entry)
 {
-       return (AE_IFMT & entry->ae_stat.aest_mode);
+       return (AE_IFMT & entry->acl.mode);
 }
 
 void
@@ -568,8 +374,8 @@ archive_entry_fflags_text(struct archive_entry *entry)
        const char *f;
        char *p;
 
-       f = aes_get_mbs(&entry->ae_fflags_text);
-       if (f != NULL)
+       if (archive_mstring_get_mbs(entry->archive,
+           &entry->ae_fflags_text, &f) == 0 && f != NULL)
                return (f);
 
        if (entry->ae_fflags_set == 0  &&  entry->ae_fflags_clear == 0)
@@ -579,13 +385,15 @@ archive_entry_fflags_text(struct archive_entry *entry)
        if (p == NULL)
                return (NULL);
 
-       aes_copy_mbs(&entry->ae_fflags_text, p);
+       archive_mstring_copy_mbs(&entry->ae_fflags_text, p);
        free(p);
-       f = aes_get_mbs(&entry->ae_fflags_text);
-       return (f);
+       if (archive_mstring_get_mbs(entry->archive,
+           &entry->ae_fflags_text, &f) == 0)
+               return (f);
+       return (NULL);
 }
 
-gid_t
+int64_t
 archive_entry_gid(struct archive_entry *entry)
 {
        return (entry->ae_stat.aest_gid);
@@ -594,37 +402,72 @@ archive_entry_gid(struct archive_entry *entry)
 const char *
 archive_entry_gname(struct archive_entry *entry)
 {
-       return (aes_get_mbs(&entry->ae_gname));
+       const char *p;
+       if (archive_mstring_get_mbs(entry->archive, &entry->ae_gname, &p) == 0)
+               return (p);
+       return (NULL);
 }
 
 const wchar_t *
 archive_entry_gname_w(struct archive_entry *entry)
 {
-       return (aes_get_wcs(&entry->ae_gname));
+       const wchar_t *p;
+       if (archive_mstring_get_wcs(entry->archive, &entry->ae_gname, &p) == 0)
+               return (p);
+       return (NULL);
+}
+
+int
+_archive_entry_gname_l(struct archive_entry *entry,
+    const char **p, size_t *len, struct archive_string_conv *sc)
+{
+       return (archive_mstring_get_mbs_l(&entry->ae_gname, p, len, sc));
 }
 
 const char *
 archive_entry_hardlink(struct archive_entry *entry)
 {
-       if (entry->ae_set & AE_SET_HARDLINK)
-               return (aes_get_mbs(&entry->ae_hardlink));
+       const char *p;
+       if ((entry->ae_set & AE_SET_HARDLINK) && archive_mstring_get_mbs(
+           entry->archive, &entry->ae_hardlink, &p) == 0)
+               return (p);
        return (NULL);
 }
 
 const wchar_t *
 archive_entry_hardlink_w(struct archive_entry *entry)
 {
-       if (entry->ae_set & AE_SET_HARDLINK)
-               return (aes_get_wcs(&entry->ae_hardlink));
+       const wchar_t *p;
+       if ((entry->ae_set & AE_SET_HARDLINK) && archive_mstring_get_wcs(
+           entry->archive, &entry->ae_hardlink, &p) == 0)
+               return (p);
        return (NULL);
 }
 
-ino_t
+int
+_archive_entry_hardlink_l(struct archive_entry *entry,
+    const char **p, size_t *len, struct archive_string_conv *sc)
+{
+       if ((entry->ae_set & AE_SET_HARDLINK) == 0) {
+               *p = NULL;
+               *len = 0;
+               return (0);
+       }
+       return (archive_mstring_get_mbs_l(&entry->ae_hardlink, p, len, sc));
+}
+
+int64_t
 archive_entry_ino(struct archive_entry *entry)
 {
        return (entry->ae_stat.aest_ino);
 }
 
+int
+archive_entry_ino_is_set(struct archive_entry *entry)
+{
+       return (entry->ae_set & AE_SET_INO);
+}
+
 int64_t
 archive_entry_ino64(struct archive_entry *entry)
 {
@@ -634,7 +477,7 @@ archive_entry_ino64(struct archive_entry *entry)
 mode_t
 archive_entry_mode(struct archive_entry *entry)
 {
-       return (entry->ae_stat.aest_mode);
+       return (entry->acl.mode);
 }
 
 time_t
@@ -664,13 +507,34 @@ archive_entry_nlink(struct archive_entry *entry)
 const char *
 archive_entry_pathname(struct archive_entry *entry)
 {
-       return (aes_get_mbs(&entry->ae_pathname));
+       const char *p;
+       if (archive_mstring_get_mbs(
+           entry->archive, &entry->ae_pathname, &p) == 0)
+               return (p);
+       return (NULL);
 }
 
 const wchar_t *
 archive_entry_pathname_w(struct archive_entry *entry)
 {
-       return (aes_get_wcs(&entry->ae_pathname));
+       const wchar_t *p;
+       if (archive_mstring_get_wcs(
+           entry->archive, &entry->ae_pathname, &p) == 0)
+               return (p);
+       return (NULL);
+}
+
+int
+_archive_entry_pathname_l(struct archive_entry *entry,
+    const char **p, size_t *len, struct archive_string_conv *sc)
+{
+       return (archive_mstring_get_mbs_l(&entry->ae_pathname, p, len, sc));
+}
+
+mode_t
+archive_entry_perm(struct archive_entry *entry)
+{
+       return (~AE_IFMT & entry->acl.mode);
 }
 
 dev_t
@@ -716,26 +580,56 @@ archive_entry_size_is_set(struct archive_entry *entry)
 const char *
 archive_entry_sourcepath(struct archive_entry *entry)
 {
-       return (aes_get_mbs(&entry->ae_sourcepath));
+       const char *p;
+       if (archive_mstring_get_mbs(
+           entry->archive, &entry->ae_sourcepath, &p) == 0)
+               return (p);
+       return (NULL);
+}
+
+const wchar_t *
+archive_entry_sourcepath_w(struct archive_entry *entry)
+{
+       const wchar_t *p;
+       if (archive_mstring_get_wcs(
+           entry->archive, &entry->ae_sourcepath, &p) == 0)
+               return (p);
+       return (NULL);
 }
 
 const char *
 archive_entry_symlink(struct archive_entry *entry)
 {
-       if (entry->ae_set & AE_SET_SYMLINK)
-               return (aes_get_mbs(&entry->ae_symlink));
+       const char *p;
+       if ((entry->ae_set & AE_SET_SYMLINK) && archive_mstring_get_mbs(
+           entry->archive, &entry->ae_symlink, &p) == 0)
+               return (p);
        return (NULL);
 }
 
 const wchar_t *
 archive_entry_symlink_w(struct archive_entry *entry)
 {
-       if (entry->ae_set & AE_SET_SYMLINK)
-               return (aes_get_wcs(&entry->ae_symlink));
+       const wchar_t *p;
+       if ((entry->ae_set & AE_SET_SYMLINK) && archive_mstring_get_wcs(
+           entry->archive, &entry->ae_symlink, &p) == 0)
+               return (p);
        return (NULL);
 }
 
-uid_t
+int
+_archive_entry_symlink_l(struct archive_entry *entry,
+    const char **p, size_t *len, struct archive_string_conv *sc)
+{
+       if ((entry->ae_set & AE_SET_SYMLINK) == 0) {
+               *p = NULL;
+               *len = 0;
+               return (0);
+       }
+       return (archive_mstring_get_mbs_l( &entry->ae_symlink, p, len, sc));
+}
+
+int64_t
 archive_entry_uid(struct archive_entry *entry)
 {
        return (entry->ae_stat.aest_uid);
@@ -744,13 +638,26 @@ archive_entry_uid(struct archive_entry *entry)
 const char *
 archive_entry_uname(struct archive_entry *entry)
 {
-       return (aes_get_mbs(&entry->ae_uname));
+       const char *p;
+       if (archive_mstring_get_mbs(entry->archive, &entry->ae_uname, &p) == 0)
+               return (p);
+       return (NULL);
 }
 
 const wchar_t *
 archive_entry_uname_w(struct archive_entry *entry)
 {
-       return (aes_get_wcs(&entry->ae_uname));
+       const wchar_t *p;
+       if (archive_mstring_get_wcs(entry->archive, &entry->ae_uname, &p) == 0)
+               return (p);
+       return (NULL);
+}
+
+int
+_archive_entry_uname_l(struct archive_entry *entry,
+    const char **p, size_t *len, struct archive_string_conv *sc)
+{
+       return (archive_mstring_get_mbs_l(&entry->ae_uname, p, len, sc));
 }
 
 /*
@@ -761,15 +668,15 @@ void
 archive_entry_set_filetype(struct archive_entry *entry, unsigned int type)
 {
        entry->stat_valid = 0;
-       entry->ae_stat.aest_mode &= ~AE_IFMT;
-       entry->ae_stat.aest_mode |= AE_IFMT & type;
+       entry->acl.mode &= ~AE_IFMT;
+       entry->acl.mode |= AE_IFMT & type;
 }
 
 void
 archive_entry_set_fflags(struct archive_entry *entry,
     unsigned long set, unsigned long clear)
 {
-       aes_clean(&entry->ae_fflags_text);
+       archive_mstring_clean(&entry->ae_fflags_text);
        entry->ae_fflags_set = set;
        entry->ae_fflags_clear = clear;
 }
@@ -778,7 +685,7 @@ const char *
 archive_entry_copy_fflags_text(struct archive_entry *entry,
     const char *flags)
 {
-       aes_copy_mbs(&entry->ae_fflags_text, flags);
+       archive_mstring_copy_mbs(&entry->ae_fflags_text, flags);
        return (ae_strtofflags(flags,
                    &entry->ae_fflags_set, &entry->ae_fflags_clear));
 }
@@ -787,13 +694,13 @@ const wchar_t *
 archive_entry_copy_fflags_text_w(struct archive_entry *entry,
     const wchar_t *flags)
 {
-       aes_copy_wcs(&entry->ae_fflags_text, flags);
+       archive_mstring_copy_wcs(&entry->ae_fflags_text, flags);
        return (ae_wcstofflags(flags,
                    &entry->ae_fflags_set, &entry->ae_fflags_clear));
 }
 
 void
-archive_entry_set_gid(struct archive_entry *entry, gid_t g)
+archive_entry_set_gid(struct archive_entry *entry, int64_t g)
 {
        entry->stat_valid = 0;
        entry->ae_stat.aest_gid = g;
@@ -802,31 +709,42 @@ archive_entry_set_gid(struct archive_entry *entry, gid_t g)
 void
 archive_entry_set_gname(struct archive_entry *entry, const char *name)
 {
-       aes_set_mbs(&entry->ae_gname, name);
+       archive_mstring_copy_mbs(&entry->ae_gname, name);
 }
 
 void
 archive_entry_copy_gname(struct archive_entry *entry, const char *name)
 {
-       aes_copy_mbs(&entry->ae_gname, name);
+       archive_mstring_copy_mbs(&entry->ae_gname, name);
 }
 
 void
 archive_entry_copy_gname_w(struct archive_entry *entry, const wchar_t *name)
 {
-       aes_copy_wcs(&entry->ae_gname, name);
+       archive_mstring_copy_wcs(&entry->ae_gname, name);
 }
 
 int
 archive_entry_update_gname_utf8(struct archive_entry *entry, const char *name)
 {
-       return (aes_update_utf8(&entry->ae_gname, name));
+       if (archive_mstring_update_utf8(entry->archive,
+           &entry->ae_gname, name) == 0)
+               return (1);
+       return (0);
+}
+
+int
+_archive_entry_copy_gname_l(struct archive_entry *entry,
+    const char *name, size_t len, struct archive_string_conv *sc)
+{
+       return (archive_mstring_copy_mbs_len_l(&entry->ae_gname, name, len, sc));
 }
 
 void
-archive_entry_set_ino(struct archive_entry *entry, unsigned long ino)
+archive_entry_set_ino(struct archive_entry *entry, int64_t ino)
 {
        entry->stat_valid = 0;
+       entry->ae_set |= AE_SET_INO;
        entry->ae_stat.aest_ino = ino;
 }
 
@@ -834,13 +752,14 @@ void
 archive_entry_set_ino64(struct archive_entry *entry, int64_t ino)
 {
        entry->stat_valid = 0;
+       entry->ae_set |= AE_SET_INO;
        entry->ae_stat.aest_ino = ino;
 }
 
 void
 archive_entry_set_hardlink(struct archive_entry *entry, const char *target)
 {
-       aes_set_mbs(&entry->ae_hardlink, target);
+       archive_mstring_copy_mbs(&entry->ae_hardlink, target);
        if (target != NULL)
                entry->ae_set |= AE_SET_HARDLINK;
        else
@@ -850,7 +769,7 @@ archive_entry_set_hardlink(struct archive_entry *entry, const char *target)
 void
 archive_entry_copy_hardlink(struct archive_entry *entry, const char *target)
 {
-       aes_copy_mbs(&entry->ae_hardlink, target);
+       archive_mstring_copy_mbs(&entry->ae_hardlink, target);
        if (target != NULL)
                entry->ae_set |= AE_SET_HARDLINK;
        else
@@ -860,7 +779,7 @@ archive_entry_copy_hardlink(struct archive_entry *entry, const char *target)
 void
 archive_entry_copy_hardlink_w(struct archive_entry *entry, const wchar_t *target)
 {
-       aes_copy_wcs(&entry->ae_hardlink, target);
+       archive_mstring_copy_wcs(&entry->ae_hardlink, target);
        if (target != NULL)
                entry->ae_set |= AE_SET_HARDLINK;
        else
@@ -874,12 +793,31 @@ archive_entry_update_hardlink_utf8(struct archive_entry *entry, const char *targ
                entry->ae_set |= AE_SET_HARDLINK;
        else
                entry->ae_set &= ~AE_SET_HARDLINK;
-       return (aes_update_utf8(&entry->ae_hardlink, target));
+       if (archive_mstring_update_utf8(entry->archive,
+           &entry->ae_hardlink, target) == 0)
+               return (1);
+       return (0);
+}
+
+int
+_archive_entry_copy_hardlink_l(struct archive_entry *entry,
+    const char *target, size_t len, struct archive_string_conv *sc)
+{
+       int r;
+
+       r = archive_mstring_copy_mbs_len_l(&entry->ae_hardlink,
+           target, len, sc);
+       if (target != NULL && r == 0)
+               entry->ae_set |= AE_SET_HARDLINK;
+       else
+               entry->ae_set &= ~AE_SET_HARDLINK;
+       return (r);
 }
 
 void
 archive_entry_set_atime(struct archive_entry *entry, time_t t, long ns)
 {
+       FIX_NS(t, ns);
        entry->stat_valid = 0;
        entry->ae_set |= AE_SET_ATIME;
        entry->ae_stat.aest_atime = t;
@@ -894,11 +832,12 @@ archive_entry_unset_atime(struct archive_entry *entry)
 }
 
 void
-archive_entry_set_birthtime(struct archive_entry *entry, time_t m, long ns)
+archive_entry_set_birthtime(struct archive_entry *entry, time_t t, long ns)
 {
+       FIX_NS(t, ns);
        entry->stat_valid = 0;
        entry->ae_set |= AE_SET_BIRTHTIME;
-       entry->ae_stat.aest_birthtime = m;
+       entry->ae_stat.aest_birthtime = t;
        entry->ae_stat.aest_birthtime_nsec = ns;
 }
 
@@ -912,6 +851,7 @@ archive_entry_unset_birthtime(struct archive_entry *entry)
 void
 archive_entry_set_ctime(struct archive_entry *entry, time_t t, long ns)
 {
+       FIX_NS(t, ns);
        entry->stat_valid = 0;
        entry->ae_set |= AE_SET_CTIME;
        entry->ae_stat.aest_ctime = t;
@@ -929,6 +869,7 @@ void
 archive_entry_set_dev(struct archive_entry *entry, dev_t d)
 {
        entry->stat_valid = 0;
+       entry->ae_set |= AE_SET_DEV;
        entry->ae_stat.aest_dev_is_broken_down = 0;
        entry->ae_stat.aest_dev = d;
 }
@@ -937,6 +878,7 @@ void
 archive_entry_set_devmajor(struct archive_entry *entry, dev_t m)
 {
        entry->stat_valid = 0;
+       entry->ae_set |= AE_SET_DEV;
        entry->ae_stat.aest_dev_is_broken_down = 1;
        entry->ae_stat.aest_devmajor = m;
 }
@@ -945,6 +887,7 @@ void
 archive_entry_set_devminor(struct archive_entry *entry, dev_t m)
 {
        entry->stat_valid = 0;
+       entry->ae_set |= AE_SET_DEV;
        entry->ae_stat.aest_dev_is_broken_down = 1;
        entry->ae_stat.aest_devminor = m;
 }
@@ -954,9 +897,9 @@ void
 archive_entry_set_link(struct archive_entry *entry, const char *target)
 {
        if (entry->ae_set & AE_SET_SYMLINK)
-               aes_set_mbs(&entry->ae_symlink, target);
+               archive_mstring_copy_mbs(&entry->ae_symlink, target);
        else
-               aes_set_mbs(&entry->ae_hardlink, target);
+               archive_mstring_copy_mbs(&entry->ae_hardlink, target);
 }
 
 /* Set symlink if symlink is already set, else set hardlink. */
@@ -964,9 +907,9 @@ void
 archive_entry_copy_link(struct archive_entry *entry, const char *target)
 {
        if (entry->ae_set & AE_SET_SYMLINK)
-               aes_copy_mbs(&entry->ae_symlink, target);
+               archive_mstring_copy_mbs(&entry->ae_symlink, target);
        else
-               aes_copy_mbs(&entry->ae_hardlink, target);
+               archive_mstring_copy_mbs(&entry->ae_hardlink, target);
 }
 
 /* Set symlink if symlink is already set, else set hardlink. */
@@ -974,33 +917,53 @@ void
 archive_entry_copy_link_w(struct archive_entry *entry, const wchar_t *target)
 {
        if (entry->ae_set & AE_SET_SYMLINK)
-               aes_copy_wcs(&entry->ae_symlink, target);
+               archive_mstring_copy_wcs(&entry->ae_symlink, target);
        else
-               aes_copy_wcs(&entry->ae_hardlink, target);
+               archive_mstring_copy_wcs(&entry->ae_hardlink, target);
 }
 
 int
 archive_entry_update_link_utf8(struct archive_entry *entry, const char *target)
 {
+       int r;
+       if (entry->ae_set & AE_SET_SYMLINK)
+               r = archive_mstring_update_utf8(entry->archive,
+                   &entry->ae_symlink, target);
+       else
+               r = archive_mstring_update_utf8(entry->archive,
+                   &entry->ae_hardlink, target);
+       return ((r == 0)? 1: 0);
+}
+
+int
+_archive_entry_copy_link_l(struct archive_entry *entry,
+    const char *target, size_t len, struct archive_string_conv *sc)
+{
+       int r;
+
        if (entry->ae_set & AE_SET_SYMLINK)
-               return (aes_update_utf8(&entry->ae_symlink, target));
+               r = archive_mstring_copy_mbs_len_l(&entry->ae_symlink,
+                   target, len, sc);
        else
-               return (aes_update_utf8(&entry->ae_hardlink, target));
+               r = archive_mstring_copy_mbs_len_l(&entry->ae_hardlink,
+                   target, len, sc);
+       return (r);
 }
 
 void
 archive_entry_set_mode(struct archive_entry *entry, mode_t m)
 {
        entry->stat_valid = 0;
-       entry->ae_stat.aest_mode = m;
+       entry->acl.mode = m;
 }
 
 void
-archive_entry_set_mtime(struct archive_entry *entry, time_t m, long ns)
+archive_entry_set_mtime(struct archive_entry *entry, time_t t, long ns)
 {
+       FIX_NS(t, ns);
        entry->stat_valid = 0;
        entry->ae_set |= AE_SET_MTIME;
-       entry->ae_stat.aest_mtime = m;
+       entry->ae_stat.aest_mtime = t;
        entry->ae_stat.aest_mtime_nsec = ns;
 }
 
@@ -1021,33 +984,44 @@ archive_entry_set_nlink(struct archive_entry *entry, unsigned int nlink)
 void
 archive_entry_set_pathname(struct archive_entry *entry, const char *name)
 {
-       aes_set_mbs(&entry->ae_pathname, name);
+       archive_mstring_copy_mbs(&entry->ae_pathname, name);
 }
 
 void
 archive_entry_copy_pathname(struct archive_entry *entry, const char *name)
 {
-       aes_copy_mbs(&entry->ae_pathname, name);
+       archive_mstring_copy_mbs(&entry->ae_pathname, name);
 }
 
 void
 archive_entry_copy_pathname_w(struct archive_entry *entry, const wchar_t *name)
 {
-       aes_copy_wcs(&entry->ae_pathname, name);
+       archive_mstring_copy_wcs(&entry->ae_pathname, name);
 }
 
 int
 archive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name)
 {
-       return (aes_update_utf8(&entry->ae_pathname, name));
+       if (archive_mstring_update_utf8(entry->archive,
+           &entry->ae_pathname, name) == 0)
+               return (1);
+       return (0);
+}
+
+int
+_archive_entry_copy_pathname_l(struct archive_entry *entry,
+    const char *name, size_t len, struct archive_string_conv *sc)
+{
+       return (archive_mstring_copy_mbs_len_l(&entry->ae_pathname,
+           name, len, sc));
 }
 
 void
 archive_entry_set_perm(struct archive_entry *entry, mode_t p)
 {
        entry->stat_valid = 0;
-       entry->ae_stat.aest_mode &= AE_IFMT;
-       entry->ae_stat.aest_mode |= ~AE_IFMT & p;
+       entry->acl.mode &= AE_IFMT;
+       entry->acl.mode |= ~AE_IFMT & p;
 }
 
 void
@@ -1092,13 +1066,19 @@ archive_entry_unset_size(struct archive_entry *entry)
 void
 archive_entry_copy_sourcepath(struct archive_entry *entry, const char *path)
 {
-       aes_set_mbs(&entry->ae_sourcepath, path);
+       archive_mstring_copy_mbs(&entry->ae_sourcepath, path);
+}
+
+void
+archive_entry_copy_sourcepath_w(struct archive_entry *entry, const wchar_t *path)
+{
+       archive_mstring_copy_wcs(&entry->ae_sourcepath, path);
 }
 
 void
 archive_entry_set_symlink(struct archive_entry *entry, const char *linkname)
 {
-       aes_set_mbs(&entry->ae_symlink, linkname);
+       archive_mstring_copy_mbs(&entry->ae_symlink, linkname);
        if (linkname != NULL)
                entry->ae_set |= AE_SET_SYMLINK;
        else
@@ -1108,7 +1088,7 @@ archive_entry_set_symlink(struct archive_entry *entry, const char *linkname)
 void
 archive_entry_copy_symlink(struct archive_entry *entry, const char *linkname)
 {
-       aes_copy_mbs(&entry->ae_symlink, linkname);
+       archive_mstring_copy_mbs(&entry->ae_symlink, linkname);
        if (linkname != NULL)
                entry->ae_set |= AE_SET_SYMLINK;
        else
@@ -1118,7 +1098,7 @@ archive_entry_copy_symlink(struct archive_entry *entry, const char *linkname)
 void
 archive_entry_copy_symlink_w(struct archive_entry *entry, const wchar_t *linkname)
 {
-       aes_copy_wcs(&entry->ae_symlink, linkname);
+       archive_mstring_copy_wcs(&entry->ae_symlink, linkname);
        if (linkname != NULL)
                entry->ae_set |= AE_SET_SYMLINK;
        else
@@ -1132,11 +1112,29 @@ archive_entry_update_symlink_utf8(struct archive_entry *entry, const char *linkn
                entry->ae_set |= AE_SET_SYMLINK;
        else
                entry->ae_set &= ~AE_SET_SYMLINK;
-       return (aes_update_utf8(&entry->ae_symlink, linkname));
+       if (archive_mstring_update_utf8(entry->archive,
+           &entry->ae_symlink, linkname) == 0)
+               return (1);
+       return (0);
+}
+
+int
+_archive_entry_copy_symlink_l(struct archive_entry *entry,
+    const char *linkname, size_t len, struct archive_string_conv *sc)
+{
+       int r;
+
+       r = archive_mstring_copy_mbs_len_l(&entry->ae_symlink,
+           linkname, len, sc);
+       if (linkname != NULL && r == 0)
+               entry->ae_set |= AE_SET_SYMLINK;
+       else
+               entry->ae_set &= ~AE_SET_SYMLINK;
+       return (r);
 }
 
 void
-archive_entry_set_uid(struct archive_entry *entry, uid_t u)
+archive_entry_set_uid(struct archive_entry *entry, int64_t u)
 {
        entry->stat_valid = 0;
        entry->ae_stat.aest_uid = u;
@@ -1145,25 +1143,60 @@ archive_entry_set_uid(struct archive_entry *entry, uid_t u)
 void
 archive_entry_set_uname(struct archive_entry *entry, const char *name)
 {
-       aes_set_mbs(&entry->ae_uname, name);
+       archive_mstring_copy_mbs(&entry->ae_uname, name);
 }
 
 void
 archive_entry_copy_uname(struct archive_entry *entry, const char *name)
 {
-       aes_copy_mbs(&entry->ae_uname, name);
+       archive_mstring_copy_mbs(&entry->ae_uname, name);
 }
 
 void
 archive_entry_copy_uname_w(struct archive_entry *entry, const wchar_t *name)
 {
-       aes_copy_wcs(&entry->ae_uname, name);
+       archive_mstring_copy_wcs(&entry->ae_uname, name);
 }
 
 int
 archive_entry_update_uname_utf8(struct archive_entry *entry, const char *name)
 {
-       return (aes_update_utf8(&entry->ae_uname, name));
+       if (archive_mstring_update_utf8(entry->archive,
+           &entry->ae_uname, name) == 0)
+               return (1);
+       return (0);
+}
+
+int
+_archive_entry_copy_uname_l(struct archive_entry *entry,
+    const char *name, size_t len, struct archive_string_conv *sc)
+{
+       return (archive_mstring_copy_mbs_len_l(&entry->ae_uname,
+           name, len, sc));
+}
+
+const void *
+archive_entry_mac_metadata(struct archive_entry *entry, size_t *s)
+{
+  *s = entry->mac_metadata_size;
+  return entry->mac_metadata;
+}
+
+void
+archive_entry_copy_mac_metadata(struct archive_entry *entry,
+    const void *p, size_t s)
+{
+  free(entry->mac_metadata);
+  if (p == NULL || s == 0) {
+    entry->mac_metadata = NULL;
+    entry->mac_metadata_size = 0;
+  } else {
+    entry->mac_metadata_size = s;
+    entry->mac_metadata = malloc(s);
+    if (entry->mac_metadata == NULL)
+      abort();
+    memcpy(entry->mac_metadata, p, s);
+  }
 }
 
 /*
@@ -1175,148 +1208,37 @@ archive_entry_update_uname_utf8(struct archive_entry *entry, const char *name)
  * uninitiated.
  */
 
+struct archive_acl *
+archive_entry_acl(struct archive_entry *entry)
+{
+       return &entry->acl;
+}
+
 void
 archive_entry_acl_clear(struct archive_entry *entry)
 {
-       struct ae_acl   *ap;
-
-       while (entry->acl_head != NULL) {
-               ap = entry->acl_head->next;
-               aes_clean(&entry->acl_head->name);
-               free(entry->acl_head);
-               entry->acl_head = ap;
-       }
-       if (entry->acl_text_w != NULL) {
-               free(entry->acl_text_w);
-               entry->acl_text_w = NULL;
-       }
-       entry->acl_p = NULL;
-       entry->acl_state = 0; /* Not counting. */
+       archive_acl_clear(&entry->acl);
 }
 
 /*
  * Add a single ACL entry to the internal list of ACL data.
  */
-void
+int
 archive_entry_acl_add_entry(struct archive_entry *entry,
     int type, int permset, int tag, int id, const char *name)
 {
-       struct ae_acl *ap;
-
-       if (acl_special(entry, type, permset, tag) == 0)
-               return;
-       ap = acl_new_entry(entry, type, permset, tag, id);
-       if (ap == NULL) {
-               /* XXX Error XXX */
-               return;
-       }
-       if (name != NULL  &&  *name != '\0')
-               aes_copy_mbs(&ap->name, name);
-       else
-               aes_clean(&ap->name);
+       return archive_acl_add_entry(&entry->acl, type, permset, tag, id, name);
 }
 
 /*
  * As above, but with a wide-character name.
  */
-void
+int
 archive_entry_acl_add_entry_w(struct archive_entry *entry,
     int type, int permset, int tag, int id, const wchar_t *name)
 {
-       archive_entry_acl_add_entry_w_len(entry, type, permset, tag, id, name, wcslen(name));
-}
-
-static void
-archive_entry_acl_add_entry_w_len(struct archive_entry *entry,
-    int type, int permset, int tag, int id, const wchar_t *name, size_t len)
-{
-       struct ae_acl *ap;
-
-       if (acl_special(entry, type, permset, tag) == 0)
-               return;
-       ap = acl_new_entry(entry, type, permset, tag, id);
-       if (ap == NULL) {
-               /* XXX Error XXX */
-               return;
-       }
-       if (name != NULL  &&  *name != L'\0' && len > 0)
-               aes_copy_wcs_len(&ap->name, name, len);
-       else
-               aes_clean(&ap->name);
-}
-
-/*
- * If this ACL entry is part of the standard POSIX permissions set,
- * store the permissions in the stat structure and return zero.
- */
-static int
-acl_special(struct archive_entry *entry, int type, int permset, int tag)
-{
-       if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) {
-               switch (tag) {
-               case ARCHIVE_ENTRY_ACL_USER_OBJ:
-                       entry->ae_stat.aest_mode &= ~0700;
-                       entry->ae_stat.aest_mode |= (permset & 7) << 6;
-                       return (0);
-               case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
-                       entry->ae_stat.aest_mode &= ~0070;
-                       entry->ae_stat.aest_mode |= (permset & 7) << 3;
-                       return (0);
-               case ARCHIVE_ENTRY_ACL_OTHER:
-                       entry->ae_stat.aest_mode &= ~0007;
-                       entry->ae_stat.aest_mode |= permset & 7;
-                       return (0);
-               }
-       }
-       return (1);
-}
-
-/*
- * Allocate and populate a new ACL entry with everything but the
- * name.
- */
-static struct ae_acl *
-acl_new_entry(struct archive_entry *entry,
-    int type, int permset, int tag, int id)
-{
-       struct ae_acl *ap, *aq;
-
-       if (type != ARCHIVE_ENTRY_ACL_TYPE_ACCESS &&
-           type != ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)
-               return (NULL);
-       if (entry->acl_text_w != NULL) {
-               free(entry->acl_text_w);
-               entry->acl_text_w = NULL;
-       }
-
-       /* XXX TODO: More sanity-checks on the arguments XXX */
-
-       /* If there's a matching entry already in the list, overwrite it. */
-       ap = entry->acl_head;
-       aq = NULL;
-       while (ap != NULL) {
-               if (ap->type == type && ap->tag == tag && ap->id == id) {
-                       ap->permset = permset;
-                       return (ap);
-               }
-               aq = ap;
-               ap = ap->next;
-       }
-
-       /* Add a new entry to the end of the list. */
-       ap = (struct ae_acl *)malloc(sizeof(*ap));
-       if (ap == NULL)
-               return (NULL);
-       memset(ap, 0, sizeof(*ap));
-       if (aq == NULL)
-               entry->acl_head = ap;
-       else
-               aq->next = ap;
-       ap->type = type;
-       ap->tag = tag;
-       ap->id = id;
-       ap->permset = permset;
-       return (ap);
+       return archive_acl_add_entry_w_len(&entry->acl,
+           type, permset, tag, id, name, wcslen(name));
 }
 
 /*
@@ -1325,20 +1247,7 @@ acl_new_entry(struct archive_entry *entry,
 int
 archive_entry_acl_count(struct archive_entry *entry, int want_type)
 {
-       int count;
-       struct ae_acl *ap;
-
-       count = 0;
-       ap = entry->acl_head;
-       while (ap != NULL) {
-               if ((ap->type & want_type) != 0)
-                       count++;
-               ap = ap->next;
-       }
-
-       if (count > 0 && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0))
-               count += 3;
-       return (count);
+       return archive_acl_count(&entry->acl, want_type);
 }
 
 /*
@@ -1349,93 +1258,18 @@ archive_entry_acl_count(struct archive_entry *entry, int want_type)
 int
 archive_entry_acl_reset(struct archive_entry *entry, int want_type)
 {
-       int count, cutoff;
-
-       count = archive_entry_acl_count(entry, want_type);
-
-       /*
-        * If the only entries are the three standard ones,
-        * then don't return any ACL data.  (In this case,
-        * client can just use chmod(2) to set permissions.)
-        */
-       if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)
-               cutoff = 3;
-       else
-               cutoff = 0;
-
-       if (count > cutoff)
-               entry->acl_state = ARCHIVE_ENTRY_ACL_USER_OBJ;
-       else
-               entry->acl_state = 0;
-       entry->acl_p = entry->acl_head;
-       return (count);
+       return archive_acl_reset(&entry->acl, want_type);
 }
 
 /*
  * Return the next ACL entry in the list.  Fake entries for the
  * standard permissions and include them in the returned list.
  */
-
 int
 archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
     int *permset, int *tag, int *id, const char **name)
 {
-       *name = NULL;
-       *id = -1;
-
-       /*
-        * The acl_state is either zero (no entries available), -1
-        * (reading from list), or an entry type (retrieve that type
-        * from ae_stat.aest_mode).
-        */
-       if (entry->acl_state == 0)
-               return (ARCHIVE_WARN);
-
-       /* The first three access entries are special. */
-       if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
-               switch (entry->acl_state) {
-               case ARCHIVE_ENTRY_ACL_USER_OBJ:
-                       *permset = (entry->ae_stat.aest_mode >> 6) & 7;
-                       *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
-                       *tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
-                       entry->acl_state = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
-                       return (ARCHIVE_OK);
-               case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
-                       *permset = (entry->ae_stat.aest_mode >> 3) & 7;
-                       *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
-                       *tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
-                       entry->acl_state = ARCHIVE_ENTRY_ACL_OTHER;
-                       return (ARCHIVE_OK);
-               case ARCHIVE_ENTRY_ACL_OTHER:
-                       *permset = entry->ae_stat.aest_mode & 7;
-                       *type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
-                       *tag = ARCHIVE_ENTRY_ACL_OTHER;
-                       entry->acl_state = -1;
-                       entry->acl_p = entry->acl_head;
-                       return (ARCHIVE_OK);
-               default:
-                       break;
-               }
-       }
-
-       while (entry->acl_p != NULL && (entry->acl_p->type & want_type) == 0)
-               entry->acl_p = entry->acl_p->next;
-       if (entry->acl_p == NULL) {
-               entry->acl_state = 0;
-               *type = 0;
-               *permset = 0;
-               *tag = 0;
-               *id = -1;
-               *name = NULL;
-               return (ARCHIVE_EOF); /* End of ACL entries. */
-       }
-       *type = entry->acl_p->type;
-       *permset = entry->acl_p->permset;
-       *tag = entry->acl_p->tag;
-       *id = entry->acl_p->id;
-       *name = aes_get_mbs(&entry->acl_p->name);
-       entry->acl_p = entry->acl_p->next;
-       return (ARCHIVE_OK);
+       return archive_acl_next(entry->archive, &entry->acl, want_type, type, permset, tag, id, name);
 }
 
 /*
@@ -1445,411 +1279,26 @@ archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
 const wchar_t *
 archive_entry_acl_text_w(struct archive_entry *entry, int flags)
 {
-       int count;
-       size_t length;
-       const wchar_t *wname;
-       const wchar_t *prefix;
-       wchar_t separator;
-       struct ae_acl *ap;
-       int id;
-       wchar_t *wp;
-
-       if (entry->acl_text_w != NULL) {
-               free (entry->acl_text_w);
-               entry->acl_text_w = NULL;
-       }
-
-       separator = L',';
-       count = 0;
-       length = 0;
-       ap = entry->acl_head;
-       while (ap != NULL) {
-               if ((ap->type & flags) != 0) {
-                       count++;
-                       if ((flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) &&
-                           (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT))
-                               length += 8; /* "default:" */
-                       length += 5; /* tag name */
-                       length += 1; /* colon */
-                       wname = aes_get_wcs(&ap->name);
-                       if (wname != NULL)
-                               length += wcslen(wname);
-                       else
-                               length += sizeof(uid_t) * 3 + 1;
-                       length ++; /* colon */
-                       length += 3; /* rwx */
-                       length += 1; /* colon */
-                       length += max(sizeof(uid_t), sizeof(gid_t)) * 3 + 1;
-                       length ++; /* newline */
-               }
-               ap = ap->next;
-       }
-
-       if (count > 0 && ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) {
-               length += 10; /* "user::rwx\n" */
-               length += 11; /* "group::rwx\n" */
-               length += 11; /* "other::rwx\n" */
-       }
-
-       if (count == 0)
-               return (NULL);
-
-       /* Now, allocate the string and actually populate it. */
-       wp = entry->acl_text_w = (wchar_t *)malloc(length * sizeof(wchar_t));
-       if (wp == NULL)
-               __archive_errx(1, "No memory to generate the text version of the ACL");
-       count = 0;
-       if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
-               append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
-                   entry->ae_stat.aest_mode & 0700, -1);
-               *wp++ = ',';
-               append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_GROUP_OBJ, NULL,
-                   entry->ae_stat.aest_mode & 0070, -1);
-               *wp++ = ',';
-               append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_OTHER, NULL,
-                   entry->ae_stat.aest_mode & 0007, -1);
-               count += 3;
-
-               ap = entry->acl_head;
-               while (ap != NULL) {
-                       if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
-                               wname = aes_get_wcs(&ap->name);
-                               *wp++ = separator;
-                               if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
-                                       id = ap->id;
-                               else
-                                       id = -1;
-                               append_entry_w(&wp, NULL, ap->tag, wname,
-                                   ap->permset, id);
-                               count++;
-                       }
-                       ap = ap->next;
-               }
-       }
-
-
-       if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
-               if (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT)
-                       prefix = L"default:";
-               else
-                       prefix = NULL;
-               ap = entry->acl_head;
-               count = 0;
-               while (ap != NULL) {
-                       if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
-                               wname = aes_get_wcs(&ap->name);
-                               if (count > 0)
-                                       *wp++ = separator;
-                               if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
-                                       id = ap->id;
-                               else
-                                       id = -1;
-                               append_entry_w(&wp, prefix, ap->tag,
-                                   wname, ap->permset, id);
-                               count ++;
-                       }
-                       ap = ap->next;
-               }
-       }
-
-       return (entry->acl_text_w);
-}
-
-static void
-append_id_w(wchar_t **wp, int id)
-{
-       if (id < 0)
-               id = 0;
-       if (id > 9)
-               append_id_w(wp, id / 10);
-       *(*wp)++ = L"0123456789"[id % 10];
+       return archive_acl_text_w(entry->archive, &entry->acl, flags);
 }
 
-static void
-append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
-    const wchar_t *wname, int perm, int id)
+const char *
+archive_entry_acl_text(struct archive_entry *entry, int flags)
 {
-       if (prefix != NULL) {
-               wcscpy(*wp, prefix);
-               *wp += wcslen(*wp);
-       }
-       switch (tag) {
-       case ARCHIVE_ENTRY_ACL_USER_OBJ:
-               wname = NULL;
-               id = -1;
-               /* FALLTHROUGH */
-       case ARCHIVE_ENTRY_ACL_USER:
-               wcscpy(*wp, L"user");
-               break;
-       case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
-               wname = NULL;
-               id = -1;
-               /* FALLTHROUGH */
-       case ARCHIVE_ENTRY_ACL_GROUP:
-               wcscpy(*wp, L"group");
-               break;
-       case ARCHIVE_ENTRY_ACL_MASK:
-               wcscpy(*wp, L"mask");
-               wname = NULL;
-               id = -1;
-               break;
-       case ARCHIVE_ENTRY_ACL_OTHER:
-               wcscpy(*wp, L"other");
-               wname = NULL;
-               id = -1;
-               break;
-       }
-       *wp += wcslen(*wp);
-       *(*wp)++ = L':';
-       if (wname != NULL) {
-               wcscpy(*wp, wname);
-               *wp += wcslen(*wp);
-       } else if (tag == ARCHIVE_ENTRY_ACL_USER
-           || tag == ARCHIVE_ENTRY_ACL_GROUP) {
-               append_id_w(wp, id);
-               id = -1;
-       }
-       *(*wp)++ = L':';
-       *(*wp)++ = (perm & 0444) ? L'r' : L'-';
-       *(*wp)++ = (perm & 0222) ? L'w' : L'-';
-       *(*wp)++ = (perm & 0111) ? L'x' : L'-';
-       if (id != -1) {
-               *(*wp)++ = L':';
-               append_id_w(wp, id);
-       }
-       **wp = L'\0';
+       const char *p;
+       if (archive_acl_text_l(&entry->acl, flags, &p, NULL, NULL) != 0
+           && errno == ENOMEM)
+               return (NULL);
+       return (p);
 }
 
-/*
- * Parse a textual ACL.  This automatically recognizes and supports
- * extensions described above.  The 'type' argument is used to
- * indicate the type that should be used for any entries not
- * explicitly marked as "default:".
- */
 int
-__archive_entry_acl_parse_w(struct archive_entry *entry,
-    const wchar_t *text, int default_type)
-{
-       struct {
-               const wchar_t *start;
-               const wchar_t *end;
-       } field[4], name;
-
-       int fields, n;
-       int type, tag, permset, id;
-       wchar_t sep;
-
-       while (text != NULL  &&  *text != L'\0') {
-               /*
-                * Parse the fields out of the next entry,
-                * advance 'text' to start of next entry.
-                */
-               fields = 0;
-               do {
-                       const wchar_t *start, *end;
-                       next_field_w(&text, &start, &end, &sep);
-                       if (fields < 4) {
-                               field[fields].start = start;
-                               field[fields].end = end;
-                       }
-                       ++fields;
-               } while (sep == L':');
-
-               /* Set remaining fields to blank. */
-               for (n = fields; n < 4; ++n)
-                       field[n].start = field[n].end = NULL;
-
-               /* Check for a numeric ID in field 1 or 3. */
-               id = -1;
-               isint_w(field[1].start, field[1].end, &id);
-               /* Field 3 is optional. */
-               if (id == -1 && fields > 3)
-                       isint_w(field[3].start, field[3].end, &id);
-
-               /*
-                * Solaris extension:  "defaultuser::rwx" is the
-                * default ACL corresponding to "user::rwx", etc.
-                */
-               if (field[0].end - field[0].start > 7
-                   && wmemcmp(field[0].start, L"default", 7) == 0) {
-                       type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
-                       field[0].start += 7;
-               } else
-                       type = default_type;
-
-               name.start = name.end = NULL;
-               if (prefix_w(field[0].start, field[0].end, L"user")) {
-                       if (!ismode_w(field[2].start, field[2].end, &permset))
-                               return (ARCHIVE_WARN);
-                       if (id != -1 || field[1].start < field[1].end) {
-                               tag = ARCHIVE_ENTRY_ACL_USER;
-                               name = field[1];
-                       } else
-                               tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
-               } else if (prefix_w(field[0].start, field[0].end, L"group")) {
-                       if (!ismode_w(field[2].start, field[2].end, &permset))
-                               return (ARCHIVE_WARN);
-                       if (id != -1 || field[1].start < field[1].end) {
-                               tag = ARCHIVE_ENTRY_ACL_GROUP;
-                               name = field[1];
-                       } else
-                               tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
-               } else if (prefix_w(field[0].start, field[0].end, L"other")) {
-                       if (fields == 2
-                           && field[1].start < field[1].end
-                           && ismode_w(field[1].start, field[1].end, &permset)) {
-                               /* This is Solaris-style "other:rwx" */
-                       } else if (fields == 3
-                           && field[1].start == field[1].end
-                           && field[2].start < field[2].end
-                           && ismode_w(field[2].start, field[2].end, &permset)) {
-                               /* This is FreeBSD-style "other::rwx" */
-                       } else
-                               return (ARCHIVE_WARN);
-                       tag = ARCHIVE_ENTRY_ACL_OTHER;
-               } else if (prefix_w(field[0].start, field[0].end, L"mask")) {
-                       if (fields == 2
-                           && field[1].start < field[1].end
-                           && ismode_w(field[1].start, field[1].end, &permset)) {
-                               /* This is Solaris-style "mask:rwx" */
-                       } else if (fields == 3
-                           && field[1].start == field[1].end
-                           && field[2].start < field[2].end
-                           && ismode_w(field[2].start, field[2].end, &permset)) {
-                               /* This is FreeBSD-style "mask::rwx" */
-                       } else
-                               return (ARCHIVE_WARN);
-                       tag = ARCHIVE_ENTRY_ACL_MASK;
-               } else
-                       return (ARCHIVE_WARN);
-
-               /* Add entry to the internal list. */
-               archive_entry_acl_add_entry_w_len(entry, type, permset,
-                   tag, id, name.start, name.end - name.start);
-       }
-       return (ARCHIVE_OK);
-}
-
-/*
- * Parse a string to a positive decimal integer.  Returns true if
- * the string is non-empty and consists only of decimal digits,
- * false otherwise.
- */
-static int
-isint_w(const wchar_t *start, const wchar_t *end, int *result)
-{
-       int n = 0;
-       if (start >= end)
-               return (0);
-       while (start < end) {
-               if (*start < '0' || *start > '9')
-                       return (0);
-               if (n > (INT_MAX / 10))
-                       n = INT_MAX;
-               else {
-                       n *= 10;
-                       n += *start - '0';
-               }
-               start++;
-       }
-       *result = n;
-       return (1);
-}
-
-/*
- * Parse a string as a mode field.  Returns true if
- * the string is non-empty and consists only of mode characters,
- * false otherwise.
- */
-static int
-ismode_w(const wchar_t *start, const wchar_t *end, int *permset)
+_archive_entry_acl_text_l(struct archive_entry *entry, int flags,
+    const char **acl_text, size_t *len, struct archive_string_conv *sc)
 {
-       const wchar_t *p;
-
-       if (start >= end)
-               return (0);
-       p = start;
-       *permset = 0;
-       while (p < end) {
-               switch (*p++) {
-               case 'r': case 'R':
-                       *permset |= ARCHIVE_ENTRY_ACL_READ;
-                       break;
-               case 'w': case 'W':
-                       *permset |= ARCHIVE_ENTRY_ACL_WRITE;
-                       break;
-               case 'x': case 'X':
-                       *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
-                       break;
-               case '-':
-                       break;
-               default:
-                       return (0);
-               }
-       }
-       return (1);
+       return (archive_acl_text_l(&entry->acl, flags, acl_text, len, sc));
 }
 
-/*
- * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]".  *wp is updated
- * to point to just after the separator.  *start points to the first
- * character of the matched text and *end just after the last
- * character of the matched identifier.  In particular *end - *start
- * is the length of the field body, not including leading or trailing
- * whitespace.
- */
-static void
-next_field_w(const wchar_t **wp, const wchar_t **start,
-    const wchar_t **end, wchar_t *sep)
-{
-       /* Skip leading whitespace to find start of field. */
-       while (**wp == L' ' || **wp == L'\t' || **wp == L'\n') {
-               (*wp)++;
-       }
-       *start = *wp;
-
-       /* Scan for the separator. */
-       while (**wp != L'\0' && **wp != L',' && **wp != L':' &&
-           **wp != L'\n') {
-               (*wp)++;
-       }
-       *sep = **wp;
-
-       /* Trim trailing whitespace to locate end of field. */
-       *end = *wp - 1;
-       while (**end == L' ' || **end == L'\t' || **end == L'\n') {
-               (*end)--;
-       }
-       (*end)++;
-
-       /* Adjust scanner location. */
-       if (**wp != L'\0')
-               (*wp)++;
-}
-
-/*
- * Return true if the characters [start...end) are a prefix of 'test'.
- * This makes it easy to handle the obvious abbreviations: 'u' for 'user', etc.
- */
-static int
-prefix_w(const wchar_t *start, const wchar_t *end, const wchar_t *test)
-{
-       if (start == end)
-               return (0);
-
-       if (*start++ != *test++)
-               return (0);
-
-       while (start < end  &&  *start++ == *test++)
-               ;
-
-       if (start < end)
-               return (0);
-
-       return (1);
-}
-
-
 /*
  * Following code is modified from UC Berkeley sources, and
  * is subject to the following copyright notice.
index d572817..533dc7f 100644 (file)
@@ -28,6 +28,9 @@
 #ifndef ARCHIVE_ENTRY_H_INCLUDED
 #define        ARCHIVE_ENTRY_H_INCLUDED
 
+/* Note: Compiler will complain if this does not match archive.h! */
+#define        ARCHIVE_VERSION_NUMBER 3000002
+
 /*
  * Note: archive_entry.h is for use outside of libarchive; the
  * configuration headers (config.h, archive_platform.h, etc.) are
 #if defined(_WIN32) && !defined(__CYGWIN__)
 #define        __LA_INT64_T    __int64
 # if defined(__BORLANDC__)
-#  define      __LA_UID_T      uid_t
-#  define      __LA_GID_T      gid_t
+#  define      __LA_UID_T      uid_t  /* Remove in libarchive 3.2 */
+#  define      __LA_GID_T      gid_t  /* Remove in libarchive 3.2 */
 #  define      __LA_DEV_T      dev_t
 #  define      __LA_MODE_T     mode_t
 # else
-#  define      __LA_UID_T      short
-#  define      __LA_GID_T      short
+#  define      __LA_UID_T      short  /* Remove in libarchive 3.2 */
+#  define      __LA_GID_T      short  /* Remove in libarchive 3.2 */
 #  define      __LA_DEV_T      unsigned int
 #  define      __LA_MODE_T     unsigned short
 # endif
 #else
 #include <unistd.h>
-#define        __LA_INT64_T    int64_t
-#define        __LA_UID_T      uid_t
-#define        __LA_GID_T      gid_t
-#define        __LA_DEV_T      dev_t
-#define        __LA_MODE_T     mode_t
+# if defined(_SCO_DS)
+#  define      __LA_INT64_T    long long
+# else
+#  define      __LA_INT64_T    int64_t
+# endif
+# define       __LA_UID_T      uid_t /* Remove in libarchive 3.2 */
+# define       __LA_GID_T      gid_t /* Remove in libarchive 3.2 */
+# define       __LA_DEV_T      dev_t
+# define       __LA_MODE_T     mode_t
 #endif
 
 /*
- * XXX Is this defined for all Windows compilers?  If so, in what
- * header?  It would be nice to remove the __LA_INO_T indirection and
- * just use plain ino_t everywhere.  Likewise for the other types just
- * above.
+ * Remove this for libarchive 3.2, since ino_t is no longer used.
  */
 #define        __LA_INO_T      ino_t
 
@@ -91,7 +95,7 @@
 #  endif
 # else
 #  ifdef __GNUC__
-#   define __LA_DECL   __attribute__((dllimport)) extern
+#   define __LA_DECL
 #  else
 #   define __LA_DECL   __declspec(dllimport)
 #  endif
@@ -121,6 +125,7 @@ extern "C" {
  * applications (e.g., a package manager could attach special
  * package-management attributes to each entry).
  */
+struct archive;
 struct archive_entry;
 
 /*
@@ -163,6 +168,15 @@ __LA_DECL struct archive_entry     *archive_entry_clone(struct archive_entry *);
 __LA_DECL void                  archive_entry_free(struct archive_entry *);
 __LA_DECL struct archive_entry *archive_entry_new(void);
 
+/*
+ * This form of archive_entry_new2() will pull character-set
+ * conversion information from the specified archive handle.  The
+ * older archive_entry_new(void) form is equivalent to calling
+ * archive_entry_new2(NULL) and will result in the use of an internal
+ * default character-set conversion.
+ */
+__LA_DECL struct archive_entry *archive_entry_new2(struct archive *);
+
 /*
  * Retrieve fields from an archive_entry.
  *
@@ -192,6 +206,7 @@ __LA_DECL time_t     archive_entry_ctime(struct archive_entry *);
 __LA_DECL long          archive_entry_ctime_nsec(struct archive_entry *);
 __LA_DECL int           archive_entry_ctime_is_set(struct archive_entry *);
 __LA_DECL dev_t                 archive_entry_dev(struct archive_entry *);
+__LA_DECL int           archive_entry_dev_is_set(struct archive_entry *);
 __LA_DECL dev_t                 archive_entry_devmajor(struct archive_entry *);
 __LA_DECL dev_t                 archive_entry_devminor(struct archive_entry *);
 __LA_DECL __LA_MODE_T   archive_entry_filetype(struct archive_entry *);
@@ -199,13 +214,14 @@ __LA_DECL void             archive_entry_fflags(struct archive_entry *,
                            unsigned long * /* set */,
                            unsigned long * /* clear */);
 __LA_DECL const char   *archive_entry_fflags_text(struct archive_entry *);
-__LA_DECL __LA_GID_T    archive_entry_gid(struct archive_entry *);
+__LA_DECL __LA_INT64_T  archive_entry_gid(struct archive_entry *);
 __LA_DECL const char   *archive_entry_gname(struct archive_entry *);
 __LA_DECL const wchar_t        *archive_entry_gname_w(struct archive_entry *);
 __LA_DECL const char   *archive_entry_hardlink(struct archive_entry *);
 __LA_DECL const wchar_t        *archive_entry_hardlink_w(struct archive_entry *);
-__LA_DECL __LA_INO_T    archive_entry_ino(struct archive_entry *);
+__LA_DECL __LA_INT64_T  archive_entry_ino(struct archive_entry *);
 __LA_DECL __LA_INT64_T  archive_entry_ino64(struct archive_entry *);
+__LA_DECL int           archive_entry_ino_is_set(struct archive_entry *);
 __LA_DECL __LA_MODE_T   archive_entry_mode(struct archive_entry *);
 __LA_DECL time_t        archive_entry_mtime(struct archive_entry *);
 __LA_DECL long          archive_entry_mtime_nsec(struct archive_entry *);
@@ -213,35 +229,34 @@ __LA_DECL int              archive_entry_mtime_is_set(struct archive_entry *);
 __LA_DECL unsigned int  archive_entry_nlink(struct archive_entry *);
 __LA_DECL const char   *archive_entry_pathname(struct archive_entry *);
 __LA_DECL const wchar_t        *archive_entry_pathname_w(struct archive_entry *);
+__LA_DECL __LA_MODE_T   archive_entry_perm(struct archive_entry *);
 __LA_DECL dev_t                 archive_entry_rdev(struct archive_entry *);
 __LA_DECL dev_t                 archive_entry_rdevmajor(struct archive_entry *);
 __LA_DECL dev_t                 archive_entry_rdevminor(struct archive_entry *);
 __LA_DECL const char   *archive_entry_sourcepath(struct archive_entry *);
+__LA_DECL const wchar_t        *archive_entry_sourcepath_w(struct archive_entry *);
 __LA_DECL __LA_INT64_T  archive_entry_size(struct archive_entry *);
 __LA_DECL int           archive_entry_size_is_set(struct archive_entry *);
 __LA_DECL const char   *archive_entry_strmode(struct archive_entry *);
 __LA_DECL const char   *archive_entry_symlink(struct archive_entry *);
 __LA_DECL const wchar_t        *archive_entry_symlink_w(struct archive_entry *);
-__LA_DECL __LA_UID_T    archive_entry_uid(struct archive_entry *);
+__LA_DECL __LA_INT64_T  archive_entry_uid(struct archive_entry *);
 __LA_DECL const char   *archive_entry_uname(struct archive_entry *);
 __LA_DECL const wchar_t        *archive_entry_uname_w(struct archive_entry *);
 
 /*
  * Set fields in an archive_entry.
  *
- * Note that string 'set' functions do not copy the string, only the pointer.
- * In contrast, 'copy' functions do copy the object pointed to.
- *
- * Note: As of libarchive 2.4, 'set' functions do copy the string and
- * are therefore exact synonyms for the 'copy' versions.  The 'copy'
- * names will be retired in libarchive 3.0.
+ * Note: Before libarchive 2.4, there were 'set' and 'copy' versions
+ * of the string setters.  'copy' copied the actual string, 'set' just
+ * stored the pointer.  In libarchive 2.4 and later, strings are
+ * always copied.
  */
 
 __LA_DECL void archive_entry_set_atime(struct archive_entry *, time_t, long);
 __LA_DECL void  archive_entry_unset_atime(struct archive_entry *);
 #if defined(_WIN32) && !defined(__CYGWIN__)
-__LA_DECL void archive_entry_copy_bhfi(struct archive_entry *,
-                                                                          BY_HANDLE_FILE_INFORMATION *);
+__LA_DECL void archive_entry_copy_bhfi(struct archive_entry *, BY_HANDLE_FILE_INFORMATION *);
 #endif
 __LA_DECL void archive_entry_set_birthtime(struct archive_entry *, time_t, long);
 __LA_DECL void  archive_entry_unset_birthtime(struct archive_entry *);
@@ -259,7 +274,7 @@ __LA_DECL const char *archive_entry_copy_fflags_text(struct archive_entry *,
            const char *);
 __LA_DECL const wchar_t *archive_entry_copy_fflags_text_w(struct archive_entry *,
            const wchar_t *);
-__LA_DECL void archive_entry_set_gid(struct archive_entry *, __LA_GID_T);
+__LA_DECL void archive_entry_set_gid(struct archive_entry *, __LA_INT64_T);
 __LA_DECL void archive_entry_set_gname(struct archive_entry *, const char *);
 __LA_DECL void archive_entry_copy_gname(struct archive_entry *, const char *);
 __LA_DECL void archive_entry_copy_gname_w(struct archive_entry *, const wchar_t *);
@@ -268,12 +283,7 @@ __LA_DECL void     archive_entry_set_hardlink(struct archive_entry *, const char *);
 __LA_DECL void archive_entry_copy_hardlink(struct archive_entry *, const char *);
 __LA_DECL void archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *);
 __LA_DECL int  archive_entry_update_hardlink_utf8(struct archive_entry *, const char *);
-#if ARCHIVE_VERSION_NUMBER >= 3000000
-/* Starting with libarchive 3.0, this will be synonym for ino64. */
 __LA_DECL void archive_entry_set_ino(struct archive_entry *, __LA_INT64_T);
-#else
-__LA_DECL void archive_entry_set_ino(struct archive_entry *, unsigned long);
-#endif
 __LA_DECL void archive_entry_set_ino64(struct archive_entry *, __LA_INT64_T);
 __LA_DECL void archive_entry_set_link(struct archive_entry *, const char *);
 __LA_DECL void archive_entry_copy_link(struct archive_entry *, const char *);
@@ -294,11 +304,12 @@ __LA_DECL void    archive_entry_set_rdevminor(struct archive_entry *, dev_t);
 __LA_DECL void archive_entry_set_size(struct archive_entry *, __LA_INT64_T);
 __LA_DECL void archive_entry_unset_size(struct archive_entry *);
 __LA_DECL void archive_entry_copy_sourcepath(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_copy_sourcepath_w(struct archive_entry *, const wchar_t *);
 __LA_DECL void archive_entry_set_symlink(struct archive_entry *, const char *);
 __LA_DECL void archive_entry_copy_symlink(struct archive_entry *, const char *);
 __LA_DECL void archive_entry_copy_symlink_w(struct archive_entry *, const wchar_t *);
 __LA_DECL int  archive_entry_update_symlink_utf8(struct archive_entry *, const char *);
-__LA_DECL void archive_entry_set_uid(struct archive_entry *, __LA_UID_T);
+__LA_DECL void archive_entry_set_uid(struct archive_entry *, __LA_INT64_T);
 __LA_DECL void archive_entry_set_uname(struct archive_entry *, const char *);
 __LA_DECL void archive_entry_copy_uname(struct archive_entry *, const char *);
 __LA_DECL void archive_entry_copy_uname_w(struct archive_entry *, const wchar_t *);
@@ -315,6 +326,15 @@ __LA_DECL int      archive_entry_update_uname_utf8(struct archive_entry *, const char
 __LA_DECL const struct stat    *archive_entry_stat(struct archive_entry *);
 __LA_DECL void archive_entry_copy_stat(struct archive_entry *, const struct stat *);
 
+/*
+ * Storage for Mac OS-specific AppleDouble metadata information.
+ * Apple-format tar files store a separate binary blob containing
+ * encoded metadata with ACL, extended attributes, etc.
+ * This provides a place to store that blob.
+ */
+
+__LA_DECL const void * archive_entry_mac_metadata(struct archive_entry *, size_t *);
+__LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const void *, size_t);
 
 /*
  * ACL routines.  This used to simply store and return text-format ACL
@@ -326,32 +346,95 @@ __LA_DECL void    archive_entry_copy_stat(struct archive_entry *, const struct stat
  *
  *  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.
  */
 
 /*
- * Permission bits mimic POSIX.1e.  Note that I've not followed POSIX.1e's
- * "permset"/"perm" abstract type nonsense.  A permset is just a simple
- * bitmap, following long-standing Unix tradition.
+ * Permission bits.
  */
-#define        ARCHIVE_ENTRY_ACL_EXECUTE       1
-#define        ARCHIVE_ENTRY_ACL_WRITE         2
-#define        ARCHIVE_ENTRY_ACL_READ          4
+#define        ARCHIVE_ENTRY_ACL_EXECUTE             0x00000001
+#define        ARCHIVE_ENTRY_ACL_WRITE               0x00000002
+#define        ARCHIVE_ENTRY_ACL_READ                0x00000004
+#define        ARCHIVE_ENTRY_ACL_READ_DATA           0x00000008
+#define        ARCHIVE_ENTRY_ACL_LIST_DIRECTORY      0x00000008
+#define        ARCHIVE_ENTRY_ACL_WRITE_DATA          0x00000010
+#define        ARCHIVE_ENTRY_ACL_ADD_FILE            0x00000010
+#define        ARCHIVE_ENTRY_ACL_APPEND_DATA         0x00000020
+#define        ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY    0x00000020
+#define        ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS    0x00000040
+#define        ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS   0x00000080
+#define        ARCHIVE_ENTRY_ACL_DELETE_CHILD        0x00000100
+#define        ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES     0x00000200
+#define        ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES    0x00000400
+#define        ARCHIVE_ENTRY_ACL_DELETE              0x00000800
+#define        ARCHIVE_ENTRY_ACL_READ_ACL            0x00001000
+#define        ARCHIVE_ENTRY_ACL_WRITE_ACL           0x00002000
+#define        ARCHIVE_ENTRY_ACL_WRITE_OWNER         0x00004000
+#define        ARCHIVE_ENTRY_ACL_SYNCHRONIZE         0x00008000
+
+#define        ARCHIVE_ENTRY_ACL_PERMS_POSIX1E                 \
+       (ARCHIVE_ENTRY_ACL_EXECUTE                      \
+           | ARCHIVE_ENTRY_ACL_WRITE                   \
+           | ARCHIVE_ENTRY_ACL_READ)
+
+#define ARCHIVE_ENTRY_ACL_PERMS_NFS4                   \
+       (ARCHIVE_ENTRY_ACL_EXECUTE                      \
+           | ARCHIVE_ENTRY_ACL_READ_DATA               \
+           | ARCHIVE_ENTRY_ACL_LIST_DIRECTORY          \
+           | ARCHIVE_ENTRY_ACL_WRITE_DATA              \
+           | ARCHIVE_ENTRY_ACL_ADD_FILE                \
+           | ARCHIVE_ENTRY_ACL_APPEND_DATA             \
+           | ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY        \
+           | ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS        \
+           | ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS       \
+           | ARCHIVE_ENTRY_ACL_DELETE_CHILD            \
+           | ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES         \
+           | ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES        \
+           | ARCHIVE_ENTRY_ACL_DELETE                  \
+           | ARCHIVE_ENTRY_ACL_READ_ACL                \
+           | ARCHIVE_ENTRY_ACL_WRITE_ACL               \
+           | ARCHIVE_ENTRY_ACL_WRITE_OWNER             \
+           | ARCHIVE_ENTRY_ACL_SYNCHRONIZE)
 
-/* We need to be able to specify either or both of these. */
-#define        ARCHIVE_ENTRY_ACL_TYPE_ACCESS   256
-#define        ARCHIVE_ENTRY_ACL_TYPE_DEFAULT  512
+/*
+ * Inheritance values (NFS4 ACLs only); included in permset.
+ */
+#define        ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT                0x02000000
+#define        ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT           0x04000000
+#define        ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT        0x08000000
+#define        ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY                0x10000000
+#define        ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS           0x20000000
+#define        ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS               0x40000000
+
+#define        ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4                      \
+       (ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT                   \
+           | ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT         \
+           | ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT      \
+           | ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY              \
+           | ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS         \
+           | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS)
+
+/* We need to be able to specify combinations of these. */
+#define        ARCHIVE_ENTRY_ACL_TYPE_ACCESS   256  /* POSIX.1e only */
+#define        ARCHIVE_ENTRY_ACL_TYPE_DEFAULT  512  /* POSIX.1e only */
+#define        ARCHIVE_ENTRY_ACL_TYPE_ALLOW    1024 /* NFS4 only */
+#define        ARCHIVE_ENTRY_ACL_TYPE_DENY     2048 /* NFS4 only */
+#define        ARCHIVE_ENTRY_ACL_TYPE_AUDIT    4096 /* NFS4 only */
+#define        ARCHIVE_ENTRY_ACL_TYPE_ALARM    8192 /* NFS4 only */
+#define        ARCHIVE_ENTRY_ACL_TYPE_POSIX1E  (ARCHIVE_ENTRY_ACL_TYPE_ACCESS \
+           | ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)
+#define        ARCHIVE_ENTRY_ACL_TYPE_NFS4     (ARCHIVE_ENTRY_ACL_TYPE_ALLOW \
+           | ARCHIVE_ENTRY_ACL_TYPE_DENY \
+           | ARCHIVE_ENTRY_ACL_TYPE_AUDIT \
+           | ARCHIVE_ENTRY_ACL_TYPE_ALARM)
 
 /* Tag values mimic POSIX.1e */
 #define        ARCHIVE_ENTRY_ACL_USER          10001   /* Specified user. */
 #define        ARCHIVE_ENTRY_ACL_USER_OBJ      10002   /* User who owns the file. */
 #define        ARCHIVE_ENTRY_ACL_GROUP         10003   /* Specified group. */
 #define        ARCHIVE_ENTRY_ACL_GROUP_OBJ     10004   /* Group who owns the file. */
-#define        ARCHIVE_ENTRY_ACL_MASK          10005   /* Modify group access. */
-#define        ARCHIVE_ENTRY_ACL_OTHER         10006   /* Public. */
+#define        ARCHIVE_ENTRY_ACL_MASK          10005   /* Modify group access (POSIX.1e only) */
+#define        ARCHIVE_ENTRY_ACL_OTHER         10006   /* Public (POSIX.1e only) */
+#define        ARCHIVE_ENTRY_ACL_EVERYONE      10107   /* Everyone (NFS4 only) */
 
 /*
  * Set the ACL by clearing it and adding entries one at a time.
@@ -363,17 +446,17 @@ __LA_DECL void    archive_entry_copy_stat(struct archive_entry *, const struct stat
  * default and access information in a single ACL list.
  */
 __LA_DECL void  archive_entry_acl_clear(struct archive_entry *);
-__LA_DECL void  archive_entry_acl_add_entry(struct archive_entry *,
+__LA_DECL int   archive_entry_acl_add_entry(struct archive_entry *,
            int /* type */, int /* permset */, int /* tag */,
            int /* qual */, const char * /* name */);
-__LA_DECL void  archive_entry_acl_add_entry_w(struct archive_entry *,
+__LA_DECL int   archive_entry_acl_add_entry_w(struct archive_entry *,
            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.
+ * certain types of entries.
  */
 __LA_DECL int   archive_entry_acl_reset(struct archive_entry *, int /* want_type */);
 __LA_DECL int   archive_entry_acl_next(struct archive_entry *, int /* want_type */,
@@ -387,36 +470,29 @@ __LA_DECL int      archive_entry_acl_next_w(struct archive_entry *, int /* want_type
  * Construct a text-format ACL.  The flags argument is a bitmask that
  * can include any of the following:
  *
- * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - Include access entries.
- * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - Include default entries.
+ * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - Include POSIX.1e "access" entries.
+ * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - Include POSIX.1e "default" entries.
+ * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - Include NFS4 entries.
  * ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID - Include extra numeric ID field in
- *    each ACL entry.  (As used by 'star'.)
+ *    each ACL entry.  ('star' introduced this for POSIX.1e, this flag
+ *    also applies to NFS4.)
  * ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT - Include "default:" before each
- *    default ACL entry.
+ *    default ACL entry, as used in old Solaris ACLs.
  */
 #define        ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID        1024
 #define        ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT    2048
 __LA_DECL const wchar_t        *archive_entry_acl_text_w(struct archive_entry *,
                    int /* flags */);
+__LA_DECL const char *archive_entry_acl_text(struct archive_entry *,
+                   int /* flags */);
 
 /* Return a count of entries matching 'want_type' */
 __LA_DECL int   archive_entry_acl_count(struct archive_entry *, int /* want_type */);
 
-/*
- * Private ACL parser.  This is private because it handles some
- * very weird formats that clients should not be messing with.
- * Clients should only deal with their platform-native formats.
- * Because of the need to support many formats cleanly, new arguments
- * are likely to get added on a regular basis.  Clients who try to use
- * 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.
- */
-__LA_DECL int           __archive_entry_acl_parse_w(struct archive_entry *,
-                   const wchar_t *, int /* type */);
+/* Return an opaque ACL object. */
+/* There's not yet anything clients can actually do with this... */
+struct archive_acl;
+__LA_DECL struct archive_acl *archive_entry_acl(struct archive_entry *);
 
 /*
  * extended attributes
@@ -437,6 +513,24 @@ __LA_DECL int      archive_entry_xattr_reset(struct archive_entry *);
 __LA_DECL int  archive_entry_xattr_next(struct archive_entry *,
            const char ** /* name */, const void ** /* value */, size_t *);
 
+/*
+ * sparse
+ */
+
+__LA_DECL void  archive_entry_sparse_clear(struct archive_entry *);
+__LA_DECL void  archive_entry_sparse_add_entry(struct archive_entry *,
+           __LA_INT64_T /* offset */, __LA_INT64_T /* length */);
+
+/*
+ * To retrieve the xattr list, first "reset", then repeatedly ask for the
+ * "next" entry.
+ */
+
+__LA_DECL int  archive_entry_sparse_count(struct archive_entry *);
+__LA_DECL int  archive_entry_sparse_reset(struct archive_entry *);
+__LA_DECL int  archive_entry_sparse_next(struct archive_entry *,
+           __LA_INT64_T * /* offset */, __LA_INT64_T * /* length */);
+
 /*
  * Utility to match up hardlinks.
  *
@@ -449,7 +543,7 @@ __LA_DECL int       archive_entry_xattr_next(struct archive_entry *,
  *      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.
+ *   5. Call archive_entry_linkresolver_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
@@ -499,7 +593,7 @@ struct archive_entry_linkresolver;
  *           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
+ *    It's noticeably 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
@@ -513,6 +607,8 @@ __LA_DECL void archive_entry_linkresolver_set_strategy(
 __LA_DECL void archive_entry_linkresolver_free(struct archive_entry_linkresolver *);
 __LA_DECL void archive_entry_linkify(struct archive_entry_linkresolver *,
     struct archive_entry **, struct archive_entry **);
+__LA_DECL struct archive_entry *archive_entry_partial_links(
+    struct archive_entry_linkresolver *res, unsigned int *links);
 
 #ifdef __cplusplus
 }
diff --git a/contrib/libarchive/libarchive/archive_entry_acl.3 b/contrib/libarchive/libarchive/archive_entry_acl.3
new file mode 100644 (file)
index 0000000..93906e7
--- /dev/null
@@ -0,0 +1,233 @@
+.\" Copyright (c) 2010 Joerg Sonnenberger
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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.
+.\"
+.Dd February 21, 2010
+.Dt ARCHIVE_ENTRY_ACL 3
+.Os
+.Sh NAME
+.Nm archive_entry_acl_add_entry ,
+.Nm archive_entry_acl_add_entry_w ,
+.Nm archive_entry_acl_clear ,
+.Nm archive_entry_acl_count ,
+.Nm archive_entry_acl_next ,
+.Nm archive_entry_acl_next_w ,
+.Nm archive_entry_acl_reset ,
+.Nm archive_entry_acl_text_w
+.Nd functions for manipulating Access Control Lists in archive entry descriptions
+.Sh SYNOPSIS
+.In archive_entry.h
+.Ft void
+.Fo archive_entry_acl_add_entry
+.Fa "struct archive_entry *a"
+.Fa "int type"
+.Fa "int permset"
+.Fa "int tag"
+.Fa "int qualifier"
+.Fa "const char *name"
+.Fc
+.Ft void
+.Fo archive_entry_acl_add_entry_w
+.Fa "struct archive_entry *a"
+.Fa "int type"
+.Fa "int permset"
+.Fa "int tag"
+.Fa "int qualifier"
+.Fa "const wchar_t *name"
+.Fc
+.Ft void
+.Fn archive_entry_acl_clear "struct archive_entry *a"
+.Ft int
+.Fn archive_entry_acl_count "struct archive_entry *a" "int type"
+.Ft int
+.Fo archive_entry_acl_next
+.Fa "struct archive_entry *a"
+.Fa "int type"
+.Fa "int *ret_type"
+.Fa "int *ret_permset"
+.Fa "int *ret_tag"
+.Fa "int *ret_qual"
+.Fa "const char **ret_name"
+.Fc
+.Ft int
+.Fo archive_entry_acl_next_w
+.Fa "struct archive_entry *a"
+.Fa "int type"
+.Fa "int *ret_type"
+.Fa "int *ret_permset"
+.Fa "int *ret_tag"
+.Fa "int *ret_qual"
+.Fa "const wchar_t **ret_name"
+.Fc
+.Ft int
+.Fn archive_entry_acl_reset "struct archive_entry *a" "int type"
+.Ft const wchar_t *
+.Fn archive_entry_acl_text_w "struct archive_entry *a" "int flags"
+.\" enum?
+.Sh DESCRIPTION
+An
+.Dq Access Control List
+is a generalisation of the classic Unix permission system.
+The ACL interface of
+.Nm libarchive
+is derived from the POSIX.1e draft, but restricted to simplify dealing
+with practical implementations in various Operating Systems and archive formats.
+.Pp
+An ACL consists of a number of independent entries.
+Each entry specifies the permission set as bitmask of basic permissions.
+Valid permissions are:
+.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_EXECUTE"
+.It Dv ARCHIVE_ENTRY_ACL_EXECUTE
+.It Dv ARCHIVE_ENTRY_ACL_WRITE
+.It Dv ARCHIVE_ENTRY_ACL_READ
+.El
+The permissions correspond to the normal Unix permissions.
+.Pp
+The tag specifies the principal to which the permission applies.
+Valid values are:
+.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_GROUP_OBJ"
+.It Dv ARCHIVE_ENTRY_ACL_USER
+The user specified by the name field.
+.It Dv ARCHIVE_ENTRY_ACL_USER_OBJ
+The owner of the file.
+.It Dv ARCHIVE_ENTRY_ACL_GROUP
+The group specied by the name field.
+.It Dv ARCHIVE_ENTRY_ACL_GROUP_OBJ
+The group who owns the file.
+.It Dv ARCHIVE_ENTRY_ACL_MASK
+The maximum permissions to be obtained via group permissions.
+.It Dv ARCHIVE_ENTRY_ACL_OTHER
+Any principal who doesn't have a user or group entry.
+.El
+The principals
+.Dv ARCHIVE_ENTRY_ACL_USER_OBJ ,
+.Dv ARCHIVE_ENTRY_ACL_GROUP_OBJ
+and
+.Dv ARCHIVE_ENTRY_ACL_OTHER
+are equivalent to user, group and other in the classic Unix permission
+model and specify non-extended ACL entries.
+.Pp
+All files have an access ACL
+.Pq Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS .
+This specifies the permissions required for access to the file itself.
+Directories have an additional ACL
+.Pq Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT ,
+which controlls the initial access ACL for newly created directory entries.
+.Pp
+.Fn archive_entry_acl_add_entry
+and
+.Fn archive_entry_acl_add_entry_w
+add a single ACL entry.
+For the access ACL and non-extended principals, the classic Unix permissions
+are updated.
+.Pp
+.Fn archive_entry_acl_clear
+removes all ACL entries and resets the enumeration pointer.
+.Pp
+.Fn archive_entry_acl_count
+counts the ACL entries that have the given type mask.
+.Fa type
+can be the bitwise-or of
+.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
+and
+.Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT .
+If
+.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
+is included and at least one extended ACL entry is found,
+the three non-extened ACLs are added.
+.Pp
+.Fn archive_entry_acl_next
+and
+.Fn archive_entry_acl_next_w
+return the next entry of the ACL list.
+This functions may only be called after
+.Fn archive_entry_acl_reset
+has indicated the presence of extended ACL entries.
+.Pp
+.Fn archive_entry_acl_reset
+prepare reading the list of ACL entries with
+.Fn archive_entry_acl_next
+or
+.Fn archive_entry_acl_next_w .
+The function returns either 0, if no non-extended ACLs are found.
+In this case, the access permissions should be obtained by
+.Xr archive_entry_mode 3
+or set using
+.Xr chmod 2 .
+Otherwise, the function returns the same value as
+.Fn archive_entry_acl_count .
+.Pp
+.Fn archive_entry_acl_text_w
+converts the ACL entries for the given type mask into a wide string.
+In addition to the normal type flags,
+.Dv ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID
+and
+.Dv ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT
+can be specified to further customize the result.
+The returned long string is valid until the next call to
+.Fn archive_entry_acl_clear ,
+.Fn archive_entry_acl_add_entry ,
+.Fn archive_entry_acl_add_entry_w
+or
+.Fn archive_entry_acl_text_w .
+.Sh RETURN VALUES
+.Fn archive_entry_acl_count
+and
+.Fn archive_entry_acl_reset
+returns the number of ACL entries that match the given type mask.
+If the type mask includes
+.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
+and at least one extended ACL entry exists, the three classic Unix
+permissions are counted.
+.Pp
+.Fn archive_entry_acl_next
+and
+.Fn archive_entry_acl_next_w
+return
+.Dv ARCHIVE_OK
+on success,
+.Dv ARCHIVE_EOF
+if no more ACL entries exist
+and
+.Dv ARCHIVE_WARN
+if
+.Fn archive_entry_acl_reset
+has not been called first.
+.Pp
+.Fn archive_entry_text_w
+returns a wide string representation of the ACL entrise matching the
+given type mask.
+The returned long string is valid until the next call to
+.Fn archive_entry_acl_clear ,
+.Fn archive_entry_acl_add_entry ,
+.Fn archive_entry_acl_add_entry_w
+or
+.Fn archive_entry_acl_text_w .
+.Sh SEE ALSO
+.Xr archive 3 ,
+.Xr archive_entry 3
+.Sh BUGS
+.Dv ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID
+and
+.Dv ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT
+are not documented.
diff --git a/contrib/libarchive/libarchive/archive_entry_copy_bhfi.c b/contrib/libarchive/libarchive/archive_entry_copy_bhfi.c
deleted file mode 100644 (file)
index 8339032..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "archive_platform.h"
-__FBSDID("$FreeBSD$");
-
-#include "archive_private.h"
-#include "archive_entry.h"
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-
-#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
-
-__inline static void
-fileTimeToUtc(const FILETIME *filetime, time_t *time, long *ns)
-{
-       ULARGE_INTEGER utc;
-
-       utc.HighPart = filetime->dwHighDateTime;
-       utc.LowPart  = filetime->dwLowDateTime;
-       if (utc.QuadPart >= EPOC_TIME) {
-               utc.QuadPart -= EPOC_TIME;
-               *time = (time_t)(utc.QuadPart / 10000000);      /* milli seconds base */
-               *ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */
-       } else {
-               *time = 0;
-               *ns = 0;
-       }
-}
-
-void
-archive_entry_copy_bhfi(struct archive_entry *entry,
-                       BY_HANDLE_FILE_INFORMATION *bhfi)
-{
-       time_t secs;
-       long nsecs;
-
-       fileTimeToUtc(&bhfi->ftLastAccessTime, &secs, &nsecs);
-       archive_entry_set_atime(entry, secs, nsecs);
-       fileTimeToUtc(&bhfi->ftLastWriteTime, &secs, &nsecs);
-       archive_entry_set_mtime(entry, secs, nsecs);
-       fileTimeToUtc(&bhfi->ftCreationTime, &secs, &nsecs);
-       archive_entry_set_birthtime(entry, secs, nsecs);
-       archive_entry_set_dev(entry, bhfi->dwVolumeSerialNumber);
-       archive_entry_set_ino64(entry, (((int64_t)bhfi->nFileIndexHigh) << 32)
-               + bhfi->nFileIndexLow);
-       archive_entry_set_nlink(entry, bhfi->nNumberOfLinks);
-       archive_entry_set_size(entry, (((int64_t)bhfi->nFileSizeHigh) << 32)
-               + bhfi->nFileSizeLow);
-//     archive_entry_set_mode(entry, st->st_mode);
-}
-#endif
index ef59a5e..37d4d6e 100644 (file)
@@ -30,6 +30,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_entry_copy_stat.c 189466 2009-03
 #include <sys/stat.h>
 #endif
 
+#include "archive.h"
 #include "archive_entry.h"
 
 void
@@ -59,12 +60,13 @@ archive_entry_copy_stat(struct archive_entry *entry, const struct stat *st)
        archive_entry_set_atime(entry, st->st_atime, 0);
        archive_entry_set_ctime(entry, st->st_ctime, 0);
        archive_entry_set_mtime(entry, st->st_mtime, 0);
-#if HAVE_STRUCT_STAT_ST_BIRTHTIME
-       archive_entry_set_birthtime(entry, st->st_birthtime, 0);
-#endif
 #endif
 #if HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC
        archive_entry_set_birthtime(entry, st->st_birthtime, st->st_birthtimespec.tv_nsec);
+#elif HAVE_STRUCT_STAT_ST_BIRTHTIME
+       archive_entry_set_birthtime(entry, st->st_birthtime, 0);
+#else
+       archive_entry_unset_birthtime(entry);
 #endif
        archive_entry_set_dev(entry, st->st_dev);
        archive_entry_set_gid(entry, st->st_gid);
index 3b13e19..a18144d 100644 (file)
@@ -70,10 +70,10 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_entry_link_resolver.c 201100 200
 struct links_entry {
        struct links_entry      *next;
        struct links_entry      *previous;
-       int