summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Griebl <robert.griebl@pelagicore.com>2018-02-06 17:47:49 +0100
committerDominik Holland <dominik.holland@pelagicore.com>2018-02-07 13:26:46 +0000
commit8df633d8195f16221ca348d527ab8671142f7426 (patch)
tree8abe6b75d476b4c63cba0371041b92a5e530fb24
parentb5b9138b77feb3b39e81eb95ebac347ccd1e7e06 (diff)
Update 3rd-party libraries
libarchive to 3.3.2 (also removed unneeded file formats) libyaml to 1.7 Change-Id: I264721b4dda63f5e69e1fe21d33000206a2b881b Reviewed-by: Dominik Holland <dominik.holland@pelagicore.com>
-rw-r--r--3rdparty/libarchive/COPYING5
-rw-r--r--3rdparty/libarchive/INSTALL2
-rw-r--r--3rdparty/libarchive/NEWS63
-rw-r--r--3rdparty/libarchive/README155
-rw-r--r--3rdparty/libarchive/README.md222
-rw-r--r--3rdparty/libarchive/config-android.h5
-rw-r--r--3rdparty/libarchive/config-osx.h2
-rw-r--r--3rdparty/libarchive/libarchive.pro39
-rw-r--r--3rdparty/libarchive/libarchive/android_lf.h47
-rw-r--r--3rdparty/libarchive/libarchive/archive.h285
-rw-r--r--3rdparty/libarchive/libarchive/archive_acl.c1639
-rw-r--r--3rdparty/libarchive/libarchive/archive_acl_private.h22
-rw-r--r--3rdparty/libarchive/libarchive/archive_check_magic.c2
-rw-r--r--3rdparty/libarchive/libarchive/archive_crypto.c1429
-rw-r--r--3rdparty/libarchive/libarchive/archive_crypto_private.h376
-rw-r--r--3rdparty/libarchive/libarchive/archive_endian.h44
-rw-r--r--3rdparty/libarchive/libarchive/archive_entry.c436
-rw-r--r--3rdparty/libarchive/libarchive/archive_entry.h159
-rw-r--r--3rdparty/libarchive/libarchive/archive_entry_copy_stat.c4
-rw-r--r--3rdparty/libarchive/libarchive/archive_entry_locale.h10
-rw-r--r--3rdparty/libarchive/libarchive/archive_entry_private.h5
-rw-r--r--3rdparty/libarchive/libarchive/archive_entry_sparse.c6
-rw-r--r--3rdparty/libarchive/libarchive/archive_entry_strmode.c2
-rw-r--r--3rdparty/libarchive/libarchive/archive_entry_xattr.c10
-rw-r--r--3rdparty/libarchive/libarchive/archive_getdate.c21
-rw-r--r--3rdparty/libarchive/libarchive/archive_getdate.h39
-rw-r--r--3rdparty/libarchive/libarchive/archive_match.c27
-rw-r--r--3rdparty/libarchive/libarchive/archive_options.c17
-rw-r--r--3rdparty/libarchive/libarchive/archive_pack_dev.h49
-rw-r--r--3rdparty/libarchive/libarchive/archive_pathmatch.c8
-rw-r--r--3rdparty/libarchive/libarchive/archive_platform.h38
-rw-r--r--3rdparty/libarchive/libarchive/archive_platform_acl.h49
-rw-r--r--3rdparty/libarchive/libarchive/archive_ppmd7.c5
-rw-r--r--3rdparty/libarchive/libarchive/archive_ppmd7_private.h2
-rw-r--r--3rdparty/libarchive/libarchive/archive_private.h19
-rw-r--r--3rdparty/libarchive/libarchive/archive_random.c272
-rw-r--r--3rdparty/libarchive/libarchive/archive_random_private.h36
-rw-r--r--3rdparty/libarchive/libarchive/archive_rb.c2
-rw-r--r--3rdparty/libarchive/libarchive/archive_read.c163
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_append_filter.c8
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_disk_entry_from_file.c697
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_disk_posix.c187
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_disk_private.h22
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_disk_set_standard_lookup.c4
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_disk_windows.c88
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_extract.c147
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_open_fd.c29
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_open_file.c10
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_open_filename.c26
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_open_memory.c15
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_private.h77
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_set_options.c39
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_filter_all.c81
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_filter_compress.c455
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_filter_grzip.c121
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_filter_lrzip.c132
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_filter_lzop.c486
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_filter_program.c2
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_filter_rpm.c289
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_filter_uu.c694
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_filter_xz.c196
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_format_7zip.c3748
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_format_all.c87
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_format_ar.c626
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_format_cab.c3348
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_format_cpio.c1066
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_format_empty.c2
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_format_iso9660.c3233
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_format_lha.c2748
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_format_mtree.c1872
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_format_rar.c2858
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_format_raw.c188
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_format_tar.c519
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_format_xar.c3331
-rw-r--r--3rdparty/libarchive/libarchive/archive_read_support_format_zip.c1742
-rw-r--r--3rdparty/libarchive/libarchive/archive_string.c212
-rw-r--r--3rdparty/libarchive/libarchive/archive_string.h8
-rw-r--r--3rdparty/libarchive/libarchive/archive_string_composition.h2
-rw-r--r--3rdparty/libarchive/libarchive/archive_string_sprintf.c2
-rw-r--r--3rdparty/libarchive/libarchive/archive_util.c120
-rw-r--r--3rdparty/libarchive/libarchive/archive_virtual.c16
-rw-r--r--3rdparty/libarchive/libarchive/archive_windows.c14
-rw-r--r--3rdparty/libarchive/libarchive/archive_windows.h18
-rw-r--r--3rdparty/libarchive/libarchive/archive_write.c37
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_add_filter.c3
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_add_filter_by_name.c3
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_add_filter_bzip2.c2
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_add_filter_compress.c455
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_add_filter_grzip.c135
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_add_filter_gzip.c2
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_add_filter_lrzip.c192
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_add_filter_lzop.c486
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_add_filter_program.c19
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_add_filter_uuencode.c305
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_add_filter_xz.c44
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_disk_acl.c249
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_disk_posix.c908
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_disk_private.h6
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_disk_set_standard_lookup.c13
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_disk_windows.c29
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_open_filename.c5
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_open_memory.c3
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_private.h17
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_set_format.c6
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_set_format_7zip.c2324
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_set_format_ar.c564
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_set_format_by_name.c4
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_set_format_cpio.c500
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_set_format_cpio_newc.c458
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_set_format_gnutar.c48
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_set_format_iso9660.c8148
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_set_format_mtree.c2203
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_set_format_pax.c1900
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_set_format_shar.c642
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_set_format_ustar.c11
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_set_format_v7tar.c661
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_set_format_xar.c3181
-rw-r--r--3rdparty/libarchive/libarchive/archive_write_set_format_zip.c930
-rw-r--r--3rdparty/libarchive/libarchive/config_freebsd.h349
-rw-r--r--3rdparty/libarchive/libarchive/filter_fork_windows.c2
-rw-r--r--3rdparty/libarchive/qt_attribution.json4
-rw-r--r--3rdparty/libyaml/README4
-rw-r--r--3rdparty/libyaml/qt_attribution.json4
-rw-r--r--3rdparty/libyaml/src/api.c8
-rw-r--r--3rdparty/libyaml/win32/config.h4
125 files changed, 5329 insertions, 54820 deletions
diff --git a/3rdparty/libarchive/COPYING b/3rdparty/libarchive/COPYING
index b2588060..93952b77 100644
--- a/3rdparty/libarchive/COPYING
+++ b/3rdparty/libarchive/COPYING
@@ -17,12 +17,11 @@ the actual statements in the files are controlling.
files for details:
libarchive/archive_entry.c
libarchive/archive_read_support_filter_compress.c
- libarchive/archive_write_set_filter_compress.c
+ libarchive/archive_write_add_filter_compress.c
libarchive/mtree.5
- tar/matching.c
* The following source files are in the public domain:
- tar/getdate.c
+ libarchive/archive_getdate.c
* The build files---including Makefiles, configure scripts,
and auxiliary scripts used as part of the compile process---have
diff --git a/3rdparty/libarchive/INSTALL b/3rdparty/libarchive/INSTALL
index 33c58b7e..2fafbd50 100644
--- a/3rdparty/libarchive/INSTALL
+++ b/3rdparty/libarchive/INSTALL
@@ -1,5 +1,5 @@
More complete build documentation is available on the libarchive
-Wiki: http://libarchive.googlecode.com/
+Wiki: https://github.com/libarchive/libarchive/wiki
On most Unix-like systems, you should be able to install libarchive,
bsdtar, and bsdcpio using the following common steps:
diff --git a/3rdparty/libarchive/NEWS b/3rdparty/libarchive/NEWS
index 107d4da0..9527e662 100644
--- a/3rdparty/libarchive/NEWS
+++ b/3rdparty/libarchive/NEWS
@@ -1,3 +1,64 @@
+Jul 09, 2017: libarchive 3.3.2 released
+
+Mar 16, 2017: NFSv4 ACL support for Linux (librichacl)
+
+Feb 26, 2017: libarchive 3.3.1 released
+ Security & Feature release
+
+Feb 19, 2017: libarchive 3.3.0 released
+ Security & Feature release
+
+Jan 29, 2017: Limited NFSv4 ACL support for Mac OS (Darwin)
+
+Jan 10, 2017: POSIX.1e and NFSv4 ACL support for Solaris and derivates
+
+Dec 27, 2016: NFSv4 ACL read and write support for pax
+ Deprecated functions: archive_entry_acl_text(), archive_entry_acl_text_w()
+
+Nov, 2016: libarchive is now being tested by the OSS-Fuzz project
+
+Oct 26, 2016: Remove liblzmadec support
+
+Oct 23, 2016: libarchive 3.2.2 released
+ Security release
+
+Jun 20, 2016: libarchive 3.2.1 released
+ This fixes a handful of security and other critical issues with 3.2.0
+
+May 01, 2016: libarchive 3.2.0 released
+
+Apr 09, 2016: libarchive 3.1.901a released
+ Another test release in preparation for 3.2.0
+
+Feb 13, 2016: libarchive 3.1.900a released
+ This is a test release in preparation for 3.2.0
+
+Oct 21, 2015: Preliminary port to OSF
+
+Apr 11, 2015: libarchive's issue tracker is now hosted at GitHub.
+ https://github.com/libarchive/libarchive/issues
+
+Early 2015: Many fixes to crash and overflow bugs thanks to Hanno Boeck
+
+Oct 13, 2014: Zip encryption and decryption support
+
+Aug 13, 2014: Add support for lz4 compression.
+
+Jun 10, 2014: Add warc format support
+
+May 3, 2014: Add experimental Zip streaming extension
+
+Apr 6, 2014: Add bsdcat command-line tool
+
+Jan 12, 2014: Add Zip64 support
+
+Dec 1, 2013: Rewrite Zip write logic
+
+Jul 1, 2013: Add ability to detect encrypted entries for many formats
+ (This does not add the ability to *decrypt* those entries, however)
+
+Feb 23, 2013: "raw" write support added
+
Feb 09, 2013: libarchive 3.1.2 released
Jan 28, 2013: libarchive's new website moved to http://www.libarchive.org.
@@ -236,7 +297,7 @@ May 04, 2008: libarchive 2.5.3b released
* libarchive: Mark which entry strings are set; be accurate about
distinguishing empty strings ("") from unset ones (NULL)
* tar: Don't crash reading entries with empty filenames
- * libarchive_test, bsdtar_test, bsdcpio_test: Better detaults:
+ * libarchive_test, bsdtar_test, bsdcpio_test: Better defaults:
run all tests, delete temp dirs, summarize repeated failures
* -no-undefined to libtool for Cygwin
* libarchive_test: Skip large file tests on systems with 32-bit off_t
diff --git a/3rdparty/libarchive/README b/3rdparty/libarchive/README
deleted file mode 100644
index 1c974fde..00000000
--- a/3rdparty/libarchive/README
+++ /dev/null
@@ -1,155 +0,0 @@
-README for libarchive bundle.
-
-Questions? Issues?
- * http://www.libarchive.org is the home for ongoing
- libarchive development, including documentation, and
- links to the libarchive mailing lists.
- * To report an issue, use the issue tracker at
- http://code.google.com/p/libarchive/issues/list
- * To submit an enhancement to libarchive, please submit
- a pull request via GitHub.
- https://github.com/libarchive/libarchive/pulls
-
-This distribution bundle includes the following components:
- * libarchive: a library for reading and writing streaming archives
- * tar: the 'bsdtar' program is a full-featured 'tar'
- replacement built on libarchive
- * cpio: the 'bsdcpio' program is a different interface to
- essentially the same functionality
- * examples: Some small example programs that you may find useful.
- * examples/minitar: a compact sample demonstrating use of libarchive.
- * contrib: Various items sent to me by third parties;
- please contact the authors with any questions.
-
-The top-level directory contains the following information files:
- * NEWS - highlights of recent changes
- * COPYING - what you can do with this
- * INSTALL - installation instructions
- * README - this file
- * configure - configuration script, see INSTALL for details.
- * CMakeLists.txt - input for "cmake" build tool, see INSTALL
-
-The following files in the top-level directory are used by the
-'configure' script:
- * Makefile.am, aclocal.m4, configure.ac
- - used to build this distribution, only needed by maintainers
- * Makefile.in, config.h.in
- - templates used by configure script
-
-Guide to Documentation installed by this system:
- * bsdtar.1 explains the use of the bsdtar program
- * bsdcpio.1 explains the use of the bsdcpio program
- * libarchive.3 gives an overview of the library as a whole
- * archive_read.3, archive_write.3, archive_write_disk.3, and
- archive_read_disk.3 provide detailed calling sequences for the read
- and write APIs
- * archive_entry.3 details the "struct archive_entry" utility class
- * archive_internals.3 provides some insight into libarchive's
- internal structure and operation.
- * libarchive-formats.5 documents the file formats supported by the library
- * cpio.5, mtree.5, and tar.5 provide detailed information about these
- popular archive formats, including hard-to-find details about
- modern cpio and tar variants.
-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 us
-know about any errors or omissions you find.
-
-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
- * POSIX pax interchange format
- * POSIX octet-oriented cpio
- * SVR4 ASCII cpio
- * POSIX octet-oriented cpio
- * Binary cpio (big-endian or little-endian)
- * ISO9660 CD-ROM images (with optional Rockridge or Joliet extensions)
- * ZIP archives (with uncompressed or "deflate" compressed entries)
- * GNU and BSD 'ar' archives
- * 'mtree' format
- * 7-Zip archives
- * 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, 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
- * 7-Zip archives
- * 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:
-
- * This is a heavily stream-oriented system. There is no direct
- support for in-place modification or random access.
-
- * The library is designed to be extended with new compression and
- archive formats. The only requirement is that the format be
- readable or writable as a stream and that each archive entry be
- independent. There are articles on the libarchive Wiki explaining
- how to extend libarchive.
-
- * On read, compression and format are always detected automatically.
-
- * I've attempted to minimize static link pollution. If you don't
- explicitly invoke a particular feature (such as support for a
- particular compression or format), it won't get pulled in.
- In particular, if you don't explicitly enable a particular
- compression or decompression support, you won't need to link
- against the corresponding compression or decompression libraries.
- This also reduces the size of statically-linked binaries in
- environments where that matters.
-
- * On read, the library accepts whatever blocks you hand it.
- Your read callback is free to pass the library a byte at a time
- or mmap the entire archive and give it to the library at once.
- On write, the library always produces correctly-blocked output.
-
- * The object-style approach allows you to have multiple archive streams
- open at once. bsdtar uses this in its "@archive" extension.
-
- * The archive itself is read/written using callback functions.
- You can read an archive directly from an in-memory buffer or
- write it to a socket, if you wish. There are some utility
- functions to provide easy-to-use "open file," etc, capabilities.
-
- * The read/write APIs are designed to allow individual entries
- to be read or written to any data source: You can create
- a block of data in memory and add it to a tar archive without
- first writing a temporary file. You can also read an entry from
- an archive and write the data directly to a socket. If you want
- to read/write entries to disk, there are convenience functions to
- make this especially easy.
-
- * Note: "pax interchange format" is really an extended tar format,
- despite what the name says.
diff --git a/3rdparty/libarchive/README.md b/3rdparty/libarchive/README.md
new file mode 100644
index 00000000..be6c13b3
--- /dev/null
+++ b/3rdparty/libarchive/README.md
@@ -0,0 +1,222 @@
+# Welcome to libarchive!
+
+The libarchive project develops a portable, efficient C library that
+can read and write streaming archives in a variety of formats. It
+also includes implementations of the common `tar`, `cpio`, and `zcat`
+command-line tools that use the libarchive library.
+
+## Questions? Issues?
+
+* http://www.libarchive.org is the home for ongoing
+ libarchive development, including documentation,
+ and links to the libarchive mailing lists.
+* To report an issue, use the issue tracker at
+ https://github.com/libarchive/libarchive/issues
+* To submit an enhancement to libarchive, please
+ submit a pull request via GitHub: https://github.com/libarchive/libarchive/pulls
+
+## Contents of the Distribution
+
+This distribution bundle includes the following major components:
+
+* **libarchive**: a library for reading and writing streaming archives
+* **tar**: the 'bsdtar' program is a full-featured 'tar' implementation built on libarchive
+* **cpio**: the 'bsdcpio' program is a different interface to essentially the same functionality
+* **cat**: the 'bsdcat' program is a simple replacement tool for zcat, bzcat, xzcat, and such
+* **examples**: Some small example programs that you may find useful.
+* **examples/minitar**: a compact sample demonstrating use of libarchive.
+* **contrib**: Various items sent to me by third parties; please contact the authors with any questions.
+
+The top-level directory contains the following information files:
+
+* **NEWS** - highlights of recent changes
+* **COPYING** - what you can do with this
+* **INSTALL** - installation instructions
+* **README** - this file
+* **CMakeLists.txt** - input for "cmake" build tool, see INSTALL
+* **configure** - configuration script, see INSTALL for details. If your copy of the source lacks a `configure` script, you can try to construct it by running the script in `build/autogen.sh` (or use `cmake`).
+
+The following files in the top-level directory are used by the 'configure' script:
+* `Makefile.am`, `aclocal.m4`, `configure.ac` - used to build this distribution, only needed by maintainers
+* `Makefile.in`, `config.h.in` - templates used by configure script
+
+## Documentation
+
+In addition to the informational articles and documentation
+in the online [libarchive Wiki](https://github.com/libarchive/libarchive/wiki),
+the distribution also includes a number of manual pages:
+
+ * bsdtar.1 explains the use of the bsdtar program
+ * bsdcpio.1 explains the use of the bsdcpio program
+ * bsdcat.1 explains the use of the bsdcat program
+ * libarchive.3 gives an overview of the library as a whole
+ * archive_read.3, archive_write.3, archive_write_disk.3, and
+ archive_read_disk.3 provide detailed calling sequences for the read
+ and write APIs
+ * archive_entry.3 details the "struct archive_entry" utility class
+ * archive_internals.3 provides some insight into libarchive's
+ internal structure and operation.
+ * libarchive-formats.5 documents the file formats supported by the library
+ * cpio.5, mtree.5, and tar.5 provide detailed information about these
+ popular archive formats, including hard-to-find details about
+ modern cpio and tar variants.
+
+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 us
+know about any errors or omissions you find.
+
+## Supported Formats
+
+Currently, the library automatically detects and reads the following fomats:
+ * Old V7 tar archives
+ * POSIX ustar
+ * GNU tar format (including GNU long filenames, long link names, and sparse files)
+ * Solaris 9 extended tar format (including ACLs)
+ * POSIX pax interchange format
+ * POSIX octet-oriented cpio
+ * SVR4 ASCII cpio
+ * POSIX octet-oriented cpio
+ * Binary cpio (big-endian or little-endian)
+ * ISO9660 CD-ROM images (with optional Rockridge or Joliet extensions)
+ * ZIP archives (with uncompressed or "deflate" compressed entries, including support for encrypted Zip archives)
+ * GNU and BSD 'ar' archives
+ * 'mtree' format
+ * 7-Zip archives
+ * Microsoft CAB format
+ * LHA and LZH archives
+ * RAR archives (with some limitations due to RAR's proprietary status)
+ * 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, lzip, and xz compression
+ * lz4 compression
+ * lzop 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
+ * Old V7 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
+ * 7-Zip archives
+ * 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
+ * lz4 compression
+ * lzop compression
+
+## Notes about the Library Design
+
+The following notes address many of the most common
+questions we are asked about libarchive:
+
+* This is a heavily stream-oriented system. That means that
+ it is optimized to read or write the archive in a single
+ pass from beginning to end. For example, this allows
+ libarchive to process archives too large to store on disk
+ by processing them on-the-fly as they are read from or
+ written to a network or tape drive. This also makes
+ libarchive useful for tools that need to produce
+ archives on-the-fly (such as webservers that provide
+ archived contents of a users account).
+
+* In-place modification and random access to the contents
+ of an archive are not directly supported. For some formats,
+ this is not an issue: For example, tar.gz archives are not
+ designed for random access. In some other cases, libarchive
+ can re-open an archive and scan it from the beginning quickly
+ enough to provide the needed abilities even without true
+ random access. Of course, some applications do require true
+ random access; those applications should consider alternatives
+ to libarchive.
+
+* The library is designed to be extended with new compression and
+ archive formats. The only requirement is that the format be
+ readable or writable as a stream and that each archive entry be
+ independent. There are articles on the libarchive Wiki explaining
+ how to extend libarchive.
+
+* On read, compression and format are always detected automatically.
+
+* The same API is used for all formats; in particular, it's very
+ easy for software using libarchive to transparently handle
+ any of libarchive's archiving formats.
+
+* Libarchive's automatic support for decompression can be used
+ without archiving by explicitly selecting the "raw" and "empty"
+ formats.
+
+* I've attempted to minimize static link pollution. If you don't
+ explicitly invoke a particular feature (such as support for a
+ particular compression or format), it won't get pulled in to
+ statically-linked programs. In particular, if you don't explicitly
+ enable a particular compression or decompression support, you won't
+ need to link against the corresponding compression or decompression
+ libraries. This also reduces the size of statically-linked
+ binaries in environments where that matters.
+
+* The library is generally _thread safe_ depending on the platform:
+ it does not define any global variables of its own. However, some
+ platforms do not provide fully thread-safe versions of key C library
+ functions. On those platforms, libarchive will use the non-thread-safe
+ functions. Patches to improve this are of great interest to us.
+
+* In particular, libarchive's modules to read or write a directory
+ tree do use `chdir()` to optimize the directory traversals. This
+ can cause problems for programs that expect to do disk access from
+ multiple threads. Of course, those modules are completely
+ optional and you can use the rest of libarchive without them.
+
+* The library is _not_ thread aware, however. It does no locking
+ or thread management of any kind. If you create a libarchive
+ object and need to access it from multiple threads, you will
+ need to provide your own locking.
+
+* On read, the library accepts whatever blocks you hand it.
+ Your read callback is free to pass the library a byte at a time
+ or mmap the entire archive and give it to the library at once.
+ On write, the library always produces correctly-blocked output.
+
+* The object-style approach allows you to have multiple archive streams
+ open at once. bsdtar uses this in its "@archive" extension.
+
+* The archive itself is read/written using callback functions.
+ You can read an archive directly from an in-memory buffer or
+ write it to a socket, if you wish. There are some utility
+ functions to provide easy-to-use "open file," etc, capabilities.
+
+* The read/write APIs are designed to allow individual entries
+ to be read or written to any data source: You can create
+ a block of data in memory and add it to a tar archive without
+ first writing a temporary file. You can also read an entry from
+ an archive and write the data directly to a socket. If you want
+ to read/write entries to disk, there are convenience functions to
+ make this especially easy.
+
+* Note: The "pax interchange format" is a POSIX standard extended tar
+ format that should be used when the older _ustar_ format is not
+ appropriate. It has many advantages over other tar formats
+ (including the legacy GNU tar format) and is widely supported by
+ current tar implementations.
+
diff --git a/3rdparty/libarchive/config-android.h b/3rdparty/libarchive/config-android.h
index 8937b5db..037f1b60 100644
--- a/3rdparty/libarchive/config-android.h
+++ b/3rdparty/libarchive/config-android.h
@@ -7,11 +7,16 @@
#define HAVE_DECL_EXTATTR_NAMESPACE_USER 0
#define HAVE_DECL_INT64_MAX 1
#define HAVE_DECL_INT64_MIN 1
+#define HAVE_DECL_INT32_MAX 1
+#define HAVE_DECL_INT32_MIN 1
+#define HAVE_DECL_INTMAX_MAX 1
+#define HAVE_DECL_INTMAX_MIN 1
#define HAVE_DECL_SIZE_MAX 1
#define HAVE_DECL_SSIZE_MAX 1
#define HAVE_DECL_STRERROR_R 1
#define HAVE_DECL_UINT32_MAX 1
#define HAVE_DECL_UINT64_MAX 1
+#define HAVE_DECL_UINTMAX_MAX 1
#define HAVE_DIRENT_H 1
#define HAVE_DIRFD 1
#define HAVE_DLFCN_H 1
diff --git a/3rdparty/libarchive/config-osx.h b/3rdparty/libarchive/config-osx.h
index 74f60c39..85294b2e 100644
--- a/3rdparty/libarchive/config-osx.h
+++ b/3rdparty/libarchive/config-osx.h
@@ -1094,3 +1094,5 @@
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef uintptr_t */
+
+#define HAVE_ARC4RANDOM_BUF 1
diff --git a/3rdparty/libarchive/libarchive.pro b/3rdparty/libarchive/libarchive.pro
index 6a82208f..e7391db9 100644
--- a/3rdparty/libarchive/libarchive.pro
+++ b/3rdparty/libarchive/libarchive.pro
@@ -37,6 +37,7 @@ OTHER_FILES += \
config-windows.h \
config-osx.h \
config-unix.h \
+ android_lf.h \
INCLUDEPATH *= $$PWD/libarchive
@@ -51,7 +52,6 @@ SOURCES += \
libarchive/archive_acl.c \
libarchive/archive_check_magic.c \
libarchive/archive_cmdline.c \
- libarchive/archive_crypto.c \
libarchive/archive_entry.c \
libarchive/archive_entry_copy_stat.c \
libarchive/archive_entry_link_resolver.c \
@@ -64,6 +64,7 @@ SOURCES += \
libarchive/archive_options.c \
libarchive/archive_pathmatch.c \
libarchive/archive_ppmd7.c \
+ libarchive/archive_random.c \
libarchive/archive_rb.c \
libarchive/archive_read_append_filter.c \
libarchive/archive_read.c \
@@ -77,33 +78,14 @@ SOURCES += \
libarchive/archive_read_open_memory.c \
libarchive/archive_read_set_format.c \
libarchive/archive_read_set_options.c \
- libarchive/archive_read_support_filter_all.c \
libarchive/archive_read_support_filter_bzip2.c \
- libarchive/archive_read_support_filter_compress.c \
- libarchive/archive_read_support_filter_grzip.c \
libarchive/archive_read_support_filter_gzip.c \
- libarchive/archive_read_support_filter_lrzip.c \
- libarchive/archive_read_support_filter_lzop.c \
libarchive/archive_read_support_filter_none.c \
libarchive/archive_read_support_filter_program.c \
- libarchive/archive_read_support_filter_rpm.c \
- libarchive/archive_read_support_filter_uu.c \
libarchive/archive_read_support_filter_xz.c \
- libarchive/archive_read_support_format_7zip.c \
- libarchive/archive_read_support_format_all.c \
- libarchive/archive_read_support_format_ar.c \
libarchive/archive_read_support_format_by_code.c \
- libarchive/archive_read_support_format_cab.c \
- libarchive/archive_read_support_format_cpio.c \
libarchive/archive_read_support_format_empty.c \
- libarchive/archive_read_support_format_iso9660.c \
- libarchive/archive_read_support_format_lha.c \
- libarchive/archive_read_support_format_mtree.c \
- libarchive/archive_read_support_format_rar.c \
- libarchive/archive_read_support_format_raw.c \
libarchive/archive_read_support_format_tar.c \
- libarchive/archive_read_support_format_xar.c \
- libarchive/archive_read_support_format_zip.c \
libarchive/archive_string.c \
libarchive/archive_string_sprintf.c \
libarchive/archive_util.c \
@@ -112,37 +94,20 @@ SOURCES += \
libarchive/archive_write_add_filter_by_name.c \
libarchive/archive_write_add_filter_bzip2.c \
libarchive/archive_write_add_filter.c \
- libarchive/archive_write_add_filter_compress.c \
- libarchive/archive_write_add_filter_grzip.c \
libarchive/archive_write_add_filter_gzip.c \
- libarchive/archive_write_add_filter_lrzip.c \
- libarchive/archive_write_add_filter_lzop.c \
libarchive/archive_write_add_filter_none.c \
libarchive/archive_write_add_filter_program.c \
- libarchive/archive_write_add_filter_uuencode.c \
libarchive/archive_write_add_filter_xz.c \
libarchive/archive_write.c \
- libarchive/archive_write_disk_acl.c \
libarchive/archive_write_disk_set_standard_lookup.c \
libarchive/archive_write_open_fd.c \
libarchive/archive_write_open_file.c \
libarchive/archive_write_open_filename.c \
libarchive/archive_write_open_memory.c \
- libarchive/archive_write_set_format_7zip.c \
- libarchive/archive_write_set_format_ar.c \
libarchive/archive_write_set_format_by_name.c \
libarchive/archive_write_set_format.c \
- libarchive/archive_write_set_format_cpio.c \
- libarchive/archive_write_set_format_cpio_newc.c \
libarchive/archive_write_set_format_gnutar.c \
- libarchive/archive_write_set_format_iso9660.c \
- libarchive/archive_write_set_format_mtree.c \
- libarchive/archive_write_set_format_pax.c \
- libarchive/archive_write_set_format_shar.c \
libarchive/archive_write_set_format_ustar.c \
- libarchive/archive_write_set_format_v7tar.c \
- libarchive/archive_write_set_format_xar.c \
- libarchive/archive_write_set_format_zip.c \
libarchive/archive_write_set_options.c \
!win32:SOURCES += \
diff --git a/3rdparty/libarchive/libarchive/android_lf.h b/3rdparty/libarchive/libarchive/android_lf.h
new file mode 100644
index 00000000..2a18f514
--- /dev/null
+++ b/3rdparty/libarchive/libarchive/android_lf.h
@@ -0,0 +1,47 @@
+/*
+ * Macros for file64 functions
+ *
+ * Android does not support the macro _FILE_OFFSET_BITS=64
+ * As of android-21 it does however support many file64 functions
+*/
+
+#ifndef ARCHIVE_ANDROID_LF_H_INCLUDED
+#define ARCHIVE_ANDROID_LF_H_INCLUDED
+
+#if __ANDROID_API__ > 20
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/types.h>
+#include <sys/vfs.h>
+
+//dirent.h
+#define readdir_r readdir64_r
+#define readdir readdir64
+#define dirent dirent64
+//fcntl.h
+#define openat openat64
+#define open open64
+#define mkstemp mkstemp64
+//unistd.h
+#define lseek lseek64
+#define ftruncate ftruncate64
+//sys/stat.h
+#define fstatat fstatat64
+#define fstat fstat64
+#define lstat lstat64
+#define stat stat64
+//sys/statvfs.h
+#define fstatvfs fstatvfs64
+#define statvfs statvfs64
+//sys/types.h
+#define off_t off64_t
+//sys/vfs.h
+#define fstatfs fstatfs64
+#define statfs statfs64
+#endif
+
+#endif /* ARCHIVE_ANDROID_LF_H_INCLUDED */
diff --git a/3rdparty/libarchive/libarchive/archive.h b/3rdparty/libarchive/libarchive/archive.h
index f56bc38e..316a68a6 100644
--- a/3rdparty/libarchive/libarchive/archive.h
+++ b/3rdparty/libarchive/libarchive/archive.h
@@ -28,9 +28,20 @@
#ifndef ARCHIVE_H_INCLUDED
#define ARCHIVE_H_INCLUDED
+/*
+ * The version number is expressed as a single integer that makes it
+ * 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_NUMBER >= 2012108.
+ */
+/* Note: Compiler will complain if this does not match archive_entry.h! */
+#define ARCHIVE_VERSION_NUMBER 3003002
+
#include <sys/stat.h>
#include <stddef.h> /* for wchar_t */
#include <stdio.h> /* For FILE * */
+#include <time.h> /* For time_t */
/*
* Note: archive.h is for use outside of libarchive; the configuration
@@ -41,29 +52,53 @@
*/
#if defined(__BORLANDC__) && __BORLANDC__ >= 0x560
# include <stdint.h>
-#elif !defined(__WATCOMC__) && !defined(_MSC_VER) && !defined(__INTERIX) && !defined(__BORLANDC__) && !defined(_SCO_DS)
+#elif !defined(__WATCOMC__) && !defined(_MSC_VER) && !defined(__INTERIX) && !defined(__BORLANDC__) && !defined(_SCO_DS) && !defined(__osf__)
# include <inttypes.h>
#endif
-/* 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
-# if defined(_SSIZE_T_DEFINED) || defined(_SSIZE_T_)
-# define __LA_SSIZE_T ssize_t
-# elif defined(_WIN64)
-# define __LA_SSIZE_T __int64
-# else
-# define __LA_SSIZE_T long
+/* Get appropriate definitions of 64-bit integer */
+#if !defined(__LA_INT64_T_DEFINED)
+/* Older code relied on the __LA_INT64_T macro; after 4.0 we'll switch to the typedef exclusively. */
+# if ARCHIVE_VERSION_NUMBER < 4000000
+#define __LA_INT64_T la_int64_t
# endif
-#else
+#define __LA_INT64_T_DEFINED
+# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)
+typedef __int64 la_int64_t;
+# else
# include <unistd.h> /* ssize_t */
-# if defined(_SCO_DS)
-# define __LA_INT64_T long long
+# if defined(_SCO_DS) || defined(__osf__)
+typedef long long la_int64_t;
+# else
+typedef int64_t la_int64_t;
+# endif
+# endif
+#endif
+
+/* The la_ssize_t should match the type used in 'struct stat' */
+#if !defined(__LA_SSIZE_T_DEFINED)
+/* Older code relied on the __LA_SSIZE_T macro; after 4.0 we'll switch to the typedef exclusively. */
+# if ARCHIVE_VERSION_NUMBER < 4000000
+#define __LA_SSIZE_T la_ssize_t
+# endif
+#define __LA_SSIZE_T_DEFINED
+# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)
+# if defined(_SSIZE_T_DEFINED) || defined(_SSIZE_T_)
+typedef ssize_t la_ssize_t;
+# elif defined(_WIN64)
+typedef __int64 la_ssize_t;
+# else
+typedef long la_ssize_t;
+# endif
# else
-# define __LA_INT64_T int64_t
+# include <unistd.h> /* ssize_t */
+typedef ssize_t la_ssize_t;
# endif
-# define __LA_SSIZE_T ssize_t
+#endif
+
+/* Large file support for Android */
+#ifdef __ANDROID__
+#include "android_lf.h"
#endif
/*
@@ -115,24 +150,34 @@ extern "C" {
* header and library are very different, you should expect some
* strangeness. Don't do that.
*/
-
-/*
- * The version number is expressed as a single integer that makes it
- * 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_NUMBER >= 2012108.
- */
-/* Note: Compiler will complain if this does not match archive_entry.h! */
-#define ARCHIVE_VERSION_NUMBER 3001002
__LA_DECL int archive_version_number(void);
/*
* Textual name/version of the library, useful for version displays.
*/
-#define ARCHIVE_VERSION_STRING "libarchive 3.1.2"
+#define ARCHIVE_VERSION_ONLY_STRING "3.3.2"
+#define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
__LA_DECL const char * archive_version_string(void);
+/*
+ * Detailed textual name/version of the library and its dependencies.
+ * This has the form:
+ * "libarchive x.y.z zlib/a.b.c liblzma/d.e.f ... etc ..."
+ * the list of libraries described here will vary depending on how
+ * libarchive was compiled.
+ */
+__LA_DECL const char * archive_version_details(void);
+
+/*
+ * Returns NULL if libarchive was compiled without the associated library.
+ * Otherwise, returns the version number that libarchive was compiled
+ * against.
+ */
+__LA_DECL const char * archive_zlib_version(void);
+__LA_DECL const char * archive_liblzma_version(void);
+__LA_DECL const char * archive_bzlib_version(void);
+__LA_DECL const char * archive_liblz4_version(void);
+
/* Declare our basic types. */
struct archive;
struct archive_entry;
@@ -173,7 +218,7 @@ struct archive_entry;
*/
/* Returns pointer and size of next block of data from archive. */
-typedef __LA_SSIZE_T archive_read_callback(struct archive *,
+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.
@@ -181,18 +226,18 @@ typedef __LA_SSIZE_T archive_read_callback(struct archive *,
* 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);
+typedef la_int64_t archive_skip_callback(struct archive *,
+ void *_client_data, la_int64_t request);
/* 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);
+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 *,
+typedef la_ssize_t archive_write_callback(struct archive *,
void *_client_data,
const void *_buffer, size_t _length);
@@ -208,6 +253,13 @@ typedef int archive_switch_callback(struct archive *, void *_client_data1,
void *_client_data2);
/*
+ * Returns a passphrase used for encryption or decryption, NULL on nothing
+ * to do and give it up.
+ */
+typedef const char *archive_passphrase_callback(struct archive *,
+ void *_client_data);
+
+/*
* Codes to identify various stream filters.
*/
#define ARCHIVE_FILTER_NONE 0
@@ -223,6 +275,7 @@ typedef int archive_switch_callback(struct archive *, void *_client_data1,
#define ARCHIVE_FILTER_LRZIP 10
#define ARCHIVE_FILTER_LZOP 11
#define ARCHIVE_FILTER_GRZIP 12
+#define ARCHIVE_FILTER_LZ4 13
#if ARCHIVE_VERSION_NUMBER < 4000000
#define ARCHIVE_COMPRESSION_NONE ARCHIVE_FILTER_NONE
@@ -284,6 +337,31 @@ typedef int archive_switch_callback(struct archive *, void *_client_data1,
#define ARCHIVE_FORMAT_CAB 0xC0000
#define ARCHIVE_FORMAT_RAR 0xD0000
#define ARCHIVE_FORMAT_7ZIP 0xE0000
+#define ARCHIVE_FORMAT_WARC 0xF0000
+
+/*
+ * Codes returned by archive_read_format_capabilities().
+ *
+ * This list can be extended with values between 0 and 0xffff.
+ * The original purpose of this list was to let different archive
+ * format readers expose their general capabilities in terms of
+ * encryption.
+ */
+#define ARCHIVE_READ_FORMAT_CAPS_NONE (0) /* no special capabilities */
+#define ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA (1<<0) /* reader can detect encrypted data */
+#define ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA (1<<1) /* reader can detect encryptable metadata (pathname, mtime, etc.) */
+
+/*
+ * Codes returned by archive_read_has_encrypted_entries().
+ *
+ * In case the archive does not support encryption detection at all
+ * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned. If the reader
+ * for some other reason (e.g. not enough bytes read) cannot say if
+ * there are encrypted entries, ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW
+ * is returned.
+ */
+#define ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED -2
+#define ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW -1
/*-
* Basic outline for reading an archive:
@@ -295,7 +373,7 @@ typedef int archive_switch_callback(struct archive *, void *_client_data1,
* 4) Repeatedly call archive_read_next_header to get information about
* successive archive entries. Call archive_read_data to extract
* data for entries of interest.
- * 5) Call archive_read_finish to end processing.
+ * 5) Call archive_read_free to end processing.
*/
__LA_DECL struct archive *archive_read_new(void);
@@ -342,6 +420,7 @@ __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_grzip(struct archive *);
__LA_DECL int archive_read_support_filter_lrzip(struct archive *);
+__LA_DECL int archive_read_support_filter_lz4(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_lzop(struct archive *);
@@ -369,8 +448,17 @@ __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_warc(struct archive *);
__LA_DECL int archive_read_support_format_xar(struct archive *);
+/* archive_read_support_format_zip() enables both streamable and seekable
+ * zip readers. */
__LA_DECL int archive_read_support_format_zip(struct archive *);
+/* Reads Zip archives as stream from beginning to end. Doesn't
+ * correctly handle SFX ZIP files or ZIP archives that have been modified
+ * in-place. */
+__LA_DECL int archive_read_support_format_zip_streamable(struct archive *);
+/* Reads starting from central directory; requires seekable input. */
+__LA_DECL int archive_read_support_format_zip_seekable(struct archive *);
/* Functions to manually set the format and filters to be used. This is
* useful to bypass the bidding process when the format and filters to use
@@ -441,9 +529,9 @@ __LA_DECL int archive_read_open_file(struct archive *,
const char *_filename, size_t _block_size) __LA_DEPRECATED;
/* Read an archive that's stored in memory. */
__LA_DECL int archive_read_open_memory(struct archive *,
- void * buff, size_t size);
+ const 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, const 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,
@@ -464,14 +552,40 @@ __LA_DECL int archive_read_next_header2(struct archive *,
* Retrieve the byte offset in UNCOMPRESSED data where last-read
* header started.
*/
-__LA_DECL __LA_INT64_T archive_read_header_position(struct archive *);
+__LA_DECL la_int64_t archive_read_header_position(struct archive *);
+
+/*
+ * Returns 1 if the archive contains at least one encrypted entry.
+ * If the archive format not support encryption at all
+ * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned.
+ * If for any other reason (e.g. not enough data read so far)
+ * we cannot say whether there are encrypted entries, then
+ * ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW is returned.
+ * In general, this function will return values below zero when the
+ * reader is uncertain or totally incapable of encryption support.
+ * When this function returns 0 you can be sure that the reader
+ * supports encryption detection but no encrypted entries have
+ * been found yet.
+ *
+ * NOTE: If the metadata/header of an archive is also encrypted, you
+ * cannot rely on the number of encrypted entries. That is why this
+ * function does not return the number of encrypted entries but#
+ * just shows that there are some.
+ */
+__LA_DECL int archive_read_has_encrypted_entries(struct archive *);
+
+/*
+ * Returns a bitmask of capabilities that are supported by the archive format reader.
+ * If the reader has no special capabilities, ARCHIVE_READ_FORMAT_CAPS_NONE is returned.
+ */
+__LA_DECL int archive_read_format_capabilities(struct archive *);
/* Read data from the body of an entry. Similar to read(2). */
-__LA_DECL __LA_SSIZE_T archive_read_data(struct archive *,
+__LA_DECL la_ssize_t archive_read_data(struct archive *,
void *, size_t);
/* Seek within the body of an entry. Similar to lseek(2). */
-__LA_DECL __LA_INT64_T archive_seek_data(struct archive *, __LA_INT64_T, int);
+__LA_DECL la_int64_t archive_seek_data(struct archive *, la_int64_t, int);
/*
* A zero-copy version of archive_read_data that also exposes the file offset
@@ -480,7 +594,7 @@ __LA_DECL __LA_INT64_T archive_seek_data(struct archive *, __LA_INT64_T, int);
* be strictly increasing and that returned blocks will not overlap.
*/
__LA_DECL int archive_read_data_block(struct archive *a,
- const void **buff, size_t *size, __LA_INT64_T *offset);
+ const void **buff, size_t *size, la_int64_t *offset);
/*-
* Some convenience functions that are built on archive_read_data:
@@ -510,6 +624,14 @@ __LA_DECL int archive_read_set_option(struct archive *_a,
__LA_DECL int archive_read_set_options(struct archive *_a,
const char *opts);
+/*
+ * Add a decryption passphrase.
+ */
+__LA_DECL int archive_read_add_passphrase(struct archive *, const char *);
+__LA_DECL int archive_read_set_passphrase_callback(struct archive *,
+ void *client_data, archive_passphrase_callback *);
+
+
/*-
* Convenience function to recreate the current entry (whose header
* has just been read) on disk.
@@ -562,6 +684,10 @@ __LA_DECL int archive_read_set_options(struct archive *_a,
/* Default: Do not use HFS+ compression if it was not compressed. */
/* This has no effect except on Mac OS v10.6 or later. */
#define ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED (0x8000)
+/* Default: Do not reject entries with absolute paths */
+#define ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS (0x10000)
+/* Default: Do not clear no-change flags when unlinking object */
+#define ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS (0x20000)
__LA_DECL int archive_read_extract(struct archive *, struct archive_entry *,
int flags);
@@ -573,7 +699,7 @@ __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 *,
- __LA_INT64_T, __LA_INT64_T);
+ la_int64_t, la_int64_t);
/* Close the file and release most resources. */
__LA_DECL int archive_read_close(struct archive *);
@@ -612,7 +738,7 @@ __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 *,
- __LA_INT64_T, __LA_INT64_T);
+ la_int64_t, la_int64_t);
#if ARCHIVE_VERSION_NUMBER < 4000000
__LA_DECL int archive_write_set_compression_bzip2(struct archive *)
@@ -643,6 +769,7 @@ __LA_DECL int archive_write_add_filter_compress(struct archive *);
__LA_DECL int archive_write_add_filter_grzip(struct archive *);
__LA_DECL int archive_write_add_filter_gzip(struct archive *);
__LA_DECL int archive_write_add_filter_lrzip(struct archive *);
+__LA_DECL int archive_write_add_filter_lz4(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_lzop(struct archive *);
@@ -670,12 +797,16 @@ __LA_DECL int archive_write_set_format_mtree_classic(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_raw(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_v7tar(struct archive *);
+__LA_DECL int archive_write_set_format_warc(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_set_format_filter_by_ext(struct archive *a, const char *filename);
+__LA_DECL int archive_write_set_format_filter_by_ext_def(struct archive *a, const char *filename, const char * def_ext);
__LA_DECL int archive_write_zip_set_compression_deflate(struct archive *);
__LA_DECL int archive_write_zip_set_compression_store(struct archive *);
__LA_DECL int archive_write_open(struct archive *, void *,
@@ -700,12 +831,12 @@ __LA_DECL int archive_write_open_memory(struct archive *,
*/
__LA_DECL int archive_write_header(struct archive *,
struct archive_entry *);
-__LA_DECL __LA_SSIZE_T archive_write_data(struct archive *,
+__LA_DECL la_ssize_t archive_write_data(struct archive *,
const void *, size_t);
/* 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);
+__LA_DECL la_ssize_t archive_write_data_block(struct archive *,
+ const void *, size_t, la_int64_t);
__LA_DECL int archive_write_finish_entry(struct archive *);
__LA_DECL int archive_write_close(struct archive *);
@@ -740,6 +871,13 @@ __LA_DECL int archive_write_set_option(struct archive *_a,
__LA_DECL int archive_write_set_options(struct archive *_a,
const char *opts);
+/*
+ * Set a encryption passphrase.
+ */
+__LA_DECL int archive_write_set_passphrase(struct archive *_a, const char *p);
+__LA_DECL int archive_write_set_passphrase_callback(struct archive *,
+ void *client_data, archive_passphrase_callback *);
+
/*-
* ARCHIVE_WRITE_DISK API
*
@@ -759,7 +897,7 @@ __LA_DECL int archive_write_set_options(struct archive *_a,
__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 *,
- __LA_INT64_T, __LA_INT64_T);
+ 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 *,
@@ -789,14 +927,14 @@ __LA_DECL int archive_write_disk_set_standard_lookup(struct archive *);
*/
__LA_DECL int archive_write_disk_set_group_lookup(struct archive *,
void * /* private_data */,
- __LA_INT64_T (*)(void *, const char *, __LA_INT64_T),
+ 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),
+ 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);
+__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
@@ -817,19 +955,19 @@ __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_INT64_T);
-__LA_DECL const char *archive_read_disk_uname(struct archive *, __LA_INT64_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_INT64_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_INT64_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 *);
@@ -846,12 +984,12 @@ __LA_DECL int archive_read_disk_can_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. */
+/* Request that the access time of the entry visited by traversal be restored. */
__LA_DECL int archive_read_disk_set_atime_restored(struct archive *);
/*
* Set behavior. The "flags" argument selects optional behavior.
*/
-/* Request that the access time of the entry visited by travesal be restored.
+/* Request that the access time of the entry visited by traversal be restored.
* This is the same as archive_read_disk_set_atime_restored. */
#define ARCHIVE_READDISK_RESTORE_ATIME (0x0001)
/* Default: Do not skip an entry which has nodump flags. */
@@ -859,8 +997,14 @@ __LA_DECL int archive_read_disk_set_atime_restored(struct archive *);
/* Default: Skip a mac resource fork file whose prefix is "._" because of
* using copyfile. */
#define ARCHIVE_READDISK_MAC_COPYFILE (0x0004)
-/* Default: Do not traverse mount points. */
+/* Default: Traverse mount points. */
#define ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS (0x0008)
+/* Default: Xattrs are read from disk. */
+#define ARCHIVE_READDISK_NO_XATTR (0x0010)
+/* Default: ACLs are read from disk. */
+#define ARCHIVE_READDISK_NO_ACL (0x0020)
+/* Default: File flags are read from disk. */
+#define ARCHIVE_READDISK_NO_FFLAGS (0x0040)
__LA_DECL int archive_read_disk_set_behavior(struct archive *,
int flags);
@@ -879,6 +1023,10 @@ __LA_DECL int archive_read_disk_set_metadata_filter_callback(struct archive *,
int (*_metadata_filter_func)(struct archive *, void *,
struct archive_entry *), void *_client_data);
+/* Simplified cleanup interface;
+ * This calls archive_read_free() or archive_write_free() as needed. */
+__LA_DECL int archive_free(struct archive *);
+
/*
* Accessor functions to read/set various information in
* the struct archive object:
@@ -889,7 +1037,7 @@ __LA_DECL int archive_read_disk_set_metadata_filter_callback(struct archive *,
* 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 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);
@@ -897,10 +1045,10 @@ __LA_DECL const char * archive_filter_name(struct archive *, int);
/* 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 *)
+__LA_DECL la_int64_t archive_position_compressed(struct archive *)
__LA_DEPRECATED;
/* 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 *)
+__LA_DECL la_int64_t archive_position_uncompressed(struct archive *)
__LA_DEPRECATED;
/* As of libarchive 3.0, this is an alias for archive_filter_name(a, 0); */
__LA_DECL const char *archive_compression_name(struct archive *)
@@ -980,7 +1128,7 @@ __LA_DECL int archive_match_time_excluded(struct archive *,
/*
* Flags to tell a matching type of time stamps. These are used for
- * following functinos.
+ * following functions.
*/
/* Time flag: mtime to be tested. */
#define ARCHIVE_MATCH_MTIME (0x0100)
@@ -1000,7 +1148,7 @@ __LA_DECL int archive_match_include_date(struct archive *, int _flag,
const char *_datestr);
__LA_DECL int archive_match_include_date_w(struct archive *, int _flag,
const wchar_t *_datestr);
-/* Set inclusion time by a particluar file. */
+/* Set inclusion time by a particular file. */
__LA_DECL int archive_match_include_file_time(struct archive *,
int _flag, const char *_pathname);
__LA_DECL int archive_match_include_file_time_w(struct archive *,
@@ -1016,8 +1164,8 @@ __LA_DECL int archive_match_exclude_entry(struct archive *,
__LA_DECL int archive_match_owner_excluded(struct archive *,
struct archive_entry *);
/* Add inclusion uid, gid, uname and gname. */
-__LA_DECL int archive_match_include_uid(struct archive *, __LA_INT64_T);
-__LA_DECL int archive_match_include_gid(struct archive *, __LA_INT64_T);
+__LA_DECL int archive_match_include_uid(struct archive *, la_int64_t);
+__LA_DECL int archive_match_include_gid(struct archive *, la_int64_t);
__LA_DECL int archive_match_include_uname(struct archive *, const char *);
__LA_DECL int archive_match_include_uname_w(struct archive *,
const wchar_t *);
@@ -1025,6 +1173,10 @@ __LA_DECL int archive_match_include_gname(struct archive *, const char *);
__LA_DECL int archive_match_include_gname_w(struct archive *,
const wchar_t *);
+/* Utility functions */
+/* Convenience function to sort a NULL terminated list of strings */
+__LA_DECL int archive_utility_string_sort(char **);
+
#ifdef __cplusplus
}
#endif
@@ -1032,9 +1184,4 @@ __LA_DECL int archive_match_include_gname_w(struct archive *,
/* These are meaningless outside of this header. */
#undef __LA_DECL
-/* These need to remain defined because they're used in the
- * callback type definitions. XXX Fix this. This is ugly. XXX */
-/* #undef __LA_INT64_T */
-/* #undef __LA_SSIZE_T */
-
#endif /* !ARCHIVE_H_INCLUDED */
diff --git a/3rdparty/libarchive/libarchive/archive_acl.c b/3rdparty/libarchive/libarchive/archive_acl.c
index bf4b6104..b8b6b636 100644
--- a/3rdparty/libarchive/libarchive/archive_acl.c
+++ b/3rdparty/libarchive/libarchive/archive_acl.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2003-2010 Tim Kientzle
+ * Copyright (c) 2016 Martin Matuska
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -55,25 +56,77 @@ static struct archive_acl_entry *acl_new_entry(struct archive_acl *acl,
static 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);
+static int archive_acl_text_want_type(struct archive_acl *acl, int flags);
+static ssize_t archive_acl_text_len(struct archive_acl *acl, int want_type,
+ int flags, int wide, struct archive *a,
+ struct archive_string_conv *sc);
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 int is_nfs4_flags_w(const wchar_t *start, const wchar_t *end,
+ int *result);
+static int is_nfs4_perms_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_entry_w(wchar_t **wp, const wchar_t *prefix, int type,
+ int tag, int flags, 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 int is_nfs4_flags(const char *start, const char *end,
+ int *result);
+static int is_nfs4_perms(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_c(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_entry(char **p, const char *prefix, int type,
+ int tag, int flags, const char *name, int perm, int id);
static void append_id(char **p, int id);
+static const struct {
+ const int perm;
+ const char c;
+ const wchar_t wc;
+} nfsv4_acl_perm_map[] = {
+ { ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 'r',
+ L'r' },
+ { ARCHIVE_ENTRY_ACL_WRITE_DATA | ARCHIVE_ENTRY_ACL_ADD_FILE, 'w',
+ L'w' },
+ { ARCHIVE_ENTRY_ACL_EXECUTE, 'x', L'x' },
+ { ARCHIVE_ENTRY_ACL_APPEND_DATA | ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY,
+ 'p', L'p' },
+ { ARCHIVE_ENTRY_ACL_DELETE, 'd', L'd' },
+ { ARCHIVE_ENTRY_ACL_DELETE_CHILD, 'D', L'D' },
+ { ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, 'a', L'a' },
+ { ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, 'A', L'A' },
+ { ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, 'R', L'R' },
+ { ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, 'W', L'W' },
+ { ARCHIVE_ENTRY_ACL_READ_ACL, 'c', L'c' },
+ { ARCHIVE_ENTRY_ACL_WRITE_ACL, 'C', L'C' },
+ { ARCHIVE_ENTRY_ACL_WRITE_OWNER, 'o', L'o' },
+ { ARCHIVE_ENTRY_ACL_SYNCHRONIZE, 's', L's' }
+};
+
+static const int nfsv4_acl_perm_map_size = (int)(sizeof(nfsv4_acl_perm_map) /
+ sizeof(nfsv4_acl_perm_map[0]));
+
+static const struct {
+ const int perm;
+ const char c;
+ const wchar_t wc;
+} nfsv4_acl_flag_map[] = {
+ { ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, 'f', L'f' },
+ { ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, 'd', L'd' },
+ { ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, 'i', L'i' },
+ { ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, 'n', L'n' },
+ { ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, 'S', L'S' },
+ { ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, 'F', L'F' },
+ { ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, 'I', L'I' }
+};
+
+static const int nfsv4_acl_flag_map_size = (int)(sizeof(nfsv4_acl_flag_map) /
+ sizeof(nfsv4_acl_flag_map[0]));
+
void
archive_acl_clear(struct archive_acl *acl)
{
@@ -94,6 +147,7 @@ archive_acl_clear(struct archive_acl *acl)
acl->acl_text = NULL;
}
acl->acl_p = NULL;
+ acl->acl_types = 0;
acl->acl_state = 0; /* Not counting. */
}
@@ -279,23 +333,31 @@ acl_new_entry(struct archive_acl *acl,
acl->acl_text = NULL;
}
- /* If there's a matching entry already in the list, overwrite it. */
+ /*
+ * If there's a matching entry already in the list, overwrite it.
+ * NFSv4 entries may be repeated and are not overwritten.
+ *
+ * TODO: compare names of no id is provided (needs more rework)
+ */
ap = acl->acl_head;
aq = NULL;
while (ap != NULL) {
- if (ap->type == type && ap->tag == tag && ap->id == id) {
- ap->permset = permset;
- return (ap);
+ if (((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) &&
+ ap->type == type && ap->tag == tag && ap->id == id) {
+ if (id != -1 || (tag != ARCHIVE_ENTRY_ACL_USER &&
+ tag != ARCHIVE_ENTRY_ACL_GROUP)) {
+ 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));
+ ap = (struct archive_acl_entry *)calloc(1, sizeof(*ap));
if (ap == NULL)
return (NULL);
- memset(ap, 0, sizeof(*ap));
if (aq == NULL)
acl->acl_head = ap;
else
@@ -331,6 +393,15 @@ archive_acl_count(struct archive_acl *acl, int want_type)
}
/*
+ * Return a bitmask of stored ACL types in an ACL list
+ */
+int
+archive_acl_types(struct archive_acl *acl)
+{
+ return (acl->acl_types);
+}
+
+/*
* 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.
@@ -366,8 +437,8 @@ archive_acl_reset(struct archive_acl *acl, int want_type)
* 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)
+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;
@@ -432,130 +503,273 @@ archive_acl_next(struct archive *a, struct archive_acl *acl, int want_type, int
}
/*
- * Generate a text version of the ACL. The flags parameter controls
- * the style of the generated ACL.
+ * Determine what type of ACL do we want
*/
-const wchar_t *
-archive_acl_text_w(struct archive *a, struct archive_acl *acl, int flags)
+static int
+archive_acl_text_want_type(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, r;
- wchar_t *wp;
+ int want_type;
- if (acl->acl_text_w != NULL) {
- free (acl->acl_text_w);
- acl->acl_text_w = NULL;
+ /* Check if ACL is NFSv4 */
+ if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
+ /* NFSv4 should never mix with POSIX.1e */
+ if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0)
+ return (0);
+ else
+ return (ARCHIVE_ENTRY_ACL_TYPE_NFS4);
}
- separator = L',';
+ /* Now deal with POSIX.1e ACLs */
+
+ want_type = 0;
+ if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)
+ want_type |= ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+ if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
+ want_type |= ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
+
+ /* By default we want both access and default ACLs */
+ if (want_type == 0)
+ return (ARCHIVE_ENTRY_ACL_TYPE_POSIX1E);
+
+ return (want_type);
+}
+
+/*
+ * Calculate ACL text string length
+ */
+static ssize_t
+archive_acl_text_len(struct archive_acl *acl, int want_type, int flags,
+ int wide, struct archive *a, struct archive_string_conv *sc) {
+ struct archive_acl_entry *ap;
+ const char *name;
+ const wchar_t *wname;
+ int count, idlen, tmp, r;
+ ssize_t length;
+ size_t len;
+
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_wcs(a, &ap->name, &wname);
- if (r == 0 && wname != NULL)
- length += wcslen(wname);
- else if (r < 0 && errno == ENOMEM)
- return (NULL);
- else
- length += sizeof(uid_t) * 3 + 1;
- length ++; /* colon */
+ for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
+ if ((ap->type & want_type) == 0)
+ continue;
+ /*
+ * Filemode-mapping ACL entries are stored exclusively in
+ * ap->mode so they should not be in the list
+ */
+ if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS)
+ && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ
+ || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ
+ || ap->tag == ARCHIVE_ENTRY_ACL_OTHER))
+ continue;
+ count++;
+ if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0
+ && (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
+ length += 8; /* "default:" */
+ switch (ap->tag) {
+ case ARCHIVE_ENTRY_ACL_USER_OBJ:
+ if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+ length += 6; /* "owner@" */
+ break;
+ }
+ /* FALLTHROUGH */
+ case ARCHIVE_ENTRY_ACL_USER:
+ case ARCHIVE_ENTRY_ACL_MASK:
+ length += 4; /* "user", "mask" */
+ break;
+ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+ if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+ length += 6; /* "group@" */
+ break;
+ }
+ /* FALLTHROUGH */
+ case ARCHIVE_ENTRY_ACL_GROUP:
+ case ARCHIVE_ENTRY_ACL_OTHER:
+ length += 5; /* "group", "other" */
+ break;
+ case ARCHIVE_ENTRY_ACL_EVERYONE:
+ length += 9; /* "everyone@" */
+ break;
+ }
+ length += 1; /* colon after tag */
+ if (ap->tag == ARCHIVE_ENTRY_ACL_USER ||
+ ap->tag == ARCHIVE_ENTRY_ACL_GROUP) {
+ if (wide) {
+ r = archive_mstring_get_wcs(a, &ap->name,
+ &wname);
+ if (r == 0 && wname != NULL)
+ length += wcslen(wname);
+ else if (r < 0 && errno == ENOMEM)
+ return (0);
+ else
+ length += sizeof(uid_t) * 3 + 1;
+ } else {
+ r = archive_mstring_get_mbs_l(&ap->name, &name,
+ &len, sc);
+ if (r != 0)
+ return (0);
+ if (len > 0 && name != NULL)
+ length += len;
+ else
+ length += sizeof(uid_t) * 3 + 1;
+ }
+ length += 1; /* colon after user or group name */
+ } else if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4)
+ length += 1; /* 2nd colon empty user,group or other */
+
+ if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0)
+ && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0)
+ && (ap->tag == ARCHIVE_ENTRY_ACL_OTHER
+ || ap->tag == ARCHIVE_ENTRY_ACL_MASK)) {
+ /* Solaris has no colon after other: and mask: */
+ length = length - 1;
+ }
+
+ if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+ /* rwxpdDaARWcCos:fdinSFI:deny */
+ length += 27;
+ if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DENY) == 0)
+ length += 1; /* allow, alarm, audit */
+ } else
length += 3; /* rwx */
+
+ if ((ap->tag == ARCHIVE_ENTRY_ACL_USER ||
+ ap->tag == ARCHIVE_ENTRY_ACL_GROUP) &&
+ (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0) {
length += 1; /* colon */
- length += max(sizeof(uid_t), sizeof(gid_t)) * 3 + 1;
- length ++; /* newline */
+ /* ID digit count */
+ idlen = 1;
+ tmp = ap->id;
+ while (tmp > 9) {
+ tmp = tmp / 10;
+ idlen++;
+ }
+ length += idlen;
}
- ap = ap->next;
+ length ++; /* entry separator */
}
- 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" */
- }
+ /* Add filemode-mapping access entries to the length */
+ if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+ if ((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0) {
+ /* "user::rwx\ngroup::rwx\nother:rwx\n" */
+ length += 31;
+ } else {
+ /* "user::rwx\ngroup::rwx\nother::rwx\n" */
+ length += 32;
+ }
+ } else if (count == 0)
+ return (0);
+
+ /* The terminating character is included in count */
+ return (length);
+}
+
+/*
+ * Generate a wide text version of the ACL. The flags parameter controls
+ * the type and style of the generated ACL.
+ */
+wchar_t *
+archive_acl_to_text_w(struct archive_acl *acl, ssize_t *text_len, int flags,
+ struct archive *a)
+{
+ int count;
+ ssize_t length;
+ size_t len;
+ const wchar_t *wname;
+ const wchar_t *prefix;
+ wchar_t separator;
+ struct archive_acl_entry *ap;
+ int id, r, want_type;
+ wchar_t *wp, *ws;
+
+ want_type = archive_acl_text_want_type(acl, flags);
+
+ /* Both NFSv4 and POSIX.1 types found */
+ if (want_type == 0)
+ return (NULL);
+
+ if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)
+ flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT;
+
+ length = archive_acl_text_len(acl, want_type, flags, 1, a, NULL);
- if (count == 0)
+ if (length == 0)
return (NULL);
+ if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA)
+ separator = L',';
+ else
+ separator = L'\n';
+
/* Now, allocate the string and actually populate it. */
- wp = acl->acl_text_w = (wchar_t *)malloc(length * sizeof(wchar_t));
- if (wp == NULL)
+ wp = ws = (wchar_t *)malloc(length * sizeof(wchar_t));
+ if (wp == NULL) {
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
return (NULL);
+ }
count = 0;
- if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
- append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
+
+ if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+ append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL,
acl->mode & 0700, -1);
- *wp++ = ',';
- append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_GROUP_OBJ, NULL,
+ *wp++ = separator;
+ append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL,
acl->mode & 0070, -1);
- *wp++ = ',';
- append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_OTHER, NULL,
+ *wp++ = separator;
+ append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_OTHER, flags, NULL,
acl->mode & 0007, -1);
count += 3;
-
- ap = acl->acl_head;
- while (ap != NULL) {
- if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
- r = archive_mstring_get_wcs(a, &ap->name, &wname);
- if (r == 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++;
- } else if (r < 0 && errno == ENOMEM)
- return (NULL);
- }
- ap = ap->next;
- }
}
-
- if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
- if (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT)
+ for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
+ if ((ap->type & want_type) == 0)
+ continue;
+ /*
+ * Filemode-mapping ACL entries are stored exclusively in
+ * ap->mode so they should not be in the list
+ */
+ if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS)
+ && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ
+ || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ
+ || ap->tag == ARCHIVE_ENTRY_ACL_OTHER))
+ continue;
+ if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT &&
+ (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0)
prefix = L"default:";
else
prefix = NULL;
- ap = acl->acl_head;
- count = 0;
- while (ap != NULL) {
- if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
- r = archive_mstring_get_wcs(a, &ap->name, &wname);
- if (r == 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 ++;
- } else if (r < 0 && errno == ENOMEM)
- return (NULL);
- }
- ap = ap->next;
- }
+ r = archive_mstring_get_wcs(a, &ap->name, &wname);
+ if (r == 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->type, ap->tag, flags,
+ wname, ap->permset, id);
+ count++;
+ } else if (r < 0 && errno == ENOMEM)
+ return (NULL);
}
- return (acl->acl_text_w);
-}
+ /* Add terminating character */
+ *wp++ = L'\0';
+
+ len = wcslen(ws);
+ if ((ssize_t)len > (length - 1))
+ __archive_errx(1, "Buffer overrun");
+
+ if (text_len != NULL)
+ *text_len = len;
+
+ return (ws);
+}
static void
append_id_w(wchar_t **wp, int id)
@@ -568,9 +782,11 @@ append_id_w(wchar_t **wp, int id)
}
static void
-append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
- const wchar_t *wname, int perm, int id)
+append_entry_w(wchar_t **wp, const wchar_t *prefix, int type,
+ int tag, int flags, const wchar_t *wname, int perm, int id)
{
+ int i;
+
if (prefix != NULL) {
wcscpy(*wp, prefix);
*wp += wcslen(*wp);
@@ -579,6 +795,10 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
case ARCHIVE_ENTRY_ACL_USER_OBJ:
wname = NULL;
id = -1;
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
+ wcscpy(*wp, L"owner@");
+ break;
+ }
/* FALLTHROUGH */
case ARCHIVE_ENTRY_ACL_USER:
wcscpy(*wp, L"user");
@@ -586,6 +806,10 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
wname = NULL;
id = -1;
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
+ wcscpy(*wp, L"group@");
+ break;
+ }
/* FALLTHROUGH */
case ARCHIVE_ENTRY_ACL_GROUP:
wcscpy(*wp, L"group");
@@ -600,153 +824,184 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
wname = NULL;
id = -1;
break;
+ case ARCHIVE_ENTRY_ACL_EVERYONE:
+ wcscpy(*wp, L"everyone@");
+ wname = NULL;
+ id = -1;
+ break;
}
*wp += wcslen(*wp);
*(*wp)++ = L':';
- if (wname != NULL) {
- wcscpy(*wp, wname);
+ if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) ||
+ tag == ARCHIVE_ENTRY_ACL_USER ||
+ tag == ARCHIVE_ENTRY_ACL_GROUP) {
+ 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);
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0)
+ id = -1;
+ }
+ /* Solaris style has no second colon after other and mask */
+ if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0)
+ || (tag != ARCHIVE_ENTRY_ACL_OTHER
+ && tag != ARCHIVE_ENTRY_ACL_MASK))
+ *(*wp)++ = L':';
+ }
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
+ /* POSIX.1e ACL perms */
+ *(*wp)++ = (perm & 0444) ? L'r' : L'-';
+ *(*wp)++ = (perm & 0222) ? L'w' : L'-';
+ *(*wp)++ = (perm & 0111) ? L'x' : L'-';
+ } else {
+ /* NFSv4 ACL perms */
+ for (i = 0; i < nfsv4_acl_perm_map_size; i++) {
+ if (perm & nfsv4_acl_perm_map[i].perm)
+ *(*wp)++ = nfsv4_acl_perm_map[i].wc;
+ else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0)
+ *(*wp)++ = L'-';
+ }
+ *(*wp)++ = L':';
+ for (i = 0; i < nfsv4_acl_flag_map_size; i++) {
+ if (perm & nfsv4_acl_flag_map[i].perm)
+ *(*wp)++ = nfsv4_acl_flag_map[i].wc;
+ else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0)
+ *(*wp)++ = L'-';
+ }
+ *(*wp)++ = L':';
+ switch (type) {
+ case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
+ wcscpy(*wp, L"allow");
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_DENY:
+ wcscpy(*wp, L"deny");
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
+ wcscpy(*wp, L"audit");
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
+ wcscpy(*wp, L"alarm");
+ break;
+ default:
+ break;
+ }
*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,
+/*
+ * Generate a text version of the ACL. The flags parameter controls
+ * the type and style of the generated ACL.
+ */
+char *
+archive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags,
struct archive_string_conv *sc)
{
int count;
- size_t length;
+ ssize_t length;
+ size_t len;
const char *name;
const char *prefix;
char separator;
struct archive_acl_entry *ap;
- size_t len;
- int id, r;
- char *p;
+ int id, r, want_type;
+ char *p, *s;
- if (acl->acl_text != NULL) {
- free (acl->acl_text);
- acl->acl_text = NULL;
- }
+ want_type = archive_acl_text_want_type(acl, flags);
- *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;
- }
+ /* Both NFSv4 and POSIX.1 types found */
+ if (want_type == 0)
+ return (NULL);
- 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 (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)
+ flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT;
- if (count == 0)
- return (0);
+ length = archive_acl_text_len(acl, want_type, flags, 0, NULL, sc);
+
+ if (length == 0)
+ return (NULL);
+
+ if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA)
+ separator = ',';
+ else
+ separator = '\n';
/* Now, allocate the string and actually populate it. */
- p = acl->acl_text = (char *)malloc(length);
- if (p == NULL)
- return (-1);
+ p = s = (char *)malloc(length * sizeof(char));
+ if (p == NULL) {
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
+ return (NULL);
+ }
count = 0;
- if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
- append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
+
+ if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+ append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL,
acl->mode & 0700, -1);
- *p++ = ',';
- append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_GROUP_OBJ, NULL,
+ *p++ = separator;
+ append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL,
acl->mode & 0070, -1);
- *p++ = ',';
- append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_OTHER, NULL,
+ *p++ = separator;
+ append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_OTHER, flags, 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)
+ for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
+ if ((ap->type & want_type) == 0)
+ continue;
+ /*
+ * Filemode-mapping ACL entries are stored exclusively in
+ * ap->mode so they should not be in the list
+ */
+ if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS)
+ && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ
+ || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ
+ || ap->tag == ARCHIVE_ENTRY_ACL_OTHER))
+ continue;
+ if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT &&
+ (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0)
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 ++;
+ r = archive_mstring_get_mbs_l(
+ &ap->name, &name, &len, sc);
+ if (r != 0)
+ return (NULL);
+ if (count > 0)
+ *p++ = separator;
+ if (name == NULL ||
+ (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)) {
+ id = ap->id;
+ } else {
+ id = -1;
}
+ append_entry(&p, prefix, ap->type, ap->tag, flags, name,
+ ap->permset, id);
+ count++;
}
- *acl_text = acl->acl_text;
- if (acl_text_len != NULL)
- *acl_text_len = strlen(acl->acl_text);
- return (0);
+ /* Add terminating character */
+ *p++ = '\0';
+
+ len = strlen(s);
+
+ if ((ssize_t)len > (length - 1))
+ __archive_errx(1, "Buffer overrun");
+
+ if (text_len != NULL)
+ *text_len = len;
+
+ return (s);
}
static void
@@ -760,9 +1015,11 @@ append_id(char **p, int id)
}
static void
-append_entry(char **p, const char *prefix, int tag,
- const char *name, int perm, int id)
+append_entry(char **p, const char *prefix, int type,
+ int tag, int flags, const char *name, int perm, int id)
{
+ int i;
+
if (prefix != NULL) {
strcpy(*p, prefix);
*p += strlen(*p);
@@ -771,6 +1028,10 @@ append_entry(char **p, const char *prefix, int tag,
case ARCHIVE_ENTRY_ACL_USER_OBJ:
name = NULL;
id = -1;
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
+ strcpy(*p, "owner@");
+ break;
+ }
/* FALLTHROUGH */
case ARCHIVE_ENTRY_ACL_USER:
strcpy(*p, "user");
@@ -778,6 +1039,10 @@ append_entry(char **p, const char *prefix, int tag,
case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
name = NULL;
id = -1;
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
+ strcpy(*p, "group@");
+ break;
+ }
/* FALLTHROUGH */
case ARCHIVE_ENTRY_ACL_GROUP:
strcpy(*p, "group");
@@ -792,48 +1057,120 @@ append_entry(char **p, const char *prefix, int tag,
name = NULL;
id = -1;
break;
+ case ARCHIVE_ENTRY_ACL_EVERYONE:
+ strcpy(*p, "everyone@");
+ name = NULL;
+ id = -1;
+ break;
}
*p += strlen(*p);
*(*p)++ = ':';
- if (name != NULL) {
- strcpy(*p, name);
+ if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) ||
+ tag == ARCHIVE_ENTRY_ACL_USER ||
+ tag == ARCHIVE_ENTRY_ACL_GROUP) {
+ 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);
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0)
+ id = -1;
+ }
+ /* Solaris style has no second colon after other and mask */
+ if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0)
+ || (tag != ARCHIVE_ENTRY_ACL_OTHER
+ && tag != ARCHIVE_ENTRY_ACL_MASK))
+ *(*p)++ = ':';
+ }
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
+ /* POSIX.1e ACL perms */
+ *(*p)++ = (perm & 0444) ? 'r' : '-';
+ *(*p)++ = (perm & 0222) ? 'w' : '-';
+ *(*p)++ = (perm & 0111) ? 'x' : '-';
+ } else {
+ /* NFSv4 ACL perms */
+ for (i = 0; i < nfsv4_acl_perm_map_size; i++) {
+ if (perm & nfsv4_acl_perm_map[i].perm)
+ *(*p)++ = nfsv4_acl_perm_map[i].c;
+ else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0)
+ *(*p)++ = '-';
+ }
+ *(*p)++ = ':';
+ for (i = 0; i < nfsv4_acl_flag_map_size; i++) {
+ if (perm & nfsv4_acl_flag_map[i].perm)
+ *(*p)++ = nfsv4_acl_flag_map[i].c;
+ else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0)
+ *(*p)++ = '-';
+ }
+ *(*p)++ = ':';
+ switch (type) {
+ case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
+ strcpy(*p, "allow");
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_DENY:
+ strcpy(*p, "deny");
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
+ strcpy(*p, "audit");
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
+ strcpy(*p, "alarm");
+ break;
+ }
*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:".
+ * Parse a wide ACL text string.
+ *
+ * The want_type argument may be one of the following:
+ * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS
+ * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT
+ * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL
+ *
+ * POSIX.1e ACL entries prefixed with "default:" are treated as
+ * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4
*/
int
-archive_acl_parse_w(struct archive_acl *acl,
- const wchar_t *text, int default_type)
+archive_acl_from_text_w(struct archive_acl *acl, const wchar_t *text,
+ int want_type)
{
struct {
const wchar_t *start;
const wchar_t *end;
- } field[4], name;
+ } field[6], name;
+
+ const wchar_t *s, *st;
- int fields, n;
- int type, tag, permset, id;
+ int numfields, fields, n, r, sol, ret;
+ int type, types, tag, permset, id;
+ size_t len;
wchar_t sep;
- while (text != NULL && *text != L'\0') {
+ ret = ARCHIVE_OK;
+ types = 0;
+
+ switch (want_type) {
+ case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E:
+ want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+ case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
+ case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
+ numfields = 5;
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_NFS4:
+ numfields = 6;
+ break;
+ default:
+ return (ARCHIVE_FATAL);
+ }
+
+ while (text != NULL && *text != L'\0') {
/*
* Parse the fields out of the next entry,
* advance 'text' to start of next entry.
@@ -842,7 +1179,7 @@ archive_acl_parse_w(struct archive_acl *acl,
do {
const wchar_t *start, *end;
next_field_w(&text, &start, &end, &sep);
- if (fields < 4) {
+ if (fields < numfields) {
field[fields].start = start;
field[fields].end = end;
}
@@ -850,78 +1187,210 @@ archive_acl_parse_w(struct archive_acl *acl,
} while (sep == L':');
/* Set remaining fields to blank. */
- for (n = fields; n < 4; ++n)
+ for (n = fields; n < numfields; ++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;
+ if (field[0].start != NULL && *(field[0].start) == L'#') {
+ /* Comment, skip entry */
+ continue;
+ }
+ n = 0;
+ sol = 0;
+ id = -1;
+ permset = 0;
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];
+
+ if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+ /* POSIX.1e ACLs */
+ /*
+ * Default keyword "default:user::rwx"
+ * if found, we have one more field
+ *
+ * We also support old Solaris extension:
+ * "defaultuser::rwx" is the default ACL corresponding
+ * to "user::rwx", etc. valid only for first field
+ */
+ s = field[0].start;
+ len = field[0].end - field[0].start;
+ if (*s == L'd' && (len == 1 || (len >= 7
+ && wmemcmp((s + 1), L"efault", 6) == 0))) {
+ type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
+ if (len > 7)
+ field[0].start += 7;
+ else
+ n = 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;
+ type = want_type;
+
+ /* Check for a numeric ID in field n+1 or n+3. */
+ isint_w(field[n + 1].start, field[n + 1].end, &id);
+ /* Field n+3 is optional. */
+ if (id == -1 && fields > n+3)
+ isint_w(field[n + 3].start, field[n + 3].end,
+ &id);
+
+ tag = 0;
+ s = field[n].start;
+ st = field[n].start + 1;
+ len = field[n].end - field[n].start;
+
+ switch (*s) {
+ case L'u':
+ if (len == 1 || (len == 4
+ && wmemcmp(st, L"ser", 3) == 0))
+ tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+ break;
+ case L'g':
+ if (len == 1 || (len == 5
+ && wmemcmp(st, L"roup", 4) == 0))
+ tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+ break;
+ case L'o':
+ if (len == 1 || (len == 5
+ && wmemcmp(st, L"ther", 4) == 0))
+ tag = ARCHIVE_ENTRY_ACL_OTHER;
+ break;
+ case L'm':
+ if (len == 1 || (len == 4
+ && wmemcmp(st, L"ask", 3) == 0))
+ tag = ARCHIVE_ENTRY_ACL_MASK;
+ break;
+ default:
+ break;
+ }
+
+ switch (tag) {
+ case ARCHIVE_ENTRY_ACL_OTHER:
+ case ARCHIVE_ENTRY_ACL_MASK:
+ if (fields == (n + 2)
+ && field[n + 1].start < field[n + 1].end
+ && ismode_w(field[n + 1].start,
+ field[n + 1].end, &permset)) {
+ /* This is Solaris-style "other:rwx" */
+ sol = 1;
+ } else if (fields == (n + 3) &&
+ field[n + 1].start < field[n + 1].end) {
+ /* Invalid mask or other field */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ break;
+ case ARCHIVE_ENTRY_ACL_USER_OBJ:
+ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+ if (id != -1 ||
+ field[n + 1].start < field[n + 1].end) {
+ name = field[n + 1];
+ if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ)
+ tag = ARCHIVE_ENTRY_ACL_USER;
+ else
+ tag = ARCHIVE_ENTRY_ACL_GROUP;
+ }
+ break;
+ default:
+ /* Invalid tag, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+
+ /*
+ * Without "default:" we expect mode in field 2
+ * Exception: Solaris other and mask fields
+ */
+ if (permset == 0 && !ismode_w(field[n + 2 - sol].start,
+ field[n + 2 - sol].end, &permset)) {
+ /* Invalid mode, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ } else {
+ /* NFS4 ACLs */
+ s = field[0].start;
+ len = field[0].end - field[0].start;
+ tag = 0;
+
+ switch (len) {
+ case 4:
+ if (wmemcmp(s, L"user", 4) == 0)
+ tag = ARCHIVE_ENTRY_ACL_USER;
+ break;
+ case 5:
+ if (wmemcmp(s, L"group", 5) == 0)
+ tag = ARCHIVE_ENTRY_ACL_GROUP;
+ break;
+ case 6:
+ if (wmemcmp(s, L"owner@", 6) == 0)
+ tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+ else if (wmemcmp(s, L"group@", len) == 0)
+ tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+ break;
+ case 9:
+ if (wmemcmp(s, L"everyone@", 9) == 0)
+ tag = ARCHIVE_ENTRY_ACL_EVERYONE;
+ default:
+ break;
+ }
+
+ if (tag == 0) {
+ /* Invalid tag, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ } else if (tag == ARCHIVE_ENTRY_ACL_USER ||
+ tag == ARCHIVE_ENTRY_ACL_GROUP) {
+ n = 1;
name = field[1];
+ isint_w(name.start, name.end, &id);
} 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);
+ n = 0;
+
+ if (!is_nfs4_perms_w(field[1 + n].start,
+ field[1 + n].end, &permset)) {
+ /* Invalid NFSv4 perms, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ if (!is_nfs4_flags_w(field[2 + n].start,
+ field[2 + n].end, &permset)) {
+ /* Invalid NFSv4 flags, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ s = field[3 + n].start;
+ len = field[3 + n].end - field[3 + n].start;
+ type = 0;
+ if (len == 4) {
+ if (wmemcmp(s, L"deny", 4) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
+ } else if (len == 5) {
+ if (wmemcmp(s, L"allow", 5) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
+ else if (wmemcmp(s, L"audit", 5) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;
+ else if (wmemcmp(s, L"alarm", 5) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
+ }
+ if (type == 0) {
+ /* Invalid entry type, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ isint_w(field[4 + n].start, field[4 + n].end, &id);
+ }
/* Add entry to the internal list. */
- archive_acl_add_entry_w_len(acl, type, permset,
+ r = archive_acl_add_entry_w_len(acl, type, permset,
tag, id, name.start, name.end - name.start);
+ if (r < ARCHIVE_WARN)
+ return (r);
+ if (r != ARCHIVE_OK)
+ ret = ARCHIVE_WARN;
+ types |= type;
}
- return (ARCHIVE_OK);
+
+ /* Reset ACL */
+ archive_acl_reset(acl, types);
+
+ return (ret);
}
/*
@@ -967,16 +1436,122 @@ ismode_w(const wchar_t *start, const wchar_t *end, int *permset)
*permset = 0;
while (p < end) {
switch (*p++) {
- case 'r': case 'R':
+ case L'r': case L'R':
*permset |= ARCHIVE_ENTRY_ACL_READ;
break;
- case 'w': case 'W':
+ case L'w': case L'W':
*permset |= ARCHIVE_ENTRY_ACL_WRITE;
break;
- case 'x': case 'X':
+ case L'x': case L'X':
*permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
break;
- case '-':
+ case L'-':
+ break;
+ default:
+ return (0);
+ }
+ }
+ return (1);
+}
+
+/*
+ * Parse a string as a NFS4 ACL permission field.
+ * Returns true if the string is non-empty and consists only of NFS4 ACL
+ * permission characters, false otherwise
+ */
+static int
+is_nfs4_perms_w(const wchar_t *start, const wchar_t *end, int *permset)
+{
+ const wchar_t *p = start;
+
+ while (p < end) {
+ switch (*p++) {
+ case L'r':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_DATA;
+ break;
+ case L'w':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA;
+ break;
+ case L'x':
+ *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
+ break;
+ case L'p':
+ *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA;
+ break;
+ case L'D':
+ *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD;
+ break;
+ case L'd':
+ *permset |= ARCHIVE_ENTRY_ACL_DELETE;
+ break;
+ case L'a':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES;
+ break;
+ case L'A':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES;
+ break;
+ case L'R':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS;
+ break;
+ case L'W':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS;
+ break;
+ case L'c':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_ACL;
+ break;
+ case L'C':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL;
+ break;
+ case L'o':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER;
+ break;
+ case L's':
+ *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE;
+ break;
+ case L'-':
+ break;
+ default:
+ return(0);
+ }
+ }
+ return (1);
+}
+
+/*
+ * Parse a string as a NFS4 ACL flags field.
+ * Returns true if the string is non-empty and consists only of NFS4 ACL
+ * flag characters, false otherwise
+ */
+static int
+is_nfs4_flags_w(const wchar_t *start, const wchar_t *end, int *permset)
+{
+ const wchar_t *p = start;
+
+ while (p < end) {
+ switch(*p++) {
+ case L'f':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT;
+ break;
+ case L'd':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT;
+ break;
+ case L'i':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY;
+ break;
+ case L'n':
+ *permset |=
+ ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT;
+ break;
+ case L'S':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS;
+ break;
+ case L'F':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS;
+ break;
+ case L'I':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED;
+ break;
+ case L'-':
break;
default:
return (0);
@@ -1023,46 +1598,48 @@ next_field_w(const wchar_t **wp, const wchar_t **start,
}
/*
- * 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:".
+ * Parse an ACL text string.
+ *
+ * The want_type argument may be one of the following:
+ * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS
+ * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT
+ * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL
+ *
+ * POSIX.1e ACL entries prefixed with "default:" are treated as
+ * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4
*/
int
-archive_acl_parse_l(struct archive_acl *acl,
- const char *text, int default_type, struct archive_string_conv *sc)
+archive_acl_from_text_l(struct archive_acl *acl, const char *text,
+ int want_type, struct archive_string_conv *sc)
{
struct {
const char *start;
const char *end;
- } field[4], name;
+ } field[6], name;
- int fields, n, r, ret = ARCHIVE_OK;
- int type, tag, permset, id;
+ const char *s, *st;
+ int numfields, fields, n, r, sol, ret;
+ int type, types, tag, permset, id;
+ size_t len;
char sep;
+ switch (want_type) {
+ case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E:
+ want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+ case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
+ case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
+ numfields = 5;
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_NFS4:
+ numfields = 6;
+ break;
+ default:
+ return (ARCHIVE_FATAL);
+ }
+
+ ret = ARCHIVE_OK;
+ types = 0;
+
while (text != NULL && *text != '\0') {
/*
* Parse the fields out of the next entry,
@@ -1072,7 +1649,7 @@ archive_acl_parse_l(struct archive_acl *acl,
do {
const char *start, *end;
next_field(&text, &start, &end, &sep);
- if (fields < 4) {
+ if (fields < numfields) {
field[fields].start = start;
field[fields].end = end;
}
@@ -1080,72 +1657,197 @@ archive_acl_parse_l(struct archive_acl *acl,
} while (sep == ':');
/* Set remaining fields to blank. */
- for (n = fields; n < 4; ++n)
+ for (n = fields; n < numfields; ++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;
+ if (field[0].start != NULL && *(field[0].start) == '#') {
+ /* Comment, skip entry */
+ continue;
+ }
+ n = 0;
+ sol = 0;
+ id = -1;
+ permset = 0;
name.start = name.end = NULL;
- if (prefix_c(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];
+
+ if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+ /* POSIX.1e ACLs */
+ /*
+ * Default keyword "default:user::rwx"
+ * if found, we have one more field
+ *
+ * We also support old Solaris extension:
+ * "defaultuser::rwx" is the default ACL corresponding
+ * to "user::rwx", etc. valid only for first field
+ */
+ s = field[0].start;
+ len = field[0].end - field[0].start;
+ if (*s == 'd' && (len == 1 || (len >= 7
+ && memcmp((s + 1), "efault", 6) == 0))) {
+ type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
+ if (len > 7)
+ field[0].start += 7;
+ else
+ n = 1;
} else
- tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
- } else if (prefix_c(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;
+ type = want_type;
+
+ /* Check for a numeric ID in field n+1 or n+3. */
+ isint(field[n + 1].start, field[n + 1].end, &id);
+ /* Field n+3 is optional. */
+ if (id == -1 && fields > (n + 3))
+ isint(field[n + 3].start, field[n + 3].end,
+ &id);
+
+ tag = 0;
+ s = field[n].start;
+ st = field[n].start + 1;
+ len = field[n].end - field[n].start;
+
+ switch (*s) {
+ case 'u':
+ if (len == 1 || (len == 4
+ && memcmp(st, "ser", 3) == 0))
+ tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+ break;
+ case 'g':
+ if (len == 1 || (len == 5
+ && memcmp(st, "roup", 4) == 0))
+ tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+ break;
+ case 'o':
+ if (len == 1 || (len == 5
+ && memcmp(st, "ther", 4) == 0))
+ tag = ARCHIVE_ENTRY_ACL_OTHER;
+ break;
+ case 'm':
+ if (len == 1 || (len == 4
+ && memcmp(st, "ask", 3) == 0))
+ tag = ARCHIVE_ENTRY_ACL_MASK;
+ break;
+ default:
+ break;
+ }
+
+ switch (tag) {
+ case ARCHIVE_ENTRY_ACL_OTHER:
+ case ARCHIVE_ENTRY_ACL_MASK:
+ if (fields == (n + 2)
+ && field[n + 1].start < field[n + 1].end
+ && ismode(field[n + 1].start,
+ field[n + 1].end, &permset)) {
+ /* This is Solaris-style "other:rwx" */
+ sol = 1;
+ } else if (fields == (n + 3) &&
+ field[n + 1].start < field[n + 1].end) {
+ /* Invalid mask or other field */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ break;
+ case ARCHIVE_ENTRY_ACL_USER_OBJ:
+ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+ if (id != -1 ||
+ field[n + 1].start < field[n + 1].end) {
+ name = field[n + 1];
+ if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ)
+ tag = ARCHIVE_ENTRY_ACL_USER;
+ else
+ tag = ARCHIVE_ENTRY_ACL_GROUP;
+ }
+ break;
+ default:
+ /* Invalid tag, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+
+ /*
+ * Without "default:" we expect mode in field 3
+ * Exception: Solaris other and mask fields
+ */
+ if (permset == 0 && !ismode(field[n + 2 - sol].start,
+ field[n + 2 - sol].end, &permset)) {
+ /* Invalid mode, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ } else {
+ /* NFS4 ACLs */
+ s = field[0].start;
+ len = field[0].end - field[0].start;
+ tag = 0;
+
+ switch (len) {
+ case 4:
+ if (memcmp(s, "user", 4) == 0)
+ tag = ARCHIVE_ENTRY_ACL_USER;
+ break;
+ case 5:
+ if (memcmp(s, "group", 5) == 0)
+ tag = ARCHIVE_ENTRY_ACL_GROUP;
+ break;
+ case 6:
+ if (memcmp(s, "owner@", 6) == 0)
+ tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+ else if (memcmp(s, "group@", 6) == 0)
+ tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+ break;
+ case 9:
+ if (memcmp(s, "everyone@", 9) == 0)
+ tag = ARCHIVE_ENTRY_ACL_EVERYONE;
+ break;
+ default:
+ break;
+ }
+
+ if (tag == 0) {
+ /* Invalid tag, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ } else if (tag == ARCHIVE_ENTRY_ACL_USER ||
+ tag == ARCHIVE_ENTRY_ACL_GROUP) {
+ n = 1;
name = field[1];
+ isint(name.start, name.end, &id);
} else
- tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
- } else if (prefix_c(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_c(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);
+ n = 0;
+
+ if (!is_nfs4_perms(field[1 + n].start,
+ field[1 + n].end, &permset)) {
+ /* Invalid NFSv4 perms, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ if (!is_nfs4_flags(field[2 + n].start,
+ field[2 + n].end, &permset)) {
+ /* Invalid NFSv4 flags, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ s = field[3 + n].start;
+ len = field[3 + n].end - field[3 + n].start;
+ type = 0;
+ if (len == 4) {
+ if (memcmp(s, "deny", 4) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
+ } else if (len == 5) {
+ if (memcmp(s, "allow", 5) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
+ else if (memcmp(s, "audit", 5) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;
+ else if (memcmp(s, "alarm", 5) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
+ }
+ if (type == 0) {
+ /* Invalid entry type, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ isint(field[4 + n].start, field[4 + n].end,
+ &id);
+ }
/* Add entry to the internal list. */
r = archive_acl_add_entry_len_l(acl, type, permset,
@@ -1154,7 +1856,12 @@ archive_acl_parse_l(struct archive_acl *acl,
return (r);
if (r != ARCHIVE_OK)
ret = ARCHIVE_WARN;
+ types |= type;
}
+
+ /* Reset ACL */
+ archive_acl_reset(acl, types);
+
return (ret);
}
@@ -1220,6 +1927,112 @@ ismode(const char *start, const char *end, int *permset)
}
/*
+ * Parse a string as a NFS4 ACL permission field.
+ * Returns true if the string is non-empty and consists only of NFS4 ACL
+ * permission characters, false otherwise
+ */
+static int
+is_nfs4_perms(const char *start, const char *end, int *permset)
+{
+ const char *p = start;
+
+ while (p < end) {
+ switch (*p++) {
+ case 'r':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_DATA;
+ break;
+ case 'w':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA;
+ break;
+ case 'x':
+ *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
+ break;
+ case 'p':
+ *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA;
+ break;
+ case 'D':
+ *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD;
+ break;
+ case 'd':
+ *permset |= ARCHIVE_ENTRY_ACL_DELETE;
+ break;
+ case 'a':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES;
+ break;
+ case 'A':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES;
+ break;
+ case 'R':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS;
+ break;
+ case 'W':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS;
+ break;
+ case 'c':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_ACL;
+ break;
+ case 'C':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL;
+ break;
+ case 'o':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER;
+ break;
+ case 's':
+ *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE;
+ break;
+ case '-':
+ break;
+ default:
+ return(0);
+ }
+ }
+ return (1);
+}
+
+/*
+ * Parse a string as a NFS4 ACL flags field.
+ * Returns true if the string is non-empty and consists only of NFS4 ACL
+ * flag characters, false otherwise
+ */
+static int
+is_nfs4_flags(const char *start, const char *end, int *permset)
+{
+ const char *p = start;
+
+ while (p < end) {
+ switch(*p++) {
+ case 'f':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT;
+ break;
+ case 'd':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT;
+ break;
+ case 'i':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY;
+ break;
+ case 'n':
+ *permset |=
+ ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT;
+ break;
+ case 'S':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS;
+ break;
+ case 'F':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS;
+ break;
+ case 'I':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED;
+ 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
@@ -1254,25 +2067,3 @@ next_field(const char **p, const char **start,
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_c(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/3rdparty/libarchive/libarchive/archive_acl_private.h b/3rdparty/libarchive/libarchive/archive_acl_private.h
index 1421adbf..ef0b0234 100644
--- a/3rdparty/libarchive/libarchive/archive_acl_private.h
+++ b/3rdparty/libarchive/libarchive/archive_acl_private.h
@@ -56,6 +56,7 @@ struct archive_acl {
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_types(struct archive_acl *);
int archive_acl_reset(struct archive_acl *, int);
int archive_acl_next(struct archive *, struct archive_acl *, int,
int *, int *, int *, int *, const char **);
@@ -66,22 +67,17 @@ int archive_acl_add_entry_w_len(struct archive_acl *,
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 *,
+wchar_t *archive_acl_to_text_w(struct archive_acl *, ssize_t *, int,
+ struct archive *);
+char *archive_acl_to_text_l(struct archive_acl *, ssize_t *, int,
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.
+ * ACL text parser.
*/
-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 *);
+int archive_acl_from_text_w(struct archive_acl *, const wchar_t * /* wtext */,
+ int /* type */);
+int archive_acl_from_text_l(struct archive_acl *, const char * /* text */,
+ int /* type */, struct archive_string_conv *);
#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */
diff --git a/3rdparty/libarchive/libarchive/archive_check_magic.c b/3rdparty/libarchive/libarchive/archive_check_magic.c
index c695e582..288ce233 100644
--- a/3rdparty/libarchive/libarchive/archive_check_magic.c
+++ b/3rdparty/libarchive/libarchive/archive_check_magic.c
@@ -62,7 +62,7 @@ errmsg(const char *m)
}
}
-static void
+static __LA_DEAD void
diediedie(void)
{
#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
diff --git a/3rdparty/libarchive/libarchive/archive_crypto.c b/3rdparty/libarchive/libarchive/archive_crypto.c
deleted file mode 100644
index 85aba3ae..00000000
--- a/3rdparty/libarchive/libarchive/archive_crypto.c
+++ /dev/null
@@ -1,1429 +0,0 @@
-/*-
-* 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 = (DWORD)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. Nettle
- * 6. OpenSSL
- * 7. libmd
- * 8. 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/3rdparty/libarchive/libarchive/archive_crypto_private.h b/3rdparty/libarchive/libarchive/archive_crypto_private.h
deleted file mode 100644
index f8b1fb3c..00000000
--- a/3rdparty/libarchive/libarchive/archive_crypto_private.h
+++ /dev/null
@@ -1,376 +0,0 @@
-/*-
-* 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
diff --git a/3rdparty/libarchive/libarchive/archive_endian.h b/3rdparty/libarchive/libarchive/archive_endian.h
index 68123b0d..1c48563b 100644
--- a/3rdparty/libarchive/libarchive/archive_endian.h
+++ b/3rdparty/libarchive/libarchive/archive_endian.h
@@ -44,10 +44,16 @@
* - Watcom C++ in C code. (For any version?)
* - SGI MIPSpro
* - Microsoft Visual C++ 6.0 (supposedly newer versions too)
+ * - IBM VisualAge 6 (XL v6)
+ * - Sun WorkShop C (SunPro) before 5.9
*/
#if defined(__WATCOMC__) || defined(__sgi) || defined(__hpux) || defined(__BORLANDC__)
#define inline
-#elif defined(_MSC_VER)
+#elif defined(__IBMC__) && __IBMC__ < 700
+#define inline
+#elif defined(__SUNPRO_C) && __SUNPRO_C < 0x590
+#define inline
+#elif defined(_MSC_VER) || defined(__osf__)
#define inline __inline
#endif
@@ -58,7 +64,13 @@ archive_be16dec(const void *pp)
{
unsigned char const *p = (unsigned char const *)pp;
- return ((p[0] << 8) | p[1]);
+ /* Store into unsigned temporaries before left shifting, to avoid
+ promotion to signed int and then left shifting into the sign bit,
+ which is undefined behaviour. */
+ unsigned int p1 = p[1];
+ unsigned int p0 = p[0];
+
+ return ((p0 << 8) | p1);
}
static inline uint32_t
@@ -66,7 +78,15 @@ archive_be32dec(const void *pp)
{
unsigned char const *p = (unsigned char const *)pp;
- return ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+ /* Store into unsigned temporaries before left shifting, to avoid
+ promotion to signed int and then left shifting into the sign bit,
+ which is undefined behaviour. */
+ unsigned int p3 = p[3];
+ unsigned int p2 = p[2];
+ unsigned int p1 = p[1];
+ unsigned int p0 = p[0];
+
+ return ((p0 << 24) | (p1 << 16) | (p2 << 8) | p3);
}
static inline uint64_t
@@ -82,7 +102,13 @@ archive_le16dec(const void *pp)
{
unsigned char const *p = (unsigned char const *)pp;
- return ((p[1] << 8) | p[0]);
+ /* Store into unsigned temporaries before left shifting, to avoid
+ promotion to signed int and then left shifting into the sign bit,
+ which is undefined behaviour. */
+ unsigned int p1 = p[1];
+ unsigned int p0 = p[0];
+
+ return ((p1 << 8) | p0);
}
static inline uint32_t
@@ -90,7 +116,15 @@ archive_le32dec(const void *pp)
{
unsigned char const *p = (unsigned char const *)pp;
- return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
+ /* Store into unsigned temporaries before left shifting, to avoid
+ promotion to signed int and then left shifting into the sign bit,
+ which is undefined behaviour. */
+ unsigned int p3 = p[3];
+ unsigned int p2 = p[2];
+ unsigned int p1 = p[1];
+ unsigned int p0 = p[0];
+
+ return ((p3 << 24) | (p2 << 16) | (p1 << 8) | p0);
}
static inline uint64_t
diff --git a/3rdparty/libarchive/libarchive/archive_entry.c b/3rdparty/libarchive/libarchive/archive_entry.c
index 386e51d4..30fb4566 100644
--- a/3rdparty/libarchive/libarchive/archive_entry.c
+++ b/3rdparty/libarchive/libarchive/archive_entry.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2016 Martin Matuska
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -201,6 +202,9 @@ archive_entry_clone(struct archive_entry *entry)
entry2->ae_set = entry->ae_set;
archive_mstring_copy(&entry2->ae_uname, &entry->ae_uname);
+ /* Copy encryption status */
+ entry2->encryption = entry->encryption;
+
/* Copy ACL data over. */
archive_acl_copy(&entry2->acl, &entry->acl);
@@ -245,10 +249,9 @@ archive_entry_new2(struct archive *a)
{
struct archive_entry *entry;
- entry = (struct archive_entry *)malloc(sizeof(*entry));
+ entry = (struct archive_entry *)calloc(1, sizeof(*entry));
if (entry == NULL)
return (NULL);
- memset(entry, 0, sizeof(*entry));
entry->archive = a;
return (entry);
}
@@ -398,7 +401,7 @@ archive_entry_fflags_text(struct archive_entry *entry)
return (NULL);
}
-int64_t
+la_int64_t
archive_entry_gid(struct archive_entry *entry)
{
return (entry->ae_stat.aest_gid);
@@ -415,6 +418,18 @@ archive_entry_gname(struct archive_entry *entry)
return (NULL);
}
+const char *
+archive_entry_gname_utf8(struct archive_entry *entry)
+{
+ const char *p;
+ if (archive_mstring_get_utf8(entry->archive, &entry->ae_gname, &p) == 0)
+ return (p);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
+ return (NULL);
+}
+
+
const wchar_t *
archive_entry_gname_w(struct archive_entry *entry)
{
@@ -447,6 +462,20 @@ archive_entry_hardlink(struct archive_entry *entry)
return (NULL);
}
+const char *
+archive_entry_hardlink_utf8(struct archive_entry *entry)
+{
+ const char *p;
+ if ((entry->ae_set & AE_SET_HARDLINK) == 0)
+ return (NULL);
+ if (archive_mstring_get_utf8(
+ entry->archive, &entry->ae_hardlink, &p) == 0)
+ return (p);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
+ return (NULL);
+}
+
const wchar_t *
archive_entry_hardlink_w(struct archive_entry *entry)
{
@@ -473,7 +502,7 @@ _archive_entry_hardlink_l(struct archive_entry *entry,
return (archive_mstring_get_mbs_l(&entry->ae_hardlink, p, len, sc));
}
-int64_t
+la_int64_t
archive_entry_ino(struct archive_entry *entry)
{
return (entry->ae_stat.aest_ino);
@@ -485,7 +514,7 @@ archive_entry_ino_is_set(struct archive_entry *entry)
return (entry->ae_set & AE_SET_INO);
}
-int64_t
+la_int64_t
archive_entry_ino64(struct archive_entry *entry)
{
return (entry->ae_stat.aest_ino);
@@ -533,6 +562,18 @@ archive_entry_pathname(struct archive_entry *entry)
return (NULL);
}
+const char *
+archive_entry_pathname_utf8(struct archive_entry *entry)
+{
+ const char *p;
+ if (archive_mstring_get_utf8(
+ entry->archive, &entry->ae_pathname, &p) == 0)
+ return (p);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
+ return (NULL);
+}
+
const wchar_t *
archive_entry_pathname_w(struct archive_entry *entry)
{
@@ -586,7 +627,7 @@ archive_entry_rdevminor(struct archive_entry *entry)
return minor(entry->ae_stat.aest_rdev);
}
-int64_t
+la_int64_t
archive_entry_size(struct archive_entry *entry)
{
return (entry->ae_stat.aest_size);
@@ -634,6 +675,20 @@ archive_entry_symlink(struct archive_entry *entry)
return (NULL);
}
+const char *
+archive_entry_symlink_utf8(struct archive_entry *entry)
+{
+ const char *p;
+ if ((entry->ae_set & AE_SET_SYMLINK) == 0)
+ return (NULL);
+ if (archive_mstring_get_utf8(
+ entry->archive, &entry->ae_symlink, &p) == 0)
+ return (p);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
+ return (NULL);
+}
+
const wchar_t *
archive_entry_symlink_w(struct archive_entry *entry)
{
@@ -660,7 +715,7 @@ _archive_entry_symlink_l(struct archive_entry *entry,
return (archive_mstring_get_mbs_l( &entry->ae_symlink, p, len, sc));
}
-int64_t
+la_int64_t
archive_entry_uid(struct archive_entry *entry)
{
return (entry->ae_stat.aest_uid);
@@ -677,6 +732,17 @@ archive_entry_uname(struct archive_entry *entry)
return (NULL);
}
+const char *
+archive_entry_uname_utf8(struct archive_entry *entry)
+{
+ const char *p;
+ if (archive_mstring_get_utf8(entry->archive, &entry->ae_uname, &p) == 0)
+ return (p);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
+ return (NULL);
+}
+
const wchar_t *
archive_entry_uname_w(struct archive_entry *entry)
{
@@ -695,6 +761,24 @@ _archive_entry_uname_l(struct archive_entry *entry,
return (archive_mstring_get_mbs_l(&entry->ae_uname, p, len, sc));
}
+int
+archive_entry_is_data_encrypted(struct archive_entry *entry)
+{
+ return ((entry->encryption & AE_ENCRYPTION_DATA) == AE_ENCRYPTION_DATA);
+}
+
+int
+archive_entry_is_metadata_encrypted(struct archive_entry *entry)
+{
+ return ((entry->encryption & AE_ENCRYPTION_METADATA) == AE_ENCRYPTION_METADATA);
+}
+
+int
+archive_entry_is_encrypted(struct archive_entry *entry)
+{
+ return (entry->encryption & (AE_ENCRYPTION_DATA|AE_ENCRYPTION_METADATA));
+}
+
/*
* Functions to set archive_entry properties.
*/
@@ -735,7 +819,7 @@ archive_entry_copy_fflags_text_w(struct archive_entry *entry,
}
void
-archive_entry_set_gid(struct archive_entry *entry, int64_t g)
+archive_entry_set_gid(struct archive_entry *entry, la_int64_t g)
{
entry->stat_valid = 0;
entry->ae_stat.aest_gid = g;
@@ -748,6 +832,12 @@ archive_entry_set_gname(struct archive_entry *entry, const char *name)
}
void
+archive_entry_set_gname_utf8(struct archive_entry *entry, const char *name)
+{
+ archive_mstring_copy_utf8(&entry->ae_gname, name);
+}
+
+void
archive_entry_copy_gname(struct archive_entry *entry, const char *name)
{
archive_mstring_copy_mbs(&entry->ae_gname, name);
@@ -778,7 +868,7 @@ _archive_entry_copy_gname_l(struct archive_entry *entry,
}
void
-archive_entry_set_ino(struct archive_entry *entry, int64_t ino)
+archive_entry_set_ino(struct archive_entry *entry, la_int64_t ino)
{
entry->stat_valid = 0;
entry->ae_set |= AE_SET_INO;
@@ -786,7 +876,7 @@ archive_entry_set_ino(struct archive_entry *entry, int64_t ino)
}
void
-archive_entry_set_ino64(struct archive_entry *entry, int64_t ino)
+archive_entry_set_ino64(struct archive_entry *entry, la_int64_t ino)
{
entry->stat_valid = 0;
entry->ae_set |= AE_SET_INO;
@@ -804,6 +894,16 @@ archive_entry_set_hardlink(struct archive_entry *entry, const char *target)
}
void
+archive_entry_set_hardlink_utf8(struct archive_entry *entry, const char *target)
+{
+ archive_mstring_copy_utf8(&entry->ae_hardlink, target);
+ if (target != NULL)
+ entry->ae_set |= AE_SET_HARDLINK;
+ else
+ entry->ae_set &= ~AE_SET_HARDLINK;
+}
+
+void
archive_entry_copy_hardlink(struct archive_entry *entry, const char *target)
{
archive_mstring_copy_mbs(&entry->ae_hardlink, target);
@@ -941,6 +1041,15 @@ archive_entry_set_link(struct archive_entry *entry, const char *target)
archive_mstring_copy_mbs(&entry->ae_hardlink, target);
}
+void
+archive_entry_set_link_utf8(struct archive_entry *entry, const char *target)
+{
+ if (entry->ae_set & AE_SET_SYMLINK)
+ archive_mstring_copy_utf8(&entry->ae_symlink, target);
+ else
+ archive_mstring_copy_utf8(&entry->ae_hardlink, target);
+}
+
/* Set symlink if symlink is already set, else set hardlink. */
void
archive_entry_copy_link(struct archive_entry *entry, const char *target)
@@ -1031,6 +1140,12 @@ archive_entry_set_pathname(struct archive_entry *entry, const char *name)
}
void
+archive_entry_set_pathname_utf8(struct archive_entry *entry, const char *name)
+{
+ archive_mstring_copy_utf8(&entry->ae_pathname, name);
+}
+
+void
archive_entry_copy_pathname(struct archive_entry *entry, const char *name)
{
archive_mstring_copy_mbs(&entry->ae_pathname, name);
@@ -1094,7 +1209,7 @@ archive_entry_set_rdevminor(struct archive_entry *entry, dev_t m)
}
void
-archive_entry_set_size(struct archive_entry *entry, int64_t s)
+archive_entry_set_size(struct archive_entry *entry, la_int64_t s)
{
entry->stat_valid = 0;
entry->ae_stat.aest_size = s;
@@ -1131,6 +1246,16 @@ archive_entry_set_symlink(struct archive_entry *entry, const char *linkname)
}
void
+archive_entry_set_symlink_utf8(struct archive_entry *entry, const char *linkname)
+{
+ archive_mstring_copy_utf8(&entry->ae_symlink, linkname);
+ if (linkname != NULL)
+ entry->ae_set |= AE_SET_SYMLINK;
+ else
+ entry->ae_set &= ~AE_SET_SYMLINK;
+}
+
+void
archive_entry_copy_symlink(struct archive_entry *entry, const char *linkname)
{
archive_mstring_copy_mbs(&entry->ae_symlink, linkname);
@@ -1181,7 +1306,7 @@ _archive_entry_copy_symlink_l(struct archive_entry *entry,
}
void
-archive_entry_set_uid(struct archive_entry *entry, int64_t u)
+archive_entry_set_uid(struct archive_entry *entry, la_int64_t u)
{
entry->stat_valid = 0;
entry->ae_stat.aest_uid = u;
@@ -1194,6 +1319,12 @@ archive_entry_set_uname(struct archive_entry *entry, const char *name)
}
void
+archive_entry_set_uname_utf8(struct archive_entry *entry, const char *name)
+{
+ archive_mstring_copy_utf8(&entry->ae_uname, name);
+}
+
+void
archive_entry_copy_uname(struct archive_entry *entry, const char *name)
{
archive_mstring_copy_mbs(&entry->ae_uname, name);
@@ -1216,6 +1347,26 @@ archive_entry_update_uname_utf8(struct archive_entry *entry, const char *name)
return (0);
}
+void
+archive_entry_set_is_data_encrypted(struct archive_entry *entry, char is_encrypted)
+{
+ if (is_encrypted) {
+ entry->encryption |= AE_ENCRYPTION_DATA;
+ } else {
+ entry->encryption &= ~AE_ENCRYPTION_DATA;
+ }
+}
+
+void
+archive_entry_set_is_metadata_encrypted(struct archive_entry *entry, char is_encrypted)
+{
+ if (is_encrypted) {
+ entry->encryption |= AE_ENCRYPTION_METADATA;
+ } else {
+ entry->encryption &= ~AE_ENCRYPTION_METADATA;
+ }
+}
+
int
_archive_entry_copy_uname_l(struct archive_entry *entry,
const char *name, size_t len, struct archive_string_conv *sc)
@@ -1291,6 +1442,15 @@ archive_entry_acl_add_entry_w(struct archive_entry *entry,
}
/*
+ * Return a bitmask of ACL types in an archive entry ACL list
+ */
+int
+archive_entry_acl_types(struct archive_entry *entry)
+{
+ return (archive_acl_types(&entry->acl));
+}
+
+/*
* Return a count of entries matching "want_type".
*/
int
@@ -1327,34 +1487,121 @@ archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
}
/*
- * Generate a text version of the ACL. The flags parameter controls
+ * Generate a text version of the ACL. The flags parameter controls
* the style of the generated ACL.
*/
+wchar_t *
+archive_entry_acl_to_text_w(struct archive_entry *entry, ssize_t *len,
+ int flags)
+{
+ return (archive_acl_to_text_w(&entry->acl, len, flags,
+ entry->archive));
+}
+
+char *
+archive_entry_acl_to_text(struct archive_entry *entry, ssize_t *len,
+ int flags)
+{
+ return (archive_acl_to_text_l(&entry->acl, len, flags, NULL));
+}
+
+char *
+_archive_entry_acl_to_text_l(struct archive_entry *entry, ssize_t *len,
+ int flags, struct archive_string_conv *sc)
+{
+ return (archive_acl_to_text_l(&entry->acl, len, flags, sc));
+}
+
+/*
+ * ACL text parser.
+ */
+int
+archive_entry_acl_from_text_w(struct archive_entry *entry,
+ const wchar_t *wtext, int type)
+{
+ return (archive_acl_from_text_w(&entry->acl, wtext, type));
+}
+
+int
+archive_entry_acl_from_text(struct archive_entry *entry,
+ const char *text, int type)
+{
+ return (archive_acl_from_text_l(&entry->acl, text, type, NULL));
+}
+
+int
+_archive_entry_acl_from_text_l(struct archive_entry *entry, const char *text,
+ int type, struct archive_string_conv *sc)
+{
+ return (archive_acl_from_text_l(&entry->acl, text, type, sc));
+}
+
+/* Deprecated */
+static int
+archive_entry_acl_text_compat(int *flags)
+{
+ if ((*flags & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) == 0)
+ return (1);
+
+ /* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID */
+ if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0)
+ *flags |= ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID;
+
+ /* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT */
+ if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0)
+ *flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT;
+
+ *flags |= ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA;
+
+ return (0);
+}
+
+/* Deprecated */
const wchar_t *
archive_entry_acl_text_w(struct archive_entry *entry, int flags)
{
- const wchar_t *r;
- r = archive_acl_text_w(entry->archive, &entry->acl, flags);
- if (r == NULL && errno == ENOMEM)
- __archive_errx(1, "No memory");
- return (r);
+ if (entry->acl.acl_text_w != NULL) {
+ free(entry->acl.acl_text_w);
+ entry->acl.acl_text_w = NULL;
+ }
+ if (archive_entry_acl_text_compat(&flags) == 0)
+ entry->acl.acl_text_w = archive_acl_to_text_w(&entry->acl,
+ NULL, flags, entry->archive);
+ return (entry->acl.acl_text_w);
}
+/* Deprecated */
const char *
archive_entry_acl_text(struct archive_entry *entry, int flags)
{
- const char *p;
- if (archive_acl_text_l(&entry->acl, flags, &p, NULL, NULL) != 0
- && errno == ENOMEM)
- __archive_errx(1, "No memory");
- return (p);
+ if (entry->acl.acl_text != NULL) {
+ free(entry->acl.acl_text);
+ entry->acl.acl_text = NULL;
+ }
+ if (archive_entry_acl_text_compat(&flags) == 0)
+ entry->acl.acl_text = archive_acl_to_text_l(&entry->acl, NULL,
+ flags, NULL);
+
+ return (entry->acl.acl_text);
}
+/* Deprecated */
int
_archive_entry_acl_text_l(struct archive_entry *entry, int flags,
const char **acl_text, size_t *len, struct archive_string_conv *sc)
{
- return (archive_acl_text_l(&entry->acl, flags, acl_text, len, sc));
+ if (entry->acl.acl_text != NULL) {
+ free(entry->acl.acl_text);
+ entry->acl.acl_text = NULL;
+ }
+
+ if (archive_entry_acl_text_compat(&flags) == 0)
+ entry->acl.acl_text = archive_acl_to_text_l(&entry->acl,
+ (ssize_t *)len, flags, sc);
+
+ *acl_text = entry->acl.acl_text;
+
+ return (0);
}
/*
@@ -1391,7 +1638,7 @@ _archive_entry_acl_text_l(struct archive_entry *entry, int flags,
* SUCH DAMAGE.
*/
-static struct flag {
+static const struct flag {
const char *name;
const wchar_t *wname;
unsigned long set;
@@ -1402,7 +1649,10 @@ static struct flag {
{ "nosappnd", L"nosappnd", SF_APPEND, 0 },
{ "nosappend", L"nosappend", SF_APPEND, 0 },
#endif
-#ifdef EXT2_APPEND_FL /* 'a' */
+#if defined(FS_APPEND_FL) /* 'a' */
+ { "nosappnd", L"nosappnd", FS_APPEND_FL, 0 },
+ { "nosappend", L"nosappend", FS_APPEND_FL, 0 },
+#elif defined(EXT2_APPEND_FL) /* 'a' */
{ "nosappnd", L"nosappnd", EXT2_APPEND_FL, 0 },
{ "nosappend", L"nosappend", EXT2_APPEND_FL, 0 },
#endif
@@ -1415,7 +1665,11 @@ static struct flag {
{ "noschange", L"noschange", SF_IMMUTABLE, 0 },
{ "nosimmutable", L"nosimmutable", SF_IMMUTABLE, 0 },
#endif
-#ifdef EXT2_IMMUTABLE_FL /* 'i' */
+#if defined(FS_IMMUTABLE_FL) /* 'i' */
+ { "noschg", L"noschg", FS_IMMUTABLE_FL, 0 },
+ { "noschange", L"noschange", FS_IMMUTABLE_FL, 0 },
+ { "nosimmutable", L"nosimmutable", FS_IMMUTABLE_FL, 0 },
+#elif defined(EXT2_IMMUTABLE_FL) /* 'i' */
{ "noschg", L"noschg", EXT2_IMMUTABLE_FL, 0 },
{ "noschange", L"noschange", EXT2_IMMUTABLE_FL, 0 },
{ "nosimmutable", L"nosimmutable", EXT2_IMMUTABLE_FL, 0 },
@@ -1439,7 +1693,9 @@ static struct flag {
#ifdef UF_NODUMP
{ "nodump", L"nodump", 0, UF_NODUMP},
#endif
-#ifdef EXT2_NODUMP_FL /* 'd' */
+#if defined(FS_NODUMP_FL) /* 'd' */
+ { "nodump", L"nodump", 0, FS_NODUMP_FL},
+#elif defined(EXT2_NODUMP_FL) /* 'd' */
{ "nodump", L"nodump", 0, EXT2_NODUMP_FL},
#endif
#ifdef UF_OPAQUE
@@ -1452,65 +1708,127 @@ static struct flag {
#ifdef UF_COMPRESSED
{ "nocompressed",L"nocompressed", UF_COMPRESSED, 0 },
#endif
-#ifdef EXT2_UNRM_FL
+#ifdef UF_HIDDEN
+ { "nohidden", L"nohidden", UF_HIDDEN, 0 },
+#endif
+#if defined(FS_UNRM_FL)
+ { "nouunlink", L"nouunlink", FS_UNRM_FL, 0},
+#elif defined(EXT2_UNRM_FL)
{ "nouunlink", L"nouunlink", EXT2_UNRM_FL, 0},
#endif
-#ifdef EXT2_BTREE_FL
+#if defined(FS_BTREE_FL)
+ { "nobtree", L"nobtree", FS_BTREE_FL, 0 },
+#elif defined(EXT2_BTREE_FL)
{ "nobtree", L"nobtree", EXT2_BTREE_FL, 0 },
#endif
-#ifdef EXT2_ECOMPR_FL
+#if defined(FS_ECOMPR_FL)
+ { "nocomperr", L"nocomperr", FS_ECOMPR_FL, 0 },
+#elif defined(EXT2_ECOMPR_FL)
{ "nocomperr", L"nocomperr", EXT2_ECOMPR_FL, 0 },
#endif
-#ifdef EXT2_COMPR_FL /* 'c' */
+#if defined(FS_COMPR_FL) /* 'c' */
+ { "nocompress", L"nocompress", FS_COMPR_FL, 0 },
+#elif defined(EXT2_COMPR_FL) /* 'c' */
{ "nocompress", L"nocompress", EXT2_COMPR_FL, 0 },
#endif
-#ifdef EXT2_NOATIME_FL /* 'A' */
+#if defined(FS_NOATIME_FL) /* 'A' */
+ { "noatime", L"noatime", 0, FS_NOATIME_FL},
+#elif defined(EXT2_NOATIME_FL) /* 'A' */
{ "noatime", L"noatime", 0, EXT2_NOATIME_FL},
#endif
-#ifdef EXT2_DIRTY_FL
+#if defined(FS_DIRTY_FL)
+ { "nocompdirty",L"nocompdirty", FS_DIRTY_FL, 0},
+#elif defined(EXT2_DIRTY_FL)
{ "nocompdirty",L"nocompdirty", EXT2_DIRTY_FL, 0},
#endif
-#ifdef EXT2_COMPRBLK_FL
-#ifdef EXT2_NOCOMPR_FL
+#if defined(FS_COMPRBLK_FL)
+#if defined(FS_NOCOMPR_FL)
+ { "nocomprblk", L"nocomprblk", FS_COMPRBLK_FL, FS_NOCOMPR_FL},
+#else
+ { "nocomprblk", L"nocomprblk", FS_COMPRBLK_FL, 0},
+#endif
+#elif defined(EXT2_COMPRBLK_FL)
+#if defined(EXT2_NOCOMPR_FL)
{ "nocomprblk", L"nocomprblk", EXT2_COMPRBLK_FL, EXT2_NOCOMPR_FL},
#else
{ "nocomprblk", L"nocomprblk", EXT2_COMPRBLK_FL, 0},
#endif
#endif
-#ifdef EXT2_DIRSYNC_FL
+#if defined(FS_DIRSYNC_FL)
+ { "nodirsync", L"nodirsync", FS_DIRSYNC_FL, 0},
+#elif defined(EXT2_DIRSYNC_FL)
{ "nodirsync", L"nodirsync", EXT2_DIRSYNC_FL, 0},
#endif
-#ifdef EXT2_INDEX_FL
+#if defined(FS_INDEX_FL)
+ { "nohashidx", L"nohashidx", FS_INDEX_FL, 0},
+#elif defined(EXT2_INDEX_FL)
{ "nohashidx", L"nohashidx", EXT2_INDEX_FL, 0},
#endif
-#ifdef EXT2_IMAGIC_FL
+#if defined(FS_IMAGIC_FL)
+ { "noimagic", L"noimagic", FS_IMAGIC_FL, 0},
+#elif defined(EXT2_IMAGIC_FL)
{ "noimagic", L"noimagic", EXT2_IMAGIC_FL, 0},
#endif
-#ifdef EXT3_JOURNAL_DATA_FL
+#if defined(FS_JOURNAL_DATA_FL)
+ { "nojournal", L"nojournal", FS_JOURNAL_DATA_FL, 0},
+#elif defined(EXT3_JOURNAL_DATA_FL)
{ "nojournal", L"nojournal", EXT3_JOURNAL_DATA_FL, 0},
#endif
-#ifdef EXT2_SECRM_FL
+#if defined(FS_SECRM_FL)
+ { "nosecuredeletion",L"nosecuredeletion",FS_SECRM_FL, 0},
+#elif defined(EXT2_SECRM_FL)
{ "nosecuredeletion",L"nosecuredeletion",EXT2_SECRM_FL, 0},
#endif
-#ifdef EXT2_SYNC_FL
+#if defined(FS_SYNC_FL)
+ { "nosync", L"nosync", FS_SYNC_FL, 0},
+#elif defined(EXT2_SYNC_FL)
{ "nosync", L"nosync", EXT2_SYNC_FL, 0},
#endif
-#ifdef EXT2_NOTAIL_FL
+#if defined(FS_NOTAIL_FL)
+ { "notail", L"notail", 0, FS_NOTAIL_FL},
+#elif defined(EXT2_NOTAIL_FL)
{ "notail", L"notail", 0, EXT2_NOTAIL_FL},
#endif
-#ifdef EXT2_TOPDIR_FL
+#if defined(FS_TOPDIR_FL)
+ { "notopdir", L"notopdir", FS_TOPDIR_FL, 0},
+#elif defined(EXT2_TOPDIR_FL)
{ "notopdir", L"notopdir", EXT2_TOPDIR_FL, 0},
#endif
-#ifdef EXT2_RESERVED_FL
+#ifdef FS_ENCRYPT_FL
+ { "noencrypt", L"noencrypt", FS_ENCRYPT_FL, 0},
+#endif
+#ifdef FS_HUGE_FILE_FL
+ { "nohugefile", L"nohugefile", FS_HUGE_FILE_FL, 0},
+#endif
+#ifdef FS_EXTENT_FL
+ { "noextent", L"noextent", FS_EXTENT_FL, 0},
+#endif
+#ifdef FS_EA_INODE_FL
+ { "noeainode", L"noeainode", FS_EA_INODE_FL, 0},
+#endif
+#ifdef FS_EOFBLOCKS_FL
+ { "noeofblocks",L"noeofblocks", FS_EOFBLOCKS_FL, 0},
+#endif
+#ifdef FS_NOCOW_FL
+ { "nocow", L"nocow", FS_NOCOW_FL, 0},
+#endif
+#ifdef FS_INLINE_DATA_FL
+ { "noinlinedata",L"noinlinedata", FS_INLINE_DATA_FL, 0},
+#endif
+#ifdef FS_PROJINHERIT_FL
+ { "noprojinherit",L"noprojinherit", FS_PROJINHERIT_FL, 0},
+#endif
+#if defined(FS_RESERVED_FL)
+ { "noreserved", L"noreserved", FS_RESERVED_FL, 0},
+#elif defined(EXT2_RESERVED_FL)
{ "noreserved", L"noreserved", EXT2_RESERVED_FL, 0},
#endif
-
{ NULL, NULL, 0, 0 }
};
@@ -1525,7 +1843,7 @@ ae_fflagstostr(unsigned long bitset, unsigned long bitclear)
char *string, *dp;
const char *sp;
unsigned long bits;
- struct flag *flag;
+ const struct flag *flag;
size_t length;
bits = bitset | bitclear;
@@ -1577,7 +1895,7 @@ static const char *
ae_strtofflags(const char *s, unsigned long *setp, unsigned long *clrp)
{
const char *start, *end;
- struct flag *flag;
+ const struct flag *flag;
unsigned long set, clear;
const char *failed;
@@ -1588,19 +1906,23 @@ ae_strtofflags(const char *s, unsigned long *setp, unsigned long *clrp)
while (*start == '\t' || *start == ' ' || *start == ',')
start++;
while (*start != '\0') {
+ size_t length;
/* Locate end of token. */
end = start;
while (*end != '\0' && *end != '\t' &&
*end != ' ' && *end != ',')
end++;
+ length = end - start;
for (flag = flags; flag->name != NULL; flag++) {
- if (memcmp(start, flag->name, end - start) == 0) {
+ size_t flag_length = strlen(flag->name);
+ if (length == flag_length
+ && memcmp(start, flag->name, length) == 0) {
/* Matched "noXXXX", so reverse the sense. */
clear |= flag->set;
set |= flag->clear;
break;
- } else if (memcmp(start, flag->name + 2, end - start)
- == 0) {
+ } else if (length == flag_length - 2
+ && memcmp(start, flag->name + 2, length) == 0) {
/* Matched "XXXX", so don't reverse. */
set |= flag->set;
clear |= flag->clear;
@@ -1641,7 +1963,7 @@ static const wchar_t *
ae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp)
{
const wchar_t *start, *end;
- struct flag *flag;
+ const struct flag *flag;
unsigned long set, clear;
const wchar_t *failed;
@@ -1652,19 +1974,23 @@ ae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp)
while (*start == L'\t' || *start == L' ' || *start == L',')
start++;
while (*start != L'\0') {
+ size_t length;
/* Locate end of token. */
end = start;
while (*end != L'\0' && *end != L'\t' &&
*end != L' ' && *end != L',')
end++;
+ length = end - start;
for (flag = flags; flag->wname != NULL; flag++) {
- if (wmemcmp(start, flag->wname, end - start) == 0) {
+ size_t flag_length = wcslen(flag->wname);
+ if (length == flag_length
+ && wmemcmp(start, flag->wname, length) == 0) {
/* Matched "noXXXX", so reverse the sense. */
clear |= flag->set;
set |= flag->clear;
break;
- } else if (wmemcmp(start, flag->wname + 2, end - start)
- == 0) {
+ } else if (length == flag_length - 2
+ && wmemcmp(start, flag->wname + 2, length) == 0) {
/* Matched "XXXX", so don't reverse. */
set |= flag->set;
clear |= flag->clear;
diff --git a/3rdparty/libarchive/libarchive/archive_entry.h b/3rdparty/libarchive/libarchive/archive_entry.h
index a9050652..bcc2962b 100644
--- a/3rdparty/libarchive/libarchive/archive_entry.h
+++ b/3rdparty/libarchive/libarchive/archive_entry.h
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2003-2008 Tim Kientzle
+ * Copyright (c) 2016 Martin Matuska
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,7 +30,7 @@
#define ARCHIVE_ENTRY_H_INCLUDED
/* Note: Compiler will complain if this does not match archive.h! */
-#define ARCHIVE_VERSION_NUMBER 3001002
+#define ARCHIVE_VERSION_NUMBER 3003002
/*
* Note: archive_entry.h is for use outside of libarchive; the
@@ -48,14 +49,41 @@
#endif
/* Get a suitable 64-bit integer type. */
-#if defined(_WIN32) && !defined(__CYGWIN__)
-# define __LA_INT64_T __int64
-#else
+#if !defined(__LA_INT64_T_DEFINED)
+# if ARCHIVE_VERSION_NUMBER < 4000000
+#define __LA_INT64_T la_int64_t
+# endif
+#define __LA_INT64_T_DEFINED
+# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)
+typedef __int64 la_int64_t;
+# else
#include <unistd.h>
-# if defined(_SCO_DS)
-# define __LA_INT64_T long long
+# if defined(_SCO_DS) || defined(__osf__)
+typedef long long la_int64_t;
+# else
+typedef int64_t la_int64_t;
+# endif
+# endif
+#endif
+
+/* The la_ssize_t should match the type used in 'struct stat' */
+#if !defined(__LA_SSIZE_T_DEFINED)
+/* Older code relied on the __LA_SSIZE_T macro; after 4.0 we'll switch to the typedef exclusively. */
+# if ARCHIVE_VERSION_NUMBER < 4000000
+#define __LA_SSIZE_T la_ssize_t
+# endif
+#define __LA_SSIZE_T_DEFINED
+# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)
+# if defined(_SSIZE_T_DEFINED) || defined(_SSIZE_T_)
+typedef ssize_t la_ssize_t;
+# elif defined(_WIN64)
+typedef __int64 la_ssize_t;
+# else
+typedef long la_ssize_t;
+# endif
# else
-# define __LA_INT64_T int64_t
+# include <unistd.h> /* ssize_t */
+typedef ssize_t la_ssize_t;
# endif
#endif
@@ -63,12 +91,17 @@
#if ARCHIVE_VERSION_NUMBER >= 3999000
/* Switch to plain 'int' for libarchive 4.0. It's less broken than 'mode_t' */
# define __LA_MODE_T int
-#elif defined(_WIN32) && !defined(__CYGWIN__) && !defined(__BORLANDC__)
+#elif defined(_WIN32) && !defined(__CYGWIN__) && !defined(__BORLANDC__) && !defined(__WATCOMC__)
# define __LA_MODE_T unsigned short
#else
# define __LA_MODE_T mode_t
#endif
+/* Large file support for Android */
+#ifdef __ANDROID__
+#include "android_lf.h"
+#endif
+
/*
* On Windows, define LIBARCHIVE_STATIC if you're building or using a
* .lib. The default here assumes you're building a DLL. Only
@@ -93,6 +126,12 @@
# define __LA_DECL
#endif
+#if defined(__GNUC__) && __GNUC__ >= 3 && __GNUC_MINOR__ >= 1
+# define __LA_DEPRECATED __attribute__((deprecated))
+#else
+# define __LA_DEPRECATED
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -206,13 +245,15 @@ __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_INT64_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 char *archive_entry_gname_utf8(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 char *archive_entry_hardlink_utf8(struct archive_entry *);
__LA_DECL const wchar_t *archive_entry_hardlink_w(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 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 *);
@@ -220,6 +261,7 @@ __LA_DECL long archive_entry_mtime_nsec(struct archive_entry *);
__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 char *archive_entry_pathname_utf8(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 *);
@@ -227,14 +269,19 @@ __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 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 char *archive_entry_symlink_utf8(struct archive_entry *);
__LA_DECL const wchar_t *archive_entry_symlink_w(struct archive_entry *);
-__LA_DECL __LA_INT64_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 char *archive_entry_uname_utf8(struct archive_entry *);
__LA_DECL const wchar_t *archive_entry_uname_w(struct archive_entry *);
+__LA_DECL int archive_entry_is_data_encrypted(struct archive_entry *);
+__LA_DECL int archive_entry_is_metadata_encrypted(struct archive_entry *);
+__LA_DECL int archive_entry_is_encrypted(struct archive_entry *);
/*
* Set fields in an archive_entry.
@@ -266,18 +313,21 @@ __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_INT64_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_set_gname_utf8(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 *);
__LA_DECL int archive_entry_update_gname_utf8(struct archive_entry *, const char *);
__LA_DECL void archive_entry_set_hardlink(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_set_hardlink_utf8(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 *);
-__LA_DECL void archive_entry_set_ino(struct archive_entry *, __LA_INT64_T);
-__LA_DECL void archive_entry_set_ino64(struct archive_entry *, __LA_INT64_T);
+__LA_DECL void archive_entry_set_ino(struct archive_entry *, la_int64_t);
+__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_set_link_utf8(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_link(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_link_w(struct archive_entry *, const wchar_t *);
__LA_DECL int archive_entry_update_link_utf8(struct archive_entry *, const char *);
@@ -286,6 +336,7 @@ __LA_DECL void archive_entry_set_mtime(struct archive_entry *, time_t, long);
__LA_DECL void archive_entry_unset_mtime(struct archive_entry *);
__LA_DECL void archive_entry_set_nlink(struct archive_entry *, unsigned int);
__LA_DECL void archive_entry_set_pathname(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_set_pathname_utf8(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_pathname(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_pathname_w(struct archive_entry *, const wchar_t *);
__LA_DECL int archive_entry_update_pathname_utf8(struct archive_entry *, const char *);
@@ -293,19 +344,23 @@ __LA_DECL void archive_entry_set_perm(struct archive_entry *, __LA_MODE_T);
__LA_DECL void archive_entry_set_rdev(struct archive_entry *, dev_t);
__LA_DECL void archive_entry_set_rdevmajor(struct archive_entry *, dev_t);
__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_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_set_symlink_utf8(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_INT64_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_set_uname_utf8(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 *);
__LA_DECL int archive_entry_update_uname_utf8(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_set_is_data_encrypted(struct archive_entry *, char is_encrypted);
+__LA_DECL void archive_entry_set_is_metadata_encrypted(struct archive_entry *, char is_encrypted);
/*
* Routines to bulk copy fields to/from a platform-native "struct
* stat." Libarchive used to just store a struct stat inside of each
@@ -393,6 +448,7 @@ __LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const voi
/*
* Inheritance values (NFS4 ACLs only); included in permset.
*/
+#define ARCHIVE_ENTRY_ACL_ENTRY_INHERITED 0x01000000
#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
@@ -406,15 +462,16 @@ __LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const voi
| 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)
+ | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS \
+ | ARCHIVE_ENTRY_ACL_ENTRY_INHERITED)
/* 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_ACCESS 0x00000100 /* POSIX.1e only */
+#define ARCHIVE_ENTRY_ACL_TYPE_DEFAULT 0x00000200 /* POSIX.1e only */
+#define ARCHIVE_ENTRY_ACL_TYPE_ALLOW 0x00000400 /* NFS4 only */
+#define ARCHIVE_ENTRY_ACL_TYPE_DENY 0x00000800 /* NFS4 only */
+#define ARCHIVE_ENTRY_ACL_TYPE_AUDIT 0x00001000 /* NFS4 only */
+#define ARCHIVE_ENTRY_ACL_TYPE_ALARM 0x00002000 /* 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 \
@@ -465,21 +522,51 @@ __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:
*
+ * Flags only for archive entries with POSIX.1e ACL:
* 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. ('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, as used in old Solaris ACLs.
+ * default ACL entry.
+ * ARCHIVE_ENTRY_ACL_STYLE_SOLARIS - Output only one colon after "other" and
+ * "mask" entries.
+ *
+ * Flags only for archive entries with NFSv4 ACL:
+ * ARCHIVE_ENTRY_ACL_STYLE_COMPACT - Do not output the minus character for
+ * unset permissions and flags in NFSv4 ACL permission and flag fields
+ *
+ * Flags for for archive entries with POSIX.1e ACL or NFSv4 ACL:
+ * ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID - Include extra numeric ID field in
+ * each ACL entry.
+ * ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA - Separate entries with comma
+ * instead of newline.
*/
-#define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024
-#define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048
+#define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 0x00000001
+#define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 0x00000002
+#define ARCHIVE_ENTRY_ACL_STYLE_SOLARIS 0x00000004
+#define ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA 0x00000008
+#define ARCHIVE_ENTRY_ACL_STYLE_COMPACT 0x00000010
+
+__LA_DECL wchar_t *archive_entry_acl_to_text_w(struct archive_entry *,
+ la_ssize_t * /* len */, int /* flags */);
+__LA_DECL char *archive_entry_acl_to_text(struct archive_entry *,
+ la_ssize_t * /* len */, int /* flags */);
+__LA_DECL int archive_entry_acl_from_text_w(struct archive_entry *,
+ const wchar_t * /* wtext */, int /* type */);
+__LA_DECL int archive_entry_acl_from_text(struct archive_entry *,
+ const char * /* text */, int /* type */);
+
+/* Deprecated constants */
+#define OLD_ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024
+#define OLD_ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048
+
+/* Deprecated functions */
__LA_DECL const wchar_t *archive_entry_acl_text_w(struct archive_entry *,
- int /* flags */);
+ int /* flags */) __LA_DEPRECATED;
__LA_DECL const char *archive_entry_acl_text(struct archive_entry *,
- int /* flags */);
+ int /* flags */) __LA_DEPRECATED;
+
+/* Return bitmask of ACL types in an archive entry */
+__LA_DECL int archive_entry_acl_types(struct archive_entry *);
/* Return a count of entries matching 'want_type' */
__LA_DECL int archive_entry_acl_count(struct archive_entry *, int /* want_type */);
@@ -514,7 +601,7 @@ __LA_DECL int archive_entry_xattr_next(struct archive_entry *,
__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 */);
+ la_int64_t /* offset */, la_int64_t /* length */);
/*
* To retrieve the xattr list, first "reset", then repeatedly ask for the
@@ -524,7 +611,7 @@ __LA_DECL void archive_entry_sparse_add_entry(struct archive_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 */);
+ la_int64_t * /* offset */, la_int64_t * /* length */);
/*
* Utility to match up hardlinks.
diff --git a/3rdparty/libarchive/libarchive/archive_entry_copy_stat.c b/3rdparty/libarchive/libarchive/archive_entry_copy_stat.c
index 37d4d6ed..ac83868e 100644
--- a/3rdparty/libarchive/libarchive/archive_entry_copy_stat.c
+++ b/3rdparty/libarchive/libarchive/archive_entry_copy_stat.c
@@ -44,6 +44,10 @@ archive_entry_copy_stat(struct archive_entry *entry, const struct stat *st)
archive_entry_set_atime(entry, st->st_atime, st->st_atim.tv_nsec);
archive_entry_set_ctime(entry, st->st_ctime, st->st_ctim.tv_nsec);
archive_entry_set_mtime(entry, st->st_mtime, st->st_mtim.tv_nsec);
+#elif HAVE_STRUCT_STAT_ST_MTIME_NSEC
+ archive_entry_set_atime(entry, st->st_atime, st->st_atime_nsec);
+ archive_entry_set_ctime(entry, st->st_ctime, st->st_ctime_nsec);
+ archive_entry_set_mtime(entry, st->st_mtime, st->st_mtime_nsec);
#elif HAVE_STRUCT_STAT_ST_MTIME_N
archive_entry_set_atime(entry, st->st_atime, st->st_atime_n);
archive_entry_set_ctime(entry, st->st_ctime, st->st_ctime_n);
diff --git a/3rdparty/libarchive/libarchive/archive_entry_locale.h b/3rdparty/libarchive/libarchive/archive_entry_locale.h
index 02e024ae..44550c51 100644
--- a/3rdparty/libarchive/libarchive/archive_entry_locale.h
+++ b/3rdparty/libarchive/libarchive/archive_entry_locale.h
@@ -63,9 +63,13 @@ int _archive_entry_uname_l(struct archive_entry *,
const char **, size_t *, struct archive_string_conv *);
#define archive_entry_acl_text_l _archive_entry_acl_text_l
int _archive_entry_acl_text_l(struct archive_entry *, int,
- const char **, size_t *, struct archive_string_conv *);
-
-
+const char **, size_t *, struct archive_string_conv *) __LA_DEPRECATED;
+#define archive_entry_acl_to_text_l _archive_entry_acl_to_text_l
+char *_archive_entry_acl_to_text_l(struct archive_entry *, ssize_t *, int,
+ struct archive_string_conv *);
+#define archive_entry_acl_from_text_l _archive_entry_acl_from_text_l
+int _archive_entry_acl_from_text_l(struct archive_entry *, const char* text,
+ int type, struct archive_string_conv *);
#define archive_entry_copy_gname_l _archive_entry_copy_gname_l
int _archive_entry_copy_gname_l(struct archive_entry *,
const char *, size_t, struct archive_string_conv *);
diff --git a/3rdparty/libarchive/libarchive/archive_entry_private.h b/3rdparty/libarchive/libarchive/archive_entry_private.h
index e3547c3e..c69233e6 100644
--- a/3rdparty/libarchive/libarchive/archive_entry_private.h
+++ b/3rdparty/libarchive/libarchive/archive_entry_private.h
@@ -154,6 +154,11 @@ struct archive_entry {
/* Not used within libarchive; useful for some clients. */
struct archive_mstring ae_sourcepath; /* Path this entry is sourced from. */
+#define AE_ENCRYPTION_NONE 0
+#define AE_ENCRYPTION_DATA 1
+#define AE_ENCRYPTION_METADATA 2
+ char encryption;
+
void *mac_metadata;
size_t mac_metadata_size;
diff --git a/3rdparty/libarchive/libarchive/archive_entry_sparse.c b/3rdparty/libarchive/libarchive/archive_entry_sparse.c
index 10c54474..74917b37 100644
--- a/3rdparty/libarchive/libarchive/archive_entry_sparse.c
+++ b/3rdparty/libarchive/libarchive/archive_entry_sparse.c
@@ -51,14 +51,14 @@ archive_entry_sparse_clear(struct archive_entry *entry)
void
archive_entry_sparse_add_entry(struct archive_entry *entry,
- int64_t offset, int64_t length)
+ la_int64_t offset, la_int64_t length)
{
struct ae_sparse *sp;
if (offset < 0 || length < 0)
/* Invalid value */
return;
- if (offset + length < 0 ||
+ if (offset > INT64_MAX - length ||
offset + length > archive_entry_size(entry))
/* A value of "length" parameter is too large. */
return;
@@ -135,7 +135,7 @@ archive_entry_sparse_reset(struct archive_entry * entry)
int
archive_entry_sparse_next(struct archive_entry * entry,
- int64_t *offset, int64_t *length)
+ la_int64_t *offset, la_int64_t *length)
{
if (entry->sparse_p) {
*offset = entry->sparse_p->offset;
diff --git a/3rdparty/libarchive/libarchive/archive_entry_strmode.c b/3rdparty/libarchive/libarchive/archive_entry_strmode.c
index 16cb3f7b..af2517a3 100644
--- a/3rdparty/libarchive/libarchive/archive_entry_strmode.c
+++ b/3rdparty/libarchive/libarchive/archive_entry_strmode.c
@@ -80,7 +80,7 @@ archive_entry_strmode(struct archive_entry *entry)
if (mode & 0001) bp[9] = 't';
else bp[9] = 'T';
}
- if (archive_entry_acl_count(entry, ARCHIVE_ENTRY_ACL_TYPE_ACCESS))
+ if (archive_entry_acl_types(entry) != 0)
bp[10] = '+';
return (bp);
diff --git a/3rdparty/libarchive/libarchive/archive_entry_xattr.c b/3rdparty/libarchive/libarchive/archive_entry_xattr.c
index a3efe7ca..5fe726b9 100644
--- a/3rdparty/libarchive/libarchive/archive_entry_xattr.c
+++ b/3rdparty/libarchive/libarchive/archive_entry_xattr.c
@@ -91,14 +91,12 @@ archive_entry_xattr_add_entry(struct archive_entry *entry,
{
struct ae_xattr *xp;
- for (xp = entry->xattr_head; xp != NULL; xp = xp->next)
- ;
-
if ((xp = (struct ae_xattr *)malloc(sizeof(struct ae_xattr))) == NULL)
- /* XXX Error XXX */
- return;
+ __archive_errx(1, "Out of memory");
+
+ if ((xp->name = strdup(name)) == NULL)
+ __archive_errx(1, "Out of memory");
- xp->name = strdup(name);
if ((xp->value = malloc(size)) != NULL) {
memcpy(xp->value, value, size);
xp->size = size;
diff --git a/3rdparty/libarchive/libarchive/archive_getdate.c b/3rdparty/libarchive/libarchive/archive_getdate.c
index f8b5a28d..030c083c 100644
--- a/3rdparty/libarchive/libarchive/archive_getdate.c
+++ b/3rdparty/libarchive/libarchive/archive_getdate.c
@@ -38,8 +38,8 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <time.h>
-/* This file defines a single public function. */
-time_t __archive_get_date(time_t now, char *);
+#define __LIBARCHIVE_BUILD 1
+#include "archive_getdate.h"
/* Basic time units. */
#define EPOCH 1970
@@ -369,8 +369,8 @@ relunitphrase(struct gdstate *gds)
&& gds->tokenp[1].token == tSEC_UNIT) {
/* "1 day" */
gds->HaveRel++;
- gds->RelSeconds += gds->tokenp[1].value * gds->tokenp[2].value;
- gds->tokenp += 3;
+ gds->RelSeconds += gds->tokenp[0].value * gds->tokenp[1].value;
+ gds->tokenp += 2;
return 1;
}
if (gds->tokenp[0].token == '-'
@@ -403,7 +403,7 @@ relunitphrase(struct gdstate *gds)
/* "now", "tomorrow" */
gds->HaveRel++;
gds->RelSeconds += gds->tokenp[0].value;
- ++gds->tokenp;
+ gds->tokenp += 1;
return 1;
}
if (gds->tokenp[0].token == tMONTH_UNIT) {
@@ -691,7 +691,7 @@ Convert(time_t Month, time_t Day, time_t Year,
time_t Hours, time_t Minutes, time_t Seconds,
time_t Timezone, enum DSTMODE DSTmode)
{
- static int DaysInMonth[12] = {
+ signed char DaysInMonth[12] = {
31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
time_t Julian;
@@ -782,7 +782,7 @@ RelativeMonth(time_t Start, time_t Timezone, time_t RelMonth)
* Tokenizer.
*/
static int
-nexttoken(char **in, time_t *value)
+nexttoken(const char **in, time_t *value)
{
char c;
char buff[64];
@@ -809,7 +809,7 @@ nexttoken(char **in, time_t *value)
/* Try the next token in the word table first. */
/* This allows us to match "2nd", for example. */
{
- char *src = *in;
+ const char *src = *in;
const struct LEXICON *tp;
unsigned i = 0;
@@ -894,7 +894,7 @@ difftm (struct tm *a, struct tm *b)
* TODO: tokens[] array should be dynamically sized.
*/
time_t
-__archive_get_date(time_t now, char *p)
+__archive_get_date(time_t now, const char *p)
{
struct token tokens[256];
struct gdstate _gds;
@@ -1022,10 +1022,11 @@ int
main(int argc, char **argv)
{
time_t d;
+ time_t now = time(NULL);
while (*++argv != NULL) {
(void)printf("Input: %s\n", *argv);
- d = get_date(*argv);
+ d = get_date(now, *argv);
if (d == -1)
(void)printf("Bad format - couldn't convert.\n");
else
diff --git a/3rdparty/libarchive/libarchive/archive_getdate.h b/3rdparty/libarchive/libarchive/archive_getdate.h
new file mode 100644
index 00000000..666ff5ff
--- /dev/null
+++ b/3rdparty/libarchive/libarchive/archive_getdate.h
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2003-2015 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_GETDATE_H_INCLUDED
+#define ARCHIVE_GETDATE_H_INCLUDED
+
+#include <time.h>
+
+time_t __archive_get_date(time_t now, const char *);
+
+#endif
diff --git a/3rdparty/libarchive/libarchive/archive_match.c b/3rdparty/libarchive/libarchive/archive_match.c
index 6b6be9cb..be72066e 100644
--- a/3rdparty/libarchive/libarchive/archive_match.c
+++ b/3rdparty/libarchive/libarchive/archive_match.c
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_private.h"
#include "archive_entry.h"
+#include "archive_getdate.h"
#include "archive_pathmatch.h"
#include "archive_rb.h"
#include "archive_string.h"
@@ -184,7 +185,6 @@ static int time_excluded(struct archive_match *,
struct archive_entry *);
static int validate_time_flag(struct archive *, int, const char *);
-time_t __archive_get_date(time_t now, const char *);
#define get_date __archive_get_date
static const struct archive_rb_tree_ops rb_ops_mbs = {
@@ -471,7 +471,7 @@ archive_match_path_excluded(struct archive *_a,
}
/*
- * Utilty functions to get statistic information for inclusion patterns.
+ * Utility functions to get statistic information for inclusion patterns.
*/
int
archive_match_path_unmatched_inclusions(struct archive *_a)
@@ -580,6 +580,7 @@ add_pattern_from_file(struct archive_match *a, struct match_list *mlist,
return (ARCHIVE_FATAL);
}
r = archive_read_support_format_raw(ar);
+ r = archive_read_support_format_empty(ar);
if (r != ARCHIVE_OK) {
archive_copy_error(&(a->archive), ar);
archive_read_free(ar);
@@ -596,9 +597,13 @@ add_pattern_from_file(struct archive_match *a, struct match_list *mlist,
}
r = archive_read_next_header(ar, &ae);
if (r != ARCHIVE_OK) {
- archive_copy_error(&(a->archive), ar);
archive_read_free(ar);
- return (r);
+ if (r == ARCHIVE_EOF) {
+ return (ARCHIVE_OK);
+ } else {
+ archive_copy_error(&(a->archive), ar);
+ return (r);
+ }
}
archive_string_init(&as);
@@ -650,7 +655,7 @@ add_pattern_from_file(struct archive_match *a, struct match_list *mlist,
}
}
- /* If something error happend, report it immediately. */
+ /* If an error occurred, report it immediately. */
if (r < ARCHIVE_OK) {
archive_copy_error(&(a->archive), ar);
archive_read_free(ar);
@@ -1152,7 +1157,7 @@ set_timefilter_pathname_mbs(struct archive_match *a, int timetype,
{
/* NOTE: stat() on Windows cannot handle nano seconds. */
HANDLE h;
- WIN32_FIND_DATA d;
+ WIN32_FIND_DATAA d;
if (path == NULL || *path == '\0') {
archive_set_error(&(a->archive), EINVAL, "pathname is empty");
@@ -1265,7 +1270,7 @@ set_timefilter_pathname_wcs(struct archive_match *a, int timetype,
#endif /* _WIN32 && !__CYGWIN__ */
/*
- * Call back funtions for archive_rb.
+ * Call back functions for archive_rb.
*/
static int
cmp_node_mbs(const struct archive_rb_node *n1,
@@ -1400,7 +1405,7 @@ add_entry(struct archive_match *a, int flag,
&(a->exclusion_tree), pathname);
/*
- * We always overwrite comparison condision.
+ * We always overwrite comparison condition.
* If you do not want to overwrite it, you should not
* call archive_match_exclude_entry(). We cannot know
* what behavior you really expect since overwriting
@@ -1476,7 +1481,7 @@ time_excluded(struct archive_match *a, struct archive_entry *entry)
if (nsec == a->older_ctime_nsec &&
(a->older_ctime_filter & ARCHIVE_MATCH_EQUAL)
== 0)
- return (1); /* Eeual, skip it. */
+ return (1); /* Equal, skip it. */
}
}
if (a->newer_mtime_filter) {
@@ -1508,7 +1513,7 @@ time_excluded(struct archive_match *a, struct archive_entry *entry)
}
}
- /* If there is no excluson list, include the file. */
+ /* If there is no exclusion list, include the file. */
if (a->exclusion_entry_list.count == 0)
return (0);
@@ -1695,7 +1700,7 @@ add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id)
break;
}
- /* Add oowner id. */
+ /* Add owner id. */
if (i == ids->count)
ids->ids[ids->count++] = id;
else if (ids->ids[i] != id) {
diff --git a/3rdparty/libarchive/libarchive/archive_options.c b/3rdparty/libarchive/libarchive/archive_options.c
index 8af62393..6496025a 100644
--- a/3rdparty/libarchive/libarchive/archive_options.c
+++ b/3rdparty/libarchive/libarchive/archive_options.c
@@ -26,6 +26,10 @@
#include "archive_platform.h"
__FBSDID("$FreeBSD$");
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
#include "archive_options_private.h"
static const char *
@@ -42,9 +46,9 @@ _archive_set_option(struct archive *a,
archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
- mp = m != NULL && m[0] == '\0' ? NULL : m;
- op = o != NULL && o[0] == '\0' ? NULL : o;
- vp = v != NULL && v[0] == '\0' ? NULL : v;
+ mp = (m != NULL && m[0] != '\0') ? m : NULL;
+ op = (o != NULL && o[0] != '\0') ? o : NULL;
+ vp = (v != NULL && v[0] != '\0') ? v : NULL;
if (op == NULL && vp == NULL)
return (ARCHIVE_OK);
@@ -105,8 +109,11 @@ _archive_set_options(struct archive *a, const char *options,
if (options == NULL || options[0] == '\0')
return ARCHIVE_OK;
- data = (char *)malloc(strlen(options) + 1);
- strcpy(data, options);
+ if ((data = strdup(options)) == NULL) {
+ archive_set_error(a,
+ ENOMEM, "Out of memory adding file to list");
+ return (ARCHIVE_FATAL);
+ }
s = (const char *)data;
do {
diff --git a/3rdparty/libarchive/libarchive/archive_pack_dev.h b/3rdparty/libarchive/libarchive/archive_pack_dev.h
new file mode 100644
index 00000000..749fd3d2
--- /dev/null
+++ b/3rdparty/libarchive/libarchive/archive_pack_dev.h
@@ -0,0 +1,49 @@
+/* $NetBSD: pack_dev.h,v 1.8 2013/06/14 16:28:20 tsutsui Exp $ */
+
+/*-
+ * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/* Originally from NetBSD's mknod(8) source. */
+
+#ifndef _PACK_DEV_H
+#define _PACK_DEV_H
+
+typedef dev_t pack_t(int, unsigned long [], const char **);
+
+pack_t *pack_find(const char *);
+pack_t pack_native;
+
+#define major_netbsd(x) ((int32_t)((((x) & 0x000fff00) >> 8)))
+#define minor_netbsd(x) ((int32_t)((((x) & 0xfff00000) >> 12) | \
+ (((x) & 0x000000ff) >> 0)))
+#define makedev_netbsd(x,y) ((dev_t)((((x) << 8) & 0x000fff00) | \
+ (((y) << 12) & 0xfff00000) | \
+ (((y) << 0) & 0x000000ff)))
+
+#endif /* _PACK_DEV_H */
diff --git a/3rdparty/libarchive/libarchive/archive_pathmatch.c b/3rdparty/libarchive/libarchive/archive_pathmatch.c
index 505252a1..619e2b62 100644
--- a/3rdparty/libarchive/libarchive/archive_pathmatch.c
+++ b/3rdparty/libarchive/libarchive/archive_pathmatch.c
@@ -394,8 +394,8 @@ __archive_pathmatch(const char *p, const char *s, int flags)
if (*p == '/' && *s != '/')
return (0);
- /* Certain patterns and file names anchor implicitly. */
- if (*p == '*' || *p == '/' || *p == '/') {
+ /* Certain patterns anchor implicitly. */
+ if (*p == '*' || *p == '/') {
while (*p == '/')
++p;
while (*s == '/')
@@ -434,8 +434,8 @@ __archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags)
if (*p == L'/' && *s != L'/')
return (0);
- /* Certain patterns and file names anchor implicitly. */
- if (*p == L'*' || *p == L'/' || *p == L'/') {
+ /* Certain patterns anchor implicitly. */
+ if (*p == L'*' || *p == L'/') {
while (*p == L'/')
++p;
while (*s == L'/')
diff --git a/3rdparty/libarchive/libarchive/archive_platform.h b/3rdparty/libarchive/libarchive/archive_platform.h
index ce2f482b..34be8eda 100644
--- a/3rdparty/libarchive/libarchive/archive_platform.h
+++ b/3rdparty/libarchive/libarchive/archive_platform.h
@@ -66,15 +66,18 @@
* headers as required.
*/
-/* Get a real definition for __FBSDID if we can */
+/* Get a real definition for __FBSDID or __RCSID if we can */
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
-/* If not, define it so as to avoid dangling semicolons. */
+/* If not, define them so as to avoid dangling semicolons. */
#ifndef __FBSDID
#define __FBSDID(a) struct _undefined_hack
#endif
+#ifndef __RCSID
+#define __RCSID(a) struct _undefined_hack
+#endif
/* Try to get standard C99-style integer type definitions. */
#if HAVE_INTTYPES_H
@@ -114,6 +117,12 @@
#if !HAVE_DECL_UINT32_MAX
#define UINT32_MAX (~(uint32_t)0)
#endif
+#if !HAVE_DECL_INT32_MAX
+#define INT32_MAX ((int32_t)(UINT32_MAX >> 1))
+#endif
+#if !HAVE_DECL_INT32_MIN
+#define INT32_MIN ((int32_t)(~INT32_MAX))
+#endif
#if !HAVE_DECL_UINT64_MAX
#define UINT64_MAX (~(uint64_t)0)
#endif
@@ -123,14 +132,14 @@
#if !HAVE_DECL_INT64_MIN
#define INT64_MIN ((int64_t)(~INT64_MAX))
#endif
-
-/*
- * If this platform has <sys/acl.h>, acl_create(), acl_init(),
- * acl_set_file(), and ACL_USER, we assume it has the rest of the
- * POSIX.1e draft functions used in archive_read_extract.c.
- */
-#if HAVE_SYS_ACL_H && HAVE_ACL_CREATE_ENTRY && HAVE_ACL_INIT && HAVE_ACL_SET_FILE && HAVE_ACL_USER
-#define HAVE_POSIX_ACL 1
+#if !HAVE_DECL_UINTMAX_MAX
+#define UINTMAX_MAX (~(uintmax_t)0)
+#endif
+#if !HAVE_DECL_INTMAX_MAX
+#define INTMAX_MAX ((intmax_t)(UINTMAX_MAX >> 1))
+#endif
+#if !HAVE_DECL_INTMAX_MIN
+#define INTMAX_MIN ((intmax_t)(~INTMAX_MAX))
#endif
/*
@@ -141,6 +150,15 @@
#define CAN_RESTORE_METADATA_FD
#endif
+/*
+ * glibc 2.24 deprecates readdir_r
+ */
+#if defined(HAVE_READDIR_R) && (!defined(__GLIBC__) || !defined(__GLIBC_MINOR__) || __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 24))
+#define USE_READDIR_R 1
+#else
+#undef USE_READDIR_R
+#endif
+
/* Set up defaults for internal error codes. */
#ifndef ARCHIVE_ERRNO_FILE_FORMAT
#if HAVE_EFTYPE
diff --git a/3rdparty/libarchive/libarchive/archive_platform_acl.h b/3rdparty/libarchive/libarchive/archive_platform_acl.h
new file mode 100644
index 00000000..3498f78b
--- /dev/null
+++ b/3rdparty/libarchive/libarchive/archive_platform_acl.h
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2017 Martin Matuska
+ * 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$
+ */
+
+/* !!ONLY FOR USE INTERNALLY TO LIBARCHIVE!! */
+
+#ifndef ARCHIVE_PLATFORM_ACL_H_INCLUDED
+#define ARCHIVE_PLATFORM_ACL_H_INCLUDED
+
+/*
+ * Determine what ACL types are supported
+ */
+#if ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_SUNOS || ARCHIVE_ACL_LIBACL
+#define ARCHIVE_ACL_POSIX1E 1
+#endif
+
+#if ARCHIVE_ACL_FREEBSD_NFS4 || ARCHIVE_ACL_SUNOS_NFS4 || \
+ ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL
+#define ARCHIVE_ACL_NFS4 1
+#endif
+
+#if ARCHIVE_ACL_POSIX1E || ARCHIVE_ACL_NFS4
+#define ARCHIVE_ACL_SUPPORT 1
+#endif
+
+#endif /* ARCHIVE_PLATFORM_ACL_H_INCLUDED */
diff --git a/3rdparty/libarchive/libarchive/archive_ppmd7.c b/3rdparty/libarchive/libarchive/archive_ppmd7.c
index fe0b0318..1aed922d 100644
--- a/3rdparty/libarchive/libarchive/archive_ppmd7.c
+++ b/3rdparty/libarchive/libarchive/archive_ppmd7.c
@@ -126,6 +126,11 @@ static Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc)
{
if (p->Base == 0 || p->Size != size)
{
+ /* RestartModel() below assumes that p->Size >= UNIT_SIZE
+ (see the calculation of m->MinContext). */
+ if (size < UNIT_SIZE) {
+ return False;
+ }
Ppmd7_Free(p, alloc);
p->AlignOffset =
#ifdef PPMD_32BIT
diff --git a/3rdparty/libarchive/libarchive/archive_ppmd7_private.h b/3rdparty/libarchive/libarchive/archive_ppmd7_private.h
index 3a6b9eb4..06c99e82 100644
--- a/3rdparty/libarchive/libarchive/archive_ppmd7_private.h
+++ b/3rdparty/libarchive/libarchive/archive_ppmd7_private.h
@@ -19,7 +19,7 @@ If you need the compatibility with original PPMd var.H, you can use external Ran
#define PPMD7_MAX_ORDER 64
#define PPMD7_MIN_MEM_SIZE (1 << 11)
-#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3)
+#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFFu - 12 * 3)
struct CPpmd7_Context_;
diff --git a/3rdparty/libarchive/libarchive/archive_private.h b/3rdparty/libarchive/libarchive/archive_private.h
index 30d472fc..4b4be979 100644
--- a/3rdparty/libarchive/libarchive/archive_private.h
+++ b/3rdparty/libarchive/libarchive/archive_private.h
@@ -119,6 +119,23 @@ struct archive {
unsigned current_codepage; /* Current ACP(ANSI CodePage). */
unsigned current_oemcp; /* Current OEMCP(OEM CodePage). */
struct archive_string_conv *sconv;
+
+ /*
+ * Used by archive_read_data() to track blocks and copy
+ * data to client buffers, filling gaps with zero bytes.
+ */
+ const char *read_data_block;
+ int64_t read_data_offset;
+ int64_t read_data_output_offset;
+ size_t read_data_remaining;
+
+ /*
+ * Used by formats/filters to determine the amount of data
+ * requested from a call to archive_read_data(). This is only
+ * useful when the format/filter has seek support.
+ */
+ char read_data_is_posix_read;
+ size_t read_data_requested;
};
/* Check magic value and state; return(ARCHIVE_FATAL) if it isn't valid. */
@@ -139,6 +156,8 @@ int __archive_mktemp(const char *tmpdir);
int __archive_clean(struct archive *);
+void __archive_reset_read_data(struct archive *);
+
#define err_combine(a,b) ((a) < (b) ? (a) : (b))
#if defined(__BORLANDC__) || (defined(_MSC_VER) && _MSC_VER <= 1300)
diff --git a/3rdparty/libarchive/libarchive/archive_random.c b/3rdparty/libarchive/libarchive/archive_random.c
new file mode 100644
index 00000000..65ea6915
--- /dev/null
+++ b/3rdparty/libarchive/libarchive/archive_random.c
@@ -0,0 +1,272 @@
+/*-
+ * Copyright (c) 2014 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"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#if !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__))
+
+#ifdef HAVE_FCNTL
+#include <fcntl.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
+
+static void arc4random_buf(void *, size_t);
+
+#endif /* HAVE_ARC4RANDOM_BUF */
+
+#include "archive.h"
+#include "archive_random_private.h"
+
+#if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__)
+#include <wincrypt.h>
+#endif
+
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+
+/*
+ * Random number generator function.
+ * This simply calls arc4random_buf function if the platform provides it.
+ */
+
+int
+archive_random(void *buf, size_t nbytes)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ HCRYPTPROV hProv;
+ BOOL success;
+
+ success = CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT);
+ if (!success && GetLastError() == (DWORD)NTE_BAD_KEYSET) {
+ success = CryptAcquireContext(&hProv, NULL, NULL,
+ PROV_RSA_FULL, CRYPT_NEWKEYSET);
+ }
+ if (success) {
+ success = CryptGenRandom(hProv, (DWORD)nbytes, (BYTE*)buf);
+ CryptReleaseContext(hProv, 0);
+ if (success)
+ return ARCHIVE_OK;
+ }
+ /* TODO: Does this case really happen? */
+ return ARCHIVE_FAILED;
+#else
+ arc4random_buf(buf, nbytes);
+ return ARCHIVE_OK;
+#endif
+}
+
+#if !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__))
+
+/* $OpenBSD: arc4random.c,v 1.24 2013/06/11 16:59:50 deraadt Exp $ */
+/*
+ * Copyright (c) 1996, David Mazieres <dm@uun.org>
+ * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Arc4 random number generator for OpenBSD.
+ *
+ * This code is derived from section 17.1 of Applied Cryptography,
+ * second edition, which describes a stream cipher allegedly
+ * compatible with RSA Labs "RC4" cipher (the actual description of
+ * which is a trade secret). The same algorithm is used as a stream
+ * cipher called "arcfour" in Tatu Ylonen's ssh package.
+ *
+ * RC4 is a registered trademark of RSA Laboratories.
+ */
+
+#ifdef __GNUC__
+#define inline __inline
+#else /* !__GNUC__ */
+#define inline
+#endif /* !__GNUC__ */
+
+struct arc4_stream {
+ uint8_t i;
+ uint8_t j;
+ uint8_t s[256];
+};
+
+#define RANDOMDEV "/dev/urandom"
+#define KEYSIZE 128
+#ifdef HAVE_PTHREAD_H
+static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
+#define _ARC4_LOCK() pthread_mutex_lock(&arc4random_mtx);
+#define _ARC4_UNLOCK() pthread_mutex_unlock(&arc4random_mtx);
+#else
+#define _ARC4_LOCK()
+#define _ARC4_UNLOCK()
+#endif
+
+static int rs_initialized;
+static struct arc4_stream rs;
+static pid_t arc4_stir_pid;
+static int arc4_count;
+
+static inline uint8_t arc4_getbyte(void);
+static void arc4_stir(void);
+
+static inline void
+arc4_init(void)
+{
+ int n;
+
+ for (n = 0; n < 256; n++)
+ rs.s[n] = n;
+ rs.i = 0;
+ rs.j = 0;
+}
+
+static inline void
+arc4_addrandom(u_char *dat, int datlen)
+{
+ int n;
+ uint8_t si;
+
+ rs.i--;
+ for (n = 0; n < 256; n++) {
+ rs.i = (rs.i + 1);
+ si = rs.s[rs.i];
+ rs.j = (rs.j + si + dat[n % datlen]);
+ rs.s[rs.i] = rs.s[rs.j];
+ rs.s[rs.j] = si;
+ }
+ rs.j = rs.i;
+}
+
+static void
+arc4_stir(void)
+{
+ int done, fd, i;
+ struct {
+ struct timeval tv;
+ pid_t pid;
+ u_char rnd[KEYSIZE];
+ } rdat;
+
+ if (!rs_initialized) {
+ arc4_init();
+ rs_initialized = 1;
+ }
+ done = 0;
+ fd = open(RANDOMDEV, O_RDONLY | O_CLOEXEC, 0);
+ if (fd >= 0) {
+ if (read(fd, &rdat, KEYSIZE) == KEYSIZE)
+ done = 1;
+ (void)close(fd);
+ }
+ if (!done) {
+ (void)gettimeofday(&rdat.tv, NULL);
+ rdat.pid = getpid();
+ /* We'll just take whatever was on the stack too... */
+ }
+
+ arc4_addrandom((u_char *)&rdat, KEYSIZE);
+
+ /*
+ * Discard early keystream, as per recommendations in:
+ * "(Not So) Random Shuffles of RC4" by Ilya Mironov.
+ * As per the Network Operations Division, cryptographic requirements
+ * published on wikileaks on March 2017.
+ */
+
+ for (i = 0; i < 3072; i++)
+ (void)arc4_getbyte();
+ arc4_count = 1600000;
+}
+
+static void
+arc4_stir_if_needed(void)
+{
+ pid_t pid = getpid();
+
+ if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid) {
+ arc4_stir_pid = pid;
+ arc4_stir();
+ }
+}
+
+static inline uint8_t
+arc4_getbyte(void)
+{
+ uint8_t si, sj;
+
+ rs.i = (rs.i + 1);
+ si = rs.s[rs.i];
+ rs.j = (rs.j + si);
+ sj = rs.s[rs.j];
+ rs.s[rs.i] = sj;
+ rs.s[rs.j] = si;
+ return (rs.s[(si + sj) & 0xff]);
+}
+
+static void
+arc4random_buf(void *_buf, size_t n)
+{
+ u_char *buf = (u_char *)_buf;
+ _ARC4_LOCK();
+ arc4_stir_if_needed();
+ while (n--) {
+ if (--arc4_count <= 0)
+ arc4_stir();
+ buf[n] = arc4_getbyte();
+ }
+ _ARC4_UNLOCK();
+}
+
+#endif /* !HAVE_ARC4RANDOM_BUF */
diff --git a/3rdparty/libarchive/libarchive/archive_random_private.h b/3rdparty/libarchive/libarchive/archive_random_private.h
new file mode 100644
index 00000000..c414779f
--- /dev/null
+++ b/3rdparty/libarchive/libarchive/archive_random_private.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2014 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.
+ */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_RANDOM_PRIVATE_H_INCLUDED
+#define ARCHIVE_RANDOM_PRIVATE_H_INCLUDED
+
+/* Random number generator. */
+int archive_random(void *buf, size_t nbytes);
+
+#endif /* ARCHIVE_RANDOM_PRIVATE_H_INCLUDED */
diff --git a/3rdparty/libarchive/libarchive/archive_rb.c b/3rdparty/libarchive/libarchive/archive_rb.c
index 5b5da203..cf58ac33 100644
--- a/3rdparty/libarchive/libarchive/archive_rb.c
+++ b/3rdparty/libarchive/libarchive/archive_rb.c
@@ -312,7 +312,7 @@ __archive_rb_tree_insert_rebalance(struct archive_rb_tree *rbt,
father = RB_FATHER(self);
if (RB_BLACK_P(father)) {
/*
- * If our greatgrandpa is black, we're done.
+ * If our great-grandpa is black, we're done.
*/
return;
}
diff --git a/3rdparty/libarchive/libarchive/archive_read.c b/3rdparty/libarchive/libarchive/archive_read.c
index 048c316c..a642a336 100644
--- a/3rdparty/libarchive/libarchive/archive_read.c
+++ b/3rdparty/libarchive/libarchive/archive_read.c
@@ -57,6 +57,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read.c 201157 2009-12-29 05:30:2
static int choose_filters(struct archive_read *);
static int choose_format(struct archive_read *);
+static int close_filters(struct archive_read *);
static struct archive_vtable *archive_read_vtable(void);
static int64_t _archive_filter_bytes(struct archive *, int);
static int _archive_filter_code(struct archive *, int);
@@ -101,16 +102,17 @@ archive_read_new(void)
{
struct archive_read *a;
- a = (struct archive_read *)malloc(sizeof(*a));
+ a = (struct archive_read *)calloc(1, sizeof(*a));
if (a == NULL)
return (NULL);
- memset(a, 0, sizeof(*a));
a->archive.magic = ARCHIVE_READ_MAGIC;
a->archive.state = ARCHIVE_STATE_NEW;
a->entry = archive_entry_new2(&a->archive);
a->archive.vtable = archive_read_vtable();
+ a->passphrases.last = &a->passphrases.first;
+
return (&a->archive);
}
@@ -194,10 +196,12 @@ client_skip_proxy(struct archive_read_filter *self, int64_t request)
ask = skip_limit;
get = (self->archive->client.skipper)
(&self->archive->archive, self->data, ask);
- if (get == 0)
+ total += get;
+ if (get == 0 || get == request)
return (total);
+ if (get > request)
+ return ARCHIVE_FATAL;
request -= get;
- total += get;
}
} else if (self->archive->client.seeker != NULL
&& request > 64 * 1024) {
@@ -230,8 +234,11 @@ client_seek_proxy(struct archive_read_filter *self, int64_t offset, int whence)
* other libarchive code that assumes a successful forward
* seek means it can also seek backwards.
*/
- if (self->archive->client.seeker == NULL)
+ if (self->archive->client.seeker == NULL) {
+ archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ "Current client reader does not support seeking a device");
return (ARCHIVE_FAILED);
+ }
return (self->archive->client.seeker)(&self->archive->archive,
self->data, offset, whence);
}
@@ -454,7 +461,7 @@ archive_read_open1(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter *filter, *tmp;
- int slot, e;
+ int slot, e = ARCHIVE_OK;
unsigned int i;
archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
@@ -522,7 +529,7 @@ archive_read_open1(struct archive *_a)
{
slot = choose_format(a);
if (slot < 0) {
- __archive_read_close_filters(a);
+ close_filters(a);
a->archive.state = ARCHIVE_STATE_FATAL;
return (ARCHIVE_FATAL);
}
@@ -541,16 +548,20 @@ archive_read_open1(struct archive *_a)
* it wants to handle this stream. Repeat until we've finished
* building the pipeline.
*/
+
+/* We won't build a filter pipeline with more stages than this. */
+#define MAX_NUMBER_FILTERS 25
+
static int
choose_filters(struct archive_read *a)
{
- int number_bidders, i, bid, best_bid;
+ int number_bidders, i, bid, best_bid, number_filters;
struct archive_read_filter_bidder *bidder, *best_bidder;
struct archive_read_filter *filter;
ssize_t avail;
int r;
- for (;;) {
+ for (number_filters = 0; number_filters < MAX_NUMBER_FILTERS; ++number_filters) {
number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);
best_bid = 0;
@@ -572,7 +583,6 @@ choose_filters(struct archive_read *a)
/* Verify the filter by asking it for some data. */
__archive_read_filter_ahead(a->filter, 1, &avail);
if (avail < 0) {
- __archive_read_close_filters(a);
__archive_read_free_filters(a);
return (ARCHIVE_FATAL);
}
@@ -591,11 +601,13 @@ choose_filters(struct archive_read *a)
a->filter = filter;
r = (best_bidder->init)(a->filter);
if (r != ARCHIVE_OK) {
- __archive_read_close_filters(a);
__archive_read_free_filters(a);
return (ARCHIVE_FATAL);
}
}
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Input requires too many filters for decoding");
+ return (ARCHIVE_FATAL);
}
/*
@@ -658,16 +670,14 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
break;
}
- a->read_data_output_offset = 0;
- a->read_data_remaining = 0;
- a->read_data_is_posix_read = 0;
- a->read_data_requested = 0;
+ __archive_reset_read_data(&a->archive);
+
a->data_start_node = a->client.cursor;
/* EOF always wins; otherwise return the worst error. */
return (r2 < r1 || r2 == ARCHIVE_EOF) ? r2 : r1;
}
-int
+static int
_archive_read_next_header(struct archive *_a, struct archive_entry **entryp)
{
int ret;
@@ -747,6 +757,59 @@ archive_read_header_position(struct archive *_a)
}
/*
+ * Returns 1 if the archive contains at least one encrypted entry.
+ * If the archive format not support encryption at all
+ * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned.
+ * If for any other reason (e.g. not enough data read so far)
+ * we cannot say whether there are encrypted entries, then
+ * ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW is returned.
+ * In general, this function will return values below zero when the
+ * reader is uncertain or totally incapable of encryption support.
+ * When this function returns 0 you can be sure that the reader
+ * supports encryption detection but no encrypted entries have
+ * been found yet.
+ *
+ * NOTE: If the metadata/header of an archive is also encrypted, you
+ * cannot rely on the number of encrypted entries. That is why this
+ * function does not return the number of encrypted entries but#
+ * just shows that there are some.
+ */
+int
+archive_read_has_encrypted_entries(struct archive *_a)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ int format_supports_encryption = archive_read_format_capabilities(_a)
+ & (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA | ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);
+
+ if (!_a || !format_supports_encryption) {
+ /* Format in general doesn't support encryption */
+ return ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED;
+ }
+
+ /* A reader potentially has read enough data now. */
+ if (a->format && a->format->has_encrypted_entries) {
+ return (a->format->has_encrypted_entries)(a);
+ }
+
+ /* For any other reason we cannot say how many entries are there. */
+ return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
+}
+
+/*
+ * Returns a bitmask of capabilities that are supported by the archive format reader.
+ * If the reader has no special capabilities, ARCHIVE_READ_FORMAT_CAPS_NONE is returned.
+ */
+int
+archive_read_format_capabilities(struct archive *_a)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ if (a && a->format && a->format->format_capabilties) {
+ return (a->format->format_capabilties)(a);
+ }
+ return ARCHIVE_READ_FORMAT_CAPS_NONE;
+}
+
+/*
* Read data from an archive entry, using a read(2)-style interface.
* This is a convenience routine that just calls
* archive_read_data_block and copies the results into the client
@@ -760,7 +823,7 @@ archive_read_header_position(struct archive *_a)
ssize_t
archive_read_data(struct archive *_a, void *buff, size_t s)
{
- struct archive_read *a = (struct archive_read *)_a;
+ struct archive *a = (struct archive *)_a;
char *dest;
const void *read_buf;
size_t bytes_read;
@@ -775,7 +838,7 @@ archive_read_data(struct archive *_a, void *buff, size_t s)
read_buf = a->read_data_block;
a->read_data_is_posix_read = 1;
a->read_data_requested = s;
- r = _archive_read_data_block(&a->archive, &read_buf,
+ r = archive_read_data_block(a, &read_buf,
&a->read_data_remaining, &a->read_data_offset);
a->read_data_block = read_buf;
if (r == ARCHIVE_EOF)
@@ -790,7 +853,7 @@ archive_read_data(struct archive *_a, void *buff, size_t s)
}
if (a->read_data_offset < a->read_data_output_offset) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
"Encountered out-of-order sparse blocks");
return (ARCHIVE_RETRY);
}
@@ -818,7 +881,8 @@ archive_read_data(struct archive *_a, void *buff, size_t s)
len = a->read_data_remaining;
if (len > s)
len = s;
- memcpy(dest, a->read_data_block, len);
+ if (len)
+ memcpy(dest, a->read_data_block, len);
s -= len;
a->read_data_block += len;
a->read_data_remaining -= len;
@@ -834,6 +898,21 @@ archive_read_data(struct archive *_a, void *buff, size_t s)
}
/*
+ * Reset the read_data_* variables, used for starting a new entry.
+ */
+void __archive_reset_read_data(struct archive * a)
+{
+ a->read_data_output_offset = 0;
+ a->read_data_remaining = 0;
+ a->read_data_is_posix_read = 0;
+ a->read_data_requested = 0;
+
+ /* extra resets, from rar.c */
+ a->read_data_block = NULL;
+ a->read_data_offset = 0;
+}
+
+/*
* Skip over all remaining data in this entry.
*/
int
@@ -900,15 +979,15 @@ _archive_read_data_block(struct archive *_a,
if (a->format->read_data == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Internal error: "
- "No format_read_data_block function registered");
+ "No format->read_data function registered");
return (ARCHIVE_FATAL);
}
return (a->format->read_data)(a, buff, size, offset);
}
-int
-__archive_read_close_filters(struct archive_read *a)
+static int
+close_filters(struct archive_read *a)
{
struct archive_read_filter *f = a->filter;
int r = ARCHIVE_OK;
@@ -931,6 +1010,9 @@ __archive_read_close_filters(struct archive_read *a)
void
__archive_read_free_filters(struct archive_read *a)
{
+ /* Make sure filters are closed and their buffers are freed */
+ close_filters(a);
+
while (a->filter != NULL) {
struct archive_read_filter *t = a->filter->upstream;
free(a->filter);
@@ -973,7 +1055,7 @@ _archive_read_close(struct archive *_a)
/* TODO: Clean up the formatters. */
/* Release the filter objects. */
- r1 = __archive_read_close_filters(a);
+ r1 = close_filters(a);
if (r1 < r)
r = r1;
@@ -987,6 +1069,7 @@ static int
_archive_read_free(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
+ struct archive_read_passphrase *p;
int i, n;
int slots;
int r = ARCHIVE_OK;
@@ -1024,9 +1107,20 @@ _archive_read_free(struct archive *_a)
}
}
+ /* Release passphrase list. */
+ p = a->passphrases.first;
+ while (p != NULL) {
+ struct archive_read_passphrase *np = p->next;
+
+ /* A passphrase should be cleaned. */
+ memset(p->passphrase, 0, strlen(p->passphrase));
+ free(p->passphrase);
+ free(p);
+ p = np;
+ }
+
archive_string_free(&a->archive.error_string);
- if (a->entry)
- archive_entry_free(a->entry);
+ archive_entry_free(a->entry);
a->archive.magic = 0;
__archive_clean(&a->archive);
free(a->client.dataset);
@@ -1070,7 +1164,7 @@ static const char *
_archive_filter_name(struct archive *_a, int n)
{
struct archive_read_filter *f = get_filter(_a, n);
- return f == NULL ? NULL : f->name;
+ return f != NULL ? f->name : NULL;
}
static int64_t
@@ -1094,7 +1188,9 @@ __archive_read_register_format(struct archive_read *a,
int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *),
int (*read_data_skip)(struct archive_read *),
int64_t (*seek_data)(struct archive_read *, int64_t, int),
- int (*cleanup)(struct archive_read *))
+ int (*cleanup)(struct archive_read *),
+ int (*format_capabilities)(struct archive_read *),
+ int (*has_encrypted_entries)(struct archive_read *))
{
int i, number_slots;
@@ -1117,6 +1213,8 @@ __archive_read_register_format(struct archive_read *a,
a->formats[i].cleanup = cleanup;
a->formats[i].data = format_data;
a->formats[i].name = name;
+ a->formats[i].format_capabilties = format_capabilities;
+ a->formats[i].has_encrypted_entries = has_encrypted_entries;
return (ARCHIVE_OK);
}
}
@@ -1394,6 +1492,8 @@ __archive_read_filter_consume(struct archive_read_filter * filter,
{
int64_t skipped;
+ if (request < 0)
+ return ARCHIVE_FATAL;
if (request == 0)
return 0;
@@ -1557,10 +1657,9 @@ __archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,
client->dataset[++cursor].begin_position = r;
}
offset -= client->dataset[cursor].begin_position;
- if (offset < 0)
- offset = 0;
- else if (offset > client->dataset[cursor].total_size - 1)
- offset = client->dataset[cursor].total_size - 1;
+ if (offset < 0
+ || offset > client->dataset[cursor].total_size)
+ return ARCHIVE_FATAL;
if ((r = client_seek_proxy(filter, offset, SEEK_SET)) < 0)
return r;
break;
diff --git a/3rdparty/libarchive/libarchive/archive_read_append_filter.c b/3rdparty/libarchive/libarchive/archive_read_append_filter.c
index 017d7c68..5e4d1630 100644
--- a/3rdparty/libarchive/libarchive/archive_read_append_filter.c
+++ b/3rdparty/libarchive/libarchive/archive_read_append_filter.c
@@ -43,7 +43,7 @@ archive_read_append_filter(struct archive *_a, int code)
struct archive_read_filter *filter;
struct archive_read *a = (struct archive_read *)_a;
- r1 = r2 = (ARCHIVE_OK);
+ r2 = (ARCHIVE_OK);
switch (code)
{
case ARCHIVE_FILTER_NONE:
@@ -85,6 +85,10 @@ archive_read_append_filter(struct archive *_a, int code)
strcpy(str, "rpm");
r1 = archive_read_support_filter_rpm(_a);
break;
+ case ARCHIVE_FILTER_LZ4:
+ strcpy(str, "lz4");
+ r1 = archive_read_support_filter_lz4(_a);
+ break;
case ARCHIVE_FILTER_LZIP:
strcpy(str, "lzip");
r1 = archive_read_support_filter_lzip(_a);
@@ -129,7 +133,6 @@ archive_read_append_filter(struct archive *_a, int code)
a->filter = filter;
r2 = (bidder->init)(a->filter);
if (r2 != ARCHIVE_OK) {
- __archive_read_close_filters(a);
__archive_read_free_filters(a);
return (ARCHIVE_FATAL);
}
@@ -187,7 +190,6 @@ archive_read_append_filter_program_signature(struct archive *_a,
a->filter = filter;
r = (bidder->init)(a->filter);
if (r != ARCHIVE_OK) {
- __archive_read_close_filters(a);
__archive_read_free_filters(a);
return (ARCHIVE_FATAL);
}
diff --git a/3rdparty/libarchive/libarchive/archive_read_disk_entry_from_file.c b/3rdparty/libarchive/libarchive/archive_read_disk_entry_from_file.c
index e984aaad..548ba89e 100644
--- a/3rdparty/libarchive/libarchive/archive_read_disk_entry_from_file.c
+++ b/3rdparty/libarchive/libarchive/archive_read_disk_entry_from_file.c
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 2003-2009 Tim Kientzle
* Copyright (c) 2010-2012 Michihiro NAKAJIMA
+ * Copyright (c) 2016 Martin Matuska
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,18 +26,14 @@
*/
#include "archive_platform.h"
-__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 201084 2009-12-28 02:14:09Z kientzle $");
+__FBSDID("$FreeBSD");
/* This is the tree-walking code for POSIX systems. */
#if !defined(_WIN32) || defined(__CYGWIN__)
#ifdef HAVE_SYS_TYPES_H
-/* Mac OSX requires sys/types.h before sys/acl.h. */
#include <sys/types.h>
#endif
-#ifdef HAVE_SYS_ACL_H
-#include <sys/acl.h>
-#endif
#ifdef HAVE_SYS_EXTATTR_H
#include <sys/extattr.h>
#endif
@@ -57,9 +54,6 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010
#ifdef HAVE_SYS_EA_H
#include <sys/ea.h>
#endif
-#ifdef HAVE_ACL_LIBACL_H
-#include <acl/libacl.h>
-#endif
#ifdef HAVE_COPYFILE_H
#include <copyfile.h>
#endif
@@ -107,24 +101,55 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010
#define O_CLOEXEC 0
#endif
-/*
- * Linux and FreeBSD plug this obvious hole in POSIX.1e in
- * different ways.
- */
-#if HAVE_ACL_GET_PERM
-#define ACL_GET_PERM acl_get_perm
-#elif HAVE_ACL_GET_PERM_NP
-#define ACL_GET_PERM acl_get_perm_np
-#endif
-
-static int setup_acls(struct archive_read_disk *,
- struct archive_entry *, int *fd);
static int setup_mac_metadata(struct archive_read_disk *,
struct archive_entry *, int *fd);
static int setup_xattrs(struct archive_read_disk *,
struct archive_entry *, int *fd);
static int setup_sparse(struct archive_read_disk *,
struct archive_entry *, int *fd);
+#if defined(HAVE_LINUX_FIEMAP_H)
+static int setup_sparse_fiemap(struct archive_read_disk *,
+ struct archive_entry *, int *fd);
+#endif
+
+#if !ARCHIVE_ACL_SUPPORT
+int
+archive_read_disk_entry_setup_acls(struct archive_read_disk *a,
+ struct archive_entry *entry, int *fd)
+{
+ (void)a; /* UNUSED */
+ (void)entry; /* UNUSED */
+ (void)fd; /* UNUSED */
+ return (ARCHIVE_OK);
+}
+#endif
+
+/*
+ * Enter working directory and return working pathname of archive_entry.
+ * If a pointer to an integer is provided and its value is below zero
+ * open a file descriptor on this pahtname.
+ */
+const char *
+archive_read_disk_entry_setup_path(struct archive_read_disk *a,
+ struct archive_entry *entry, int *fd)
+{
+ const char *path;
+
+ path = archive_entry_sourcepath(entry);
+
+ if (path == NULL || (a->tree != NULL &&
+ a->tree_enter_working_dir(a->tree) != 0))
+ path = archive_entry_pathname(entry);
+ if (path == NULL) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Couldn't determine path");
+ } else if (fd != NULL && *fd < 0 && a->tree != NULL &&
+ (a->follow_symlinks || archive_entry_filetype(entry) != AE_IFLNK)) {
+ *fd = a->open_on_current_dir(a->tree, path,
+ O_RDONLY | O_NONBLOCK);
+ }
+ return (path);
+}
int
archive_read_disk_entry_from_file(struct archive *_a,
@@ -184,15 +209,17 @@ archive_read_disk_entry_from_file(struct archive *_a,
#ifdef HAVE_STRUCT_STAT_ST_FLAGS
/* On FreeBSD, we get flags for free with the stat. */
/* TODO: Does this belong in copy_stat()? */
- if (st->st_flags != 0)
+ if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0 && st->st_flags != 0)
archive_entry_set_fflags(entry, st->st_flags, 0);
#endif
-#if defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)
+#if (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \
+ (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS))
/* Linux requires an extra ioctl to pull the flags. Although
* this is an extra step, it has a nice side-effect: We get an
* open file descriptor which we can use in the subsequent lookups. */
- if ((S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) {
+ if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0 &&
+ (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) {
if (fd < 0) {
if (a->tree != NULL)
fd = a->open_on_current_dir(a->tree, path,
@@ -204,7 +231,13 @@ archive_read_disk_entry_from_file(struct archive *_a,
}
if (fd >= 0) {
int stflags;
- r = ioctl(fd, EXT2_IOC_GETFLAGS, &stflags);
+ r = ioctl(fd,
+#if defined(FS_IOC_GETFLAGS)
+ FS_IOC_GETFLAGS,
+#else
+ EXT2_IOC_GETFLAGS,
+#endif
+ &stflags);
if (r == 0 && stflags != 0)
archive_entry_set_fflags(entry, stflags, 0);
}
@@ -250,11 +283,15 @@ archive_read_disk_entry_from_file(struct archive *_a,
}
#endif /* HAVE_READLINK || HAVE_READLINKAT */
- r = setup_acls(a, entry, &fd);
- r1 = setup_xattrs(a, entry, &fd);
- if (r1 < r)
- r = r1;
- if (a->enable_copyfile) {
+ r = 0;
+ if ((a->flags & ARCHIVE_READDISK_NO_ACL) == 0)
+ r = archive_read_disk_entry_setup_acls(a, entry, &fd);
+ if ((a->flags & ARCHIVE_READDISK_NO_XATTR) == 0) {
+ r1 = setup_xattrs(a, entry, &fd);
+ if (r1 < r)
+ r = r1;
+ }
+ if (a->flags & ARCHIVE_READDISK_MAC_COPYFILE) {
r1 = setup_mac_metadata(a, entry, &fd);
if (r1 < r)
r = r1;
@@ -297,22 +334,10 @@ setup_mac_metadata(struct archive_read_disk *a,
struct archive_string tempfile;
(void)fd; /* UNUSED */
- name = archive_entry_sourcepath(entry);
+
+ name = archive_read_disk_entry_setup_path(a, entry, NULL);
if (name == NULL)
- name = archive_entry_pathname(entry);
- if (name == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Can't open file to read extended attributes: No name");
return (ARCHIVE_WARN);
- }
-
- if (a->tree != NULL) {
- if (a->tree_enter_working_dir(a->tree) != 0) {
- archive_set_error(&a->archive, errno,
- "Couldn't change dir");
- return (ARCHIVE_FAILED);
- }
- }
/* Short-circuit if there's nothing to do. */
have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK);
@@ -398,279 +423,10 @@ setup_mac_metadata(struct archive_read_disk *a,
}
#endif
-
-#if defined(HAVE_POSIX_ACL) && defined(ACL_TYPE_NFS4)
-static int translate_acl(struct archive_read_disk *a,
- struct archive_entry *entry, acl_t acl, int archive_entry_acl_type);
-
-static int
-setup_acls(struct archive_read_disk *a,
- struct archive_entry *entry, int *fd)
-{
- const char *accpath;
- acl_t acl;
-#if HAVE_ACL_IS_TRIVIAL_NP
- int r;
-#endif
-
- accpath = archive_entry_sourcepath(entry);
- if (accpath == NULL)
- accpath = archive_entry_pathname(entry);
-
- archive_entry_acl_clear(entry);
-
- /* Try NFS4 ACL first. */
- if (*fd >= 0)
- acl = acl_get_fd(*fd);
-#if HAVE_ACL_GET_LINK_NP
- else if (!a->follow_symlinks)
- acl = acl_get_link_np(accpath, ACL_TYPE_NFS4);
-#else
- else if ((!a->follow_symlinks)
- && (archive_entry_filetype(entry) == AE_IFLNK))
- /* We can't get the ACL of a symlink, so we assume it can't
- have one. */
- acl = NULL;
-#endif
- else
- acl = acl_get_file(accpath, ACL_TYPE_NFS4);
-#if HAVE_ACL_IS_TRIVIAL_NP
- /* Ignore "trivial" ACLs that just mirror the file mode. */
- acl_is_trivial_np(acl, &r);
- if (r) {
- acl_free(acl);
- acl = NULL;
- }
-#endif
- if (acl != NULL) {
- translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4);
- acl_free(acl);
- return (ARCHIVE_OK);
- }
-
- /* Retrieve access ACL from file. */
- if (*fd >= 0)
- acl = acl_get_fd(*fd);
-#if HAVE_ACL_GET_LINK_NP
- else if (!a->follow_symlinks)
- acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);
-#else
- else if ((!a->follow_symlinks)
- && (archive_entry_filetype(entry) == AE_IFLNK))
- /* We can't get the ACL of a symlink, so we assume it can't
- have one. */
- acl = NULL;
-#endif
- else
- acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
- if (acl != NULL) {
- translate_acl(a, entry, acl,
- ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
- acl_free(acl);
- }
-
- /* Only directories can have default ACLs. */
- if (S_ISDIR(archive_entry_mode(entry))) {
- acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
- if (acl != NULL) {
- translate_acl(a, entry, acl,
- ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
- acl_free(acl);
- }
- }
- return (ARCHIVE_OK);
-}
-
-/*
- * Translate system ACL into libarchive internal structure.
- */
-
-static struct {
- int archive_perm;
- int platform_perm;
-} acl_perm_map[] = {
- {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
- {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
- {ARCHIVE_ENTRY_ACL_READ, ACL_READ},
- {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
- {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
- {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
- {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
- {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
- {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
- {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
- {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
- {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
- {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
- {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
- {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
- {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
- {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
- {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
- {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
-};
-
-static struct {
- int archive_inherit;
- int platform_inherit;
-} acl_inherit_map[] = {
- {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
- {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
- {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
- {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY}
-};
-
-static int
-translate_acl(struct archive_read_disk *a,
- struct archive_entry *entry, acl_t acl, int default_entry_acl_type)
-{
- acl_tag_t acl_tag;
- acl_entry_type_t acl_type;
- acl_flagset_t acl_flagset;
- acl_entry_t acl_entry;
- acl_permset_t acl_permset;
- int brand, i, r, entry_acl_type;
- int s, ae_id, ae_tag, ae_perm;
- const char *ae_name;
-
-
- // FreeBSD "brands" ACLs as POSIX.1e or NFSv4
- // Make sure the "brand" on this ACL is consistent
- // with the default_entry_acl_type bits provided.
- acl_get_brand_np(acl, &brand);
- switch (brand) {
- case ACL_BRAND_POSIX:
- switch (default_entry_acl_type) {
- case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
- case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
- break;
- default:
- // XXX set warning message?
- return ARCHIVE_FAILED;
- }
- break;
- case ACL_BRAND_NFS4:
- if (default_entry_acl_type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
- // XXX set warning message?
- return ARCHIVE_FAILED;
- }
- break;
- default:
- // XXX set warning message?
- return ARCHIVE_FAILED;
- break;
- }
-
-
- s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
- while (s == 1) {
- ae_id = -1;
- ae_name = NULL;
- ae_perm = 0;
-
- acl_get_tag_type(acl_entry, &acl_tag);
- switch (acl_tag) {
- case ACL_USER:
- ae_id = (int)*(uid_t *)acl_get_qualifier(acl_entry);
- ae_name = archive_read_disk_uname(&a->archive, ae_id);
- ae_tag = ARCHIVE_ENTRY_ACL_USER;
- break;
- case ACL_GROUP:
- ae_id = (int)*(gid_t *)acl_get_qualifier(acl_entry);
- ae_name = archive_read_disk_gname(&a->archive, ae_id);
- ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
- break;
- case ACL_MASK:
- ae_tag = ARCHIVE_ENTRY_ACL_MASK;
- break;
- case ACL_USER_OBJ:
- ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
- break;
- case ACL_GROUP_OBJ:
- ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
- break;
- case ACL_OTHER:
- ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
- break;
- case ACL_EVERYONE:
- ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
- break;
- default:
- /* Skip types that libarchive can't support. */
- s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
- continue;
- }
-
- // XXX acl type maps to allow/deny/audit/YYYY bits
- // XXX acl_get_entry_type_np on FreeBSD returns EINVAL for
- // non-NFSv4 ACLs
- entry_acl_type = default_entry_acl_type;
- r = acl_get_entry_type_np(acl_entry, &acl_type);
- if (r == 0) {
- switch (acl_type) {
- case ACL_ENTRY_TYPE_ALLOW:
- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
- break;
- case ACL_ENTRY_TYPE_DENY:
- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
- break;
- case ACL_ENTRY_TYPE_AUDIT:
- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;
- break;
- case ACL_ENTRY_TYPE_ALARM:
- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
- break;
- }
- }
-
- /*
- * Libarchive stores "flag" (NFSv4 inheritance bits)
- * in the ae_perm bitmap.
- */
- acl_get_flagset_np(acl_entry, &acl_flagset);
- for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) {
- if (acl_get_flag_np(acl_flagset,
- acl_inherit_map[i].platform_inherit))
- ae_perm |= acl_inherit_map[i].archive_inherit;
-
- }
-
- acl_get_permset(acl_entry, &acl_permset);
- for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
- /*
- * acl_get_perm() is spelled differently on different
- * platforms; see above.
- */
- if (ACL_GET_PERM(acl_permset, acl_perm_map[i].platform_perm))
- ae_perm |= acl_perm_map[i].archive_perm;
- }
-
- archive_entry_acl_add_entry(entry, entry_acl_type,
- ae_perm, ae_tag,
- ae_id, ae_name);
-
- s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
- }
- return (ARCHIVE_OK);
-}
-#else
-static int
-setup_acls(struct archive_read_disk *a,
- struct archive_entry *entry, int *fd)
-{
- (void)a; /* UNUSED */
- (void)entry; /* UNUSED */
- (void)fd; /* UNUSED */
- return (ARCHIVE_OK);
-}
-#endif
-
-#if (HAVE_FGETXATTR && HAVE_FLISTXATTR && HAVE_LISTXATTR && \
- HAVE_LLISTXATTR && HAVE_GETXATTR && HAVE_LGETXATTR) || \
- (HAVE_FGETEA && HAVE_FLISTEA && HAVE_LISTEA)
+#if ARCHIVE_XATTR_LINUX || ARCHIVE_XATTR_DARWIN || ARCHIVE_XATTR_AIX
/*
- * Linux and AIX extended attribute support.
+ * Linux, Darwin and AIX extended attribute support.
*
* TODO: By using a stack-allocated buffer for the first
* call to getxattr(), we might be able to avoid the second
@@ -683,31 +439,37 @@ setup_acls(struct archive_read_disk *a,
static int
setup_xattr(struct archive_read_disk *a,
- struct archive_entry *entry, const char *name, int fd)
+ struct archive_entry *entry, const char *name, int fd, const char *accpath)
{
ssize_t size;
void *value = NULL;
- const char *accpath;
- accpath = archive_entry_sourcepath(entry);
- if (accpath == NULL)
- accpath = archive_entry_pathname(entry);
-#if HAVE_FGETXATTR
- if (fd >= 0)
+ if (fd >= 0) {
+#if ARCHIVE_XATTR_LINUX
size = fgetxattr(fd, name, NULL, 0);
- else if (!a->follow_symlinks)
- size = lgetxattr(accpath, name, NULL, 0);
- else
- size = getxattr(accpath, name, NULL, 0);
-#elif HAVE_FGETEA
- if (fd >= 0)
+#elif ARCHIVE_XATTR_DARWIN
+ size = fgetxattr(fd, name, NULL, 0, 0, 0);
+#elif ARCHIVE_XATTR_AIX
size = fgetea(fd, name, NULL, 0);
- else if (!a->follow_symlinks)
+#endif
+ } else if (!a->follow_symlinks) {
+#if ARCHIVE_XATTR_LINUX
+ size = lgetxattr(accpath, name, NULL, 0);
+#elif ARCHIVE_XATTR_DARWIN
+ size = getxattr(accpath, name, NULL, 0, 0, XATTR_NOFOLLOW);
+#elif ARCHIVE_XATTR_AIX
size = lgetea(accpath, name, NULL, 0);
- else
+#endif
+ } else {
+#if ARCHIVE_XATTR_LINUX
+ size = getxattr(accpath, name, NULL, 0);
+#elif ARCHIVE_XATTR_DARWIN
+ size = getxattr(accpath, name, NULL, 0, 0, 0);
+#elif ARCHIVE_XATTR_AIX
size = getea(accpath, name, NULL, 0);
#endif
+ }
if (size == -1) {
archive_set_error(&a->archive, errno,
@@ -720,21 +482,32 @@ setup_xattr(struct archive_read_disk *a,
return (ARCHIVE_FATAL);
}
-#if HAVE_FGETXATTR
- if (fd >= 0)
+
+ if (fd >= 0) {
+#if ARCHIVE_XATTR_LINUX
size = fgetxattr(fd, name, value, size);
- else if (!a->follow_symlinks)
- size = lgetxattr(accpath, name, value, size);
- else
- size = getxattr(accpath, name, value, size);
-#elif HAVE_FGETEA
- if (fd >= 0)
+#elif ARCHIVE_XATTR_DARWIN
+ size = fgetxattr(fd, name, value, size, 0, 0);
+#elif ARCHIVE_XATTR_AIX
size = fgetea(fd, name, value, size);
- else if (!a->follow_symlinks)
+#endif
+ } else if (!a->follow_symlinks) {
+#if ARCHIVE_XATTR_LINUX
+ size = lgetxattr(accpath, name, value, size);
+#elif ARCHIVE_XATTR_DARWIN
+ size = getxattr(accpath, name, value, size, 0, XATTR_NOFOLLOW);
+#elif ARCHIVE_XATTR_AIX
size = lgetea(accpath, name, value, size);
- else
+#endif
+ } else {
+#if ARCHIVE_XATTR_LINUX
+ size = getxattr(accpath, name, value, size);
+#elif ARCHIVE_XATTR_DARWIN
+ size = getxattr(accpath, name, value, size, 0, 0);
+#elif ARCHIVE_XATTR_AIX
size = getea(accpath, name, value, size);
#endif
+ }
if (size == -1) {
archive_set_error(&a->archive, errno,
@@ -756,39 +529,39 @@ setup_xattrs(struct archive_read_disk *a,
const char *path;
ssize_t list_size;
- path = archive_entry_sourcepath(entry);
- if (path == NULL)
- path = archive_entry_pathname(entry);
+ path = NULL;
- if (*fd < 0 && a->tree != NULL) {
- if (a->follow_symlinks ||
- archive_entry_filetype(entry) != AE_IFLNK)
- *fd = a->open_on_current_dir(a->tree, path,
- O_RDONLY | O_NONBLOCK);
- if (*fd < 0) {
- if (a->tree_enter_working_dir(a->tree) != 0) {
- archive_set_error(&a->archive, errno,
- "Couldn't access %s", path);
- return (ARCHIVE_FAILED);
- }
- }
+ if (*fd < 0) {
+ path = archive_read_disk_entry_setup_path(a, entry, fd);
+ if (path == NULL)
+ return (ARCHIVE_WARN);
}
-#if HAVE_FLISTXATTR
- if (*fd >= 0)
+ if (*fd >= 0) {
+#if ARCHIVE_XATTR_LINUX
list_size = flistxattr(*fd, NULL, 0);
- else if (!a->follow_symlinks)
- list_size = llistxattr(path, NULL, 0);
- else
- list_size = listxattr(path, NULL, 0);
-#elif HAVE_FLISTEA
- if (*fd >= 0)
+#elif ARCHIVE_XATTR_DARWIN
+ list_size = flistxattr(*fd, NULL, 0, 0);
+#elif ARCHIVE_XATTR_AIX
list_size = flistea(*fd, NULL, 0);
- else if (!a->follow_symlinks)
+#endif
+ } else if (!a->follow_symlinks) {
+#if ARCHIVE_XATTR_LINUX
+ list_size = llistxattr(path, NULL, 0);
+#elif ARCHIVE_XATTR_DARWIN
+ list_size = listxattr(path, NULL, 0, XATTR_NOFOLLOW);
+#elif ARCHIVE_XATTR_AIX
list_size = llistea(path, NULL, 0);
- else
+#endif
+ } else {
+#if ARCHIVE_XATTR_LINUX
+ list_size = listxattr(path, NULL, 0);
+#elif ARCHIVE_XATTR_DARWIN
+ list_size = listxattr(path, NULL, 0, 0);
+#elif ARCHIVE_XATTR_AIX
list_size = listea(path, NULL, 0);
#endif
+ }
if (list_size == -1) {
if (errno == ENOTSUP || errno == ENOSYS)
@@ -806,21 +579,31 @@ setup_xattrs(struct archive_read_disk *a,
return (ARCHIVE_FATAL);
}
-#if HAVE_FLISTXATTR
- if (*fd >= 0)
+ if (*fd >= 0) {
+#if ARCHIVE_XATTR_LINUX
list_size = flistxattr(*fd, list, list_size);
- else if (!a->follow_symlinks)
- list_size = llistxattr(path, list, list_size);
- else
- list_size = listxattr(path, list, list_size);
-#elif HAVE_FLISTEA
- if (*fd >= 0)
+#elif ARCHIVE_XATTR_DARWIN
+ list_size = flistxattr(*fd, list, list_size, 0);
+#elif ARCHIVE_XATTR_AIX
list_size = flistea(*fd, list, list_size);
- else if (!a->follow_symlinks)
+#endif
+ } else if (!a->follow_symlinks) {
+#if ARCHIVE_XATTR_LINUX
+ list_size = llistxattr(path, list, list_size);
+#elif ARCHIVE_XATTR_DARWIN
+ list_size = listxattr(path, list, list_size, XATTR_NOFOLLOW);
+#elif ARCHIVE_XATTR_AIX
list_size = llistea(path, list, list_size);
- else
+#endif
+ } else {
+#if ARCHIVE_XATTR_LINUX
+ list_size = listxattr(path, list, list_size);
+#elif ARCHIVE_XATTR_DARWIN
+ list_size = listxattr(path, list, list_size, 0);
+#elif ARCHIVE_XATTR_AIX
list_size = listea(path, list, list_size);
#endif
+ }
if (list_size == -1) {
archive_set_error(&a->archive, errno,
@@ -830,18 +613,29 @@ setup_xattrs(struct archive_read_disk *a,
}
for (p = list; (p - list) < list_size; p += strlen(p) + 1) {
- if (strncmp(p, "system.", 7) == 0 ||
- strncmp(p, "xfsroot.", 8) == 0)
+#if ARCHIVE_XATTR_LINUX
+ /* Linux: skip POSIX.1e ACL extended attributes */
+ if (strncmp(p, "system.", 7) == 0 &&
+ (strcmp(p + 7, "posix_acl_access") == 0 ||
+ strcmp(p + 7, "posix_acl_default") == 0))
+ continue;
+ if (strncmp(p, "trusted.SGI_", 12) == 0 &&
+ (strcmp(p + 12, "ACL_DEFAULT") == 0 ||
+ strcmp(p + 12, "ACL_FILE") == 0))
continue;
- setup_xattr(a, entry, p, *fd);
+
+ /* Linux: xfsroot namespace is obsolete and unsupported */
+ if (strncmp(p, "xfsroot.", 8) == 0)
+ continue;
+#endif
+ setup_xattr(a, entry, p, *fd, path);
}
free(list);
return (ARCHIVE_OK);
}
-#elif HAVE_EXTATTR_GET_FILE && HAVE_EXTATTR_LIST_FILE && \
- HAVE_DECL_EXTATTR_NAMESPACE_USER
+#elif ARCHIVE_XATTR_FREEBSD
/*
* FreeBSD extattr interface.
@@ -854,19 +648,16 @@ setup_xattrs(struct archive_read_disk *a,
*/
static int
setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
- int namespace, const char *name, const char *fullname, int fd);
+ int namespace, const char *name, const char *fullname, int fd,
+ const char *path);
static int
setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
- int namespace, const char *name, const char *fullname, int fd)
+ int namespace, const char *name, const char *fullname, int fd,
+ const char *accpath)
{
ssize_t size;
void *value = NULL;
- const char *accpath;
-
- accpath = archive_entry_sourcepath(entry);
- if (accpath == NULL)
- accpath = archive_entry_pathname(entry);
if (fd >= 0)
size = extattr_get_fd(fd, namespace, name, NULL, 0);
@@ -916,22 +707,12 @@ setup_xattrs(struct archive_read_disk *a,
const char *path;
int namespace = EXTATTR_NAMESPACE_USER;
- path = archive_entry_sourcepath(entry);
- if (path == NULL)
- path = archive_entry_pathname(entry);
+ path = NULL;
- if (*fd < 0 && a->tree != NULL) {
- if (a->follow_symlinks ||
- archive_entry_filetype(entry) != AE_IFLNK)
- *fd = a->open_on_current_dir(a->tree, path,
- O_RDONLY | O_NONBLOCK);
- if (*fd < 0) {
- if (a->tree_enter_working_dir(a->tree) != 0) {
- archive_set_error(&a->archive, errno,
- "Couldn't access %s", path);
- return (ARCHIVE_FAILED);
- }
- }
+ if (*fd < 0) {
+ path = archive_read_disk_entry_setup_path(a, entry, fd);
+ if (path == NULL)
+ return (ARCHIVE_WARN);
}
if (*fd >= 0)
@@ -980,7 +761,7 @@ setup_xattrs(struct archive_read_disk *a,
name = buff + strlen(buff);
memcpy(name, p + 1, len);
name[len] = '\0';
- setup_xattr(a, entry, namespace, name, buff, *fd);
+ setup_xattr(a, entry, namespace, name, buff, *fd, path);
p += 1 + len;
}
@@ -1008,7 +789,7 @@ setup_xattrs(struct archive_read_disk *a,
#if defined(HAVE_LINUX_FIEMAP_H)
/*
- * Linux sparse interface.
+ * Linux FIEMAP sparse interface.
*
* The FIEMAP ioctl returns an "extent" for each physical allocation
* on disk. We need to process those to generate a more compact list
@@ -1023,15 +804,16 @@ setup_xattrs(struct archive_read_disk *a,
*/
static int
-setup_sparse(struct archive_read_disk *a,
+setup_sparse_fiemap(struct archive_read_disk *a,
struct archive_entry *entry, int *fd)
{
char buff[4096];
struct fiemap *fm;
struct fiemap_extent *fe;
int64_t size;
- int count, do_fiemap;
+ int count, do_fiemap, iters;
int exit_sts = ARCHIVE_OK;
+ const char *path;
if (archive_entry_filetype(entry) != AE_IFREG
|| archive_entry_size(entry) <= 0
@@ -1039,11 +821,10 @@ setup_sparse(struct archive_read_disk *a,
return (ARCHIVE_OK);
if (*fd < 0) {
- const char *path;
-
- path = archive_entry_sourcepath(entry);
+ path = archive_read_disk_entry_setup_path(a, entry, NULL);
if (path == NULL)
- path = archive_entry_pathname(entry);
+ return (ARCHIVE_FAILED);
+
if (a->tree != NULL)
*fd = a->open_on_current_dir(a->tree, path,
O_RDONLY | O_NONBLOCK | O_CLOEXEC);
@@ -1067,18 +848,23 @@ setup_sparse(struct archive_read_disk *a,
fm->fm_extent_count = count;
do_fiemap = 1;
size = archive_entry_size(entry);
- for (;;) {
+ for (iters = 0; ; ++iters) {
int i, r;
r = ioctl(*fd, FS_IOC_FIEMAP, fm);
if (r < 0) {
/* When something error happens, it is better we
* should return ARCHIVE_OK because an earlier
- * version(<2.6.28) cannot perfom FS_IOC_FIEMAP. */
- goto exit_setup_sparse;
+ * version(<2.6.28) cannot perform FS_IOC_FIEMAP. */
+ goto exit_setup_sparse_fiemap;
}
- if (fm->fm_mapped_extents == 0)
+ if (fm->fm_mapped_extents == 0) {
+ if (iters == 0) {
+ /* Fully sparse file; insert a zero-length "data" entry */
+ archive_entry_sparse_add_entry(entry, 0, 0);
+ }
break;
+ }
fe = fm->fm_extents;
for (i = 0; i < (int)fm->fm_mapped_extents; i++, fe++) {
if (!(fe->fe_flags & FIEMAP_EXTENT_UNWRITTEN)) {
@@ -1105,14 +891,24 @@ setup_sparse(struct archive_read_disk *a,
} else
break;
}
-exit_setup_sparse:
+exit_setup_sparse_fiemap:
return (exit_sts);
}
-#elif defined(SEEK_HOLE) && defined(SEEK_DATA) && defined(_PC_MIN_HOLE_SIZE)
+#if !defined(SEEK_HOLE) || !defined(SEEK_DATA)
+static int
+setup_sparse(struct archive_read_disk *a,
+ struct archive_entry *entry, int *fd)
+{
+ return setup_sparse_fiemap(a, entry, fd);
+}
+#endif
+#endif /* defined(HAVE_LINUX_FIEMAP_H) */
+
+#if defined(SEEK_HOLE) && defined(SEEK_DATA)
/*
- * FreeBSD and Solaris sparse interface.
+ * SEEK_HOLE sparse interface (FreeBSD, Linux, Solaris)
*/
static int
@@ -1120,9 +916,11 @@ setup_sparse(struct archive_read_disk *a,
struct archive_entry *entry, int *fd)
{
int64_t size;
- off_t initial_off; /* FreeBSD/Solaris only, so off_t okay here */
- off_t off_s, off_e; /* FreeBSD/Solaris only, so off_t okay here */
+ off_t initial_off;
+ off_t off_s, off_e;
int exit_sts = ARCHIVE_OK;
+ int check_fully_sparse = 0;
+ const char *path;
if (archive_entry_filetype(entry) != AE_IFREG
|| archive_entry_size(entry) <= 0
@@ -1130,36 +928,26 @@ setup_sparse(struct archive_read_disk *a,
return (ARCHIVE_OK);
/* Does filesystem support the reporting of hole ? */
- if (*fd < 0 && a->tree != NULL) {
- const char *path;
-
- path = archive_entry_sourcepath(entry);
- if (path == NULL)
- path = archive_entry_pathname(entry);
- *fd = a->open_on_current_dir(a->tree, path,
- O_RDONLY | O_NONBLOCK);
- if (*fd < 0) {
- archive_set_error(&a->archive, errno,
- "Can't open `%s'", path);
- return (ARCHIVE_FAILED);
- }
- }
+ if (*fd < 0)
+ path = archive_read_disk_entry_setup_path(a, entry, fd);
+ else
+ path = NULL;
if (*fd >= 0) {
+#ifdef _PC_MIN_HOLE_SIZE
if (fpathconf(*fd, _PC_MIN_HOLE_SIZE) <= 0)
return (ARCHIVE_OK);
+#endif
initial_off = lseek(*fd, 0, SEEK_CUR);
if (initial_off != 0)
lseek(*fd, 0, SEEK_SET);
} else {
- const char *path;
-
- path = archive_entry_sourcepath(entry);
if (path == NULL)
- path = archive_entry_pathname(entry);
-
+ return (ARCHIVE_FAILED);
+#ifdef _PC_MIN_HOLE_SIZE
if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0)
return (ARCHIVE_OK);
+#endif
*fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
if (*fd < 0) {
archive_set_error(&a->archive, errno,
@@ -1170,13 +958,32 @@ setup_sparse(struct archive_read_disk *a,
initial_off = 0;
}
+#ifndef _PC_MIN_HOLE_SIZE
+ /* Check if the underlying filesystem supports seek hole */
+ off_s = lseek(*fd, 0, SEEK_HOLE);
+ if (off_s < 0)
+#if defined(HAVE_LINUX_FIEMAP_H)
+ return setup_sparse_fiemap(a, entry, fd);
+#else
+ goto exit_setup_sparse;
+#endif
+ else if (off_s > 0)
+ lseek(*fd, 0, SEEK_SET);
+#endif
+
off_s = 0;
size = archive_entry_size(entry);
while (off_s < size) {
off_s = lseek(*fd, off_s, SEEK_DATA);
if (off_s == (off_t)-1) {
- if (errno == ENXIO)
- break;/* no more hole */
+ if (errno == ENXIO) {
+ /* no more hole */
+ if (archive_entry_sparse_count(entry) == 0) {
+ /* Potentially a fully-sparse file. */
+ check_fully_sparse = 1;
+ }
+ break;
+ }
archive_set_error(&a->archive, errno,
"lseek(SEEK_HOLE) failed");
exit_sts = ARCHIVE_FAILED;
@@ -1195,17 +1002,25 @@ setup_sparse(struct archive_read_disk *a,
goto exit_setup_sparse;
}
if (off_s == 0 && off_e == size)
- break;/* This is not spase. */
+ break;/* This is not sparse. */
archive_entry_sparse_add_entry(entry, off_s,
off_e - off_s);
off_s = off_e;
}
+
+ if (check_fully_sparse) {
+ if (lseek(*fd, 0, SEEK_HOLE) == 0 &&
+ lseek(*fd, 0, SEEK_END) == size) {
+ /* Fully sparse file; insert a zero-length "data" entry */
+ archive_entry_sparse_add_entry(entry, 0, 0);
+ }
+ }
exit_setup_sparse:
lseek(*fd, initial_off, SEEK_SET);
return (exit_sts);
}
-#else
+#elif !defined(HAVE_LINUX_FIEMAP_H)
/*
* Generic (stub) sparse support.
diff --git a/3rdparty/libarchive/libarchive/archive_read_disk_posix.c b/3rdparty/libarchive/libarchive/archive_read_disk_posix.c
index a13dbbf8..6961ae6a 100644
--- a/3rdparty/libarchive/libarchive/archive_read_disk_posix.c
+++ b/3rdparty/libarchive/libarchive/archive_read_disk_posix.c
@@ -165,7 +165,7 @@ struct filesystem {
int synthetic;
int remote;
int noatime;
-#if defined(HAVE_READDIR_R)
+#if defined(USE_READDIR_R)
size_t name_max;
#endif
long incr_xfer_size;
@@ -200,7 +200,7 @@ struct tree {
DIR *d;
#define INVALID_DIR_HANDLE NULL
struct dirent *de;
-#if defined(HAVE_READDIR_R)
+#if defined(USE_READDIR_R)
struct dirent *dirent;
size_t dirent_allocated;
#endif
@@ -244,7 +244,7 @@ struct tree {
int initial_filesystem_id;
int current_filesystem_id;
int max_filesystem_id;
- int allocated_filesytem;
+ int allocated_filesystem;
int entry_fd;
int entry_eof;
@@ -356,6 +356,8 @@ static int _archive_read_free(struct archive *);
static int _archive_read_close(struct archive *);
static int _archive_read_data_block(struct archive *,
const void **, size_t *, int64_t *);
+static int _archive_read_next_header(struct archive *,
+ struct archive_entry **);
static int _archive_read_next_header2(struct archive *,
struct archive_entry *);
static const char *trivial_lookup_gname(void *, int64_t gid);
@@ -377,6 +379,7 @@ archive_read_disk_vtable(void)
av.archive_free = _archive_read_free;
av.archive_close = _archive_read_close;
av.archive_read_data_block = _archive_read_data_block;
+ av.archive_read_next_header = _archive_read_next_header;
av.archive_read_next_header2 = _archive_read_next_header2;
inited = 1;
}
@@ -459,10 +462,10 @@ archive_read_disk_new(void)
a->archive.magic = ARCHIVE_READ_DISK_MAGIC;
a->archive.state = ARCHIVE_STATE_NEW;
a->archive.vtable = archive_read_disk_vtable();
+ a->entry = archive_entry_new2(&a->archive);
a->lookup_uname = trivial_lookup_uname;
a->lookup_gname = trivial_lookup_gname;
- a->enable_copyfile = 1;
- a->traverse_mount_points = 1;
+ a->flags = ARCHIVE_READDISK_MAC_COPYFILE;
a->open_on_current_dir = open_on_current_dir;
a->tree_current_dir_fd = tree_current_dir_fd;
a->tree_enter_working_dir = tree_enter_working_dir;
@@ -491,6 +494,7 @@ _archive_read_free(struct archive *_a)
if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL)
(a->cleanup_uname)(a->lookup_uname_data);
archive_string_free(&a->archive.error_string);
+ archive_entry_free(a->entry);
a->archive.magic = 0;
__archive_clean(&a->archive);
free(a);
@@ -558,25 +562,19 @@ archive_read_disk_set_symlink_hybrid(struct archive *_a)
int
archive_read_disk_set_atime_restored(struct archive *_a)
{
-#ifndef HAVE_UTIMES
- static int warning_done = 0;
-#endif
struct archive_read_disk *a = (struct archive_read_disk *)_a;
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
ARCHIVE_STATE_ANY, "archive_read_disk_restore_atime");
#ifdef HAVE_UTIMES
- a->restore_time = 1;
+ a->flags |= ARCHIVE_READDISK_RESTORE_ATIME;
if (a->tree != NULL)
a->tree->flags |= needsRestoreTimes;
return (ARCHIVE_OK);
#else
- if (warning_done)
- /* Warning was already emitted; suppress further warnings. */
- return (ARCHIVE_OK);
-
+ /* Display warning and unset flag */
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Cannot restore access time on this system");
- warning_done = 1;
+ a->flags &= ~ARCHIVE_READDISK_RESTORE_ATIME;
return (ARCHIVE_WARN);
#endif
}
@@ -590,25 +588,14 @@ archive_read_disk_set_behavior(struct archive *_a, int flags)
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
ARCHIVE_STATE_ANY, "archive_read_disk_honor_nodump");
+ a->flags = flags;
+
if (flags & ARCHIVE_READDISK_RESTORE_ATIME)
r = archive_read_disk_set_atime_restored(_a);
else {
- a->restore_time = 0;
if (a->tree != NULL)
a->tree->flags &= ~needsRestoreTimes;
}
- if (flags & ARCHIVE_READDISK_HONOR_NODUMP)
- a->honor_nodump = 1;
- else
- a->honor_nodump = 0;
- if (flags & ARCHIVE_READDISK_MAC_COPYFILE)
- a->enable_copyfile = 1;
- else
- a->enable_copyfile = 0;
- if (flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS)
- a->traverse_mount_points = 0;
- else
- a->traverse_mount_points = 1;
return (r);
}
@@ -666,7 +653,7 @@ setup_suitable_read_buffer(struct archive_read_disk *a)
asize = cf->min_xfer_size;
/* Increase a buffer size up to 64K bytes in
- * a proper incremant size. */
+ * a proper increment size. */
while (asize < 1024*64)
asize += incr;
/* Take a margin to adjust to the filesystem
@@ -708,6 +695,7 @@ _archive_read_data_block(struct archive *_a, const void **buff,
int r;
ssize_t bytes;
size_t buffbytes;
+ int empty_sparse_region = 0;
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,
"archive_read_data_block");
@@ -789,6 +777,9 @@ _archive_read_data_block(struct archive *_a, const void **buff,
if ((int64_t)buffbytes > t->current_sparse->length)
buffbytes = t->current_sparse->length;
+ if (t->current_sparse->length == 0)
+ empty_sparse_region = 1;
+
/*
* Skip hole.
* TODO: Should we consider t->current_filesystem->xfer_align?
@@ -819,7 +810,11 @@ _archive_read_data_block(struct archive *_a, const void **buff,
}
} else
bytes = 0;
- if (bytes == 0) {
+ /*
+ * Return an EOF unless we've read a leading empty sparse region, which
+ * is used to represent fully-sparse files.
+ */
+ if (bytes == 0 && !empty_sparse_region) {
/* Get EOF */
t->entry_eof = 1;
r = ARCHIVE_EOF;
@@ -901,7 +896,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
} while (lst == NULL);
#ifdef __APPLE__
- if (a->enable_copyfile) {
+ if (a->flags & ARCHIVE_READDISK_MAC_COPYFILE) {
/* If we're using copyfile(), ignore "._XXX" files. */
const char *bname = strrchr(tree_current_path(t), '/');
if (bname == NULL)
@@ -921,7 +916,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
r = archive_match_path_excluded(a->matching, entry);
if (r < 0) {
archive_set_error(&(a->archive), errno,
- "Faild : %s", archive_error_string(a->matching));
+ "Failed : %s", archive_error_string(a->matching));
return (r);
}
if (r) {
@@ -972,9 +967,9 @@ next_entry(struct archive_read_disk *a, struct tree *t,
}
if (t->initial_filesystem_id == -1)
t->initial_filesystem_id = t->current_filesystem_id;
- if (!a->traverse_mount_points) {
+ if (a->flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS) {
if (t->initial_filesystem_id != t->current_filesystem_id)
- return (ARCHIVE_RETRY);
+ descend = 0;
}
t->descend = descend;
@@ -982,12 +977,14 @@ next_entry(struct archive_read_disk *a, struct tree *t,
* Honor nodump flag.
* If the file is marked with nodump flag, do not return this entry.
*/
- if (a->honor_nodump) {
+ if (a->flags & ARCHIVE_READDISK_HONOR_NODUMP) {
#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
if (st->st_flags & UF_NODUMP)
return (ARCHIVE_RETRY);
-#elif defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) &&\
- defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)
+#elif (defined(FS_IOC_GETFLAGS) && defined(FS_NODUMP_FL) && \
+ defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \
+ (defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) && \
+ defined(HAVE_WORKING_EXT2_IOC_GETFLAGS))
if (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode)) {
int stflags;
@@ -996,9 +993,18 @@ next_entry(struct archive_read_disk *a, struct tree *t,
O_RDONLY | O_NONBLOCK | O_CLOEXEC);
__archive_ensure_cloexec_flag(t->entry_fd);
if (t->entry_fd >= 0) {
- r = ioctl(t->entry_fd, EXT2_IOC_GETFLAGS,
+ r = ioctl(t->entry_fd,
+#ifdef FS_IOC_GETFLAGS
+ FS_IOC_GETFLAGS,
+#else
+ EXT2_IOC_GETFLAGS,
+#endif
&stflags);
+#ifdef FS_NODUMP_FL
+ if (r == 0 && (stflags & FS_NODUMP_FL) != 0)
+#else
if (r == 0 && (stflags & EXT2_NODUMP_FL) != 0)
+#endif
return (ARCHIVE_RETRY);
}
}
@@ -1009,7 +1015,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
/* Save the times to be restored. This must be in before
* calling archive_read_disk_descend() or any chance of it,
- * especially, invokng a callback. */
+ * especially, invoking a callback. */
t->restore_time.mtime = archive_entry_mtime(entry);
t->restore_time.mtime_nsec = archive_entry_mtime_nsec(entry);
t->restore_time.atime = archive_entry_atime(entry);
@@ -1024,7 +1030,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
r = archive_match_time_excluded(a->matching, entry);
if (r < 0) {
archive_set_error(&(a->archive), errno,
- "Faild : %s", archive_error_string(a->matching));
+ "Failed : %s", archive_error_string(a->matching));
return (r);
}
if (r) {
@@ -1050,7 +1056,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
r = archive_match_owner_excluded(a->matching, entry);
if (r < 0) {
archive_set_error(&(a->archive), errno,
- "Faild : %s", archive_error_string(a->matching));
+ "Failed : %s", archive_error_string(a->matching));
return (r);
}
if (r) {
@@ -1081,6 +1087,17 @@ next_entry(struct archive_read_disk *a, struct tree *t,
}
static int
+_archive_read_next_header(struct archive *_a, struct archive_entry **entryp)
+{
+ int ret;
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ *entryp = NULL;
+ ret = _archive_read_next_header2(_a, a->entry);
+ *entryp = a->entry;
+ return ret;
+}
+
+static int
_archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
{
struct archive_read_disk *a = (struct archive_read_disk *)_a;
@@ -1148,6 +1165,7 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
break;
}
+ __archive_reset_read_data(&a->archive);
return (r);
}
@@ -1311,10 +1329,11 @@ _archive_read_disk_open(struct archive *_a, const char *pathname)
struct archive_read_disk *a = (struct archive_read_disk *)_a;
if (a->tree != NULL)
- a->tree = tree_reopen(a->tree, pathname, a->restore_time);
+ a->tree = tree_reopen(a->tree, pathname,
+ a->flags & ARCHIVE_READDISK_RESTORE_ATIME);
else
a->tree = tree_open(pathname, a->symlink_mode,
- a->restore_time);
+ a->flags & ARCHIVE_READDISK_RESTORE_ATIME);
if (a->tree == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate tar data");
@@ -1353,7 +1372,7 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
for (i = 0; i < t->max_filesystem_id; i++) {
if (t->filesystem_table[i].dev == dev) {
- /* There is the filesytem ID we've already generated. */
+ /* There is the filesystem ID we've already generated. */
t->current_filesystem_id = i;
t->current_filesystem = &(t->filesystem_table[i]);
return (ARCHIVE_OK);
@@ -1361,10 +1380,10 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
}
/*
- * This is the new filesytem which we have to generate a new ID for.
+ * This is the new filesystem which we have to generate a new ID for.
*/
fid = t->max_filesystem_id++;
- if (t->max_filesystem_id > t->allocated_filesytem) {
+ if (t->max_filesystem_id > t->allocated_filesystem) {
size_t s;
void *p;
@@ -1377,7 +1396,7 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
return (ARCHIVE_FATAL);
}
t->filesystem_table = (struct filesystem *)p;
- t->allocated_filesytem = s;
+ t->allocated_filesystem = s;
}
t->current_filesystem_id = fid;
t->current_filesystem = &(t->filesystem_table[fid]);
@@ -1475,7 +1494,20 @@ setup_current_filesystem(struct archive_read_disk *a)
struct tree *t = a->tree;
struct statfs sfs;
#if defined(HAVE_GETVFSBYNAME) && defined(VFCF_SYNTHETIC)
+/* TODO: configure should set GETVFSBYNAME_ARG_TYPE to make
+ * this accurate; some platforms have both and we need the one that's
+ * used by getvfsbyname()
+ *
+ * Then the following would become:
+ * #if defined(GETVFSBYNAME_ARG_TYPE)
+ * GETVFSBYNAME_ARG_TYPE vfc;
+ * #endif
+ */
+# if defined(HAVE_STRUCT_XVFSCONF)
struct xvfsconf vfc;
+# else
+ struct vfsconf vfc;
+# endif
#endif
int r, xr = 0;
#if !defined(HAVE_STRUCT_STATFS_F_NAMEMAX)
@@ -1550,11 +1582,12 @@ setup_current_filesystem(struct archive_read_disk *a)
#endif
t->current_filesystem->noatime = 0;
-#if defined(HAVE_READDIR_R)
+#if defined(USE_READDIR_R)
/* Set maximum filename length. */
#if defined(HAVE_STRUCT_STATFS_F_NAMEMAX)
t->current_filesystem->name_max = sfs.f_namemax;
#else
+# if defined(_PC_NAME_MAX)
/* Mac OS X does not have f_namemax in struct statfs. */
if (tree_current_is_symblic_link_target(t)) {
if (tree_enter_working_dir(t) != 0) {
@@ -1564,12 +1597,15 @@ setup_current_filesystem(struct archive_read_disk *a)
nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX);
} else
nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX);
+# else
+ nm = -1;
+# endif
if (nm == -1)
t->current_filesystem->name_max = NAME_MAX;
else
t->current_filesystem->name_max = nm;
#endif
-#endif /* HAVE_READDIR_R */
+#endif /* USE_READDIR_R */
return (ARCHIVE_OK);
}
@@ -1610,7 +1646,7 @@ setup_current_filesystem(struct archive_read_disk *a)
archive_set_error(&a->archive, errno, "statvfs failed");
return (ARCHIVE_FAILED);
} else if (xr == 1) {
- /* Usuall come here unless NetBSD supports _PC_REC_XFER_ALIGN
+ /* Usually come here unless NetBSD supports _PC_REC_XFER_ALIGN
* for pathconf() function. */
t->current_filesystem->xfer_align = sfs.f_frsize;
t->current_filesystem->max_xfer_size = -1;
@@ -1660,7 +1696,9 @@ setup_current_filesystem(struct archive_read_disk *a)
{
struct tree *t = a->tree;
struct statfs sfs;
+#if defined(HAVE_STATVFS)
struct statvfs svfs;
+#endif
int r, vr = 0, xr = 0;
if (tree_current_is_symblic_link_target(t)) {
@@ -1677,7 +1715,9 @@ setup_current_filesystem(struct archive_read_disk *a)
"openat failed");
return (ARCHIVE_FAILED);
}
+#if defined(HAVE_FSTATVFS)
vr = fstatvfs(fd, &svfs);/* for f_flag, mount flags */
+#endif
r = fstatfs(fd, &sfs);
if (r == 0)
xr = get_xfer_size(t, fd, NULL);
@@ -1687,14 +1727,18 @@ setup_current_filesystem(struct archive_read_disk *a)
archive_set_error(&a->archive, errno, "fchdir failed");
return (ARCHIVE_FAILED);
}
+#if defined(HAVE_STATVFS)
vr = statvfs(tree_current_access_path(t), &svfs);
+#endif
r = statfs(tree_current_access_path(t), &sfs);
if (r == 0)
xr = get_xfer_size(t, -1, tree_current_access_path(t));
#endif
} else {
#ifdef HAVE_FSTATFS
+#if defined(HAVE_FSTATVFS)
vr = fstatvfs(tree_current_dir_fd(t), &svfs);
+#endif
r = fstatfs(tree_current_dir_fd(t), &sfs);
if (r == 0)
xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);
@@ -1703,7 +1747,9 @@ setup_current_filesystem(struct archive_read_disk *a)
archive_set_error(&a->archive, errno, "fchdir failed");
return (ARCHIVE_FAILED);
}
+#if defined(HAVE_STATVFS)
vr = statvfs(".", &svfs);
+#endif
r = statfs(".", &sfs);
if (r == 0)
xr = get_xfer_size(t, -1, ".");
@@ -1716,10 +1762,17 @@ setup_current_filesystem(struct archive_read_disk *a)
return (ARCHIVE_FAILED);
} else if (xr == 1) {
/* pathconf(_PC_REX_*) operations are not supported. */
+#if defined(HAVE_STATVFS)
t->current_filesystem->xfer_align = svfs.f_frsize;
t->current_filesystem->max_xfer_size = -1;
t->current_filesystem->min_xfer_size = svfs.f_bsize;
t->current_filesystem->incr_xfer_size = svfs.f_bsize;
+#else
+ t->current_filesystem->xfer_align = sfs.f_frsize;
+ t->current_filesystem->max_xfer_size = -1;
+ t->current_filesystem->min_xfer_size = sfs.f_bsize;
+ t->current_filesystem->incr_xfer_size = sfs.f_bsize;
+#endif
}
switch (sfs.f_type) {
case AFS_SUPER_MAGIC:
@@ -1744,13 +1797,17 @@ setup_current_filesystem(struct archive_read_disk *a)
}
#if defined(ST_NOATIME)
+#if defined(HAVE_STATVFS)
if (svfs.f_flag & ST_NOATIME)
+#else
+ if (sfs.f_flag & ST_NOATIME)
+#endif
t->current_filesystem->noatime = 1;
else
#endif
t->current_filesystem->noatime = 0;
-#if defined(HAVE_READDIR_R)
+#if defined(USE_READDIR_R)
/* Set maximum filename length. */
t->current_filesystem->name_max = sfs.f_namelen;
#endif
@@ -1834,7 +1891,7 @@ setup_current_filesystem(struct archive_read_disk *a)
#endif
t->current_filesystem->noatime = 0;
-#if defined(HAVE_READDIR_R)
+#if defined(USE_READDIR_R)
/* Set maximum filename length. */
t->current_filesystem->name_max = sfs.f_namemax;
#endif
@@ -1851,7 +1908,7 @@ static int
setup_current_filesystem(struct archive_read_disk *a)
{
struct tree *t = a->tree;
-#if defined(_PC_NAME_MAX) && defined(HAVE_READDIR_R)
+#if defined(_PC_NAME_MAX) && defined(USE_READDIR_R)
long nm;
#endif
t->current_filesystem->synthetic = -1;/* Not supported */
@@ -1863,7 +1920,7 @@ setup_current_filesystem(struct archive_read_disk *a)
t->current_filesystem->min_xfer_size = -1;
t->current_filesystem->incr_xfer_size = -1;
-#if defined(HAVE_READDIR_R)
+#if defined(USE_READDIR_R)
/* Set maximum filename length. */
# if defined(_PC_NAME_MAX)
if (tree_current_is_symblic_link_target(t)) {
@@ -1877,7 +1934,7 @@ setup_current_filesystem(struct archive_read_disk *a)
if (nm == -1)
# endif /* _PC_NAME_MAX */
/*
- * Some sysmtes (HP-UX or others?) incorrectly defined
+ * Some systems (HP-UX or others?) incorrectly defined
* NAME_MAX macro to be a smaller value.
*/
# if defined(NAME_MAX) && NAME_MAX >= 255
@@ -1891,7 +1948,7 @@ setup_current_filesystem(struct archive_read_disk *a)
else
t->current_filesystem->name_max = nm;
# endif /* _PC_NAME_MAX */
-#endif /* HAVE_READDIR_R */
+#endif /* USE_READDIR_R */
return (ARCHIVE_OK);
}
@@ -1973,7 +2030,7 @@ tree_dup(int fd)
static volatile int can_dupfd_cloexec = 1;
if (can_dupfd_cloexec) {
- new_fd = fcntl(fd, F_DUPFD_CLOEXEC);
+ new_fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
if (new_fd != -1)
return (new_fd);
/* Linux 2.6.18 - 2.6.23 declare F_DUPFD_CLOEXEC,
@@ -1996,8 +2053,7 @@ tree_push(struct tree *t, const char *path, int filesystem_id,
{
struct tree_entry *te;
- te = malloc(sizeof(*te));
- memset(te, 0, sizeof(*te));
+ te = calloc(1, sizeof(*te));
te->next = t->stack;
te->parent = t->current;
if (te->parent)
@@ -2055,9 +2111,8 @@ tree_open(const char *path, int symlink_mode, int restore_time)
{
struct tree *t;
- if ((t = malloc(sizeof(*t))) == NULL)
+ if ((t = calloc(1, sizeof(*t))) == NULL)
return (NULL);
- memset(t, 0, sizeof(*t));
archive_string_init(&t->path);
archive_string_ensure(&t->path, 31);
t->initial_symlink_mode = symlink_mode;
@@ -2067,7 +2122,7 @@ tree_open(const char *path, int symlink_mode, int restore_time)
static struct tree *
tree_reopen(struct tree *t, const char *path, int restore_time)
{
- t->flags = (restore_time)?needsRestoreTimes:0;
+ t->flags = (restore_time != 0)?needsRestoreTimes:0;
t->flags |= onInitialDir;
t->visit_type = 0;
t->tree_errno = 0;
@@ -2299,7 +2354,7 @@ tree_dir_next_posix(struct tree *t)
size_t namelen;
if (t->d == NULL) {
-#if defined(HAVE_READDIR_R)
+#if defined(USE_READDIR_R)
size_t dirent_size;
#endif
@@ -2320,7 +2375,7 @@ tree_dir_next_posix(struct tree *t)
t->visit_type = r != 0 ? r : TREE_ERROR_DIR;
return (t->visit_type);
}
-#if defined(HAVE_READDIR_R)
+#if defined(USE_READDIR_R)
dirent_size = offsetof(struct dirent, d_name) +
t->filesystem_table[t->current->filesystem_id].name_max + 1;
if (t->dirent == NULL || t->dirent_allocated < dirent_size) {
@@ -2337,11 +2392,11 @@ tree_dir_next_posix(struct tree *t)
}
t->dirent_allocated = dirent_size;
}
-#endif /* HAVE_READDIR_R */
+#endif /* USE_READDIR_R */
}
for (;;) {
errno = 0;
-#if defined(HAVE_READDIR_R)
+#if defined(USE_READDIR_R)
r = readdir_r(t->d, t->dirent, &t->de);
#ifdef _AIX
/* Note: According to the man page, return value 9 indicates
@@ -2593,7 +2648,7 @@ tree_free(struct tree *t)
if (t == NULL)
return;
archive_string_free(&t->path);
-#if defined(HAVE_READDIR_R)
+#if defined(USE_READDIR_R)
free(t->dirent);
#endif
free(t->sparse_list);
diff --git a/3rdparty/libarchive/libarchive/archive_read_disk_private.h b/3rdparty/libarchive/libarchive/archive_read_disk_private.h
index e5af16b9..f03a0a9c 100644
--- a/3rdparty/libarchive/libarchive/archive_read_disk_private.h
+++ b/3rdparty/libarchive/libarchive/archive_read_disk_private.h
@@ -33,12 +33,17 @@
#ifndef ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED
#define ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED
+#include "archive_platform_acl.h"
+
struct tree;
struct archive_entry;
struct archive_read_disk {
struct archive archive;
+ /* Reused by archive_read_next_header() */
+ struct archive_entry *entry;
+
/*
* Symlink mode is one of 'L'ogical, 'P'hysical, or 'H'ybrid,
* following an old BSD convention. 'L' follows all symlinks,
@@ -60,14 +65,8 @@ struct archive_read_disk {
int (*tree_current_dir_fd)(struct tree*);
int (*tree_enter_working_dir)(struct tree*);
- /* Set 1 if users request to restore atime . */
- int restore_time;
- /* Set 1 if users request to honor nodump flag . */
- int honor_nodump;
- /* Set 1 if users request to enable mac copyfile. */
- int enable_copyfile;
- /* Set 1 if users request to traverse mount points. */
- int traverse_mount_points;
+ /* Bitfield with ARCHIVE_READDISK_* tunables */
+ int flags;
const char * (*lookup_gname)(void *private, int64_t gid);
void (*cleanup_gname)(void *private);
@@ -89,4 +88,11 @@ struct archive_read_disk {
void *excluded_cb_data;
};
+const char *
+archive_read_disk_entry_setup_path(struct archive_read_disk *,
+ struct archive_entry *, int *);
+
+int
+archive_read_disk_entry_setup_acls(struct archive_read_disk *,
+ struct archive_entry *, int *);
#endif
diff --git a/3rdparty/libarchive/libarchive/archive_read_disk_set_standard_lookup.c b/3rdparty/libarchive/libarchive/archive_read_disk_set_standard_lookup.c
index 3bc52c70..c7fd2471 100644
--- a/3rdparty/libarchive/libarchive/archive_read_disk_set_standard_lookup.c
+++ b/3rdparty/libarchive/libarchive/archive_read_disk_set_standard_lookup.c
@@ -83,7 +83,7 @@ static const char * lookup_uname_helper(struct name_cache *, id_t uid);
* a simple cache to accelerate such lookups---into the archive_read_disk
* object. This is in a separate file because getpwuid()/getgrgid()
* can pull in a LOT of library code (including NIS/LDAP functions, which
- * pull in DNS resolveers, etc). This can easily top 500kB, which makes
+ * pull in DNS resolvers, etc). This can easily top 500kB, which makes
* it inappropriate for some space-constrained applications.
*
* Applications that are size-sensitive may want to just use the
@@ -232,6 +232,7 @@ static const char *
lookup_uname_helper(struct name_cache *cache, id_t id)
{
struct passwd *result;
+ (void)cache; /* UNUSED */
result = getpwuid((uid_t)id);
@@ -298,6 +299,7 @@ static const char *
lookup_gname_helper(struct name_cache *cache, id_t id)
{
struct group *result;
+ (void)cache; /* UNUSED */
result = getgrgid((gid_t)id);
diff --git a/3rdparty/libarchive/libarchive/archive_read_disk_windows.c b/3rdparty/libarchive/libarchive/archive_read_disk_windows.c
index 9c5420d8..3b903304 100644
--- a/3rdparty/libarchive/libarchive/archive_read_disk_windows.c
+++ b/3rdparty/libarchive/libarchive/archive_read_disk_windows.c
@@ -168,7 +168,7 @@ struct tree {
int initial_filesystem_id;
int current_filesystem_id;
int max_filesystem_id;
- int allocated_filesytem;
+ int allocated_filesystem;
HANDLE entry_fh;
int entry_eof;
@@ -288,6 +288,8 @@ static int _archive_read_free(struct archive *);
static int _archive_read_close(struct archive *);
static int _archive_read_data_block(struct archive *,
const void **, size_t *, int64_t *);
+static int _archive_read_next_header(struct archive *,
+ struct archive_entry **);
static int _archive_read_next_header2(struct archive *,
struct archive_entry *);
static const char *trivial_lookup_gname(void *, int64_t gid);
@@ -310,6 +312,7 @@ archive_read_disk_vtable(void)
av.archive_free = _archive_read_free;
av.archive_close = _archive_read_close;
av.archive_read_data_block = _archive_read_data_block;
+ av.archive_read_next_header = _archive_read_next_header;
av.archive_read_next_header2 = _archive_read_next_header2;
inited = 1;
}
@@ -386,17 +389,16 @@ archive_read_disk_new(void)
{
struct archive_read_disk *a;
- a = (struct archive_read_disk *)malloc(sizeof(*a));
+ a = (struct archive_read_disk *)calloc(1, sizeof(*a));
if (a == NULL)
return (NULL);
- memset(a, 0, sizeof(*a));
a->archive.magic = ARCHIVE_READ_DISK_MAGIC;
a->archive.state = ARCHIVE_STATE_NEW;
a->archive.vtable = archive_read_disk_vtable();
+ a->entry = archive_entry_new2(&a->archive);
a->lookup_uname = trivial_lookup_uname;
a->lookup_gname = trivial_lookup_gname;
- a->enable_copyfile = 1;
- a->traverse_mount_points = 1;
+ a->flags = ARCHIVE_READDISK_MAC_COPYFILE;
return (&a->archive);
}
@@ -422,6 +424,7 @@ _archive_read_free(struct archive *_a)
if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL)
(a->cleanup_uname)(a->lookup_uname_data);
archive_string_free(&a->archive.error_string);
+ archive_entry_free(a->entry);
a->archive.magic = 0;
free(a);
return (r);
@@ -491,7 +494,7 @@ archive_read_disk_set_atime_restored(struct archive *_a)
struct archive_read_disk *a = (struct archive_read_disk *)_a;
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
ARCHIVE_STATE_ANY, "archive_read_disk_restore_atime");
- a->restore_time = 1;
+ a->flags |= ARCHIVE_READDISK_RESTORE_ATIME;
if (a->tree != NULL)
a->tree->flags |= needsRestoreTimes;
return (ARCHIVE_OK);
@@ -506,25 +509,14 @@ archive_read_disk_set_behavior(struct archive *_a, int flags)
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
ARCHIVE_STATE_ANY, "archive_read_disk_honor_nodump");
+ a->flags = flags;
+
if (flags & ARCHIVE_READDISK_RESTORE_ATIME)
r = archive_read_disk_set_atime_restored(_a);
else {
- a->restore_time = 0;
if (a->tree != NULL)
a->tree->flags &= ~needsRestoreTimes;
}
- if (flags & ARCHIVE_READDISK_HONOR_NODUMP)
- a->honor_nodump = 1;
- else
- a->honor_nodump = 0;
- if (flags & ARCHIVE_READDISK_MAC_COPYFILE)
- a->enable_copyfile = 1;
- else
- a->enable_copyfile = 0;
- if (flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS)
- a->traverse_mount_points = 0;
- else
- a->traverse_mount_points = 1;
return (r);
}
@@ -798,7 +790,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
r = archive_match_path_excluded(a->matching, entry);
if (r < 0) {
archive_set_error(&(a->archive), errno,
- "Faild : %s", archive_error_string(a->matching));
+ "Failed : %s", archive_error_string(a->matching));
return (r);
}
if (r) {
@@ -848,7 +840,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
}
if (t->initial_filesystem_id == -1)
t->initial_filesystem_id = t->current_filesystem_id;
- if (!a->traverse_mount_points) {
+ if (a->flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS) {
if (t->initial_filesystem_id != t->current_filesystem_id)
return (ARCHIVE_RETRY);
}
@@ -858,7 +850,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
/* Save the times to be restored. This must be in before
* calling archive_read_disk_descend() or any chance of it,
- * especially, invokng a callback. */
+ * especially, invoking a callback. */
t->restore_time.lastWriteTime = st->ftLastWriteTime;
t->restore_time.lastAccessTime = st->ftLastAccessTime;
t->restore_time.filetype = archive_entry_filetype(entry);
@@ -870,7 +862,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
r = archive_match_time_excluded(a->matching, entry);
if (r < 0) {
archive_set_error(&(a->archive), errno,
- "Faild : %s", archive_error_string(a->matching));
+ "Failed : %s", archive_error_string(a->matching));
return (r);
}
if (r) {
@@ -896,7 +888,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
r = archive_match_owner_excluded(a->matching, entry);
if (r < 0) {
archive_set_error(&(a->archive), errno,
- "Faild : %s", archive_error_string(a->matching));
+ "Failed : %s", archive_error_string(a->matching));
return (r);
}
if (r) {
@@ -929,7 +921,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
else
flags |= FILE_FLAG_SEQUENTIAL_SCAN;
t->entry_fh = CreateFileW(tree_current_access_path(t),
- GENERIC_READ, 0, NULL, OPEN_EXISTING, flags, NULL);
+ GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, flags, NULL);
if (t->entry_fh == INVALID_HANDLE_VALUE) {
archive_set_error(&a->archive, errno,
"Couldn't open %ls", tree_current_path(a->tree));
@@ -945,6 +937,17 @@ next_entry(struct archive_read_disk *a, struct tree *t,
}
static int
+_archive_read_next_header(struct archive *_a, struct archive_entry **entryp)
+{
+ int ret;
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ *entryp = NULL;
+ ret = _archive_read_next_header2(_a, a->entry);
+ *entryp = a->entry;
+ return ret;
+}
+
+static int
_archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
{
struct archive_read_disk *a = (struct archive_read_disk *)_a;
@@ -1000,6 +1003,7 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
break;
}
+ __archive_reset_read_data(&a->archive);
return (r);
}
@@ -1203,9 +1207,11 @@ _archive_read_disk_open_w(struct archive *_a, const wchar_t *pathname)
struct archive_read_disk *a = (struct archive_read_disk *)_a;
if (a->tree != NULL)
- a->tree = tree_reopen(a->tree, pathname, a->restore_time);
+ a->tree = tree_reopen(a->tree, pathname,
+ a->flags & ARCHIVE_READDISK_RESTORE_ATIME);
else
- a->tree = tree_open(pathname, a->symlink_mode, a->restore_time);
+ a->tree = tree_open(pathname, a->symlink_mode,
+ a->flags & ARCHIVE_READDISK_RESTORE_ATIME);
if (a->tree == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate directory traversal data");
@@ -1244,7 +1250,7 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
for (i = 0; i < t->max_filesystem_id; i++) {
if (t->filesystem_table[i].dev == dev) {
- /* There is the filesytem ID we've already generated. */
+ /* There is the filesystem ID we've already generated. */
t->current_filesystem_id = i;
t->current_filesystem = &(t->filesystem_table[i]);
return (ARCHIVE_OK);
@@ -1252,10 +1258,10 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
}
/*
- * There is a new filesytem, we generate a new ID for.
+ * There is a new filesystem, we generate a new ID for.
*/
fid = t->max_filesystem_id++;
- if (t->max_filesystem_id > t->allocated_filesytem) {
+ if (t->max_filesystem_id > t->allocated_filesystem) {
size_t s;
void *p;
@@ -1268,7 +1274,7 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
return (ARCHIVE_FATAL);
}
t->filesystem_table = (struct filesystem *)p;
- t->allocated_filesytem = (int)s;
+ t->allocated_filesystem = (int)s;
}
t->current_filesystem_id = fid;
t->current_filesystem = &(t->filesystem_table[fid]);
@@ -1385,7 +1391,7 @@ close_and_restore_time(HANDLE h, struct tree *t, struct restore_time *rt)
if (h == INVALID_HANDLE_VALUE && AE_IFLNK == rt->filetype)
return (0);
- /* Close a file descritor.
+ /* Close a file descriptor.
* It will not be used for SetFileTime() because it has been opened
* by a read only mode.
*/
@@ -1420,8 +1426,7 @@ tree_push(struct tree *t, const wchar_t *path, const wchar_t *full_path,
{
struct tree_entry *te;
- te = malloc(sizeof(*te));
- memset(te, 0, sizeof(*te));
+ te = calloc(1, sizeof(*te));
te->next = t->stack;
te->parent = t->current;
if (te->parent)
@@ -1490,8 +1495,7 @@ tree_open(const wchar_t *path, int symlink_mode, int restore_time)
{
struct tree *t;
- t = malloc(sizeof(*t));
- memset(t, 0, sizeof(*t));
+ t = calloc(1, sizeof(*t));
archive_string_init(&(t->full_path));
archive_string_init(&t->path);
archive_wstring_ensure(&t->path, 15);
@@ -1505,7 +1509,7 @@ tree_reopen(struct tree *t, const wchar_t *path, int restore_time)
struct archive_wstring ws;
wchar_t *pathname, *p, *base;
- t->flags = (restore_time)?needsRestoreTimes:0;
+ t->flags = (restore_time != 0)?needsRestoreTimes:0;
t->visit_type = 0;
t->tree_errno = 0;
t->full_path_dir_length = 0;
@@ -1569,7 +1573,7 @@ tree_reopen(struct tree *t, const wchar_t *path, int restore_time)
t->stack->flags = needsFirstVisit;
/*
* Debug flag for Direct IO(No buffering) or Async IO.
- * Those dependant on environment variable switches
+ * Those dependent on environment variable switches
* will be removed until next release.
*/
{
@@ -1851,8 +1855,6 @@ entry_copy_bhfi(struct archive_entry *entry, const wchar_t *path,
break;
case L'C': case L'c':
if (((p[2] == L'M' || p[2] == L'm' ) &&
- (p[3] == L'D' || p[3] == L'd' )) ||
- ((p[2] == L'M' || p[2] == L'm' ) &&
(p[3] == L'D' || p[3] == L'd' )))
mode |= S_IXUSR | S_IXGRP | S_IXOTH;
break;
@@ -1886,7 +1888,7 @@ tree_current_file_information(struct tree *t, BY_HANDLE_FILE_INFORMATION *st,
if (sim_lstat && tree_current_is_physical_link(t))
flag |= FILE_FLAG_OPEN_REPARSE_POINT;
- h = CreateFileW(tree_current_access_path(t), 0, 0, NULL,
+ h = CreateFileW(tree_current_access_path(t), 0, FILE_SHARE_READ, NULL,
OPEN_EXISTING, flag, NULL);
if (h == INVALID_HANDLE_VALUE) {
la_dosmaperr(GetLastError());
@@ -2115,7 +2117,7 @@ archive_read_disk_entry_from_file(struct archive *_a,
} else
desiredAccess = GENERIC_READ;
- h = CreateFileW(path, desiredAccess, 0, NULL,
+ h = CreateFileW(path, desiredAccess, FILE_SHARE_READ, NULL,
OPEN_EXISTING, flag, NULL);
if (h == INVALID_HANDLE_VALUE) {
la_dosmaperr(GetLastError());
@@ -2162,7 +2164,7 @@ archive_read_disk_entry_from_file(struct archive *_a,
if (fd >= 0) {
h = (HANDLE)_get_osfhandle(fd);
} else {
- h = CreateFileW(path, GENERIC_READ, 0, NULL,
+ h = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (h == INVALID_HANDLE_VALUE) {
la_dosmaperr(GetLastError());
diff --git a/3rdparty/libarchive/libarchive/archive_read_extract.c b/3rdparty/libarchive/libarchive/archive_read_extract.c
index 795f2abe..b7973fa8 100644
--- a/3rdparty/libarchive/libarchive/archive_read_extract.c
+++ b/3rdparty/libarchive/libarchive/archive_read_extract.c
@@ -26,158 +26,35 @@
#include "archive_platform.h"
__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_extract.c,v 1.61 2008/05/26 17:00:22 kientzle Exp $");
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
#include "archive_read_private.h"
-#include "archive_write_disk_private.h"
-
-struct extract {
- struct archive *ad; /* archive_write_disk object */
-
- /* Progress function invoked during extract. */
- void (*extract_progress)(void *);
- void *extract_progress_user_data;
-};
-
-static int archive_read_extract_cleanup(struct archive_read *);
-static int copy_data(struct archive *ar, struct archive *aw);
-static struct extract *get_extract(struct archive_read *);
-
-static struct extract *
-get_extract(struct archive_read *a)
-{
- /* If we haven't initialized, do it now. */
- /* This also sets up a lot of global state. */
- if (a->extract == NULL) {
- a->extract = (struct extract *)malloc(sizeof(*a->extract));
- if (a->extract == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Can't extract");
- return (NULL);
- }
- memset(a->extract, 0, sizeof(*a->extract));
- a->extract->ad = archive_write_disk_new();
- if (a->extract->ad == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Can't extract");
- return (NULL);
- }
- archive_write_disk_set_standard_lookup(a->extract->ad);
- a->cleanup_archive_extract = archive_read_extract_cleanup;
- }
- return (a->extract);
-}
int
archive_read_extract(struct archive *_a, struct archive_entry *entry, int flags)
{
- struct extract *extract;
+ struct archive_read_extract *extract;
+ struct archive_read * a = (struct archive_read *)_a;
- extract = get_extract((struct archive_read *)_a);
+ extract = __archive_read_get_extract(a);
if (extract == NULL)
return (ARCHIVE_FATAL);
- archive_write_disk_set_options(extract->ad, flags);
- return (archive_read_extract2(_a, entry, extract->ad));
-}
-int
-archive_read_extract2(struct archive *_a, struct archive_entry *entry,
- struct archive *ad)
-{
- struct archive_read *a = (struct archive_read *)_a;
- int r, r2;
-
- /* Set up for this particular entry. */
- if (a->skip_file_set)
- archive_write_disk_set_skip_file(ad,
- a->skip_file_dev, a->skip_file_ino);
- r = archive_write_header(ad, entry);
- if (r < ARCHIVE_WARN)
- r = ARCHIVE_WARN;
- if (r != ARCHIVE_OK)
- /* If _write_header failed, copy the error. */
- archive_copy_error(&a->archive, ad);
- else if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) > 0)
- /* Otherwise, pour data into the entry. */
- r = copy_data(_a, ad);
- r2 = archive_write_finish_entry(ad);
- if (r2 < ARCHIVE_WARN)
- r2 = ARCHIVE_WARN;
- /* Use the first message. */
- if (r2 != ARCHIVE_OK && r == ARCHIVE_OK)
- archive_copy_error(&a->archive, ad);
- /* Use the worst error return. */
- if (r2 < r)
- r = r2;
- return (r);
-}
-
-void
-archive_read_extract_set_progress_callback(struct archive *_a,
- void (*progress_func)(void *), void *user_data)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct extract *extract = get_extract(a);
- if (extract != NULL) {
- extract->extract_progress = progress_func;
- extract->extract_progress_user_data = user_data;
- }
-}
-
-static int
-copy_data(struct archive *ar, struct archive *aw)
-{
- int64_t offset;
- const void *buff;
- struct extract *extract;
- size_t size;
- int r;
-
- extract = get_extract((struct archive_read *)ar);
- if (extract == NULL)
- return (ARCHIVE_FATAL);
- for (;;) {
- r = archive_read_data_block(ar, &buff, &size, &offset);
- if (r == ARCHIVE_EOF)
- return (ARCHIVE_OK);
- if (r != ARCHIVE_OK)
- return (r);
- r = (int)archive_write_data_block(aw, buff, size, offset);
- if (r < ARCHIVE_WARN)
- r = ARCHIVE_WARN;
- if (r != ARCHIVE_OK) {
- archive_set_error(ar, archive_errno(aw),
- "%s", archive_error_string(aw));
- return (r);
+ /* If we haven't initialized the archive_write_disk object, do it now. */
+ if (extract->ad == NULL) {
+ extract->ad = archive_write_disk_new();
+ if (extract->ad == NULL) {
+ archive_set_error(&a->archive, ENOMEM, "Can't extract");
+ return (ARCHIVE_FATAL);
}
- if (extract->extract_progress)
- (extract->extract_progress)
- (extract->extract_progress_user_data);
+ archive_write_disk_set_standard_lookup(extract->ad);
}
-}
-/*
- * Cleanup function for archive_extract.
- */
-static int
-archive_read_extract_cleanup(struct archive_read *a)
-{
- int ret = ARCHIVE_OK;
-
- ret = archive_write_free(a->extract->ad);
- free(a->extract);
- a->extract = NULL;
- return (ret);
+ archive_write_disk_set_options(extract->ad, flags);
+ return (archive_read_extract2(&a->archive, entry, extract->ad));
}
diff --git a/3rdparty/libarchive/libarchive/archive_read_open_fd.c b/3rdparty/libarchive/libarchive/archive_read_open_fd.c
index e0f95bf4..f59cd07f 100644
--- a/3rdparty/libarchive/libarchive/archive_read_open_fd.c
+++ b/3rdparty/libarchive/libarchive/archive_read_open_fd.c
@@ -59,6 +59,7 @@ struct read_fd_data {
static int file_close(struct archive *, void *);
static ssize_t file_read(struct archive *, void *, const void **buff);
+static int64_t file_seek(struct archive *, void *, int64_t request, int);
static int64_t file_skip(struct archive *, void *, int64_t request);
int
@@ -102,6 +103,7 @@ archive_read_open_fd(struct archive *a, int fd, size_t block_size)
archive_read_set_read_callback(a, file_read);
archive_read_set_skip_callback(a, file_skip);
+ archive_read_set_seek_callback(a, file_seek);
archive_read_set_close_callback(a, file_close);
archive_read_set_callback_data(a, mine);
return (archive_read_open1(a));
@@ -170,6 +172,33 @@ file_skip(struct archive *a, void *client_data, int64_t request)
return (-1);
}
+/*
+ * TODO: Store the offset and use it in the read callback.
+ */
+static int64_t
+file_seek(struct archive *a, void *client_data, int64_t request, int whence)
+{
+ struct read_fd_data *mine = (struct read_fd_data *)client_data;
+ int64_t r;
+
+ /* We use off_t here because lseek() is declared that way. */
+ /* See above for notes about when off_t is less than 64 bits. */
+ r = lseek(mine->fd, request, whence);
+ if (r >= 0)
+ return r;
+
+ if (errno == ESPIPE) {
+ archive_set_error(a, errno,
+ "A file descriptor(%d) is not seekable(PIPE)", mine->fd);
+ return (ARCHIVE_FAILED);
+ } else {
+ /* If the input is corrupted or truncated, fail. */
+ archive_set_error(a, errno,
+ "Error seeking in a file descriptor(%d)", mine->fd);
+ return (ARCHIVE_FATAL);
+ }
+}
+
static int
file_close(struct archive *a, void *client_data)
{
diff --git a/3rdparty/libarchive/libarchive/archive_read_open_file.c b/3rdparty/libarchive/libarchive/archive_read_open_file.c
index 3a33c258..bfe933bf 100644
--- a/3rdparty/libarchive/libarchive/archive_read_open_file.c
+++ b/3rdparty/libarchive/libarchive/archive_read_open_file.c
@@ -83,8 +83,9 @@ archive_read_open_FILE(struct archive *a, FILE *f)
mine->f = f;
/*
* If we can't fstat() the file, it may just be that it's not
- * a file. (FILE * objects can wrap many kinds of I/O
- * streams, some of which don't support fileno()).)
+ * a file. (On some platforms, FILE * objects can wrap I/O
+ * streams that don't support fileno()). As a result, fileno()
+ * should be used cautiously.)
*/
if (fstat(fileno(mine->f), &st) == 0 && S_ISREG(st.st_mode)) {
archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
@@ -150,7 +151,10 @@ file_skip(struct archive *a, void *client_data, int64_t request)
skip = max_skip;
}
-#if HAVE_FSEEKO
+#ifdef __ANDROID__
+ /* fileno() isn't safe on all platforms ... see above. */
+ if (lseek(fileno(mine->f), skip, SEEK_CUR) < 0)
+#elif HAVE_FSEEKO
if (fseeko(mine->f, skip, SEEK_CUR) != 0)
#elif HAVE__FSEEKI64
if (_fseeki64(mine->f, skip, SEEK_CUR) != 0)
diff --git a/3rdparty/libarchive/libarchive/archive_read_open_filename.c b/3rdparty/libarchive/libarchive/archive_read_open_filename.c
index fefcd904..86635e21 100644
--- a/3rdparty/libarchive/libarchive/archive_read_open_filename.c
+++ b/3rdparty/libarchive/libarchive/archive_read_open_filename.c
@@ -103,7 +103,9 @@ int
archive_read_open_filename(struct archive *a, const char *filename,
size_t block_size)
{
- const char *filenames[2] = { filename, NULL };
+ const char *filenames[2];
+ filenames[0] = filename;
+ filenames[1] = NULL;
return archive_read_open_filenames(a, filenames, block_size);
}
@@ -176,7 +178,7 @@ archive_read_open_filename_w(struct archive *a, const wchar_t *wfilename,
#else
/*
* POSIX system does not support a wchar_t interface for
- * open() system call, so we have to translate a whcar_t
+ * open() system call, so we have to translate a wchar_t
* filename to multi-byte one and use it.
*/
struct archive_string fn;
@@ -220,7 +222,7 @@ file_open(struct archive *a, void *client_data)
void *buffer;
const char *filename = NULL;
const wchar_t *wfilename = NULL;
- int fd;
+ int fd = -1;
int is_disk_like = 0;
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
off_t mediasize = 0; /* FreeBSD-specific, so off_t okay here. */
@@ -275,7 +277,7 @@ file_open(struct archive *a, void *client_data)
#else
archive_set_error(a, ARCHIVE_ERRNO_MISC,
"Unexpedted operation in archive_read_open_filename");
- return (ARCHIVE_FATAL);
+ goto fail;
#endif
}
if (fstat(fd, &st) != 0) {
@@ -285,7 +287,7 @@ file_open(struct archive *a, void *client_data)
else
archive_set_error(a, errno, "Can't stat '%s'",
filename);
- return (ARCHIVE_FATAL);
+ goto fail;
}
/*
@@ -354,11 +356,9 @@ file_open(struct archive *a, void *client_data)
mine->block_size = new_block_size;
}
buffer = malloc(mine->block_size);
- if (mine == NULL || buffer == NULL) {
+ if (buffer == NULL) {
archive_set_error(a, ENOMEM, "No memory");
- free(mine);
- free(buffer);
- return (ARCHIVE_FATAL);
+ goto fail;
}
mine->buffer = buffer;
mine->fd = fd;
@@ -370,6 +370,14 @@ file_open(struct archive *a, void *client_data)
mine->use_lseek = 1;
return (ARCHIVE_OK);
+fail:
+ /*
+ * Don't close file descriptors not opened or ones pointing referring
+ * to `FNT_STDIN`.
+ */
+ if (fd != -1 && fd != 0)
+ close(fd);
+ return (ARCHIVE_FATAL);
}
static ssize_t
diff --git a/3rdparty/libarchive/libarchive/archive_read_open_memory.c b/3rdparty/libarchive/libarchive/archive_read_open_memory.c
index bcc7d6f7..311be470 100644
--- a/3rdparty/libarchive/libarchive/archive_read_open_memory.c
+++ b/3rdparty/libarchive/libarchive/archive_read_open_memory.c
@@ -41,9 +41,9 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_open_memory.c,v 1.6 2007/07/
*/
struct read_memory_data {
- unsigned char *start;
- unsigned char *p;
- unsigned char *end;
+ const unsigned char *start;
+ const unsigned char *p;
+ const unsigned char *end;
ssize_t read_size;
};
@@ -54,7 +54,7 @@ static int64_t memory_read_skip(struct archive *, void *, int64_t request);
static ssize_t memory_read(struct archive *, void *, const void **buff);
int
-archive_read_open_memory(struct archive *a, void *buff, size_t size)
+archive_read_open_memory(struct archive *a, const void *buff, size_t size)
{
return archive_read_open_memory2(a, buff, size, size);
}
@@ -65,18 +65,17 @@ archive_read_open_memory(struct archive *a, void *buff, size_t size)
* test harnesses can exercise block operations inside the library.
*/
int
-archive_read_open_memory2(struct archive *a, void *buff,
+archive_read_open_memory2(struct archive *a, const void *buff,
size_t size, size_t read_size)
{
struct read_memory_data *mine;
- mine = (struct read_memory_data *)malloc(sizeof(*mine));
+ mine = (struct read_memory_data *)calloc(1, sizeof(*mine));
if (mine == NULL) {
archive_set_error(a, ENOMEM, "No memory");
return (ARCHIVE_FATAL);
}
- memset(mine, 0, sizeof(*mine));
- mine->start = mine->p = (unsigned char *)buff;
+ mine->start = mine->p = (const unsigned char *)buff;
mine->end = mine->start + size;
mine->read_size = read_size;
archive_read_set_open_callback(a, memory_read_open);
diff --git a/3rdparty/libarchive/libarchive/archive_read_private.h b/3rdparty/libarchive/libarchive/archive_read_private.h
index 8a6c859a..78546dca 100644
--- a/3rdparty/libarchive/libarchive/archive_read_private.h
+++ b/3rdparty/libarchive/libarchive/archive_read_private.h
@@ -26,8 +26,10 @@
*/
#ifndef __LIBARCHIVE_BUILD
+#ifndef __LIBARCHIVE_TEST
#error This header is only to be used internally to libarchive.
#endif
+#endif
#ifndef ARCHIVE_READ_PRIVATE_H_INCLUDED
#define ARCHIVE_READ_PRIVATE_H_INCLUDED
@@ -141,6 +143,18 @@ struct archive_read_client {
int64_t position;
struct archive_read_data_node *dataset;
};
+struct archive_read_passphrase {
+ char *passphrase;
+ struct archive_read_passphrase *next;
+};
+
+struct archive_read_extract {
+ struct archive *ad; /* archive_write_disk object */
+
+ /* Progress function invoked during extract. */
+ void (*extract_progress)(void *);
+ void *extract_progress_user_data;
+};
struct archive_read {
struct archive archive;
@@ -152,28 +166,11 @@ struct archive_read {
int64_t skip_file_dev;
int64_t skip_file_ino;
- /*
- * Used by archive_read_data() to track blocks and copy
- * data to client buffers, filling gaps with zero bytes.
- */
- const char *read_data_block;
- int64_t read_data_offset;
- int64_t read_data_output_offset;
- size_t read_data_remaining;
-
- /*
- * Used by formats/filters to determine the amount of data
- * requested from a call to archive_read_data(). This is only
- * useful when the format/filter has seek support.
- */
- char read_data_is_posix_read;
- size_t read_data_requested;
-
/* Callbacks to open/read/write/close client archive streams. */
struct archive_read_client client;
/* Registered filter bidders. */
- struct archive_read_filter_bidder bidders[14];
+ struct archive_read_filter_bidder bidders[16];
/* Last filter in chain */
struct archive_read_filter *filter;
@@ -207,26 +204,41 @@ struct archive_read {
int (*read_data_skip)(struct archive_read *);
int64_t (*seek_data)(struct archive_read *, int64_t, int);
int (*cleanup)(struct archive_read *);
+ int (*format_capabilties)(struct archive_read *);
+ int (*has_encrypted_entries)(struct archive_read *);
} formats[16];
struct archive_format_descriptor *format; /* Active format. */
/*
* Various information needed by archive_extract.
*/
- struct extract *extract;
+ struct archive_read_extract *extract;
int (*cleanup_archive_extract)(struct archive_read *);
+
+ /*
+ * Decryption passphrase.
+ */
+ struct {
+ struct archive_read_passphrase *first;
+ struct archive_read_passphrase **last;
+ int candidate;
+ archive_passphrase_callback *callback;
+ void *client_data;
+ } passphrases;
};
int __archive_read_register_format(struct archive_read *a,
- void *format_data,
- const char *name,
- int (*bid)(struct archive_read *, int),
- int (*options)(struct archive_read *, const char *, const char *),
- int (*read_header)(struct archive_read *, struct archive_entry *),
- int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *),
- int (*read_data_skip)(struct archive_read *),
- int64_t (*seek_data)(struct archive_read *, int64_t, int),
- int (*cleanup)(struct archive_read *));
+ void *format_data,
+ const char *name,
+ int (*bid)(struct archive_read *, int),
+ int (*options)(struct archive_read *, const char *, const char *),
+ int (*read_header)(struct archive_read *, struct archive_entry *),
+ int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *),
+ int (*read_data_skip)(struct archive_read *),
+ int64_t (*seek_data)(struct archive_read *, int64_t, int),
+ int (*cleanup)(struct archive_read *),
+ int (*format_capabilities)(struct archive_read *),
+ int (*has_encrypted_entries)(struct archive_read *));
int __archive_read_get_bidder(struct archive_read *a,
struct archive_read_filter_bidder **bidder);
@@ -240,5 +252,12 @@ int64_t __archive_read_consume(struct archive_read *, int64_t);
int64_t __archive_read_filter_consume(struct archive_read_filter *, int64_t);
int __archive_read_program(struct archive_read_filter *, const char *);
void __archive_read_free_filters(struct archive_read *);
-int __archive_read_close_filters(struct archive_read *);
+struct archive_read_extract *__archive_read_get_extract(struct archive_read *);
+
+
+/*
+ * Get a decryption passphrase.
+ */
+void __archive_read_reset_passphrase(struct archive_read *a);
+const char * __archive_read_next_passphrase(struct archive_read *a);
#endif
diff --git a/3rdparty/libarchive/libarchive/archive_read_set_options.c b/3rdparty/libarchive/libarchive/archive_read_set_options.c
index 793f8f73..2e2eea69 100644
--- a/3rdparty/libarchive/libarchive/archive_read_set_options.c
+++ b/3rdparty/libarchive/libarchive/archive_read_set_options.c
@@ -76,18 +76,20 @@ archive_set_format_option(struct archive *_a, const char *m, const char *o,
const char *v)
{
struct archive_read *a = (struct archive_read *)_a;
- struct archive_format_descriptor *format;
size_t i;
- int r, rv = ARCHIVE_WARN;
+ int r, rv = ARCHIVE_WARN, matched_modules = 0;
for (i = 0; i < sizeof(a->formats)/sizeof(a->formats[0]); i++) {
- format = &a->formats[i];
- if (format == NULL || format->options == NULL ||
- format->name == NULL)
+ struct archive_format_descriptor *format = &a->formats[i];
+
+ if (format->options == NULL || format->name == NULL)
/* This format does not support option. */
continue;
- if (m != NULL && strcmp(format->name, m) != 0)
- continue;
+ if (m != NULL) {
+ if (strcmp(format->name, m) != 0)
+ continue;
+ ++matched_modules;
+ }
a->format = format;
r = format->options(a, o, v);
@@ -96,16 +98,13 @@ archive_set_format_option(struct archive *_a, const char *m, const char *o,
if (r == ARCHIVE_FATAL)
return (ARCHIVE_FATAL);
- if (m != NULL)
- return (r);
-
if (r == ARCHIVE_OK)
rv = ARCHIVE_OK;
}
/* If the format name didn't match, return a special code for
* _archive_set_option[s]. */
- if (rv == ARCHIVE_WARN && m != NULL)
- rv = ARCHIVE_WARN - 1;
+ if (m != NULL && matched_modules == 0)
+ return ARCHIVE_WARN - 1;
return (rv);
}
@@ -116,7 +115,7 @@ archive_set_filter_option(struct archive *_a, const char *m, const char *o,
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter *filter;
struct archive_read_filter_bidder *bidder;
- int r, rv = ARCHIVE_WARN;
+ int r, rv = ARCHIVE_WARN, matched_modules = 0;
for (filter = a->filter; filter != NULL; filter = filter->upstream) {
bidder = filter->bidder;
@@ -125,24 +124,24 @@ archive_set_filter_option(struct archive *_a, const char *m, const char *o,
if (bidder->options == NULL)
/* This bidder does not support option */
continue;
- if (m != NULL && strcmp(filter->name, m) != 0)
- continue;
+ if (m != NULL) {
+ if (strcmp(filter->name, m) != 0)
+ continue;
+ ++matched_modules;
+ }
r = bidder->options(bidder, o, v);
if (r == ARCHIVE_FATAL)
return (ARCHIVE_FATAL);
- if (m != NULL)
- return (r);
-
if (r == ARCHIVE_OK)
rv = ARCHIVE_OK;
}
/* If the filter name didn't match, return a special code for
* _archive_set_option[s]. */
- if (rv == ARCHIVE_WARN && m != NULL)
- rv = ARCHIVE_WARN - 1;
+ if (m != NULL && matched_modules == 0)
+ return ARCHIVE_WARN - 1;
return (rv);
}
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_filter_all.c b/3rdparty/libarchive/libarchive/archive_read_support_filter_all.c
deleted file mode 100644
index b778cfb7..00000000
--- a/3rdparty/libarchive/libarchive/archive_read_support_filter_all.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*-
- * Copyright (c) 2003-2011 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.h"
-#include "archive_private.h"
-
-#if ARCHIVE_VERSION_NUMBER < 4000000
-/* Deprecated; remove in libarchive 4.0 */
-int
-archive_read_support_compression_all(struct archive *a)
-{
- return archive_read_support_filter_all(a);
-}
-#endif
-
-int
-archive_read_support_filter_all(struct archive *a)
-{
- archive_check_magic(a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_NEW, "archive_read_support_filter_all");
-
- /* Bzip falls back to "bunzip2" command-line */
- archive_read_support_filter_bzip2(a);
- /* The decompress code doesn't use an outside library. */
- archive_read_support_filter_compress(a);
- /* Gzip decompress falls back to "gzip -d" command-line. */
- archive_read_support_filter_gzip(a);
- /* Lzip falls back to "unlzip" command-line program. */
- archive_read_support_filter_lzip(a);
- /* The LZMA file format has a very weak signature, so it
- * may not be feasible to keep this here, but we'll try.
- * This will come back out if there are problems. */
- /* Lzma falls back to "unlzma" command-line program. */
- archive_read_support_filter_lzma(a);
- /* Xz falls back to "unxz" command-line program. */
- archive_read_support_filter_xz(a);
- /* The decode code doesn't use an outside library. */
- archive_read_support_filter_uu(a);
- /* The decode code doesn't use an outside library. */
- archive_read_support_filter_rpm(a);
- /* The decode code always uses "lrzip -q -d" command-line. */
- archive_read_support_filter_lrzip(a);
- /* Lzop decompress falls back to "lzop -d" command-line. */
- archive_read_support_filter_lzop(a);
- /* The decode code always uses "grzip -d" command-line. */
- archive_read_support_filter_grzip(a);
-
- /* Note: We always return ARCHIVE_OK here, even if some of the
- * above return ARCHIVE_WARN. The intent here is to enable
- * "as much as possible." Clients who need specific
- * compression should enable those individually so they can
- * verify the level of support. */
- /* Clear any warning messages set by the above functions. */
- archive_clear_error(a);
- return (ARCHIVE_OK);
-}
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_filter_compress.c b/3rdparty/libarchive/libarchive/archive_read_support_filter_compress.c
deleted file mode 100644
index 3f5d1f37..00000000
--- a/3rdparty/libarchive/libarchive/archive_read_support_filter_compress.c
+++ /dev/null
@@ -1,455 +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.
- */
-
-/*
- * This code borrows heavily from "compress" source code, which is
- * protected by the following copyright. (Clause 3 dropped by request
- * of the Regents.)
- */
-
-/*-
- * Copyright (c) 1985, 1986, 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Diomidis Spinellis and James A. Woods, derived from original
- * work by Spencer Thomas and Joseph Orost.
- *
- * 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.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- */
-
-
-#include "archive_platform.h"
-__FBSDID("$FreeBSD$");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include "archive.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-
-/*
- * Because LZW decompression is pretty simple, I've just implemented
- * the whole decompressor here (cribbing from "compress" source code,
- * of course), rather than relying on an external library. I have
- * made an effort to clarify and simplify the algorithm, so the
- * names and structure here don't exactly match those used by compress.
- */
-
-struct private_data {
- /* Input variables. */
- const unsigned char *next_in;
- size_t avail_in;
- size_t consume_unnotified;
- int bit_buffer;
- int bits_avail;
- size_t bytes_in_section;
-
- /* Output variables. */
- size_t out_block_size;
- void *out_block;
-
- /* Decompression status variables. */
- int use_reset_code;
- int end_of_stream; /* EOF status. */
- int maxcode; /* Largest code. */
- int maxcode_bits; /* Length of largest code. */
- int section_end_code; /* When to increase bits. */
- int bits; /* Current code length. */
- int oldcode; /* Previous code. */
- int finbyte; /* Last byte of prev code. */
-
- /* Dictionary. */
- int free_ent; /* Next dictionary entry. */
- unsigned char suffix[65536];
- uint16_t prefix[65536];
-
- /*
- * Scratch area for expanding dictionary entries. Note:
- * "worst" case here comes from compressing /dev/zero: the
- * last code in the dictionary will code a sequence of
- * 65536-256 zero bytes. Thus, we need stack space to expand
- * a 65280-byte dictionary entry. (Of course, 32640:1
- * compression could also be considered the "best" case. ;-)
- */
- unsigned char *stackp;
- unsigned char stack[65300];
-};
-
-static int compress_bidder_bid(struct archive_read_filter_bidder *, struct archive_read_filter *);
-static int compress_bidder_init(struct archive_read_filter *);
-static int compress_bidder_free(struct archive_read_filter_bidder *);
-
-static ssize_t compress_filter_read(struct archive_read_filter *, const void **);
-static int compress_filter_close(struct archive_read_filter *);
-
-static int getbits(struct archive_read_filter *, int n);
-static int next_code(struct archive_read_filter *);
-
-#if ARCHIVE_VERSION_NUMBER < 4000000
-/* Deprecated; remove in libarchive 4.0 */
-int
-archive_read_support_compression_compress(struct archive *a)
-{
- return archive_read_support_filter_compress(a);
-}
-#endif
-
-int
-archive_read_support_filter_compress(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct archive_read_filter_bidder *bidder;
-
- archive_check_magic(_a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_NEW, "archive_read_support_filter_compress");
-
- if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- bidder->data = NULL;
- bidder->name = "compress (.Z)";
- bidder->bid = compress_bidder_bid;
- bidder->init = compress_bidder_init;
- bidder->options = NULL;
- bidder->free = compress_bidder_free;
- return (ARCHIVE_OK);
-}
-
-/*
- * Test whether we can handle this data.
- * This logic returns zero if any part of the signature fails.
- */
-static int
-compress_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
-{
- const unsigned char *buffer;
- ssize_t avail;
- int bits_checked;
-
- (void)self; /* UNUSED */
-
- buffer = __archive_read_filter_ahead(filter, 2, &avail);
-
- if (buffer == NULL)
- return (0);
-
- bits_checked = 0;
- if (buffer[0] != 0x1F || buffer[1] != 0x9D)
- return (0);
- bits_checked += 16;
-
- /*
- * TODO: Verify more.
- */
-
- return (bits_checked);
-}
-
-/*
- * Setup the callbacks.
- */
-static int
-compress_bidder_init(struct archive_read_filter *self)
-{
- struct private_data *state;
- static const size_t out_block_size = 64 * 1024;
- void *out_block;
- int code;
-
- self->code = ARCHIVE_FILTER_COMPRESS;
- self->name = "compress (.Z)";
-
- state = (struct private_data *)calloc(sizeof(*state), 1);
- out_block = malloc(out_block_size);
- if (state == NULL || out_block == NULL) {
- free(out_block);
- free(state);
- archive_set_error(&self->archive->archive, ENOMEM,
- "Can't allocate data for %s decompression",
- self->name);
- return (ARCHIVE_FATAL);
- }
-
- self->data = state;
- state->out_block_size = out_block_size;
- state->out_block = out_block;
- self->read = compress_filter_read;
- self->skip = NULL; /* not supported */
- self->close = compress_filter_close;
-
- /* XXX MOVE THE FOLLOWING OUT OF INIT() XXX */
-
- (void)getbits(self, 8); /* Skip first signature byte. */
- (void)getbits(self, 8); /* Skip second signature byte. */
-
- code = getbits(self, 8);
- state->maxcode_bits = code & 0x1f;
- state->maxcode = (1 << state->maxcode_bits);
- state->use_reset_code = code & 0x80;
-
- /* Initialize decompressor. */
- state->free_ent = 256;
- state->stackp = state->stack;
- if (state->use_reset_code)
- state->free_ent++;
- state->bits = 9;
- state->section_end_code = (1<<state->bits) - 1;
- state->oldcode = -1;
- for (code = 255; code >= 0; code--) {
- state->prefix[code] = 0;
- state->suffix[code] = code;
- }
- next_code(self);
-
- return (ARCHIVE_OK);
-}
-
-/*
- * Return a block of data from the decompression buffer. Decompress more
- * as necessary.
- */
-static ssize_t
-compress_filter_read(struct archive_read_filter *self, const void **pblock)
-{
- struct private_data *state;
- unsigned char *p, *start, *end;
- int ret;
-
- state = (struct private_data *)self->data;
- if (state->end_of_stream) {
- *pblock = NULL;
- return (0);
- }
- p = start = (unsigned char *)state->out_block;
- end = start + state->out_block_size;
-
- while (p < end && !state->end_of_stream) {
- if (state->stackp > state->stack) {
- *p++ = *--state->stackp;
- } else {
- ret = next_code(self);
- if (ret == -1)
- state->end_of_stream = ret;
- else if (ret != ARCHIVE_OK)
- return (ret);
- }
- }
-
- *pblock = start;
- return (p - start);
-}
-
-/*
- * Clean up the reader.
- */
-static int
-compress_bidder_free(struct archive_read_filter_bidder *self)
-{
- self->data = NULL;
- return (ARCHIVE_OK);
-}
-
-/*
- * Close and release the filter.
- */
-static int
-compress_filter_close(struct archive_read_filter *self)
-{
- struct private_data *state = (struct private_data *)self->data;
-
- free(state->out_block);
- free(state);
- return (ARCHIVE_OK);
-}
-
-/*
- * Process the next code and fill the stack with the expansion
- * of the code. Returns ARCHIVE_FATAL if there is a fatal I/O or
- * format error, ARCHIVE_EOF if we hit end of data, ARCHIVE_OK otherwise.
- */
-static int
-next_code(struct archive_read_filter *self)
-{
- struct private_data *state = (struct private_data *)self->data;
- int code, newcode;
-
- static int debug_buff[1024];
- static unsigned debug_index;
-
- code = newcode = getbits(self, state->bits);
- if (code < 0)
- return (code);
-
- debug_buff[debug_index++] = code;
- if (debug_index >= sizeof(debug_buff)/sizeof(debug_buff[0]))
- debug_index = 0;
-
- /* If it's a reset code, reset the dictionary. */
- if ((code == 256) && state->use_reset_code) {
- /*
- * The original 'compress' implementation blocked its
- * I/O in a manner that resulted in junk bytes being
- * inserted after every reset. The next section skips
- * this junk. (Yes, the number of *bytes* to skip is
- * a function of the current *bit* length.)
- */
- int skip_bytes = state->bits -
- (state->bytes_in_section % state->bits);
- skip_bytes %= state->bits;
- state->bits_avail = 0; /* Discard rest of this byte. */
- while (skip_bytes-- > 0) {
- code = getbits(self, 8);
- if (code < 0)
- return (code);
- }
- /* Now, actually do the reset. */
- state->bytes_in_section = 0;
- state->bits = 9;
- state->section_end_code = (1 << state->bits) - 1;
- state->free_ent = 257;
- state->oldcode = -1;
- return (next_code(self));
- }
-
- if (code > state->free_ent) {
- /* An invalid code is a fatal error. */
- archive_set_error(&(self->archive->archive), -1,
- "Invalid compressed data");
- return (ARCHIVE_FATAL);
- }
-
- /* Special case for KwKwK string. */
- if (code >= state->free_ent) {
- *state->stackp++ = state->finbyte;
- code = state->oldcode;
- }
-
- /* Generate output characters in reverse order. */
- while (code >= 256) {
- *state->stackp++ = state->suffix[code];
- code = state->prefix[code];
- }
- *state->stackp++ = state->finbyte = code;
-
- /* Generate the new entry. */
- code = state->free_ent;
- if (code < state->maxcode && state->oldcode >= 0) {
- state->prefix[code] = state->oldcode;
- state->suffix[code] = state->finbyte;
- ++state->free_ent;
- }
- if (state->free_ent > state->section_end_code) {
- state->bits++;
- state->bytes_in_section = 0;
- if (state->bits == state->maxcode_bits)
- state->section_end_code = state->maxcode;
- else
- state->section_end_code = (1 << state->bits) - 1;
- }
-
- /* Remember previous code. */
- state->oldcode = newcode;
- return (ARCHIVE_OK);
-}
-
-/*
- * Return next 'n' bits from stream.
- *
- * -1 indicates end of available data.
- */
-static int
-getbits(struct archive_read_filter *self, int n)
-{
- struct private_data *state = (struct private_data *)self->data;
- int code;
- ssize_t ret;
- static const int mask[] = {
- 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff,
- 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff
- };
-
- while (state->bits_avail < n) {
- if (state->avail_in <= 0) {
- if (state->consume_unnotified) {
- __archive_read_filter_consume(self->upstream,
- state->consume_unnotified);
- state->consume_unnotified = 0;
- }
- state->next_in
- = __archive_read_filter_ahead(self->upstream,
- 1, &ret);
- if (ret == 0)
- return (-1);
- if (ret < 0 || state->next_in == NULL)
- return (ARCHIVE_FATAL);
- state->consume_unnotified = state->avail_in = ret;
- }
- state->bit_buffer |= *state->next_in++ << state->bits_avail;
- state->avail_in--;
- state->bits_avail += 8;
- state->bytes_in_section++;
- }
-
- code = state->bit_buffer;
- state->bit_buffer >>= n;
- state->bits_avail -= n;
-
- return (code & mask[n]);
-}
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_filter_grzip.c b/3rdparty/libarchive/libarchive/archive_read_support_filter_grzip.c
deleted file mode 100644
index 84c86aeb..00000000
--- a/3rdparty/libarchive/libarchive/archive_read_support_filter_grzip.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*-
- * Copyright (c) 2012 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"
-
-__FBSDID("$FreeBSD$");
-
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include "archive.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-
-static const unsigned char grzip_magic[] = {
- 0x47, 0x52, 0x5a, 0x69, 0x70, 0x49, 0x49, 0x00,
- 0x02, 0x04, 0x3a, 0x29 };
-
-static int grzip_bidder_bid(struct archive_read_filter_bidder *,
- struct archive_read_filter *);
-static int grzip_bidder_init(struct archive_read_filter *);
-
-
-static int
-grzip_reader_free(struct archive_read_filter_bidder *self)
-{
- (void)self; /* UNUSED */
- return (ARCHIVE_OK);
-}
-
-int
-archive_read_support_filter_grzip(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct archive_read_filter_bidder *reader;
-
- archive_check_magic(_a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_NEW, "archive_read_support_filter_grzip");
-
- if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- reader->data = NULL;
- reader->bid = grzip_bidder_bid;
- reader->init = grzip_bidder_init;
- reader->options = NULL;
- reader->free = grzip_reader_free;
- /* This filter always uses an external program. */
- archive_set_error(_a, ARCHIVE_ERRNO_MISC,
- "Using external grzip program for grzip decompression");
- return (ARCHIVE_WARN);
-}
-
-/*
- * Bidder just verifies the header and returns the number of verified bits.
- */
-static int
-grzip_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
-{
- const unsigned char *p;
- ssize_t avail;
-
- (void)self; /* UNUSED */
-
- p = __archive_read_filter_ahead(filter, sizeof(grzip_magic), &avail);
- if (p == NULL || avail == 0)
- return (0);
-
- if (memcmp(p, grzip_magic, sizeof(grzip_magic)))
- return (0);
-
- return (sizeof(grzip_magic) * 8);
-}
-
-static int
-grzip_bidder_init(struct archive_read_filter *self)
-{
- int r;
-
- r = __archive_read_program(self, "grzip -d");
- /* Note: We set the format here even if __archive_read_program()
- * above fails. We do, after all, know what the format is
- * even if we weren't able to read it. */
- self->code = ARCHIVE_FILTER_GRZIP;
- self->name = "grzip";
- return (r);
-}
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_filter_lrzip.c b/3rdparty/libarchive/libarchive/archive_read_support_filter_lrzip.c
deleted file mode 100644
index c82a8e2f..00000000
--- a/3rdparty/libarchive/libarchive/archive_read_support_filter_lrzip.c
+++ /dev/null
@@ -1,132 +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$");
-
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include "archive.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-
-#define LRZIP_HEADER_MAGIC "LRZI"
-#define LRZIP_HEADER_MAGIC_LEN 4
-
-static int lrzip_bidder_bid(struct archive_read_filter_bidder *,
- struct archive_read_filter *);
-static int lrzip_bidder_init(struct archive_read_filter *);
-
-
-static int
-lrzip_reader_free(struct archive_read_filter_bidder *self)
-{
- (void)self; /* UNUSED */
- return (ARCHIVE_OK);
-}
-
-int
-archive_read_support_filter_lrzip(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct archive_read_filter_bidder *reader;
-
- archive_check_magic(_a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_NEW, "archive_read_support_filter_lrzip");
-
- if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- reader->data = NULL;
- reader->name = "lrzip";
- reader->bid = lrzip_bidder_bid;
- reader->init = lrzip_bidder_init;
- reader->options = NULL;
- reader->free = lrzip_reader_free;
- /* This filter always uses an external program. */
- archive_set_error(_a, ARCHIVE_ERRNO_MISC,
- "Using external lrzip program for lrzip decompression");
- return (ARCHIVE_WARN);
-}
-
-/*
- * Bidder just verifies the header and returns the number of verified bits.
- */
-static int
-lrzip_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
-{
- const unsigned char *p;
- ssize_t avail, len;
- int i;
-
- (void)self; /* UNUSED */
- /* Start by looking at the first six bytes of the header, which
- * is all fixed layout. */
- len = 6;
- p = __archive_read_filter_ahead(filter, len, &avail);
- if (p == NULL || avail == 0)
- return (0);
-
- if (memcmp(p, LRZIP_HEADER_MAGIC, LRZIP_HEADER_MAGIC_LEN))
- return (0);
-
- /* current major version is always 0, verify this */
- if (p[LRZIP_HEADER_MAGIC_LEN])
- return 0;
- /* support only v0.6+ lrzip for sanity */
- i = p[LRZIP_HEADER_MAGIC_LEN + 1];
- if ((i < 6) || (i > 10))
- return 0;
-
- return (int)len;
-}
-
-static int
-lrzip_bidder_init(struct archive_read_filter *self)
-{
- int r;
-
- r = __archive_read_program(self, "lrzip -d -q");
- /* Note: We set the format here even if __archive_read_program()
- * above fails. We do, after all, know what the format is
- * even if we weren't able to read it. */
- self->code = ARCHIVE_FILTER_LRZIP;
- self->name = "lrzip";
- return (r);
-}
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_filter_lzop.c b/3rdparty/libarchive/libarchive/archive_read_support_filter_lzop.c
deleted file mode 100644
index 713af31e..00000000
--- a/3rdparty/libarchive/libarchive/archive_read_support_filter_lzop.c
+++ /dev/null
@@ -1,486 +0,0 @@
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * Copyright (c) 2012 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"
-
-__FBSDID("$FreeBSD$");
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_LZO_LZOCONF_H
-#include <lzo/lzoconf.h>
-#endif
-#ifdef HAVE_LZO_LZO1X_H
-#include <lzo/lzo1x.h>
-#endif
-#ifdef HAVE_ZLIB_H
-#include <zlib.h> /* for crc32 and adler32 */
-#endif
-
-#include "archive.h"
-#if !defined(HAVE_ZLIB_H) &&\
- defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
-#include "archive_crc32.h"
-#endif
-#include "archive_endian.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-
-#ifndef HAVE_ZLIB_H
-#define adler32 lzo_adler32
-#endif
-
-#define LZOP_HEADER_MAGIC "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a"
-#define LZOP_HEADER_MAGIC_LEN 9
-
-#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
-struct read_lzop {
- unsigned char *out_block;
- size_t out_block_size;
- int64_t total_out;
- int flags;
- uint32_t compressed_cksum;
- uint32_t uncompressed_cksum;
- size_t compressed_size;
- size_t uncompressed_size;
- size_t unconsumed_bytes;
- char in_stream;
- char eof; /* True = found end of compressed data. */
-};
-
-#define FILTER 0x0800
-#define CRC32_HEADER 0x1000
-#define EXTRA_FIELD 0x0040
-#define ADLER32_UNCOMPRESSED 0x0001
-#define ADLER32_COMPRESSED 0x0002
-#define CRC32_UNCOMPRESSED 0x0100
-#define CRC32_COMPRESSED 0x0200
-#define MAX_BLOCK_SIZE (64 * 1024 * 1024)
-
-static ssize_t lzop_filter_read(struct archive_read_filter *, const void **);
-static int lzop_filter_close(struct archive_read_filter *);
-#endif
-
-static int lzop_bidder_bid(struct archive_read_filter_bidder *,
- struct archive_read_filter *);
-static int lzop_bidder_init(struct archive_read_filter *);
-
-int
-archive_read_support_filter_lzop(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct archive_read_filter_bidder *reader;
-
- archive_check_magic(_a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_NEW, "archive_read_support_filter_lzop");
-
- if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- reader->data = NULL;
- reader->bid = lzop_bidder_bid;
- reader->init = lzop_bidder_init;
- reader->options = NULL;
- reader->free = NULL;
- /* Signal the extent of lzop support with the return value here. */
-#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
- return (ARCHIVE_OK);
-#else
- /* Return ARCHIVE_WARN since this always uses an external program. */
- archive_set_error(_a, ARCHIVE_ERRNO_MISC,
- "Using external lzop program for lzop decompression");
- return (ARCHIVE_WARN);
-#endif
-}
-
-/*
- * Bidder just verifies the header and returns the number of verified bits.
- */
-static int
-lzop_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
-{
- const unsigned char *p;
- ssize_t avail;
-
- (void)self; /* UNUSED */
-
- p = __archive_read_filter_ahead(filter, LZOP_HEADER_MAGIC_LEN, &avail);
- if (p == NULL || avail == 0)
- return (0);
-
- if (memcmp(p, LZOP_HEADER_MAGIC, LZOP_HEADER_MAGIC_LEN))
- return (0);
-
- return (LZOP_HEADER_MAGIC_LEN * 8);
-}
-
-#if !defined(HAVE_LZO_LZOCONF_H) || !defined(HAVE_LZO_LZO1X_H)
-/*
- * If we don't have the library on this system, we can't do the
- * decompression directly. We can, however, try to run "lzop -d"
- * in case that's available.
- */
-static int
-lzop_bidder_init(struct archive_read_filter *self)
-{
- int r;
-
- r = __archive_read_program(self, "lzop -d");
- /* Note: We set the format here even if __archive_read_program()
- * above fails. We do, after all, know what the format is
- * even if we weren't able to read it. */
- self->code = ARCHIVE_FILTER_LZOP;
- self->name = "lzop";
- return (r);
-}
-#else
-/*
- * Initialize the filter object.
- */
-static int
-lzop_bidder_init(struct archive_read_filter *self)
-{
- struct read_lzop *state;
-
- self->code = ARCHIVE_FILTER_LZOP;
- self->name = "lzop";
-
- state = (struct read_lzop *)calloc(sizeof(*state), 1);
- if (state == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
- "Can't allocate data for lzop decompression");
- return (ARCHIVE_FATAL);
- }
-
- self->data = state;
- self->read = lzop_filter_read;
- self->skip = NULL; /* not supported */
- self->close = lzop_filter_close;
-
- return (ARCHIVE_OK);
-}
-
-static int
-consume_header(struct archive_read_filter *self)
-{
- struct read_lzop *state = (struct read_lzop *)self->data;
- const unsigned char *p, *_p;
- unsigned checksum, flags, len, method, version;
-
- /*
- * Check LZOP magic code.
- */
- p = __archive_read_filter_ahead(self->upstream,
- LZOP_HEADER_MAGIC_LEN, NULL);
- if (p == NULL)
- return (ARCHIVE_EOF);
-
- if (memcmp(p, LZOP_HEADER_MAGIC, LZOP_HEADER_MAGIC_LEN))
- return (ARCHIVE_EOF);
- __archive_read_filter_consume(self->upstream,
- LZOP_HEADER_MAGIC_LEN);
-
- p = __archive_read_filter_ahead(self->upstream, 29, NULL);
- if (p == NULL)
- goto truncated;
- _p = p;
- version = archive_be16dec(p);
- p += 4;/* version(2 bytes) + library version(2 bytes) */
-
- if (version >= 0x940) {
- unsigned reqversion = archive_be16dec(p); p += 2;
- if (reqversion < 0x900) {
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC, "Invalid required version");
- return (ARCHIVE_FAILED);
- }
- }
-
- method = *p++;
- if (method < 1 || method > 3) {
- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
- "Unsupported method");
- return (ARCHIVE_FAILED);
- }
-
- if (version >= 0x940) {
- unsigned level = *p++;
- if (method == 1 && level == 0) level = 3;
- if (method == 2 && level == 0) level = 1;
- if (method == 3 && level == 0) level = 9;
- if (level < 1 && level > 9) {
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC, "Invalid level");
- return (ARCHIVE_FAILED);
- }
- }
-
- flags = archive_be32dec(p); p += 4;
-
- if (flags & FILTER)
- p += 4; /* Skip filter */
- p += 4; /* Skip mode */
- if (version >= 0x940)
- p += 8; /* Skip mtime */
- else
- p += 4; /* Skip mtime */
- len = *p++; /* Read filename length */
- len += p - _p;
- /* Make sure we have all bytes we need to calculate checksum. */
- p = __archive_read_filter_ahead(self->upstream, len + 4, NULL);
- if (p == NULL)
- goto truncated;
- if (flags & CRC32_HEADER)
- checksum = crc32(crc32(0, NULL, 0), p, len);
- else
- checksum = adler32(adler32(0, NULL, 0), p, len);
- if (archive_be32dec(p + len) != checksum)
- goto corrupted;
- __archive_read_filter_consume(self->upstream, len + 4);
- if (flags & EXTRA_FIELD) {
- /* Skip extra field */
- p = __archive_read_filter_ahead(self->upstream, 4, NULL);
- if (p == NULL)
- goto truncated;
- len = archive_be32dec(p);
- __archive_read_filter_consume(self->upstream, len + 4 + 4);
- }
- state->flags = flags;
- state->in_stream = 1;
- return (ARCHIVE_OK);
-truncated:
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
- return (ARCHIVE_FAILED);
-corrupted:
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header");
- return (ARCHIVE_FAILED);
-}
-
-static int
-consume_block_info(struct archive_read_filter *self)
-{
- struct read_lzop *state = (struct read_lzop *)self->data;
- const unsigned char *p;
- unsigned flags = state->flags;
-
- p = __archive_read_filter_ahead(self->upstream, 4, NULL);
- if (p == NULL)
- goto truncated;
- state->uncompressed_size = archive_be32dec(p);
- __archive_read_filter_consume(self->upstream, 4);
- if (state->uncompressed_size == 0)
- return (ARCHIVE_EOF);
- if (state->uncompressed_size > MAX_BLOCK_SIZE)
- goto corrupted;
-
- p = __archive_read_filter_ahead(self->upstream, 4, NULL);
- if (p == NULL)
- goto truncated;
- state->compressed_size = archive_be32dec(p);
- __archive_read_filter_consume(self->upstream, 4);
- if (state->compressed_size > state->uncompressed_size)
- goto corrupted;
-
- if (flags & (CRC32_UNCOMPRESSED | ADLER32_UNCOMPRESSED)) {
- p = __archive_read_filter_ahead(self->upstream, 4, NULL);
- if (p == NULL)
- goto truncated;
- state->compressed_cksum = state->uncompressed_cksum =
- archive_be32dec(p);
- __archive_read_filter_consume(self->upstream, 4);
- }
- if ((flags & (CRC32_COMPRESSED | ADLER32_COMPRESSED)) &&
- state->compressed_size < state->uncompressed_size) {
- p = __archive_read_filter_ahead(self->upstream, 4, NULL);
- if (p == NULL)
- goto truncated;
- state->compressed_cksum = archive_be32dec(p);
- __archive_read_filter_consume(self->upstream, 4);
- }
- return (ARCHIVE_OK);
-truncated:
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
- return (ARCHIVE_FAILED);
-corrupted:
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header");
- return (ARCHIVE_FAILED);
-}
-
-static ssize_t
-lzop_filter_read(struct archive_read_filter *self, const void **p)
-{
- struct read_lzop *state = (struct read_lzop *)self->data;
- const void *b;
- lzo_uint out_size;
- uint32_t cksum;
- int ret, r;
-
- if (state->unconsumed_bytes) {
- __archive_read_filter_consume(self->upstream,
- state->unconsumed_bytes);
- state->unconsumed_bytes = 0;
- }
- if (state->eof)
- return (0);
-
- for (;;) {
- if (!state->in_stream) {
- ret = consume_header(self);
- if (ret < ARCHIVE_OK)
- return (ret);
- if (ret == ARCHIVE_EOF) {
- state->eof = 1;
- return (0);
- }
- }
- ret = consume_block_info(self);
- if (ret < ARCHIVE_OK)
- return (ret);
- if (ret == ARCHIVE_EOF)
- state->in_stream = 0;
- else
- break;
- }
-
- if (state->out_block == NULL ||
- state->out_block_size < state->uncompressed_size) {
- void *new_block;
-
- new_block = realloc(state->out_block, state->uncompressed_size);
- if (new_block == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
- "Can't allocate data for lzop decompression");
- return (ARCHIVE_FATAL);
- }
- state->out_block = new_block;
- state->out_block_size = state->uncompressed_size;
- }
-
- b = __archive_read_filter_ahead(self->upstream,
- state->compressed_size, NULL);
- if (b == NULL) {
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
- return (ARCHIVE_FATAL);
- }
- if (state->flags & CRC32_COMPRESSED)
- cksum = crc32(crc32(0, NULL, 0), b, state->compressed_size);
- else if (state->flags & ADLER32_COMPRESSED)
- cksum = adler32(adler32(0, NULL, 0), b, state->compressed_size);
- else
- cksum = state->compressed_cksum;
- if (cksum != state->compressed_cksum) {
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC, "Corrupted data");
- return (ARCHIVE_FATAL);
- }
-
- /*
- * If the both uncompressed size and compressed size are the same,
- * we do not decompress this block.
- */
- if (state->uncompressed_size == state->compressed_size) {
- *p = b;
- state->total_out += state->compressed_size;
- state->unconsumed_bytes = state->compressed_size;
- return ((ssize_t)state->uncompressed_size);
- }
-
- /*
- * Drive lzo uncompresison.
- */
- out_size = (lzo_uint)state->uncompressed_size;
- r = lzo1x_decompress_safe(b, (lzo_uint)state->compressed_size,
- state->out_block, &out_size, NULL);
- switch (r) {
- case LZO_E_OK:
- if (out_size == state->uncompressed_size)
- break;
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC, "Corrupted data");
- return (ARCHIVE_FATAL);
- case LZO_E_OUT_OF_MEMORY:
- archive_set_error(&self->archive->archive, ENOMEM,
- "lzop decompression failed: out of memory");
- return (ARCHIVE_FATAL);
- default:
- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
- "lzop decompression failed: %d", r);
- return (ARCHIVE_FATAL);
- }
-
- if (state->flags & CRC32_UNCOMPRESSED)
- cksum = crc32(crc32(0, NULL, 0), state->out_block,
- state->uncompressed_size);
- else if (state->flags & ADLER32_UNCOMPRESSED)
- cksum = adler32(adler32(0, NULL, 0), state->out_block,
- state->uncompressed_size);
- else
- cksum = state->uncompressed_cksum;
- if (cksum != state->uncompressed_cksum) {
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC, "Corrupted data");
- return (ARCHIVE_FATAL);
- }
-
- __archive_read_filter_consume(self->upstream, state->compressed_size);
- *p = state->out_block;
- state->total_out += out_size;
- return ((ssize_t)out_size);
-}
-
-/*
- * Clean up the decompressor.
- */
-static int
-lzop_filter_close(struct archive_read_filter *self)
-{
- struct read_lzop *state = (struct read_lzop *)self->data;
-
- free(state->out_block);
- free(state);
- return (ARCHIVE_OK);
-}
-
-#endif
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_filter_program.c b/3rdparty/libarchive/libarchive/archive_read_support_filter_program.c
index 66dc2f42..b8bf1288 100644
--- a/3rdparty/libarchive/libarchive/archive_read_support_filter_program.c
+++ b/3rdparty/libarchive/libarchive/archive_read_support_filter_program.c
@@ -430,6 +430,7 @@ __archive_read_program(struct archive_read_filter *self, const char *cmd)
&state->child_stdout);
if (child == -1) {
free(state->out_buf);
+ archive_string_free(&state->description);
free(state);
archive_set_error(&self->archive->archive, EINVAL,
"Can't initialize filter; unable to run program \"%s\"",
@@ -441,6 +442,7 @@ __archive_read_program(struct archive_read_filter *self, const char *cmd)
if (state->child == NULL) {
child_stop(self, state);
free(state->out_buf);
+ archive_string_free(&state->description);
free(state);
archive_set_error(&self->archive->archive, EINVAL,
"Can't initialize filter; unable to run program \"%s\"",
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_filter_rpm.c b/3rdparty/libarchive/libarchive/archive_read_support_filter_rpm.c
deleted file mode 100644
index e7e58e51..00000000
--- a/3rdparty/libarchive/libarchive/archive_read_support_filter_rpm.c
+++ /dev/null
@@ -1,289 +0,0 @@
-/*-
- * Copyright (c) 2009 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"
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-
-#include "archive.h"
-#include "archive_endian.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-
-struct rpm {
- int64_t total_in;
- size_t hpos;
- size_t hlen;
- unsigned char header[16];
- enum {
- ST_LEAD, /* Skipping 'Lead' section. */
- ST_HEADER, /* Reading 'Header' section;
- * first 16 bytes. */
- ST_HEADER_DATA, /* Skipping 'Header' section. */
- ST_PADDING, /* Skipping padding data after the
- * 'Header' section. */
- ST_ARCHIVE /* Reading 'Archive' section. */
- } state;
- int first_header;
-};
-#define RPM_LEAD_SIZE 96 /* Size of 'Lead' section. */
-
-static int rpm_bidder_bid(struct archive_read_filter_bidder *,
- struct archive_read_filter *);
-static int rpm_bidder_init(struct archive_read_filter *);
-
-static ssize_t rpm_filter_read(struct archive_read_filter *,
- const void **);
-static int rpm_filter_close(struct archive_read_filter *);
-
-#if ARCHIVE_VERSION_NUMBER < 4000000
-/* Deprecated; remove in libarchive 4.0 */
-int
-archive_read_support_compression_rpm(struct archive *a)
-{
- return archive_read_support_filter_rpm(a);
-}
-#endif
-
-int
-archive_read_support_filter_rpm(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct archive_read_filter_bidder *bidder;
-
- archive_check_magic(_a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_NEW, "archive_read_support_filter_rpm");
-
- if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- bidder->data = NULL;
- bidder->name = "rpm";
- bidder->bid = rpm_bidder_bid;
- bidder->init = rpm_bidder_init;
- bidder->options = NULL;
- bidder->free = NULL;
- return (ARCHIVE_OK);
-}
-
-static int
-rpm_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
-{
- const unsigned char *b;
- ssize_t avail;
- int bits_checked;
-
- (void)self; /* UNUSED */
-
- b = __archive_read_filter_ahead(filter, 8, &avail);
- if (b == NULL)
- return (0);
-
- bits_checked = 0;
- /*
- * Verify Header Magic Bytes : 0XED 0XAB 0XEE 0XDB
- */
- if (memcmp(b, "\xED\xAB\xEE\xDB", 4) != 0)
- return (0);
- bits_checked += 32;
- /*
- * Check major version.
- */
- if (b[4] != 3 && b[4] != 4)
- return (0);
- bits_checked += 8;
- /*
- * Check package type; binary or source.
- */
- if (b[6] != 0)
- return (0);
- bits_checked += 8;
- if (b[7] != 0 && b[7] != 1)
- return (0);
- bits_checked += 8;
-
- return (bits_checked);
-}
-
-static int
-rpm_bidder_init(struct archive_read_filter *self)
-{
- struct rpm *rpm;
-
- self->code = ARCHIVE_FILTER_RPM;
- self->name = "rpm";
- self->read = rpm_filter_read;
- self->skip = NULL; /* not supported */
- self->close = rpm_filter_close;
-
- rpm = (struct rpm *)calloc(sizeof(*rpm), 1);
- if (rpm == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
- "Can't allocate data for rpm");
- return (ARCHIVE_FATAL);
- }
-
- self->data = rpm;
- rpm->state = ST_LEAD;
-
- return (ARCHIVE_OK);
-}
-
-static ssize_t
-rpm_filter_read(struct archive_read_filter *self, const void **buff)
-{
- struct rpm *rpm;
- const unsigned char *b;
- ssize_t avail_in, total;
- size_t used, n;
- uint32_t section;
- uint32_t bytes;
-
- rpm = (struct rpm *)self->data;
- *buff = NULL;
- total = avail_in = 0;
- b = NULL;
- used = 0;
- do {
- if (b == NULL) {
- b = __archive_read_filter_ahead(self->upstream, 1,
- &avail_in);
- if (b == NULL) {
- if (avail_in < 0)
- return (ARCHIVE_FATAL);
- else
- break;
- }
- }
-
- switch (rpm->state) {
- case ST_LEAD:
- if (rpm->total_in + avail_in < RPM_LEAD_SIZE)
- used += avail_in;
- else {
- n = (size_t)(RPM_LEAD_SIZE - rpm->total_in);
- used += n;
- b += n;
- rpm->state = ST_HEADER;
- rpm->hpos = 0;
- rpm->hlen = 0;
- rpm->first_header = 1;
- }
- break;
- case ST_HEADER:
- n = 16 - rpm->hpos;
- if (n > avail_in - used)
- n = avail_in - used;
- memcpy(rpm->header+rpm->hpos, b, n);
- b += n;
- used += n;
- rpm->hpos += n;
-
- if (rpm->hpos == 16) {
- if (rpm->header[0] != 0x8e ||
- rpm->header[1] != 0xad ||
- rpm->header[2] != 0xe8 ||
- rpm->header[3] != 0x01) {
- if (rpm->first_header) {
- archive_set_error(
- &self->archive->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Unrecoginized rpm header");
- return (ARCHIVE_FATAL);
- }
- rpm->state = ST_ARCHIVE;
- *buff = rpm->header;
- total = rpm->hpos;
- break;
- }
- /* Calculate 'Header' length. */
- section = archive_be32dec(rpm->header+8);
- bytes = archive_be32dec(rpm->header+12);
- rpm->hlen = 16 + section * 16 + bytes;
- rpm->state = ST_HEADER_DATA;
- rpm->first_header = 0;
- }
- break;
- case ST_HEADER_DATA:
- n = rpm->hlen - rpm->hpos;
- if (n > avail_in - used)
- n = avail_in - used;
- b += n;
- used += n;
- rpm->hpos += n;
- if (rpm->hpos == rpm->hlen)
- rpm->state = ST_PADDING;
- break;
- case ST_PADDING:
- while (used < (size_t)avail_in) {
- if (*b != 0) {
- /* Read next header. */
- rpm->state = ST_HEADER;
- rpm->hpos = 0;
- rpm->hlen = 0;
- break;
- }
- b++;
- used++;
- }
- break;
- case ST_ARCHIVE:
- *buff = b;
- total = avail_in;
- used = avail_in;
- break;
- }
- if (used == (size_t)avail_in) {
- rpm->total_in += used;
- __archive_read_filter_consume(self->upstream, used);
- b = NULL;
- used = 0;
- }
- } while (total == 0 && avail_in > 0);
-
- if (used > 0 && b != NULL) {
- rpm->total_in += used;
- __archive_read_filter_consume(self->upstream, used);
- }
- return (total);
-}
-
-static int
-rpm_filter_close(struct archive_read_filter *self)
-{
- struct rpm *rpm;
-
- rpm = (struct rpm *)self->data;
- free(rpm);
-
- return (ARCHIVE_OK);
-}
-
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_filter_uu.c b/3rdparty/libarchive/libarchive/archive_read_support_filter_uu.c
deleted file mode 100644
index 471771b6..00000000
--- a/3rdparty/libarchive/libarchive/archive_read_support_filter_uu.c
+++ /dev/null
@@ -1,694 +0,0 @@
-/*-
- * Copyright (c) 2009-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"
-__FBSDID("$FreeBSD$");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#include "archive.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-
-/* Maximum lookahead during bid phase */
-#define UUENCODE_BID_MAX_READ 128*1024 /* in bytes */
-
-struct uudecode {
- int64_t total;
- unsigned char *in_buff;
-#define IN_BUFF_SIZE (1024)
- int in_cnt;
- size_t in_allocated;
- unsigned char *out_buff;
-#define OUT_BUFF_SIZE (64 * 1024)
- int state;
-#define ST_FIND_HEAD 0
-#define ST_READ_UU 1
-#define ST_UUEND 2
-#define ST_READ_BASE64 3
-#define ST_IGNORE 4
-};
-
-static int uudecode_bidder_bid(struct archive_read_filter_bidder *,
- struct archive_read_filter *filter);
-static int uudecode_bidder_init(struct archive_read_filter *);
-
-static ssize_t uudecode_filter_read(struct archive_read_filter *,
- const void **);
-static int uudecode_filter_close(struct archive_read_filter *);
-
-#if ARCHIVE_VERSION_NUMBER < 4000000
-/* Deprecated; remove in libarchive 4.0 */
-int
-archive_read_support_compression_uu(struct archive *a)
-{
- return archive_read_support_filter_uu(a);
-}
-#endif
-
-int
-archive_read_support_filter_uu(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct archive_read_filter_bidder *bidder;
-
- archive_check_magic(_a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_NEW, "archive_read_support_filter_uu");
-
- if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- bidder->data = NULL;
- bidder->name = "uu";
- bidder->bid = uudecode_bidder_bid;
- bidder->init = uudecode_bidder_init;
- bidder->options = NULL;
- bidder->free = NULL;
- return (ARCHIVE_OK);
-}
-
-static const unsigned char ascii[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\n', 0, 0, '\r', 0, 0, /* 00 - 0F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
-};
-
-static const unsigned char uuchar[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70 - 7F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
-};
-
-static const unsigned char base64[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, /* 20 - 2F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, /* 30 - 3F */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 50 - 5F */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 70 - 7F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
-};
-
-static const int base64num[128] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 62, 0, 0, 0, 63, /* 20 - 2F */
- 52, 53, 54, 55, 56, 57, 58, 59,
- 60, 61, 0, 0, 0, 0, 0, 0, /* 30 - 3F */
- 0, 0, 1, 2, 3, 4, 5, 6,
- 7, 8, 9, 10, 11, 12, 13, 14, /* 40 - 4F */
- 15, 16, 17, 18, 19, 20, 21, 22,
- 23, 24, 25, 0, 0, 0, 0, 0, /* 50 - 5F */
- 0, 26, 27, 28, 29, 30, 31, 32,
- 33, 34, 35, 36, 37, 38, 39, 40, /* 60 - 6F */
- 41, 42, 43, 44, 45, 46, 47, 48,
- 49, 50, 51, 0, 0, 0, 0, 0, /* 70 - 7F */
-};
-
-static ssize_t
-get_line(const unsigned char *b, ssize_t avail, ssize_t *nlsize)
-{
- ssize_t len;
-
- len = 0;
- while (len < avail) {
- switch (ascii[*b]) {
- case 0: /* Non-ascii character or control character. */
- if (nlsize != NULL)
- *nlsize = 0;
- return (-1);
- case '\r':
- if (avail-len > 1 && b[1] == '\n') {
- if (nlsize != NULL)
- *nlsize = 2;
- return (len+2);
- }
- /* FALL THROUGH */
- case '\n':
- if (nlsize != NULL)
- *nlsize = 1;
- return (len+1);
- case 1:
- b++;
- len++;
- break;
- }
- }
- if (nlsize != NULL)
- *nlsize = 0;
- return (avail);
-}
-
-static ssize_t
-bid_get_line(struct archive_read_filter *filter,
- const unsigned char **b, ssize_t *avail, ssize_t *ravail,
- ssize_t *nl, size_t* nbytes_read)
-{
- ssize_t len;
- int quit;
-
- quit = 0;
- if (*avail == 0) {
- *nl = 0;
- len = 0;
- } else
- len = get_line(*b, *avail, nl);
-
- /*
- * Read bytes more while it does not reach the end of line.
- */
- while (*nl == 0 && len == *avail && !quit &&
- *nbytes_read < UUENCODE_BID_MAX_READ) {
- ssize_t diff = *ravail - *avail;
- size_t nbytes_req = (*ravail+1023) & ~1023U;
- ssize_t tested;
-
- /* Increase reading bytes if it is not enough to at least
- * new two lines. */
- if (nbytes_req < (size_t)*ravail + 160)
- nbytes_req <<= 1;
-
- *b = __archive_read_filter_ahead(filter, nbytes_req, avail);
- if (*b == NULL) {
- if (*ravail >= *avail)
- return (0);
- /* Reading bytes reaches the end of a stream. */
- *b = __archive_read_filter_ahead(filter, *avail, avail);
- quit = 1;
- }
- *nbytes_read = *avail;
- *ravail = *avail;
- *b += diff;
- *avail -= diff;
- tested = len;/* Skip some bytes we already determinated. */
- len = get_line(*b + tested, *avail - tested, nl);
- if (len >= 0)
- len += tested;
- }
- return (len);
-}
-
-#define UUDECODE(c) (((c) - 0x20) & 0x3f)
-
-static int
-uudecode_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
-{
- const unsigned char *b;
- ssize_t avail, ravail;
- ssize_t len, nl;
- int l;
- int firstline;
- size_t nbytes_read;
-
- (void)self; /* UNUSED */
-
- b = __archive_read_filter_ahead(filter, 1, &avail);
- if (b == NULL)
- return (0);
-
- firstline = 20;
- ravail = avail;
- nbytes_read = avail;
- for (;;) {
- len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read);
- if (len < 0 || nl == 0)
- return (0); /* No match found. */
- if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0)
- l = 6;
- else if (len -nl >= 18 && memcmp(b, "begin-base64 ", 13) == 0)
- l = 13;
- else
- l = 0;
-
- if (l > 0 && (b[l] < '0' || b[l] > '7' ||
- b[l+1] < '0' || b[l+1] > '7' ||
- b[l+2] < '0' || b[l+2] > '7' || b[l+3] != ' '))
- l = 0;
-
- b += len;
- avail -= len;
- if (l)
- break;
- firstline = 0;
-
- /* Do not read more than UUENCODE_BID_MAX_READ bytes */
- if (nbytes_read >= UUENCODE_BID_MAX_READ)
- return (0);
- }
- if (!avail)
- return (0);
- len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read);
- if (len < 0 || nl == 0)
- return (0);/* There are non-ascii characters. */
- avail -= len;
-
- if (l == 6) {
- if (!uuchar[*b])
- return (0);
- /* Get a length of decoded bytes. */
- l = UUDECODE(*b++); len--;
- if (l > 45)
- /* Normally, maximum length is 45(character 'M'). */
- return (0);
- while (l && len-nl > 0) {
- if (l > 0) {
- if (!uuchar[*b++])
- return (0);
- if (!uuchar[*b++])
- return (0);
- len -= 2;
- --l;
- }
- if (l > 0) {
- if (!uuchar[*b++])
- return (0);
- --len;
- --l;
- }
- if (l > 0) {
- if (!uuchar[*b++])
- return (0);
- --len;
- --l;
- }
- }
- if (len-nl < 0)
- return (0);
- if (len-nl == 1 &&
- (uuchar[*b] || /* Check sum. */
- (*b >= 'a' && *b <= 'z'))) {/* Padding data(MINIX). */
- ++b;
- --len;
- }
- b += nl;
- if (avail && uuchar[*b])
- return (firstline+30);
- }
- if (l == 13) {
- while (len-nl > 0) {
- if (!base64[*b++])
- return (0);
- --len;
- }
- b += nl;
-
- if (avail >= 5 && memcmp(b, "====\n", 5) == 0)
- return (firstline+40);
- if (avail >= 6 && memcmp(b, "====\r\n", 6) == 0)
- return (firstline+40);
- if (avail > 0 && base64[*b])
- return (firstline+30);
- }
-
- return (0);
-}
-
-static int
-uudecode_bidder_init(struct archive_read_filter *self)
-{
- struct uudecode *uudecode;
- void *out_buff;
- void *in_buff;
-
- self->code = ARCHIVE_FILTER_UU;
- self->name = "uu";
- self->read = uudecode_filter_read;
- self->skip = NULL; /* not supported */
- self->close = uudecode_filter_close;
-
- uudecode = (struct uudecode *)calloc(sizeof(*uudecode), 1);
- out_buff = malloc(OUT_BUFF_SIZE);
- in_buff = malloc(IN_BUFF_SIZE);
- if (uudecode == NULL || out_buff == NULL || in_buff == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
- "Can't allocate data for uudecode");
- free(uudecode);
- free(out_buff);
- free(in_buff);
- return (ARCHIVE_FATAL);
- }
-
- self->data = uudecode;
- uudecode->in_buff = in_buff;
- uudecode->in_cnt = 0;
- uudecode->in_allocated = IN_BUFF_SIZE;
- uudecode->out_buff = out_buff;
- uudecode->state = ST_FIND_HEAD;
-
- return (ARCHIVE_OK);
-}
-
-static int
-ensure_in_buff_size(struct archive_read_filter *self,
- struct uudecode *uudecode, size_t size)
-{
-
- if (size > uudecode->in_allocated) {
- unsigned char *ptr;
- size_t newsize;
-
- /*
- * Calculate a new buffer size for in_buff.
- * Increase its value until it has enough size we need.
- */
- newsize = uudecode->in_allocated;
- do {
- if (newsize < IN_BUFF_SIZE*32)
- newsize <<= 1;
- else
- newsize += IN_BUFF_SIZE;
- } while (size > newsize);
- /* Allocate the new buffer. */
- ptr = malloc(newsize);
- if (ptr == NULL) {
- free(ptr);
- archive_set_error(&self->archive->archive,
- ENOMEM,
- "Can't allocate data for uudecode");
- return (ARCHIVE_FATAL);
- }
- /* Move the remaining data in in_buff into the new buffer. */
- if (uudecode->in_cnt)
- memmove(ptr, uudecode->in_buff, uudecode->in_cnt);
- /* Replace in_buff with the new buffer. */
- free(uudecode->in_buff);
- uudecode->in_buff = ptr;
- uudecode->in_allocated = newsize;
- }
- return (ARCHIVE_OK);
-}
-
-static ssize_t
-uudecode_filter_read(struct archive_read_filter *self, const void **buff)
-{
- struct uudecode *uudecode;
- const unsigned char *b, *d;
- unsigned char *out;
- ssize_t avail_in, ravail;
- ssize_t used;
- ssize_t total;
- ssize_t len, llen, nl;
-
- uudecode = (struct uudecode *)self->data;
-
-read_more:
- d = __archive_read_filter_ahead(self->upstream, 1, &avail_in);
- if (d == NULL && avail_in < 0)
- return (ARCHIVE_FATAL);
- /* Quiet a code analyzer; make sure avail_in must be zero
- * when d is NULL. */
- if (d == NULL)
- avail_in = 0;
- used = 0;
- total = 0;
- out = uudecode->out_buff;
- ravail = avail_in;
- if (uudecode->state == ST_IGNORE) {
- used = avail_in;
- goto finish;
- }
- if (uudecode->in_cnt) {
- /*
- * If there is remaining data which is saved by
- * previous calling, use it first.
- */
- if (ensure_in_buff_size(self, uudecode,
- avail_in + uudecode->in_cnt) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- memcpy(uudecode->in_buff + uudecode->in_cnt,
- d, avail_in);
- d = uudecode->in_buff;
- avail_in += uudecode->in_cnt;
- uudecode->in_cnt = 0;
- }
- for (;used < avail_in; d += llen, used += llen) {
- int64_t l, body;
-
- b = d;
- len = get_line(b, avail_in - used, &nl);
- if (len < 0) {
- /* Non-ascii character is found. */
- if (uudecode->state == ST_FIND_HEAD &&
- (uudecode->total > 0 || total > 0)) {
- uudecode->state = ST_IGNORE;
- used = avail_in;
- goto finish;
- }
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Insufficient compressed data");
- return (ARCHIVE_FATAL);
- }
- llen = len;
- if (nl == 0) {
- /*
- * Save remaining data which does not contain
- * NL('\n','\r').
- */
- if (ensure_in_buff_size(self, uudecode, len)
- != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- if (uudecode->in_buff != b)
- memmove(uudecode->in_buff, b, len);
- uudecode->in_cnt = (int)len;
- if (total == 0) {
- /* Do not return 0; it means end-of-file.
- * We should try to read bytes more. */
- __archive_read_filter_consume(
- self->upstream, ravail);
- goto read_more;
- }
- break;
- }
- switch (uudecode->state) {
- default:
- case ST_FIND_HEAD:
- /* Do not read more than UUENCODE_BID_MAX_READ bytes */
- if (total + len >= UUENCODE_BID_MAX_READ) {
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid format data");
- return (ARCHIVE_FATAL);
- }
- if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0)
- l = 6;
- else if (len - nl >= 18 &&
- memcmp(b, "begin-base64 ", 13) == 0)
- l = 13;
- else
- l = 0;
- if (l != 0 && b[l] >= '0' && b[l] <= '7' &&
- b[l+1] >= '0' && b[l+1] <= '7' &&
- b[l+2] >= '0' && b[l+2] <= '7' && b[l+3] == ' ') {
- if (l == 6)
- uudecode->state = ST_READ_UU;
- else
- uudecode->state = ST_READ_BASE64;
- }
- break;
- case ST_READ_UU:
- if (total + len * 2 > OUT_BUFF_SIZE)
- goto finish;
- body = len - nl;
- if (!uuchar[*b] || body <= 0) {
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Insufficient compressed data");
- return (ARCHIVE_FATAL);
- }
- /* Get length of undecoded bytes of curent line. */
- l = UUDECODE(*b++);
- body--;
- if (l > body) {
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Insufficient compressed data");
- return (ARCHIVE_FATAL);
- }
- if (l == 0) {
- uudecode->state = ST_UUEND;
- break;
- }
- while (l > 0) {
- int n = 0;
-
- if (l > 0) {
- if (!uuchar[b[0]] || !uuchar[b[1]])
- break;
- n = UUDECODE(*b++) << 18;
- n |= UUDECODE(*b++) << 12;
- *out++ = n >> 16; total++;
- --l;
- }
- if (l > 0) {
- if (!uuchar[b[0]])
- break;
- n |= UUDECODE(*b++) << 6;
- *out++ = (n >> 8) & 0xFF; total++;
- --l;
- }
- if (l > 0) {
- if (!uuchar[b[0]])
- break;
- n |= UUDECODE(*b++);
- *out++ = n & 0xFF; total++;
- --l;
- }
- }
- if (l) {
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Insufficient compressed data");
- return (ARCHIVE_FATAL);
- }
- break;
- case ST_UUEND:
- if (len - nl == 3 && memcmp(b, "end ", 3) == 0)
- uudecode->state = ST_FIND_HEAD;
- else {
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Insufficient compressed data");
- return (ARCHIVE_FATAL);
- }
- break;
- case ST_READ_BASE64:
- if (total + len * 2 > OUT_BUFF_SIZE)
- goto finish;
- l = len - nl;
- if (l >= 3 && b[0] == '=' && b[1] == '=' &&
- b[2] == '=') {
- uudecode->state = ST_FIND_HEAD;
- break;
- }
- while (l > 0) {
- int n = 0;
-
- if (l > 0) {
- if (!base64[b[0]] || !base64[b[1]])
- break;
- n = base64num[*b++] << 18;
- n |= base64num[*b++] << 12;
- *out++ = n >> 16; total++;
- l -= 2;
- }
- if (l > 0) {
- if (*b == '=')
- break;
- if (!base64[*b])
- break;
- n |= base64num[*b++] << 6;
- *out++ = (n >> 8) & 0xFF; total++;
- --l;
- }
- if (l > 0) {
- if (*b == '=')
- break;
- if (!base64[*b])
- break;
- n |= base64num[*b++];
- *out++ = n & 0xFF; total++;
- --l;
- }
- }
- if (l && *b != '=') {
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Insufficient compressed data");
- return (ARCHIVE_FATAL);
- }
- break;
- }
- }
-finish:
- if (ravail < avail_in)
- used -= avail_in - ravail;
- __archive_read_filter_consume(self->upstream, used);
-
- *buff = uudecode->out_buff;
- uudecode->total += total;
- return (total);
-}
-
-static int
-uudecode_filter_close(struct archive_read_filter *self)
-{
- struct uudecode *uudecode;
-
- uudecode = (struct uudecode *)self->data;
- free(uudecode->in_buff);
- free(uudecode->out_buff);
- free(uudecode);
-
- return (ARCHIVE_OK);
-}
-
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_filter_xz.c b/3rdparty/libarchive/libarchive/archive_read_support_filter_xz.c
index 15824b1d..11807cf6 100644
--- a/3rdparty/libarchive/libarchive/archive_read_support_filter_xz.c
+++ b/3rdparty/libarchive/libarchive/archive_read_support_filter_xz.c
@@ -43,8 +43,6 @@ __FBSDID("$FreeBSD$");
#endif
#if HAVE_LZMA_H
#include <lzma.h>
-#elif HAVE_LZMADEC_H
-#include <lzmadec.h>
#endif
#include "archive.h"
@@ -82,19 +80,6 @@ static ssize_t xz_filter_read(struct archive_read_filter *, const void **);
static int xz_filter_close(struct archive_read_filter *);
static int xz_lzma_bidder_init(struct archive_read_filter *);
-#elif HAVE_LZMADEC_H && HAVE_LIBLZMADEC
-
-struct private_data {
- lzmadec_stream stream;
- unsigned char *out_block;
- size_t out_block_size;
- int64_t total_out;
- char eof; /* True = found end of compressed data. */
-};
-
-/* Lzma-only filter */
-static ssize_t lzma_filter_read(struct archive_read_filter *, const void **);
-static int lzma_filter_close(struct archive_read_filter *);
#endif
/*
@@ -178,8 +163,6 @@ archive_read_support_filter_lzma(struct archive *_a)
bidder->free = NULL;
#if HAVE_LZMA_H && HAVE_LIBLZMA
return (ARCHIVE_OK);
-#elif HAVE_LZMADEC_H && HAVE_LIBLZMADEC
- return (ARCHIVE_OK);
#else
archive_set_error(_a, ARCHIVE_ERRNO_MISC,
"Using external lzma program for lzma decompression");
@@ -310,7 +293,7 @@ lzma_bidder_bid(struct archive_read_filter_bidder *self,
/* Second through fifth bytes are dictionary size, stored in
* little-endian order. The minimum dictionary size is
* 1 << 12(4KiB) which the lzma of LZMA SDK uses with option
- * -d12 and the maxinam dictionary size is 1 << 27(128MiB)
+ * -d12 and the maximum dictionary size is 1 << 27(128MiB)
* which the one uses with option -d27.
* NOTE: A comment of LZMA SDK source code says this dictionary
* range is from 1 << 12 to 1 << 30. */
@@ -601,9 +584,7 @@ lzip_init(struct archive_read_filter *self)
return (ARCHIVE_FATAL);
}
ret = lzma_raw_decoder(&(state->stream), filters);
-#if LZMA_VERSION < 50000030
free(filters[0].options);
-#endif
if (ret != LZMA_OK) {
set_error(self, ret);
return (ARCHIVE_FATAL);
@@ -627,7 +608,7 @@ lzip_tail(struct archive_read_filter *self)
f = __archive_read_filter_ahead(self->upstream, tail, &avail_in);
if (f == NULL && avail_in < 0)
return (ARCHIVE_FATAL);
- if (avail_in < tail) {
+ if (f == NULL || avail_in < tail) {
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
"Lzip: Remaining data is less bytes");
return (ARCHIVE_FAILED);
@@ -763,175 +744,6 @@ xz_filter_close(struct archive_read_filter *self)
#else
-#if HAVE_LZMADEC_H && HAVE_LIBLZMADEC
-
-/*
- * If we have the older liblzmadec library, then we can handle
- * LZMA streams but not XZ streams.
- */
-
-/*
- * Setup the callbacks.
- */
-static int
-lzma_bidder_init(struct archive_read_filter *self)
-{
- static const size_t out_block_size = 64 * 1024;
- void *out_block;
- struct private_data *state;
- ssize_t ret, avail_in;
-
- self->code = ARCHIVE_FILTER_LZMA;
- self->name = "lzma";
-
- state = (struct private_data *)calloc(sizeof(*state), 1);
- out_block = (unsigned char *)malloc(out_block_size);
- if (state == NULL || out_block == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
- "Can't allocate data for lzma decompression");
- free(out_block);
- free(state);
- return (ARCHIVE_FATAL);
- }
-
- self->data = state;
- state->out_block_size = out_block_size;
- state->out_block = out_block;
- self->read = lzma_filter_read;
- self->skip = NULL; /* not supported */
- self->close = lzma_filter_close;
-
- /* Prime the lzma library with 18 bytes of input. */
- state->stream.next_in = (unsigned char *)(uintptr_t)
- __archive_read_filter_ahead(self->upstream, 18, &avail_in);
- if (state->stream.next_in == NULL)
- return (ARCHIVE_FATAL);
- state->stream.avail_in = avail_in;
- state->stream.next_out = state->out_block;
- state->stream.avail_out = state->out_block_size;
-
- /* Initialize compression library. */
- ret = lzmadec_init(&(state->stream));
- __archive_read_filter_consume(self->upstream,
- avail_in - state->stream.avail_in);
- if (ret == LZMADEC_OK)
- return (ARCHIVE_OK);
-
- /* Library setup failed: Clean up. */
- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
- "Internal error initializing lzma library");
-
- /* Override the error message if we know what really went wrong. */
- switch (ret) {
- case LZMADEC_HEADER_ERROR:
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library: "
- "invalid header");
- break;
- case LZMADEC_MEM_ERROR:
- archive_set_error(&self->archive->archive, ENOMEM,
- "Internal error initializing compression library: "
- "out of memory");
- break;
- }
-
- free(state->out_block);
- free(state);
- self->data = NULL;
- return (ARCHIVE_FATAL);
-}
-
-/*
- * Return the next block of decompressed data.
- */
-static ssize_t
-lzma_filter_read(struct archive_read_filter *self, const void **p)
-{
- struct private_data *state;
- size_t decompressed;
- ssize_t avail_in, ret;
-
- state = (struct private_data *)self->data;
-
- /* Empty our output buffer. */
- state->stream.next_out = state->out_block;
- state->stream.avail_out = state->out_block_size;
-
- /* Try to fill the output buffer. */
- while (state->stream.avail_out > 0 && !state->eof) {
- state->stream.next_in = (unsigned char *)(uintptr_t)
- __archive_read_filter_ahead(self->upstream, 1, &avail_in);
- if (state->stream.next_in == NULL && avail_in < 0) {
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "truncated lzma input");
- return (ARCHIVE_FATAL);
- }
- state->stream.avail_in = avail_in;
-
- /* Decompress as much as we can in one pass. */
- ret = lzmadec_decode(&(state->stream), avail_in == 0);
- switch (ret) {
- case LZMADEC_STREAM_END: /* Found end of stream. */
- state->eof = 1;
- /* FALL THROUGH */
- case LZMADEC_OK: /* Decompressor made some progress. */
- __archive_read_filter_consume(self->upstream,
- avail_in - state->stream.avail_in);
- break;
- case LZMADEC_BUF_ERROR: /* Insufficient input data? */
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Insufficient compressed data");
- return (ARCHIVE_FATAL);
- default:
- /* Return an error. */
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Lzma decompression failed");
- return (ARCHIVE_FATAL);
- }
- }
-
- decompressed = state->stream.next_out - state->out_block;
- state->total_out += decompressed;
- if (decompressed == 0)
- *p = NULL;
- else
- *p = state->out_block;
- return (decompressed);
-}
-
-/*
- * Clean up the decompressor.
- */
-static int
-lzma_filter_close(struct archive_read_filter *self)
-{
- struct private_data *state;
- int ret;
-
- state = (struct private_data *)self->data;
- ret = ARCHIVE_OK;
- switch (lzmadec_end(&(state->stream))) {
- case LZMADEC_OK:
- break;
- default:
- archive_set_error(&(self->archive->archive),
- ARCHIVE_ERRNO_MISC,
- "Failed to clean up %s compressor",
- self->archive->archive.compression_name);
- ret = ARCHIVE_FATAL;
- }
-
- free(state->out_block);
- free(state);
- return (ret);
-}
-
-#else
-
/*
*
* If we have no suitable library on this system, we can't actually do
@@ -953,9 +765,6 @@ lzma_bidder_init(struct archive_read_filter *self)
return (r);
}
-#endif /* HAVE_LZMADEC_H */
-
-
static int
xz_bidder_init(struct archive_read_filter *self)
{
@@ -984,5 +793,4 @@ lzip_bidder_init(struct archive_read_filter *self)
return (r);
}
-
#endif /* HAVE_LZMA_H */
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_format_7zip.c b/3rdparty/libarchive/libarchive/archive_read_support_format_7zip.c
deleted file mode 100644
index 194b8d51..00000000
--- a/3rdparty/libarchive/libarchive/archive_read_support_format_7zip.c
+++ /dev/null
@@ -1,3748 +0,0 @@
-/*-
- * 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"
-__FBSDID("$FreeBSD$");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_BZLIB_H
-#include <bzlib.h>
-#endif
-#ifdef HAVE_LZMA_H
-#include <lzma.h>
-#endif
-#ifdef HAVE_ZLIB_H
-#include <zlib.h>
-#endif
-
-#include "archive.h"
-#include "archive_entry.h"
-#include "archive_entry_locale.h"
-#include "archive_ppmd7_private.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-#include "archive_endian.h"
-
-#ifndef HAVE_ZLIB_H
-#include "archive_crc32.h"
-#endif
-
-#define _7ZIP_SIGNATURE "7z\xBC\xAF\x27\x1C"
-#define SFX_MIN_ADDR 0x27000
-#define SFX_MAX_ADDR 0x60000
-
-
-/*
- * Codec ID
- */
-#define _7Z_COPY 0
-#define _7Z_LZMA 0x030101
-#define _7Z_LZMA2 0x21
-#define _7Z_DEFLATE 0x040108
-#define _7Z_BZ2 0x040202
-#define _7Z_PPMD 0x030401
-#define _7Z_DELTA 0x03
-#define _7Z_CRYPTO 0x06F10701
-#define _7Z_X86 0x03030103
-#define _7Z_X86_BCJ2 0x0303011B
-#define _7Z_POWERPC 0x03030205
-#define _7Z_IA64 0x03030401
-#define _7Z_ARM 0x03030501
-#define _7Z_ARMTHUMB 0x03030701
-#define _7Z_SPARC 0x03030805
-
-/*
- * 7-Zip header property IDs.
- */
-#define kEnd 0x00
-#define kHeader 0x01
-#define kArchiveProperties 0x02
-#define kAdditionalStreamsInfo 0x03
-#define kMainStreamsInfo 0x04
-#define kFilesInfo 0x05
-#define kPackInfo 0x06
-#define kUnPackInfo 0x07
-#define kSubStreamsInfo 0x08
-#define kSize 0x09
-#define kCRC 0x0A
-#define kFolder 0x0B
-#define kCodersUnPackSize 0x0C
-#define kNumUnPackStream 0x0D
-#define kEmptyStream 0x0E
-#define kEmptyFile 0x0F
-#define kAnti 0x10
-#define kName 0x11
-#define kCTime 0x12
-#define kATime 0x13
-#define kMTime 0x14
-#define kAttributes 0x15
-#define kEncodedHeader 0x17
-
-struct _7z_digests {
- unsigned char *defineds;
- uint32_t *digests;
-};
-
-
-struct _7z_folder {
- uint64_t numCoders;
- struct _7z_coder {
- unsigned long codec;
- uint64_t numInStreams;
- uint64_t numOutStreams;
- uint64_t propertiesSize;
- unsigned char *properties;
- } *coders;
- uint64_t numBindPairs;
- struct {
- uint64_t inIndex;
- uint64_t outIndex;
- } *bindPairs;
- uint64_t numPackedStreams;
- uint64_t *packedStreams;
- uint64_t numInStreams;
- uint64_t numOutStreams;
- uint64_t *unPackSize;
- unsigned char digest_defined;
- uint32_t digest;
- uint64_t numUnpackStreams;
- uint32_t packIndex;
- /* Unoperated bytes. */
- uint64_t skipped_bytes;
-};
-
-struct _7z_coders_info {
- uint64_t numFolders;
- struct _7z_folder *folders;
- uint64_t dataStreamIndex;
-};
-
-struct _7z_pack_info {
- uint64_t pos;
- uint64_t numPackStreams;
- uint64_t *sizes;
- struct _7z_digests digest;
- /* Calculated from pos and numPackStreams. */
- uint64_t *positions;
-};
-
-struct _7z_substream_info {
- size_t unpack_streams;
- uint64_t *unpackSizes;
- unsigned char *digestsDefined;
- uint32_t *digests;
-};
-
-struct _7z_stream_info {
- struct _7z_pack_info pi;
- struct _7z_coders_info ci;
- struct _7z_substream_info ss;
-};
-
-struct _7z_header_info {
- uint64_t dataIndex;
-
- unsigned char *emptyStreamBools;
- unsigned char *emptyFileBools;
- unsigned char *antiBools;
- unsigned char *attrBools;
-};
-
-struct _7zip_entry {
- size_t name_len;
- unsigned char *utf16name;
-#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
- const wchar_t *wname;
-#endif
- uint32_t folderIndex;
- uint32_t ssIndex;
- unsigned flg;
-#define MTIME_IS_SET (1<<0)
-#define ATIME_IS_SET (1<<1)
-#define CTIME_IS_SET (1<<2)
-#define CRC32_IS_SET (1<<3)
-#define HAS_STREAM (1<<4)
-
- time_t mtime;
- time_t atime;
- time_t ctime;
- long mtime_ns;
- long atime_ns;
- long ctime_ns;
- uint32_t mode;
- uint32_t attr;
-};
-
-struct _7zip {
- /* Structural information about the archive. */
- struct _7z_stream_info si;
-
- int header_is_being_read;
- int header_is_encoded;
- uint64_t header_bytes_remaining;
- unsigned long header_crc32;
- /* Header offset to check that reading pointes of the file contens
- * will not exceed the header. */
- uint64_t header_offset;
- /* Base offset of the archive file for a seek in case reading SFX. */
- uint64_t seek_base;
-
- /* List of entries */
- size_t entries_remaining;
- uint64_t numFiles;
- struct _7zip_entry *entries;
- struct _7zip_entry *entry;
- unsigned char *entry_names;
-
- /* entry_bytes_remaining is the number of bytes we expect. */
- int64_t entry_offset;
- uint64_t entry_bytes_remaining;
-
- /* Running CRC32 of the decompressed data */
- unsigned long entry_crc32;
-
- /* Flags to mark progress of decompression. */
- char end_of_entry;
-
- /* Uncompressed buffer control. */
-#define UBUFF_SIZE (64 * 1024)
- unsigned char *uncompressed_buffer;
- unsigned char *uncompressed_buffer_pointer;
- size_t uncompressed_buffer_size;
- size_t uncompressed_buffer_bytes_remaining;
-
- /* Offset of the compressed data. */
- int64_t stream_offset;
-
- /*
- * Decompressing control data.
- */
- unsigned folder_index;
- uint64_t folder_outbytes_remaining;
- unsigned pack_stream_index;
- unsigned pack_stream_remaining;
- uint64_t pack_stream_inbytes_remaining;
- size_t pack_stream_bytes_unconsumed;
-
- /* The codec information of a folder. */
- unsigned long codec;
- unsigned long codec2;
-
- /*
- * Decompressor controllers.
- */
- /* Decording LZMA1 and LZMA2 data. */
-#ifdef HAVE_LZMA_H
- lzma_stream lzstream;
- int lzstream_valid;
-#endif
- /* Decording bzip2 data. */
-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
- bz_stream bzstream;
- int bzstream_valid;
-#endif
- /* Decording deflate data. */
-#ifdef HAVE_ZLIB_H
- z_stream stream;
- int stream_valid;
-#endif
- /* Decording PPMd data. */
- int ppmd7_stat;
- CPpmd7 ppmd7_context;
- CPpmd7z_RangeDec range_dec;
- IByteIn bytein;
- struct {
- const unsigned char *next_in;
- int64_t avail_in;
- int64_t total_in;
- unsigned char *next_out;
- int64_t avail_out;
- int64_t total_out;
- int overconsumed;
- } ppstream;
- int ppmd7_valid;
-
- /* Decoding BCJ and BCJ2 data. */
- uint32_t bcj_state;
- size_t odd_bcj_size;
- unsigned char odd_bcj[4];
- /* Decoding BCJ data. */
- size_t bcj_prevPosT;
- uint32_t bcj_prevMask;
- uint32_t bcj_ip;
-
- /* Decoding BCJ2 data. */
- size_t main_stream_bytes_remaining;
- unsigned char *sub_stream_buff[3];
- size_t sub_stream_size[3];
- size_t sub_stream_bytes_remaining[3];
- unsigned char *tmp_stream_buff;
- size_t tmp_stream_buff_size;
- size_t tmp_stream_bytes_avail;
- size_t tmp_stream_bytes_remaining;
-#ifdef _LZMA_PROB32
-#define CProb uint32_t
-#else
-#define CProb uint16_t
-#endif
- CProb bcj2_p[256 + 2];
- uint8_t bcj2_prevByte;
- uint32_t bcj2_range;
- uint32_t bcj2_code;
- uint64_t bcj2_outPos;
-
- /* Filename character-set conversion data. */
- struct archive_string_conv *sconv;
-
- char format_name[64];
-};
-
-static int archive_read_format_7zip_bid(struct archive_read *, int);
-static int archive_read_format_7zip_cleanup(struct archive_read *);
-static int archive_read_format_7zip_read_data(struct archive_read *,
- const void **, size_t *, int64_t *);
-static int archive_read_format_7zip_read_data_skip(struct archive_read *);
-static int archive_read_format_7zip_read_header(struct archive_read *,
- struct archive_entry *);
-static int check_7zip_header_in_sfx(const char *);
-static unsigned long decode_codec_id(const unsigned char *, size_t);
-static int decode_encoded_header_info(struct archive_read *,
- struct _7z_stream_info *);
-static int decompress(struct archive_read *, struct _7zip *,
- void *, size_t *, const void *, size_t *);
-static ssize_t extract_pack_stream(struct archive_read *, size_t);
-static void fileTimeToUtc(uint64_t, time_t *, long *);
-static uint64_t folder_uncompressed_size(struct _7z_folder *);
-static void free_CodersInfo(struct _7z_coders_info *);
-static void free_Digest(struct _7z_digests *);
-static void free_Folder(struct _7z_folder *);
-static void free_Header(struct _7z_header_info *);
-static void free_PackInfo(struct _7z_pack_info *);
-static void free_StreamsInfo(struct _7z_stream_info *);
-static void free_SubStreamsInfo(struct _7z_substream_info *);
-static int free_decompression(struct archive_read *, struct _7zip *);
-static ssize_t get_uncompressed_data(struct archive_read *, const void **,
- size_t, size_t);
-static const unsigned char * header_bytes(struct archive_read *, size_t);
-static int init_decompression(struct archive_read *, struct _7zip *,
- const struct _7z_coder *, const struct _7z_coder *);
-static int parse_7zip_uint64(struct archive_read *, uint64_t *);
-static int read_Bools(struct archive_read *, unsigned char *, size_t);
-static int read_CodersInfo(struct archive_read *,
- struct _7z_coders_info *);
-static int read_Digests(struct archive_read *, struct _7z_digests *,
- size_t);
-static int read_Folder(struct archive_read *, struct _7z_folder *);
-static int read_Header(struct archive_read *, struct _7z_header_info *,
- int);
-static int read_PackInfo(struct archive_read *, struct _7z_pack_info *);
-static int read_StreamsInfo(struct archive_read *,
- struct _7z_stream_info *);
-static int read_SubStreamsInfo(struct archive_read *,
- struct _7z_substream_info *, struct _7z_folder *, size_t);
-static int read_Times(struct archive_read *, struct _7z_header_info *,
- int);
-static void read_consume(struct archive_read *);
-static ssize_t read_stream(struct archive_read *, const void **, size_t,
- size_t);
-static int seek_pack(struct archive_read *);
-static int64_t skip_stream(struct archive_read *, size_t);
-static int skip_sfx(struct archive_read *, ssize_t);
-static int slurp_central_directory(struct archive_read *, struct _7zip *,
- struct _7z_header_info *);
-static int setup_decode_folder(struct archive_read *, struct _7z_folder *,
- int);
-static void x86_Init(struct _7zip *);
-static size_t x86_Convert(struct _7zip *, uint8_t *, size_t);
-static ssize_t Bcj2_Decode(struct _7zip *, uint8_t *, size_t);
-
-
-int
-archive_read_support_format_7zip(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct _7zip *zip;
- int r;
-
- archive_check_magic(_a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_NEW, "archive_read_support_format_7zip");
-
- zip = calloc(1, sizeof(*zip));
- if (zip == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate 7zip data");
- return (ARCHIVE_FATAL);
- }
-
- r = __archive_read_register_format(a,
- zip,
- "7zip",
- archive_read_format_7zip_bid,
- NULL,
- archive_read_format_7zip_read_header,
- archive_read_format_7zip_read_data,
- archive_read_format_7zip_read_data_skip,
- NULL,
- archive_read_format_7zip_cleanup);
-
- if (r != ARCHIVE_OK)
- free(zip);
- return (ARCHIVE_OK);
-}
-
-static int
-archive_read_format_7zip_bid(struct archive_read *a, int best_bid)
-{
- const char *p;
-
- /* If someone has already bid more than 32, then avoid
- trashing the look-ahead buffers with a seek. */
- if (best_bid > 32)
- return (-1);
-
- if ((p = __archive_read_ahead(a, 6, NULL)) == NULL)
- return (0);
-
- /* If first six bytes are the 7-Zip signature,
- * return the bid right now. */
- if (memcmp(p, _7ZIP_SIGNATURE, 6) == 0)
- return (48);
-
- /*
- * It may a 7-Zip SFX archive file. If first two bytes are
- * 'M' and 'Z' available on Windows or first four bytes are
- * "\x7F\x45LF" available on posix like system, seek the 7-Zip
- * signature. Although we will perform a seek when reading
- * a header, what we do not use __archive_read_seek() here is
- * due to a bidding performance.
- */
- if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {
- ssize_t offset = SFX_MIN_ADDR;
- ssize_t window = 4096;
- ssize_t bytes_avail;
- while (offset + window <= (SFX_MAX_ADDR)) {
- const char *buff = __archive_read_ahead(a,
- offset + window, &bytes_avail);
- if (buff == NULL) {
- /* Remaining bytes are less than window. */
- window >>= 1;
- if (window < 0x40)
- return (0);
- continue;
- }
- p = buff + offset;
- while (p + 32 < buff + bytes_avail) {
- int step = check_7zip_header_in_sfx(p);
- if (step == 0)
- return (48);
- p += step;
- }
- offset = p - buff;
- }
- }
- return (0);
-}
-
-static int
-check_7zip_header_in_sfx(const char *p)
-{
- switch ((unsigned char)p[5]) {
- case 0x1C:
- if (memcmp(p, _7ZIP_SIGNATURE, 6) != 0)
- return (6);
- /*
- * Test the CRC because its extraction code has 7-Zip
- * Magic Code, so we should do this in order not to
- * make a mis-detection.
- */
- if (crc32(0, (const unsigned char *)p + 12, 20)
- != archive_le32dec(p + 8))
- return (6);
- /* Hit the header! */
- return (0);
- case 0x37: return (5);
- case 0x7A: return (4);
- case 0xBC: return (3);
- case 0xAF: return (2);
- case 0x27: return (1);
- default: return (6);
- }
-}
-
-static int
-skip_sfx(struct archive_read *a, ssize_t bytes_avail)
-{
- const void *h;
- const char *p, *q;
- size_t skip, offset;
- ssize_t bytes, window;
-
- /*
- * If bytes_avail > SFX_MIN_ADDR we do not have to call
- * __archive_read_seek() at this time since we have
- * alredy had enough data.
- */
- if (bytes_avail > SFX_MIN_ADDR)
- __archive_read_consume(a, SFX_MIN_ADDR);
- else if (__archive_read_seek(a, SFX_MIN_ADDR, SEEK_SET) < 0)
- return (ARCHIVE_FATAL);
-
- offset = 0;
- window = 1;
- while (offset + window <= SFX_MAX_ADDR - SFX_MIN_ADDR) {
- h = __archive_read_ahead(a, window, &bytes);
- if (h == NULL) {
- /* Remaining bytes are less than window. */
- window >>= 1;
- if (window < 0x40)
- goto fatal;
- continue;
- }
- if (bytes < 6) {
- /* This case might happen when window == 1. */
- window = 4096;
- continue;
- }
- p = (const char *)h;
- q = p + bytes;
-
- /*
- * Scan ahead until we find something that looks
- * like the 7-Zip header.
- */
- while (p + 32 < q) {
- int step = check_7zip_header_in_sfx(p);
- if (step == 0) {
- struct _7zip *zip =
- (struct _7zip *)a->format->data;
- skip = p - (const char *)h;
- __archive_read_consume(a, skip);
- zip->seek_base = SFX_MIN_ADDR + offset + skip;
- return (ARCHIVE_OK);
- }
- p += step;
- }
- skip = p - (const char *)h;
- __archive_read_consume(a, skip);
- offset += skip;
- if (window == 1)
- window = 4096;
- }
-fatal:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Couldn't find out 7-Zip header");
- return (ARCHIVE_FATAL);
-}
-
-static int
-archive_read_format_7zip_read_header(struct archive_read *a,
- struct archive_entry *entry)
-{
- struct _7zip *zip = (struct _7zip *)a->format->data;
- struct _7zip_entry *zip_entry;
- int r, ret = ARCHIVE_OK;
-
- a->archive.archive_format = ARCHIVE_FORMAT_7ZIP;
- if (a->archive.archive_format_name == NULL)
- a->archive.archive_format_name = "7-Zip";
-
- if (zip->entries == NULL) {
- struct _7z_header_info header;
-
- memset(&header, 0, sizeof(header));
- r = slurp_central_directory(a, zip, &header);
- free_Header(&header);
- if (r != ARCHIVE_OK)
- return (r);
- zip->entries_remaining = (size_t)zip->numFiles;
- zip->entry = zip->entries;
- } else {
- ++zip->entry;
- }
- zip_entry = zip->entry;
-
- if (zip->entries_remaining <= 0)
- return ARCHIVE_EOF;
- --zip->entries_remaining;
-
- zip->entry_offset = 0;
- zip->end_of_entry = 0;
- zip->entry_crc32 = crc32(0, NULL, 0);
-
- /* Setup a string conversion for a filename. */
- if (zip->sconv == NULL) {
- zip->sconv = archive_string_conversion_from_charset(
- &a->archive, "UTF-16LE", 1);
- if (zip->sconv == NULL)
- return (ARCHIVE_FATAL);
- }
-
- if (archive_entry_copy_pathname_l(entry,
- (const char *)zip_entry->utf16name,
- zip_entry->name_len, zip->sconv) != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Pathname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Pathname cannot be converted "
- "from %s to current locale.",
- archive_string_conversion_charset_name(zip->sconv));
- ret = ARCHIVE_WARN;
- }
-
- /* Populate some additional entry fields: */
- archive_entry_set_mode(entry, zip_entry->mode);
- if (zip_entry->flg & MTIME_IS_SET)
- archive_entry_set_mtime(entry, zip_entry->mtime,
- zip_entry->mtime_ns);
- if (zip_entry->flg & CTIME_IS_SET)
- archive_entry_set_ctime(entry, zip_entry->ctime,
- zip_entry->ctime_ns);
- if (zip_entry->flg & ATIME_IS_SET)
- archive_entry_set_atime(entry, zip_entry->atime,
- zip_entry->atime_ns);
- if (zip_entry->ssIndex != (uint32_t)-1) {
- zip->entry_bytes_remaining =
- zip->si.ss.unpackSizes[zip_entry->ssIndex];
- archive_entry_set_size(entry, zip->entry_bytes_remaining);
- } else {
- zip->entry_bytes_remaining = 0;
- archive_entry_set_size(entry, 0);
- }
-
- /* If there's no body, force read_data() to return EOF immediately. */
- if (zip->entry_bytes_remaining < 1)
- zip->end_of_entry = 1;
-
- if ((zip_entry->mode & AE_IFMT) == AE_IFLNK) {
- unsigned char *symname = NULL;
- size_t symsize = 0;
-
- /*
- * Symbolic-name is recorded as its contents. We have to
- * read the contents at this time.
- */
- while (zip->entry_bytes_remaining > 0) {
- const void *buff;
- unsigned char *mem;
- size_t size;
- int64_t offset;
-
- r = archive_read_format_7zip_read_data(a, &buff,
- &size, &offset);
- if (r < ARCHIVE_WARN) {
- free(symname);
- return (r);
- }
- mem = realloc(symname, symsize + size + 1);
- if (mem == NULL) {
- free(symname);
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Symname");
- return (ARCHIVE_FATAL);
- }
- symname = mem;
- memcpy(symname+symsize, buff, size);
- symsize += size;
- }
- if (symsize == 0) {
- /* If there is no synname, handle it as a regular
- * file. */
- zip_entry->mode &= ~AE_IFMT;
- zip_entry->mode |= AE_IFREG;
- archive_entry_set_mode(entry, zip_entry->mode);
- } else {
- symname[symsize] = '\0';
- archive_entry_copy_symlink(entry,
- (const char *)symname);
- }
- free(symname);
- archive_entry_set_size(entry, 0);
- }
-
- /* Set up a more descriptive format name. */
- sprintf(zip->format_name, "7-Zip");
- a->archive.archive_format_name = zip->format_name;
-
- return (ret);
-}
-
-static int
-archive_read_format_7zip_read_data(struct archive_read *a,
- const void **buff, size_t *size, int64_t *offset)
-{
- struct _7zip *zip;
- ssize_t bytes;
- int ret = ARCHIVE_OK;
-
- zip = (struct _7zip *)(a->format->data);
-
- if (zip->pack_stream_bytes_unconsumed)
- read_consume(a);
-
- *offset = zip->entry_offset;
- *size = 0;
- *buff = NULL;
- /*
- * If we hit end-of-entry last time, clean up and return
- * ARCHIVE_EOF this time.
- */
- if (zip->end_of_entry)
- return (ARCHIVE_EOF);
-
- bytes = read_stream(a, buff,
- (size_t)zip->entry_bytes_remaining, 0);
- if (bytes < 0)
- return ((int)bytes);
- if (bytes == 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated 7-Zip file body");
- return (ARCHIVE_FATAL);
- }
- zip->entry_bytes_remaining -= bytes;
- if (zip->entry_bytes_remaining == 0)
- zip->end_of_entry = 1;
-
- /* Update checksum */
- if ((zip->entry->flg & CRC32_IS_SET) && bytes)
- zip->entry_crc32 = crc32(zip->entry_crc32, *buff,
- (unsigned)bytes);
-
- /* If we hit the end, swallow any end-of-data marker. */
- if (zip->end_of_entry) {
- /* Check computed CRC against file contents. */
- if ((zip->entry->flg & CRC32_IS_SET) &&
- zip->si.ss.digests[zip->entry->ssIndex] !=
- zip->entry_crc32) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "7-Zip bad CRC: 0x%lx should be 0x%lx",
- (unsigned long)zip->entry_crc32,
- (unsigned long)zip->si.ss.digests[
- zip->entry->ssIndex]);
- ret = ARCHIVE_WARN;
- }
- }
-
- *size = bytes;
- *offset = zip->entry_offset;
- zip->entry_offset += bytes;
-
- return (ret);
-}
-
-static int
-archive_read_format_7zip_read_data_skip(struct archive_read *a)
-{
- struct _7zip *zip;
- int64_t bytes_skipped;
-
- zip = (struct _7zip *)(a->format->data);
-
- if (zip->pack_stream_bytes_unconsumed)
- read_consume(a);
-
- /* If we've already read to end of data, we're done. */
- if (zip->end_of_entry)
- return (ARCHIVE_OK);
-
- /*
- * If the length is at the beginning, we can skip the
- * compressed data much more quickly.
- */
- bytes_skipped = skip_stream(a, (size_t)zip->entry_bytes_remaining);
- if (bytes_skipped < 0)
- return (ARCHIVE_FATAL);
- zip->entry_bytes_remaining = 0;
-
- /* This entry is finished and done. */
- zip->end_of_entry = 1;
- return (ARCHIVE_OK);
-}
-
-static int
-archive_read_format_7zip_cleanup(struct archive_read *a)
-{
- struct _7zip *zip;
-
- zip = (struct _7zip *)(a->format->data);
- free_StreamsInfo(&(zip->si));
- free(zip->entries);
- free(zip->entry_names);
- free_decompression(a, zip);
- free(zip->uncompressed_buffer);
- free(zip->sub_stream_buff[0]);
- free(zip->sub_stream_buff[1]);
- free(zip->sub_stream_buff[2]);
- free(zip->tmp_stream_buff);
- free(zip);
- (a->format->data) = NULL;
- return (ARCHIVE_OK);
-}
-
-static void
-read_consume(struct archive_read *a)
-{
- struct _7zip *zip = (struct _7zip *)a->format->data;
-
- if (zip->pack_stream_bytes_unconsumed) {
- __archive_read_consume(a, zip->pack_stream_bytes_unconsumed);
- zip->stream_offset += zip->pack_stream_bytes_unconsumed;
- zip->pack_stream_bytes_unconsumed = 0;
- }
-}
-
-#ifdef HAVE_LZMA_H
-
-/*
- * Set an error code and choose an error message for liblzma.
- */
-static void
-set_error(struct archive_read *a, int ret)
-{
-
- switch (ret) {
- case LZMA_STREAM_END: /* Found end of stream. */
- case LZMA_OK: /* Decompressor made some progress. */
- break;
- case LZMA_MEM_ERROR:
- archive_set_error(&a->archive, ENOMEM,
- "Lzma library error: Cannot allocate memory");
- break;
- case LZMA_MEMLIMIT_ERROR:
- archive_set_error(&a->archive, ENOMEM,
- "Lzma library error: Out of memory");
- break;
- case LZMA_FORMAT_ERROR:
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Lzma library error: format not recognized");
- break;
- case LZMA_OPTIONS_ERROR:
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Lzma library error: Invalid options");
- break;
- case LZMA_DATA_ERROR:
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Lzma library error: Corrupted input data");
- break;
- case LZMA_BUF_ERROR:
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Lzma library error: No progress is possible");
- break;
- default:
- /* Return an error. */
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Lzma decompression failed: Unknown error");
- break;
- }
-}
-
-#endif
-
-static unsigned long
-decode_codec_id(const unsigned char *codecId, size_t id_size)
-{
- unsigned i;
- unsigned long id = 0;
-
- for (i = 0; i < id_size; i++) {
- id <<= 8;
- id += codecId[i];
- }
- return (id);
-}
-
-static void *
-ppmd_alloc(void *p, size_t size)
-{
- (void)p;
- return malloc(size);
-}
-static void
-ppmd_free(void *p, void *address)
-{
- (void)p;
- free(address);
-}
-static Byte
-ppmd_read(void *p)
-{
- struct archive_read *a = ((IByteIn*)p)->a;
- struct _7zip *zip = (struct _7zip *)(a->format->data);
- Byte b;
-
- if (zip->ppstream.avail_in == 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated RAR file data");
- zip->ppstream.overconsumed = 1;
- return (0);
- }
- b = *zip->ppstream.next_in++;
- zip->ppstream.avail_in--;
- zip->ppstream.total_in++;
- return (b);
-}
-
-static ISzAlloc g_szalloc = { ppmd_alloc, ppmd_free };
-
-static int
-init_decompression(struct archive_read *a, struct _7zip *zip,
- const struct _7z_coder *coder1, const struct _7z_coder *coder2)
-{
- int r;
-
- zip->codec = coder1->codec;
- zip->codec2 = -1;
-
- switch (zip->codec) {
- case _7Z_COPY:
- case _7Z_BZ2:
- case _7Z_DEFLATE:
- case _7Z_PPMD:
- if (coder2 != NULL) {
- if (coder2->codec != _7Z_X86 &&
- coder2->codec != _7Z_X86_BCJ2) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Unsupported filter %lx for %lx",
- coder2->codec, coder1->codec);
- return (ARCHIVE_FAILED);
- }
- zip->codec2 = coder2->codec;
- zip->bcj_state = 0;
- if (coder2->codec == _7Z_X86)
- x86_Init(zip);
- }
- break;
- default:
- break;
- }
-
- switch (zip->codec) {
- case _7Z_COPY:
- break;
-
- case _7Z_LZMA: case _7Z_LZMA2:
-#ifdef HAVE_LZMA_H
-#if LZMA_VERSION_MAJOR >= 5
-/* Effectively disable the limiter. */
-#define LZMA_MEMLIMIT UINT64_MAX
-#else
-/* NOTE: This needs to check memory size which running system has. */
-#define LZMA_MEMLIMIT (1U << 30)
-#endif
- {
- lzma_options_delta delta_opt;
- lzma_filter filters[LZMA_FILTERS_MAX];
-#if LZMA_VERSION < 50000030
- lzma_filter *ff;
-#endif
- int fi = 0;
-
- if (zip->lzstream_valid) {
- lzma_end(&(zip->lzstream));
- zip->lzstream_valid = 0;
- }
-
- /*
- * NOTE: liblzma incompletely handle the BCJ+LZMA compressed
- * data made by 7-Zip because 7-Zip does not add End-Of-
- * Payload Marker(EOPM) at the end of LZMA compressed data,
- * and so liblzma cannot know the end of the compressed data
- * without EOPM. So consequently liblzma will not return last
- * three or four bytes of uncompressed data because
- * LZMA_FILTER_X86 filter does not handle input data if its
- * data size is less than five bytes. If liblzma detect EOPM
- * or know the uncompressed data size, liblzma will flush out
- * the remaining that three or four bytes of uncompressed
- * data. That is why we have to use our converting program
- * for BCJ+LZMA. If we were able to tell the uncompressed
- * size to liblzma when using lzma_raw_decoder() liblzma
- * could correctly deal with BCJ+LZMA. But unfortunately
- * there is no way to do that.
- * Discussion about this can be found at XZ Utils forum.
- */
- if (coder2 != NULL) {
- zip->codec2 = coder2->codec;
-
- filters[fi].options = NULL;
- switch (zip->codec2) {
- case _7Z_X86:
- if (zip->codec == _7Z_LZMA2) {
- filters[fi].id = LZMA_FILTER_X86;
- fi++;
- } else
- /* Use our filter. */
- x86_Init(zip);
- break;
- case _7Z_X86_BCJ2:
- /* Use our filter. */
- zip->bcj_state = 0;
- break;
- case _7Z_DELTA:
- filters[fi].id = LZMA_FILTER_DELTA;
- memset(&delta_opt, 0, sizeof(delta_opt));
- delta_opt.type = LZMA_DELTA_TYPE_BYTE;
- delta_opt.dist = 1;
- filters[fi].options = &delta_opt;
- fi++;
- break;
- /* Following filters have not been tested yet. */
- case _7Z_POWERPC:
- filters[fi].id = LZMA_FILTER_POWERPC;
- fi++;
- break;
- case _7Z_IA64:
- filters[fi].id = LZMA_FILTER_IA64;
- fi++;
- break;
- case _7Z_ARM:
- filters[fi].id = LZMA_FILTER_ARM;
- fi++;
- break;
- case _7Z_ARMTHUMB:
- filters[fi].id = LZMA_FILTER_ARMTHUMB;
- fi++;
- break;
- case _7Z_SPARC:
- filters[fi].id = LZMA_FILTER_SPARC;
- fi++;
- break;
- default:
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Unexpected codec ID: %lX", zip->codec2);
- return (ARCHIVE_FAILED);
- }
- }
-
- if (zip->codec == _7Z_LZMA2)
- filters[fi].id = LZMA_FILTER_LZMA2;
- else
- filters[fi].id = LZMA_FILTER_LZMA1;
- filters[fi].options = NULL;
-#if LZMA_VERSION < 50000030
- ff = &filters[fi];
-#endif
- r = lzma_properties_decode(&filters[fi], NULL,
- coder1->properties, (size_t)coder1->propertiesSize);
- if (r != LZMA_OK) {
- set_error(a, r);
- return (ARCHIVE_FAILED);
- }
- fi++;
-
- filters[fi].id = LZMA_VLI_UNKNOWN;
- filters[fi].options = NULL;
- r = lzma_raw_decoder(&(zip->lzstream), filters);
-#if LZMA_VERSION < 50000030
- free(ff->options);
-#endif
- if (r != LZMA_OK) {
- set_error(a, r);
- return (ARCHIVE_FAILED);
- }
- zip->lzstream_valid = 1;
- zip->lzstream.total_in = 0;
- zip->lzstream.total_out = 0;
- break;
- }
-#else
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "LZMA codec is unsupported");
- return (ARCHIVE_FAILED);
-#endif
- case _7Z_BZ2:
-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
- if (zip->bzstream_valid) {
- BZ2_bzDecompressEnd(&(zip->bzstream));
- zip->bzstream_valid = 0;
- }
- r = BZ2_bzDecompressInit(&(zip->bzstream), 0, 0);
- if (r == BZ_MEM_ERROR)
- r = BZ2_bzDecompressInit(&(zip->bzstream), 0, 1);
- if (r != BZ_OK) {
- int err = ARCHIVE_ERRNO_MISC;
- const char *detail = NULL;
- switch (r) {
- case BZ_PARAM_ERROR:
- detail = "invalid setup parameter";
- break;
- case BZ_MEM_ERROR:
- err = ENOMEM;
- detail = "out of memory";
- break;
- case BZ_CONFIG_ERROR:
- detail = "mis-compiled library";
- break;
- }
- archive_set_error(&a->archive, err,
- "Internal error initializing decompressor: %s",
- detail == NULL ? "??" : detail);
- zip->bzstream_valid = 0;
- return (ARCHIVE_FAILED);
- }
- zip->bzstream_valid = 1;
- zip->bzstream.total_in_lo32 = 0;
- zip->bzstream.total_in_hi32 = 0;
- zip->bzstream.total_out_lo32 = 0;
- zip->bzstream.total_out_hi32 = 0;
- break;
-#else
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "BZ2 codec is unsupported");
- return (ARCHIVE_FAILED);
-#endif
- case _7Z_DEFLATE:
-#ifdef HAVE_ZLIB_H
- if (zip->stream_valid)
- r = inflateReset(&(zip->stream));
- else
- r = inflateInit2(&(zip->stream),
- -15 /* Don't check for zlib header */);
- if (r != Z_OK) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Couldn't initialize zlib stream.");
- return (ARCHIVE_FAILED);
- }
- zip->stream_valid = 1;
- zip->stream.total_in = 0;
- zip->stream.total_out = 0;
- break;
-#else
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "DEFLATE codec is unsupported");
- return (ARCHIVE_FAILED);
-#endif
- case _7Z_PPMD:
- {
- unsigned order;
- uint32_t msize;
-
- if (zip->ppmd7_valid) {
- __archive_ppmd7_functions.Ppmd7_Free(
- &zip->ppmd7_context, &g_szalloc);
- zip->ppmd7_valid = 0;
- }
-
- if (coder1->propertiesSize < 5) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Malformed PPMd parameter");
- return (ARCHIVE_FAILED);
- }
- order = coder1->properties[0];
- msize = archive_le32dec(&(coder1->properties[1]));
- if (order < PPMD7_MIN_ORDER || order > PPMD7_MAX_ORDER ||
- msize < PPMD7_MIN_MEM_SIZE || msize > PPMD7_MAX_MEM_SIZE) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Malformed PPMd parameter");
- return (ARCHIVE_FAILED);
- }
- __archive_ppmd7_functions.Ppmd7_Construct(&zip->ppmd7_context);
- r = __archive_ppmd7_functions.Ppmd7_Alloc(
- &zip->ppmd7_context, msize, &g_szalloc);
- if (r == 0) {
- archive_set_error(&a->archive, ENOMEM,
- "Coludn't allocate memory for PPMd");
- return (ARCHIVE_FATAL);
- }
- __archive_ppmd7_functions.Ppmd7_Init(
- &zip->ppmd7_context, order);
- __archive_ppmd7_functions.Ppmd7z_RangeDec_CreateVTable(
- &zip->range_dec);
- zip->ppmd7_valid = 1;
- zip->ppmd7_stat = 0;
- zip->ppstream.overconsumed = 0;
- zip->ppstream.total_in = 0;
- zip->ppstream.total_out = 0;
- break;
- }
- case _7Z_X86:
- case _7Z_X86_BCJ2:
- case _7Z_POWERPC:
- case _7Z_IA64:
- case _7Z_ARM:
- case _7Z_ARMTHUMB:
- case _7Z_SPARC:
- case _7Z_DELTA:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Unexpected codec ID: %lX", zip->codec);
- return (ARCHIVE_FAILED);
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Unknown codec ID: %lX", zip->codec);
- return (ARCHIVE_FAILED);
- }
-
- return (ARCHIVE_OK);
-}
-
-static int
-decompress(struct archive_read *a, struct _7zip *zip,
- void *buff, size_t *outbytes, const void *b, size_t *used)
-{
- const uint8_t *t_next_in;
- uint8_t *t_next_out;
- size_t o_avail_in, o_avail_out;
- size_t t_avail_in, t_avail_out;
- uint8_t *bcj2_next_out;
- size_t bcj2_avail_out;
- int r, ret = ARCHIVE_OK;
-
- t_avail_in = o_avail_in = *used;
- t_avail_out = o_avail_out = *outbytes;
- t_next_in = b;
- t_next_out = buff;
-
- if (zip->codec != _7Z_LZMA2 && zip->codec2 == _7Z_X86) {
- int i;
-
- /* Do not copy out the BCJ remaining bytes when the output
- * buffer size is less than five bytes. */
- if (o_avail_in != 0 && t_avail_out < 5 && zip->odd_bcj_size) {
- *used = 0;
- *outbytes = 0;
- return (ret);
- }
- for (i = 0; zip->odd_bcj_size > 0 && t_avail_out; i++) {
- *t_next_out++ = zip->odd_bcj[i];
- t_avail_out--;
- zip->odd_bcj_size--;
- }
- if (o_avail_in == 0 || t_avail_out == 0) {
- *used = o_avail_in - t_avail_in;
- *outbytes = o_avail_out - t_avail_out;
- if (o_avail_in == 0)
- ret = ARCHIVE_EOF;
- return (ret);
- }
- }
-
- bcj2_next_out = t_next_out;
- bcj2_avail_out = t_avail_out;
- if (zip->codec2 == _7Z_X86_BCJ2) {
- /*
- * Decord a remaining decompressed main stream for BCJ2.
- */
- if (zip->tmp_stream_bytes_remaining) {
- ssize_t bytes;
- size_t remaining = zip->tmp_stream_bytes_remaining;
- bytes = Bcj2_Decode(zip, t_next_out, t_avail_out);
- if (bytes < 0) {
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "BCJ2 conversion Failed");
- return (ARCHIVE_FAILED);
- }
- zip->main_stream_bytes_remaining -=
- remaining - zip->tmp_stream_bytes_remaining;
- t_avail_out -= bytes;
- if (o_avail_in == 0 || t_avail_out == 0) {
- *used = 0;
- *outbytes = o_avail_out - t_avail_out;
- if (o_avail_in == 0 &&
- zip->tmp_stream_bytes_remaining)
- ret = ARCHIVE_EOF;
- return (ret);
- }
- t_next_out += bytes;
- bcj2_next_out = t_next_out;
- bcj2_avail_out = t_avail_out;
- }
- t_next_out = zip->tmp_stream_buff;
- t_avail_out = zip->tmp_stream_buff_size;
- }
-
- switch (zip->codec) {
- case _7Z_COPY:
- {
- size_t bytes =
- (t_avail_in > t_avail_out)?t_avail_out:t_avail_in;
-
- memcpy(t_next_out, t_next_in, bytes);
- t_avail_in -= bytes;
- t_avail_out -= bytes;
- if (o_avail_in == 0)
- ret = ARCHIVE_EOF;
- break;
- }
-#ifdef HAVE_LZMA_H
- case _7Z_LZMA: case _7Z_LZMA2:
- zip->lzstream.next_in = t_next_in;
- zip->lzstream.avail_in = t_avail_in;
- zip->lzstream.next_out = t_next_out;
- zip->lzstream.avail_out = t_avail_out;
-
- r = lzma_code(&(zip->lzstream), LZMA_RUN);
- switch (r) {
- case LZMA_STREAM_END: /* Found end of stream. */
- lzma_end(&(zip->lzstream));
- zip->lzstream_valid = 0;
- ret = ARCHIVE_EOF;
- break;
- case LZMA_OK: /* Decompressor made some progress. */
- break;
- default:
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "Decompression failed(%d)",
- r);
- return (ARCHIVE_FAILED);
- }
- t_avail_in = zip->lzstream.avail_in;
- t_avail_out = zip->lzstream.avail_out;
- break;
-#endif
-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
- case _7Z_BZ2:
- zip->bzstream.next_in = (char *)(uintptr_t)t_next_in;
- zip->bzstream.avail_in = t_avail_in;
- zip->bzstream.next_out = (char *)(uintptr_t)t_next_out;
- zip->bzstream.avail_out = t_avail_out;
- r = BZ2_bzDecompress(&(zip->bzstream));
- switch (r) {
- case BZ_STREAM_END: /* Found end of stream. */
- switch (BZ2_bzDecompressEnd(&(zip->bzstream))) {
- case BZ_OK:
- break;
- default:
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "Failed to clean up decompressor");
- return (ARCHIVE_FAILED);
- }
- zip->bzstream_valid = 0;
- ret = ARCHIVE_EOF;
- break;
- case BZ_OK: /* Decompressor made some progress. */
- break;
- default:
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "bzip decompression failed");
- return (ARCHIVE_FAILED);
- }
- t_avail_in = zip->bzstream.avail_in;
- t_avail_out = zip->bzstream.avail_out;
- break;
-#endif
-#ifdef HAVE_ZLIB_H
- case _7Z_DEFLATE:
- zip->stream.next_in = (Bytef *)(uintptr_t)t_next_in;
- zip->stream.avail_in = (uInt)t_avail_in;
- zip->stream.next_out = t_next_out;
- zip->stream.avail_out = (uInt)t_avail_out;
- r = inflate(&(zip->stream), 0);
- switch (r) {
- case Z_STREAM_END: /* Found end of stream. */
- ret = ARCHIVE_EOF;
- break;
- case Z_OK: /* Decompressor made some progress.*/
- break;
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "File decompression failed (%d)", r);
- return (ARCHIVE_FAILED);
- }
- t_avail_in = zip->stream.avail_in;
- t_avail_out = zip->stream.avail_out;
- break;
-#endif
- case _7Z_PPMD:
- {
- uint64_t flush_bytes;
-
- if (!zip->ppmd7_valid || zip->ppmd7_stat < 0 ||
- t_avail_out <= 0) {
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "Decompression internal error");
- return (ARCHIVE_FAILED);
- }
- zip->ppstream.next_in = t_next_in;
- zip->ppstream.avail_in = t_avail_in;
- zip->ppstream.next_out = t_next_out;
- zip->ppstream.avail_out = t_avail_out;
- if (zip->ppmd7_stat == 0) {
- zip->bytein.a = a;
- zip->bytein.Read = &ppmd_read;
- zip->range_dec.Stream = &zip->bytein;
- r = __archive_ppmd7_functions.Ppmd7z_RangeDec_Init(
- &(zip->range_dec));
- if (r == 0) {
- zip->ppmd7_stat = -1;
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Failed to initialize PPMd range decorder");
- return (ARCHIVE_FAILED);
- }
- if (zip->ppstream.overconsumed) {
- zip->ppmd7_stat = -1;
- return (ARCHIVE_FAILED);
- }
- zip->ppmd7_stat = 1;
- }
-
- if (t_avail_in == 0)
- /* XXX Flush out remaining decoded data XXX */
- flush_bytes = zip->folder_outbytes_remaining;
- else
- flush_bytes = 0;
-
- do {
- int sym;
-
- sym = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(
- &(zip->ppmd7_context), &(zip->range_dec.p));
- if (sym < 0) {
- zip->ppmd7_stat = -1;
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Failed to decode PPMd");
- return (ARCHIVE_FAILED);
- }
- if (zip->ppstream.overconsumed) {
- zip->ppmd7_stat = -1;
- return (ARCHIVE_FAILED);
- }
- *zip->ppstream.next_out++ = (unsigned char)sym;
- zip->ppstream.avail_out--;
- zip->ppstream.total_out++;
- if (flush_bytes)
- flush_bytes--;
- } while (zip->ppstream.avail_out &&
- (zip->ppstream.avail_in || flush_bytes));
-
- t_avail_in = (size_t)zip->ppstream.avail_in;
- t_avail_out = (size_t)zip->ppstream.avail_out;
- break;
- }
- default:
- archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
- "Decompression internal error");
- return (ARCHIVE_FAILED);
- }
- if (ret != ARCHIVE_OK && ret != ARCHIVE_EOF)
- return (ret);
-
- *used = o_avail_in - t_avail_in;
- *outbytes = o_avail_out - t_avail_out;
-
- /*
- * Decord BCJ.
- */
- if (zip->codec != _7Z_LZMA2 && zip->codec2 == _7Z_X86) {
- size_t l = x86_Convert(zip, buff, *outbytes);
- zip->odd_bcj_size = *outbytes - l;
- if (zip->odd_bcj_size > 0 && zip->odd_bcj_size <= 4 &&
- o_avail_in && ret != ARCHIVE_EOF) {
- memcpy(zip->odd_bcj, ((unsigned char *)buff) + l,
- zip->odd_bcj_size);
- *outbytes = l;
- } else
- zip->odd_bcj_size = 0;
- }
-
- /*
- * Decord BCJ2 with a decompressed main stream.
- */
- if (zip->codec2 == _7Z_X86_BCJ2) {
- ssize_t bytes;
-
- zip->tmp_stream_bytes_avail =
- zip->tmp_stream_buff_size - t_avail_out;
- if (zip->tmp_stream_bytes_avail >
- zip->main_stream_bytes_remaining)
- zip->tmp_stream_bytes_avail =
- zip->main_stream_bytes_remaining;
- zip->tmp_stream_bytes_remaining = zip->tmp_stream_bytes_avail;
- bytes = Bcj2_Decode(zip, bcj2_next_out, bcj2_avail_out);
- if (bytes < 0) {
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC, "BCJ2 conversion Failed");
- return (ARCHIVE_FAILED);
- }
- zip->main_stream_bytes_remaining -=
- zip->tmp_stream_bytes_avail
- - zip->tmp_stream_bytes_remaining;
- bcj2_avail_out -= bytes;
- *outbytes = o_avail_out - bcj2_avail_out;
- }
-
- return (ret);
-}
-
-static int
-free_decompression(struct archive_read *a, struct _7zip *zip)
-{
- int r = ARCHIVE_OK;
-
-#if !defined(HAVE_ZLIB_H) &&\
- !(defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR))
- (void)a;/* UNUSED */
-#endif
-#ifdef HAVE_LZMA_H
- if (zip->lzstream_valid)
- lzma_end(&(zip->lzstream));
-#endif
-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
- if (zip->bzstream_valid) {
- if (BZ2_bzDecompressEnd(&(zip->bzstream)) != BZ_OK) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Failed to clean up bzip2 decompressor");
- r = ARCHIVE_FATAL;
- }
- zip->bzstream_valid = 0;
- }
-#endif
-#ifdef HAVE_ZLIB_H
- if (zip->stream_valid) {
- if (inflateEnd(&(zip->stream)) != Z_OK) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Failed to clean up zlib decompressor");
- r = ARCHIVE_FATAL;
- }
- zip->stream_valid = 0;
- }
-#endif
- if (zip->ppmd7_valid) {
- __archive_ppmd7_functions.Ppmd7_Free(
- &zip->ppmd7_context, &g_szalloc);
- zip->ppmd7_valid = 0;
- }
- return (r);
-}
-
-static int
-parse_7zip_uint64(struct archive_read *a, uint64_t *val)
-{
- const unsigned char *p;
- unsigned char avail, mask;
- int i;
-
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- avail = *p;
- mask = 0x80;
- *val = 0;
- for (i = 0; i < 8; i++) {
- if (avail & mask) {
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- *val |= ((uint64_t)*p) << (8 * i);
- mask >>= 1;
- continue;
- }
- *val += (avail & (mask -1)) << (8 * i);
- break;
- }
- return (0);
-}
-
-static int
-read_Bools(struct archive_read *a, unsigned char *data, size_t num)
-{
- const unsigned char *p;
- unsigned i, mask = 0, avail = 0;
-
- for (i = 0; i < num; i++) {
- if (mask == 0) {
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- avail = *p;
- mask = 0x80;
- }
- data[i] = (avail & mask)?1:0;
- mask >>= 1;
- }
- return (0);
-}
-
-static void
-free_Digest(struct _7z_digests *d)
-{
- free(d->defineds);
- free(d->digests);
-}
-
-static int
-read_Digests(struct archive_read *a, struct _7z_digests *d, size_t num)
-{
- const unsigned char *p;
- unsigned i;
-
- if (num == 0)
- return (-1);
- memset(d, 0, sizeof(*d));
-
- d->defineds = malloc(num);
- if (d->defineds == NULL)
- return (-1);
- /*
- * Read Bools.
- */
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- if (*p == 0) {
- if (read_Bools(a, d->defineds, num) < 0)
- return (-1);
- } else
- /* All are defined */
- memset(d->defineds, 1, num);
-
- d->digests = calloc(num, sizeof(*d->digests));
- if (d->digests == NULL)
- return (-1);
- for (i = 0; i < num; i++) {
- if (d->defineds[i]) {
- if ((p = header_bytes(a, 4)) == NULL)
- return (-1);
- d->digests[i] = archive_le32dec(p);
- }
- }
-
- return (0);
-}
-
-static void
-free_PackInfo(struct _7z_pack_info *pi)
-{
- free(pi->sizes);
- free(pi->positions);
- free_Digest(&(pi->digest));
-}
-
-static int
-read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
-{
- const unsigned char *p;
- unsigned i;
-
- memset(pi, 0, sizeof(*pi));
-
- /*
- * Read PackPos.
- */
- if (parse_7zip_uint64(a, &(pi->pos)) < 0)
- return (-1);
-
- /*
- * Read NumPackStreams.
- */
- if (parse_7zip_uint64(a, &(pi->numPackStreams)) < 0)
- return (-1);
- if (pi->numPackStreams == 0)
- return (-1);
- if (1000000 < pi->numPackStreams)
- return (-1);
-
- /*
- * Read PackSizes[num]
- */
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- if (*p == kEnd)
- /* PackSizes[num] are not present. */
- return (0);
- if (*p != kSize)
- return (-1);
- pi->sizes = calloc((size_t)pi->numPackStreams, sizeof(uint64_t));
- pi->positions = calloc((size_t)pi->numPackStreams, sizeof(uint64_t));
- if (pi->sizes == NULL || pi->positions == NULL)
- return (-1);
-
- for (i = 0; i < pi->numPackStreams; i++) {
- if (parse_7zip_uint64(a, &(pi->sizes[i])) < 0)
- return (-1);
- }
-
- /*
- * Read PackStreamDigests[num]
- */
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- if (*p == kEnd) {
- /* PackStreamDigests[num] are not present. */
- pi->digest.defineds =
- calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.defineds));
- pi->digest.digests =
- calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.digests));
- if (pi->digest.defineds == NULL || pi->digest.digests == NULL)
- return (-1);
- return (0);
- }
-
- if (*p != kSize)
- return (-1);
-
- if (read_Digests(a, &(pi->digest), (size_t)pi->numPackStreams) < 0)
- return (-1);
-
- /*
- * Must be marked by kEnd.
- */
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- if (*p != kEnd)
- return (-1);
- return (0);
-}
-
-static void
-free_Folder(struct _7z_folder *f)
-{
- unsigned i;
-
- if (f->coders) {
- for (i = 0; i< f->numCoders; i++) {
- free(f->coders[i].properties);
- }
- free(f->coders);
- }
- free(f->bindPairs);
- free(f->packedStreams);
- free(f->unPackSize);
-}
-
-static int
-read_Folder(struct archive_read *a, struct _7z_folder *f)
-{
- struct _7zip *zip = (struct _7zip *)a->format->data;
- const unsigned char *p;
- uint64_t numInStreamsTotal = 0;
- uint64_t numOutStreamsTotal = 0;
- unsigned i;
-
- memset(f, 0, sizeof(*f));
-
- /*
- * Read NumCoders.
- */
- if (parse_7zip_uint64(a, &(f->numCoders)) < 0)
- return (-1);
- if (f->numCoders > 4)
- /* Too many coders. */
- return (-1);
-
- f->coders = calloc((size_t)f->numCoders, sizeof(*f->coders));
- if (f->coders == NULL)
- return (-1);
- for (i = 0; i< f->numCoders; i++) {
- size_t codec_size;
- int simple, attr;
-
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- /*
- * 0:3 CodecIdSize
- * 4: 0 - IsSimple
- * 1 - Is not Simple
- * 5: 0 - No Attributes
- * 1 - There are Attributes;
- * 7: Must be zero.
- */
- codec_size = *p & 0xf;
- simple = (*p & 0x10)?0:1;
- attr = *p & 0x20;
- if (*p & 0x80)
- return (-1);/* Not supported. */
-
- /*
- * Read Decompression Method IDs.
- */
- if ((p = header_bytes(a, codec_size)) == NULL)
- return (-1);
-
- f->coders[i].codec = decode_codec_id(p, codec_size);
-
- if (simple) {
- f->coders[i].numInStreams = 1;
- f->coders[i].numOutStreams = 1;
- } else {
- if (parse_7zip_uint64(
- a, &(f->coders[i].numInStreams)) < 0)
- return (-1);
- if (1000000 < f->coders[i].numInStreams)
- return (-1);
- if (parse_7zip_uint64(
- a, &(f->coders[i].numOutStreams)) < 0)
- return (-1);
- if (1000000 < f->coders[i].numOutStreams)
- return (-1);
- }
-
- if (attr) {
- if (parse_7zip_uint64(
- a, &(f->coders[i].propertiesSize)) < 0)
- return (-1);
- if ((p = header_bytes(
- a, (size_t)f->coders[i].propertiesSize)) == NULL)
- return (-1);
- f->coders[i].properties =
- malloc((size_t)f->coders[i].propertiesSize);
- if (f->coders[i].properties == NULL)
- return (-1);
- memcpy(f->coders[i].properties, p,
- (size_t)f->coders[i].propertiesSize);
- }
-
- numInStreamsTotal += f->coders[i].numInStreams;
- numOutStreamsTotal += f->coders[i].numOutStreams;
- }
-
- if (numOutStreamsTotal == 0 ||
- numInStreamsTotal < numOutStreamsTotal-1)
- return (-1);
-
- f->numBindPairs = numOutStreamsTotal - 1;
- if (zip->header_bytes_remaining < f->numBindPairs)
- return (-1);
- if (f->numBindPairs > 0) {
- f->bindPairs =
- calloc((size_t)f->numBindPairs, sizeof(*f->bindPairs));
- if (f->bindPairs == NULL)
- return (-1);
- } else
- f->bindPairs = NULL;
- for (i = 0; i < f->numBindPairs; i++) {
- if (parse_7zip_uint64(a, &(f->bindPairs[i].inIndex)) < 0)
- return (-1);
- if (1000000 < f->bindPairs[i].inIndex)
- return (-1);
- if (parse_7zip_uint64(a, &(f->bindPairs[i].outIndex)) < 0)
- return (-1);
- if (1000000 < f->bindPairs[i].outIndex)
- return (-1);
- }
-
- f->numPackedStreams = numInStreamsTotal - f->numBindPairs;
- f->packedStreams =
- calloc((size_t)f->numPackedStreams, sizeof(*f->packedStreams));
- if (f->packedStreams == NULL)
- return (-1);
- if (f->numPackedStreams == 1) {
- for (i = 0; i < numInStreamsTotal; i++) {
- unsigned j;
- for (j = 0; j < f->numBindPairs; j++) {
- if (f->bindPairs[j].inIndex == i)
- break;
- }
- if (j == f->numBindPairs)
- break;
- }
- if (i == numInStreamsTotal)
- return (-1);
- f->packedStreams[0] = i;
- } else {
- for (i = 0; i < f->numPackedStreams; i++) {
- if (parse_7zip_uint64(a, &(f->packedStreams[i])) < 0)
- return (-1);
- if (1000000 < f->packedStreams[i])
- return (-1);
- }
- }
- f->numInStreams = numInStreamsTotal;
- f->numOutStreams = numOutStreamsTotal;
-
- return (0);
-}
-
-static void
-free_CodersInfo(struct _7z_coders_info *ci)
-{
- unsigned i;
-
- if (ci->folders) {
- for (i = 0; i < ci->numFolders; i++)
- free_Folder(&(ci->folders[i]));
- free(ci->folders);
- }
-}
-
-static int
-read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
-{
- const unsigned char *p;
- struct _7z_digests digest;
- unsigned i;
-
- memset(ci, 0, sizeof(*ci));
- memset(&digest, 0, sizeof(digest));
-
- if ((p = header_bytes(a, 1)) == NULL)
- goto failed;
- if (*p != kFolder)
- goto failed;
-
- /*
- * Read NumFolders.
- */
- if (parse_7zip_uint64(a, &(ci->numFolders)) < 0)
- goto failed;
- if (1000000 < ci->numFolders)
- return (-1);
-
- /*
- * Read External.
- */
- if ((p = header_bytes(a, 1)) == NULL)
- goto failed;
- switch (*p) {
- case 0:
- ci->folders =
- calloc((size_t)ci->numFolders, sizeof(*ci->folders));
- if (ci->folders == NULL)
- return (-1);
- for (i = 0; i < ci->numFolders; i++) {
- if (read_Folder(a, &(ci->folders[i])) < 0)
- goto failed;
- }
- break;
- case 1:
- if (parse_7zip_uint64(a, &(ci->dataStreamIndex)) < 0)
- return (-1);
- if (1000000 < ci->dataStreamIndex)
- return (-1);
- break;
- }
-
- if ((p = header_bytes(a, 1)) == NULL)
- goto failed;
- if (*p != kCodersUnPackSize)
- goto failed;
-
- for (i = 0; i < ci->numFolders; i++) {
- struct _7z_folder *folder = &(ci->folders[i]);
- unsigned j;
-
- folder->unPackSize =
- calloc((size_t)folder->numOutStreams, sizeof(*folder->unPackSize));
- if (folder->unPackSize == NULL)
- goto failed;
- for (j = 0; j < folder->numOutStreams; j++) {
- if (parse_7zip_uint64(a, &(folder->unPackSize[j])) < 0)
- goto failed;
- }
- }
-
- /*
- * Read CRCs.
- */
- if ((p = header_bytes(a, 1)) == NULL)
- goto failed;
- if (*p == kEnd)
- return (0);
- if (*p != kCRC)
- goto failed;
- if (read_Digests(a, &digest, (size_t)ci->numFolders) < 0)
- goto failed;
- for (i = 0; i < ci->numFolders; i++) {
- ci->folders[i].digest_defined = digest.defineds[i];
- ci->folders[i].digest = digest.digests[i];
- }
-
- /*
- * Must be kEnd.
- */
- if ((p = header_bytes(a, 1)) == NULL)
- goto failed;
- if (*p != kEnd)
- goto failed;
- free_Digest(&digest);
- return (0);
-failed:
- free_Digest(&digest);
- return (-1);
-}
-
-static uint64_t
-folder_uncompressed_size(struct _7z_folder *f)
-{
- int n = (int)f->numOutStreams;
- unsigned pairs = (unsigned)f->numBindPairs;
-
- while (--n >= 0) {
- unsigned i;
- for (i = 0; i < pairs; i++) {
- if (f->bindPairs[i].outIndex == (uint64_t)n)
- break;
- }
- if (i >= pairs)
- return (f->unPackSize[n]);
- }
- return (0);
-}
-
-static void
-free_SubStreamsInfo(struct _7z_substream_info *ss)
-{
- free(ss->unpackSizes);
- free(ss->digestsDefined);
- free(ss->digests);
-}
-
-static int
-read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
- struct _7z_folder *f, size_t numFolders)
-{
- const unsigned char *p;
- uint64_t *usizes;
- size_t unpack_streams;
- int type;
- unsigned i;
- uint32_t numDigests;
-
- memset(ss, 0, sizeof(*ss));
-
- for (i = 0; i < numFolders; i++)
- f[i].numUnpackStreams = 1;
-
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- type = *p;
-
- if (type == kNumUnPackStream) {
- unpack_streams = 0;
- for (i = 0; i < numFolders; i++) {
- if (parse_7zip_uint64(a, &(f[i].numUnpackStreams)) < 0)
- return (-1);
- if (1000000 < f[i].numUnpackStreams)
- return (-1);
- unpack_streams += (size_t)f[i].numUnpackStreams;
- }
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- type = *p;
- } else
- unpack_streams = numFolders;
-
- ss->unpack_streams = unpack_streams;
- if (unpack_streams) {
- ss->unpackSizes = calloc(unpack_streams,
- sizeof(*ss->unpackSizes));
- ss->digestsDefined = calloc(unpack_streams,
- sizeof(*ss->digestsDefined));
- ss->digests = calloc(unpack_streams,
- sizeof(*ss->digests));
- if (ss->unpackSizes == NULL || ss->digestsDefined == NULL ||
- ss->digests == NULL)
- return (-1);
- }
-
- usizes = ss->unpackSizes;
- for (i = 0; i < numFolders; i++) {
- unsigned pack;
- uint64_t sum;
-
- if (f[i].numUnpackStreams == 0)
- continue;
-
- sum = 0;
- if (type == kSize) {
- for (pack = 1; pack < f[i].numUnpackStreams; pack++) {
- if (parse_7zip_uint64(a, usizes) < 0)
- return (-1);
- sum += *usizes++;
- }
- }
- *usizes++ = folder_uncompressed_size(&f[i]) - sum;
- }
-
- if (type == kSize) {
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- type = *p;
- }
-
- for (i = 0; i < unpack_streams; i++) {
- ss->digestsDefined[i] = 0;
- ss->digests[i] = 0;
- }
-
- numDigests = 0;
- for (i = 0; i < numFolders; i++) {
- if (f[i].numUnpackStreams != 1 || !f[i].digest_defined)
- numDigests += (uint32_t)f[i].numUnpackStreams;
- }
-
- if (type == kCRC) {
- struct _7z_digests tmpDigests;
- unsigned char *digestsDefined = ss->digestsDefined;
- uint32_t * digests = ss->digests;
- int di = 0;
-
- memset(&tmpDigests, 0, sizeof(tmpDigests));
- if (read_Digests(a, &(tmpDigests), numDigests) < 0) {
- free_Digest(&tmpDigests);
- return (-1);
- }
- for (i = 0; i < numFolders; i++) {
- if (f[i].numUnpackStreams == 1 && f[i].digest_defined) {
- *digestsDefined++ = 1;
- *digests++ = f[i].digest;
- } else {
- unsigned j;
-
- for (j = 0; j < f[i].numUnpackStreams;
- j++, di++) {
- *digestsDefined++ =
- tmpDigests.defineds[di];
- *digests++ =
- tmpDigests.digests[di];
- }
- }
- }
- free_Digest(&tmpDigests);
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- type = *p;
- }
-
- /*
- * Must be kEnd.
- */
- if (type != kEnd)
- return (-1);
- return (0);
-}
-
-static void
-free_StreamsInfo(struct _7z_stream_info *si)
-{
- free_PackInfo(&(si->pi));
- free_CodersInfo(&(si->ci));
- free_SubStreamsInfo(&(si->ss));
-}
-
-static int
-read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)
-{
- struct _7zip *zip = (struct _7zip *)a->format->data;
- const unsigned char *p;
- unsigned i;
-
- memset(si, 0, sizeof(*si));
-
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- if (*p == kPackInfo) {
- uint64_t packPos;
-
- if (read_PackInfo(a, &(si->pi)) < 0)
- return (-1);
-
- if (si->pi.positions == NULL || si->pi.sizes == NULL)
- return (-1);
- /*
- * Calculate packed stream positions.
- */
- packPos = si->pi.pos;
- for (i = 0; i < si->pi.numPackStreams; i++) {
- si->pi.positions[i] = packPos;
- packPos += si->pi.sizes[i];
- if (packPos > zip->header_offset)
- return (-1);
- }
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- }
- if (*p == kUnPackInfo) {
- uint32_t packIndex;
- struct _7z_folder *f;
-
- if (read_CodersInfo(a, &(si->ci)) < 0)
- return (-1);
-
- /*
- * Calculate packed stream indexes.
- */
- packIndex = 0;
- f = si->ci.folders;
- for (i = 0; i < si->ci.numFolders; i++) {
- f[i].packIndex = packIndex;
- packIndex += (uint32_t)f[i].numPackedStreams;
- if (packIndex > si->pi.numPackStreams)
- return (-1);
- }
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- }
-
- if (*p == kSubStreamsInfo) {
- if (read_SubStreamsInfo(a, &(si->ss),
- si->ci.folders, (size_t)si->ci.numFolders) < 0)
- return (-1);
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- }
-
- /*
- * Must be kEnd.
- */
- if (*p != kEnd)
- return (-1);
- return (0);
-}
-
-static void
-free_Header(struct _7z_header_info *h)
-{
- free(h->emptyStreamBools);
- free(h->emptyFileBools);
- free(h->antiBools);
- free(h->attrBools);
-}
-
-static int
-read_Header(struct archive_read *a, struct _7z_header_info *h,
- int check_header_id)
-{
- struct _7zip *zip = (struct _7zip *)a->format->data;
- const unsigned char *p;
- struct _7z_folder *folders;
- struct _7z_stream_info *si = &(zip->si);
- struct _7zip_entry *entries;
- uint32_t folderIndex, indexInFolder;
- unsigned i;
- int eindex, empty_streams, sindex;
-
- if (check_header_id) {
- /*
- * Read Header.
- */
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- if (*p != kHeader)
- return (-1);
- }
-
- /*
- * Read ArchiveProperties.
- */
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- if (*p == kArchiveProperties) {
- for (;;) {
- uint64_t size;
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- if (*p == 0)
- break;
- if (parse_7zip_uint64(a, &size) < 0)
- return (-1);
- }
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- }
-
- /*
- * Read MainStreamsInfo.
- */
- if (*p == kMainStreamsInfo) {
- if (read_StreamsInfo(a, &(zip->si)) < 0)
- return (-1);
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- }
- if (*p == kEnd)
- return (0);
-
- /*
- * Read FilesInfo.
- */
- if (*p != kFilesInfo)
- return (-1);
-
- if (parse_7zip_uint64(a, &(zip->numFiles)) < 0)
- return (-1);
- if (1000000 < zip->numFiles)
- return (-1);
-
- zip->entries = calloc((size_t)zip->numFiles, sizeof(*zip->entries));
- if (zip->entries == NULL)
- return (-1);
- entries = zip->entries;
-
- empty_streams = 0;
- for (;;) {
- int type;
- uint64_t size;
- size_t ll;
-
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- type = *p;
- if (type == kEnd)
- break;
-
- if (parse_7zip_uint64(a, &size) < 0)
- return (-1);
- if (zip->header_bytes_remaining < size)
- return (-1);
- ll = (size_t)size;
-
- switch (type) {
- case kEmptyStream:
- h->emptyStreamBools = calloc((size_t)zip->numFiles,
- sizeof(*h->emptyStreamBools));
- if (h->emptyStreamBools == NULL)
- return (-1);
- if (read_Bools(
- a, h->emptyStreamBools, (size_t)zip->numFiles) < 0)
- return (-1);
- empty_streams = 0;
- for (i = 0; i < zip->numFiles; i++) {
- if (h->emptyStreamBools[i])
- empty_streams++;
- }
- break;
- case kEmptyFile:
- if (empty_streams <= 0) {
- /* Unexcepted sequence. Skip this. */
- if (header_bytes(a, ll) == NULL)
- return (-1);
- break;
- }
- h->emptyFileBools = calloc(empty_streams,
- sizeof(*h->emptyFileBools));
- if (h->emptyFileBools == NULL)
- return (-1);
- if (read_Bools(a, h->emptyFileBools, empty_streams) < 0)
- return (-1);
- break;
- case kAnti:
- if (empty_streams <= 0) {
- /* Unexcepted sequence. Skip this. */
- if (header_bytes(a, ll) == NULL)
- return (-1);
- break;
- }
- h->antiBools = calloc(empty_streams,
- sizeof(*h->antiBools));
- if (h->antiBools == NULL)
- return (-1);
- if (read_Bools(a, h->antiBools, empty_streams) < 0)
- return (-1);
- break;
- case kCTime:
- case kATime:
- case kMTime:
- if (read_Times(a, h, type) < 0)
- return (-1);
- break;
- case kName:
- {
- unsigned char *np;
- size_t nl, nb;
-
- /* Skip one byte. */
- if ((p = header_bytes(a, 1)) == NULL)
- return (-1);
- ll--;
-
- if ((ll & 1) || ll < zip->numFiles * 4)
- return (-1);
-
- zip->entry_names = malloc(ll);
- if (zip->entry_names == NULL)
- return (-1);
- np = zip->entry_names;
- nb = ll;
- /*
- * Copy whole file names.
- * NOTE: This loop prevents from expanding
- * the uncompressed buffer in order not to
- * use extra memory resource.
- */
- while (nb) {
- size_t b;
- if (nb > UBUFF_SIZE)
- b = UBUFF_SIZE;
- else
- b = nb;
- if ((p = header_bytes(a, b)) == NULL)
- return (-1);
- memcpy(np, p, b);
- np += b;
- nb -= b;
- }
- np = zip->entry_names;
- nl = ll;
-
- for (i = 0; i < zip->numFiles; i++) {
- entries[i].utf16name = np;
-#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
- entries[i].wname = (wchar_t *)np;
-#endif
-
- /* Find a terminator. */
- while (nl >= 2 && (np[0] || np[1])) {
- np += 2;
- nl -= 2;
- }
- if (nl < 2)
- return (-1);/* Terminator not found */
- entries[i].name_len = np - entries[i].utf16name;
- np += 2;
- nl -= 2;
- }
- break;
- }
- case kAttributes:
- {
- int allAreDefined;
-
- if ((p = header_bytes(a, 2)) == NULL)
- return (-1);
- allAreDefined = *p;
- h->attrBools = calloc((size_t)zip->numFiles,
- sizeof(*h->attrBools));
- if (h->attrBools == NULL)
- return (-1);
- if (allAreDefined)
- memset(h->attrBools, 1, (size_t)zip->numFiles);
- else {
- if (read_Bools(a, h->attrBools,
- (size_t)zip->numFiles) < 0)
- return (-1);
- }
- for (i = 0; i < zip->numFiles; i++) {
- if (h->attrBools[i]) {
- if ((p = header_bytes(a, 4)) == NULL)
- return (-1);
- entries[i].attr = archive_le32dec(p);
- }
- }
- break;
- }
- default:
- if (header_bytes(a, ll) == NULL)
- return (-1);
- break;
- }
- }
-
- /*
- * Set up entry's attributes.
- */
- folders = si->ci.folders;
- eindex = sindex = 0;
- folderIndex = indexInFolder = 0;
- for (i = 0; i < zip->numFiles; i++) {
- if (h->emptyStreamBools == NULL || h->emptyStreamBools[i] == 0)
- entries[i].flg |= HAS_STREAM;
- /* The high 16 bits of attributes is a posix file mode. */
- entries[i].mode = entries[i].attr >> 16;
- if (entries[i].flg & HAS_STREAM) {
- if ((size_t)sindex >= si->ss.unpack_streams)
- return (-1);
- if (entries[i].mode == 0)
- entries[i].mode = AE_IFREG | 0666;
- if (si->ss.digestsDefined[sindex])
- entries[i].flg |= CRC32_IS_SET;
- entries[i].ssIndex = sindex;
- sindex++;
- } else {
- int dir;
- if (h->emptyFileBools == NULL)
- dir = 1;
- else {
- if (h->emptyFileBools[eindex])
- dir = 0;
- else
- dir = 1;
- eindex++;
- }
- if (entries[i].mode == 0) {
- if (dir)
- entries[i].mode = AE_IFDIR | 0777;
- else
- entries[i].mode = AE_IFREG | 0666;
- } else if (dir &&
- (entries[i].mode & AE_IFMT) != AE_IFDIR) {
- entries[i].mode &= ~AE_IFMT;
- entries[i].mode |= AE_IFDIR;
- }
- if ((entries[i].mode & AE_IFMT) == AE_IFDIR &&
- entries[i].name_len >= 2 &&
- (entries[i].utf16name[entries[i].name_len-2] != '/' ||
- entries[i].utf16name[entries[i].name_len-1] != 0)) {
- entries[i].utf16name[entries[i].name_len] = '/';
- entries[i].utf16name[entries[i].name_len+1] = 0;
- entries[i].name_len += 2;
- }
- entries[i].ssIndex = -1;
- }
- if (entries[i].attr & 0x01)
- entries[i].mode &= ~0222;/* Read only. */
-
- if ((entries[i].flg & HAS_STREAM) == 0 && indexInFolder == 0) {
- /*
- * The entry is an empty file or a directory file,
- * those both have no contents.
- */
- entries[i].folderIndex = -1;
- continue;
- }
- if (indexInFolder == 0) {
- for (;;) {
- if (folderIndex >= si->ci.numFolders)
- return (-1);
- if (folders[folderIndex].numUnpackStreams)
- break;
- folderIndex++;
- }
- }
- entries[i].folderIndex = folderIndex;
- if ((entries[i].flg & HAS_STREAM) == 0)
- continue;
- indexInFolder++;
- if (indexInFolder >= folders[folderIndex].numUnpackStreams) {
- folderIndex++;
- indexInFolder = 0;
- }
- }
-
- return (0);
-}
-
-#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
-static void
-fileTimeToUtc(uint64_t fileTime, time_t *timep, long *ns)
-{
-
- if (fileTime >= EPOC_TIME) {
- fileTime -= EPOC_TIME;
- /* milli seconds base */
- *timep = (time_t)(fileTime / 10000000);
- /* nano seconds base */
- *ns = (long)(fileTime % 10000000) * 100;
- } else {
- *timep = 0;
- *ns = 0;
- }
-}
-
-static int
-read_Times(struct archive_read *a, struct _7z_header_info *h, int type)
-{
- struct _7zip *zip = (struct _7zip *)a->format->data;
- const unsigned char *p;
- struct _7zip_entry *entries = zip->entries;
- unsigned char *timeBools;
- int allAreDefined;
- unsigned i;
-
- timeBools = calloc((size_t)zip->numFiles, sizeof(*timeBools));
- if (timeBools == NULL)
- return (-1);
-
- /* Read allAreDefined. */
- if ((p = header_bytes(a, 1)) == NULL)
- goto failed;
- allAreDefined = *p;
- if (allAreDefined)
- memset(timeBools, 1, (size_t)zip->numFiles);
- else {
- if (read_Bools(a, timeBools, (size_t)zip->numFiles) < 0)
- goto failed;
- }
-
- /* Read external. */
- if ((p = header_bytes(a, 1)) == NULL)
- goto failed;
- if (*p) {
- if (parse_7zip_uint64(a, &(h->dataIndex)) < 0)
- goto failed;
- if (1000000 < h->dataIndex)
- goto failed;
- }
-
- for (i = 0; i < zip->numFiles; i++) {
- if (!timeBools[i])
- continue;
- if ((p = header_bytes(a, 8)) == NULL)
- goto failed;
- switch (type) {
- case kCTime:
- fileTimeToUtc(archive_le64dec(p),
- &(entries[i].ctime),
- &(entries[i].ctime_ns));
- entries[i].flg |= CTIME_IS_SET;
- break;
- case kATime:
- fileTimeToUtc(archive_le64dec(p),
- &(entries[i].atime),
- &(entries[i].atime_ns));
- entries[i].flg |= ATIME_IS_SET;
- break;
- case kMTime:
- fileTimeToUtc(archive_le64dec(p),
- &(entries[i].mtime),
- &(entries[i].mtime_ns));
- entries[i].flg |= MTIME_IS_SET;
- break;
- }
- }
-
- free(timeBools);
- return (0);
-failed:
- free(timeBools);
- return (-1);
-}
-
-static int
-decode_encoded_header_info(struct archive_read *a, struct _7z_stream_info *si)
-{
- struct _7zip *zip = (struct _7zip *)a->format->data;
-
- errno = 0;
- if (read_StreamsInfo(a, si) < 0) {
- if (errno == ENOMEM)
- archive_set_error(&a->archive, -1,
- "Couldn't allocate memory");
- else
- archive_set_error(&a->archive, -1,
- "Malformed 7-Zip archive");
- return (ARCHIVE_FATAL);
- }
-
- if (si->pi.numPackStreams == 0 || si->ci.numFolders == 0) {
- archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");
- return (ARCHIVE_FATAL);
- }
-
- if (zip->header_offset < si->pi.pos + si->pi.sizes[0] ||
- (int64_t)(si->pi.pos + si->pi.sizes[0]) < 0 ||
- si->pi.sizes[0] == 0 || (int64_t)si->pi.pos < 0) {
- archive_set_error(&a->archive, -1, "Malformed Header offset");
- return (ARCHIVE_FATAL);
- }
-
- return (ARCHIVE_OK);
-}
-
-static const unsigned char *
-header_bytes(struct archive_read *a, size_t rbytes)
-{
- struct _7zip *zip = (struct _7zip *)a->format->data;
- const unsigned char *p;
-
- if (zip->header_bytes_remaining < rbytes)
- return (NULL);
- if (zip->pack_stream_bytes_unconsumed)
- read_consume(a);
-
- if (zip->header_is_encoded == 0) {
- p = __archive_read_ahead(a, rbytes, NULL);
- if (p == NULL)
- return (NULL);
- zip->header_bytes_remaining -= rbytes;
- zip->pack_stream_bytes_unconsumed = rbytes;
- } else {
- const void *buff;
- ssize_t bytes;
-
- bytes = read_stream(a, &buff, rbytes, rbytes);
- if (bytes <= 0)
- return (NULL);
- zip->header_bytes_remaining -= bytes;
- p = buff;
- }
-
- /* Update checksum */
- zip->header_crc32 = crc32(zip->header_crc32, p, (unsigned)rbytes);
- return (p);
-}
-
-static int
-slurp_central_directory(struct archive_read *a, struct _7zip *zip,
- struct _7z_header_info *header)
-{
- const unsigned char *p;
- uint64_t next_header_offset;
- uint64_t next_header_size;
- uint32_t next_header_crc;
- ssize_t bytes_avail;
- int check_header_crc, r;
-
- if ((p = __archive_read_ahead(a, 32, &bytes_avail)) == NULL)
- return (ARCHIVE_FATAL);
-
- if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {
- /* This is an executable ? Must be self-extracting... */
- r = skip_sfx(a, bytes_avail);
- if (r < ARCHIVE_WARN)
- return (r);
- if ((p = __archive_read_ahead(a, 32, &bytes_avail)) == NULL)
- return (ARCHIVE_FATAL);
- }
- zip->seek_base += 32;
-
- if (memcmp(p, _7ZIP_SIGNATURE, 6) != 0) {
- archive_set_error(&a->archive, -1, "Not 7-Zip archive file");
- return (ARCHIVE_FATAL);
- }
-
- /* CRC check. */
- if (crc32(0, (const unsigned char *)p + 12, 20)
- != archive_le32dec(p + 8)) {
- archive_set_error(&a->archive, -1, "Header CRC error");
- return (ARCHIVE_FATAL);
- }
-
- next_header_offset = archive_le64dec(p + 12);
- next_header_size = archive_le64dec(p + 20);
- next_header_crc = archive_le32dec(p + 28);
-
- if (next_header_size == 0)
- /* There is no entry in an archive file. */
- return (ARCHIVE_EOF);
-
- if (((int64_t)next_header_offset) < 0) {
- archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");
- return (ARCHIVE_FATAL);
- }
- __archive_read_consume(a, 32);
- if (next_header_offset != 0) {
- if (bytes_avail >= (ssize_t)next_header_offset)
- __archive_read_consume(a, next_header_offset);
- else if (__archive_read_seek(a,
- next_header_offset + zip->seek_base, SEEK_SET) < 0)
- return (ARCHIVE_FATAL);
- }
- zip->stream_offset = next_header_offset;
- zip->header_offset = next_header_offset;
- zip->header_bytes_remaining = next_header_size;
- zip->header_crc32 = 0;
- zip->header_is_encoded = 0;
- zip->header_is_being_read = 1;
- check_header_crc = 1;
-
- if ((p = header_bytes(a, 1)) == NULL) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated 7-Zip file body");
- return (ARCHIVE_FATAL);
- }
- /* Parse ArchiveProperties. */
- switch (p[0]) {
- case kEncodedHeader:
- /*
- * The archive has an encoded header and we have to decode it
- * in order to parse the header correctly.
- */
- r = decode_encoded_header_info(a, &(zip->si));
-
- /* Check the EncodedHeader CRC.*/
- if (r == 0 && zip->header_crc32 != next_header_crc) {
- archive_set_error(&a->archive, -1,
- "Damaged 7-Zip archive");
- r = -1;
- }
- if (r == 0) {
- if (zip->si.ci.folders[0].digest_defined)
- next_header_crc = zip->si.ci.folders[0].digest;
- else
- check_header_crc = 0;
- if (zip->pack_stream_bytes_unconsumed)
- read_consume(a);
- r = setup_decode_folder(a, zip->si.ci.folders, 1);
- if (r == 0) {
- zip->header_bytes_remaining =
- zip->folder_outbytes_remaining;
- r = seek_pack(a);
- }
- }
- /* Clean up StreamsInfo. */
- free_StreamsInfo(&(zip->si));
- memset(&(zip->si), 0, sizeof(zip->si));
- if (r < 0)
- return (ARCHIVE_FATAL);
- zip->header_is_encoded = 1;
- zip->header_crc32 = 0;
- /* FALL THROUGH */
- case kHeader:
- /*
- * Parse the header.
- */
- errno = 0;
- r = read_Header(a, header, zip->header_is_encoded);
- if (r < 0) {
- if (errno == ENOMEM)
- archive_set_error(&a->archive, -1,
- "Couldn't allocate memory");
- else
- archive_set_error(&a->archive, -1,
- "Damaged 7-Zip archive");
- return (ARCHIVE_FATAL);
- }
-
- /*
- * Must be kEnd.
- */
- if ((p = header_bytes(a, 1)) == NULL ||*p != kEnd) {
- archive_set_error(&a->archive, -1,
- "Malformed 7-Zip archive");
- return (ARCHIVE_FATAL);
- }
-
- /* Check the Header CRC.*/
- if (check_header_crc && zip->header_crc32 != next_header_crc) {
- archive_set_error(&a->archive, -1,
- "Malformed 7-Zip archive");
- return (ARCHIVE_FATAL);
- }
- break;
- default:
- archive_set_error(&a->archive, -1,
- "Unexpected Property ID = %X", p[0]);
- return (ARCHIVE_FATAL);
- }
-
- /* Clean up variables be used for decoding the archive header */
- zip->pack_stream_remaining = 0;
- zip->pack_stream_index = 0;
- zip->folder_outbytes_remaining = 0;
- zip->uncompressed_buffer_bytes_remaining = 0;
- zip->pack_stream_bytes_unconsumed = 0;
- zip->header_is_being_read = 0;
-
- return (ARCHIVE_OK);
-}
-
-static ssize_t
-get_uncompressed_data(struct archive_read *a, const void **buff, size_t size,
- size_t minimum)
-{
- struct _7zip *zip = (struct _7zip *)a->format->data;
- ssize_t bytes_avail;
-
- if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {
- /* Copy mode. */
-
- /*
- * Note: '1' here is a performance optimization.
- * Recall that the decompression layer returns a count of
- * available bytes; asking for more than that forces the
- * decompressor to combine reads by copying data.
- */
- *buff = __archive_read_ahead(a, 1, &bytes_avail);
- if (bytes_avail <= 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated 7-Zip file data");
- return (ARCHIVE_FATAL);
- }
- if ((size_t)bytes_avail >
- zip->uncompressed_buffer_bytes_remaining)
- bytes_avail = (ssize_t)
- zip->uncompressed_buffer_bytes_remaining;
- if ((size_t)bytes_avail > size)
- bytes_avail = (ssize_t)size;
-
- zip->pack_stream_bytes_unconsumed = bytes_avail;
- } else if (zip->uncompressed_buffer_pointer == NULL) {
- /* Decompression has failed. */
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");
- return (ARCHIVE_FATAL);
- } else {
- /* Packed mode. */
- if (minimum > zip->uncompressed_buffer_bytes_remaining) {
- /*
- * If remaining uncompressed data size is less than
- * the minimum size, fill the buffer up to the
- * minimum size.
- */
- if (extract_pack_stream(a, minimum) < 0)
- return (ARCHIVE_FATAL);
- }
- if (size > zip->uncompressed_buffer_bytes_remaining)
- bytes_avail = (ssize_t)
- zip->uncompressed_buffer_bytes_remaining;
- else
- bytes_avail = (ssize_t)size;
- *buff = zip->uncompressed_buffer_pointer;
- zip->uncompressed_buffer_pointer += bytes_avail;
- }
- zip->uncompressed_buffer_bytes_remaining -= bytes_avail;
- return (bytes_avail);
-}
-
-static ssize_t
-extract_pack_stream(struct archive_read *a, size_t minimum)
-{
- struct _7zip *zip = (struct _7zip *)a->format->data;
- ssize_t bytes_avail;
- int r;
-
- if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {
- if (minimum == 0)
- minimum = 1;
- if (__archive_read_ahead(a, minimum, &bytes_avail) == NULL
- || bytes_avail <= 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated 7-Zip file body");
- return (ARCHIVE_FATAL);
- }
- if (bytes_avail > (ssize_t)zip->pack_stream_inbytes_remaining)
- bytes_avail = (ssize_t)zip->pack_stream_inbytes_remaining;
- zip->pack_stream_inbytes_remaining -= bytes_avail;
- if (bytes_avail > (ssize_t)zip->folder_outbytes_remaining)
- bytes_avail = (ssize_t)zip->folder_outbytes_remaining;
- zip->folder_outbytes_remaining -= bytes_avail;
- zip->uncompressed_buffer_bytes_remaining = bytes_avail;
- return (ARCHIVE_OK);
- }
-
- /* If the buffer hasn't been allocated, allocate it now. */
- if (zip->uncompressed_buffer == NULL) {
- zip->uncompressed_buffer_size = UBUFF_SIZE;
- if (zip->uncompressed_buffer_size < minimum) {
- zip->uncompressed_buffer_size = minimum + 1023;
- zip->uncompressed_buffer_size &= ~0x3ff;
- }
- zip->uncompressed_buffer =
- malloc(zip->uncompressed_buffer_size);
- if (zip->uncompressed_buffer == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "No memory for 7-Zip decompression");
- return (ARCHIVE_FATAL);
- }
- zip->uncompressed_buffer_bytes_remaining = 0;
- } else if (zip->uncompressed_buffer_size < minimum ||
- zip->uncompressed_buffer_bytes_remaining < minimum) {
- /*
- * Make sure the uncompressed buffer can have bytes
- * at least `minimum' bytes.
- * NOTE: This case happen when reading the header.
- */
- size_t used;
- if (zip->uncompressed_buffer_pointer != 0)
- used = zip->uncompressed_buffer_pointer -
- zip->uncompressed_buffer;
- else
- used = 0;
- if (zip->uncompressed_buffer_size < minimum) {
- /*
- * Expand the uncompressed buffer up to
- * the minimum size.
- */
- void *p;
- size_t new_size;
-
- new_size = minimum + 1023;
- new_size &= ~0x3ff;
- p = realloc(zip->uncompressed_buffer, new_size);
- if (p == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "No memory for 7-Zip decompression");
- return (ARCHIVE_FATAL);
- }
- zip->uncompressed_buffer = (unsigned char *)p;
- zip->uncompressed_buffer_size = new_size;
- }
- /*
- * Move unconsumed bytes to the head.
- */
- if (used) {
- memmove(zip->uncompressed_buffer,
- zip->uncompressed_buffer + used,
- zip->uncompressed_buffer_bytes_remaining);
- }
- } else
- zip->uncompressed_buffer_bytes_remaining = 0;
- zip->uncompressed_buffer_pointer = NULL;
- for (;;) {
- size_t bytes_in, bytes_out;
- const void *buff_in;
- unsigned char *buff_out;
- int end_of_data;
-
- /*
- * Note: '1' here is a performance optimization.
- * Recall that the decompression layer returns a count of
- * available bytes; asking for more than that forces the
- * decompressor to combine reads by copying data.
- */
- buff_in = __archive_read_ahead(a, 1, &bytes_avail);
- if (bytes_avail <= 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated 7-Zip file body");
- return (ARCHIVE_FATAL);
- }
-
- buff_out = zip->uncompressed_buffer
- + zip->uncompressed_buffer_bytes_remaining;
- bytes_out = zip->uncompressed_buffer_size
- - zip->uncompressed_buffer_bytes_remaining;
- bytes_in = bytes_avail;
- if (bytes_in > zip->pack_stream_inbytes_remaining)
- bytes_in = (size_t)zip->pack_stream_inbytes_remaining;
- /* Drive decompression. */
- r = decompress(a, zip, buff_out, &bytes_out,
- buff_in, &bytes_in);
- switch (r) {
- case ARCHIVE_OK:
- end_of_data = 0;
- break;
- case ARCHIVE_EOF:
- end_of_data = 1;
- break;
- default:
- return (ARCHIVE_FATAL);
- }
- zip->pack_stream_inbytes_remaining -= bytes_in;
- if (bytes_out > zip->folder_outbytes_remaining)
- bytes_out = (size_t)zip->folder_outbytes_remaining;
- zip->folder_outbytes_remaining -= bytes_out;
- zip->uncompressed_buffer_bytes_remaining += bytes_out;
- zip->pack_stream_bytes_unconsumed = bytes_in;
-
- /*
- * Continue decompression until uncompressed_buffer is full.
- */
- if (zip->uncompressed_buffer_bytes_remaining ==
- zip->uncompressed_buffer_size)
- break;
- if (zip->codec2 == _7Z_X86 && zip->odd_bcj_size &&
- zip->uncompressed_buffer_bytes_remaining + 5 >
- zip->uncompressed_buffer_size)
- break;
- if (zip->pack_stream_inbytes_remaining == 0 &&
- zip->folder_outbytes_remaining == 0)
- break;
- if (end_of_data || (bytes_in == 0 && bytes_out == 0)) {
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");
- return (ARCHIVE_FATAL);
- }
- read_consume(a);
- }
- if (zip->uncompressed_buffer_bytes_remaining < minimum) {
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");
- return (ARCHIVE_FATAL);
- }
- zip->uncompressed_buffer_pointer = zip->uncompressed_buffer;
- return (ARCHIVE_OK);
-}
-
-static int
-seek_pack(struct archive_read *a)
-{
- struct _7zip *zip = (struct _7zip *)a->format->data;
- int64_t pack_offset;
-
- if (zip->pack_stream_remaining <= 0) {
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");
- return (ARCHIVE_FATAL);
- }
- zip->pack_stream_inbytes_remaining =
- zip->si.pi.sizes[zip->pack_stream_index];
- pack_offset = zip->si.pi.positions[zip->pack_stream_index];
- if (zip->stream_offset != pack_offset) {
- if (0 > __archive_read_seek(a, pack_offset + zip->seek_base,
- SEEK_SET))
- return (ARCHIVE_FATAL);
- zip->stream_offset = pack_offset;
- }
- zip->pack_stream_index++;
- zip->pack_stream_remaining--;
- return (ARCHIVE_OK);
-}
-
-static ssize_t
-read_stream(struct archive_read *a, const void **buff, size_t size,
- size_t minimum)
-{
- struct _7zip *zip = (struct _7zip *)a->format->data;
- uint64_t skip_bytes = 0;
- ssize_t r;
-
- if (zip->uncompressed_buffer_bytes_remaining == 0) {
- if (zip->pack_stream_inbytes_remaining > 0) {
- r = extract_pack_stream(a, 0);
- if (r < 0)
- return (r);
- return (get_uncompressed_data(a, buff, size, minimum));
- } else if (zip->folder_outbytes_remaining > 0) {
- /* Extract a remaining pack stream. */
- r = extract_pack_stream(a, 0);
- if (r < 0)
- return (r);
- return (get_uncompressed_data(a, buff, size, minimum));
- }
- } else
- return (get_uncompressed_data(a, buff, size, minimum));
-
- /*
- * Current pack stream has been consumed.
- */
- if (zip->pack_stream_remaining == 0) {
- if (zip->header_is_being_read) {
- /* Invalid sequence. This might happen when
- * reading a malformed archive. */
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC, "Malformed 7-Zip archive");
- return (ARCHIVE_FATAL);
- }
-
- /*
- * All current folder's pack streams have been
- * consumed. Switch to next folder.
- */
- if (zip->folder_index == 0 &&
- (zip->si.ci.folders[zip->entry->folderIndex].skipped_bytes
- || zip->folder_index != zip->entry->folderIndex)) {
- zip->folder_index = zip->entry->folderIndex;
- skip_bytes =
- zip->si.ci.folders[zip->folder_index].skipped_bytes;
- }
-
- if (zip->folder_index >= zip->si.ci.numFolders) {
- /*
- * We have consumed all folders and its pack streams.
- */
- *buff = NULL;
- return (0);
- }
- r = setup_decode_folder(a,
- &(zip->si.ci.folders[zip->folder_index]), 0);
- if (r != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- zip->folder_index++;
- }
-
- /*
- * Switch to next pack stream.
- */
- r = seek_pack(a);
- if (r < 0)
- return (r);
-
- /* Extract a new pack stream. */
- r = extract_pack_stream(a, 0);
- if (r < 0)
- return (r);
-
- /*
- * Skip the bytes we alrady has skipped in skip_stream().
- */
- while (skip_bytes) {
- ssize_t skipped;
-
- if (zip->uncompressed_buffer_bytes_remaining == 0) {
- if (zip->pack_stream_inbytes_remaining > 0) {
- r = extract_pack_stream(a, 0);
- if (r < 0)
- return (r);
- } else if (zip->folder_outbytes_remaining > 0) {
- /* Extract a remaining pack stream. */
- r = extract_pack_stream(a, 0);
- if (r < 0)
- return (r);
- } else {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated 7-Zip file body");
- return (ARCHIVE_FATAL);
- }
- }
- skipped = get_uncompressed_data(
- a, buff, (size_t)skip_bytes, 0);
- if (skipped < 0)
- return (skipped);
- skip_bytes -= skipped;
- if (zip->pack_stream_bytes_unconsumed)
- read_consume(a);
- }
-
- return (get_uncompressed_data(a, buff, size, minimum));
-}
-
-static int
-setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
- int header)
-{
- struct _7zip *zip = (struct _7zip *)a->format->data;
- const struct _7z_coder *coder1, *coder2;
- const char *cname = (header)?"archive header":"file content";
- unsigned i;
- int r, found_bcj2 = 0;
-
- /*
- * Release the memory which the previous folder used for BCJ2.
- */
- for (i = 0; i < 3; i++) {
- if (zip->sub_stream_buff[i] != NULL)
- free(zip->sub_stream_buff[i]);
- zip->sub_stream_buff[i] = NULL;
- }
-
- /*
- * Initialize a stream reader.
- */
- zip->pack_stream_remaining = (unsigned)folder->numPackedStreams;
- zip->pack_stream_index = (unsigned)folder->packIndex;
- zip->folder_outbytes_remaining = folder_uncompressed_size(folder);
- zip->uncompressed_buffer_bytes_remaining = 0;
-
- /*
- * Check coder types.
- */
- for (i = 0; i < folder->numCoders; i++) {
- if (folder->coders[i].codec == _7Z_CRYPTO) {
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "The %s is encrypted, "
- "but currently not supported", cname);
- return (ARCHIVE_FATAL);
- }
- if (folder->coders[i].codec == _7Z_X86_BCJ2)
- found_bcj2++;
- }
- if ((folder->numCoders > 2 && !found_bcj2) || found_bcj2 > 1) {
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "The %s is encoded with many filters, "
- "but currently not supported", cname);
- return (ARCHIVE_FATAL);
- }
- coder1 = &(folder->coders[0]);
- if (folder->numCoders == 2)
- coder2 = &(folder->coders[1]);
- else
- coder2 = NULL;
-
- if (found_bcj2) {
- /*
- * Preparation to decode BCJ2.
- * Decoding BCJ2 requires four sources. Those are at least,
- * as far as I know, two types of the storage form.
- */
- const struct _7z_coder *fc = folder->coders;
- static const struct _7z_coder coder_copy = {0, 1, 1, 0, NULL};
- const struct _7z_coder *scoder[3] =
- {&coder_copy, &coder_copy, &coder_copy};
- const void *buff;
- ssize_t bytes;
- unsigned char *b[3] = {NULL, NULL, NULL};
- uint64_t sunpack[3] ={-1, -1, -1};
- size_t s[3] = {0, 0, 0};
- int idx[3] = {0, 1, 2};
-
- if (folder->numCoders == 4 && fc[3].codec == _7Z_X86_BCJ2 &&
- folder->numInStreams == 7 && folder->numOutStreams == 4 &&
- zip->pack_stream_remaining == 4) {
- /* Source type 1 made by 7zr or 7z with -m options. */
- if (folder->bindPairs[0].inIndex == 5) {
- /* The form made by 7zr */
- idx[0] = 1; idx[1] = 2; idx[2] = 0;
- scoder[1] = &(fc[1]);
- scoder[2] = &(fc[0]);
- sunpack[1] = folder->unPackSize[1];
- sunpack[2] = folder->unPackSize[0];
- coder1 = &(fc[2]);
- } else {
- /*
- * NOTE: Some patterns do not work.
- * work:
- * 7z a -m0=BCJ2 -m1=COPY -m2=COPY
- * -m3=(any)
- * 7z a -m0=BCJ2 -m1=COPY -m2=(any)
- * -m3=COPY
- * 7z a -m0=BCJ2 -m1=(any) -m2=COPY
- * -m3=COPY
- * not work:
- * other patterns.
- *
- * We have to handle this like `pipe' or
- * our libarchive7s filter frame work,
- * decoding the BCJ2 main stream sequentially,
- * m3 -> m2 -> m1 -> BCJ2.
- *
- */
- if (fc[0].codec == _7Z_COPY &&
- fc[1].codec == _7Z_COPY)
- coder1 = &(folder->coders[2]);
- else if (fc[0].codec == _7Z_COPY &&
- fc[2].codec == _7Z_COPY)
- coder1 = &(folder->coders[1]);
- else if (fc[1].codec == _7Z_COPY &&
- fc[2].codec == _7Z_COPY)
- coder1 = &(folder->coders[0]);
- else {
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "Unsupported form of "
- "BCJ2 streams");
- return (ARCHIVE_FATAL);
- }
- }
- coder2 = &(fc[3]);
- zip->main_stream_bytes_remaining =
- (size_t)folder->unPackSize[2];
- } else if (coder2 != NULL && coder2->codec == _7Z_X86_BCJ2 &&
- zip->pack_stream_remaining == 4 &&
- folder->numInStreams == 5 && folder->numOutStreams == 2) {
- /* Source type 0 made by 7z */
- zip->main_stream_bytes_remaining =
- (size_t)folder->unPackSize[0];
- } else {
- /* We got an unexpected form. */
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "Unsupported form of BCJ2 streams");
- return (ARCHIVE_FATAL);
- }
-
- /* Skip the main stream at this time. */
- if ((r = seek_pack(a)) < 0)
- return (r);
- zip->pack_stream_bytes_unconsumed =
- (size_t)zip->pack_stream_inbytes_remaining;
- read_consume(a);
-
- /* Read following three sub streams. */
- for (i = 0; i < 3; i++) {
- const struct _7z_coder *coder = scoder[i];
-
- if ((r = seek_pack(a)) < 0) {
- free(b[0]); free(b[1]); free(b[2]);
- return (r);
- }
-
- if (sunpack[i] == (uint64_t)-1)
- zip->folder_outbytes_remaining =
- zip->pack_stream_inbytes_remaining;
- else
- zip->folder_outbytes_remaining = sunpack[i];
-
- r = init_decompression(a, zip, coder, NULL);
- if (r != ARCHIVE_OK) {
- free(b[0]); free(b[1]); free(b[2]);
- return (ARCHIVE_FATAL);
- }
-
- /* Allocate memory for the decorded data of a sub
- * stream. */
- b[i] = malloc((size_t)zip->folder_outbytes_remaining);
- if (b[i] == NULL) {
- free(b[0]); free(b[1]); free(b[2]);
- archive_set_error(&a->archive, ENOMEM,
- "No memory for 7-Zip decompression");
- return (ARCHIVE_FATAL);
- }
-
- /* Extract a sub stream. */
- while (zip->pack_stream_inbytes_remaining > 0) {
- r = (int)extract_pack_stream(a, 0);
- if (r < 0) {
- free(b[0]); free(b[1]); free(b[2]);
- return (r);
- }
- bytes = get_uncompressed_data(a, &buff,
- zip->uncompressed_buffer_bytes_remaining,
- 0);
- if (bytes < 0) {
- free(b[0]); free(b[1]); free(b[2]);
- return ((int)bytes);
- }
- memcpy(b[i]+s[i], buff, bytes);
- s[i] += bytes;
- if (zip->pack_stream_bytes_unconsumed)
- read_consume(a);
- }
- }
-
- /* Set the sub streams to the right place. */
- for (i = 0; i < 3; i++) {
- zip->sub_stream_buff[i] = b[idx[i]];
- zip->sub_stream_size[i] = s[idx[i]];
- zip->sub_stream_bytes_remaining[i] = s[idx[i]];
- }
-
- /* Allocate memory used for decoded main stream bytes. */
- if (zip->tmp_stream_buff == NULL) {
- zip->tmp_stream_buff_size = 32 * 1024;
- zip->tmp_stream_buff =
- malloc(zip->tmp_stream_buff_size);
- if (zip->tmp_stream_buff == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "No memory for 7-Zip decompression");
- return (ARCHIVE_FATAL);
- }
- }
- zip->tmp_stream_bytes_avail = 0;
- zip->tmp_stream_bytes_remaining = 0;
- zip->odd_bcj_size = 0;
- zip->bcj2_outPos = 0;
-
- /*
- * Reset a stream reader in order to read the main stream
- * of BCJ2.
- */
- zip->pack_stream_remaining = 1;
- zip->pack_stream_index = (unsigned)folder->packIndex;
- zip->folder_outbytes_remaining =
- folder_uncompressed_size(folder);
- zip->uncompressed_buffer_bytes_remaining = 0;
- }
-
- /*
- * Initialize the decompressor for the new folder's pack streams.
- */
- r = init_decompression(a, zip, coder1, coder2);
- if (r != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- return (ARCHIVE_OK);
-}
-
-static int64_t
-skip_stream(struct archive_read *a, size_t skip_bytes)
-{
- struct _7zip *zip = (struct _7zip *)a->format->data;
- const void *p;
- int64_t skipped_bytes;
- size_t bytes = skip_bytes;
-
- if (zip->folder_index == 0) {
- /*
- * Optimization for a list mode.
- * Avoid unncecessary decoding operations.
- */
- zip->si.ci.folders[zip->entry->folderIndex].skipped_bytes
- += skip_bytes;
- return (skip_bytes);
- }
-
- while (bytes) {
- skipped_bytes = read_stream(a, &p, bytes, 0);
- if (skipped_bytes < 0)
- return (skipped_bytes);
- if (skipped_bytes == 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated 7-Zip file body");
- return (ARCHIVE_FATAL);
- }
- bytes -= (size_t)skipped_bytes;
- if (zip->pack_stream_bytes_unconsumed)
- read_consume(a);
- }
- return (skip_bytes);
-}
-
-/*
- * Brought from LZMA SDK.
- *
- * Bra86.c -- Converter for x86 code (BCJ)
- * 2008-10-04 : Igor Pavlov : Public domain
- *
- */
-
-#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)
-
-static void
-x86_Init(struct _7zip *zip)
-{
- zip->bcj_state = 0;
- zip->bcj_prevPosT = (size_t)0 - 1;
- zip->bcj_prevMask = 0;
- zip->bcj_ip = 5;
-}
-
-static size_t
-x86_Convert(struct _7zip *zip, uint8_t *data, size_t size)
-{
- static const uint8_t kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0};
- static const uint8_t kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3};
- size_t bufferPos, prevPosT;
- uint32_t ip, prevMask;
-
- if (size < 5)
- return 0;
-
- bufferPos = 0;
- prevPosT = zip->bcj_prevPosT;
- prevMask = zip->bcj_prevMask;
- ip = zip->bcj_ip;
-
- for (;;) {
- uint8_t *p = data + bufferPos;
- uint8_t *limit = data + size - 4;
-
- for (; p < limit; p++)
- if ((*p & 0xFE) == 0xE8)
- break;
- bufferPos = (size_t)(p - data);
- if (p >= limit)
- break;
- prevPosT = bufferPos - prevPosT;
- if (prevPosT > 3)
- prevMask = 0;
- else {
- prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7;
- if (prevMask != 0) {
- unsigned char b =
- p[4 - kMaskToBitNumber[prevMask]];
- if (!kMaskToAllowedStatus[prevMask] ||
- Test86MSByte(b)) {
- prevPosT = bufferPos;
- prevMask = ((prevMask << 1) & 0x7) | 1;
- bufferPos++;
- continue;
- }
- }
- }
- prevPosT = bufferPos;
-
- if (Test86MSByte(p[4])) {
- uint32_t src = ((uint32_t)p[4] << 24) |
- ((uint32_t)p[3] << 16) | ((uint32_t)p[2] << 8) |
- ((uint32_t)p[1]);
- uint32_t dest;
- for (;;) {
- uint8_t b;
- int b_index;
-
- dest = src - (ip + (uint32_t)bufferPos);
- if (prevMask == 0)
- break;
- b_index = kMaskToBitNumber[prevMask] * 8;
- b = (uint8_t)(dest >> (24 - b_index));
- if (!Test86MSByte(b))
- break;
- src = dest ^ ((1 << (32 - b_index)) - 1);
- }
- p[4] = (uint8_t)(~(((dest >> 24) & 1) - 1));
- p[3] = (uint8_t)(dest >> 16);
- p[2] = (uint8_t)(dest >> 8);
- p[1] = (uint8_t)dest;
- bufferPos += 5;
- } else {
- prevMask = ((prevMask << 1) & 0x7) | 1;
- bufferPos++;
- }
- }
- zip->bcj_prevPosT = prevPosT;
- zip->bcj_prevMask = prevMask;
- zip->bcj_ip += (uint32_t)bufferPos;
- return (bufferPos);
-}
-
-/*
- * Brought from LZMA SDK.
- *
- * Bcj2.c -- Converter for x86 code (BCJ2)
- * 2008-10-04 : Igor Pavlov : Public domain
- *
- */
-
-#define SZ_ERROR_DATA ARCHIVE_FAILED
-
-#define IsJcc(b0, b1) ((b0) == 0x0F && ((b1) & 0xF0) == 0x80)
-#define IsJ(b0, b1) ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1))
-
-#define kNumTopBits 24
-#define kTopValue ((uint32_t)1 << kNumTopBits)
-
-#define kNumBitModelTotalBits 11
-#define kBitModelTotal (1 << kNumBitModelTotalBits)
-#define kNumMoveBits 5
-
-#define RC_READ_BYTE (*buffer++)
-#define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; }
-#define RC_INIT2 zip->bcj2_code = 0; zip->bcj2_range = 0xFFFFFFFF; \
- { int ii; for (ii = 0; ii < 5; ii++) { RC_TEST; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }}
-
-#define NORMALIZE if (zip->bcj2_range < kTopValue) { RC_TEST; zip->bcj2_range <<= 8; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }
-
-#define IF_BIT_0(p) ttt = *(p); bound = (zip->bcj2_range >> kNumBitModelTotalBits) * ttt; if (zip->bcj2_code < bound)
-#define UPDATE_0(p) zip->bcj2_range = bound; *(p) = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); NORMALIZE;
-#define UPDATE_1(p) zip->bcj2_range -= bound; zip->bcj2_code -= bound; *(p) = (CProb)(ttt - (ttt >> kNumMoveBits)); NORMALIZE;
-
-static ssize_t
-Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize)
-{
- size_t inPos = 0, outPos = 0;
- const uint8_t *buf0, *buf1, *buf2, *buf3;
- size_t size0, size1, size2, size3;
- const uint8_t *buffer, *bufferLim;
- unsigned int i, j;
-
- size0 = zip->tmp_stream_bytes_remaining;
- buf0 = zip->tmp_stream_buff + zip->tmp_stream_bytes_avail - size0;
- size1 = zip->sub_stream_bytes_remaining[0];
- buf1 = zip->sub_stream_buff[0] + zip->sub_stream_size[0] - size1;
- size2 = zip->sub_stream_bytes_remaining[1];
- buf2 = zip->sub_stream_buff[1] + zip->sub_stream_size[1] - size2;
- size3 = zip->sub_stream_bytes_remaining[2];
- buf3 = zip->sub_stream_buff[2] + zip->sub_stream_size[2] - size3;
-
- buffer = buf3;
- bufferLim = buffer + size3;
-
- if (zip->bcj_state == 0) {
- /*
- * Initialize.
- */
- zip->bcj2_prevByte = 0;
- for (i = 0;
- i < sizeof(zip->bcj2_p) / sizeof(zip->bcj2_p[0]); i++)
- zip->bcj2_p[i] = kBitModelTotal >> 1;
- RC_INIT2;
- zip->bcj_state = 1;
- }
-
- /*
- * Gather the odd bytes of a previous call.
- */
- for (i = 0; zip->odd_bcj_size > 0 && outPos < outSize; i++) {
- outBuf[outPos++] = zip->odd_bcj[i];
- zip->odd_bcj_size--;
- }
-
- if (outSize == 0) {
- zip->bcj2_outPos += outPos;
- return (outPos);
- }
-
- for (;;) {
- uint8_t b;
- CProb *prob;
- uint32_t bound;
- uint32_t ttt;
-
- size_t limit = size0 - inPos;
- if (outSize - outPos < limit)
- limit = outSize - outPos;
-
- if (zip->bcj_state == 1) {
- while (limit != 0) {
- uint8_t bb = buf0[inPos];
- outBuf[outPos++] = bb;
- if (IsJ(zip->bcj2_prevByte, bb)) {
- zip->bcj_state = 2;
- break;
- }
- inPos++;
- zip->bcj2_prevByte = bb;
- limit--;
- }
- }
-
- if (limit == 0 || outPos == outSize)
- break;
- zip->bcj_state = 1;
-
- b = buf0[inPos++];
-
- if (b == 0xE8)
- prob = zip->bcj2_p + zip->bcj2_prevByte;
- else if (b == 0xE9)
- prob = zip->bcj2_p + 256;
- else
- prob = zip->bcj2_p + 257;
-
- IF_BIT_0(prob) {
- UPDATE_0(prob)
- zip->bcj2_prevByte = b;
- } else {
- uint32_t dest;
- const uint8_t *v;
- uint8_t out[4];
-
- UPDATE_1(prob)
- if (b == 0xE8) {
- v = buf1;
- if (size1 < 4)
- return SZ_ERROR_DATA;
- buf1 += 4;
- size1 -= 4;
- } else {
- v = buf2;
- if (size2 < 4)
- return SZ_ERROR_DATA;
- buf2 += 4;
- size2 -= 4;
- }
- dest = (((uint32_t)v[0] << 24) |
- ((uint32_t)v[1] << 16) |
- ((uint32_t)v[2] << 8) |
- ((uint32_t)v[3])) -
- ((uint32_t)zip->bcj2_outPos + (uint32_t)outPos + 4);
- out[0] = (uint8_t)dest;
- out[1] = (uint8_t)(dest >> 8);
- out[2] = (uint8_t)(dest >> 16);
- out[3] = zip->bcj2_prevByte = (uint8_t)(dest >> 24);
-
- for (i = 0; i < 4 && outPos < outSize; i++)
- outBuf[outPos++] = out[i];
- if (i < 4) {
- /*
- * Save odd bytes which we could not add into
- * the output buffer because of out of space.
- */
- zip->odd_bcj_size = 4 -i;
- for (; i < 4; i++) {
- j = i - 4 + (unsigned)zip->odd_bcj_size;
- zip->odd_bcj[j] = out[i];
- }
- break;
- }
- }
- }
- zip->tmp_stream_bytes_remaining -= inPos;
- zip->sub_stream_bytes_remaining[0] = size1;
- zip->sub_stream_bytes_remaining[1] = size2;
- zip->sub_stream_bytes_remaining[2] = bufferLim - buffer;
- zip->bcj2_outPos += outPos;
-
- return ((ssize_t)outPos);
-}
-
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_format_all.c b/3rdparty/libarchive/libarchive/archive_read_support_format_all.c
deleted file mode 100644
index 53fe6fa3..00000000
--- a/3rdparty/libarchive/libarchive/archive_read_support_format_all.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*-
- * Copyright (c) 2003-2011 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: head/lib/libarchive/archive_read_support_format_all.c 174991 2007-12-30 04:58:22Z kientzle $");
-
-#include "archive.h"
-#include "archive_private.h"
-
-int
-archive_read_support_format_all(struct archive *a)
-{
- archive_check_magic(a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_NEW, "archive_read_support_format_all");
-
- /* TODO: It would be nice to compute the ordering
- * here automatically so that people who enable just
- * a few formats can still get the benefits. That
- * may just require the format registration to include
- * a "maximum read-ahead" value (anything that uses seek
- * would be essentially infinite read-ahead). The core
- * bid management can then sort the bidders before calling
- * them.
- *
- * If you implement the above, please return the list below
- * to alphabetic order.
- */
-
- /*
- * These bidders are all pretty cheap; they just examine a
- * small initial part of the archive. If one of these bids
- * high, we can maybe avoid running any of the more expensive
- * bidders below.
- */
- archive_read_support_format_ar(a);
- archive_read_support_format_cpio(a);
- archive_read_support_format_empty(a);
- archive_read_support_format_lha(a);
- archive_read_support_format_mtree(a);
- archive_read_support_format_tar(a);
- archive_read_support_format_xar(a);
-
- /*
- * Install expensive bidders last. By doing them last, we
- * increase the chance that a high bid from someone else will
- * make it unnecessary for these to do anything at all.
- */
- /* These three have potentially large look-ahead. */
- archive_read_support_format_7zip(a);
- archive_read_support_format_cab(a);
- archive_read_support_format_rar(a);
- archive_read_support_format_iso9660(a);
- /* Seek is really bad, since it forces the read-ahead
- * logic to discard buffered data. */
- archive_read_support_format_zip(a);
-
- /* Note: We always return ARCHIVE_OK here, even if some of the
- * above return ARCHIVE_WARN. The intent here is to enable
- * "as much as possible." Clients who need specific
- * compression should enable those individually so they can
- * verify the level of support. */
- /* Clear any warning messages set by the above functions. */
- archive_clear_error(a);
- return (ARCHIVE_OK);
-}
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_format_ar.c b/3rdparty/libarchive/libarchive/archive_read_support_format_ar.c
deleted file mode 100644
index 40be18c0..00000000
--- a/3rdparty/libarchive/libarchive/archive_read_support_format_ar.c
+++ /dev/null
@@ -1,626 +0,0 @@
-/*-
- * Copyright (c) 2007 Kai Wang
- * Copyright (c) 2007 Tim Kientzle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer
- * in this position and unchanged.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "archive_platform.h"
-__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_ar.c 201101 2009-12-28 03:06:27Z kientzle $");
-
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#endif
-
-#include "archive.h"
-#include "archive_entry.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-
-struct ar {
- int64_t entry_bytes_remaining;
- /* unconsumed is purely to track data we've gotten from readahead,
- * but haven't yet marked as consumed. Must be paired with
- * entry_bytes_remaining usage/modification.
- */
- size_t entry_bytes_unconsumed;
- int64_t entry_offset;
- int64_t entry_padding;
- char *strtab;
- size_t strtab_size;
- char read_global_header;
-};
-
-/*
- * Define structure of the "ar" header.
- */
-#define AR_name_offset 0
-#define AR_name_size 16
-#define AR_date_offset 16
-#define AR_date_size 12
-#define AR_uid_offset 28
-#define AR_uid_size 6
-#define AR_gid_offset 34
-#define AR_gid_size 6
-#define AR_mode_offset 40
-#define AR_mode_size 8
-#define AR_size_offset 48
-#define AR_size_size 10
-#define AR_fmag_offset 58
-#define AR_fmag_size 2
-
-static int archive_read_format_ar_bid(struct archive_read *a, int);
-static int archive_read_format_ar_cleanup(struct archive_read *a);
-static int archive_read_format_ar_read_data(struct archive_read *a,
- const void **buff, size_t *size, int64_t *offset);
-static int archive_read_format_ar_skip(struct archive_read *a);
-static int archive_read_format_ar_read_header(struct archive_read *a,
- struct archive_entry *e);
-static uint64_t ar_atol8(const char *p, unsigned char_cnt);
-static uint64_t ar_atol10(const char *p, unsigned char_cnt);
-static int ar_parse_gnu_filename_table(struct archive_read *a);
-static int ar_parse_common_header(struct ar *ar, struct archive_entry *,
- const char *h);
-
-int
-archive_read_support_format_ar(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct ar *ar;
- int r;
-
- archive_check_magic(_a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_NEW, "archive_read_support_format_ar");
-
- ar = (struct ar *)malloc(sizeof(*ar));
- if (ar == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate ar data");
- return (ARCHIVE_FATAL);
- }
- memset(ar, 0, sizeof(*ar));
- ar->strtab = NULL;
-
- r = __archive_read_register_format(a,
- ar,
- "ar",
- archive_read_format_ar_bid,
- NULL,
- archive_read_format_ar_read_header,
- archive_read_format_ar_read_data,
- archive_read_format_ar_skip,
- NULL,
- archive_read_format_ar_cleanup);
-
- if (r != ARCHIVE_OK) {
- free(ar);
- return (r);
- }
- return (ARCHIVE_OK);
-}
-
-static int
-archive_read_format_ar_cleanup(struct archive_read *a)
-{
- struct ar *ar;
-
- ar = (struct ar *)(a->format->data);
- if (ar->strtab)
- free(ar->strtab);
- free(ar);
- (a->format->data) = NULL;
- return (ARCHIVE_OK);
-}
-
-static int
-archive_read_format_ar_bid(struct archive_read *a, int best_bid)
-{
- const void *h;
-
- (void)best_bid; /* UNUSED */
-
- /*
- * Verify the 8-byte file signature.
- * TODO: Do we need to check more than this?
- */
- if ((h = __archive_read_ahead(a, 8, NULL)) == NULL)
- return (-1);
- if (memcmp(h, "!<arch>\n", 8) == 0) {
- return (64);
- }
- return (-1);
-}
-
-static int
-_ar_read_header(struct archive_read *a, struct archive_entry *entry,
- struct ar *ar, const char *h, size_t *unconsumed)
-{
- char filename[AR_name_size + 1];
- uint64_t number; /* Used to hold parsed numbers before validation. */
- size_t bsd_name_length, entry_size;
- char *p, *st;
- const void *b;
- int r;
-
- /* Verify the magic signature on the file header. */
- if (strncmp(h + AR_fmag_offset, "`\n", 2) != 0) {
- archive_set_error(&a->archive, EINVAL,
- "Incorrect file header signature");
- return (ARCHIVE_WARN);
- }
-
- /* Copy filename into work buffer. */
- strncpy(filename, h + AR_name_offset, AR_name_size);
- filename[AR_name_size] = '\0';
-
- /*
- * Guess the format variant based on the filename.
- */
- if (a->archive.archive_format == ARCHIVE_FORMAT_AR) {
- /* We don't already know the variant, so let's guess. */
- /*
- * Biggest clue is presence of '/': GNU starts special
- * filenames with '/', appends '/' as terminator to
- * non-special names, so anything with '/' should be
- * GNU except for BSD long filenames.
- */
- if (strncmp(filename, "#1/", 3) == 0)
- a->archive.archive_format = ARCHIVE_FORMAT_AR_BSD;
- else if (strchr(filename, '/') != NULL)
- a->archive.archive_format = ARCHIVE_FORMAT_AR_GNU;
- else if (strncmp(filename, "__.SYMDEF", 9) == 0)
- a->archive.archive_format = ARCHIVE_FORMAT_AR_BSD;
- /*
- * XXX Do GNU/SVR4 'ar' programs ever omit trailing '/'
- * if name exactly fills 16-byte field? If so, we
- * can't assume entries without '/' are BSD. XXX
- */
- }
-
- /* Update format name from the code. */
- if (a->archive.archive_format == ARCHIVE_FORMAT_AR_GNU)
- a->archive.archive_format_name = "ar (GNU/SVR4)";
- else if (a->archive.archive_format == ARCHIVE_FORMAT_AR_BSD)
- a->archive.archive_format_name = "ar (BSD)";
- else
- a->archive.archive_format_name = "ar";
-
- /*
- * Remove trailing spaces from the filename. GNU and BSD
- * variants both pad filename area out with spaces.
- * This will only be wrong if GNU/SVR4 'ar' implementations
- * omit trailing '/' for 16-char filenames and we have
- * a 16-char filename that ends in ' '.
- */
- p = filename + AR_name_size - 1;
- while (p >= filename && *p == ' ') {
- *p = '\0';
- p--;
- }
-
- /*
- * Remove trailing slash unless first character is '/'.
- * (BSD entries never end in '/', so this will only trim
- * GNU-format entries. GNU special entries start with '/'
- * and are not terminated in '/', so we don't trim anything
- * that starts with '/'.)
- */
- if (filename[0] != '/' && *p == '/')
- *p = '\0';
-
- /*
- * '//' is the GNU filename table.
- * Later entries can refer to names in this table.
- */
- if (strcmp(filename, "//") == 0) {
- /* This must come before any call to _read_ahead. */
- ar_parse_common_header(ar, entry, h);
- archive_entry_copy_pathname(entry, filename);
- archive_entry_set_filetype(entry, AE_IFREG);
- /* Get the size of the filename table. */
- number = ar_atol10(h + AR_size_offset, AR_size_size);
- if (number > SIZE_MAX) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Filename table too large");
- return (ARCHIVE_FATAL);
- }
- entry_size = (size_t)number;
- if (entry_size == 0) {
- archive_set_error(&a->archive, EINVAL,
- "Invalid string table");
- return (ARCHIVE_WARN);
- }
- if (ar->strtab != NULL) {
- archive_set_error(&a->archive, EINVAL,
- "More than one string tables exist");
- return (ARCHIVE_WARN);
- }
-
- /* Read the filename table into memory. */
- st = malloc(entry_size);
- if (st == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate filename table buffer");
- return (ARCHIVE_FATAL);
- }
- ar->strtab = st;
- ar->strtab_size = entry_size;
-
- if (*unconsumed) {
- __archive_read_consume(a, *unconsumed);
- *unconsumed = 0;
- }
-
- if ((b = __archive_read_ahead(a, entry_size, NULL)) == NULL)
- return (ARCHIVE_FATAL);
- memcpy(st, b, entry_size);
- __archive_read_consume(a, entry_size);
- /* All contents are consumed. */
- ar->entry_bytes_remaining = 0;
- archive_entry_set_size(entry, ar->entry_bytes_remaining);
-
- /* Parse the filename table. */
- return (ar_parse_gnu_filename_table(a));
- }
-
- /*
- * GNU variant handles long filenames by storing /<number>
- * to indicate a name stored in the filename table.
- * XXX TODO: Verify that it's all digits... Don't be fooled
- * by "/9xyz" XXX
- */
- if (filename[0] == '/' && filename[1] >= '0' && filename[1] <= '9') {
- number = ar_atol10(h + AR_name_offset + 1, AR_name_size - 1);
- /*
- * If we can't look up the real name, warn and return
- * the entry with the wrong name.
- */
- if (ar->strtab == NULL || number > ar->strtab_size) {
- archive_set_error(&a->archive, EINVAL,
- "Can't find long filename for entry");
- archive_entry_copy_pathname(entry, filename);
- /* Parse the time, owner, mode, size fields. */
- ar_parse_common_header(ar, entry, h);
- return (ARCHIVE_WARN);
- }
-
- archive_entry_copy_pathname(entry, &ar->strtab[(size_t)number]);
- /* Parse the time, owner, mode, size fields. */
- return (ar_parse_common_header(ar, entry, h));
- }
-
- /*
- * BSD handles long filenames by storing "#1/" followed by the
- * length of filename as a decimal number, then prepends the
- * the filename to the file contents.
- */
- if (strncmp(filename, "#1/", 3) == 0) {
- /* Parse the time, owner, mode, size fields. */
- /* This must occur before _read_ahead is called again. */
- ar_parse_common_header(ar, entry, h);
-
- /* Parse the size of the name, adjust the file size. */
- number = ar_atol10(h + AR_name_offset + 3, AR_name_size - 3);
- bsd_name_length = (size_t)number;
- /* Guard against the filename + trailing NUL
- * overflowing a size_t and against the filename size
- * being larger than the entire entry. */
- if (number > (uint64_t)(bsd_name_length + 1)
- || (int64_t)bsd_name_length > ar->entry_bytes_remaining) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Bad input file size");
- return (ARCHIVE_FATAL);
- }
- ar->entry_bytes_remaining -= bsd_name_length;
- /* Adjust file size reported to client. */
- archive_entry_set_size(entry, ar->entry_bytes_remaining);
-
- if (*unconsumed) {
- __archive_read_consume(a, *unconsumed);
- *unconsumed = 0;
- }
-
- /* Read the long name into memory. */
- if ((b = __archive_read_ahead(a, bsd_name_length, NULL)) == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Truncated input file");
- return (ARCHIVE_FATAL);
- }
- /* Store it in the entry. */
- p = (char *)malloc(bsd_name_length + 1);
- if (p == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate fname buffer");
- return (ARCHIVE_FATAL);
- }
- strncpy(p, b, bsd_name_length);
- p[bsd_name_length] = '\0';
-
- __archive_read_consume(a, bsd_name_length);
-
- archive_entry_copy_pathname(entry, p);
- free(p);
- return (ARCHIVE_OK);
- }
-
- /*
- * "/" is the SVR4/GNU archive symbol table.
- */
- if (strcmp(filename, "/") == 0) {
- archive_entry_copy_pathname(entry, "/");
- /* Parse the time, owner, mode, size fields. */
- r = ar_parse_common_header(ar, entry, h);
- /* Force the file type to a regular file. */
- archive_entry_set_filetype(entry, AE_IFREG);
- return (r);
- }
-
- /*
- * "__.SYMDEF" is a BSD archive symbol table.
- */
- if (strcmp(filename, "__.SYMDEF") == 0) {
- archive_entry_copy_pathname(entry, filename);
- /* Parse the time, owner, mode, size fields. */
- return (ar_parse_common_header(ar, entry, h));
- }
-
- /*
- * Otherwise, this is a standard entry. The filename
- * has already been trimmed as much as possible, based
- * on our current knowledge of the format.
- */
- archive_entry_copy_pathname(entry, filename);
- return (ar_parse_common_header(ar, entry, h));
-}
-
-static int
-archive_read_format_ar_read_header(struct archive_read *a,
- struct archive_entry *entry)
-{
- struct ar *ar = (struct ar*)(a->format->data);
- size_t unconsumed;
- const void *header_data;
- int ret;
-
- if (!ar->read_global_header) {
- /*
- * We are now at the beginning of the archive,
- * so we need first consume the ar global header.
- */
- __archive_read_consume(a, 8);
- ar->read_global_header = 1;
- /* Set a default format code for now. */
- a->archive.archive_format = ARCHIVE_FORMAT_AR;
- }
-
- /* Read the header for the next file entry. */
- if ((header_data = __archive_read_ahead(a, 60, NULL)) == NULL)
- /* Broken header. */
- return (ARCHIVE_EOF);
-
- unconsumed = 60;
-
- ret = _ar_read_header(a, entry, ar, (const char *)header_data, &unconsumed);
-
- if (unconsumed)
- __archive_read_consume(a, unconsumed);
-
- return ret;
-}
-
-
-static int
-ar_parse_common_header(struct ar *ar, struct archive_entry *entry,
- const char *h)
-{
- uint64_t n;
-
- /* Copy remaining header */
- archive_entry_set_mtime(entry,
- (time_t)ar_atol10(h + AR_date_offset, AR_date_size), 0L);
- archive_entry_set_uid(entry,
- (uid_t)ar_atol10(h + AR_uid_offset, AR_uid_size));
- archive_entry_set_gid(entry,
- (gid_t)ar_atol10(h + AR_gid_offset, AR_gid_size));
- archive_entry_set_mode(entry,
- (mode_t)ar_atol8(h + AR_mode_offset, AR_mode_size));
- n = ar_atol10(h + AR_size_offset, AR_size_size);
-
- ar->entry_offset = 0;
- ar->entry_padding = n % 2;
- archive_entry_set_size(entry, n);
- ar->entry_bytes_remaining = n;
- return (ARCHIVE_OK);
-}
-
-static int
-archive_read_format_ar_read_data(struct archive_read *a,
- const void **buff, size_t *size, int64_t *offset)
-{
- ssize_t bytes_read;
- struct ar *ar;
-
- ar = (struct ar *)(a->format->data);
-
- if (ar->entry_bytes_unconsumed) {
- __archive_read_consume(a, ar->entry_bytes_unconsumed);
- ar->entry_bytes_unconsumed = 0;
- }
-
- if (ar->entry_bytes_remaining > 0) {
- *buff = __archive_read_ahead(a, 1, &bytes_read);
- if (bytes_read == 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Truncated ar archive");
- return (ARCHIVE_FATAL);
- }
- if (bytes_read < 0)
- return (ARCHIVE_FATAL);
- if (bytes_read > ar->entry_bytes_remaining)
- bytes_read = (ssize_t)ar->entry_bytes_remaining;
- *size = bytes_read;
- ar->entry_bytes_unconsumed = bytes_read;
- *offset = ar->entry_offset;
- ar->entry_offset += bytes_read;
- ar->entry_bytes_remaining -= bytes_read;
- return (ARCHIVE_OK);
- } else {
- int64_t skipped = __archive_read_consume(a, ar->entry_padding);
- if (skipped >= 0) {
- ar->entry_padding -= skipped;
- }
- if (ar->entry_padding) {
- if (skipped >= 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Truncated ar archive- failed consuming padding");
- }
- return (ARCHIVE_FATAL);
- }
- *buff = NULL;
- *size = 0;
- *offset = ar->entry_offset;
- return (ARCHIVE_EOF);
- }
-}
-
-static int
-archive_read_format_ar_skip(struct archive_read *a)
-{
- int64_t bytes_skipped;
- struct ar* ar;
-
- ar = (struct ar *)(a->format->data);
-
- bytes_skipped = __archive_read_consume(a,
- ar->entry_bytes_remaining + ar->entry_padding
- + ar->entry_bytes_unconsumed);
- if (bytes_skipped < 0)
- return (ARCHIVE_FATAL);
-
- ar->entry_bytes_remaining = 0;
- ar->entry_bytes_unconsumed = 0;
- ar->entry_padding = 0;
-
- return (ARCHIVE_OK);
-}
-
-static int
-ar_parse_gnu_filename_table(struct archive_read *a)
-{
- struct ar *ar;
- char *p;
- size_t size;
-
- ar = (struct ar*)(a->format->data);
- size = ar->strtab_size;
-
- for (p = ar->strtab; p < ar->strtab + size - 1; ++p) {
- if (*p == '/') {
- *p++ = '\0';
- if (*p != '\n')
- goto bad_string_table;
- *p = '\0';
- }
- }
- /*
- * GNU ar always pads the table to an even size.
- * The pad character is either '\n' or '`'.
- */
- if (p != ar->strtab + size && *p != '\n' && *p != '`')
- goto bad_string_table;
-
- /* Enforce zero termination. */
- ar->strtab[size - 1] = '\0';
-
- return (ARCHIVE_OK);
-
-bad_string_table:
- archive_set_error(&a->archive, EINVAL,
- "Invalid string table");
- free(ar->strtab);
- ar->strtab = NULL;
- return (ARCHIVE_WARN);
-}
-
-static uint64_t
-ar_atol8(const char *p, unsigned char_cnt)
-{
- uint64_t l, limit, last_digit_limit;
- unsigned int digit, base;
-
- base = 8;
- limit = UINT64_MAX / base;
- last_digit_limit = UINT64_MAX % base;
-
- while ((*p == ' ' || *p == '\t') && char_cnt-- > 0)
- p++;
-
- l = 0;
- digit = *p - '0';
- while (*p >= '0' && digit < base && char_cnt-- > 0) {
- if (l>limit || (l == limit && digit > last_digit_limit)) {
- l = UINT64_MAX; /* Truncate on overflow. */
- break;
- }
- l = (l * base) + digit;
- digit = *++p - '0';
- }
- return (l);
-}
-
-static uint64_t
-ar_atol10(const char *p, unsigned char_cnt)
-{
- uint64_t l, limit, last_digit_limit;
- unsigned int base, digit;
-
- base = 10;
- limit = UINT64_MAX / base;
- last_digit_limit = UINT64_MAX % base;
-
- while ((*p == ' ' || *p == '\t') && char_cnt-- > 0)
- p++;
- l = 0;
- digit = *p - '0';
- while (*p >= '0' && digit < base && char_cnt-- > 0) {
- if (l > limit || (l == limit && digit > last_digit_limit)) {
- l = UINT64_MAX; /* Truncate on overflow. */
- break;
- }
- l = (l * base) + digit;
- digit = *++p - '0';
- }
- return (l);
-}
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_format_cab.c b/3rdparty/libarchive/libarchive/archive_read_support_format_cab.c
deleted file mode 100644
index 3c9f94ca..00000000
--- a/3rdparty/libarchive/libarchive/archive_read_support_format_cab.c
+++ /dev/null
@@ -1,3348 +0,0 @@
-/*-
- * Copyright (c) 2010-2012 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"
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_ZLIB_H
-#include <zlib.h>
-#endif
-
-#include "archive.h"
-#include "archive_entry.h"
-#include "archive_entry_locale.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-#include "archive_endian.h"
-
-
-struct lzx_dec {
- /* Decoding status. */
- int state;
-
- /*
- * Window to see last decoded data, from 32KBi to 2MBi.
- */
- int w_size;
- int w_mask;
- /* Window buffer, which is a loop buffer. */
- unsigned char *w_buff;
- /* The insert position to the window. */
- int w_pos;
- /* The position where we can copy decoded code from the window. */
- int copy_pos;
- /* The length how many bytes we can copy decoded code from
- * the window. */
- int copy_len;
- /* Translation reversal for x86 proccessor CALL byte sequence(E8).
- * This is used for LZX only. */
- uint32_t translation_size;
- char translation;
- char block_type;
-#define VERBATIM_BLOCK 1
-#define ALIGNED_OFFSET_BLOCK 2
-#define UNCOMPRESSED_BLOCK 3
- size_t block_size;
- size_t block_bytes_avail;
- /* Repeated offset. */
- int r0, r1, r2;
- unsigned char rbytes[4];
- int rbytes_avail;
- int length_header;
- int position_slot;
- int offset_bits;
-
- struct lzx_pos_tbl {
- int base;
- int footer_bits;
- } *pos_tbl;
- /*
- * Bit stream reader.
- */
- struct lzx_br {
-#define CACHE_TYPE uint64_t
-#define CACHE_BITS (8 * sizeof(CACHE_TYPE))
- /* Cache buffer. */
- CACHE_TYPE cache_buffer;
- /* Indicates how many bits avail in cache_buffer. */
- int cache_avail;
- unsigned char odd;
- char have_odd;
- } br;
-
- /*
- * Huffman coding.
- */
- struct huffman {
- int len_size;
- int freq[17];
- unsigned char *bitlen;
-
- /*
- * Use a index table. It's faster than searching a huffman
- * coding tree, which is a binary tree. But a use of a large
- * index table causes L1 cache read miss many times.
- */
-#define HTBL_BITS 10
- int max_bits;
- int shift_bits;
- int tbl_bits;
- int tree_used;
- int tree_avail;
- /* Direct access table. */
- uint16_t *tbl;
- /* Binary tree table for extra bits over the direct access. */
- struct htree_t {
- uint16_t left;
- uint16_t right;
- } *tree;
- } at, lt, mt, pt;
-
- int loop;
- int error;
-};
-
-static const int slots[] = {
- 30, 32, 34, 36, 38, 42, 50, 66, 98, 162, 290
-};
-#define SLOT_BASE 15
-#define SLOT_MAX 21/*->25*/
-
-struct lzx_stream {
- const unsigned char *next_in;
- int64_t avail_in;
- int64_t total_in;
- unsigned char *next_out;
- int64_t avail_out;
- int64_t total_out;
- struct lzx_dec *ds;
-};
-
-/*
- * Cabinet file definitions.
- */
-/* CFHEADER offset */
-#define CFHEADER_signature 0
-#define CFHEADER_cbCabinet 8
-#define CFHEADER_coffFiles 16
-#define CFHEADER_versionMinor 24
-#define CFHEADER_versionMajor 25
-#define CFHEADER_cFolders 26
-#define CFHEADER_cFiles 28
-#define CFHEADER_flags 30
-#define CFHEADER_setID 32
-#define CFHEADER_iCabinet 34
-#define CFHEADER_cbCFHeader 36
-#define CFHEADER_cbCFFolder 38
-#define CFHEADER_cbCFData 39
-
-/* CFFOLDER offset */
-#define CFFOLDER_coffCabStart 0
-#define CFFOLDER_cCFData 4
-#define CFFOLDER_typeCompress 6
-#define CFFOLDER_abReserve 8
-
-/* CFFILE offset */
-#define CFFILE_cbFile 0
-#define CFFILE_uoffFolderStart 4
-#define CFFILE_iFolder 8
-#define CFFILE_date_time 10
-#define CFFILE_attribs 14
-
-/* CFDATA offset */
-#define CFDATA_csum 0
-#define CFDATA_cbData 4
-#define CFDATA_cbUncomp 6
-
-static const char *compression_name[] = {
- "NONE",
- "MSZIP",
- "Quantum",
- "LZX",
-};
-
-struct cfdata {
- /* Sum value of this CFDATA. */
- uint32_t sum;
- uint16_t compressed_size;
- uint16_t compressed_bytes_remaining;
- uint16_t uncompressed_size;
- uint16_t uncompressed_bytes_remaining;
- /* To know how many bytes we have decompressed. */
- uint16_t uncompressed_avail;
- /* Offset from the beginning of compressed data of this CFDATA */
- uint16_t read_offset;
- int64_t unconsumed;
- /* To keep memory image of this CFDATA to compute the sum. */
- size_t memimage_size;
- unsigned char *memimage;
- /* Result of calculation of sum. */
- uint32_t sum_calculated;
- unsigned char sum_extra[4];
- int sum_extra_avail;
- const void *sum_ptr;
-};
-
-struct cffolder {
- uint32_t cfdata_offset_in_cab;
- uint16_t cfdata_count;
- uint16_t comptype;
-#define COMPTYPE_NONE 0x0000
-#define COMPTYPE_MSZIP 0x0001
-#define COMPTYPE_QUANTUM 0x0002
-#define COMPTYPE_LZX 0x0003
- uint16_t compdata;
- const char *compname;
- /* At the time reading CFDATA */
- struct cfdata cfdata;
- int cfdata_index;
- /* Flags to mark progress of decompression. */
- char decompress_init;
-};
-
-struct cffile {
- uint32_t uncompressed_size;
- uint32_t offset;
- time_t mtime;
- uint16_t folder;
-#define iFoldCONTINUED_FROM_PREV 0xFFFD
-#define iFoldCONTINUED_TO_NEXT 0xFFFE
-#define iFoldCONTINUED_PREV_AND_NEXT 0xFFFF
- unsigned char attr;
-#define ATTR_RDONLY 0x01
-#define ATTR_NAME_IS_UTF 0x80
- struct archive_string pathname;
-};
-
-struct cfheader {
- /* Total bytes of all file size in a Cabinet. */
- uint32_t total_bytes;
- uint32_t files_offset;
- uint16_t folder_count;
- uint16_t file_count;
- uint16_t flags;
-#define PREV_CABINET 0x0001
-#define NEXT_CABINET 0x0002
-#define RESERVE_PRESENT 0x0004
- uint16_t setid;
- uint16_t cabinet;
- /* Version number. */
- unsigned char major;
- unsigned char minor;
- unsigned char cffolder;
- unsigned char cfdata;
- /* All folders in a cabinet. */
- struct cffolder *folder_array;
- /* All files in a cabinet. */
- struct cffile *file_array;
- int file_index;
-};
-
-struct cab {
- /* entry_bytes_remaining is the number of bytes we expect. */
- int64_t entry_offset;
- int64_t entry_bytes_remaining;
- int64_t entry_unconsumed;
- int64_t entry_compressed_bytes_read;
- int64_t entry_uncompressed_bytes_read;
- struct cffolder *entry_cffolder;
- struct cffile *entry_cffile;
- struct cfdata *entry_cfdata;
-
- /* Offset from beginning of a cabinet file. */
- int64_t cab_offset;
- struct cfheader cfheader;
- struct archive_wstring ws;
-
- /* Flag to mark progress that an archive was read their first header.*/
- char found_header;
- char end_of_archive;
- char end_of_entry;
- char end_of_entry_cleanup;
- char read_data_invoked;
- int64_t bytes_skipped;
-
- unsigned char *uncompressed_buffer;
- size_t uncompressed_buffer_size;
-
- int init_default_conversion;
- struct archive_string_conv *sconv;
- struct archive_string_conv *sconv_default;
- struct archive_string_conv *sconv_utf8;
- char format_name[64];
-
-#ifdef HAVE_ZLIB_H
- z_stream stream;
- char stream_valid;
-#endif
- struct lzx_stream xstrm;
-};
-
-static int archive_read_format_cab_bid(struct archive_read *, int);
-static int archive_read_format_cab_options(struct archive_read *,
- const char *, const char *);
-static int archive_read_format_cab_read_header(struct archive_read *,
- struct archive_entry *);
-static int archive_read_format_cab_read_data(struct archive_read *,
- const void **, size_t *, int64_t *);
-static int archive_read_format_cab_read_data_skip(struct archive_read *);
-static int archive_read_format_cab_cleanup(struct archive_read *);
-
-static int cab_skip_sfx(struct archive_read *);
-static time_t cab_dos_time(const unsigned char *);
-static int cab_read_data(struct archive_read *, const void **,
- size_t *, int64_t *);
-static int cab_read_header(struct archive_read *);
-static uint32_t cab_checksum_cfdata_4(const void *, size_t bytes, uint32_t);
-static uint32_t cab_checksum_cfdata(const void *, size_t bytes, uint32_t);
-static void cab_checksum_update(struct archive_read *, size_t);
-static int cab_checksum_finish(struct archive_read *);
-static int cab_next_cfdata(struct archive_read *);
-static const void *cab_read_ahead_cfdata(struct archive_read *, ssize_t *);
-static const void *cab_read_ahead_cfdata_none(struct archive_read *, ssize_t *);
-static const void *cab_read_ahead_cfdata_deflate(struct archive_read *,
- ssize_t *);
-static const void *cab_read_ahead_cfdata_lzx(struct archive_read *,
- ssize_t *);
-static int64_t cab_consume_cfdata(struct archive_read *, int64_t);
-static int64_t cab_minimum_consume_cfdata(struct archive_read *, int64_t);
-static int lzx_decode_init(struct lzx_stream *, int);
-static int lzx_read_blocks(struct lzx_stream *, int);
-static int lzx_decode_blocks(struct lzx_stream *, int);
-static void lzx_decode_free(struct lzx_stream *);
-static void lzx_translation(struct lzx_stream *, void *, size_t, uint32_t);
-static void lzx_cleanup_bitstream(struct lzx_stream *);
-static int lzx_decode(struct lzx_stream *, int);
-static int lzx_read_pre_tree(struct lzx_stream *);
-static int lzx_read_bitlen(struct lzx_stream *, struct huffman *, int);
-static int lzx_huffman_init(struct huffman *, size_t, int);
-static void lzx_huffman_free(struct huffman *);
-static int lzx_make_huffman_table(struct huffman *);
-static inline int lzx_decode_huffman(struct huffman *, unsigned);
-static int lzx_decode_huffman_tree(struct huffman *, unsigned, int);
-
-
-int
-archive_read_support_format_cab(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct cab *cab;
- int r;
-
- archive_check_magic(_a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_NEW, "archive_read_support_format_cab");
-
- cab = (struct cab *)calloc(1, sizeof(*cab));
- if (cab == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate CAB data");
- return (ARCHIVE_FATAL);
- }
- archive_string_init(&cab->ws);
- archive_wstring_ensure(&cab->ws, 256);
-
- r = __archive_read_register_format(a,
- cab,
- "cab",
- archive_read_format_cab_bid,
- archive_read_format_cab_options,
- archive_read_format_cab_read_header,
- archive_read_format_cab_read_data,
- archive_read_format_cab_read_data_skip,
- NULL,
- archive_read_format_cab_cleanup);
-
- if (r != ARCHIVE_OK)
- free(cab);
- return (ARCHIVE_OK);
-}
-
-static int
-find_cab_magic(const char *p)
-{
- switch (p[4]) {
- case 0:
- /*
- * Note: Self-Extraction program has 'MSCF' string in their
- * program. If we were finding 'MSCF' string only, we got
- * wrong place for Cabinet header, thus, we have to check
- * following four bytes which are reserved and must be set
- * to zero.
- */
- if (memcmp(p, "MSCF\0\0\0\0", 8) == 0)
- return 0;
- return 5;
- case 'F': return 1;
- case 'C': return 2;
- case 'S': return 3;
- case 'M': return 4;
- default: return 5;
- }
-}
-
-static int
-archive_read_format_cab_bid(struct archive_read *a, int best_bid)
-{
- const char *p;
- ssize_t bytes_avail, offset, window;
-
- /* If there's already a better bid than we can ever
- make, don't bother testing. */
- if (best_bid > 64)
- return (-1);
-
- if ((p = __archive_read_ahead(a, 8, NULL)) == NULL)
- return (-1);
-
- if (memcmp(p, "MSCF\0\0\0\0", 8) == 0)
- return (64);
-
- /*
- * Attempt to handle self-extracting archives
- * by noting a PE header and searching forward
- * up to 128k for a 'MSCF' marker.
- */
- if (p[0] == 'M' && p[1] == 'Z') {
- offset = 0;
- window = 4096;
- while (offset < (1024 * 128)) {
- const char *h = __archive_read_ahead(a, offset + window,
- &bytes_avail);
- if (h == NULL) {
- /* Remaining bytes are less than window. */
- window >>= 1;
- if (window < 128)
- return (0);
- continue;
- }
- p = h + offset;
- while (p + 8 < h + bytes_avail) {
- int next;
- if ((next = find_cab_magic(p)) == 0)
- return (64);
- p += next;
- }
- offset = p - h;
- }
- }
- return (0);
-}
-
-static int
-archive_read_format_cab_options(struct archive_read *a,
- const char *key, const char *val)
-{
- struct cab *cab;
- int ret = ARCHIVE_FAILED;
-
- cab = (struct cab *)(a->format->data);
- if (strcmp(key, "hdrcharset") == 0) {
- if (val == NULL || val[0] == 0)
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "cab: hdrcharset option needs a character-set name");
- else {
- cab->sconv = archive_string_conversion_from_charset(
- &a->archive, val, 0);
- if (cab->sconv != NULL)
- ret = ARCHIVE_OK;
- else
- ret = ARCHIVE_FATAL;
- }
- return (ret);
- }
-
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
-}
-
-static int
-cab_skip_sfx(struct archive_read *a)
-{
- const char *p, *q;
- size_t skip;
- ssize_t bytes, window;
-
- window = 4096;
- for (;;) {
- const char *h = __archive_read_ahead(a, window, &bytes);
- if (h == NULL) {
- /* Remaining size are less than window. */
- window >>= 1;
- if (window < 128) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Couldn't find out CAB header");
- return (ARCHIVE_FATAL);
- }
- continue;
- }
- p = h;
- q = p + bytes;
-
- /*
- * Scan ahead until we find something that looks
- * like the cab header.
- */
- while (p + 8 < q) {
- int next;
- if ((next = find_cab_magic(p)) == 0) {
- skip = p - h;
- __archive_read_consume(a, skip);
- return (ARCHIVE_OK);
- }
- p += next;
- }
- skip = p - h;
- __archive_read_consume(a, skip);
- }
-}
-
-static int
-truncated_error(struct archive_read *a)
-{
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated CAB header");
- return (ARCHIVE_FATAL);
-}
-
-static ssize_t
-cab_strnlen(const unsigned char *p, size_t maxlen)
-{
- size_t i;
-
- for (i = 0; i <= maxlen; i++) {
- if (p[i] == 0)
- break;
- }
- if (i > maxlen)
- return (-1);/* invalid */
- return ((ssize_t)i);
-}
-
-/* Read bytes as much as remaining. */
-static const void *
-cab_read_ahead_remaining(struct archive_read *a, size_t min, ssize_t *avail)
-{
- const void *p;
-
- while (min > 0) {
- p = __archive_read_ahead(a, min, avail);
- if (p != NULL)
- return (p);
- min--;
- }
- return (NULL);
-}
-
-/* Convert a path separator '\' -> '/' */
-static int
-cab_convert_path_separator_1(struct archive_string *fn, unsigned char attr)
-{
- size_t i;
- int mb;
-
- /* Easy check if we have '\' in multi-byte string. */
- mb = 0;
- for (i = 0; i < archive_strlen(fn); i++) {
- if (fn->s[i] == '\\') {
- if (mb) {
- /* This may be second byte of multi-byte
- * character. */
- break;
- }
- fn->s[i] = '/';
- mb = 0;
- } else if ((fn->s[i] & 0x80) && !(attr & ATTR_NAME_IS_UTF))
- mb = 1;
- else
- mb = 0;
- }
- if (i == archive_strlen(fn))
- return (0);
- return (-1);
-}
-
-/*
- * Replace a character '\' with '/' in wide character.
- */
-static void
-cab_convert_path_separator_2(struct cab *cab, struct archive_entry *entry)
-{
- const wchar_t *wp;
- size_t i;
-
- /* If a conversion to wide character failed, force the replacement. */
- if ((wp = archive_entry_pathname_w(entry)) != NULL) {
- archive_wstrcpy(&(cab->ws), wp);
- for (i = 0; i < archive_strlen(&(cab->ws)); i++) {
- if (cab->ws.s[i] == L'\\')
- cab->ws.s[i] = L'/';
- }
- archive_entry_copy_pathname_w(entry, cab->ws.s);
- }
-}
-
-/*
- * Read CFHEADER, CFFOLDER and CFFILE.
- */
-static int
-cab_read_header(struct archive_read *a)
-{
- const unsigned char *p;
- struct cab *cab;
- struct cfheader *hd;
- size_t bytes, used;
- ssize_t len;
- int64_t skip;
- int err, i;
- int cur_folder, prev_folder;
- uint32_t offset32;
-
- a->archive.archive_format = ARCHIVE_FORMAT_CAB;
- if (a->archive.archive_format_name == NULL)
- a->archive.archive_format_name = "CAB";
-
- if ((p = __archive_read_ahead(a, 42, NULL)) == NULL)
- return (truncated_error(a));
-
- cab = (struct cab *)(a->format->data);
- if (cab->found_header == 0 &&
- p[0] == 'M' && p[1] == 'Z') {
- /* This is an executable? Must be self-extracting... */
- err = cab_skip_sfx(a);
- if (err < ARCHIVE_WARN)
- return (err);
-
- if ((p = __archive_read_ahead(a, sizeof(*p), NULL)) == NULL)
- return (truncated_error(a));
- }
-
- cab->cab_offset = 0;
- /*
- * Read CFHEADER.
- */
- hd = &cab->cfheader;
- if (p[CFHEADER_signature+0] != 'M' || p[CFHEADER_signature+1] != 'S' ||
- p[CFHEADER_signature+2] != 'C' || p[CFHEADER_signature+3] != 'F') {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Couldn't find out CAB header");
- return (ARCHIVE_FATAL);
- }
- hd->total_bytes = archive_le32dec(p + CFHEADER_cbCabinet);
- hd->files_offset = archive_le32dec(p + CFHEADER_coffFiles);
- hd->minor = p[CFHEADER_versionMinor];
- hd->major = p[CFHEADER_versionMajor];
- hd->folder_count = archive_le16dec(p + CFHEADER_cFolders);
- if (hd->folder_count == 0)
- goto invalid;
- hd->file_count = archive_le16dec(p + CFHEADER_cFiles);
- if (hd->file_count == 0)
- goto invalid;
- hd->flags = archive_le16dec(p + CFHEADER_flags);
- hd->setid = archive_le16dec(p + CFHEADER_setID);
- hd->cabinet = archive_le16dec(p + CFHEADER_iCabinet);
- used = CFHEADER_iCabinet + 2;
- if (hd->flags & RESERVE_PRESENT) {
- uint16_t cfheader;
- cfheader = archive_le16dec(p + CFHEADER_cbCFHeader);
- if (cfheader > 60000U)
- goto invalid;
- hd->cffolder = p[CFHEADER_cbCFFolder];
- hd->cfdata = p[CFHEADER_cbCFData];
- used += 4;/* cbCFHeader, cbCFFolder and cbCFData */
- used += cfheader;/* abReserve */
- } else
- hd->cffolder = 0;/* Avoid compiling warning. */
- if (hd->flags & PREV_CABINET) {
- /* How many bytes are used for szCabinetPrev. */
- if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
- return (truncated_error(a));
- if ((len = cab_strnlen(p + used, 255)) <= 0)
- goto invalid;
- used += len + 1;
- /* How many bytes are used for szDiskPrev. */
- if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
- return (truncated_error(a));
- if ((len = cab_strnlen(p + used, 255)) <= 0)
- goto invalid;
- used += len + 1;
- }
- if (hd->flags & NEXT_CABINET) {
- /* How many bytes are used for szCabinetNext. */
- if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
- return (truncated_error(a));
- if ((len = cab_strnlen(p + used, 255)) <= 0)
- goto invalid;
- used += len + 1;
- /* How many bytes are used for szDiskNext. */
- if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
- return (truncated_error(a));
- if ((len = cab_strnlen(p + used, 255)) <= 0)
- goto invalid;
- used += len + 1;
- }
- __archive_read_consume(a, used);
- cab->cab_offset += used;
- used = 0;
-
- /*
- * Read CFFOLDER.
- */
- hd->folder_array = (struct cffolder *)calloc(
- hd->folder_count, sizeof(struct cffolder));
- if (hd->folder_array == NULL)
- goto nomem;
-
- bytes = 8;
- if (hd->flags & RESERVE_PRESENT)
- bytes += hd->cffolder;
- bytes *= hd->folder_count;
- if ((p = __archive_read_ahead(a, bytes, NULL)) == NULL)
- return (truncated_error(a));
- offset32 = 0;
- for (i = 0; i < hd->folder_count; i++) {
- struct cffolder *folder = &(hd->folder_array[i]);
- folder->cfdata_offset_in_cab =
- archive_le32dec(p + CFFOLDER_coffCabStart);
- folder->cfdata_count = archive_le16dec(p+CFFOLDER_cCFData);
- folder->comptype =
- archive_le16dec(p+CFFOLDER_typeCompress) & 0x0F;
- folder->compdata =
- archive_le16dec(p+CFFOLDER_typeCompress) >> 8;
- /* Get a compression name. */
- if (folder->comptype <
- sizeof(compression_name) / sizeof(compression_name[0]))
- folder->compname = compression_name[folder->comptype];
- else
- folder->compname = "UNKNOWN";
- p += 8;
- used += 8;
- if (hd->flags & RESERVE_PRESENT) {
- p += hd->cffolder;/* abReserve */
- used += hd->cffolder;
- }
- /*
- * Sanity check if each data is acceptable.
- */
- if (offset32 >= folder->cfdata_offset_in_cab)
- goto invalid;
- offset32 = folder->cfdata_offset_in_cab;
-
- /* Set a request to initialize zlib for the CFDATA of
- * this folder. */
- folder->decompress_init = 0;
- }
- __archive_read_consume(a, used);
- cab->cab_offset += used;
-
- /*
- * Read CFFILE.
- */
- /* Seek read pointer to the offset of CFFILE if needed. */
- skip = (int64_t)hd->files_offset - cab->cab_offset;
- if (skip < 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid offset of CFFILE %jd < %jd",
- (intmax_t)hd->files_offset, (intmax_t)cab->cab_offset);
- return (ARCHIVE_FATAL);
- }
- if (skip) {
- __archive_read_consume(a, skip);
- cab->cab_offset += skip;
- }
- /* Allocate memory for CFDATA */
- hd->file_array = (struct cffile *)calloc(
- hd->file_count, sizeof(struct cffile));
- if (hd->file_array == NULL)
- goto nomem;
-
- prev_folder = -1;
- for (i = 0; i < hd->file_count; i++) {
- struct cffile *file = &(hd->file_array[i]);
- ssize_t avail;
-
- if ((p = __archive_read_ahead(a, 16, NULL)) == NULL)
- return (truncated_error(a));
- file->uncompressed_size = archive_le32dec(p + CFFILE_cbFile);
- file->offset = archive_le32dec(p + CFFILE_uoffFolderStart);
- file->folder = archive_le16dec(p + CFFILE_iFolder);
- file->mtime = cab_dos_time(p + CFFILE_date_time);
- file->attr = (uint8_t)archive_le16dec(p + CFFILE_attribs);
- __archive_read_consume(a, 16);
-
- cab->cab_offset += 16;
- if ((p = cab_read_ahead_remaining(a, 256, &avail)) == NULL)
- return (truncated_error(a));
- if ((len = cab_strnlen(p, avail-1)) <= 0)
- goto invalid;
-
- /* Copy a pathname. */
- archive_string_init(&(file->pathname));
- archive_strncpy(&(file->pathname), p, len);
- __archive_read_consume(a, len + 1);
- cab->cab_offset += len + 1;
-
- /*
- * Sanity check if each data is acceptable.
- */
- if (file->uncompressed_size > 0x7FFF8000)
- goto invalid;/* Too large */
- if ((int64_t)file->offset + (int64_t)file->uncompressed_size
- > ARCHIVE_LITERAL_LL(0x7FFF8000))
- goto invalid;/* Too large */
- switch (file->folder) {
- case iFoldCONTINUED_TO_NEXT:
- /* This must be last file in a folder. */
- if (i != hd->file_count -1)
- goto invalid;
- cur_folder = hd->folder_count -1;
- break;
- case iFoldCONTINUED_PREV_AND_NEXT:
- /* This must be only one file in a folder. */
- if (hd->file_count != 1)
- goto invalid;
- /* FALL THROUGH */
- case iFoldCONTINUED_FROM_PREV:
- /* This must be first file in a folder. */
- if (i != 0)
- goto invalid;
- prev_folder = cur_folder = 0;
- offset32 = file->offset;
- break;
- default:
- if (file->folder >= hd->folder_count)
- goto invalid;
- cur_folder = file->folder;
- break;
- }
- /* Dot not back track. */
- if (cur_folder < prev_folder)
- goto invalid;
- if (cur_folder != prev_folder)
- offset32 = 0;
- prev_folder = cur_folder;
-
- /* Make sure there are not any blanks from last file
- * contents. */
- if (offset32 != file->offset)
- goto invalid;
- offset32 += file->uncompressed_size;
-
- /* CFDATA is available for file contents. */
- if (file->uncompressed_size > 0 &&
- hd->folder_array[cur_folder].cfdata_count == 0)
- goto invalid;
- }
-
- if (hd->cabinet != 0 || hd->flags & (PREV_CABINET | NEXT_CABINET)) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Multivolume cabinet file is unsupported");
- return (ARCHIVE_WARN);
- }
- return (ARCHIVE_OK);
-invalid:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid CAB header");
- return (ARCHIVE_FATAL);
-nomem:
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for CAB data");
- return (ARCHIVE_FATAL);
-}
-
-static int
-archive_read_format_cab_read_header(struct archive_read *a,
- struct archive_entry *entry)
-{
- struct cab *cab;
- struct cfheader *hd;
- struct cffolder *prev_folder;
- struct cffile *file;
- struct archive_string_conv *sconv;
- int err = ARCHIVE_OK, r;
-
- cab = (struct cab *)(a->format->data);
- if (cab->found_header == 0) {
- err = cab_read_header(a);
- if (err < ARCHIVE_WARN)
- return (err);
- /* We've found the header. */
- cab->found_header = 1;
- }
- hd = &cab->cfheader;
-
- if (hd->file_index >= hd->file_count) {
- cab->end_of_archive = 1;
- return (ARCHIVE_EOF);
- }
- file = &hd->file_array[hd->file_index++];
-
- cab->end_of_entry = 0;
- cab->end_of_entry_cleanup = 0;
- cab->entry_compressed_bytes_read = 0;
- cab->entry_uncompressed_bytes_read = 0;
- cab->entry_unconsumed = 0;
- cab->entry_cffile = file;
-
- /*
- * Choose a proper folder.
- */
- prev_folder = cab->entry_cffolder;
- switch (file->folder) {
- case iFoldCONTINUED_FROM_PREV:
- case iFoldCONTINUED_PREV_AND_NEXT:
- cab->entry_cffolder = &hd->folder_array[0];
- break;
- case iFoldCONTINUED_TO_NEXT:
- cab->entry_cffolder = &hd->folder_array[hd->folder_count-1];
- break;
- default:
- cab->entry_cffolder = &hd->folder_array[file->folder];
- break;
- }
- /* If a cffolder of this file is changed, reset a cfdata to read
- * file contents from next cfdata. */
- if (prev_folder != cab->entry_cffolder)
- cab->entry_cfdata = NULL;
-
- /* If a pathname is UTF-8, prepare a string conversion object
- * for UTF-8 and use it. */
- if (file->attr & ATTR_NAME_IS_UTF) {
- if (cab->sconv_utf8 == NULL) {
- cab->sconv_utf8 =
- archive_string_conversion_from_charset(
- &(a->archive), "UTF-8", 1);
- if (cab->sconv_utf8 == NULL)
- return (ARCHIVE_FATAL);
- }
- sconv = cab->sconv_utf8;
- } else if (cab->sconv != NULL) {
- /* Choose the conversion specified by the option. */
- sconv = cab->sconv;
- } else {
- /* Choose the default conversion. */
- if (!cab->init_default_conversion) {
- cab->sconv_default =
- archive_string_default_conversion_for_read(
- &(a->archive));
- cab->init_default_conversion = 1;
- }
- sconv = cab->sconv_default;
- }
-
- /*
- * Set a default value and common data
- */
- r = cab_convert_path_separator_1(&(file->pathname), file->attr);
- if (archive_entry_copy_pathname_l(entry, file->pathname.s,
- archive_strlen(&(file->pathname)), sconv) != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Pathname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Pathname cannot be converted "
- "from %s to current locale.",
- archive_string_conversion_charset_name(sconv));
- err = ARCHIVE_WARN;
- }
- if (r < 0) {
- /* Convert a path separator '\' -> '/' */
- cab_convert_path_separator_2(cab, entry);
- }
-
- archive_entry_set_size(entry, file->uncompressed_size);
- if (file->attr & ATTR_RDONLY)
- archive_entry_set_mode(entry, AE_IFREG | 0555);
- else
- archive_entry_set_mode(entry, AE_IFREG | 0666);
- archive_entry_set_mtime(entry, file->mtime, 0);
-
- cab->entry_bytes_remaining = file->uncompressed_size;
- cab->entry_offset = 0;
- /* We don't need compress data. */
- if (file->uncompressed_size == 0)
- cab->end_of_entry_cleanup = cab->end_of_entry = 1;
-
- /* Set up a more descriptive format name. */
- sprintf(cab->format_name, "CAB %d.%d (%s)",
- hd->major, hd->minor, cab->entry_cffolder->compname);
- a->archive.archive_format_name = cab->format_name;
-
- return (err);
-}
-
-static int
-archive_read_format_cab_read_data(struct archive_read *a,
- const void **buff, size_t *size, int64_t *offset)
-{
- struct cab *cab = (struct cab *)(a->format->data);
- int r;
-
- switch (cab->entry_cffile->folder) {
- case iFoldCONTINUED_FROM_PREV:
- case iFoldCONTINUED_TO_NEXT:
- case iFoldCONTINUED_PREV_AND_NEXT:
- *buff = NULL;
- *size = 0;
- *offset = 0;
- archive_clear_error(&a->archive);
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Cannot restore this file split in multivolume.");
- return (ARCHIVE_FAILED);
- default:
- break;
- }
- if (cab->read_data_invoked == 0) {
- if (cab->bytes_skipped) {
- if (cab->entry_cfdata == NULL) {
- r = cab_next_cfdata(a);
- if (r < 0)
- return (r);
- }
- if (cab_consume_cfdata(a, cab->bytes_skipped) < 0)
- return (ARCHIVE_FATAL);
- cab->bytes_skipped = 0;
- }
- cab->read_data_invoked = 1;
- }
- if (cab->entry_unconsumed) {
- /* Consume as much as the compressor actually used. */
- r = (int)cab_consume_cfdata(a, cab->entry_unconsumed);
- cab->entry_unconsumed = 0;
- if (r < 0)
- return (r);
- }
- if (cab->end_of_archive || cab->end_of_entry) {
- if (!cab->end_of_entry_cleanup) {
- /* End-of-entry cleanup done. */
- cab->end_of_entry_cleanup = 1;
- }
- *offset = cab->entry_offset;
- *size = 0;
- *buff = NULL;
- return (ARCHIVE_EOF);
- }
-
- return (cab_read_data(a, buff, size, offset));
-}
-
-static uint32_t
-cab_checksum_cfdata_4(const void *p, size_t bytes, uint32_t seed)
-{
- const unsigned char *b;
- unsigned u32num;
- uint32_t sum;
-
- u32num = (unsigned)bytes / 4;
- sum = seed;
- b = p;
- for (;u32num > 0; --u32num) {
- sum ^= archive_le32dec(b);
- b += 4;
- }
- return (sum);
-}
-
-static uint32_t
-cab_checksum_cfdata(const void *p, size_t bytes, uint32_t seed)
-{
- const unsigned char *b;
- uint32_t sum;
- uint32_t t;
-
- sum = cab_checksum_cfdata_4(p, bytes, seed);
- b = p;
- b += bytes & ~3;
- t = 0;
- switch (bytes & 3) {
- case 3:
- t |= ((uint32_t)(*b++)) << 16;
- /* FALL THROUGH */
- case 2:
- t |= ((uint32_t)(*b++)) << 8;
- /* FALL THROUGH */
- case 1:
- t |= *b;
- /* FALL THROUGH */
- default:
- break;
- }
- sum ^= t;
-
- return (sum);
-}
-
-static void
-cab_checksum_update(struct archive_read *a, size_t bytes)
-{
- struct cab *cab = (struct cab *)(a->format->data);
- struct cfdata *cfdata = cab->entry_cfdata;
- const unsigned char *p;
- size_t sumbytes;
-
- if (cfdata->sum == 0 || cfdata->sum_ptr == NULL)
- return;
- /*
- * Calculate the sum of this CFDATA.
- * Make sure CFDATA must be calculated in four bytes.
- */
- p = cfdata->sum_ptr;
- sumbytes = bytes;
- if (cfdata->sum_extra_avail) {
- while (cfdata->sum_extra_avail < 4 && sumbytes > 0) {
- cfdata->sum_extra[
- cfdata->sum_extra_avail++] = *p++;
- sumbytes--;
- }
- if (cfdata->sum_extra_avail == 4) {
- cfdata->sum_calculated = cab_checksum_cfdata_4(
- cfdata->sum_extra, 4, cfdata->sum_calculated);
- cfdata->sum_extra_avail = 0;
- }
- }
- if (sumbytes) {
- int odd = sumbytes & 3;
- if (sumbytes - odd > 0)
- cfdata->sum_calculated = cab_checksum_cfdata_4(
- p, sumbytes - odd, cfdata->sum_calculated);
- if (odd)
- memcpy(cfdata->sum_extra, p + sumbytes - odd, odd);
- cfdata->sum_extra_avail = odd;
- }
- cfdata->sum_ptr = NULL;
-}
-
-static int
-cab_checksum_finish(struct archive_read *a)
-{
- struct cab *cab = (struct cab *)(a->format->data);
- struct cfdata *cfdata = cab->entry_cfdata;
- int l;
-
- /* Do not need to compute a sum. */
- if (cfdata->sum == 0)
- return (ARCHIVE_OK);
-
- /*
- * Calculate the sum of remaining CFDATA.
- */
- if (cfdata->sum_extra_avail) {
- cfdata->sum_calculated =
- cab_checksum_cfdata(cfdata->sum_extra,
- cfdata->sum_extra_avail, cfdata->sum_calculated);
- cfdata->sum_extra_avail = 0;
- }
-
- l = 4;
- if (cab->cfheader.flags & RESERVE_PRESENT)
- l += cab->cfheader.cfdata;
- cfdata->sum_calculated = cab_checksum_cfdata(
- cfdata->memimage + CFDATA_cbData, l, cfdata->sum_calculated);
- if (cfdata->sum_calculated != cfdata->sum) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Checksum error CFDATA[%d] %x:%x in %d bytes",
- cab->entry_cffolder->cfdata_index -1,
- cfdata->sum, cfdata->sum_calculated,
- cfdata->compressed_size);
- return (ARCHIVE_FAILED);
- }
- return (ARCHIVE_OK);
-}
-
-/*
- * Read CFDATA if needed.
- */
-static int
-cab_next_cfdata(struct archive_read *a)
-{
- struct cab *cab = (struct cab *)(a->format->data);
- struct cfdata *cfdata = cab->entry_cfdata;
-
- /* There are remaining bytes in current CFDATA, use it first. */
- if (cfdata != NULL && cfdata->uncompressed_bytes_remaining > 0)
- return (ARCHIVE_OK);
-
- if (cfdata == NULL) {
- int64_t skip;
-
- cab->entry_cffolder->cfdata_index = 0;
-
- /* Seek read pointer to the offset of CFDATA if needed. */
- skip = cab->entry_cffolder->cfdata_offset_in_cab
- - cab->cab_offset;
- if (skip < 0) {
- int folder_index;
- switch (cab->entry_cffile->folder) {
- case iFoldCONTINUED_FROM_PREV:
- case iFoldCONTINUED_PREV_AND_NEXT:
- folder_index = 0;
- break;
- case iFoldCONTINUED_TO_NEXT:
- folder_index = cab->cfheader.folder_count-1;
- break;
- default:
- folder_index = cab->entry_cffile->folder;
- break;
- }
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid offset of CFDATA in folder(%d) %jd < %jd",
- folder_index,
- (intmax_t)cab->entry_cffolder->cfdata_offset_in_cab,
- (intmax_t)cab->cab_offset);
- return (ARCHIVE_FATAL);
- }
- if (skip > 0) {
- if (__archive_read_consume(a, skip) < 0)
- return (ARCHIVE_FATAL);
- cab->cab_offset =
- cab->entry_cffolder->cfdata_offset_in_cab;
- }
- }
-
- /*
- * Read a CFDATA.
- */
- if (cab->entry_cffolder->cfdata_index <
- cab->entry_cffolder->cfdata_count) {
- const unsigned char *p;
- int l;
-
- cfdata = &(cab->entry_cffolder->cfdata);
- cab->entry_cffolder->cfdata_index++;
- cab->entry_cfdata = cfdata;
- cfdata->sum_calculated = 0;
- cfdata->sum_extra_avail = 0;
- cfdata->sum_ptr = NULL;
- l = 8;
- if (cab->cfheader.flags & RESERVE_PRESENT)
- l += cab->cfheader.cfdata;
- if ((p = __archive_read_ahead(a, l, NULL)) == NULL)
- return (truncated_error(a));
- cfdata->sum = archive_le32dec(p + CFDATA_csum);
- cfdata->compressed_size = archive_le16dec(p + CFDATA_cbData);
- cfdata->compressed_bytes_remaining = cfdata->compressed_size;
- cfdata->uncompressed_size =
- archive_le16dec(p + CFDATA_cbUncomp);
- cfdata->uncompressed_bytes_remaining =
- cfdata->uncompressed_size;
- cfdata->uncompressed_avail = 0;
- cfdata->read_offset = 0;
- cfdata->unconsumed = 0;
-
- /*
- * Sanity check if data size is acceptable.
- */
- if (cfdata->compressed_size == 0 ||
- cfdata->compressed_size > (0x8000+6144))
- goto invalid;
- if (cfdata->uncompressed_size > 0x8000)
- goto invalid;
- if (cfdata->uncompressed_size == 0) {
- switch (cab->entry_cffile->folder) {
- case iFoldCONTINUED_PREV_AND_NEXT:
- case iFoldCONTINUED_TO_NEXT:
- break;
- case iFoldCONTINUED_FROM_PREV:
- default:
- goto invalid;
- }
- }
- /* If CFDATA is not last in a folder, an uncompressed
- * size must be 0x8000(32KBi) */
- if ((cab->entry_cffolder->cfdata_index <
- cab->entry_cffolder->cfdata_count) &&
- cfdata->uncompressed_size != 0x8000)
- goto invalid;
-
- /* A compressed data size and an uncompressed data size must
- * be the same in no compression mode. */
- if (cab->entry_cffolder->comptype == COMPTYPE_NONE &&
- cfdata->compressed_size != cfdata->uncompressed_size)
- goto invalid;
-
- /*
- * Save CFDATA image for sum check.
- */
- if (cfdata->memimage_size < (size_t)l) {
- free(cfdata->memimage);
- cfdata->memimage = malloc(l);
- if (cfdata->memimage == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for CAB data");
- return (ARCHIVE_FATAL);
- }
- cfdata->memimage_size = l;
- }
- memcpy(cfdata->memimage, p, l);
-
- /* Consume bytes as much as we used. */
- __archive_read_consume(a, l);
- cab->cab_offset += l;
- } else if (cab->entry_cffolder->cfdata_count > 0) {
- /* Run out of all CFDATA in a folder. */
- cfdata->compressed_size = 0;
- cfdata->uncompressed_size = 0;
- cfdata->compressed_bytes_remaining = 0;
- cfdata->uncompressed_bytes_remaining = 0;
- } else {
- /* Current folder does not have any CFDATA. */
- cfdata = &(cab->entry_cffolder->cfdata);
- cab->entry_cfdata = cfdata;
- memset(cfdata, 0, sizeof(*cfdata));
- }
- return (ARCHIVE_OK);
-invalid:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid CFDATA");
- return (ARCHIVE_FATAL);
-}
-
-/*
- * Read ahead CFDATA.
- */
-static const void *
-cab_read_ahead_cfdata(struct archive_read *a, ssize_t *avail)
-{
- struct cab *cab = (struct cab *)(a->format->data);
- int err;
-
- err = cab_next_cfdata(a);
- if (err < ARCHIVE_OK) {
- *avail = err;
- return (NULL);
- }
-
- switch (cab->entry_cffolder->comptype) {
- case COMPTYPE_NONE:
- return (cab_read_ahead_cfdata_none(a, avail));
- case COMPTYPE_MSZIP:
- return (cab_read_ahead_cfdata_deflate(a, avail));
- case COMPTYPE_LZX:
- return (cab_read_ahead_cfdata_lzx(a, avail));
- default: /* Unsupported compression. */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Unsupported CAB compression : %s",
- cab->entry_cffolder->compname);
- *avail = ARCHIVE_FAILED;
- return (NULL);
- }
-}
-
-/*
- * Read ahead CFDATA as uncompressed data.
- */
-static const void *
-cab_read_ahead_cfdata_none(struct archive_read *a, ssize_t *avail)
-{
- struct cab *cab = (struct cab *)(a->format->data);
- struct cfdata *cfdata;
- const void *d;
-
- cfdata = cab->entry_cfdata;
-
- /*
- * Note: '1' here is a performance optimization.
- * Recall that the decompression layer returns a count of
- * available bytes; asking for more than that forces the
- * decompressor to combine reads by copying data.
- */
- d = __archive_read_ahead(a, 1, avail);
- if (*avail <= 0) {
- *avail = truncated_error(a);
- return (NULL);
- }
- if (*avail > cfdata->uncompressed_bytes_remaining)
- *avail = cfdata->uncompressed_bytes_remaining;
- cfdata->uncompressed_avail = cfdata->uncompressed_size;
- cfdata->unconsumed = *avail;
- cfdata->sum_ptr = d;
- return (d);
-}
-
-/*
- * Read ahead CFDATA as deflate data.
- */
-#ifdef HAVE_ZLIB_H
-static const void *
-cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
-{
- struct cab *cab = (struct cab *)(a->format->data);
- struct cfdata *cfdata;
- const void *d;
- int r, mszip;
- uint16_t uavail;
- char eod = 0;
-
- cfdata = cab->entry_cfdata;
- /* If the buffer hasn't been allocated, allocate it now. */
- if (cab->uncompressed_buffer == NULL) {
- cab->uncompressed_buffer_size = 0x8000;
- cab->uncompressed_buffer
- = (unsigned char *)malloc(cab->uncompressed_buffer_size);
- if (cab->uncompressed_buffer == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "No memory for CAB reader");
- *avail = ARCHIVE_FATAL;
- return (NULL);
- }
- }
-
- uavail = cfdata->uncompressed_avail;
- if (uavail == cfdata->uncompressed_size) {
- d = cab->uncompressed_buffer + cfdata->read_offset;
- *avail = uavail - cfdata->read_offset;
- return (d);
- }
-
- if (!cab->entry_cffolder->decompress_init) {
- cab->stream.next_in = NULL;
- cab->stream.avail_in = 0;
- cab->stream.total_in = 0;
- cab->stream.next_out = NULL;
- cab->stream.avail_out = 0;
- cab->stream.total_out = 0;
- if (cab->stream_valid)
- r = inflateReset(&cab->stream);
- else
- r = inflateInit2(&cab->stream,
- -15 /* Don't check for zlib header */);
- if (r != Z_OK) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Can't initialize deflate decompression.");
- *avail = ARCHIVE_FATAL;
- return (NULL);
- }
- /* Stream structure has been set up. */
- cab->stream_valid = 1;
- /* We've initialized decompression for this stream. */
- cab->entry_cffolder->decompress_init = 1;
- }
-
- if (cfdata->compressed_bytes_remaining == cfdata->compressed_size)
- mszip = 2;
- else
- mszip = 0;
- eod = 0;
- cab->stream.total_out = uavail;
- /*
- * We always uncompress all data in current CFDATA.
- */
- while (!eod && cab->stream.total_out < cfdata->uncompressed_size) {
- ssize_t bytes_avail;
-
- cab->stream.next_out =
- cab->uncompressed_buffer + cab->stream.total_out;
- cab->stream.avail_out =
- cfdata->uncompressed_size - cab->stream.total_out;
-
- d = __archive_read_ahead(a, 1, &bytes_avail);
- if (bytes_avail <= 0) {
- *avail = truncated_error(a);
- return (NULL);
- }
- if (bytes_avail > cfdata->compressed_bytes_remaining)
- bytes_avail = cfdata->compressed_bytes_remaining;
- /*
- * A bug in zlib.h: stream.next_in should be marked 'const'
- * but isn't (the library never alters data through the
- * next_in pointer, only reads it). The result: this ugly
- * cast to remove 'const'.
- */
- cab->stream.next_in = (Bytef *)(uintptr_t)d;
- cab->stream.avail_in = (uInt)bytes_avail;
- cab->stream.total_in = 0;
-
- /* Cut out a tow-byte MSZIP signature(0x43, 0x4b). */
- if (mszip > 0) {
- if (bytes_avail <= mszip) {
- if (mszip == 2) {
- if (cab->stream.next_in[0] != 0x43)
- goto nomszip;
- if (bytes_avail > 1 &&
- cab->stream.next_in[1] != 0x4b)
- goto nomszip;
- } else if (cab->stream.next_in[0] != 0x4b)
- goto nomszip;
- cfdata->unconsumed = bytes_avail;
- cfdata->sum_ptr = d;
- if (cab_minimum_consume_cfdata(
- a, cfdata->unconsumed) < 0) {
- *avail = ARCHIVE_FATAL;
- return (NULL);
- }
- mszip -= (int)bytes_avail;
- continue;
- }
- if (mszip == 1 && cab->stream.next_in[0] != 0x4b)
- goto nomszip;
- else if (cab->stream.next_in[0] != 0x43 ||
- cab->stream.next_in[1] != 0x4b)
- goto nomszip;
- cab->stream.next_in += mszip;
- cab->stream.avail_in -= mszip;
- cab->stream.total_in += mszip;
- mszip = 0;
- }
-
- r = inflate(&cab->stream, 0);
- switch (r) {
- case Z_OK:
- break;
- case Z_STREAM_END:
- eod = 1;
- break;
- default:
- goto zlibfailed;
- }
- cfdata->unconsumed = cab->stream.total_in;
- cfdata->sum_ptr = d;
- if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {
- *avail = ARCHIVE_FATAL;
- return (NULL);
- }
- }
- uavail = (uint16_t)cab->stream.total_out;
-
- if (uavail < cfdata->uncompressed_size) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid uncompressed size (%d < %d)",
- uavail, cfdata->uncompressed_size);
- *avail = ARCHIVE_FATAL;
- return (NULL);
- }
-
- /*
- * Note: I suspect there is a bug in makecab.exe because, in rare
- * case, compressed bytes are still remaining regardless we have
- * gotten all uncompressed bytes, which size is recoded in CFDATA,
- * as much as we need, and we have to use the garbage so as to
- * correctly compute the sum of CFDATA accordingly.
- */
- if (cfdata->compressed_bytes_remaining > 0) {
- ssize_t bytes_avail;
-
- d = __archive_read_ahead(a, cfdata->compressed_bytes_remaining,
- &bytes_avail);
- if (bytes_avail <= 0) {
- *avail = truncated_error(a);
- return (NULL);
- }
- cfdata->unconsumed = cfdata->compressed_bytes_remaining;
- cfdata->sum_ptr = d;
- if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {
- *avail = ARCHIVE_FATAL;
- return (NULL);
- }
- }
-
- /*
- * Set dictionary data for decompressing of next CFDATA, which
- * in the same folder. This is why we always do decompress CFDATA
- * even if beginning CFDATA or some of CFDATA are not used in
- * skipping file data.
- */
- if (cab->entry_cffolder->cfdata_index <
- cab->entry_cffolder->cfdata_count) {
- r = inflateReset(&cab->stream);
- if (r != Z_OK)
- goto zlibfailed;
- r = inflateSetDictionary(&cab->stream,
- cab->uncompressed_buffer, cfdata->uncompressed_size);
- if (r != Z_OK)
- goto zlibfailed;
- }
-
- d = cab->uncompressed_buffer + cfdata->read_offset;
- *avail = uavail - cfdata->read_offset;
- cfdata->uncompressed_avail = uavail;
-
- return (d);
-
-zlibfailed:
- switch (r) {
- case Z_MEM_ERROR:
- archive_set_error(&a->archive, ENOMEM,
- "Out of memory for deflate decompression");
- break;
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Deflate decompression failed (%d)", r);
- break;
- }
- *avail = ARCHIVE_FATAL;
- return (NULL);
-nomszip:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "CFDATA incorrect(no MSZIP signature)");
- *avail = ARCHIVE_FATAL;
- return (NULL);
-}
-
-#else /* HAVE_ZLIB_H */
-
-static const void *
-cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
-{
- *avail = ARCHIVE_FATAL;
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "libarchive compiled without deflate support (no libz)");
- return (NULL);
-}
-
-#endif /* HAVE_ZLIB_H */
-
-static const void *
-cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail)
-{
- struct cab *cab = (struct cab *)(a->format->data);
- struct cfdata *cfdata;
- const void *d;
- int r;
- uint16_t uavail;
-
- cfdata = cab->entry_cfdata;
- /* If the buffer hasn't been allocated, allocate it now. */
- if (cab->uncompressed_buffer == NULL) {
- cab->uncompressed_buffer_size = 0x8000;
- cab->uncompressed_buffer
- = (unsigned char *)malloc(cab->uncompressed_buffer_size);
- if (cab->uncompressed_buffer == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "No memory for CAB reader");
- *avail = ARCHIVE_FATAL;
- return (NULL);
- }
- }
-
- uavail = cfdata->uncompressed_avail;
- if (uavail == cfdata->uncompressed_size) {
- d = cab->uncompressed_buffer + cfdata->read_offset;
- *avail = uavail - cfdata->read_offset;
- return (d);
- }
-
- if (!cab->entry_cffolder->decompress_init) {
- r = lzx_decode_init(&cab->xstrm,
- cab->entry_cffolder->compdata);
- if (r != ARCHIVE_OK) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Can't initialize LZX decompression.");
- *avail = ARCHIVE_FATAL;
- return (NULL);
- }
- /* We've initialized decompression for this stream. */
- cab->entry_cffolder->decompress_init = 1;
- }
-
- /* Clean up remaining bits of previous CFDATA. */
- lzx_cleanup_bitstream(&cab->xstrm);
- cab->xstrm.total_out = uavail;
- while (cab->xstrm.total_out < cfdata->uncompressed_size) {
- ssize_t bytes_avail;
-
- cab->xstrm.next_out =
- cab->uncompressed_buffer + cab->xstrm.total_out;
- cab->xstrm.avail_out =
- cfdata->uncompressed_size - cab->xstrm.total_out;
-
- d = __archive_read_ahead(a, 1, &bytes_avail);
- if (bytes_avail <= 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated CAB file data");
- *avail = ARCHIVE_FATAL;
- return (NULL);
- }
- if (bytes_avail > cfdata->compressed_bytes_remaining)
- bytes_avail = cfdata->compressed_bytes_remaining;
-
- cab->xstrm.next_in = d;
- cab->xstrm.avail_in = bytes_avail;
- cab->xstrm.total_in = 0;
- r = lzx_decode(&cab->xstrm,
- cfdata->compressed_bytes_remaining == bytes_avail);
- switch (r) {
- case ARCHIVE_OK:
- case ARCHIVE_EOF:
- break;
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "LZX decompression failed (%d)", r);
- *avail = ARCHIVE_FATAL;
- return (NULL);
- }
- cfdata->unconsumed = cab->xstrm.total_in;
- cfdata->sum_ptr = d;
- if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {
- *avail = ARCHIVE_FATAL;
- return (NULL);
- }
- }
-
- uavail = (uint16_t)cab->xstrm.total_out;
- /*
- * Make sure a read pointer advances to next CFDATA.
- */
- if (cfdata->compressed_bytes_remaining > 0) {
- ssize_t bytes_avail;
-
- d = __archive_read_ahead(a, cfdata->compressed_bytes_remaining,
- &bytes_avail);
- if (bytes_avail <= 0) {
- *avail = truncated_error(a);
- return (NULL);
- }
- cfdata->unconsumed = cfdata->compressed_bytes_remaining;
- cfdata->sum_ptr = d;
- if (cab_minimum_consume_cfdata(a, cfdata->unconsumed) < 0) {
- *avail = ARCHIVE_FATAL;
- return (NULL);
- }
- }
-
- /*
- * Translation reversal of x86 proccessor CALL byte sequence(E8).
- */
- lzx_translation(&cab->xstrm, cab->uncompressed_buffer,
- cfdata->uncompressed_size,
- (cab->entry_cffolder->cfdata_index-1) * 0x8000);
-
- d = cab->uncompressed_buffer + cfdata->read_offset;
- *avail = uavail - cfdata->read_offset;
- cfdata->uncompressed_avail = uavail;
-
- return (d);
-}
-
-/*
- * Consume CFDATA.
- * We always decompress CFDATA to consume CFDATA as much as we need
- * in uncompressed bytes because all CFDATA in a folder are related
- * so we do not skip any CFDATA without decompressing.
- * Note: If the folder of a CFFILE is iFoldCONTINUED_PREV_AND_NEXT or
- * iFoldCONTINUED_FROM_PREV, we won't decompress because a CFDATA for
- * the CFFILE is remaining bytes of previous Multivolume CAB file.
- */
-static int64_t
-cab_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
-{
- struct cab *cab = (struct cab *)(a->format->data);
- struct cfdata *cfdata;
- int64_t cbytes, rbytes;
- int err;
-
- rbytes = cab_minimum_consume_cfdata(a, consumed_bytes);
- if (rbytes < 0)
- return (ARCHIVE_FATAL);
-
- cfdata = cab->entry_cfdata;
- while (rbytes > 0) {
- ssize_t avail;
-
- if (cfdata->compressed_size == 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid CFDATA");
- return (ARCHIVE_FATAL);
- }
- cbytes = cfdata->uncompressed_bytes_remaining;
- if (cbytes > rbytes)
- cbytes = rbytes;
- rbytes -= cbytes;
-
- if (cfdata->uncompressed_avail == 0 &&
- (cab->entry_cffile->folder == iFoldCONTINUED_PREV_AND_NEXT ||
- cab->entry_cffile->folder == iFoldCONTINUED_FROM_PREV)) {
- /* We have not read any data yet. */
- if (cbytes == cfdata->uncompressed_bytes_remaining) {
- /* Skip whole current CFDATA. */
- __archive_read_consume(a,
- cfdata->compressed_size);
- cab->cab_offset += cfdata->compressed_size;
- cfdata->compressed_bytes_remaining = 0;
- cfdata->uncompressed_bytes_remaining = 0;
- err = cab_next_cfdata(a);
- if (err < 0)
- return (err);
- cfdata = cab->entry_cfdata;
- if (cfdata->uncompressed_size == 0) {
- switch (cab->entry_cffile->folder) {
- case iFoldCONTINUED_PREV_AND_NEXT:
- case iFoldCONTINUED_TO_NEXT:
- case iFoldCONTINUED_FROM_PREV:
- rbytes = 0;
- break;
- default:
- break;
- }
- }
- continue;
- }
- cfdata->read_offset += (uint16_t)cbytes;
- cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;
- break;
- } else if (cbytes == 0) {
- err = cab_next_cfdata(a);
- if (err < 0)
- return (err);
- cfdata = cab->entry_cfdata;
- if (cfdata->uncompressed_size == 0) {
- switch (cab->entry_cffile->folder) {
- case iFoldCONTINUED_PREV_AND_NEXT:
- case iFoldCONTINUED_TO_NEXT:
- case iFoldCONTINUED_FROM_PREV:
- return (ARCHIVE_FATAL);
- default:
- break;
- }
- }
- continue;
- }
- while (cbytes > 0) {
- (void)cab_read_ahead_cfdata(a, &avail);
- if (avail <= 0)
- return (ARCHIVE_FATAL);
- if (avail > cbytes)
- avail = (ssize_t)cbytes;
- if (cab_minimum_consume_cfdata(a, avail) < 0)
- return (ARCHIVE_FATAL);
- cbytes -= avail;
- }
- }
- return (consumed_bytes);
-}
-
-/*
- * Consume CFDATA as much as we have already gotten and
- * compute the sum of CFDATA.
- */
-static int64_t
-cab_minimum_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
-{
- struct cab *cab = (struct cab *)(a->format->data);
- struct cfdata *cfdata;
- int64_t cbytes, rbytes;
- int err;
-
- cfdata = cab->entry_cfdata;
- rbytes = consumed_bytes;
- if (cab->entry_cffolder->comptype == COMPTYPE_NONE) {
- if (consumed_bytes < cfdata->unconsumed)
- cbytes = consumed_bytes;
- else
- cbytes = cfdata->unconsumed;
- rbytes -= cbytes;
- cfdata->read_offset += (uint16_t)cbytes;
- cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;
- cfdata->unconsumed -= cbytes;
- } else {
- cbytes = cfdata->uncompressed_avail - cfdata->read_offset;
- if (cbytes > 0) {
- if (consumed_bytes < cbytes)
- cbytes = consumed_bytes;
- rbytes -= cbytes;
- cfdata->read_offset += (uint16_t)cbytes;
- cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;
- }
-
- if (cfdata->unconsumed) {
- cbytes = cfdata->unconsumed;
- cfdata->unconsumed = 0;
- } else
- cbytes = 0;
- }
- if (cbytes) {
- /* Compute the sum. */
- cab_checksum_update(a, (size_t)cbytes);
-
- /* Consume as much as the compressor actually used. */
- __archive_read_consume(a, cbytes);
- cab->cab_offset += cbytes;
- cfdata->compressed_bytes_remaining -= (uint16_t)cbytes;
- if (cfdata->compressed_bytes_remaining == 0) {
- err = cab_checksum_finish(a);
- if (err < 0)
- return (err);
- }
- }
- return (rbytes);
-}
-
-/*
- * Returns ARCHIVE_OK if successful, ARCHIVE_FATAL otherwise, sets
- * cab->end_of_entry if it consumes all of the data.
- */
-static int
-cab_read_data(struct archive_read *a, const void **buff,
- size_t *size, int64_t *offset)
-{
- struct cab *cab = (struct cab *)(a->format->data);
- ssize_t bytes_avail;
-
- if (cab->entry_bytes_remaining == 0) {
- *buff = NULL;
- *size = 0;
- *offset = cab->entry_offset;
- cab->end_of_entry = 1;
- return (ARCHIVE_OK);
- }
-
- *buff = cab_read_ahead_cfdata(a, &bytes_avail);
- if (bytes_avail <= 0) {
- *buff = NULL;
- *size = 0;
- *offset = 0;
- if (bytes_avail == 0 &&
- cab->entry_cfdata->uncompressed_size == 0) {
- /* All of CFDATA in a folder has been handled. */
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT, "Invalid CFDATA");
- return (ARCHIVE_FATAL);
- } else
- return ((int)bytes_avail);
- }
- if (bytes_avail > cab->entry_bytes_remaining)
- bytes_avail = (ssize_t)cab->entry_bytes_remaining;
-
- *size = bytes_avail;
- *offset = cab->entry_offset;
- cab->entry_offset += bytes_avail;
- cab->entry_bytes_remaining -= bytes_avail;
- if (cab->entry_bytes_remaining == 0)
- cab->end_of_entry = 1;
- cab->entry_unconsumed = bytes_avail;
- if (cab->entry_cffolder->comptype == COMPTYPE_NONE) {
- /* Don't consume more than current entry used. */
- if (cab->entry_cfdata->unconsumed > cab->entry_unconsumed)
- cab->entry_cfdata->unconsumed = cab->entry_unconsumed;
- }
- return (ARCHIVE_OK);
-}
-
-static int
-archive_read_format_cab_read_data_skip(struct archive_read *a)
-{
- struct cab *cab;
- int64_t bytes_skipped;
- int r;
-
- cab = (struct cab *)(a->format->data);
-
- if (cab->end_of_archive)
- return (ARCHIVE_EOF);
-
- if (!cab->read_data_invoked) {
- cab->bytes_skipped += cab->entry_bytes_remaining;
- cab->entry_bytes_remaining = 0;
- /* This entry is finished and done. */
- cab->end_of_entry_cleanup = cab->end_of_entry = 1;
- return (ARCHIVE_OK);
- }
-
- if (cab->entry_unconsumed) {
- /* Consume as much as the compressor actually used. */
- r = (int)cab_consume_cfdata(a, cab->entry_unconsumed);
- cab->entry_unconsumed = 0;
- if (r < 0)
- return (r);
- } else if (cab->entry_cfdata == NULL) {
- r = cab_next_cfdata(a);
- if (r < 0)
- return (r);
- }
-
- /* if we've already read to end of data, we're done. */
- if (cab->end_of_entry_cleanup)
- return (ARCHIVE_OK);
-
- /*
- * If the length is at the beginning, we can skip the
- * compressed data much more quickly.
- */
- bytes_skipped = cab_consume_cfdata(a, cab->entry_bytes_remaining);
- if (bytes_skipped < 0)
- return (ARCHIVE_FATAL);
-
- /* If the compression type is none(uncompressed), we've already
- * consumed data as much as the current entry size. */
- if (cab->entry_cffolder->comptype == COMPTYPE_NONE &&
- cab->entry_cfdata != NULL)
- cab->entry_cfdata->unconsumed = 0;
-
- /* This entry is finished and done. */
- cab->end_of_entry_cleanup = cab->end_of_entry = 1;
- return (ARCHIVE_OK);
-}
-
-static int
-archive_read_format_cab_cleanup(struct archive_read *a)
-{
- struct cab *cab = (struct cab *)(a->format->data);
- struct cfheader *hd = &cab->cfheader;
- int i;
-
- if (hd->folder_array != NULL) {
- for (i = 0; i < hd->folder_count; i++)
- free(hd->folder_array[i].cfdata.memimage);
- free(hd->folder_array);
- }
- if (hd->file_array != NULL) {
- for (i = 0; i < cab->cfheader.file_count; i++)
- archive_string_free(&(hd->file_array[i].pathname));
- free(hd->file_array);
- }
-#ifdef HAVE_ZLIB_H
- if (cab->stream_valid)
- inflateEnd(&cab->stream);
-#endif
- lzx_decode_free(&cab->xstrm);
- archive_wstring_free(&cab->ws);
- free(cab->uncompressed_buffer);
- free(cab);
- (a->format->data) = NULL;
- return (ARCHIVE_OK);
-}
-
-/* Convert an MSDOS-style date/time into Unix-style time. */
-static time_t
-cab_dos_time(const unsigned char *p)
-{
- int msTime, msDate;
- struct tm ts;
-
- msDate = archive_le16dec(p);
- msTime = archive_le16dec(p+2);
-
- memset(&ts, 0, sizeof(ts));
- ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */
- ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */
- ts.tm_mday = msDate & 0x1f; /* Day of month. */
- ts.tm_hour = (msTime >> 11) & 0x1f;
- ts.tm_min = (msTime >> 5) & 0x3f;
- ts.tm_sec = (msTime << 1) & 0x3e;
- ts.tm_isdst = -1;
- return (mktime(&ts));
-}
-
-/*****************************************************************
- *
- * LZX decompression code.
- *
- *****************************************************************/
-
-/*
- * Initialize LZX decoder.
- *
- * Returns ARCHIVE_OK if initialization was successful.
- * Returns ARCHIVE_FAILED if w_bits has unsupported value.
- * Returns ARCHIVE_FATAL if initialization failed; memory allocation
- * error occurred.
- */
-static int
-lzx_decode_init(struct lzx_stream *strm, int w_bits)
-{
- struct lzx_dec *ds;
- int slot, w_size, w_slot;
- int base, footer;
- int base_inc[18];
-
- if (strm->ds == NULL) {
- strm->ds = calloc(1, sizeof(*strm->ds));
- if (strm->ds == NULL)
- return (ARCHIVE_FATAL);
- }
- ds = strm->ds;
- ds->error = ARCHIVE_FAILED;
-
- /* Allow bits from 15(32KBi) up to 21(2MBi) */
- if (w_bits < SLOT_BASE || w_bits > SLOT_MAX)
- return (ARCHIVE_FAILED);
-
- ds->error = ARCHIVE_FATAL;
-
- /*
- * Alloc window
- */
- w_size = ds->w_size;
- w_slot = slots[w_bits - SLOT_BASE];
- ds->w_size = 1U << w_bits;
- ds->w_mask = ds->w_size -1;
- if (ds->w_buff == NULL || w_size != ds->w_size) {
- free(ds->w_buff);
- ds->w_buff = malloc(ds->w_size);
- if (ds->w_buff == NULL)
- return (ARCHIVE_FATAL);
- free(ds->pos_tbl);
- ds->pos_tbl = malloc(sizeof(ds->pos_tbl[0]) * w_slot);
- if (ds->pos_tbl == NULL)
- return (ARCHIVE_FATAL);
- lzx_huffman_free(&(ds->mt));
- }
-
- for (footer = 0; footer < 18; footer++)
- base_inc[footer] = 1 << footer;
- base = footer = 0;
- for (slot = 0; slot < w_slot; slot++) {
- int n;
- if (footer == 0)
- base = slot;
- else
- base += base_inc[footer];
- if (footer < 17) {
- footer = -2;
- for (n = base; n; n >>= 1)
- footer++;
- if (footer <= 0)
- footer = 0;
- }
- ds->pos_tbl[slot].base = base;
- ds->pos_tbl[slot].footer_bits = footer;
- }
-
- ds->w_pos = 0;
- ds->state = 0;
- ds->br.cache_buffer = 0;
- ds->br.cache_avail = 0;
- ds->r0 = ds->r1 = ds->r2 = 1;
-
- /* Initialize aligned offset tree. */
- if (lzx_huffman_init(&(ds->at), 8, 8) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- /* Initialize pre-tree. */
- if (lzx_huffman_init(&(ds->pt), 20, 10) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- /* Initialize Main tree. */
- if (lzx_huffman_init(&(ds->mt), 256+(w_slot<<3), 16)
- != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- /* Initialize Length tree. */
- if (lzx_huffman_init(&(ds->lt), 249, 16) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- ds->error = 0;
-
- return (ARCHIVE_OK);
-}
-
-/*
- * Release LZX decoder.
- */
-static void
-lzx_decode_free(struct lzx_stream *strm)
-{
-
- if (strm->ds == NULL)
- return;
- free(strm->ds->w_buff);
- free(strm->ds->pos_tbl);
- lzx_huffman_free(&(strm->ds->at));
- lzx_huffman_free(&(strm->ds->pt));
- lzx_huffman_free(&(strm->ds->mt));
- lzx_huffman_free(&(strm->ds->lt));
- free(strm->ds);
- strm->ds = NULL;
-}
-
-/*
- * E8 Call Translation reversal.
- */
-static void
-lzx_translation(struct lzx_stream *strm, void *p, size_t size, uint32_t offset)
-{
- struct lzx_dec *ds = strm->ds;
- unsigned char *b, *end;
-
- if (!ds->translation || size <= 10)
- return;
- b = p;
- end = b + size - 10;
- while (b < end && (b = memchr(b, 0xE8, end - b)) != NULL) {
- size_t i = b - (unsigned char *)p;
- int32_t cp, displacement, value;
-
- cp = (int32_t)(offset + (uint32_t)i);
- value = archive_le32dec(&b[1]);
- if (value >= -cp && value < (int32_t)ds->translation_size) {
- if (value >= 0)
- displacement = value - cp;
- else
- displacement = value + ds->translation_size;
- archive_le32enc(&b[1], (uint32_t)displacement);
- }
- b += 5;
- }
-}
-
-/*
- * Bit stream reader.
- */
-/* Check that the cache buffer has enough bits. */
-#define lzx_br_has(br, n) ((br)->cache_avail >= n)
-/* Get compressed data by bit. */
-#define lzx_br_bits(br, n) \
- (((uint32_t)((br)->cache_buffer >> \
- ((br)->cache_avail - (n)))) & cache_masks[n])
-#define lzx_br_bits_forced(br, n) \
- (((uint32_t)((br)->cache_buffer << \
- ((n) - (br)->cache_avail))) & cache_masks[n])
-/* Read ahead to make sure the cache buffer has enough compressed data we
- * will use.
- * True : completed, there is enough data in the cache buffer.
- * False : we met that strm->next_in is empty, we have to get following
- * bytes. */
-#define lzx_br_read_ahead_0(strm, br, n) \
- (lzx_br_has((br), (n)) || lzx_br_fillup(strm, br))
-/* True : the cache buffer has some bits as much as we need.
- * False : there are no enough bits in the cache buffer to be used,
- * we have to get following bytes if we could. */
-#define lzx_br_read_ahead(strm, br, n) \
- (lzx_br_read_ahead_0((strm), (br), (n)) || lzx_br_has((br), (n)))
-
-/* Notify how many bits we consumed. */
-#define lzx_br_consume(br, n) ((br)->cache_avail -= (n))
-#define lzx_br_consume_unaligned_bits(br) ((br)->cache_avail &= ~0x0f)
-
-#define lzx_br_is_unaligned(br) ((br)->cache_avail & 0x0f)
-
-static const uint32_t cache_masks[] = {
- 0x00000000, 0x00000001, 0x00000003, 0x00000007,
- 0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F,
- 0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF,
- 0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF,
- 0x0000FFFF, 0x0001FFFF, 0x0003FFFF, 0x0007FFFF,
- 0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF,
- 0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF,
- 0x0FFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF,
- 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
-};
-
-/*
- * Shift away used bits in the cache data and fill it up with following bits.
- * Call this when cache buffer does not have enough bits you need.
- *
- * Returns 1 if the cache buffer is full.
- * Returns 0 if the cache buffer is not full; input buffer is empty.
- */
-static int
-lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
-{
-/*
- * x86 proccessor family can read misaligned data without an access error.
- */
- int n = CACHE_BITS - br->cache_avail;
-
- for (;;) {
- switch (n >> 4) {
- case 4:
- if (strm->avail_in >= 8) {
- br->cache_buffer =
- ((uint64_t)strm->next_in[1]) << 56 |
- ((uint64_t)strm->next_in[0]) << 48 |
- ((uint64_t)strm->next_in[3]) << 40 |
- ((uint64_t)strm->next_in[2]) << 32 |
- ((uint32_t)strm->next_in[5]) << 24 |
- ((uint32_t)strm->next_in[4]) << 16 |
- ((uint32_t)strm->next_in[7]) << 8 |
- (uint32_t)strm->next_in[6];
- strm->next_in += 8;
- strm->avail_in -= 8;
- br->cache_avail += 8 * 8;
- return (1);
- }
- break;
- case 3:
- if (strm->avail_in >= 6) {
- br->cache_buffer =
- (br->cache_buffer << 48) |
- ((uint64_t)strm->next_in[1]) << 40 |
- ((uint64_t)strm->next_in[0]) << 32 |
- ((uint32_t)strm->next_in[3]) << 24 |
- ((uint32_t)strm->next_in[2]) << 16 |
- ((uint32_t)strm->next_in[5]) << 8 |
- (uint32_t)strm->next_in[4];
- strm->next_in += 6;
- strm->avail_in -= 6;
- br->cache_avail += 6 * 8;
- return (1);
- }
- break;
- case 0:
- /* We have enough compressed data in
- * the cache buffer.*/
- return (1);
- default:
- break;
- }
- if (strm->avail_in < 2) {
- /* There is not enough compressed data to
- * fill up the cache buffer. */
- if (strm->avail_in == 1) {
- br->odd = *strm->next_in++;
- strm->avail_in--;
- br->have_odd = 1;
- }
- return (0);
- }
- br->cache_buffer =
- (br->cache_buffer << 16) |
- archive_le16dec(strm->next_in);
- strm->next_in += 2;
- strm->avail_in -= 2;
- br->cache_avail += 16;
- n -= 16;
- }
-}
-
-static void
-lzx_br_fixup(struct lzx_stream *strm, struct lzx_br *br)
-{
- int n = CACHE_BITS - br->cache_avail;
-
- if (br->have_odd && n >= 16 && strm->avail_in > 0) {
- br->cache_buffer =
- (br->cache_buffer << 16) |
- ((uint16_t)(*strm->next_in)) << 8 | br->odd;
- strm->next_in++;
- strm->avail_in--;
- br->cache_avail += 16;
- br->have_odd = 0;
- }
-}
-
-static void
-lzx_cleanup_bitstream(struct lzx_stream *strm)
-{
- strm->ds->br.cache_avail = 0;
- strm->ds->br.have_odd = 0;
-}
-
-/*
- * Decode LZX.
- *
- * 1. Returns ARCHIVE_OK if output buffer or input buffer are empty.
- * Please set available buffer and call this function again.
- * 2. Returns ARCHIVE_EOF if decompression has been completed.
- * 3. Returns ARCHIVE_FAILED if an error occurred; compressed data
- * is broken or you do not set 'last' flag properly.
- */
-#define ST_RD_TRANSLATION 0
-#define ST_RD_TRANSLATION_SIZE 1
-#define ST_RD_BLOCK_TYPE 2
-#define ST_RD_BLOCK_SIZE 3
-#define ST_RD_ALIGNMENT 4
-#define ST_RD_R0 5
-#define ST_RD_R1 6
-#define ST_RD_R2 7
-#define ST_COPY_UNCOMP1 8
-#define ST_COPY_UNCOMP2 9
-#define ST_RD_ALIGNED_OFFSET 10
-#define ST_RD_VERBATIM 11
-#define ST_RD_PRE_MAIN_TREE_256 12
-#define ST_MAIN_TREE_256 13
-#define ST_RD_PRE_MAIN_TREE_REM 14
-#define ST_MAIN_TREE_REM 15
-#define ST_RD_PRE_LENGTH_TREE 16
-#define ST_LENGTH_TREE 17
-#define ST_MAIN 18
-#define ST_LENGTH 19
-#define ST_OFFSET 20
-#define ST_REAL_POS 21
-#define ST_COPY 22
-
-static int
-lzx_decode(struct lzx_stream *strm, int last)
-{
- struct lzx_dec *ds = strm->ds;
- int64_t avail_in;
- int r;
-
- if (ds->error)
- return (ds->error);
-
- avail_in = strm->avail_in;
- lzx_br_fixup(strm, &(ds->br));
- do {
- if (ds->state < ST_MAIN)
- r = lzx_read_blocks(strm, last);
- else {
- int64_t bytes_written = strm->avail_out;
- r = lzx_decode_blocks(strm, last);
- bytes_written -= strm->avail_out;
- strm->next_out += bytes_written;
- strm->total_out += bytes_written;
- }
- } while (r == 100);
- strm->total_in += avail_in - strm->avail_in;
- return (r);
-}
-
-static int
-lzx_read_blocks(struct lzx_stream *strm, int last)
-{
- struct lzx_dec *ds = strm->ds;
- struct lzx_br *br = &(ds->br);
- int i, r;
-
- for (;;) {
- switch (ds->state) {
- case ST_RD_TRANSLATION:
- if (!lzx_br_read_ahead(strm, br, 1)) {
- ds->state = ST_RD_TRANSLATION;
- if (last)
- goto failed;
- return (ARCHIVE_OK);
- }
- ds->translation = lzx_br_bits(br, 1);
- lzx_br_consume(br, 1);
- /* FALL THROUGH */
- case ST_RD_TRANSLATION_SIZE:
- if (ds->translation) {
- if (!lzx_br_read_ahead(strm, br, 32)) {
- ds->state = ST_RD_TRANSLATION_SIZE;
- if (last)
- goto failed;
- return (ARCHIVE_OK);
- }
- ds->translation_size = lzx_br_bits(br, 16);
- lzx_br_consume(br, 16);
- ds->translation_size <<= 16;
- ds->translation_size |= lzx_br_bits(br, 16);
- lzx_br_consume(br, 16);
- }
- /* FALL THROUGH */
- case ST_RD_BLOCK_TYPE:
- if (!lzx_br_read_ahead(strm, br, 3)) {
- ds->state = ST_RD_BLOCK_TYPE;
- if (last)
- goto failed;
- return (ARCHIVE_OK);
- }
- ds->block_type = lzx_br_bits(br, 3);
- lzx_br_consume(br, 3);
- /* Check a block type. */
- switch (ds->block_type) {
- case VERBATIM_BLOCK:
- case ALIGNED_OFFSET_BLOCK:
- case UNCOMPRESSED_BLOCK:
- break;
- default:
- goto failed;/* Invalid */
- }
- /* FALL THROUGH */
- case ST_RD_BLOCK_SIZE:
- if (!lzx_br_read_ahead(strm, br, 24)) {
- ds->state = ST_RD_BLOCK_SIZE;
- if (last)
- goto failed;
- return (ARCHIVE_OK);
- }
- ds->block_size = lzx_br_bits(br, 8);
- lzx_br_consume(br, 8);
- ds->block_size <<= 16;
- ds->block_size |= lzx_br_bits(br, 16);
- lzx_br_consume(br, 16);
- if (ds->block_size == 0)
- goto failed;
- ds->block_bytes_avail = ds->block_size;
- if (ds->block_type != UNCOMPRESSED_BLOCK) {
- if (ds->block_type == VERBATIM_BLOCK)
- ds->state = ST_RD_VERBATIM;
- else
- ds->state = ST_RD_ALIGNED_OFFSET;
- break;
- }
- /* FALL THROUGH */
- case ST_RD_ALIGNMENT:
- /*
- * Handle an Uncompressed Block.
- */
- /* Skip padding to align following field on
- * 16-bit boundary. */
- if (lzx_br_is_unaligned(br))
- lzx_br_consume_unaligned_bits(br);
- else {
- if (lzx_br_read_ahead(strm, br, 16))
- lzx_br_consume(br, 16);
- else {
- ds->state = ST_RD_ALIGNMENT;
- if (last)
- goto failed;
- return (ARCHIVE_OK);
- }
- }
- /* Preparation to read repeated offsets R0,R1 and R2. */
- ds->rbytes_avail = 0;
- ds->state = ST_RD_R0;
- /* FALL THROUGH */
- case ST_RD_R0:
- case ST_RD_R1:
- case ST_RD_R2:
- do {
- uint16_t u16;
- /* Drain bits in the cache buffer of
- * bit-stream. */
- if (lzx_br_has(br, 32)) {
- u16 = lzx_br_bits(br, 16);
- lzx_br_consume(br, 16);
- archive_le16enc(ds->rbytes, u16);
- u16 = lzx_br_bits(br, 16);
- lzx_br_consume(br, 16);
- archive_le16enc(ds->rbytes+2, u16);
- ds->rbytes_avail = 4;
- } else if (lzx_br_has(br, 16)) {
- u16 = lzx_br_bits(br, 16);
- lzx_br_consume(br, 16);
- archive_le16enc(ds->rbytes, u16);
- ds->rbytes_avail = 2;
- }
- if (ds->rbytes_avail < 4 && ds->br.have_odd) {
- ds->rbytes[ds->rbytes_avail++] =
- ds->br.odd;
- ds->br.have_odd = 0;
- }
- while (ds->rbytes_avail < 4) {
- if (strm->avail_in <= 0) {
- if (last)
- goto failed;
- return (ARCHIVE_OK);
- }
- ds->rbytes[ds->rbytes_avail++] =
- *strm->next_in++;
- strm->avail_in--;
- }
- ds->rbytes_avail = 0;
- if (ds->state == ST_RD_R0) {
- ds->r0 = archive_le32dec(ds->rbytes);
- if (ds->r0 < 0)
- goto failed;
- ds->state = ST_RD_R1;
- } else if (ds->state == ST_RD_R1) {
- ds->r1 = archive_le32dec(ds->rbytes);
- if (ds->r1 < 0)
- goto failed;
- ds->state = ST_RD_R2;
- } else if (ds->state == ST_RD_R2) {
- ds->r2 = archive_le32dec(ds->rbytes);
- if (ds->r2 < 0)
- goto failed;
- /* We've gotten all repeated offsets. */
- ds->state = ST_COPY_UNCOMP1;
- }
- } while (ds->state != ST_COPY_UNCOMP1);
- /* FALL THROUGH */
- case ST_COPY_UNCOMP1:
- /*
- * Copy bytes form next_in to next_out directly.
- */
- while (ds->block_bytes_avail) {
- int l;
-
- if (strm->avail_out <= 0)
- /* Output buffer is empty. */
- return (ARCHIVE_OK);
- if (strm->avail_in <= 0) {
- /* Input buffer is empty. */
- if (last)
- goto failed;
- return (ARCHIVE_OK);
- }
- l = (int)ds->block_bytes_avail;
- if (l > ds->w_size - ds->w_pos)
- l = ds->w_size - ds->w_pos;
- if (l > strm->avail_out)
- l = (int)strm->avail_out;
- if (l > strm->avail_in)
- l = (int)strm->avail_in;
- memcpy(strm->next_out, strm->next_in, l);
- memcpy(&(ds->w_buff[ds->w_pos]),
- strm->next_in, l);
- strm->next_in += l;
- strm->avail_in -= l;
- strm->next_out += l;
- strm->avail_out -= l;
- strm->total_out += l;
- ds->w_pos = (ds->w_pos + l) & ds->w_mask;
- ds->block_bytes_avail -= l;
- }
- /* FALL THROUGH */
- case ST_COPY_UNCOMP2:
- /* Re-align; skip padding byte. */
- if (ds->block_size & 1) {
- if (strm->avail_in <= 0) {
- /* Input buffer is empty. */
- ds->state = ST_COPY_UNCOMP2;
- if (last)
- goto failed;
- return (ARCHIVE_OK);
- }
- strm->next_in++;
- strm->avail_in --;
- }
- /* This block ended. */
- ds->state = ST_RD_BLOCK_TYPE;
- return (ARCHIVE_EOF);
- /********************/
- case ST_RD_ALIGNED_OFFSET:
- /*
- * Read Aligned offset tree.
- */
- if (!lzx_br_read_ahead(strm, br, 3 * ds->at.len_size)) {
- ds->state = ST_RD_ALIGNED_OFFSET;
- if (last)
- goto failed;
- return (ARCHIVE_OK);
- }
- memset(ds->at.freq, 0, sizeof(ds->at.freq));
- for (i = 0; i < ds->at.len_size; i++) {
- ds->at.bitlen[i] = lzx_br_bits(br, 3);
- ds->at.freq[ds->at.bitlen[i]]++;
- lzx_br_consume(br, 3);
- }
- if (!lzx_make_huffman_table(&ds->at))
- goto failed;
- /* FALL THROUGH */
- case ST_RD_VERBATIM:
- ds->loop = 0;
- /* FALL THROUGH */
- case ST_RD_PRE_MAIN_TREE_256:
- /*
- * Read Pre-tree for first 256 elements of main tree.
- */
- if (!lzx_read_pre_tree(strm)) {
- ds->state = ST_RD_PRE_MAIN_TREE_256;
- if (last)
- goto failed;
- return (ARCHIVE_OK);
- }
- if (!lzx_make_huffman_table(&ds->pt))
- goto failed;
- ds->loop = 0;
- /* FALL THROUGH */
- case ST_MAIN_TREE_256:
- /*
- * Get path lengths of first 256 elements of main tree.
- */
- r = lzx_read_bitlen(strm, &ds->mt, 256);
- if (r < 0)
- goto failed;
- else if (!r) {
- ds->state = ST_MAIN_TREE_256;
- if (last)
- goto failed;
- return (ARCHIVE_OK);
- }
- ds->loop = 0;
- /* FALL THROUGH */
- case ST_RD_PRE_MAIN_TREE_REM:
- /*
- * Read Pre-tree for remaining elements of main tree.
- */
- if (!lzx_read_pre_tree(strm)) {
- ds->state = ST_RD_PRE_MAIN_TREE_REM;
- if (last)
- goto failed;
- return (ARCHIVE_OK);
- }
- if (!lzx_make_huffman_table(&ds->pt))
- goto failed;
- ds->loop = 256;
- /* FALL THROUGH */
- case ST_MAIN_TREE_REM:
- /*
- * Get path lengths of remaining elements of main tree.
- */
- r = lzx_read_bitlen(strm, &ds->mt, -1);
- if (r < 0)
- goto failed;
- else if (!r) {
- ds->state = ST_MAIN_TREE_REM;
- if (last)
- goto failed;
- return (ARCHIVE_OK);
- }
- if (!lzx_make_huffman_table(&ds->mt))
- goto failed;
- ds->loop = 0;
- /* FALL THROUGH */
- case ST_RD_PRE_LENGTH_TREE:
- /*
- * Read Pre-tree for remaining elements of main tree.
- */
- if (!lzx_read_pre_tree(strm)) {
- ds->state = ST_RD_PRE_LENGTH_TREE;
- if (last)
- goto failed;
- return (ARCHIVE_OK);
- }
- if (!lzx_make_huffman_table(&ds->pt))
- goto failed;
- ds->loop = 0;
- /* FALL THROUGH */
- case ST_LENGTH_TREE:
- /*
- * Get path lengths of remaining elements of main tree.
- */
- r = lzx_read_bitlen(strm, &ds->lt, -1);
- if (r < 0)
- goto failed;
- else if (!r) {
- ds->state = ST_LENGTH_TREE;
- if (last)
- goto failed;
- return (ARCHIVE_OK);
- }
- if (!lzx_make_huffman_table(&ds->lt))
- goto failed;
- ds->state = ST_MAIN;
- return (100);
- }
- }
-failed:
- return (ds->error = ARCHIVE_FAILED);
-}
-
-static int
-lzx_decode_blocks(struct lzx_stream *strm, int last)
-{
- struct lzx_dec *ds = strm->ds;
- struct lzx_br bre = ds->br;
- struct huffman *at = &(ds->at), *lt = &(ds->lt), *mt = &(ds->mt);
- const struct lzx_pos_tbl *pos_tbl = ds->pos_tbl;
- unsigned char *noutp = strm->next_out;
- unsigned char *endp = noutp + strm->avail_out;
- unsigned char *w_buff = ds->w_buff;
- unsigned char *at_bitlen = at->bitlen;
- unsigned char *lt_bitlen = lt->bitlen;
- unsigned char *mt_bitlen = mt->bitlen;
- size_t block_bytes_avail = ds->block_bytes_avail;
- int at_max_bits = at->max_bits;
- int lt_max_bits = lt->max_bits;
- int mt_max_bits = mt->max_bits;
- int c, copy_len = ds->copy_len, copy_pos = ds->copy_pos;
- int w_pos = ds->w_pos, w_mask = ds->w_mask, w_size = ds->w_size;
- int length_header = ds->length_header;
- int offset_bits = ds->offset_bits;
- int position_slot = ds->position_slot;
- int r0 = ds->r0, r1 = ds->r1, r2 = ds->r2;
- int state = ds->state;
- char block_type = ds->block_type;
-
- for (;;) {
- switch (state) {
- case ST_MAIN:
- for (;;) {
- if (block_bytes_avail == 0) {
- /* This block ended. */
- ds->state = ST_RD_BLOCK_TYPE;
- ds->br = bre;
- ds->block_bytes_avail =
- block_bytes_avail;
- ds->copy_len = copy_len;
- ds->copy_pos = copy_pos;
- ds->length_header = length_header;
- ds->position_slot = position_slot;
- ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
- ds->w_pos = w_pos;
- strm->avail_out = endp - noutp;
- return (ARCHIVE_EOF);
- }
- if (noutp >= endp)
- /* Output buffer is empty. */
- goto next_data;
-
- if (!lzx_br_read_ahead(strm, &bre,
- mt_max_bits)) {
- if (!last)
- goto next_data;
- /* Remaining bits are less than
- * maximum bits(mt.max_bits) but maybe
- * it still remains as much as we need,
- * so we should try to use it with
- * dummy bits. */
- c = lzx_decode_huffman(mt,
- lzx_br_bits_forced(
- &bre, mt_max_bits));
- lzx_br_consume(&bre, mt_bitlen[c]);
- if (!lzx_br_has(&bre, 0))
- goto failed;/* Over read. */
- } else {
- c = lzx_decode_huffman(mt,
- lzx_br_bits(&bre, mt_max_bits));
- lzx_br_consume(&bre, mt_bitlen[c]);
- }
- if (c > UCHAR_MAX)
- break;
- /*
- * 'c' is exactly literal code.
- */
- /* Save a decoded code to reference it
- * afterward. */
- w_buff[w_pos] = c;
- w_pos = (w_pos + 1) & w_mask;
- /* Store the decoded code to output buffer. */
- *noutp++ = c;
- block_bytes_avail--;
- }
- /*
- * Get a match code, its length and offset.
- */
- c -= UCHAR_MAX + 1;
- length_header = c & 7;
- position_slot = c >> 3;
- /* FALL THROUGH */
- case ST_LENGTH:
- /*
- * Get a length.
- */
- if (length_header == 7) {
- if (!lzx_br_read_ahead(strm, &bre,
- lt_max_bits)) {
- if (!last) {
- state = ST_LENGTH;
- goto next_data;
- }
- c = lzx_decode_huffman(lt,
- lzx_br_bits_forced(
- &bre, lt_max_bits));
- lzx_br_consume(&bre, lt_bitlen[c]);
- if (!lzx_br_has(&bre, 0))
- goto failed;/* Over read. */
- } else {
- c = lzx_decode_huffman(lt,
- lzx_br_bits(&bre, lt_max_bits));
- lzx_br_consume(&bre, lt_bitlen[c]);
- }
- copy_len = c + 7 + 2;
- } else
- copy_len = length_header + 2;
- if ((size_t)copy_len > block_bytes_avail)
- goto failed;
- /*
- * Get an offset.
- */
- switch (position_slot) {
- case 0: /* Use repeated offset 0. */
- copy_pos = r0;
- state = ST_REAL_POS;
- continue;
- case 1: /* Use repeated offset 1. */
- copy_pos = r1;
- /* Swap repeated offset. */
- r1 = r0;
- r0 = copy_pos;
- state = ST_REAL_POS;
- continue;
- case 2: /* Use repeated offset 2. */
- copy_pos = r2;
- /* Swap repeated offset. */
- r2 = r0;
- r0 = copy_pos;
- state = ST_REAL_POS;
- continue;
- default:
- offset_bits =
- pos_tbl[position_slot].footer_bits;
- break;
- }
- /* FALL THROUGH */
- case ST_OFFSET:
- /*
- * Get the offset, which is a distance from
- * current window position.
- */
- if (block_type == ALIGNED_OFFSET_BLOCK &&
- offset_bits >= 3) {
- int offbits = offset_bits - 3;
-
- if (!lzx_br_read_ahead(strm, &bre, offbits)) {
- state = ST_OFFSET;
- if (last)
- goto failed;
- goto next_data;
- }
- copy_pos = lzx_br_bits(&bre, offbits) << 3;
-
- /* Get an aligned number. */
- if (!lzx_br_read_ahead(strm, &bre,
- offbits + at_max_bits)) {
- if (!last) {
- state = ST_OFFSET;
- goto next_data;
- }
- lzx_br_consume(&bre, offbits);
- c = lzx_decode_huffman(at,
- lzx_br_bits_forced(&bre,
- at_max_bits));
- lzx_br_consume(&bre, at_bitlen[c]);
- if (!lzx_br_has(&bre, 0))
- goto failed;/* Over read. */
- } else {
- lzx_br_consume(&bre, offbits);
- c = lzx_decode_huffman(at,
- lzx_br_bits(&bre, at_max_bits));
- lzx_br_consume(&bre, at_bitlen[c]);
- }
- /* Add an aligned number. */
- copy_pos += c;
- } else {
- if (!lzx_br_read_ahead(strm, &bre,
- offset_bits)) {
- state = ST_OFFSET;
- if (last)
- goto failed;
- goto next_data;
- }
- copy_pos = lzx_br_bits(&bre, offset_bits);
- lzx_br_consume(&bre, offset_bits);
- }
- copy_pos += pos_tbl[position_slot].base -2;
-
- /* Update repeated offset LRU queue. */
- r2 = r1;
- r1 = r0;
- r0 = copy_pos;
- /* FALL THROUGH */
- case ST_REAL_POS:
- /*
- * Compute a real position in window.
- */
- copy_pos = (w_pos - copy_pos) & w_mask;
- /* FALL THROUGH */
- case ST_COPY:
- /*
- * Copy several bytes as extracted data from the window
- * into the output buffer.
- */
- for (;;) {
- const unsigned char *s;
- int l;
-
- l = copy_len;
- if (copy_pos > w_pos) {
- if (l > w_size - copy_pos)
- l = w_size - copy_pos;
- } else {
- if (l > w_size - w_pos)
- l = w_size - w_pos;
- }
- if (noutp + l >= endp)
- l = (int)(endp - noutp);
- s = w_buff + copy_pos;
- if (l >= 8 && ((copy_pos + l < w_pos)
- || (w_pos + l < copy_pos))) {
- memcpy(w_buff + w_pos, s, l);
- memcpy(noutp, s, l);
- } else {
- unsigned char *d;
- int li;
-
- d = w_buff + w_pos;
- for (li = 0; li < l; li++)
- noutp[li] = d[li] = s[li];
- }
- noutp += l;
- copy_pos = (copy_pos + l) & w_mask;
- w_pos = (w_pos + l) & w_mask;
- block_bytes_avail -= l;
- if (copy_len <= l)
- /* A copy of current pattern ended. */
- break;
- copy_len -= l;
- if (noutp >= endp) {
- /* Output buffer is empty. */
- state = ST_COPY;
- goto next_data;
- }
- }
- state = ST_MAIN;
- break;
- }
- }
-failed:
- return (ds->error = ARCHIVE_FAILED);
-next_data:
- ds->br = bre;
- ds->block_bytes_avail = block_bytes_avail;
- ds->copy_len = copy_len;
- ds->copy_pos = copy_pos;
- ds->length_header = length_header;
- ds->offset_bits = offset_bits;
- ds->position_slot = position_slot;
- ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
- ds->state = state;
- ds->w_pos = w_pos;
- strm->avail_out = endp - noutp;
- return (ARCHIVE_OK);
-}
-
-static int
-lzx_read_pre_tree(struct lzx_stream *strm)
-{
- struct lzx_dec *ds = strm->ds;
- struct lzx_br *br = &(ds->br);
- int i;
-
- if (ds->loop == 0)
- memset(ds->pt.freq, 0, sizeof(ds->pt.freq));
- for (i = ds->loop; i < ds->pt.len_size; i++) {
- if (!lzx_br_read_ahead(strm, br, 4)) {
- ds->loop = i;
- return (0);
- }
- ds->pt.bitlen[i] = lzx_br_bits(br, 4);
- ds->pt.freq[ds->pt.bitlen[i]]++;
- lzx_br_consume(br, 4);
- }
- ds->loop = i;
- return (1);
-}
-
-/*
- * Read a bunch of bit-lengths from pre-tree.
- */
-static int
-lzx_read_bitlen(struct lzx_stream *strm, struct huffman *d, int end)
-{
- struct lzx_dec *ds = strm->ds;
- struct lzx_br *br = &(ds->br);
- int c, i, j, ret, same;
- unsigned rbits;
-
- i = ds->loop;
- if (i == 0)
- memset(d->freq, 0, sizeof(d->freq));
- ret = 0;
- if (end < 0)
- end = d->len_size;
- while (i < end) {
- ds->loop = i;
- if (!lzx_br_read_ahead(strm, br, ds->pt.max_bits))
- goto getdata;
- rbits = lzx_br_bits(br, ds->pt.max_bits);
- c = lzx_decode_huffman(&(ds->pt), rbits);
- switch (c) {
- case 17:/* several zero lengths, from 4 to 19. */
- if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+4))
- goto getdata;
- lzx_br_consume(br, ds->pt.bitlen[c]);
- same = lzx_br_bits(br, 4) + 4;
- if (i + same > end)
- return (-1);/* Invalid */
- lzx_br_consume(br, 4);
- for (j = 0; j < same; j++)
- d->bitlen[i++] = 0;
- break;
- case 18:/* many zero lengths, from 20 to 51. */
- if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+5))
- goto getdata;
- lzx_br_consume(br, ds->pt.bitlen[c]);
- same = lzx_br_bits(br, 5) + 20;
- if (i + same > end)
- return (-1);/* Invalid */
- lzx_br_consume(br, 5);
- memset(d->bitlen + i, 0, same);
- i += same;
- break;
- case 19:/* a few same lengths. */
- if (!lzx_br_read_ahead(strm, br,
- ds->pt.bitlen[c]+1+ds->pt.max_bits))
- goto getdata;
- lzx_br_consume(br, ds->pt.bitlen[c]);
- same = lzx_br_bits(br, 1) + 4;
- if (i + same > end)
- return (-1);
- lzx_br_consume(br, 1);
- rbits = lzx_br_bits(br, ds->pt.max_bits);
- c = lzx_decode_huffman(&(ds->pt), rbits);
- lzx_br_consume(br, ds->pt.bitlen[c]);
- c = (d->bitlen[i] - c + 17) % 17;
- if (c < 0)
- return (-1);/* Invalid */
- for (j = 0; j < same; j++)
- d->bitlen[i++] = c;
- d->freq[c] += same;
- break;
- default:
- lzx_br_consume(br, ds->pt.bitlen[c]);
- c = (d->bitlen[i] - c + 17) % 17;
- if (c < 0)
- return (-1);/* Invalid */
- d->freq[c]++;
- d->bitlen[i++] = c;
- break;
- }
- }
- ret = 1;
-getdata:
- ds->loop = i;
- return (ret);
-}
-
-static int
-lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
-{
- int bits;
-
- if (hf->bitlen == NULL || hf->len_size != (int)len_size) {
- free(hf->bitlen);
- hf->bitlen = calloc(len_size, sizeof(hf->bitlen[0]));
- if (hf->bitlen == NULL)
- return (ARCHIVE_FATAL);
- hf->len_size = (int)len_size;
- } else
- memset(hf->bitlen, 0, len_size * sizeof(hf->bitlen[0]));
- if (hf->tbl == NULL) {
- if (tbl_bits < HTBL_BITS)
- bits = tbl_bits;
- else
- bits = HTBL_BITS;
- hf->tbl = malloc(((size_t)1 << bits) * sizeof(hf->tbl[0]));
- if (hf->tbl == NULL)
- return (ARCHIVE_FATAL);
- hf->tbl_bits = tbl_bits;
- }
- if (hf->tree == NULL && tbl_bits > HTBL_BITS) {
- hf->tree_avail = 1 << (tbl_bits - HTBL_BITS + 4);
- hf->tree = malloc(hf->tree_avail * sizeof(hf->tree[0]));
- if (hf->tree == NULL)
- return (ARCHIVE_FATAL);
- }
- return (ARCHIVE_OK);
-}
-
-static void
-lzx_huffman_free(struct huffman *hf)
-{
- free(hf->bitlen);
- free(hf->tbl);
- free(hf->tree);
-}
-
-/*
- * Make a huffman coding table.
- */
-static int
-lzx_make_huffman_table(struct huffman *hf)
-{
- uint16_t *tbl;
- const unsigned char *bitlen;
- int bitptn[17], weight[17];
- int i, maxbits = 0, ptn, tbl_size, w;
- int diffbits, len_avail;
-
- /*
- * Initialize bit patterns.
- */
- ptn = 0;
- for (i = 1, w = 1 << 15; i <= 16; i++, w >>= 1) {
- bitptn[i] = ptn;
- weight[i] = w;
- if (hf->freq[i]) {
- ptn += hf->freq[i] * w;
- maxbits = i;
- }
- }
- if ((ptn & 0xffff) != 0 || maxbits > hf->tbl_bits)
- return (0);/* Invalid */
-
- hf->max_bits = maxbits;
-
- /*
- * Cut out extra bits which we won't house in the table.
- * This preparation reduces the same calculation in the for-loop
- * making the table.
- */
- if (maxbits < 16) {
- int ebits = 16 - maxbits;
- for (i = 1; i <= maxbits; i++) {
- bitptn[i] >>= ebits;
- weight[i] >>= ebits;
- }
- }
- if (maxbits > HTBL_BITS) {
- int htbl_max;
- uint16_t *p;
-
- diffbits = maxbits - HTBL_BITS;
- for (i = 1; i <= HTBL_BITS; i++) {
- bitptn[i] >>= diffbits;
- weight[i] >>= diffbits;
- }
- htbl_max = bitptn[HTBL_BITS] +
- weight[HTBL_BITS] * hf->freq[HTBL_BITS];
- p = &(hf->tbl[htbl_max]);
- while (p < &hf->tbl[1U<<HTBL_BITS])
- *p++ = 0;
- } else
- diffbits = 0;
- hf->shift_bits = diffbits;
-
- /*
- * Make the table.
- */
- tbl_size = 1 << HTBL_BITS;
- tbl = hf->tbl;
- bitlen = hf->bitlen;
- len_avail = hf->len_size;
- hf->tree_used = 0;
- for (i = 0; i < len_avail; i++) {
- uint16_t *p;
- int len, cnt;
- uint16_t bit;
- int extlen;
- struct htree_t *ht;
-
- if (bitlen[i] == 0)
- continue;
- /* Get a bit pattern */
- len = bitlen[i];
- ptn = bitptn[len];
- cnt = weight[len];
- if (len <= HTBL_BITS) {
- /* Calculate next bit pattern */
- if ((bitptn[len] = ptn + cnt) > tbl_size)
- return (0);/* Invalid */
- /* Update the table */
- p = &(tbl[ptn]);
- while (--cnt >= 0)
- p[cnt] = (uint16_t)i;
- continue;
- }
-
- /*
- * A bit length is too big to be housed to a direct table,
- * so we use a tree model for its extra bits.
- */
- bitptn[len] = ptn + cnt;
- bit = 1U << (diffbits -1);
- extlen = len - HTBL_BITS;
-
- p = &(tbl[ptn >> diffbits]);
- if (*p == 0) {
- *p = len_avail + hf->tree_used;
- ht = &(hf->tree[hf->tree_used++]);
- if (hf->tree_used > hf->tree_avail)
- return (0);/* Invalid */
- ht->left = 0;
- ht->right = 0;
- } else {
- if (*p < len_avail ||
- *p >= (len_avail + hf->tree_used))
- return (0);/* Invalid */
- ht = &(hf->tree[*p - len_avail]);
- }
- while (--extlen > 0) {
- if (ptn & bit) {
- if (ht->left < len_avail) {
- ht->left = len_avail + hf->tree_used;
- ht = &(hf->tree[hf->tree_used++]);
- if (hf->tree_used > hf->tree_avail)
- return (0);/* Invalid */
- ht->left = 0;
- ht->right = 0;
- } else {
- ht = &(hf->tree[ht->left - len_avail]);
- }
- } else {
- if (ht->right < len_avail) {
- ht->right = len_avail + hf->tree_used;
- ht = &(hf->tree[hf->tree_used++]);
- if (hf->tree_used > hf->tree_avail)
- return (0);/* Invalid */
- ht->left = 0;
- ht->right = 0;
- } else {
- ht = &(hf->tree[ht->right - len_avail]);
- }
- }
- bit >>= 1;
- }
- if (ptn & bit) {
- if (ht->left != 0)
- return (0);/* Invalid */
- ht->left = (uint16_t)i;
- } else {
- if (ht->right != 0)
- return (0);/* Invalid */
- ht->right = (uint16_t)i;
- }
- }
- return (1);
-}
-
-static int
-lzx_decode_huffman_tree(struct huffman *hf, unsigned rbits, int c)
-{
- struct htree_t *ht;
- int extlen;
-
- ht = hf->tree;
- extlen = hf->shift_bits;
- while (c >= hf->len_size) {
- c -= hf->len_size;
- if (extlen-- <= 0 || c >= hf->tree_used)
- return (0);
- if (rbits & (1U << extlen))
- c = ht[c].left;
- else
- c = ht[c].right;
- }
- return (c);
-}
-
-static inline int
-lzx_decode_huffman(struct huffman *hf, unsigned rbits)
-{
- int c;
- /*
- * At first search an index table for a bit pattern.
- * If it fails, search a huffman tree for.
- */
- c = hf->tbl[rbits >> hf->shift_bits];
- if (c < hf->len_size)
- return (c);
- /* This bit pattern needs to be found out at a huffman tree. */
- return (lzx_decode_huffman_tree(hf, rbits, c));
-}
-
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_format_cpio.c b/3rdparty/libarchive/libarchive/archive_read_support_format_cpio.c
deleted file mode 100644
index 819f4a4f..00000000
--- a/3rdparty/libarchive/libarchive/archive_read_support_format_cpio.c
+++ /dev/null
@@ -1,1066 +0,0 @@
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * Copyright (c) 2010-2012 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"
-__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_cpio.c 201163 2009-12-29 05:50:34Z kientzle $");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-/* #include <stdint.h> */ /* See archive_platform.h */
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#include "archive.h"
-#include "archive_entry.h"
-#include "archive_entry_locale.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-
-#define bin_magic_offset 0
-#define bin_magic_size 2
-#define bin_dev_offset 2
-#define bin_dev_size 2
-#define bin_ino_offset 4
-#define bin_ino_size 2
-#define bin_mode_offset 6
-#define bin_mode_size 2
-#define bin_uid_offset 8
-#define bin_uid_size 2
-#define bin_gid_offset 10
-#define bin_gid_size 2
-#define bin_nlink_offset 12
-#define bin_nlink_size 2
-#define bin_rdev_offset 14
-#define bin_rdev_size 2
-#define bin_mtime_offset 16
-#define bin_mtime_size 4
-#define bin_namesize_offset 20
-#define bin_namesize_size 2
-#define bin_filesize_offset 22
-#define bin_filesize_size 4
-#define bin_header_size 26
-
-#define odc_magic_offset 0
-#define odc_magic_size 6
-#define odc_dev_offset 6
-#define odc_dev_size 6
-#define odc_ino_offset 12
-#define odc_ino_size 6
-#define odc_mode_offset 18
-#define odc_mode_size 6
-#define odc_uid_offset 24
-#define odc_uid_size 6
-#define odc_gid_offset 30
-#define odc_gid_size 6
-#define odc_nlink_offset 36
-#define odc_nlink_size 6
-#define odc_rdev_offset 42
-#define odc_rdev_size 6
-#define odc_mtime_offset 48
-#define odc_mtime_size 11
-#define odc_namesize_offset 59
-#define odc_namesize_size 6
-#define odc_filesize_offset 65
-#define odc_filesize_size 11
-#define odc_header_size 76
-
-#define newc_magic_offset 0
-#define newc_magic_size 6
-#define newc_ino_offset 6
-#define newc_ino_size 8
-#define newc_mode_offset 14
-#define newc_mode_size 8
-#define newc_uid_offset 22
-#define newc_uid_size 8
-#define newc_gid_offset 30
-#define newc_gid_size 8
-#define newc_nlink_offset 38
-#define newc_nlink_size 8
-#define newc_mtime_offset 46
-#define newc_mtime_size 8
-#define newc_filesize_offset 54
-#define newc_filesize_size 8
-#define newc_devmajor_offset 62
-#define newc_devmajor_size 8
-#define newc_devminor_offset 70
-#define newc_devminor_size 8
-#define newc_rdevmajor_offset 78
-#define newc_rdevmajor_size 8
-#define newc_rdevminor_offset 86
-#define newc_rdevminor_size 8
-#define newc_namesize_offset 94
-#define newc_namesize_size 8
-#define newc_checksum_offset 102
-#define newc_checksum_size 8
-#define newc_header_size 110
-
-/*
- * An afio large ASCII header, which they named itself.
- * afio utility uses this header, if a file size is larger than 2G bytes
- * or inode/uid/gid is bigger than 65535(0xFFFF) or mtime is bigger than
- * 0x7fffffff, which we cannot record to odc header because of its limit.
- * If not, uses odc header.
- */
-#define afiol_magic_offset 0
-#define afiol_magic_size 6
-#define afiol_dev_offset 6
-#define afiol_dev_size 8 /* hex */
-#define afiol_ino_offset 14
-#define afiol_ino_size 16 /* hex */
-#define afiol_ino_m_offset 30 /* 'm' */
-#define afiol_mode_offset 31
-#define afiol_mode_size 6 /* oct */
-#define afiol_uid_offset 37
-#define afiol_uid_size 8 /* hex */
-#define afiol_gid_offset 45
-#define afiol_gid_size 8 /* hex */
-#define afiol_nlink_offset 53
-#define afiol_nlink_size 8 /* hex */
-#define afiol_rdev_offset 61
-#define afiol_rdev_size 8 /* hex */
-#define afiol_mtime_offset 69
-#define afiol_mtime_size 16 /* hex */
-#define afiol_mtime_n_offset 85 /* 'n' */
-#define afiol_namesize_offset 86
-#define afiol_namesize_size 4 /* hex */
-#define afiol_flag_offset 90
-#define afiol_flag_size 4 /* hex */
-#define afiol_xsize_offset 94
-#define afiol_xsize_size 4 /* hex */
-#define afiol_xsize_s_offset 98 /* 's' */
-#define afiol_filesize_offset 99
-#define afiol_filesize_size 16 /* hex */
-#define afiol_filesize_c_offset 115 /* ':' */
-#define afiol_header_size 116
-
-
-struct links_entry {
- struct links_entry *next;
- struct links_entry *previous;
- int links;
- dev_t dev;
- int64_t ino;
- char *name;
-};
-
-#define CPIO_MAGIC 0x13141516
-struct cpio {
- int magic;
- int (*read_header)(struct archive_read *, struct cpio *,
- struct archive_entry *, size_t *, size_t *);
- struct links_entry *links_head;
- int64_t entry_bytes_remaining;
- int64_t entry_bytes_unconsumed;
- int64_t entry_offset;
- int64_t entry_padding;
-
- struct archive_string_conv *opt_sconv;
- struct archive_string_conv *sconv_default;
- int init_default_conversion;
-};
-
-static int64_t atol16(const char *, unsigned);
-static int64_t atol8(const char *, unsigned);
-static int archive_read_format_cpio_bid(struct archive_read *, int);
-static int archive_read_format_cpio_options(struct archive_read *,
- const char *, const char *);
-static int archive_read_format_cpio_cleanup(struct archive_read *);
-static int archive_read_format_cpio_read_data(struct archive_read *,
- const void **, size_t *, int64_t *);
-static int archive_read_format_cpio_read_header(struct archive_read *,
- struct archive_entry *);
-static int archive_read_format_cpio_skip(struct archive_read *);
-static int be4(const unsigned char *);
-static int find_odc_header(struct archive_read *);
-static int find_newc_header(struct archive_read *);
-static int header_bin_be(struct archive_read *, struct cpio *,
- struct archive_entry *, size_t *, size_t *);
-static int header_bin_le(struct archive_read *, struct cpio *,
- struct archive_entry *, size_t *, size_t *);
-static int header_newc(struct archive_read *, struct cpio *,
- struct archive_entry *, size_t *, size_t *);
-static int header_odc(struct archive_read *, struct cpio *,
- struct archive_entry *, size_t *, size_t *);
-static int header_afiol(struct archive_read *, struct cpio *,
- struct archive_entry *, size_t *, size_t *);
-static int is_octal(const char *, size_t);
-static int is_hex(const char *, size_t);
-static int le4(const unsigned char *);
-static int record_hardlink(struct archive_read *a,
- struct cpio *cpio, struct archive_entry *entry);
-
-int
-archive_read_support_format_cpio(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct cpio *cpio;
- int r;
-
- archive_check_magic(_a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_NEW, "archive_read_support_format_cpio");
-
- cpio = (struct cpio *)calloc(1, sizeof(*cpio));
- if (cpio == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");
- return (ARCHIVE_FATAL);
- }
- cpio->magic = CPIO_MAGIC;
-
- r = __archive_read_register_format(a,
- cpio,
- "cpio",
- archive_read_format_cpio_bid,
- archive_read_format_cpio_options,
- archive_read_format_cpio_read_header,
- archive_read_format_cpio_read_data,
- archive_read_format_cpio_skip,
- NULL,
- archive_read_format_cpio_cleanup);
-
- if (r != ARCHIVE_OK)
- free(cpio);
- return (ARCHIVE_OK);
-}
-
-
-static int
-archive_read_format_cpio_bid(struct archive_read *a, int best_bid)
-{
- const unsigned char *p;
- struct cpio *cpio;
- int bid;
-
- (void)best_bid; /* UNUSED */
-
- cpio = (struct cpio *)(a->format->data);
-
- if ((p = __archive_read_ahead(a, 6, NULL)) == NULL)
- return (-1);
-
- bid = 0;
- if (memcmp(p, "070707", 6) == 0) {
- /* ASCII cpio archive (odc, POSIX.1) */
- cpio->read_header = header_odc;
- bid += 48;
- /*
- * XXX TODO: More verification; Could check that only octal
- * digits appear in appropriate header locations. XXX
- */
- } else if (memcmp(p, "070727", 6) == 0) {
- /* afio large ASCII cpio archive */
- cpio->read_header = header_odc;
- bid += 48;
- /*
- * XXX TODO: More verification; Could check that almost hex
- * digits appear in appropriate header locations. XXX
- */
- } else if (memcmp(p, "070701", 6) == 0) {
- /* ASCII cpio archive (SVR4 without CRC) */
- cpio->read_header = header_newc;
- bid += 48;
- /*
- * XXX TODO: More verification; Could check that only hex
- * digits appear in appropriate header locations. XXX
- */
- } else if (memcmp(p, "070702", 6) == 0) {
- /* ASCII cpio archive (SVR4 with CRC) */
- /* XXX TODO: Flag that we should check the CRC. XXX */
- cpio->read_header = header_newc;
- bid += 48;
- /*
- * XXX TODO: More verification; Could check that only hex
- * digits appear in appropriate header locations. XXX
- */
- } else if (p[0] * 256 + p[1] == 070707) {
- /* big-endian binary cpio archives */
- cpio->read_header = header_bin_be;
- bid += 16;
- /* Is more verification possible here? */
- } else if (p[0] + p[1] * 256 == 070707) {
- /* little-endian binary cpio archives */
- cpio->read_header = header_bin_le;
- bid += 16;
- /* Is more verification possible here? */
- } else
- return (ARCHIVE_WARN);
-
- return (bid);
-}
-
-static int
-archive_read_format_cpio_options(struct archive_read *a,
- const char *key, const char *val)
-{
- struct cpio *cpio;
- int ret = ARCHIVE_FAILED;
-
- cpio = (struct cpio *)(a->format->data);
- if (strcmp(key, "compat-2x") == 0) {
- /* Handle filnames as libarchive 2.x */
- cpio->init_default_conversion = (val != NULL)?1:0;
- return (ARCHIVE_OK);
- } else if (strcmp(key, "hdrcharset") == 0) {
- if (val == NULL || val[0] == 0)
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "cpio: hdrcharset option needs a character-set name");
- else {
- cpio->opt_sconv =
- archive_string_conversion_from_charset(
- &a->archive, val, 0);
- if (cpio->opt_sconv != NULL)
- ret = ARCHIVE_OK;
- else
- ret = ARCHIVE_FATAL;
- }
- return (ret);
- }
-
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
-}
-
-static int
-archive_read_format_cpio_read_header(struct archive_read *a,
- struct archive_entry *entry)
-{
- struct cpio *cpio;
- const void *h;
- struct archive_string_conv *sconv;
- size_t namelength;
- size_t name_pad;
- int r;
-
- cpio = (struct cpio *)(a->format->data);
- sconv = cpio->opt_sconv;
- if (sconv == NULL) {
- if (!cpio->init_default_conversion) {
- cpio->sconv_default =
- archive_string_default_conversion_for_read(
- &(a->archive));
- cpio->init_default_conversion = 1;
- }
- sconv = cpio->sconv_default;
- }
-
- r = (cpio->read_header(a, cpio, entry, &namelength, &name_pad));
-
- if (r < ARCHIVE_WARN)
- return (r);
-
- /* Read name from buffer. */
- h = __archive_read_ahead(a, namelength + name_pad, NULL);
- if (h == NULL)
- return (ARCHIVE_FATAL);
- if (archive_entry_copy_pathname_l(entry,
- (const char *)h, namelength, sconv) != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Pathname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Pathname can't be converted from %s to current locale.",
- archive_string_conversion_charset_name(sconv));
- r = ARCHIVE_WARN;
- }
- cpio->entry_offset = 0;
-
- __archive_read_consume(a, namelength + name_pad);
-
- /* If this is a symlink, read the link contents. */
- if (archive_entry_filetype(entry) == AE_IFLNK) {
- h = __archive_read_ahead(a,
- (size_t)cpio->entry_bytes_remaining, NULL);
- if (h == NULL)
- return (ARCHIVE_FATAL);
- if (archive_entry_copy_symlink_l(entry, (const char *)h,
- (size_t)cpio->entry_bytes_remaining, sconv) != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Linkname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Linkname can't be converted from %s to "
- "current locale.",
- archive_string_conversion_charset_name(sconv));
- r = ARCHIVE_WARN;
- }
- __archive_read_consume(a, cpio->entry_bytes_remaining);
- cpio->entry_bytes_remaining = 0;
- }
-
- /* XXX TODO: If the full mode is 0160200, then this is a Solaris
- * ACL description for the following entry. Read this body
- * and parse it as a Solaris-style ACL, then read the next
- * header. XXX */
-
- /* Compare name to "TRAILER!!!" to test for end-of-archive. */
- if (namelength == 11 && strcmp((const char *)h, "TRAILER!!!") == 0) {
- /* TODO: Store file location of start of block. */
- archive_clear_error(&a->archive);
- return (ARCHIVE_EOF);
- }
-
- /* Detect and record hardlinks to previously-extracted entries. */
- if (record_hardlink(a, cpio, entry) != ARCHIVE_OK) {
- return (ARCHIVE_FATAL);
- }
-
- return (r);
-}
-
-static int
-archive_read_format_cpio_read_data(struct archive_read *a,
- const void **buff, size_t *size, int64_t *offset)
-{
- ssize_t bytes_read;
- struct cpio *cpio;
-
- cpio = (struct cpio *)(a->format->data);
-
- if (cpio->entry_bytes_unconsumed) {
- __archive_read_consume(a, cpio->entry_bytes_unconsumed);
- cpio->entry_bytes_unconsumed = 0;
- }
-
- if (cpio->entry_bytes_remaining > 0) {
- *buff = __archive_read_ahead(a, 1, &bytes_read);
- if (bytes_read <= 0)
- return (ARCHIVE_FATAL);
- if (bytes_read > cpio->entry_bytes_remaining)
- bytes_read = (ssize_t)cpio->entry_bytes_remaining;
- *size = bytes_read;
- cpio->entry_bytes_unconsumed = bytes_read;
- *offset = cpio->entry_offset;
- cpio->entry_offset += bytes_read;
- cpio->entry_bytes_remaining -= bytes_read;
- return (ARCHIVE_OK);
- } else {
- if (cpio->entry_padding !=
- __archive_read_consume(a, cpio->entry_padding)) {
- return (ARCHIVE_FATAL);
- }
- cpio->entry_padding = 0;
- *buff = NULL;
- *size = 0;
- *offset = cpio->entry_offset;
- return (ARCHIVE_EOF);
- }
-}
-
-static int
-archive_read_format_cpio_skip(struct archive_read *a)
-{
- struct cpio *cpio = (struct cpio *)(a->format->data);
- int64_t to_skip = cpio->entry_bytes_remaining + cpio->entry_padding +
- cpio->entry_bytes_unconsumed;
-
- if (to_skip != __archive_read_consume(a, to_skip)) {
- return (ARCHIVE_FATAL);
- }
- cpio->entry_bytes_remaining = 0;
- cpio->entry_padding = 0;
- cpio->entry_bytes_unconsumed = 0;
- return (ARCHIVE_OK);
-}
-
-/*
- * Skip forward to the next cpio newc header by searching for the
- * 07070[12] string. This should be generalized and merged with
- * find_odc_header below.
- */
-static int
-is_hex(const char *p, size_t len)
-{
- while (len-- > 0) {
- if ((*p >= '0' && *p <= '9')
- || (*p >= 'a' && *p <= 'f')
- || (*p >= 'A' && *p <= 'F'))
- ++p;
- else
- return (0);
- }
- return (1);
-}
-
-static int
-find_newc_header(struct archive_read *a)
-{
- const void *h;
- const char *p, *q;
- size_t skip, skipped = 0;
- ssize_t bytes;
-
- for (;;) {
- h = __archive_read_ahead(a, newc_header_size, &bytes);
- if (h == NULL)
- return (ARCHIVE_FATAL);
- p = h;
- q = p + bytes;
-
- /* Try the typical case first, then go into the slow search.*/
- if (memcmp("07070", p, 5) == 0
- && (p[5] == '1' || p[5] == '2')
- && is_hex(p, newc_header_size))
- return (ARCHIVE_OK);
-
- /*
- * Scan ahead until we find something that looks
- * like a newc header.
- */
- while (p + newc_header_size <= q) {
- switch (p[5]) {
- case '1':
- case '2':
- if (memcmp("07070", p, 5) == 0
- && is_hex(p, newc_header_size)) {
- skip = p - (const char *)h;
- __archive_read_consume(a, skip);
- skipped += skip;
- if (skipped > 0) {
- archive_set_error(&a->archive,
- 0,
- "Skipped %d bytes before "
- "finding valid header",
- (int)skipped);
- return (ARCHIVE_WARN);
- }
- return (ARCHIVE_OK);
- }
- p += 2;
- break;
- case '0':
- p++;
- break;
- default:
- p += 6;
- break;
- }
- }
- skip = p - (const char *)h;
- __archive_read_consume(a, skip);
- skipped += skip;
- }
-}
-
-static int
-header_newc(struct archive_read *a, struct cpio *cpio,
- struct archive_entry *entry, size_t *namelength, size_t *name_pad)
-{
- const void *h;
- const char *header;
- int r;
-
- r = find_newc_header(a);
- if (r < ARCHIVE_WARN)
- return (r);
-
- /* Read fixed-size portion of header. */
- h = __archive_read_ahead(a, newc_header_size, NULL);
- if (h == NULL)
- return (ARCHIVE_FATAL);
-
- /* Parse out hex fields. */
- header = (const char *)h;
-
- if (memcmp(header + newc_magic_offset, "070701", 6) == 0) {
- a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC;
- a->archive.archive_format_name = "ASCII cpio (SVR4 with no CRC)";
- } else if (memcmp(header + newc_magic_offset, "070702", 6) == 0) {
- a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_CRC;
- a->archive.archive_format_name = "ASCII cpio (SVR4 with CRC)";
- } else {
- /* TODO: Abort here? */
- }
-
- archive_entry_set_devmajor(entry,
- (dev_t)atol16(header + newc_devmajor_offset, newc_devmajor_size));
- archive_entry_set_devminor(entry,
- (dev_t)atol16(header + newc_devminor_offset, newc_devminor_size));
- archive_entry_set_ino(entry, atol16(header + newc_ino_offset, newc_ino_size));
- archive_entry_set_mode(entry,
- (mode_t)atol16(header + newc_mode_offset, newc_mode_size));
- archive_entry_set_uid(entry, atol16(header + newc_uid_offset, newc_uid_size));
- archive_entry_set_gid(entry, atol16(header + newc_gid_offset, newc_gid_size));
- archive_entry_set_nlink(entry,
- (unsigned int)atol16(header + newc_nlink_offset, newc_nlink_size));
- archive_entry_set_rdevmajor(entry,
- (dev_t)atol16(header + newc_rdevmajor_offset, newc_rdevmajor_size));
- archive_entry_set_rdevminor(entry,
- (dev_t)atol16(header + newc_rdevminor_offset, newc_rdevminor_size));
- archive_entry_set_mtime(entry, atol16(header + newc_mtime_offset, newc_mtime_size), 0);
- *namelength = (size_t)atol16(header + newc_namesize_offset, newc_namesize_size);
- /* Pad name to 2 more than a multiple of 4. */
- *name_pad = (2 - *namelength) & 3;
-
- /*
- * Note: entry_bytes_remaining is at least 64 bits and
- * therefore guaranteed to be big enough for a 33-bit file
- * size.
- */
- cpio->entry_bytes_remaining =
- atol16(header + newc_filesize_offset, newc_filesize_size);
- archive_entry_set_size(entry, cpio->entry_bytes_remaining);
- /* Pad file contents to a multiple of 4. */
- cpio->entry_padding = 3 & -cpio->entry_bytes_remaining;
- __archive_read_consume(a, newc_header_size);
- return (r);
-}
-
-/*
- * Skip forward to the next cpio odc header by searching for the
- * 070707 string. This is a hand-optimized search that could
- * probably be easily generalized to handle all character-based
- * cpio variants.
- */
-static int
-is_octal(const char *p, size_t len)
-{
- while (len-- > 0) {
- if (*p < '0' || *p > '7')
- return (0);
- ++p;
- }
- return (1);
-}
-
-static int
-is_afio_large(const char *h, size_t len)
-{
- if (len < afiol_header_size)
- return (0);
- if (h[afiol_ino_m_offset] != 'm'
- || h[afiol_mtime_n_offset] != 'n'
- || h[afiol_xsize_s_offset] != 's'
- || h[afiol_filesize_c_offset] != ':')
- return (0);
- if (!is_hex(h + afiol_dev_offset, afiol_ino_m_offset - afiol_dev_offset))
- return (0);
- if (!is_hex(h + afiol_mode_offset, afiol_mtime_n_offset - afiol_mode_offset))
- return (0);
- if (!is_hex(h + afiol_namesize_offset, afiol_xsize_s_offset - afiol_namesize_offset))
- return (0);
- if (!is_hex(h + afiol_filesize_offset, afiol_filesize_size))
- return (0);
- return (1);
-}
-
-static int
-find_odc_header(struct archive_read *a)
-{
- const void *h;
- const char *p, *q;
- size_t skip, skipped = 0;
- ssize_t bytes;
-
- for (;;) {
- h = __archive_read_ahead(a, odc_header_size, &bytes);
- if (h == NULL)
- return (ARCHIVE_FATAL);
- p = h;
- q = p + bytes;
-
- /* Try the typical case first, then go into the slow search.*/
- if (memcmp("070707", p, 6) == 0 && is_octal(p, odc_header_size))
- return (ARCHIVE_OK);
- if (memcmp("070727", p, 6) == 0 && is_afio_large(p, bytes)) {
- a->archive.archive_format = ARCHIVE_FORMAT_CPIO_AFIO_LARGE;
- return (ARCHIVE_OK);
- }
-
- /*
- * Scan ahead until we find something that looks
- * like an odc header.
- */
- while (p + odc_header_size <= q) {
- switch (p[5]) {
- case '7':
- if ((memcmp("070707", p, 6) == 0
- && is_octal(p, odc_header_size))
- || (memcmp("070727", p, 6) == 0
- && is_afio_large(p, q - p))) {
- skip = p - (const char *)h;
- __archive_read_consume(a, skip);
- skipped += skip;
- if (p[4] == '2')
- a->archive.archive_format =
- ARCHIVE_FORMAT_CPIO_AFIO_LARGE;
- if (skipped > 0) {
- archive_set_error(&a->archive,
- 0,
- "Skipped %d bytes before "
- "finding valid header",
- (int)skipped);
- return (ARCHIVE_WARN);
- }
- return (ARCHIVE_OK);
- }
- p += 2;
- break;
- case '0':
- p++;
- break;
- default:
- p += 6;
- break;
- }
- }
- skip = p - (const char *)h;
- __archive_read_consume(a, skip);
- skipped += skip;
- }
-}
-
-static int
-header_odc(struct archive_read *a, struct cpio *cpio,
- struct archive_entry *entry, size_t *namelength, size_t *name_pad)
-{
- const void *h;
- int r;
- const char *header;
-
- a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
- a->archive.archive_format_name = "POSIX octet-oriented cpio";
-
- /* Find the start of the next header. */
- r = find_odc_header(a);
- if (r < ARCHIVE_WARN)
- return (r);
-
- if (a->archive.archive_format == ARCHIVE_FORMAT_CPIO_AFIO_LARGE) {
- int r2 = (header_afiol(a, cpio, entry, namelength, name_pad));
- if (r2 == ARCHIVE_OK)
- return (r);
- else
- return (r2);
- }
-
- /* Read fixed-size portion of header. */
- h = __archive_read_ahead(a, odc_header_size, NULL);
- if (h == NULL)
- return (ARCHIVE_FATAL);
-
- /* Parse out octal fields. */
- header = (const char *)h;
-
- archive_entry_set_dev(entry,
- (dev_t)atol8(header + odc_dev_offset, odc_dev_size));
- archive_entry_set_ino(entry, atol8(header + odc_ino_offset, odc_ino_size));
- archive_entry_set_mode(entry,
- (mode_t)atol8(header + odc_mode_offset, odc_mode_size));
- archive_entry_set_uid(entry, atol8(header + odc_uid_offset, odc_uid_size));
- archive_entry_set_gid(entry, atol8(header + odc_gid_offset, odc_gid_size));
- archive_entry_set_nlink(entry,
- (unsigned int)atol8(header + odc_nlink_offset, odc_nlink_size));
- archive_entry_set_rdev(entry,
- (dev_t)atol8(header + odc_rdev_offset, odc_rdev_size));
- archive_entry_set_mtime(entry, atol8(header + odc_mtime_offset, odc_mtime_size), 0);
- *namelength = (size_t)atol8(header + odc_namesize_offset, odc_namesize_size);
- *name_pad = 0; /* No padding of filename. */
-
- /*
- * Note: entry_bytes_remaining is at least 64 bits and
- * therefore guaranteed to be big enough for a 33-bit file
- * size.
- */
- cpio->entry_bytes_remaining =
- atol8(header + odc_filesize_offset, odc_filesize_size);
- archive_entry_set_size(entry, cpio->entry_bytes_remaining);
- cpio->entry_padding = 0;
- __archive_read_consume(a, odc_header_size);
- return (r);
-}
-
-/*
- * NOTE: if a filename suffix is ".z", it is the file gziped by afio.
- * it would be nice that we can show uncompressed file size and we can
- * uncompressed file contents automatically, unfortunately we have nothing
- * to get a uncompressed file size while reading each header. it means
- * we also cannot uncompressed file contens under the our framework.
- */
-static int
-header_afiol(struct archive_read *a, struct cpio *cpio,
- struct archive_entry *entry, size_t *namelength, size_t *name_pad)
-{
- const void *h;
- const char *header;
-
- a->archive.archive_format = ARCHIVE_FORMAT_CPIO_AFIO_LARGE;
- a->archive.archive_format_name = "afio large ASCII";
-
- /* Read fixed-size portion of header. */
- h = __archive_read_ahead(a, afiol_header_size, NULL);
- if (h == NULL)
- return (ARCHIVE_FATAL);
-
- /* Parse out octal fields. */
- header = (const char *)h;
-
- archive_entry_set_dev(entry,
- (dev_t)atol16(header + afiol_dev_offset, afiol_dev_size));
- archive_entry_set_ino(entry, atol16(header + afiol_ino_offset, afiol_ino_size));
- archive_entry_set_mode(entry,
- (mode_t)atol8(header + afiol_mode_offset, afiol_mode_size));
- archive_entry_set_uid(entry, atol16(header + afiol_uid_offset, afiol_uid_size));
- archive_entry_set_gid(entry, atol16(header + afiol_gid_offset, afiol_gid_size));
- archive_entry_set_nlink(entry,
- (unsigned int)atol16(header + afiol_nlink_offset, afiol_nlink_size));
- archive_entry_set_rdev(entry,
- (dev_t)atol16(header + afiol_rdev_offset, afiol_rdev_size));
- archive_entry_set_mtime(entry, atol16(header + afiol_mtime_offset, afiol_mtime_size), 0);
- *namelength = (size_t)atol16(header + afiol_namesize_offset, afiol_namesize_size);
- *name_pad = 0; /* No padding of filename. */
-
- cpio->entry_bytes_remaining =
- atol16(header + afiol_filesize_offset, afiol_filesize_size);
- archive_entry_set_size(entry, cpio->entry_bytes_remaining);
- cpio->entry_padding = 0;
- __archive_read_consume(a, afiol_header_size);
- return (ARCHIVE_OK);
-}
-
-
-static int
-header_bin_le(struct archive_read *a, struct cpio *cpio,
- struct archive_entry *entry, size_t *namelength, size_t *name_pad)
-{
- const void *h;
- const unsigned char *header;
-
- a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_LE;
- a->archive.archive_format_name = "cpio (little-endian binary)";
-
- /* Read fixed-size portion of header. */
- h = __archive_read_ahead(a, bin_header_size, NULL);
- if (h == NULL)
- return (ARCHIVE_FATAL);
-
- /* Parse out binary fields. */
- header = (const unsigned char *)h;
-
- archive_entry_set_dev(entry, header[bin_dev_offset] + header[bin_dev_offset + 1] * 256);
- archive_entry_set_ino(entry, header[bin_ino_offset] + header[bin_ino_offset + 1] * 256);
- archive_entry_set_mode(entry, header[bin_mode_offset] + header[bin_mode_offset + 1] * 256);
- archive_entry_set_uid(entry, header[bin_uid_offset] + header[bin_uid_offset + 1] * 256);
- archive_entry_set_gid(entry, header[bin_gid_offset] + header[bin_gid_offset + 1] * 256);
- archive_entry_set_nlink(entry, header[bin_nlink_offset] + header[bin_nlink_offset + 1] * 256);
- archive_entry_set_rdev(entry, header[bin_rdev_offset] + header[bin_rdev_offset + 1] * 256);
- archive_entry_set_mtime(entry, le4(header + bin_mtime_offset), 0);
- *namelength = header[bin_namesize_offset] + header[bin_namesize_offset + 1] * 256;
- *name_pad = *namelength & 1; /* Pad to even. */
-
- cpio->entry_bytes_remaining = le4(header + bin_filesize_offset);
- archive_entry_set_size(entry, cpio->entry_bytes_remaining);
- cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */
- __archive_read_consume(a, bin_header_size);
- return (ARCHIVE_OK);
-}
-
-static int
-header_bin_be(struct archive_read *a, struct cpio *cpio,
- struct archive_entry *entry, size_t *namelength, size_t *name_pad)
-{
- const void *h;
- const unsigned char *header;
-
- a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_BE;
- a->archive.archive_format_name = "cpio (big-endian binary)";
-
- /* Read fixed-size portion of header. */
- h = __archive_read_ahead(a, bin_header_size, NULL);
- if (h == NULL)
- return (ARCHIVE_FATAL);
-
- /* Parse out binary fields. */
- header = (const unsigned char *)h;
-
- archive_entry_set_dev(entry, header[bin_dev_offset] * 256 + header[bin_dev_offset + 1]);
- archive_entry_set_ino(entry, header[bin_ino_offset] * 256 + header[bin_ino_offset + 1]);
- archive_entry_set_mode(entry, header[bin_mode_offset] * 256 + header[bin_mode_offset + 1]);
- archive_entry_set_uid(entry, header[bin_uid_offset] * 256 + header[bin_uid_offset + 1]);
- archive_entry_set_gid(entry, header[bin_gid_offset] * 256 + header[bin_gid_offset + 1]);
- archive_entry_set_nlink(entry, header[bin_nlink_offset] * 256 + header[bin_nlink_offset + 1]);
- archive_entry_set_rdev(entry, header[bin_rdev_offset] * 256 + header[bin_rdev_offset + 1]);
- archive_entry_set_mtime(entry, be4(header + bin_mtime_offset), 0);
- *namelength = header[bin_namesize_offset] * 256 + header[bin_namesize_offset + 1];
- *name_pad = *namelength & 1; /* Pad to even. */
-
- cpio->entry_bytes_remaining = be4(header + bin_filesize_offset);
- archive_entry_set_size(entry, cpio->entry_bytes_remaining);
- cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */
- __archive_read_consume(a, bin_header_size);
- return (ARCHIVE_OK);
-}
-
-static int
-archive_read_format_cpio_cleanup(struct archive_read *a)
-{
- struct cpio *cpio;
-
- cpio = (struct cpio *)(a->format->data);
- /* Free inode->name map */
- while (cpio->links_head != NULL) {
- struct links_entry *lp = cpio->links_head->next;
-
- if (cpio->links_head->name)
- free(cpio->links_head->name);
- free(cpio->links_head);
- cpio->links_head = lp;
- }
- free(cpio);
- (a->format->data) = NULL;
- return (ARCHIVE_OK);
-}
-
-static int
-le4(const unsigned char *p)
-{
- return ((p[0]<<16) + (p[1]<<24) + (p[2]<<0) + (p[3]<<8));
-}
-
-
-static int
-be4(const unsigned char *p)
-{
- return ((p[0]<<24) + (p[1]<<16) + (p[2]<<8) + (p[3]));
-}
-
-/*
- * Note that this implementation does not (and should not!) obey
- * locale settings; you cannot simply substitute strtol here, since
- * it does obey locale.
- */
-static int64_t
-atol8(const char *p, unsigned char_cnt)
-{
- int64_t l;
- int digit;
-
- l = 0;
- while (char_cnt-- > 0) {
- if (*p >= '0' && *p <= '7')
- digit = *p - '0';
- else
- return (l);
- p++;
- l <<= 3;
- l |= digit;
- }
- return (l);
-}
-
-static int64_t
-atol16(const char *p, unsigned char_cnt)
-{
- int64_t l;
- int digit;
-
- l = 0;
- while (char_cnt-- > 0) {
- if (*p >= 'a' && *p <= 'f')
- digit = *p - 'a' + 10;
- else if (*p >= 'A' && *p <= 'F')
- digit = *p - 'A' + 10;
- else if (*p >= '0' && *p <= '9')
- digit = *p - '0';
- else
- return (l);
- p++;
- l <<= 4;
- l |= digit;
- }
- return (l);
-}
-
-static int
-record_hardlink(struct archive_read *a,
- struct cpio *cpio, struct archive_entry *entry)
-{
- struct links_entry *le;
- dev_t dev;
- int64_t ino;
-
- if (archive_entry_nlink(entry) <= 1)
- return (ARCHIVE_OK);
-
- dev = archive_entry_dev(entry);
- ino = archive_entry_ino64(entry);
-
- /*
- * First look in the list of multiply-linked files. If we've
- * already dumped it, convert this entry to a hard link entry.
- */
- for (le = cpio->links_head; le; le = le->next) {
- if (le->dev == dev && le->ino == ino) {
- archive_entry_copy_hardlink(entry, le->name);
-
- if (--le->links <= 0) {
- if (le->previous != NULL)
- le->previous->next = le->next;
- if (le->next != NULL)
- le->next->previous = le->previous;
- if (cpio->links_head == le)
- cpio->links_head = le->next;
- free(le->name);
- free(le);
- }
-
- return (ARCHIVE_OK);
- }
- }
-
- le = (struct links_entry *)malloc(sizeof(struct links_entry));
- if (le == NULL) {
- archive_set_error(&a->archive,
- ENOMEM, "Out of memory adding file to list");
- return (ARCHIVE_FATAL);
- }
- if (cpio->links_head != NULL)
- cpio->links_head->previous = le;
- le->next = cpio->links_head;
- le->previous = NULL;
- cpio->links_head = le;
- le->dev = dev;
- le->ino = ino;
- le->links = archive_entry_nlink(entry) - 1;
- le->name = strdup(archive_entry_pathname(entry));
- if (le->name == NULL) {
- archive_set_error(&a->archive,
- ENOMEM, "Out of memory adding file to list");
- return (ARCHIVE_FATAL);
- }
-
- return (ARCHIVE_OK);
-}
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_format_empty.c b/3rdparty/libarchive/libarchive/archive_read_support_format_empty.c
index 36607382..c641eb9b 100644
--- a/3rdparty/libarchive/libarchive/archive_read_support_format_empty.c
+++ b/3rdparty/libarchive/libarchive/archive_read_support_format_empty.c
@@ -54,6 +54,8 @@ archive_read_support_format_empty(struct archive *_a)
archive_read_format_empty_read_data,
NULL,
NULL,
+ NULL,
+ NULL,
NULL);
return (r);
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_format_iso9660.c b/3rdparty/libarchive/libarchive/archive_read_support_format_iso9660.c
deleted file mode 100644
index 914bc71d..00000000
--- a/3rdparty/libarchive/libarchive/archive_read_support_format_iso9660.c
+++ /dev/null
@@ -1,3233 +0,0 @@
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * Copyright (c) 2009 Andreas Henriksson <andreas@fatal.se>
- * Copyright (c) 2009-2012 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"
-__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_iso9660.c 201246 2009-12-30 05:30:35Z kientzle $");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-/* #include <stdint.h> */ /* See archive_platform.h */
-#include <stdio.h>
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#include <time.h>
-#ifdef HAVE_ZLIB_H
-#include <zlib.h>
-#endif
-
-#include "archive.h"
-#include "archive_endian.h"
-#include "archive_entry.h"
-#include "archive_entry_locale.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-#include "archive_string.h"
-
-/*
- * An overview of ISO 9660 format:
- *
- * Each disk is laid out as follows:
- * * 32k reserved for private use
- * * Volume descriptor table. Each volume descriptor
- * is 2k and specifies basic format information.
- * The "Primary Volume Descriptor" (PVD) is defined by the
- * standard and should always be present; other volume
- * descriptors include various vendor-specific extensions.
- * * Files and directories. Each file/dir is specified by
- * an "extent" (starting sector and length in bytes).
- * Dirs are just files with directory records packed one
- * after another. The PVD contains a single dir entry
- * specifying the location of the root directory. Everything
- * else follows from there.
- *
- * This module works by first reading the volume descriptors, then
- * building a list of directory entries, sorted by starting
- * sector. At each step, I look for the earliest dir entry that
- * hasn't yet been read, seek forward to that location and read
- * that entry. If it's a dir, I slurp in the new dir entries and
- * add them to the heap; if it's a regular file, I return the
- * corresponding archive_entry and wait for the client to request
- * the file body. This strategy allows us to read most compliant
- * CDs with a single pass through the data, as required by libarchive.
- */
-#define LOGICAL_BLOCK_SIZE 2048
-#define SYSTEM_AREA_BLOCK 16
-
-/* Structure of on-disk primary volume descriptor. */
-#define PVD_type_offset 0
-#define PVD_type_size 1
-#define PVD_id_offset (PVD_type_offset + PVD_type_size)
-#define PVD_id_size 5
-#define PVD_version_offset (PVD_id_offset + PVD_id_size)
-#define PVD_version_size 1
-#define PVD_reserved1_offset (PVD_version_offset + PVD_version_size)
-#define PVD_reserved1_size 1
-#define PVD_system_id_offset (PVD_reserved1_offset + PVD_reserved1_size)
-#define PVD_system_id_size 32
-#define PVD_volume_id_offset (PVD_system_id_offset + PVD_system_id_size)
-#define PVD_volume_id_size 32
-#define PVD_reserved2_offset (PVD_volume_id_offset + PVD_volume_id_size)
-#define PVD_reserved2_size 8
-#define PVD_volume_space_size_offset (PVD_reserved2_offset + PVD_reserved2_size)
-#define PVD_volume_space_size_size 8
-#define PVD_reserved3_offset (PVD_volume_space_size_offset + PVD_volume_space_size_size)
-#define PVD_reserved3_size 32
-#define PVD_volume_set_size_offset (PVD_reserved3_offset + PVD_reserved3_size)
-#define PVD_volume_set_size_size 4
-#define PVD_volume_sequence_number_offset (PVD_volume_set_size_offset + PVD_volume_set_size_size)
-#define PVD_volume_sequence_number_size 4
-#define PVD_logical_block_size_offset (PVD_volume_sequence_number_offset + PVD_volume_sequence_number_size)
-#define PVD_logical_block_size_size 4
-#define PVD_path_table_size_offset (PVD_logical_block_size_offset + PVD_logical_block_size_size)
-#define PVD_path_table_size_size 8
-#define PVD_type_1_path_table_offset (PVD_path_table_size_offset + PVD_path_table_size_size)
-#define PVD_type_1_path_table_size 4
-#define PVD_opt_type_1_path_table_offset (PVD_type_1_path_table_offset + PVD_type_1_path_table_size)
-#define PVD_opt_type_1_path_table_size 4
-#define PVD_type_m_path_table_offset (PVD_opt_type_1_path_table_offset + PVD_opt_type_1_path_table_size)
-#define PVD_type_m_path_table_size 4
-#define PVD_opt_type_m_path_table_offset (PVD_type_m_path_table_offset + PVD_type_m_path_table_size)
-#define PVD_opt_type_m_path_table_size 4
-#define PVD_root_directory_record_offset (PVD_opt_type_m_path_table_offset + PVD_opt_type_m_path_table_size)
-#define PVD_root_directory_record_size 34
-#define PVD_volume_set_id_offset (PVD_root_directory_record_offset + PVD_root_directory_record_size)
-#define PVD_volume_set_id_size 128
-#define PVD_publisher_id_offset (PVD_volume_set_id_offset + PVD_volume_set_id_size)
-#define PVD_publisher_id_size 128
-#define PVD_preparer_id_offset (PVD_publisher_id_offset + PVD_publisher_id_size)
-#define PVD_preparer_id_size 128
-#define PVD_application_id_offset (PVD_preparer_id_offset + PVD_preparer_id_size)
-#define PVD_application_id_size 128
-#define PVD_copyright_file_id_offset (PVD_application_id_offset + PVD_application_id_size)
-#define PVD_copyright_file_id_size 37
-#define PVD_abstract_file_id_offset (PVD_copyright_file_id_offset + PVD_copyright_file_id_size)
-#define PVD_abstract_file_id_size 37
-#define PVD_bibliographic_file_id_offset (PVD_abstract_file_id_offset + PVD_abstract_file_id_size)
-#define PVD_bibliographic_file_id_size 37
-#define PVD_creation_date_offset (PVD_bibliographic_file_id_offset + PVD_bibliographic_file_id_size)
-#define PVD_creation_date_size 17
-#define PVD_modification_date_offset (PVD_creation_date_offset + PVD_creation_date_size)
-#define PVD_modification_date_size 17
-#define PVD_expiration_date_offset (PVD_modification_date_offset + PVD_modification_date_size)
-#define PVD_expiration_date_size 17
-#define PVD_effective_date_offset (PVD_expiration_date_offset + PVD_expiration_date_size)
-#define PVD_effective_date_size 17
-#define PVD_file_structure_version_offset (PVD_effective_date_offset + PVD_effective_date_size)
-#define PVD_file_structure_version_size 1
-#define PVD_reserved4_offset (PVD_file_structure_version_offset + PVD_file_structure_version_size)
-#define PVD_reserved4_size 1
-#define PVD_application_data_offset (PVD_reserved4_offset + PVD_reserved4_size)
-#define PVD_application_data_size 512
-#define PVD_reserved5_offset (PVD_application_data_offset + PVD_application_data_size)
-#define PVD_reserved5_size (2048 - PVD_reserved5_offset)
-
-/* TODO: It would make future maintenance easier to just hardcode the
- * above values. In particular, ECMA119 states the offsets as part of
- * the standard. That would eliminate the need for the following check.*/
-#if PVD_reserved5_offset != 1395
-#error PVD offset and size definitions are wrong.
-#endif
-
-
-/* Structure of optional on-disk supplementary volume descriptor. */
-#define SVD_type_offset 0
-#define SVD_type_size 1
-#define SVD_id_offset (SVD_type_offset + SVD_type_size)
-#define SVD_id_size 5
-#define SVD_version_offset (SVD_id_offset + SVD_id_size)
-#define SVD_version_size 1
-/* ... */
-#define SVD_reserved1_offset 72
-#define SVD_reserved1_size 8
-#define SVD_volume_space_size_offset 80
-#define SVD_volume_space_size_size 8
-#define SVD_escape_sequences_offset (SVD_volume_space_size_offset + SVD_volume_space_size_size)
-#define SVD_escape_sequences_size 32
-/* ... */
-#define SVD_logical_block_size_offset 128
-#define SVD_logical_block_size_size 4
-#define SVD_type_L_path_table_offset 140
-#define SVD_type_M_path_table_offset 148
-/* ... */
-#define SVD_root_directory_record_offset 156
-#define SVD_root_directory_record_size 34
-#define SVD_file_structure_version_offset 881
-#define SVD_reserved2_offset 882
-#define SVD_reserved2_size 1
-#define SVD_reserved3_offset 1395
-#define SVD_reserved3_size 653
-/* ... */
-/* FIXME: validate correctness of last SVD entry offset. */
-
-/* Structure of an on-disk directory record. */
-/* Note: ISO9660 stores each multi-byte integer twice, once in
- * each byte order. The sizes here are the size of just one
- * of the two integers. (This is why the offset of a field isn't
- * the same as the offset+size of the previous field.) */
-#define DR_length_offset 0
-#define DR_length_size 1
-#define DR_ext_attr_length_offset 1
-#define DR_ext_attr_length_size 1
-#define DR_extent_offset 2
-#define DR_extent_size 4
-#define DR_size_offset 10
-#define DR_size_size 4
-#define DR_date_offset 18
-#define DR_date_size 7
-#define DR_flags_offset 25
-#define DR_flags_size 1
-#define DR_file_unit_size_offset 26
-#define DR_file_unit_size_size 1
-#define DR_interleave_offset 27
-#define DR_interleave_size 1
-#define DR_volume_sequence_number_offset 28
-#define DR_volume_sequence_number_size 2
-#define DR_name_len_offset 32
-#define DR_name_len_size 1
-#define DR_name_offset 33
-
-#ifdef HAVE_ZLIB_H
-static const unsigned char zisofs_magic[8] = {
- 0x37, 0xE4, 0x53, 0x96, 0xC9, 0xDB, 0xD6, 0x07
-};
-
-struct zisofs {
- /* Set 1 if this file compressed by paged zlib */
- int pz;
- int pz_log2_bs; /* Log2 of block size */
- uint64_t pz_uncompressed_size;
-
- int initialized;
- unsigned char *uncompressed_buffer;
- size_t uncompressed_buffer_size;
-
- uint32_t pz_offset;
- unsigned char header[16];
- size_t header_avail;
- int header_passed;
- unsigned char *block_pointers;
- size_t block_pointers_alloc;
- size_t block_pointers_size;
- size_t block_pointers_avail;
- size_t block_off;
- uint32_t block_avail;
-
- z_stream stream;
- int stream_valid;
-};
-#else
-struct zisofs {
- /* Set 1 if this file compressed by paged zlib */
- int pz;
-};
-#endif
-
-struct content {
- uint64_t offset;/* Offset on disk. */
- uint64_t size; /* File size in bytes. */
- struct content *next;
-};
-
-/* In-memory storage for a directory record. */
-struct file_info {
- struct file_info *use_next;
- struct file_info *parent;
- struct file_info *next;
- struct file_info *re_next;
- int subdirs;
- uint64_t key; /* Heap Key. */
- uint64_t offset; /* Offset on disk. */
- uint64_t size; /* File size in bytes. */
- uint32_t ce_offset; /* Offset of CE. */
- uint32_t ce_size; /* Size of CE. */
- char rr_moved; /* Flag to rr_moved. */
- char rr_moved_has_re_only;
- char re; /* Having RRIP "RE" extension. */
- char re_descendant;
- uint64_t cl_offset; /* Having RRIP "CL" extension. */
- int birthtime_is_set;
- time_t birthtime; /* File created time. */
- time_t mtime; /* File last modified time. */
- time_t atime; /* File last accessed time. */
- time_t ctime; /* File attribute change time. */
- uint64_t rdev; /* Device number. */
- mode_t mode;
- uid_t uid;
- gid_t gid;
- int64_t number;
- int nlinks;
- struct archive_string name; /* Pathname */
- unsigned char *utf16be_name;
- size_t utf16be_bytes;
- char name_continues; /* Non-zero if name continues */
- struct archive_string symlink;
- char symlink_continues; /* Non-zero if link continues */
- /* Set 1 if this file compressed by paged zlib(zisofs) */
- int pz;
- int pz_log2_bs; /* Log2 of block size */
- uint64_t pz_uncompressed_size;
- /* Set 1 if this file is multi extent. */
- int multi_extent;
- struct {
- struct content *first;
- struct content **last;
- } contents;
- struct {
- struct file_info *first;
- struct file_info **last;
- } rede_files;
-};
-
-struct heap_queue {
- struct file_info **files;
- int allocated;
- int used;
-};
-
-struct iso9660 {
- int magic;
-#define ISO9660_MAGIC 0x96609660
-
- int opt_support_joliet;
- int opt_support_rockridge;
-
- struct archive_string pathname;
- char seenRockridge; /* Set true if RR extensions are used. */
- char seenSUSP; /* Set true if SUSP is beging used. */
- char seenJoliet;
-
- unsigned char suspOffset;
- struct file_info *rr_moved;
- struct read_ce_queue {
- struct read_ce_req {
- uint64_t offset;/* Offset of CE on disk. */
- struct file_info *file;
- } *reqs;
- int cnt;
- int allocated;
- } read_ce_req;
-
- int64_t previous_number;
- struct archive_string previous_pathname;
-
- struct file_info *use_files;
- struct heap_queue pending_files;
- struct {
- struct file_info *first;
- struct file_info **last;
- } cache_files;
- struct {
- struct file_info *first;
- struct file_info **last;
- } re_files;
-
- uint64_t current_position;
- ssize_t logical_block_size;
- uint64_t volume_size; /* Total size of volume in bytes. */
- int32_t volume_block;/* Total size of volume in logical blocks. */
-
- struct vd {
- int location; /* Location of Extent. */
- uint32_t size;
- } primary, joliet;
-
- int64_t entry_sparse_offset;
- int64_t entry_bytes_remaining;
- size_t entry_bytes_unconsumed;
- struct zisofs entry_zisofs;
- struct content *entry_content;
- struct archive_string_conv *sconv_utf16be;
- /*
- * Buffers for a full pathname in UTF-16BE in Joliet extensions.
- */
-#define UTF16_NAME_MAX 1024
- unsigned char *utf16be_path;
- size_t utf16be_path_len;
- unsigned char *utf16be_previous_path;
- size_t utf16be_previous_path_len;
- /* Null buufer used in bidder to improve its performance. */
- unsigned char null[2048];
-};
-
-static int archive_read_format_iso9660_bid(struct archive_read *, int);
-static int archive_read_format_iso9660_options(struct archive_read *,
- const char *, const char *);
-static int archive_read_format_iso9660_cleanup(struct archive_read *);
-static int archive_read_format_iso9660_read_data(struct archive_read *,
- const void **, size_t *, int64_t *);
-static int archive_read_format_iso9660_read_data_skip(struct archive_read *);
-static int archive_read_format_iso9660_read_header(struct archive_read *,
- struct archive_entry *);
-static const char *build_pathname(struct archive_string *, struct file_info *);
-static int build_pathname_utf16be(unsigned char *, size_t, size_t *,
- struct file_info *);
-#if DEBUG
-static void dump_isodirrec(FILE *, const unsigned char *isodirrec);
-#endif
-static time_t time_from_tm(struct tm *);
-static time_t isodate17(const unsigned char *);
-static time_t isodate7(const unsigned char *);
-static int isBootRecord(struct iso9660 *, const unsigned char *);
-static int isVolumePartition(struct iso9660 *, const unsigned char *);
-static int isVDSetTerminator(struct iso9660 *, const unsigned char *);
-static int isJolietSVD(struct iso9660 *, const unsigned char *);
-static int isSVD(struct iso9660 *, const unsigned char *);
-static int isEVD(struct iso9660 *, const unsigned char *);
-static int isPVD(struct iso9660 *, const unsigned char *);
-static int next_cache_entry(struct archive_read *, struct iso9660 *,
- struct file_info **);
-static int next_entry_seek(struct archive_read *, struct iso9660 *,
- struct file_info **);
-static struct file_info *
- parse_file_info(struct archive_read *a,
- struct file_info *parent, const unsigned char *isodirrec);
-static int parse_rockridge(struct archive_read *a,
- struct file_info *file, const unsigned char *start,
- const unsigned char *end);
-static int register_CE(struct archive_read *a, int32_t location,
- struct file_info *file);
-static int read_CE(struct archive_read *a, struct iso9660 *iso9660);
-static void parse_rockridge_NM1(struct file_info *,
- const unsigned char *, int);
-static void parse_rockridge_SL1(struct file_info *,
- const unsigned char *, int);
-static void parse_rockridge_TF1(struct file_info *,
- const unsigned char *, int);
-static void parse_rockridge_ZF1(struct file_info *,
- const unsigned char *, int);
-static void register_file(struct iso9660 *, struct file_info *);
-static void release_files(struct iso9660 *);
-static unsigned toi(const void *p, int n);
-static inline void re_add_entry(struct iso9660 *, struct file_info *);
-static inline struct file_info * re_get_entry(struct iso9660 *);
-static inline int rede_add_entry(struct file_info *);
-static inline struct file_info * rede_get_entry(struct file_info *);
-static inline void cache_add_entry(struct iso9660 *iso9660,
- struct file_info *file);
-static inline struct file_info *cache_get_entry(struct iso9660 *iso9660);
-static int heap_add_entry(struct archive_read *a, struct heap_queue *heap,
- struct file_info *file, uint64_t key);
-static struct file_info *heap_get_entry(struct heap_queue *heap);
-
-#define add_entry(arch, iso9660, file) \
- heap_add_entry(arch, &((iso9660)->pending_files), file, file->offset)
-#define next_entry(iso9660) \
- heap_get_entry(&((iso9660)->pending_files))
-
-int
-archive_read_support_format_iso9660(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct iso9660 *iso9660;
- int r;
-
- archive_check_magic(_a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_NEW, "archive_read_support_format_iso9660");
-
- iso9660 = (struct iso9660 *)calloc(1, sizeof(*iso9660));
- if (iso9660 == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate iso9660 data");
- return (ARCHIVE_FATAL);
- }
- iso9660->magic = ISO9660_MAGIC;
- iso9660->cache_files.first = NULL;
- iso9660->cache_files.last = &(iso9660->cache_files.first);
- iso9660->re_files.first = NULL;
- iso9660->re_files.last = &(iso9660->re_files.first);
- /* Enable to support Joliet extensions by default. */
- iso9660->opt_support_joliet = 1;
- /* Enable to support Rock Ridge extensions by default. */
- iso9660->opt_support_rockridge = 1;
-
- r = __archive_read_register_format(a,
- iso9660,
- "iso9660",
- archive_read_format_iso9660_bid,
- archive_read_format_iso9660_options,
- archive_read_format_iso9660_read_header,
- archive_read_format_iso9660_read_data,
- archive_read_format_iso9660_read_data_skip,
- NULL,
- archive_read_format_iso9660_cleanup);
-
- if (r != ARCHIVE_OK) {
- free(iso9660);
- return (r);
- }
- return (ARCHIVE_OK);
-}
-
-
-static int
-archive_read_format_iso9660_bid(struct archive_read *a, int best_bid)
-{
- struct iso9660 *iso9660;
- ssize_t bytes_read;
- const unsigned char *p;
- int seenTerminator;
-
- /* If there's already a better bid than we can ever
- make, don't bother testing. */
- if (best_bid > 48)
- return (-1);
-
- iso9660 = (struct iso9660 *)(a->format->data);
-
- /*
- * Skip the first 32k (reserved area) and get the first
- * 8 sectors of the volume descriptor table. Of course,
- * if the I/O layer gives us more, we'll take it.
- */
-#define RESERVED_AREA (SYSTEM_AREA_BLOCK * LOGICAL_BLOCK_SIZE)
- p = __archive_read_ahead(a,
- RESERVED_AREA + 8 * LOGICAL_BLOCK_SIZE,
- &bytes_read);
- if (p == NULL)
- return (-1);
-
- /* Skip the reserved area. */
- bytes_read -= RESERVED_AREA;
- p += RESERVED_AREA;
-
- /* Check each volume descriptor. */
- seenTerminator = 0;
- for (; bytes_read > LOGICAL_BLOCK_SIZE;
- bytes_read -= LOGICAL_BLOCK_SIZE, p += LOGICAL_BLOCK_SIZE) {
- /* Do not handle undefined Volume Descriptor Type. */
- if (p[0] >= 4 && p[0] <= 254)
- return (0);
- /* Standard Identifier must be "CD001" */
- if (memcmp(p + 1, "CD001", 5) != 0)
- return (0);
- if (isPVD(iso9660, p))
- continue;
- if (!iso9660->joliet.location) {
- if (isJolietSVD(iso9660, p))
- continue;
- }
- if (isBootRecord(iso9660, p))
- continue;
- if (isEVD(iso9660, p))
- continue;
- if (isSVD(iso9660, p))
- continue;
- if (isVolumePartition(iso9660, p))
- continue;
- if (isVDSetTerminator(iso9660, p)) {
- seenTerminator = 1;
- break;
- }
- return (0);
- }
- /*
- * ISO 9660 format must have Primary Volume Descriptor and
- * Volume Descriptor Set Terminator.
- */
- if (seenTerminator && iso9660->primary.location > 16)
- return (48);
-
- /* We didn't find a valid PVD; return a bid of zero. */
- return (0);
-}
-
-static int
-archive_read_format_iso9660_options(struct archive_read *a,
- const char *key, const char *val)
-{
- struct iso9660 *iso9660;
-
- iso9660 = (struct iso9660 *)(a->format->data);
-
- if (strcmp(key, "joliet") == 0) {
- if (val == NULL || strcmp(val, "off") == 0 ||
- strcmp(val, "ignore") == 0 ||
- strcmp(val, "disable") == 0 ||
- strcmp(val, "0") == 0)
- iso9660->opt_support_joliet = 0;
- else
- iso9660->opt_support_joliet = 1;
- return (ARCHIVE_OK);
- }
- if (strcmp(key, "rockridge") == 0 ||
- strcmp(key, "Rockridge") == 0) {
- iso9660->opt_support_rockridge = val != NULL;
- return (ARCHIVE_OK);
- }
-
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
-}
-
-static int
-isNull(struct iso9660 *iso9660, const unsigned char *h, unsigned offset,
-unsigned bytes)
-{
-
- while (bytes >= sizeof(iso9660->null)) {
- if (!memcmp(iso9660->null, h + offset, sizeof(iso9660->null)))
- return (0);
- offset += sizeof(iso9660->null);
- bytes -= sizeof(iso9660->null);
- }
- if (bytes)
- return memcmp(iso9660->null, h + offset, bytes) == 0;
- else
- return (1);
-}
-
-static int
-isBootRecord(struct iso9660 *iso9660, const unsigned char *h)
-{
- (void)iso9660; /* UNUSED */
-
- /* Type of the Volume Descriptor Boot Record must be 0. */
- if (h[0] != 0)
- return (0);
-
- /* Volume Descriptor Version must be 1. */
- if (h[6] != 1)
- return (0);
-
- return (1);
-}
-
-static int
-isVolumePartition(struct iso9660 *iso9660, const unsigned char *h)
-{
- int32_t location;
-
- /* Type of the Volume Partition Descriptor must be 3. */
- if (h[0] != 3)
- return (0);
-
- /* Volume Descriptor Version must be 1. */
- if (h[6] != 1)
- return (0);
- /* Unused Field */
- if (h[7] != 0)
- return (0);
-
- location = archive_le32dec(h + 72);
- if (location <= SYSTEM_AREA_BLOCK ||
- location >= iso9660->volume_block)
- return (0);
- if ((uint32_t)location != archive_be32dec(h + 76))
- return (0);
-
- return (1);
-}
-
-static int
-isVDSetTerminator(struct iso9660 *iso9660, const unsigned char *h)
-{
- (void)iso9660; /* UNUSED */
-
- /* Type of the Volume Descriptor Set Terminator must be 255. */
- if (h[0] != 255)
- return (0);
-
- /* Volume Descriptor Version must be 1. */
- if (h[6] != 1)
- return (0);
-
- /* Reserved field must be 0. */
- if (!isNull(iso9660, h, 7, 2048-7))
- return (0);
-
- return (1);
-}
-
-static int
-isJolietSVD(struct iso9660 *iso9660, const unsigned char *h)
-{
- const unsigned char *p;
- ssize_t logical_block_size;
- int32_t volume_block;
-
- /* Check if current sector is a kind of Supplementary Volume
- * Descriptor. */
- if (!isSVD(iso9660, h))
- return (0);
-
- /* FIXME: do more validations according to joliet spec. */
-
- /* check if this SVD contains joliet extension! */
- p = h + SVD_escape_sequences_offset;
- /* N.B. Joliet spec says p[1] == '\\', but.... */
- if (p[0] == '%' && p[1] == '/') {
- int level = 0;
-
- if (p[2] == '@')
- level = 1;
- else if (p[2] == 'C')
- level = 2;
- else if (p[2] == 'E')
- level = 3;
- else /* not joliet */
- return (0);
-
- iso9660->seenJoliet = level;
-
- } else /* not joliet */
- return (0);
-
- logical_block_size =
- archive_le16dec(h + SVD_logical_block_size_offset);
- volume_block = archive_le32dec(h + SVD_volume_space_size_offset);
-
- iso9660->logical_block_size = logical_block_size;
- iso9660->volume_block = volume_block;
- iso9660->volume_size = logical_block_size * (uint64_t)volume_block;
- /* Read Root Directory Record in Volume Descriptor. */
- p = h + SVD_root_directory_record_offset;
- iso9660->joliet.location = archive_le32dec(p + DR_extent_offset);
- iso9660->joliet.size = archive_le32dec(p + DR_size_offset);
-
- return (48);
-}
-
-static int
-isSVD(struct iso9660 *iso9660, const unsigned char *h)
-{
- const unsigned char *p;
- ssize_t logical_block_size;
- int32_t volume_block;
- int32_t location;
-
- (void)iso9660; /* UNUSED */
-
- /* Type 2 means it's a SVD. */
- if (h[SVD_type_offset] != 2)
- return (0);
-
- /* Reserved field must be 0. */
- if (!isNull(iso9660, h, SVD_reserved1_offset, SVD_reserved1_size))
- return (0);
- if (!isNull(iso9660, h, SVD_reserved2_offset, SVD_reserved2_size))
- return (0);
- if (!isNull(iso9660, h, SVD_reserved3_offset, SVD_reserved3_size))
- return (0);
-
- /* File structure version must be 1 for ISO9660/ECMA119. */
- if (h[SVD_file_structure_version_offset] != 1)
- return (0);
-
- logical_block_size =
- archive_le16dec(h + SVD_logical_block_size_offset);
- if (logical_block_size <= 0)
- return (0);
-
- volume_block = archive_le32dec(h + SVD_volume_space_size_offset);
- if (volume_block <= SYSTEM_AREA_BLOCK+4)
- return (0);
-
- /* Location of Occurrence of Type L Path Table must be
- * available location,
- * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */
- location = archive_le32dec(h+SVD_type_L_path_table_offset);
- if (location < SYSTEM_AREA_BLOCK+2 || location >= volume_block)
- return (0);
-
- /* The Type M Path Table must be at a valid location (WinISO
- * and probably other programs omit this, so we allow zero)
- *
- * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */
- location = archive_be32dec(h+SVD_type_M_path_table_offset);
- if ((location > 0 && location < SYSTEM_AREA_BLOCK+2)
- || location >= volume_block)
- return (0);
-
- /* Read Root Directory Record in Volume Descriptor. */
- p = h + SVD_root_directory_record_offset;
- if (p[DR_length_offset] != 34)
- return (0);
-
- return (48);
-}
-
-static int
-isEVD(struct iso9660 *iso9660, const unsigned char *h)
-{
- const unsigned char *p;
- ssize_t logical_block_size;
- int32_t volume_block;
- int32_t location;
-
- (void)iso9660; /* UNUSED */
-
- /* Type of the Enhanced Volume Descriptor must be 2. */
- if (h[PVD_type_offset] != 2)
- return (0);
-
- /* EVD version must be 2. */
- if (h[PVD_version_offset] != 2)
- return (0);
-
- /* Reserved field must be 0. */
- if (h[PVD_reserved1_offset] != 0)
- return (0);
-
- /* Reserved field must be 0. */
- if (!isNull(iso9660, h, PVD_reserved2_offset, PVD_reserved2_size))
- return (0);
-
- /* Reserved field must be 0. */
- if (!isNull(iso9660, h, PVD_reserved3_offset, PVD_reserved3_size))
- return (0);
-
- /* Logical block size must be > 0. */
- /* I've looked at Ecma 119 and can't find any stronger
- * restriction on this field. */
- logical_block_size =
- archive_le16dec(h + PVD_logical_block_size_offset);
- if (logical_block_size <= 0)
- return (0);
-
- volume_block =
- archive_le32dec(h + PVD_volume_space_size_offset);
- if (volume_block <= SYSTEM_AREA_BLOCK+4)
- return (0);
-
- /* File structure version must be 2 for ISO9660:1999. */
- if (h[PVD_file_structure_version_offset] != 2)
- return (0);
-
- /* Location of Occurrence of Type L Path Table must be
- * available location,
- * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */
- location = archive_le32dec(h+PVD_type_1_path_table_offset);
- if (location < SYSTEM_AREA_BLOCK+2 || location >= volume_block)
- return (0);
-
- /* Location of Occurrence of Type M Path Table must be
- * available location,
- * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */
- location = archive_be32dec(h+PVD_type_m_path_table_offset);
- if ((location > 0 && location < SYSTEM_AREA_BLOCK+2)
- || location >= volume_block)
- return (0);
-
- /* Reserved field must be 0. */
- if (!isNull(iso9660, h, PVD_reserved4_offset, PVD_reserved4_size))
- return (0);
-
- /* Reserved field must be 0. */
- if (!isNull(iso9660, h, PVD_reserved5_offset, PVD_reserved5_size))
- return (0);
-
- /* Read Root Directory Record in Volume Descriptor. */
- p = h + PVD_root_directory_record_offset;
- if (p[DR_length_offset] != 34)
- return (0);
-
- return (48);
-}
-
-static int
-isPVD(struct iso9660 *iso9660, const unsigned char *h)
-{
- const unsigned char *p;
- ssize_t logical_block_size;
- int32_t volume_block;
- int32_t location;
- int i;
-
- /* Type of the Primary Volume Descriptor must be 1. */
- if (h[PVD_type_offset] != 1)
- return (0);
-
- /* PVD version must be 1. */
- if (h[PVD_version_offset] != 1)
- return (0);
-
- /* Reserved field must be 0. */
- if (h[PVD_reserved1_offset] != 0)
- return (0);
-
- /* Reserved field must be 0. */
- if (!isNull(iso9660, h, PVD_reserved2_offset, PVD_reserved2_size))
- return (0);
-
- /* Reserved field must be 0. */
- if (!isNull(iso9660, h, PVD_reserved3_offset, PVD_reserved3_size))
- return (0);
-
- /* Logical block size must be > 0. */
- /* I've looked at Ecma 119 and can't find any stronger
- * restriction on this field. */
- logical_block_size =
- archive_le16dec(h + PVD_logical_block_size_offset);
- if (logical_block_size <= 0)
- return (0);
-
- volume_block = archive_le32dec(h + PVD_volume_space_size_offset);
- if (volume_block <= SYSTEM_AREA_BLOCK+4)
- return (0);
-
- /* File structure version must be 1 for ISO9660/ECMA119. */
- if (h[PVD_file_structure_version_offset] != 1)
- return (0);
-
- /* Location of Occurrence of Type L Path Table must be
- * available location,
- * > SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */
- location = archive_le32dec(h+PVD_type_1_path_table_offset);
- if (location < SYSTEM_AREA_BLOCK+2 || location >= volume_block)
- return (0);
-
- /* The Type M Path Table must also be at a valid location
- * (although ECMA 119 requires a Type M Path Table, WinISO and
- * probably other programs omit it, so we permit a zero here)
- *
- * >= SYSTEM_AREA_BLOCK(16) + 2 and < Volume Space Size. */
- location = archive_be32dec(h+PVD_type_m_path_table_offset);
- if ((location > 0 && location < SYSTEM_AREA_BLOCK+2)
- || location >= volume_block)
- return (0);
-
- /* Reserved field must be 0. */
- /* But accept NetBSD/FreeBSD "makefs" images with 0x20 here. */
- for (i = 0; i < PVD_reserved4_size; ++i)
- if (h[PVD_reserved4_offset + i] != 0
- && h[PVD_reserved4_offset + i] != 0x20)
- return (0);
-
- /* Reserved field must be 0. */
- if (!isNull(iso9660, h, PVD_reserved5_offset, PVD_reserved5_size))
- return (0);
-
- /* XXX TODO: Check other values for sanity; reject more
- * malformed PVDs. XXX */
-
- /* Read Root Directory Record in Volume Descriptor. */
- p = h + PVD_root_directory_record_offset;
- if (p[DR_length_offset] != 34)
- return (0);
-
- if (!iso9660->primary.location) {
- iso9660->logical_block_size = logical_block_size;
- iso9660->volume_block = volume_block;
- iso9660->volume_size =
- logical_block_size * (uint64_t)volume_block;
- iso9660->primary.location =
- archive_le32dec(p + DR_extent_offset);
- iso9660->primary.size = archive_le32dec(p + DR_size_offset);
- }
-
- return (48);
-}
-
-static int
-read_children(struct archive_read *a, struct file_info *parent)
-{
- struct iso9660 *iso9660;
- const unsigned char *b, *p;
- struct file_info *multi;
- size_t step, skip_size;
-
- iso9660 = (struct iso9660 *)(a->format->data);
- /* flush any remaining bytes from the last round to ensure
- * we're positioned */
- if (iso9660->entry_bytes_unconsumed) {
- __archive_read_consume(a, iso9660->entry_bytes_unconsumed);
- iso9660->entry_bytes_unconsumed = 0;
- }
- if (iso9660->current_position > parent->offset) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Ignoring out-of-order directory (%s) %jd > %jd",
- parent->name.s,
- (intmax_t)iso9660->current_position,
- (intmax_t)parent->offset);
- return (ARCHIVE_WARN);
- }
- if (parent->offset + parent->size > iso9660->volume_size) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Directory is beyond end-of-media: %s",
- parent->name.s);
- return (ARCHIVE_WARN);
- }
- if (iso9660->current_position < parent->offset) {
- int64_t skipsize;
-
- skipsize = parent->offset - iso9660->current_position;
- skipsize = __archive_read_consume(a, skipsize);
- if (skipsize < 0)
- return ((int)skipsize);
- iso9660->current_position = parent->offset;
- }
-
- step = (size_t)(((parent->size + iso9660->logical_block_size -1) /
- iso9660->logical_block_size) * iso9660->logical_block_size);
- b = __archive_read_ahead(a, step, NULL);
- if (b == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Failed to read full block when scanning "
- "ISO9660 directory list");
- return (ARCHIVE_FATAL);
- }
- iso9660->current_position += step;
- multi = NULL;
- skip_size = step;
- while (step) {
- p = b;
- b += iso9660->logical_block_size;
- step -= iso9660->logical_block_size;
- for (; *p != 0 && p < b && p + *p <= b; p += *p) {
- struct file_info *child;
-
- /* N.B.: these special directory identifiers
- * are 8 bit "values" even on a
- * Joliet CD with UCS-2 (16bit) encoding.
- */
-
- /* Skip '.' entry. */
- if (*(p + DR_name_len_offset) == 1
- && *(p + DR_name_offset) == '\0')
- continue;
- /* Skip '..' entry. */
- if (*(p + DR_name_len_offset) == 1
- && *(p + DR_name_offset) == '\001')
- continue;
- child = parse_file_info(a, parent, p);
- if (child == NULL) {
- __archive_read_consume(a, skip_size);
- return (ARCHIVE_FATAL);
- }
- if (child->cl_offset == 0 &&
- (child->multi_extent || multi != NULL)) {
- struct content *con;
-
- if (multi == NULL) {
- multi = child;
- multi->contents.first = NULL;
- multi->contents.last =
- &(multi->contents.first);
- }
- con = malloc(sizeof(struct content));
- if (con == NULL) {
- archive_set_error(
- &a->archive, ENOMEM,
- "No memory for multi extent");
- __archive_read_consume(a, skip_size);
- return (ARCHIVE_FATAL);
- }
- con->offset = child->offset;
- con->size = child->size;
- con->next = NULL;
- *multi->contents.last = con;
- multi->contents.last = &(con->next);
- if (multi == child) {
- if (add_entry(a, iso9660, child)
- != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- } else {
- multi->size += child->size;
- if (!child->multi_extent)
- multi = NULL;
- }
- } else
- if (add_entry(a, iso9660, child) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
- }
-
- __archive_read_consume(a, skip_size);
-
- /* Read data which recorded by RRIP "CE" extension. */
- if (read_CE(a, iso9660) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- return (ARCHIVE_OK);
-}
-
-static int
-choose_volume(struct archive_read *a, struct iso9660 *iso9660)
-{
- struct file_info *file;
- int64_t skipsize;
- struct vd *vd;
- const void *block;
- char seenJoliet;
-
- vd = &(iso9660->primary);
- if (!iso9660->opt_support_joliet)
- iso9660->seenJoliet = 0;
- if (iso9660->seenJoliet &&
- vd->location > iso9660->joliet.location)
- /* This condition is unlikely; by way of caution. */
- vd = &(iso9660->joliet);
-
- skipsize = LOGICAL_BLOCK_SIZE * vd->location;
- skipsize = __archive_read_consume(a, skipsize);
- if (skipsize < 0)
- return ((int)skipsize);
- iso9660->current_position = skipsize;
-
- block = __archive_read_ahead(a, vd->size, NULL);
- if (block == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Failed to read full block when scanning "
- "ISO9660 directory list");
- return (ARCHIVE_FATAL);
- }
-
- /*
- * While reading Root Directory, flag seenJoliet must be zero to
- * avoid converting special name 0x00(Current Directory) and
- * next byte to UCS2.
- */
- seenJoliet = iso9660->seenJoliet;/* Save flag. */
- iso9660->seenJoliet = 0;
- file = parse_file_info(a, NULL, block);
- if (file == NULL)
- return (ARCHIVE_FATAL);
- iso9660->seenJoliet = seenJoliet;
-
- /*
- * If the iso image has both RockRidge and Joliet, we preferentially
- * use RockRidge Extensions rather than Joliet ones.
- */
- if (vd == &(iso9660->primary) && iso9660->seenRockridge
- && iso9660->seenJoliet)
- iso9660->seenJoliet = 0;
-
- if (vd == &(iso9660->primary) && !iso9660->seenRockridge
- && iso9660->seenJoliet) {
- /* Switch reading data from primary to joliet. */
- vd = &(iso9660->joliet);
- skipsize = LOGICAL_BLOCK_SIZE * vd->location;
- skipsize -= iso9660->current_position;
- skipsize = __archive_read_consume(a, skipsize);
- if (skipsize < 0)
- return ((int)skipsize);
- iso9660->current_position += skipsize;
-
- block = __archive_read_ahead(a, vd->size, NULL);
- if (block == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Failed to read full block when scanning "
- "ISO9660 directory list");
- return (ARCHIVE_FATAL);
- }
- iso9660->seenJoliet = 0;
- file = parse_file_info(a, NULL, block);
- if (file == NULL)
- return (ARCHIVE_FATAL);
- iso9660->seenJoliet = seenJoliet;
- }
-
- /* Store the root directory in the pending list. */
- if (add_entry(a, iso9660, file) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- if (iso9660->seenRockridge) {
- a->archive.archive_format = ARCHIVE_FORMAT_ISO9660_ROCKRIDGE;
- a->archive.archive_format_name =
- "ISO9660 with Rockridge extensions";
- }
-
- return (ARCHIVE_OK);
-}
-
-static int
-archive_read_format_iso9660_read_header(struct archive_read *a,
- struct archive_entry *entry)
-{
- struct iso9660 *iso9660;
- struct file_info *file;
- int r, rd_r = ARCHIVE_OK;
-
- iso9660 = (struct iso9660 *)(a->format->data);
-
- if (!a->archive.archive_format) {
- a->archive.archive_format = ARCHIVE_FORMAT_ISO9660;
- a->archive.archive_format_name = "ISO9660";
- }
-
- if (iso9660->current_position == 0) {
- r = choose_volume(a, iso9660);
- if (r != ARCHIVE_OK)
- return (r);
- }
-
- file = NULL;/* Eliminate a warning. */
- /* Get the next entry that appears after the current offset. */
- r = next_entry_seek(a, iso9660, &file);
- if (r != ARCHIVE_OK)
- return (r);
-
- if (iso9660->seenJoliet) {
- /*
- * Convert UTF-16BE of a filename to local locale MBS
- * and store the result into a filename field.
- */
- if (iso9660->sconv_utf16be == NULL) {
- iso9660->sconv_utf16be =
- archive_string_conversion_from_charset(
- &(a->archive), "UTF-16BE", 1);
- if (iso9660->sconv_utf16be == NULL)
- /* Coundn't allocate memory */
- return (ARCHIVE_FATAL);
- }
- if (iso9660->utf16be_path == NULL) {
- iso9660->utf16be_path = malloc(UTF16_NAME_MAX);
- if (iso9660->utf16be_path == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "No memory");
- return (ARCHIVE_FATAL);
- }
- }
- if (iso9660->utf16be_previous_path == NULL) {
- iso9660->utf16be_previous_path = malloc(UTF16_NAME_MAX);
- if (iso9660->utf16be_previous_path == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "No memory");
- return (ARCHIVE_FATAL);
- }
- }
-
- iso9660->utf16be_path_len = 0;
- if (build_pathname_utf16be(iso9660->utf16be_path,
- UTF16_NAME_MAX, &(iso9660->utf16be_path_len), file) != 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Pathname is too long");
- }
-
- r = archive_entry_copy_pathname_l(entry,
- (const char *)iso9660->utf16be_path,
- iso9660->utf16be_path_len,
- iso9660->sconv_utf16be);
- if (r != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "No memory for Pathname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Pathname cannot be converted "
- "from %s to current locale.",
- archive_string_conversion_charset_name(
- iso9660->sconv_utf16be));
-
- rd_r = ARCHIVE_WARN;
- }
- } else {
- archive_string_empty(&iso9660->pathname);
- archive_entry_set_pathname(entry,
- build_pathname(&iso9660->pathname, file));
- }
-
- iso9660->entry_bytes_remaining = file->size;
- /* Offset for sparse-file-aware clients. */
- iso9660->entry_sparse_offset = 0;
-
- if (file->offset + file->size > iso9660->volume_size) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "File is beyond end-of-media: %s",
- archive_entry_pathname(entry));
- iso9660->entry_bytes_remaining = 0;
- return (ARCHIVE_WARN);
- }
-
- /* Set up the entry structure with information about this entry. */
- archive_entry_set_mode(entry, file->mode);
- archive_entry_set_uid(entry, file->uid);
- archive_entry_set_gid(entry, file->gid);
- archive_entry_set_nlink(entry, file->nlinks);
- if (file->birthtime_is_set)
- archive_entry_set_birthtime(entry, file->birthtime, 0);
- else
- archive_entry_unset_birthtime(entry);
- archive_entry_set_mtime(entry, file->mtime, 0);
- archive_entry_set_ctime(entry, file->ctime, 0);
- archive_entry_set_atime(entry, file->atime, 0);
- /* N.B.: Rock Ridge supports 64-bit device numbers. */
- archive_entry_set_rdev(entry, (dev_t)file->rdev);
- archive_entry_set_size(entry, iso9660->entry_bytes_remaining);
- if (file->symlink.s != NULL)
- archive_entry_copy_symlink(entry, file->symlink.s);
-
- /* Note: If the input isn't seekable, we can't rewind to
- * return the same body again, so if the next entry refers to
- * the same data, we have to return it as a hardlink to the
- * original entry. */
- if (file->number != -1 &&
- file->number == iso9660->previous_number) {
- if (iso9660->seenJoliet) {
- r = archive_entry_copy_hardlink_l(entry,
- (const char *)iso9660->utf16be_previous_path,
- iso9660->utf16be_previous_path_len,
- iso9660->sconv_utf16be);
- if (r != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "No memory for Linkname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Linkname cannot be converted "
- "from %s to current locale.",
- archive_string_conversion_charset_name(
- iso9660->sconv_utf16be));
- rd_r = ARCHIVE_WARN;
- }
- } else
- archive_entry_set_hardlink(entry,
- iso9660->previous_pathname.s);
- archive_entry_unset_size(entry);
- iso9660->entry_bytes_remaining = 0;
- return (rd_r);
- }
-
- if ((file->mode & AE_IFMT) != AE_IFDIR &&
- file->offset < iso9660->current_position) {
- int64_t r64;
-
- r64 = __archive_read_seek(a, file->offset, SEEK_SET);
- if (r64 != (int64_t)file->offset) {
- /* We can't seek backwards to extract it, so issue
- * a warning. Note that this can only happen if
- * this entry was added to the heap after we passed
- * this offset, that is, only if the directory
- * mentioning this entry is later than the body of
- * the entry. Such layouts are very unusual; most
- * ISO9660 writers lay out and record all directory
- * information first, then store all file bodies. */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Ignoring out-of-order file @%jx (%s) %jd < %jd",
- (intmax_t)file->number,
- iso9660->pathname.s,
- (intmax_t)file->offset,
- (intmax_t)iso9660->current_position);
- iso9660->entry_bytes_remaining = 0;
- return (ARCHIVE_WARN);
- }
- iso9660->current_position = (uint64_t)r64;
- }
-
- /* Initialize zisofs variables. */
- iso9660->entry_zisofs.pz = file->pz;
- if (file->pz) {
-#ifdef HAVE_ZLIB_H
- struct zisofs *zisofs;
-
- zisofs = &iso9660->entry_zisofs;
- zisofs->initialized = 0;
- zisofs->pz_log2_bs = file->pz_log2_bs;
- zisofs->pz_uncompressed_size = file->pz_uncompressed_size;
- zisofs->pz_offset = 0;
- zisofs->header_avail = 0;
- zisofs->header_passed = 0;
- zisofs->block_pointers_avail = 0;
-#endif
- archive_entry_set_size(entry, file->pz_uncompressed_size);
- }
-
- iso9660->previous_number = file->number;
- if (iso9660->seenJoliet) {
- memcpy(iso9660->utf16be_previous_path, iso9660->utf16be_path,
- iso9660->utf16be_path_len);
- iso9660->utf16be_previous_path_len = iso9660->utf16be_path_len;
- } else
- archive_strcpy(
- &iso9660->previous_pathname, iso9660->pathname.s);
-
- /* Reset entry_bytes_remaining if the file is multi extent. */
- iso9660->entry_content = file->contents.first;
- if (iso9660->entry_content != NULL)
- iso9660->entry_bytes_remaining = iso9660->entry_content->size;
-
- if (archive_entry_filetype(entry) == AE_IFDIR) {
- /* Overwrite nlinks by proper link number which is
- * calculated from number of sub directories. */
- archive_entry_set_nlink(entry, 2 + file->subdirs);
- /* Directory data has been read completely. */
- iso9660->entry_bytes_remaining = 0;
- }
-
- if (rd_r != ARCHIVE_OK)
- return (rd_r);
- return (ARCHIVE_OK);
-}
-
-static int
-archive_read_format_iso9660_read_data_skip(struct archive_read *a)
-{
- /* Because read_next_header always does an explicit skip
- * to the next entry, we don't need to do anything here. */
- (void)a; /* UNUSED */
- return (ARCHIVE_OK);
-}
-
-#ifdef HAVE_ZLIB_H
-
-static int
-zisofs_read_data(struct archive_read *a,
- const void **buff, size_t *size, int64_t *offset)
-{
- struct iso9660 *iso9660;
- struct zisofs *zisofs;
- const unsigned char *p;
- size_t avail;
- ssize_t bytes_read;
- size_t uncompressed_size;
- int r;
-
- iso9660 = (struct iso9660 *)(a->format->data);
- zisofs = &iso9660->entry_zisofs;
-
- p = __archive_read_ahead(a, 1, &bytes_read);
- if (bytes_read <= 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated zisofs file body");
- return (ARCHIVE_FATAL);
- }
- if (bytes_read > iso9660->entry_bytes_remaining)
- bytes_read = (ssize_t)iso9660->entry_bytes_remaining;
- avail = bytes_read;
- uncompressed_size = 0;
-
- if (!zisofs->initialized) {
- size_t ceil, xsize;
-
- /* Allocate block pointers buffer. */
- ceil = (size_t)((zisofs->pz_uncompressed_size +
- (((int64_t)1) << zisofs->pz_log2_bs) - 1)
- >> zisofs->pz_log2_bs);
- xsize = (ceil + 1) * 4;
- if (zisofs->block_pointers_alloc < xsize) {
- size_t alloc;
-
- if (zisofs->block_pointers != NULL)
- free(zisofs->block_pointers);
- alloc = ((xsize >> 10) + 1) << 10;
- zisofs->block_pointers = malloc(alloc);
- if (zisofs->block_pointers == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "No memory for zisofs decompression");
- return (ARCHIVE_FATAL);
- }
- zisofs->block_pointers_alloc = alloc;
- }
- zisofs->block_pointers_size = xsize;
-
- /* Allocate uncompressed data buffer. */
- xsize = (size_t)1UL << zisofs->pz_log2_bs;
- if (zisofs->uncompressed_buffer_size < xsize) {
- if (zisofs->uncompressed_buffer != NULL)
- free(zisofs->uncompressed_buffer);
- zisofs->uncompressed_buffer = malloc(xsize);
- if (zisofs->uncompressed_buffer == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "No memory for zisofs decompression");
- return (ARCHIVE_FATAL);
- }
- }
- zisofs->uncompressed_buffer_size = xsize;
-
- /*
- * Read the file header, and check the magic code of zisofs.
- */
- if (zisofs->header_avail < sizeof(zisofs->header)) {
- xsize = sizeof(zisofs->header) - zisofs->header_avail;
- if (avail < xsize)
- xsize = avail;
- memcpy(zisofs->header + zisofs->header_avail, p, xsize);
- zisofs->header_avail += xsize;
- avail -= xsize;
- p += xsize;
- }
- if (!zisofs->header_passed &&
- zisofs->header_avail == sizeof(zisofs->header)) {
- int err = 0;
-
- if (memcmp(zisofs->header, zisofs_magic,
- sizeof(zisofs_magic)) != 0)
- err = 1;
- if (archive_le32dec(zisofs->header + 8)
- != zisofs->pz_uncompressed_size)
- err = 1;
- if (zisofs->header[12] != 4)
- err = 1;
- if (zisofs->header[13] != zisofs->pz_log2_bs)
- err = 1;
- if (err) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Illegal zisofs file body");
- return (ARCHIVE_FATAL);
- }
- zisofs->header_passed = 1;
- }
- /*
- * Read block pointers.
- */
- if (zisofs->header_passed &&
- zisofs->block_pointers_avail < zisofs->block_pointers_size) {
- xsize = zisofs->block_pointers_size
- - zisofs->block_pointers_avail;
- if (avail < xsize)
- xsize = avail;
- memcpy(zisofs->block_pointers
- + zisofs->block_pointers_avail, p, xsize);
- zisofs->block_pointers_avail += xsize;
- avail -= xsize;
- p += xsize;
- if (zisofs->block_pointers_avail
- == zisofs->block_pointers_size) {
- /* We've got all block pointers and initialize
- * related variables. */
- zisofs->block_off = 0;
- zisofs->block_avail = 0;
- /* Complete a initialization */
- zisofs->initialized = 1;
- }
- }
-
- if (!zisofs->initialized)
- goto next_data; /* We need more data. */
- }
-
- /*
- * Get block offsets from block pointers.
- */
- if (zisofs->block_avail == 0) {
- uint32_t bst, bed;
-
- if (zisofs->block_off + 4 >= zisofs->block_pointers_size) {
- /* There isn't a pair of offsets. */
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Illegal zisofs block pointers");
- return (ARCHIVE_FATAL);
- }
- bst = archive_le32dec(
- zisofs->block_pointers + zisofs->block_off);
- if (bst != zisofs->pz_offset + (bytes_read - avail)) {
- /* TODO: Should we seek offset of current file
- * by bst ? */
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Illegal zisofs block pointers(cannot seek)");
- return (ARCHIVE_FATAL);
- }
- bed = archive_le32dec(
- zisofs->block_pointers + zisofs->block_off + 4);
- if (bed < bst) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Illegal zisofs block pointers");
- return (ARCHIVE_FATAL);
- }
- zisofs->block_avail = bed - bst;
- zisofs->block_off += 4;
-
- /* Initialize compression library for new block. */
- if (zisofs->stream_valid)
- r = inflateReset(&zisofs->stream);
- else
- r = inflateInit(&zisofs->stream);
- if (r != Z_OK) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Can't initialize zisofs decompression.");
- return (ARCHIVE_FATAL);
- }
- zisofs->stream_valid = 1;
- zisofs->stream.total_in = 0;
- zisofs->stream.total_out = 0;
- }
-
- /*
- * Make uncompressed data.
- */
- if (zisofs->block_avail == 0) {
- memset(zisofs->uncompressed_buffer, 0,
- zisofs->uncompressed_buffer_size);
- uncompressed_size = zisofs->uncompressed_buffer_size;
- } else {
- zisofs->stream.next_in = (Bytef *)(uintptr_t)(const void *)p;
- if (avail > zisofs->block_avail)
- zisofs->stream.avail_in = zisofs->block_avail;
- else
- zisofs->stream.avail_in = (uInt)avail;
- zisofs->stream.next_out = zisofs->uncompressed_buffer;
- zisofs->stream.avail_out =
- (uInt)zisofs->uncompressed_buffer_size;
-
- r = inflate(&zisofs->stream, 0);
- switch (r) {
- case Z_OK: /* Decompressor made some progress.*/
- case Z_STREAM_END: /* Found end of stream. */
- break;
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "zisofs decompression failed (%d)", r);
- return (ARCHIVE_FATAL);
- }
- uncompressed_size =
- zisofs->uncompressed_buffer_size - zisofs->stream.avail_out;
- avail -= zisofs->stream.next_in - p;
- zisofs->block_avail -= (uint32_t)(zisofs->stream.next_in - p);
- }
-next_data:
- bytes_read -= avail;
- *buff = zisofs->uncompressed_buffer;
- *size = uncompressed_size;
- *offset = iso9660->entry_sparse_offset;
- iso9660->entry_sparse_offset += uncompressed_size;
- iso9660->entry_bytes_remaining -= bytes_read;
- iso9660->current_position += bytes_read;
- zisofs->pz_offset += (uint32_t)bytes_read;
- iso9660->entry_bytes_unconsumed += bytes_read;
-
- return (ARCHIVE_OK);
-}
-
-#else /* HAVE_ZLIB_H */
-
-static int
-zisofs_read_data(struct archive_read *a,
- const void **buff, size_t *size, int64_t *offset)
-{
-
- (void)buff;/* UNUSED */
- (void)size;/* UNUSED */
- (void)offset;/* UNUSED */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "zisofs is not supported on this platform.");
- return (ARCHIVE_FAILED);
-}
-
-#endif /* HAVE_ZLIB_H */
-
-static int
-archive_read_format_iso9660_read_data(struct archive_read *a,
- const void **buff, size_t *size, int64_t *offset)
-{
- ssize_t bytes_read;
- struct iso9660 *iso9660;
-
- iso9660 = (struct iso9660 *)(a->format->data);
-
- if (iso9660->entry_bytes_unconsumed) {
- __archive_read_consume(a, iso9660->entry_bytes_unconsumed);
- iso9660->entry_bytes_unconsumed = 0;
- }
-
- if (iso9660->entry_bytes_remaining <= 0) {
- if (iso9660->entry_content != NULL)
- iso9660->entry_content = iso9660->entry_content->next;
- if (iso9660->entry_content == NULL) {
- *buff = NULL;
- *size = 0;
- *offset = iso9660->entry_sparse_offset;
- return (ARCHIVE_EOF);
- }
- /* Seek forward to the start of the entry. */
- if (iso9660->current_position < iso9660->entry_content->offset) {
- int64_t step;
-
- step = iso9660->entry_content->offset -
- iso9660->current_position;
- step = __archive_read_consume(a, step);
- if (step < 0)
- return ((int)step);
- iso9660->current_position =
- iso9660->entry_content->offset;
- }
- if (iso9660->entry_content->offset < iso9660->current_position) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Ignoring out-of-order file (%s) %jd < %jd",
- iso9660->pathname.s,
- (intmax_t)iso9660->entry_content->offset,
- (intmax_t)iso9660->current_position);
- *buff = NULL;
- *size = 0;
- *offset = iso9660->entry_sparse_offset;
- return (ARCHIVE_WARN);
- }
- iso9660->entry_bytes_remaining = iso9660->entry_content->size;
- }
- if (iso9660->entry_zisofs.pz)
- return (zisofs_read_data(a, buff, size, offset));
-
- *buff = __archive_read_ahead(a, 1, &bytes_read);
- if (bytes_read == 0)
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Truncated input file");
- if (*buff == NULL)
- return (ARCHIVE_FATAL);
- if (bytes_read > iso9660->entry_bytes_remaining)
- bytes_read = (ssize_t)iso9660->entry_bytes_remaining;
- *size = bytes_read;
- *offset = iso9660->entry_sparse_offset;
- iso9660->entry_sparse_offset += bytes_read;
- iso9660->entry_bytes_remaining -= bytes_read;
- iso9660->entry_bytes_unconsumed = bytes_read;
- iso9660->current_position += bytes_read;
- return (ARCHIVE_OK);
-}
-
-static int
-archive_read_format_iso9660_cleanup(struct archive_read *a)
-{
- struct iso9660 *iso9660;
- int r = ARCHIVE_OK;
-
- iso9660 = (struct iso9660 *)(a->format->data);
- release_files(iso9660);
- free(iso9660->read_ce_req.reqs);
- archive_string_free(&iso9660->pathname);
- archive_string_free(&iso9660->previous_pathname);
- if (iso9660->pending_files.files)
- free(iso9660->pending_files.files);
-#ifdef HAVE_ZLIB_H
- free(iso9660->entry_zisofs.uncompressed_buffer);
- free(iso9660->entry_zisofs.block_pointers);
- if (iso9660->entry_zisofs.stream_valid) {
- if (inflateEnd(&iso9660->entry_zisofs.stream) != Z_OK) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Failed to clean up zlib decompressor");
- r = ARCHIVE_FATAL;
- }
- }
-#endif
- free(iso9660->utf16be_path);
- free(iso9660->utf16be_previous_path);
- free(iso9660);
- (a->format->data) = NULL;
- return (r);
-}
-
-/*
- * This routine parses a single ISO directory record, makes sense
- * of any extensions, and stores the result in memory.
- */
-static struct file_info *
-parse_file_info(struct archive_read *a, struct file_info *parent,
- const unsigned char *isodirrec)
-{
- struct iso9660 *iso9660;
- struct file_info *file;
- size_t name_len;
- const unsigned char *rr_start, *rr_end;
- const unsigned char *p;
- size_t dr_len;
- uint64_t fsize;
- int32_t location;
- int flags;
-
- iso9660 = (struct iso9660 *)(a->format->data);
-
- dr_len = (size_t)isodirrec[DR_length_offset];
- name_len = (size_t)isodirrec[DR_name_len_offset];
- location = archive_le32dec(isodirrec + DR_extent_offset);
- fsize = toi(isodirrec + DR_size_offset, DR_size_size);
- /* Sanity check that dr_len needs at least 34. */
- if (dr_len < 34) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid length of directory record");
- return (NULL);
- }
- /* Sanity check that name_len doesn't exceed dr_len. */
- if (dr_len - 33 < name_len || name_len == 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid length of file identifier");
- return (NULL);
- }
- /* Sanity check that location doesn't exceed volume block.
- * Don't check lower limit of location; it's possibility
- * the location has negative value when file type is symbolic
- * link or file size is zero. As far as I know latest mkisofs
- * do that.
- */
- if (location > 0 &&
- (location + ((fsize + iso9660->logical_block_size -1)
- / iso9660->logical_block_size))
- > (uint32_t)iso9660->volume_block) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid location of extent of file");
- return (NULL);
- }
- /* Sanity check that location doesn't have a negative value
- * when the file is not empty. it's too large. */
- if (fsize != 0 && location < 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid location of extent of file");
- return (NULL);
- }
-
- /* Create a new file entry and copy data from the ISO dir record. */
- file = (struct file_info *)calloc(1, sizeof(*file));
- if (file == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "No memory for file entry");
- return (NULL);
- }
- file->parent = parent;
- file->offset = iso9660->logical_block_size * (uint64_t)location;
- file->size = fsize;
- file->mtime = isodate7(isodirrec + DR_date_offset);
- file->ctime = file->atime = file->mtime;
- file->rede_files.first = NULL;
- file->rede_files.last = &(file->rede_files.first);
-
- p = isodirrec + DR_name_offset;
- /* Rockridge extensions (if any) follow name. Compute this
- * before fidgeting the name_len below. */
- rr_start = p + name_len + (name_len & 1 ? 0 : 1);
- rr_end = isodirrec + dr_len;
-
- if (iso9660->seenJoliet) {
- /* Joliet names are max 64 chars (128 bytes) according to spec,
- * but genisoimage/mkisofs allows recording longer Joliet
- * names which are 103 UCS2 characters(206 bytes) by their
- * option '-joliet-long'.
- */
- if (name_len > 206)
- name_len = 206;
- name_len &= ~1;
-
- /* trim trailing first version and dot from filename.
- *
- * Remember we were in UTF-16BE land!
- * SEPARATOR 1 (.) and SEPARATOR 2 (;) are both
- * 16 bits big endian characters on Joliet.
- *
- * TODO: sanitize filename?
- * Joliet allows any UCS-2 char except:
- * *, /, :, ;, ? and \.
- */
- /* Chop off trailing ';1' from files. */
- if (name_len > 4 && p[name_len-4] == 0 && p[name_len-3] == ';'
- && p[name_len-2] == 0 && p[name_len-1] == '1')
- name_len -= 4;
-#if 0 /* XXX: this somehow manages to strip of single-character file extensions, like '.c'. */
- /* Chop off trailing '.' from filenames. */
- if (name_len > 2 && p[name_len-2] == 0 && p[name_len-1] == '.')
- name_len -= 2;
-#endif
- if ((file->utf16be_name = malloc(name_len)) == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "No memory for file name");
- return (NULL);
- }
- memcpy(file->utf16be_name, p, name_len);
- file->utf16be_bytes = name_len;
- } else {
- /* Chop off trailing ';1' from files. */
- if (name_len > 2 && p[name_len - 2] == ';' &&
- p[name_len - 1] == '1')
- name_len -= 2;
- /* Chop off trailing '.' from filenames. */
- if (name_len > 1 && p[name_len - 1] == '.')
- --name_len;
-
- archive_strncpy(&file->name, (const char *)p, name_len);
- }
-
- flags = isodirrec[DR_flags_offset];
- if (flags & 0x02)
- file->mode = AE_IFDIR | 0700;
- else
- file->mode = AE_IFREG | 0400;
- if (flags & 0x80)
- file->multi_extent = 1;
- else
- file->multi_extent = 0;
- /*
- * Use a location for the file number, which is treated as an inode
- * number to find out hardlink target. If Rockridge extensions is
- * being used, the file number will be overwritten by FILE SERIAL
- * NUMBER of RRIP "PX" extension.
- * Note: Old mkisofs did not record that FILE SERIAL NUMBER
- * in ISO images.
- * Note2: xorriso set 0 to the location of a symlink file.
- */
- if (file->size == 0 && location >= 0) {
- /* If file->size is zero, its location points wrong place,
- * and so we should not use it for the file number.
- * When the location has negative value, it can be used
- * for the file number.
- */
- file->number = -1;
- /* Do not appear before any directory entries. */
- file->offset = -1;
- } else
- file->number = (int64_t)(uint32_t)location;
-
- /* Rockridge extensions overwrite information from above. */
- if (iso9660->opt_support_rockridge) {
- if (parent == NULL && rr_end - rr_start >= 7) {
- p = rr_start;
- if (memcmp(p, "SP\x07\x01\xbe\xef", 6) == 0) {
- /*
- * SP extension stores the suspOffset
- * (Number of bytes to skip between
- * filename and SUSP records.)
- * It is mandatory by the SUSP standard
- * (IEEE 1281).
- *
- * It allows SUSP to coexist with
- * non-SUSP uses of the System
- * Use Area by placing non-SUSP data
- * before SUSP data.
- *
- * SP extension must be in the root
- * directory entry, disable all SUSP
- * processing if not found.
- */
- iso9660->suspOffset = p[6];
- iso9660->seenSUSP = 1;
- rr_start += 7;
- }
- }
- if (iso9660->seenSUSP) {
- int r;
-
- file->name_continues = 0;
- file->symlink_continues = 0;
- rr_start += iso9660->suspOffset;
- r = parse_rockridge(a, file, rr_start, rr_end);
- if (r != ARCHIVE_OK) {
- free(file);
- return (NULL);
- }
- /*
- * A file size of symbolic link files in ISO images
- * made by makefs is not zero and its location is
- * the same as those of next regular file. That is
- * the same as hard like file and it causes unexpected
- * error.
- */
- if (file->size > 0 &&
- (file->mode & AE_IFMT) == AE_IFLNK) {
- file->size = 0;
- file->number = -1;
- file->offset = -1;
- }
- } else
- /* If there isn't SUSP, disable parsing
- * rock ridge extensions. */
- iso9660->opt_support_rockridge = 0;
- }
-
- file->nlinks = 1;/* Reset nlink. we'll calculate it later. */
- /* Tell file's parent how many children that parent has. */
- if (parent != NULL && (flags & 0x02))
- parent->subdirs++;
-
- if (iso9660->seenRockridge) {
- if (parent != NULL && parent->parent == NULL &&
- (flags & 0x02) && iso9660->rr_moved == NULL &&
- file->name.s &&
- (strcmp(file->name.s, "rr_moved") == 0 ||
- strcmp(file->name.s, ".rr_moved") == 0)) {
- iso9660->rr_moved = file;
- file->rr_moved = 1;
- file->rr_moved_has_re_only = 1;
- file->re = 0;
- parent->subdirs--;
- } else if (file->re) {
- /*
- * Sanity check: file's parent is rr_moved.
- */
- if (parent == NULL || parent->rr_moved == 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Invalid Rockridge RE");
- return (NULL);
- }
- /*
- * Sanity check: file does not have "CL" extension.
- */
- if (file->cl_offset) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Invalid Rockridge RE and CL");
- return (NULL);
- }
- /*
- * Sanity check: The file type must be a directory.
- */
- if ((flags & 0x02) == 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Invalid Rockridge RE");
- return (NULL);
- }
- } else if (parent != NULL && parent->rr_moved)
- file->rr_moved_has_re_only = 0;
- else if (parent != NULL && (flags & 0x02) &&
- (parent->re || parent->re_descendant))
- file->re_descendant = 1;
- if (file->cl_offset) {
- struct file_info *r;
-
- if (parent == NULL || parent->parent == NULL) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Invalid Rockridge CL");
- return (NULL);
- }
- /*
- * Sanity check: The file type must be a regular file.
- */
- if ((flags & 0x02) != 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Invalid Rockridge CL");
- return (NULL);
- }
- parent->subdirs++;
- /* Overwrite an offset and a number of this "CL" entry
- * to appear before other dirs. "+1" to those is to
- * make sure to appear after "RE" entry which this
- * "CL" entry should be connected with. */
- file->offset = file->number = file->cl_offset + 1;
-
- /*
- * Sanity check: cl_offset does not point at its
- * the parents or itself.
- */
- for (r = parent; r; r = r->parent) {
- if (r->offset == file->cl_offset) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Invalid Rockridge CL");
- return (NULL);
- }
- }
- if (file->cl_offset == file->offset ||
- parent->rr_moved) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Invalid Rockridge CL");
- return (NULL);
- }
- }
- }
-
-#if DEBUG
- /* DEBUGGING: Warn about attributes I don't yet fully support. */
- if ((flags & ~0x02) != 0) {
- fprintf(stderr, "\n ** Unrecognized flag: ");
- dump_isodirrec(stderr, isodirrec);
- fprintf(stderr, "\n");
- } else if (toi(isodirrec + DR_volume_sequence_number_offset, 2) != 1) {
- fprintf(stderr, "\n ** Unrecognized sequence number: ");
- dump_isodirrec(stderr, isodirrec);
- fprintf(stderr, "\n");
- } else if (*(isodirrec + DR_file_unit_size_offset) != 0) {
- fprintf(stderr, "\n ** Unexpected file unit size: ");
- dump_isodirrec(stderr, isodirrec);
- fprintf(stderr, "\n");
- } else if (*(isodirrec + DR_interleave_offset) != 0) {
- fprintf(stderr, "\n ** Unexpected interleave: ");
- dump_isodirrec(stderr, isodirrec);
- fprintf(stderr, "\n");
- } else if (*(isodirrec + DR_ext_attr_length_offset) != 0) {
- fprintf(stderr, "\n ** Unexpected extended attribute length: ");
- dump_isodirrec(stderr, isodirrec);
- fprintf(stderr, "\n");
- }
-#endif
- register_file(iso9660, file);
- return (file);
-}
-
-static int
-parse_rockridge(struct archive_read *a, struct file_info *file,
- const unsigned char *p, const unsigned char *end)
-{
- struct iso9660 *iso9660;
-
- iso9660 = (struct iso9660 *)(a->format->data);
-
- while (p + 4 <= end /* Enough space for another entry. */
- && p[0] >= 'A' && p[0] <= 'Z' /* Sanity-check 1st char of name. */
- && p[1] >= 'A' && p[1] <= 'Z' /* Sanity-check 2nd char of name. */
- && p[2] >= 4 /* Sanity-check length. */
- && p + p[2] <= end) { /* Sanity-check length. */
- const unsigned char *data = p + 4;
- int data_length = p[2] - 4;
- int version = p[3];
-
- switch(p[0]) {
- case 'C':
- if (p[1] == 'E') {
- if (version == 1 && data_length == 24) {
- /*
- * CE extension comprises:
- * 8 byte sector containing extension
- * 8 byte offset w/in above sector
- * 8 byte length of continuation
- */
- int32_t location =
- archive_le32dec(data);
- file->ce_offset =
- archive_le32dec(data+8);
- file->ce_size =
- archive_le32dec(data+16);
- if (register_CE(a, location, file)
- != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
- }
- else if (p[1] == 'L') {
- if (version == 1 && data_length == 8) {
- file->cl_offset = (uint64_t)
- iso9660->logical_block_size *
- (uint64_t)archive_le32dec(data);
- iso9660->seenRockridge = 1;
- }
- }
- break;
- case 'N':
- if (p[1] == 'M') {
- if (version == 1) {
- parse_rockridge_NM1(file,
- data, data_length);
- iso9660->seenRockridge = 1;
- }
- }
- break;
- case 'P':
- /*
- * PD extension is padding;
- * contents are always ignored.
- *
- * PL extension won't appear;
- * contents are always ignored.
- */
- if (p[1] == 'N') {
- if (version == 1 && data_length == 16) {
- file->rdev = toi(data,4);
- file->rdev <<= 32;
- file->rdev |= toi(data + 8, 4);
- iso9660->seenRockridge = 1;
- }
- }
- else if (p[1] == 'X') {
- /*
- * PX extension comprises:
- * 8 bytes for mode,
- * 8 bytes for nlinks,
- * 8 bytes for uid,
- * 8 bytes for gid,
- * 8 bytes for inode.
- */
- if (version == 1) {
- if (data_length >= 8)
- file->mode
- = toi(data, 4);
- if (data_length >= 16)
- file->nlinks
- = toi(data + 8, 4);
- if (data_length >= 24)
- file->uid
- = toi(data + 16, 4);
- if (data_length >= 32)
- file->gid
- = toi(data + 24, 4);
- if (data_length >= 40)
- file->number
- = toi(data + 32, 4);
- iso9660->seenRockridge = 1;
- }
- }
- break;
- case 'R':
- if (p[1] == 'E' && version == 1) {
- file->re = 1;
- iso9660->seenRockridge = 1;
- }
- else if (p[1] == 'R' && version == 1) {
- /*
- * RR extension comprises:
- * one byte flag value
- * This extension is obsolete,
- * so contents are always ignored.
- */
- }
- break;
- case 'S':
- if (p[1] == 'L') {
- if (version == 1) {
- parse_rockridge_SL1(file,
- data, data_length);
- iso9660->seenRockridge = 1;
- }
- }
- else if (p[1] == 'T'
- && data_length == 0 && version == 1) {
- /*
- * ST extension marks end of this
- * block of SUSP entries.
- *
- * It allows SUSP to coexist with
- * non-SUSP uses of the System
- * Use Area by placing non-SUSP data
- * after SUSP data.
- */
- iso9660->seenSUSP = 0;
- iso9660->seenRockridge = 0;
- return (ARCHIVE_OK);
- }
- break;
- case 'T':
- if (p[1] == 'F') {
- if (version == 1) {
- parse_rockridge_TF1(file,
- data, data_length);
- iso9660->seenRockridge = 1;
- }
- }
- break;
- case 'Z':
- if (p[1] == 'F') {
- if (version == 1)
- parse_rockridge_ZF1(file,
- data, data_length);
- }
- break;
- default:
- break;
- }
-
- p += p[2];
- }
- return (ARCHIVE_OK);
-}
-
-static int
-register_CE(struct archive_read *a, int32_t location,
- struct file_info *file)
-{
- struct iso9660 *iso9660;
- struct read_ce_queue *heap;
- struct read_ce_req *p;
- uint64_t offset, parent_offset;
- int hole, parent;
-
- iso9660 = (struct iso9660 *)(a->format->data);
- offset = ((uint64_t)location) * (uint64_t)iso9660->logical_block_size;
- if (((file->mode & AE_IFMT) == AE_IFREG &&
- offset >= file->offset) ||
- offset < iso9660->current_position ||
- (((uint64_t)file->ce_offset) + file->ce_size)
- > (uint64_t)iso9660->logical_block_size ||
- offset + file->ce_offset + file->ce_size
- > iso9660->volume_size) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid parameter in SUSP \"CE\" extension");
- return (ARCHIVE_FATAL);
- }
-
- /* Expand our CE list as necessary. */
- heap = &(iso9660->read_ce_req);
- if (heap->cnt >= heap->allocated) {
- int new_size;
-
- if (heap->allocated < 16)
- new_size = 16;
- else
- new_size = heap->allocated * 2;
- /* Overflow might keep us from growing the list. */
- if (new_size <= heap->allocated) {
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- p = calloc(new_size, sizeof(p[0]));
- if (p == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- if (heap->reqs != NULL) {
- memcpy(p, heap->reqs, heap->cnt * sizeof(*p));
- free(heap->reqs);
- }
- heap->reqs = p;
- heap->allocated = new_size;
- }
-
- /*
- * Start with hole at end, walk it up tree to find insertion point.
- */
- hole = heap->cnt++;
- while (hole > 0) {
- parent = (hole - 1)/2;
- parent_offset = heap->reqs[parent].offset;
- if (offset >= parent_offset) {
- heap->reqs[hole].offset = offset;
- heap->reqs[hole].file = file;
- return (ARCHIVE_OK);
- }
- /* Move parent into hole <==> move hole up tree. */
- heap->reqs[hole] = heap->reqs[parent];
- hole = parent;
- }
- heap->reqs[0].offset = offset;
- heap->reqs[0].file = file;
- return (ARCHIVE_OK);
-}
-
-static void
-next_CE(struct read_ce_queue *heap)
-{
- uint64_t a_offset, b_offset, c_offset;
- int a, b, c;
- struct read_ce_req tmp;
-
- if (heap->cnt < 1)
- return;
-
- /*
- * Move the last item in the heap to the root of the tree
- */
- heap->reqs[0] = heap->reqs[--(heap->cnt)];
-
- /*
- * Rebalance the heap.
- */
- a = 0; /* Starting element and its offset */
- a_offset = heap->reqs[a].offset;
- for (;;) {
- b = a + a + 1; /* First child */
- if (b >= heap->cnt)
- return;
- b_offset = heap->reqs[b].offset;
- c = b + 1; /* Use second child if it is smaller. */
- if (c < heap->cnt) {
- c_offset = heap->reqs[c].offset;
- if (c_offset < b_offset) {
- b = c;
- b_offset = c_offset;
- }
- }
- if (a_offset <= b_offset)
- return;
- tmp = heap->reqs[a];
- heap->reqs[a] = heap->reqs[b];
- heap->reqs[b] = tmp;
- a = b;
- }
-}
-
-
-static int
-read_CE(struct archive_read *a, struct iso9660 *iso9660)
-{
- struct read_ce_queue *heap;
- const unsigned char *b, *p, *end;
- struct file_info *file;
- size_t step;
- int r;
-
- /* Read data which RRIP "CE" extension points. */
- heap = &(iso9660->read_ce_req);
- step = iso9660->logical_block_size;
- while (heap->cnt &&
- heap->reqs[0].offset == iso9660->current_position) {
- b = __archive_read_ahead(a, step, NULL);
- if (b == NULL) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Failed to read full block when scanning "
- "ISO9660 directory list");
- return (ARCHIVE_FATAL);
- }
- do {
- file = heap->reqs[0].file;
- if (file->ce_offset + file->ce_size > step) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Malformed CE information");
- return (ARCHIVE_FATAL);
- }
- p = b + file->ce_offset;
- end = p + file->ce_size;
- next_CE(heap);
- r = parse_rockridge(a, file, p, end);
- if (r != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- } while (heap->cnt &&
- heap->reqs[0].offset == iso9660->current_position);
- /* NOTE: Do not move this consume's code to fron of
- * do-while loop. Registration of nested CE extension
- * might cause error because of current position. */
- __archive_read_consume(a, step);
- iso9660->current_position += step;
- }
- return (ARCHIVE_OK);
-}
-
-static void
-parse_rockridge_NM1(struct file_info *file,
- const unsigned char *data, int data_length)
-{
- if (!file->name_continues)
- archive_string_empty(&file->name);
- file->name_continues = 0;
- if (data_length < 1)
- return;
- /*
- * NM version 1 extension comprises:
- * 1 byte flag, value is one of:
- * = 0: remainder is name
- * = 1: remainder is name, next NM entry continues name
- * = 2: "."
- * = 4: ".."
- * = 32: Implementation specific
- * All other values are reserved.
- */
- switch(data[0]) {
- case 0:
- if (data_length < 2)
- return;
- archive_strncat(&file->name,
- (const char *)data + 1, data_length - 1);
- break;
- case 1:
- if (data_length < 2)
- return;
- archive_strncat(&file->name,
- (const char *)data + 1, data_length - 1);
- file->name_continues = 1;
- break;
- case 2:
- archive_strcat(&file->name, ".");
- break;
- case 4:
- archive_strcat(&file->name, "..");
- break;
- default:
- return;
- }
-
-}
-
-static void
-parse_rockridge_TF1(struct file_info *file, const unsigned char *data,
- int data_length)
-{
- char flag;
- /*
- * TF extension comprises:
- * one byte flag
- * create time (optional)
- * modify time (optional)
- * access time (optional)
- * attribute time (optional)
- * Time format and presence of fields
- * is controlled by flag bits.
- */
- if (data_length < 1)
- return;
- flag = data[0];
- ++data;
- --data_length;
- if (flag & 0x80) {
- /* Use 17-byte time format. */
- if ((flag & 1) && data_length >= 17) {
- /* Create time. */
- file->birthtime_is_set = 1;
- file->birthtime = isodate17(data);
- data += 17;
- data_length -= 17;
- }
- if ((flag & 2) && data_length >= 17) {
- /* Modify time. */
- file->mtime = isodate17(data);
- data += 17;
- data_length -= 17;
- }
- if ((flag & 4) && data_length >= 17) {
- /* Access time. */
- file->atime = isodate17(data);
- data += 17;
- data_length -= 17;
- }
- if ((flag & 8) && data_length >= 17) {
- /* Attribute change time. */
- file->ctime = isodate17(data);
- }
- } else {
- /* Use 7-byte time format. */
- if ((flag & 1) && data_length >= 7) {
- /* Create time. */
- file->birthtime_is_set = 1;
- file->birthtime = isodate7(data);
- data += 7;
- data_length -= 7;
- }
- if ((flag & 2) && data_length >= 7) {
- /* Modify time. */
- file->mtime = isodate7(data);
- data += 7;
- data_length -= 7;
- }
- if ((flag & 4) && data_length >= 7) {
- /* Access time. */
- file->atime = isodate7(data);
- data += 7;
- data_length -= 7;
- }
- if ((flag & 8) && data_length >= 7) {
- /* Attribute change time. */
- file->ctime = isodate7(data);
- }
- }
-}
-
-static void
-parse_rockridge_SL1(struct file_info *file, const unsigned char *data,
- int data_length)
-{
- const char *separator = "";
-
- if (!file->symlink_continues || file->symlink.length < 1)
- archive_string_empty(&file->symlink);
- file->symlink_continues = 0;
-
- /*
- * Defined flag values:
- * 0: This is the last SL record for this symbolic link
- * 1: this symbolic link field continues in next SL entry
- * All other values are reserved.
- */
- if (data_length < 1)
- return;
- switch(*data) {
- case 0:
- break;
- case 1:
- file->symlink_continues = 1;
- break;
- default:
- return;
- }
- ++data; /* Skip flag byte. */
- --data_length;
-
- /*
- * SL extension body stores "components".
- * Basically, this is a complicated way of storing
- * a POSIX path. It also interferes with using
- * symlinks for storing non-path data. <sigh>
- *
- * Each component is 2 bytes (flag and length)
- * possibly followed by name data.
- */
- while (data_length >= 2) {
- unsigned char flag = *data++;
- unsigned char nlen = *data++;
- data_length -= 2;
-
- archive_strcat(&file->symlink, separator);
- separator = "/";
-
- switch(flag) {
- case 0: /* Usual case, this is text. */
- if (data_length < nlen)
- return;
- archive_strncat(&file->symlink,
- (const char *)data, nlen);
- break;
- case 0x01: /* Text continues in next component. */
- if (data_length < nlen)
- return;
- archive_strncat(&file->symlink,
- (const char *)data, nlen);
- separator = "";
- break;
- case 0x02: /* Current dir. */
- archive_strcat(&file->symlink, ".");
- break;
- case 0x04: /* Parent dir. */
- archive_strcat(&file->symlink, "..");
- break;
- case 0x08: /* Root of filesystem. */
- archive_strcat(&file->symlink, "/");
- separator = "";
- break;
- case 0x10: /* Undefined (historically "volume root" */
- archive_string_empty(&file->symlink);
- archive_strcat(&file->symlink, "ROOT");
- break;
- case 0x20: /* Undefined (historically "hostname") */
- archive_strcat(&file->symlink, "hostname");
- break;
- default:
- /* TODO: issue a warning ? */
- return;
- }
- data += nlen;
- data_length -= nlen;
- }
-}
-
-static void
-parse_rockridge_ZF1(struct file_info *file, const unsigned char *data,
- int data_length)
-{
-
- if (data[0] == 0x70 && data[1] == 0x7a && data_length == 12) {
- /* paged zlib */
- file->pz = 1;
- file->pz_log2_bs = data[3];
- file->pz_uncompressed_size = archive_le32dec(&data[4]);
- }
-}
-
-static void
-register_file(struct iso9660 *iso9660, struct file_info *file)
-{
-
- file->use_next = iso9660->use_files;
- iso9660->use_files = file;
-}
-
-static void
-release_files(struct iso9660 *iso9660)
-{
- struct content *con, *connext;
- struct file_info *file;
-
- file = iso9660->use_files;
- while (file != NULL) {
- struct file_info *next = file->use_next;
-
- archive_string_free(&file->name);
- archive_string_free(&file->symlink);
- free(file->utf16be_name);
- con = file->contents.first;
- while (con != NULL) {
- connext = con->next;
- free(con);
- con = connext;
- }
- free(file);
- file = next;
- }
-}
-
-static int
-next_entry_seek(struct archive_read *a, struct iso9660 *iso9660,
- struct file_info **pfile)
-{
- struct file_info *file;
- int r;
-
- r = next_cache_entry(a, iso9660, pfile);
- if (r != ARCHIVE_OK)
- return (r);
- file = *pfile;
-
- /* Don't waste time seeking for zero-length bodies. */
- if (file->size == 0)
- file->offset = iso9660->current_position;
-
- /* flush any remaining bytes from the last round to ensure
- * we're positioned */
- if (iso9660->entry_bytes_unconsumed) {
- __archive_read_consume(a, iso9660->entry_bytes_unconsumed);
- iso9660->entry_bytes_unconsumed = 0;
- }
-
- /* Seek forward to the start of the entry. */
- if (iso9660->current_position < file->offset) {
- int64_t step;
-
- step = file->offset - iso9660->current_position;
- step = __archive_read_consume(a, step);
- if (step < 0)
- return ((int)step);
- iso9660->current_position = file->offset;
- }
-
- /* We found body of file; handle it now. */
- return (ARCHIVE_OK);
-}
-
-static int
-next_cache_entry(struct archive_read *a, struct iso9660 *iso9660,
- struct file_info **pfile)
-{
- struct file_info *file;
- struct {
- struct file_info *first;
- struct file_info **last;
- } empty_files;
- int64_t number;
- int count;
-
- file = cache_get_entry(iso9660);
- if (file != NULL) {
- *pfile = file;
- return (ARCHIVE_OK);
- }
-
- for (;;) {
- struct file_info *re, *d;
-
- *pfile = file = next_entry(iso9660);
- if (file == NULL) {
- /*
- * If directory entries all which are descendant of
- * rr_moved are stil remaning, expose their.
- */
- if (iso9660->re_files.first != NULL &&
- iso9660->rr_moved != NULL &&
- iso9660->rr_moved->rr_moved_has_re_only)
- /* Expose "rr_moved" entry. */
- cache_add_entry(iso9660, iso9660->rr_moved);
- while ((re = re_get_entry(iso9660)) != NULL) {
- /* Expose its descendant dirs. */
- while ((d = rede_get_entry(re)) != NULL)
- cache_add_entry(iso9660, d);
- }
- if (iso9660->cache_files.first != NULL)
- return (next_cache_entry(a, iso9660, pfile));
- return (ARCHIVE_EOF);
- }
-
- if (file->cl_offset) {
- struct file_info *first_re = NULL;
- int nexted_re = 0;
-
- /*
- * Find "RE" dir for the current file, which
- * has "CL" flag.
- */
- while ((re = re_get_entry(iso9660))
- != first_re) {
- if (first_re == NULL)
- first_re = re;
- if (re->offset == file->cl_offset) {
- re->parent->subdirs--;
- re->parent = file->parent;
- re->re = 0;
- if (re->parent->re_descendant) {
- nexted_re = 1;
- re->re_descendant = 1;
- if (rede_add_entry(re) < 0)
- goto fatal_rr;
- /* Move a list of descendants
- * to a new ancestor. */
- while ((d = rede_get_entry(
- re)) != NULL)
- if (rede_add_entry(d)
- < 0)
- goto fatal_rr;
- break;
- }
- /* Replace the current file
- * with "RE" dir */
- *pfile = file = re;
- /* Expose its descendant */
- while ((d = rede_get_entry(
- file)) != NULL)
- cache_add_entry(
- iso9660, d);
- break;
- } else
- re_add_entry(iso9660, re);
- }
- if (nexted_re) {
- /*
- * Do not expose this at this time
- * because we have not gotten its full-path
- * name yet.
- */
- continue;
- }
- } else if ((file->mode & AE_IFMT) == AE_IFDIR) {
- int r;
-
- /* Read file entries in this dir. */
- r = read_children(a, file);
- if (r != ARCHIVE_OK)
- return (r);
-
- /*
- * Handle a special dir of Rockridge extensions,
- * "rr_moved".
- */
- if (file->rr_moved) {
- /*
- * If this has only the subdirectories which
- * have "RE" flags, do not expose at this time.
- */
- if (file->rr_moved_has_re_only)
- continue;
- /* Otherwise expose "rr_moved" entry. */
- } else if (file->re) {
- /*
- * Do not expose this at this time
- * because we have not gotten its full-path
- * name yet.
- */
- re_add_entry(iso9660, file);
- continue;
- } else if (file->re_descendant) {
- /*
- * If the top level "RE" entry of this entry
- * is not exposed, we, accordingly, should not
- * expose this entry at this time because
- * we cannot make its proper full-path name.
- */
- if (rede_add_entry(file) == 0)
- continue;
- /* Otherwise we can expose this entry because
- * it seems its top level "RE" has already been
- * exposed. */
- }
- }
- break;
- }
-
- if ((file->mode & AE_IFMT) != AE_IFREG || file->number == -1)
- return (ARCHIVE_OK);
-
- count = 0;
- number = file->number;
- iso9660->cache_files.first = NULL;
- iso9660->cache_files.last = &(iso9660->cache_files.first);
- empty_files.first = NULL;
- empty_files.last = &empty_files.first;
- /* Collect files which has the same file serial number.
- * Peek pending_files so that file which number is different
- * is not put bak. */
- while (iso9660->pending_files.used > 0 &&
- (iso9660->pending_files.files[0]->number == -1 ||
- iso9660->pending_files.files[0]->number == number)) {
- if (file->number == -1) {
- /* This file has the same offset
- * but it's wrong offset which empty files
- * and symlink files have.
- * NOTE: This wrong offse was recorded by
- * old mkisofs utility. If ISO images is
- * created by latest mkisofs, this does not
- * happen.
- */
- file->next = NULL;
- *empty_files.last = file;
- empty_files.last = &(file->next);
- } else {
- count++;
- cache_add_entry(iso9660, file);
- }
- file = next_entry(iso9660);
- }
-
- if (count == 0) {
- *pfile = file;
- return ((file == NULL)?ARCHIVE_EOF:ARCHIVE_OK);
- }
- if (file->number == -1) {
- file->next = NULL;
- *empty_files.last = file;
- empty_files.last = &(file->next);
- } else {
- count++;
- cache_add_entry(iso9660, file);
- }
-
- if (count > 1) {
- /* The count is the same as number of hardlink,
- * so much so that each nlinks of files in cache_file
- * is overwritten by value of the count.
- */
- for (file = iso9660->cache_files.first;
- file != NULL; file = file->next)
- file->nlinks = count;
- }
- /* If there are empty files, that files are added
- * to the tail of the cache_files. */
- if (empty_files.first != NULL) {
- *iso9660->cache_files.last = empty_files.first;
- iso9660->cache_files.last = empty_files.last;
- }
- *pfile = cache_get_entry(iso9660);
- return ((*pfile == NULL)?ARCHIVE_EOF:ARCHIVE_OK);
-
-fatal_rr:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Failed to connect 'CL' pointer to 'RE' rr_moved pointer of "
- "Rockridge extensions: current position = %jd, CL offset = %jd",
- (intmax_t)iso9660->current_position, (intmax_t)file->cl_offset);
- return (ARCHIVE_FATAL);
-}
-
-static inline void
-re_add_entry(struct iso9660 *iso9660, struct file_info *file)
-{
- file->re_next = NULL;
- *iso9660->re_files.last = file;
- iso9660->re_files.last = &(file->re_next);
-}
-
-static inline struct file_info *
-re_get_entry(struct iso9660 *iso9660)
-{
- struct file_info *file;
-
- if ((file = iso9660->re_files.first) != NULL) {
- iso9660->re_files.first = file->re_next;
- if (iso9660->re_files.first == NULL)
- iso9660->re_files.last =
- &(iso9660->re_files.first);
- }
- return (file);
-}
-
-static inline int
-rede_add_entry(struct file_info *file)
-{
- struct file_info *re;
-
- /*
- * Find "RE" entry.
- */
- re = file->parent;
- while (re != NULL && !re->re)
- re = re->parent;
- if (re == NULL)
- return (-1);
-
- file->re_next = NULL;
- *re->rede_files.last = file;
- re->rede_files.last = &(file->re_next);
- return (0);
-}
-
-static inline struct file_info *
-rede_get_entry(struct file_info *re)
-{
- struct file_info *file;
-
- if ((file = re->rede_files.first) != NULL) {
- re->rede_files.first = file->re_next;
- if (re->rede_files.first == NULL)
- re->rede_files.last =
- &(re->rede_files.first);
- }
- return (file);
-}
-
-static inline void
-cache_add_entry(struct iso9660 *iso9660, struct file_info *file)
-{
- file->next = NULL;
- *iso9660->cache_files.last = file;
- iso9660->cache_files.last = &(file->next);
-}
-
-static inline struct file_info *
-cache_get_entry(struct iso9660 *iso9660)
-{
- struct file_info *file;
-
- if ((file = iso9660->cache_files.first) != NULL) {
- iso9660->cache_files.first = file->next;
- if (iso9660->cache_files.first == NULL)
- iso9660->cache_files.last =
- &(iso9660->cache_files.first);
- }
- return (file);
-}
-
-static int
-heap_add_entry(struct archive_read *a, struct heap_queue *heap,
- struct file_info *file, uint64_t key)
-{
- uint64_t file_key, parent_key;
- int hole, parent;
-
- /* Expand our pending files list as necessary. */
- if (heap->used >= heap->allocated) {
- struct file_info **new_pending_files;
- int new_size = heap->allocated * 2;
-
- if (heap->allocated < 1024)
- new_size = 1024;
- /* Overflow might keep us from growing the list. */
- if (new_size <= heap->allocated) {
- archive_set_error(&a->archive,
- ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- new_pending_files = (struct file_info **)
- malloc(new_size * sizeof(new_pending_files[0]));
- if (new_pending_files == NULL) {
- archive_set_error(&a->archive,
- ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- memcpy(new_pending_files, heap->files,
- heap->allocated * sizeof(new_pending_files[0]));
- if (heap->files != NULL)
- free(heap->files);
- heap->files = new_pending_files;
- heap->allocated = new_size;
- }
-
- file_key = file->key = key;
-
- /*
- * Start with hole at end, walk it up tree to find insertion point.
- */
- hole = heap->used++;
- while (hole > 0) {
- parent = (hole - 1)/2;
- parent_key = heap->files[parent]->key;
- if (file_key >= parent_key) {
- heap->files[hole] = file;
- return (ARCHIVE_OK);
- }
- /* Move parent into hole <==> move hole up tree. */
- heap->files[hole] = heap->files[parent];
- hole = parent;
- }
- heap->files[0] = file;
-
- return (ARCHIVE_OK);
-}
-
-static struct file_info *
-heap_get_entry(struct heap_queue *heap)
-{
- uint64_t a_key, b_key, c_key;
- int a, b, c;
- struct file_info *r, *tmp;
-
- if (heap->used < 1)
- return (NULL);
-
- /*
- * The first file in the list is the earliest; we'll return this.
- */
- r = heap->files[0];
-
- /*
- * Move the last item in the heap to the root of the tree
- */
- heap->files[0] = heap->files[--(heap->used)];
-
- /*
- * Rebalance the heap.
- */
- a = 0; /* Starting element and its heap key */
- a_key = heap->files[a]->key;
- for (;;) {
- b = a + a + 1; /* First child */
- if (b >= heap->used)
- return (r);
- b_key = heap->files[b]->key;
- c = b + 1; /* Use second child if it is smaller. */
- if (c < heap->used) {
- c_key = heap->files[c]->key;
- if (c_key < b_key) {
- b = c;
- b_key = c_key;
- }
- }
- if (a_key <= b_key)
- return (r);
- tmp = heap->files[a];
- heap->files[a] = heap->files[b];
- heap->files[b] = tmp;
- a = b;
- }
-}
-
-static unsigned int
-toi(const void *p, int n)
-{
- const unsigned char *v = (const unsigned char *)p;
- if (n > 1)
- return v[0] + 256 * toi(v + 1, n - 1);
- if (n == 1)
- return v[0];
- return (0);
-}
-
-static time_t
-isodate7(const unsigned char *v)
-{
- struct tm tm;
- int offset;
- time_t t;
-
- memset(&tm, 0, sizeof(tm));
- tm.tm_year = v[0];
- tm.tm_mon = v[1] - 1;
- tm.tm_mday = v[2];
- tm.tm_hour = v[3];
- tm.tm_min = v[4];
- tm.tm_sec = v[5];
- /* v[6] is the signed timezone offset, in 1/4-hour increments. */
- offset = ((const signed char *)v)[6];
- if (offset > -48 && offset < 52) {
- tm.tm_hour -= offset / 4;
- tm.tm_min -= (offset % 4) * 15;
- }
- t = time_from_tm(&tm);
- if (t == (time_t)-1)
- return ((time_t)0);
- return (t);
-}
-
-static time_t
-isodate17(const unsigned char *v)
-{
- struct tm tm;
- int offset;
- time_t t;
-
- memset(&tm, 0, sizeof(tm));
- tm.tm_year = (v[0] - '0') * 1000 + (v[1] - '0') * 100
- + (v[2] - '0') * 10 + (v[3] - '0')
- - 1900;
- tm.tm_mon = (v[4] - '0') * 10 + (v[5] - '0');
- tm.tm_mday = (v[6] - '0') * 10 + (v[7] - '0');
- tm.tm_hour = (v[8] - '0') * 10 + (v[9] - '0');
- tm.tm_min = (v[10] - '0') * 10 + (v[11] - '0');
- tm.tm_sec = (v[12] - '0') * 10 + (v[13] - '0');
- /* v[16] is the signed timezone offset, in 1/4-hour increments. */
- offset = ((const signed char *)v)[16];
- if (offset > -48 && offset < 52) {
- tm.tm_hour -= offset / 4;
- tm.tm_min -= (offset % 4) * 15;
- }
- t = time_from_tm(&tm);
- if (t == (time_t)-1)
- return ((time_t)0);
- return (t);
-}
-
-static time_t
-time_from_tm(struct tm *t)
-{
-#if HAVE_TIMEGM
- /* Use platform timegm() if available. */
- return (timegm(t));
-#elif HAVE__MKGMTIME64
- return (_mkgmtime64(t));
-#else
- /* Else use direct calculation using POSIX assumptions. */
- /* First, fix up tm_yday based on the year/month/day. */
- if (mktime(t) == (time_t)-1)
- return ((time_t)-1);
- /* Then we can compute timegm() from first principles. */
- return (t->tm_sec + t->tm_min * 60 + t->tm_hour * 3600
- + t->tm_yday * 86400 + (t->tm_year - 70) * 31536000
- + ((t->tm_year - 69) / 4) * 86400 -
- ((t->tm_year - 1) / 100) * 86400
- + ((t->tm_year + 299) / 400) * 86400);
-#endif
-}
-
-static const char *
-build_pathname(struct archive_string *as, struct file_info *file)
-{
- if (file->parent != NULL && archive_strlen(&file->parent->name) > 0) {
- build_pathname(as, file->parent);
- archive_strcat(as, "/");
- }
- if (archive_strlen(&file->name) == 0)
- archive_strcat(as, ".");
- else
- archive_string_concat(as, &file->name);
- return (as->s);
-}
-
-static int
-build_pathname_utf16be(unsigned char *p, size_t max, size_t *len,
- struct file_info *file)
-{
- if (file->parent != NULL && file->parent->utf16be_bytes > 0) {
- if (build_pathname_utf16be(p, max, len, file->parent) != 0)
- return (-1);
- p[*len] = 0;
- p[*len + 1] = '/';
- *len += 2;
- }
- if (file->utf16be_bytes == 0) {
- if (*len + 2 > max)
- return (-1);/* Path is too long! */
- p[*len] = 0;
- p[*len + 1] = '.';
- *len += 2;
- } else {
- if (*len + file->utf16be_bytes > max)
- return (-1);/* Path is too long! */
- memcpy(p + *len, file->utf16be_name, file->utf16be_bytes);
- *len += file->utf16be_bytes;
- }
- return (0);
-}
-
-#if DEBUG
-static void
-dump_isodirrec(FILE *out, const unsigned char *isodirrec)
-{
- fprintf(out, " l %d,",
- toi(isodirrec + DR_length_offset, DR_length_size));
- fprintf(out, " a %d,",
- toi(isodirrec + DR_ext_attr_length_offset, DR_ext_attr_length_size));
- fprintf(out, " ext 0x%x,",
- toi(isodirrec + DR_extent_offset, DR_extent_size));
- fprintf(out, " s %d,",
- toi(isodirrec + DR_size_offset, DR_extent_size));
- fprintf(out, " f 0x%x,",
- toi(isodirrec + DR_flags_offset, DR_flags_size));
- fprintf(out, " u %d,",
- toi(isodirrec + DR_file_unit_size_offset, DR_file_unit_size_size));
- fprintf(out, " ilv %d,",
- toi(isodirrec + DR_interleave_offset, DR_interleave_size));
- fprintf(out, " seq %d,",
- toi(isodirrec + DR_volume_sequence_number_offset,
- DR_volume_sequence_number_size));
- fprintf(out, " nl %d:",
- toi(isodirrec + DR_name_len_offset, DR_name_len_size));
- fprintf(out, " `%.*s'",
- toi(isodirrec + DR_name_len_offset, DR_name_len_size),
- isodirrec + DR_name_offset);
-}
-#endif
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_format_lha.c b/3rdparty/libarchive/libarchive/archive_read_support_format_lha.c
deleted file mode 100644
index f702949f..00000000
--- a/3rdparty/libarchive/libarchive/archive_read_support_format_lha.c
+++ /dev/null
@@ -1,2748 +0,0 @@
-/*-
- * Copyright (c) 2008-2012 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"
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#include "archive.h"
-#include "archive_entry.h"
-#include "archive_entry_locale.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-#include "archive_endian.h"
-
-
-#define MAXMATCH 256 /* Maximum match length. */
-#define MINMATCH 3 /* Minimum match length. */
-/*
- * Literal table format:
- * +0 +256 +510
- * +---------------+-------------------------+
- * | literal code | match length |
- * | 0 ... 255 | MINMATCH ... MAXMATCH |
- * +---------------+-------------------------+
- * <--- LT_BITLEN_SIZE --->
- */
-/* Literal table size. */
-#define LT_BITLEN_SIZE (UCHAR_MAX + 1 + MAXMATCH - MINMATCH + 1)
-/* Position table size.
- * Note: this used for both position table and pre literal table.*/
-#define PT_BITLEN_SIZE (3 + 16)
-
-struct lzh_dec {
- /* Decoding status. */
- int state;
-
- /*
- * Window to see last 8Ki(lh5),32Ki(lh6),64Ki(lh7) bytes of decoded
- * data.
- */
- int w_size;
- int w_mask;
- /* Window buffer, which is a loop buffer. */
- unsigned char *w_buff;
- /* The insert position to the window. */
- int w_pos;
- /* The position where we can copy decoded code from the window. */
- int copy_pos;
- /* The length how many bytes we can copy decoded code from
- * the window. */
- int copy_len;
- /* The remaining bytes that we have not copied decoded data from
- * the window to an output buffer. */
- int w_remaining;
-
- /*
- * Bit stream reader.
- */
- struct lzh_br {
-#define CACHE_TYPE uint64_t
-#define CACHE_BITS (8 * sizeof(CACHE_TYPE))
- /* Cache buffer. */
- CACHE_TYPE cache_buffer;
- /* Indicates how many bits avail in cache_buffer. */
- int cache_avail;
- } br;
-
- /*
- * Huffman coding.
- */
- struct huffman {
- int len_size;
- int len_avail;
- int len_bits;
- int freq[17];
- unsigned char *bitlen;
-
- /*
- * Use a index table. It's faster than searching a huffman
- * coding tree, which is a binary tree. But a use of a large
- * index table causes L1 cache read miss many times.
- */
-#define HTBL_BITS 10
- int max_bits;
- int shift_bits;
- int tbl_bits;
- int tree_used;
- int tree_avail;
- /* Direct access table. */
- uint16_t *tbl;
- /* Binary tree table for extra bits over the direct access. */
- struct htree_t {
- uint16_t left;
- uint16_t right;
- } *tree;
- } lt, pt;
-
- int blocks_avail;
- int pos_pt_len_size;
- int pos_pt_len_bits;
- int literal_pt_len_size;
- int literal_pt_len_bits;
- int reading_position;
- int loop;
- int error;
-};
-
-struct lzh_stream {
- const unsigned char *next_in;
- int64_t avail_in;
- int64_t total_in;
- unsigned char *next_out;
- int64_t avail_out;
- int64_t total_out;
- struct lzh_dec *ds;
-};
-
-struct lha {
- /* entry_bytes_remaining is the number of bytes we expect. */
- int64_t entry_offset;
- int64_t entry_bytes_remaining;
- int64_t entry_unconsumed;
- uint16_t entry_crc_calculated;
-
- size_t header_size; /* header size */
- unsigned char level; /* header level */
- char method[3]; /* compress type */
- int64_t compsize; /* compressed data size */
- int64_t origsize; /* original file size */
- int setflag;
-#define BIRTHTIME_IS_SET 1
-#define ATIME_IS_SET 2
-#define UNIX_MODE_IS_SET 4
-#define CRC_IS_SET 8
- time_t birthtime;
- long birthtime_tv_nsec;
- time_t mtime;
- long mtime_tv_nsec;
- time_t atime;
- long atime_tv_nsec;
- mode_t mode;
- int64_t uid;
- int64_t gid;
- struct archive_string uname;
- struct archive_string gname;
- uint16_t header_crc;
- uint16_t crc;
- struct archive_string_conv *sconv;
- struct archive_string_conv *opt_sconv;
-
- struct archive_string dirname;
- struct archive_string filename;
- struct archive_wstring ws;
-
- unsigned char dos_attr;
-
- /* Flag to mark progress that an archive was read their first header.*/
- char found_first_header;
- /* Flag to mark that indicates an empty directory. */
- char directory;
-
- /* Flags to mark progress of decompression. */
- char decompress_init;
- char end_of_entry;
- char end_of_entry_cleanup;
- char entry_is_compressed;
-
- unsigned char *uncompressed_buffer;
- size_t uncompressed_buffer_size;
-
- char format_name[64];
-
- struct lzh_stream strm;
-};
-
-/*
- * LHA header common member offset.
- */
-#define H_METHOD_OFFSET 2 /* Compress type. */
-#define H_ATTR_OFFSET 19 /* DOS attribute. */
-#define H_LEVEL_OFFSET 20 /* Header Level. */
-#define H_SIZE 22 /* Minimum header size. */
-
-static const uint16_t crc16tbl[256] = {
- 0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,
- 0xC601,0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440,
- 0xCC01,0x0CC0,0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40,
- 0x0A00,0xCAC1,0xCB81,0x0B40,0xC901,0x09C0,0x0880,0xC841,
- 0xD801,0x18C0,0x1980,0xD941,0x1B00,0xDBC1,0xDA81,0x1A40,
- 0x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,0x1DC0,0x1C80,0xDC41,
- 0x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,0x1680,0xD641,
- 0xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,0x1040,
- 0xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240,
- 0x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441,
- 0x3C00,0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41,
- 0xFA01,0x3AC0,0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840,
- 0x2800,0xE8C1,0xE981,0x2940,0xEB01,0x2BC0,0x2A80,0xEA41,
- 0xEE01,0x2EC0,0x2F80,0xEF41,0x2D00,0xEDC1,0xEC81,0x2C40,
- 0xE401,0x24C0,0x2580,0xE541,0x2700,0xE7C1,0xE681,0x2640,
- 0x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,0x2080,0xE041,
- 0xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,0x6240,
- 0x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441,
- 0x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41,
- 0xAA01,0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840,
- 0x7800,0xB8C1,0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41,
- 0xBE01,0x7EC0,0x7F80,0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40,
- 0xB401,0x74C0,0x7580,0xB541,0x7700,0xB7C1,0xB681,0x7640,
- 0x7200,0xB2C1,0xB381,0x7340,0xB101,0x71C0,0x7080,0xB041,
- 0x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,0x5280,0x9241,
- 0x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,0x5440,
- 0x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40,
- 0x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841,
- 0x8801,0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40,
- 0x4E00,0x8EC1,0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41,
- 0x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641,
- 0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040
-};
-
-static int archive_read_format_lha_bid(struct archive_read *, int);
-static int archive_read_format_lha_options(struct archive_read *,
- const char *, const char *);
-static int archive_read_format_lha_read_header(struct archive_read *,
- struct archive_entry *);
-static int archive_read_format_lha_read_data(struct archive_read *,
- const void **, size_t *, int64_t *);
-static int archive_read_format_lha_read_data_skip(struct archive_read *);
-static int archive_read_format_lha_cleanup(struct archive_read *);
-
-static void lha_replace_path_separator(struct lha *,
- struct archive_entry *);
-static int lha_read_file_header_0(struct archive_read *, struct lha *);
-static int lha_read_file_header_1(struct archive_read *, struct lha *);
-static int lha_read_file_header_2(struct archive_read *, struct lha *);
-static int lha_read_file_header_3(struct archive_read *, struct lha *);
-static int lha_read_file_extended_header(struct archive_read *,
- struct lha *, uint16_t *, int, size_t, size_t *);
-static size_t lha_check_header_format(const void *);
-static int lha_skip_sfx(struct archive_read *);
-static time_t lha_dos_time(const unsigned char *);
-static time_t lha_win_time(uint64_t, long *);
-static unsigned char lha_calcsum(unsigned char, const void *,
- int, size_t);
-static int lha_parse_linkname(struct archive_string *,
- struct archive_string *);
-static int lha_read_data_none(struct archive_read *, const void **,
- size_t *, int64_t *);
-static int lha_read_data_lzh(struct archive_read *, const void **,
- size_t *, int64_t *);
-static uint16_t lha_crc16(uint16_t, const void *, size_t);
-static int lzh_decode_init(struct lzh_stream *, const char *);
-static void lzh_decode_free(struct lzh_stream *);
-static int lzh_decode(struct lzh_stream *, int);
-static int lzh_br_fillup(struct lzh_stream *, struct lzh_br *);
-static int lzh_huffman_init(struct huffman *, size_t, int);
-static void lzh_huffman_free(struct huffman *);
-static int lzh_read_pt_bitlen(struct lzh_stream *, int start, int end);
-static int lzh_make_fake_table(struct huffman *, uint16_t);
-static int lzh_make_huffman_table(struct huffman *);
-static inline int lzh_decode_huffman(struct huffman *, unsigned);
-static int lzh_decode_huffman_tree(struct huffman *, unsigned, int);
-
-
-int
-archive_read_support_format_lha(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct lha *lha;
- int r;
-
- archive_check_magic(_a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_NEW, "archive_read_support_format_lha");
-
- lha = (struct lha *)calloc(1, sizeof(*lha));
- if (lha == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate lha data");
- return (ARCHIVE_FATAL);
- }
- archive_string_init(&lha->ws);
-
- r = __archive_read_register_format(a,
- lha,
- "lha",
- archive_read_format_lha_bid,
- archive_read_format_lha_options,
- archive_read_format_lha_read_header,
- archive_read_format_lha_read_data,
- archive_read_format_lha_read_data_skip,
- NULL,
- archive_read_format_lha_cleanup);
-
- if (r != ARCHIVE_OK)
- free(lha);
- return (ARCHIVE_OK);
-}
-
-static size_t
-lha_check_header_format(const void *h)
-{
- const unsigned char *p = h;
- size_t next_skip_bytes;
-
- switch (p[H_METHOD_OFFSET+3]) {
- /*
- * "-lh0-" ... "-lh7-" "-lhd-"
- * "-lzs-" "-lz5-"
- */
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- case 'd':
- case 's':
- next_skip_bytes = 4;
-
- /* b0 == 0 means the end of an LHa archive file. */
- if (p[0] == 0)
- break;
- if (p[H_METHOD_OFFSET] != '-' || p[H_METHOD_OFFSET+1] != 'l'
- || p[H_METHOD_OFFSET+4] != '-')
- break;
-
- if (p[H_METHOD_OFFSET+2] == 'h') {
- /* "-lh?-" */
- if (p[H_METHOD_OFFSET+3] == 's')
- break;
- if (p[H_LEVEL_OFFSET] == 0)
- return (0);
- if (p[H_LEVEL_OFFSET] <= 3 && p[H_ATTR_OFFSET] == 0x20)
- return (0);
- }
- if (p[H_METHOD_OFFSET+2] == 'z') {
- /* LArc extensions: -lzs-,-lz4- and -lz5- */
- if (p[H_LEVEL_OFFSET] != 0)
- break;
- if (p[H_METHOD_OFFSET+3] == 's'
- || p[H_METHOD_OFFSET+3] == '4'
- || p[H_METHOD_OFFSET+3] == '5')
- return (0);
- }
- break;
- case 'h': next_skip_bytes = 1; break;
- case 'z': next_skip_bytes = 1; break;
- case 'l': next_skip_bytes = 2; break;
- case '-': next_skip_bytes = 3; break;
- default : next_skip_bytes = 4; break;
- }
-
- return (next_skip_bytes);
-}
-
-static int
-archive_read_format_lha_bid(struct archive_read *a, int best_bid)
-{
- const char *p;
- const void *buff;
- ssize_t bytes_avail, offset, window;
- size_t next;
-
- /* If there's already a better bid than we can ever
- make, don't bother testing. */
- if (best_bid > 30)
- return (-1);
-
- if ((p = __archive_read_ahead(a, H_SIZE, NULL)) == NULL)
- return (-1);
-
- if (lha_check_header_format(p) == 0)
- return (30);
-
- if (p[0] == 'M' && p[1] == 'Z') {
- /* PE file */
- offset = 0;
- window = 4096;
- while (offset < (1024 * 20)) {
- buff = __archive_read_ahead(a, offset + window,
- &bytes_avail);
- if (buff == NULL) {
- /* Remaining bytes are less than window. */
- window >>= 1;
- if (window < (H_SIZE + 3))
- return (0);
- continue;
- }
- p = (const char *)buff + offset;
- while (p + H_SIZE < (const char *)buff + bytes_avail) {
- if ((next = lha_check_header_format(p)) == 0)
- return (30);
- p += next;
- }
- offset = p - (const char *)buff;
- }
- }
- return (0);
-}
-
-static int
-archive_read_format_lha_options(struct archive_read *a,
- const char *key, const char *val)
-{
- struct lha *lha;
- int ret = ARCHIVE_FAILED;
-
- lha = (struct lha *)(a->format->data);
- if (strcmp(key, "hdrcharset") == 0) {
- if (val == NULL || val[0] == 0)
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "lha: hdrcharset option needs a character-set name");
- else {
- lha->opt_sconv =
- archive_string_conversion_from_charset(
- &a->archive, val, 0);
- if (lha->opt_sconv != NULL)
- ret = ARCHIVE_OK;
- else
- ret = ARCHIVE_FATAL;
- }
- return (ret);
- }
-
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
-}
-
-static int
-lha_skip_sfx(struct archive_read *a)
-{
- const void *h;
- const char *p, *q;
- size_t next, skip;
- ssize_t bytes, window;
-
- window = 4096;
- for (;;) {
- h = __archive_read_ahead(a, window, &bytes);
- if (h == NULL) {
- /* Remaining bytes are less than window. */
- window >>= 1;
- if (window < (H_SIZE + 3))
- goto fatal;
- continue;
- }
- if (bytes < H_SIZE)
- goto fatal;
- p = h;
- q = p + bytes;
-
- /*
- * Scan ahead until we find something that looks
- * like the lha header.
- */
- while (p + H_SIZE < q) {
- if ((next = lha_check_header_format(p)) == 0) {
- skip = p - (const char *)h;
- __archive_read_consume(a, skip);
- return (ARCHIVE_OK);
- }
- p += next;
- }
- skip = p - (const char *)h;
- __archive_read_consume(a, skip);
- }
-fatal:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Couldn't find out LHa header");
- return (ARCHIVE_FATAL);
-}
-
-static int
-truncated_error(struct archive_read *a)
-{
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated LHa header");
- return (ARCHIVE_FATAL);
-}
-
-static int
-archive_read_format_lha_read_header(struct archive_read *a,
- struct archive_entry *entry)
-{
- struct archive_string linkname;
- struct archive_string pathname;
- struct lha *lha;
- const unsigned char *p;
- const char *signature;
- int err;
-
- a->archive.archive_format = ARCHIVE_FORMAT_LHA;
- if (a->archive.archive_format_name == NULL)
- a->archive.archive_format_name = "lha";
-
- lha = (struct lha *)(a->format->data);
- lha->decompress_init = 0;
- lha->end_of_entry = 0;
- lha->end_of_entry_cleanup = 0;
- lha->entry_unconsumed = 0;
-
- if ((p = __archive_read_ahead(a, H_SIZE, NULL)) == NULL) {
- /*
- * LHa archiver added 0 to the tail of its archive file as
- * the mark of the end of the archive.
- */
- signature = __archive_read_ahead(a, sizeof(signature[0]), NULL);
- if (signature == NULL || signature[0] == 0)
- return (ARCHIVE_EOF);
- return (truncated_error(a));
- }
-
- signature = (const char *)p;
- if (lha->found_first_header == 0 &&
- signature[0] == 'M' && signature[1] == 'Z') {
- /* This is an executable? Must be self-extracting... */
- err = lha_skip_sfx(a);
- if (err < ARCHIVE_WARN)
- return (err);
-
- if ((p = __archive_read_ahead(a, sizeof(*p), NULL)) == NULL)
- return (truncated_error(a));
- signature = (const char *)p;
- }
- /* signature[0] == 0 means the end of an LHa archive file. */
- if (signature[0] == 0)
- return (ARCHIVE_EOF);
-
- /*
- * Check the header format and method type.
- */
- if (lha_check_header_format(p) != 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Bad LHa file");
- return (ARCHIVE_FATAL);
- }
-
- /* We've found the first header. */
- lha->found_first_header = 1;
- /* Set a default value and common data */
- lha->header_size = 0;
- lha->level = p[H_LEVEL_OFFSET];
- lha->method[0] = p[H_METHOD_OFFSET+1];
- lha->method[1] = p[H_METHOD_OFFSET+2];
- lha->method[2] = p[H_METHOD_OFFSET+3];
- if (memcmp(lha->method, "lhd", 3) == 0)
- lha->directory = 1;
- else
- lha->directory = 0;
- if (memcmp(lha->method, "lh0", 3) == 0 ||
- memcmp(lha->method, "lz4", 3) == 0)
- lha->entry_is_compressed = 0;
- else
- lha->entry_is_compressed = 1;
-
- lha->compsize = 0;
- lha->origsize = 0;
- lha->setflag = 0;
- lha->birthtime = 0;
- lha->birthtime_tv_nsec = 0;
- lha->mtime = 0;
- lha->mtime_tv_nsec = 0;
- lha->atime = 0;
- lha->atime_tv_nsec = 0;
- lha->mode = (lha->directory)? 0777 : 0666;
- lha->uid = 0;
- lha->gid = 0;
- archive_string_empty(&lha->dirname);
- archive_string_empty(&lha->filename);
- lha->dos_attr = 0;
- if (lha->opt_sconv != NULL)
- lha->sconv = lha->opt_sconv;
- else
- lha->sconv = NULL;
-
- switch (p[H_LEVEL_OFFSET]) {
- case 0:
- err = lha_read_file_header_0(a, lha);
- break;
- case 1:
- err = lha_read_file_header_1(a, lha);
- break;
- case 2:
- err = lha_read_file_header_2(a, lha);
- break;
- case 3:
- err = lha_read_file_header_3(a, lha);
- break;
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Unsupported LHa header level %d", p[H_LEVEL_OFFSET]);
- err = ARCHIVE_FATAL;
- break;
- }
- if (err < ARCHIVE_WARN)
- return (err);
-
-
- if (!lha->directory && archive_strlen(&lha->filename) == 0)
- /* The filename has not been set */
- return (truncated_error(a));
-
- /*
- * Make a pathname from a dirname and a filename.
- */
- archive_string_concat(&lha->dirname, &lha->filename);
- archive_string_init(&pathname);
- archive_string_init(&linkname);
- archive_string_copy(&pathname, &lha->dirname);
-
- if ((lha->mode & AE_IFMT) == AE_IFLNK) {
- /*
- * Extract the symlink-name if it's included in the pathname.
- */
- if (!lha_parse_linkname(&linkname, &pathname)) {
- /* We couldn't get the symlink-name. */
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Unknown symlink-name");
- archive_string_free(&pathname);
- archive_string_free(&linkname);
- return (ARCHIVE_FAILED);
- }
- } else {
- /*
- * Make sure a file-type is set.
- * The mode has been overridden if it is in the extended data.
- */
- lha->mode = (lha->mode & ~AE_IFMT) |
- ((lha->directory)? AE_IFDIR: AE_IFREG);
- }
- if ((lha->setflag & UNIX_MODE_IS_SET) == 0 &&
- (lha->dos_attr & 1) != 0)
- lha->mode &= ~(0222);/* read only. */
-
- /*
- * Set basic file parameters.
- */
- if (archive_entry_copy_pathname_l(entry, pathname.s,
- pathname.length, lha->sconv) != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Pathname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Pathname cannot be converted "
- "from %s to current locale.",
- archive_string_conversion_charset_name(lha->sconv));
- err = ARCHIVE_WARN;
- }
- archive_string_free(&pathname);
- if (archive_strlen(&linkname) > 0) {
- if (archive_entry_copy_symlink_l(entry, linkname.s,
- linkname.length, lha->sconv) != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Linkname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Linkname cannot be converted "
- "from %s to current locale.",
- archive_string_conversion_charset_name(lha->sconv));
- err = ARCHIVE_WARN;
- }
- } else
- archive_entry_set_symlink(entry, NULL);
- archive_string_free(&linkname);
- /*
- * When a header level is 0, there is a possibility that
- * a pathname and a symlink has '\' character, a directory
- * separator in DOS/Windows. So we should convert it to '/'.
- */
- if (p[H_LEVEL_OFFSET] == 0)
- lha_replace_path_separator(lha, entry);
-
- archive_entry_set_mode(entry, lha->mode);
- archive_entry_set_uid(entry, lha->uid);
- archive_entry_set_gid(entry, lha->gid);
- if (archive_strlen(&lha->uname) > 0)
- archive_entry_set_uname(entry, lha->uname.s);
- if (archive_strlen(&lha->gname) > 0)
- archive_entry_set_gname(entry, lha->gname.s);
- if (lha->setflag & BIRTHTIME_IS_SET) {
- archive_entry_set_birthtime(entry, lha->birthtime,
- lha->birthtime_tv_nsec);
- archive_entry_set_ctime(entry, lha->birthtime,
- lha->birthtime_tv_nsec);
- } else {
- archive_entry_unset_birthtime(entry);
- archive_entry_unset_ctime(entry);
- }
- archive_entry_set_mtime(entry, lha->mtime, lha->mtime_tv_nsec);
- if (lha->setflag & ATIME_IS_SET)
- archive_entry_set_atime(entry, lha->atime,
- lha->atime_tv_nsec);
- else
- archive_entry_unset_atime(entry);
- if (lha->directory || archive_entry_symlink(entry) != NULL)
- archive_entry_unset_size(entry);
- else
- archive_entry_set_size(entry, lha->origsize);
-
- /*
- * Prepare variables used to read a file content.
- */
- lha->entry_bytes_remaining = lha->compsize;
- lha->entry_offset = 0;
- lha->entry_crc_calculated = 0;
-
- /*
- * This file does not have a content.
- */
- if (lha->directory || lha->compsize == 0)
- lha->end_of_entry = 1;
-
- sprintf(lha->format_name, "lha -%c%c%c-",
- lha->method[0], lha->method[1], lha->method[2]);
- a->archive.archive_format_name = lha->format_name;
-
- return (err);
-}
-
-/*
- * Replace a DOS path separator '\' by a character '/'.
- * Some multi-byte character set have a character '\' in its second byte.
- */
-static void
-lha_replace_path_separator(struct lha *lha, struct archive_entry *entry)
-{
- const wchar_t *wp;
- size_t i;
-
- if ((wp = archive_entry_pathname_w(entry)) != NULL) {
- archive_wstrcpy(&(lha->ws), wp);
- for (i = 0; i < archive_strlen(&(lha->ws)); i++) {
- if (lha->ws.s[i] == L'\\')
- lha->ws.s[i] = L'/';
- }
- archive_entry_copy_pathname_w(entry, lha->ws.s);
- }
-
- if ((wp = archive_entry_symlink_w(entry)) != NULL) {
- archive_wstrcpy(&(lha->ws), wp);
- for (i = 0; i < archive_strlen(&(lha->ws)); i++) {
- if (lha->ws.s[i] == L'\\')
- lha->ws.s[i] = L'/';
- }
- archive_entry_copy_symlink_w(entry, lha->ws.s);
- }
-}
-
-/*
- * Header 0 format
- *
- * +0 +1 +2 +7 +11
- * +---------------+----------+----------------+-------------------+
- * |header size(*1)|header sum|compression type|compressed size(*2)|
- * +---------------+----------+----------------+-------------------+
- * <---------------------(*1)----------*
- *
- * +11 +15 +17 +19 +20 +21
- * +-----------------+---------+---------+--------------+----------------+
- * |uncompressed size|time(DOS)|date(DOS)|attribute(DOS)|header level(=0)|
- * +-----------------+---------+---------+--------------+----------------+
- * *--------------------------------(*1)---------------------------------*
- *
- * +21 +22 +22+(*3) +22+(*3)+2 +22+(*3)+2+(*4)
- * +---------------+---------+----------+----------------+------------------+
- * |name length(*3)|file name|file CRC16|extra header(*4)| compressed data |
- * +---------------+---------+----------+----------------+------------------+
- * <--(*3)-> <------(*2)------>
- * *----------------------(*1)-------------------------->
- *
- */
-#define H0_HEADER_SIZE_OFFSET 0
-#define H0_HEADER_SUM_OFFSET 1
-#define H0_COMP_SIZE_OFFSET 7
-#define H0_ORIG_SIZE_OFFSET 11
-#define H0_DOS_TIME_OFFSET 15
-#define H0_NAME_LEN_OFFSET 21
-#define H0_FILE_NAME_OFFSET 22
-#define H0_FIXED_SIZE 24
-static int
-lha_read_file_header_0(struct archive_read *a, struct lha *lha)
-{
- const unsigned char *p;
- int extdsize, namelen;
- unsigned char headersum, sum_calculated;
-
- if ((p = __archive_read_ahead(a, H0_FIXED_SIZE, NULL)) == NULL)
- return (truncated_error(a));
- lha->header_size = p[H0_HEADER_SIZE_OFFSET] + 2;
- headersum = p[H0_HEADER_SUM_OFFSET];
- lha->compsize = archive_le32dec(p + H0_COMP_SIZE_OFFSET);
- lha->origsize = archive_le32dec(p + H0_ORIG_SIZE_OFFSET);
- lha->mtime = lha_dos_time(p + H0_DOS_TIME_OFFSET);
- namelen = p[H0_NAME_LEN_OFFSET];
- extdsize = (int)lha->header_size - H0_FIXED_SIZE - namelen;
- if ((namelen > 221 || extdsize < 0) && extdsize != -2) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid LHa header");
- return (ARCHIVE_FATAL);
- }
- if ((p = __archive_read_ahead(a, lha->header_size, NULL)) == NULL)
- return (truncated_error(a));
-
- archive_strncpy(&lha->filename, p + H0_FILE_NAME_OFFSET, namelen);
- /* When extdsize == -2, A CRC16 value is not present in the header. */
- if (extdsize >= 0) {
- lha->crc = archive_le16dec(p + H0_FILE_NAME_OFFSET + namelen);
- lha->setflag |= CRC_IS_SET;
- }
- sum_calculated = lha_calcsum(0, p, 2, lha->header_size - 2);
-
- /* Read an extended header */
- if (extdsize > 0) {
- /* This extended data is set by 'LHa for UNIX' only.
- * Maybe fixed size.
- */
- p += H0_FILE_NAME_OFFSET + namelen + 2;
- if (p[0] == 'U' && extdsize == 12) {
- /* p[1] is a minor version. */
- lha->mtime = archive_le32dec(&p[2]);
- lha->mode = archive_le16dec(&p[6]);
- lha->uid = archive_le16dec(&p[8]);
- lha->gid = archive_le16dec(&p[10]);
- lha->setflag |= UNIX_MODE_IS_SET;
- }
- }
- __archive_read_consume(a, lha->header_size);
-
- if (sum_calculated != headersum) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "LHa header sum error");
- return (ARCHIVE_FATAL);
- }
-
- return (ARCHIVE_OK);
-}
-
-/*
- * Header 1 format
- *
- * +0 +1 +2 +7 +11
- * +---------------+----------+----------------+-------------+
- * |header size(*1)|header sum|compression type|skip size(*2)|
- * +---------------+----------+----------------+-------------+
- * <---------------(*1)----------*
- *
- * +11 +15 +17 +19 +20 +21
- * +-----------------+---------+---------+--------------+----------------+
- * |uncompressed size|time(DOS)|date(DOS)|attribute(DOS)|header level(=1)|
- * +-----------------+---------+---------+--------------+----------------+
- * *-------------------------------(*1)----------------------------------*
- *
- * +21 +22 +22+(*3) +22+(*3)+2 +22+(*3)+3 +22+(*3)+3+(*4)
- * +---------------+---------+----------+-----------+-----------+
- * |name length(*3)|file name|file CRC16| creator |padding(*4)|
- * +---------------+---------+----------+-----------+-----------+
- * <--(*3)->
- * *----------------------------(*1)----------------------------*
- *
- * +22+(*3)+3+(*4) +22+(*3)+3+(*4)+2 +22+(*3)+3+(*4)+2+(*5)
- * +----------------+---------------------+------------------------+
- * |next header size| extended header(*5) | compressed data |
- * +----------------+---------------------+------------------------+
- * *------(*1)-----> <--------------------(*2)-------------------->
- */
-#define H1_HEADER_SIZE_OFFSET 0
-#define H1_HEADER_SUM_OFFSET 1
-#define H1_COMP_SIZE_OFFSET 7
-#define H1_ORIG_SIZE_OFFSET 11
-#define H1_DOS_TIME_OFFSET 15
-#define H1_NAME_LEN_OFFSET 21
-#define H1_FILE_NAME_OFFSET 22
-#define H1_FIXED_SIZE 27
-static int
-lha_read_file_header_1(struct archive_read *a, struct lha *lha)
-{
- const unsigned char *p;
- size_t extdsize;
- int i, err, err2;
- int namelen, padding;
- unsigned char headersum, sum_calculated;
-
- err = ARCHIVE_OK;
-
- if ((p = __archive_read_ahead(a, H1_FIXED_SIZE, NULL)) == NULL)
- return (truncated_error(a));
-
- lha->header_size = p[H1_HEADER_SIZE_OFFSET] + 2;
- headersum = p[H1_HEADER_SUM_OFFSET];
- /* Note: An extended header size is included in a compsize. */
- lha->compsize = archive_le32dec(p + H1_COMP_SIZE_OFFSET);
- lha->origsize = archive_le32dec(p + H1_ORIG_SIZE_OFFSET);
- lha->mtime = lha_dos_time(p + H1_DOS_TIME_OFFSET);
- namelen = p[H1_NAME_LEN_OFFSET];
- /* Calculate a padding size. The result will be normally 0 only(?) */
- padding = ((int)lha->header_size) - H1_FIXED_SIZE - namelen;
-
- if (namelen > 230 || padding < 0)
- goto invalid;
-
- if ((p = __archive_read_ahead(a, lha->header_size, NULL)) == NULL)
- return (truncated_error(a));
-
- for (i = 0; i < namelen; i++) {
- if (p[i + H1_FILE_NAME_OFFSET] == 0xff)
- goto invalid;/* Invalid filename. */
- }
- archive_strncpy(&lha->filename, p + H1_FILE_NAME_OFFSET, namelen);
- lha->crc = archive_le16dec(p + H1_FILE_NAME_OFFSET + namelen);
- lha->setflag |= CRC_IS_SET;
-
- sum_calculated = lha_calcsum(0, p, 2, lha->header_size - 2);
- /* Consume used bytes but not include `next header size' data
- * since it will be consumed in lha_read_file_extended_header(). */
- __archive_read_consume(a, lha->header_size - 2);
-
- /* Read extended headers */
- err2 = lha_read_file_extended_header(a, lha, NULL, 2,
- (size_t)(lha->compsize + 2), &extdsize);
- if (err2 < ARCHIVE_WARN)
- return (err2);
- if (err2 < err)
- err = err2;
- /* Get a real compressed file size. */
- lha->compsize -= extdsize - 2;
-
- if (sum_calculated != headersum) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "LHa header sum error");
- return (ARCHIVE_FATAL);
- }
- return (err);
-invalid:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid LHa header");
- return (ARCHIVE_FATAL);
-}
-
-/*
- * Header 2 format
- *
- * +0 +2 +7 +11 +15
- * +---------------+----------------+-------------------+-----------------+
- * |header size(*1)|compression type|compressed size(*2)|uncompressed size|
- * +---------------+----------------+-------------------+-----------------+
- * <--------------------------------(*1)---------------------------------*
- *
- * +15 +19 +20 +21 +23 +24
- * +-----------------+------------+----------------+----------+-----------+
- * |data/time(time_t)| 0x20 fixed |header level(=2)|file CRC16| creator |
- * +-----------------+------------+----------------+----------+-----------+
- * *---------------------------------(*1)---------------------------------*
- *
- * +24 +26 +26+(*3) +26+(*3)+(*4)
- * +----------------+-------------------+-------------+-------------------+
- * |next header size|extended header(*3)| padding(*4) | compressed data |
- * +----------------+-------------------+-------------+-------------------+
- * *--------------------------(*1)-------------------> <------(*2)------->
- *
- */
-#define H2_HEADER_SIZE_OFFSET 0
-#define H2_COMP_SIZE_OFFSET 7
-#define H2_ORIG_SIZE_OFFSET 11
-#define H2_TIME_OFFSET 15
-#define H2_CRC_OFFSET 21
-#define H2_FIXED_SIZE 24
-static int
-lha_read_file_header_2(struct archive_read *a, struct lha *lha)
-{
- const unsigned char *p;
- size_t extdsize;
- int err, padding;
- uint16_t header_crc;
-
- if ((p = __archive_read_ahead(a, H2_FIXED_SIZE, NULL)) == NULL)
- return (truncated_error(a));
-
- lha->header_size =archive_le16dec(p + H2_HEADER_SIZE_OFFSET);
- lha->compsize = archive_le32dec(p + H2_COMP_SIZE_OFFSET);
- lha->origsize = archive_le32dec(p + H2_ORIG_SIZE_OFFSET);
- lha->mtime = archive_le32dec(p + H2_TIME_OFFSET);
- lha->crc = archive_le16dec(p + H2_CRC_OFFSET);
- lha->setflag |= CRC_IS_SET;
-
- if (lha->header_size < H2_FIXED_SIZE) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid LHa header size");
- return (ARCHIVE_FATAL);
- }
-
- header_crc = lha_crc16(0, p, H2_FIXED_SIZE);
- __archive_read_consume(a, H2_FIXED_SIZE);
-
- /* Read extended headers */
- err = lha_read_file_extended_header(a, lha, &header_crc, 2,
- lha->header_size - H2_FIXED_SIZE, &extdsize);
- if (err < ARCHIVE_WARN)
- return (err);
-
- /* Calculate a padding size. The result will be normally 0 or 1. */
- padding = (int)lha->header_size - (int)(H2_FIXED_SIZE + extdsize);
- if (padding > 0) {
- if ((p = __archive_read_ahead(a, padding, NULL)) == NULL)
- return (truncated_error(a));
- header_crc = lha_crc16(header_crc, p, padding);
- __archive_read_consume(a, padding);
- }
-
- if (header_crc != lha->header_crc) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "LHa header CRC error");
- return (ARCHIVE_FATAL);
- }
- return (err);
-}
-
-/*
- * Header 3 format
- *
- * +0 +2 +7 +11 +15
- * +------------+----------------+-------------------+-----------------+
- * | 0x04 fixed |compression type|compressed size(*2)|uncompressed size|
- * +------------+----------------+-------------------+-----------------+
- * <-------------------------------(*1)-------------------------------*
- *
- * +15 +19 +20 +21 +23 +24
- * +-----------------+------------+----------------+----------+-----------+
- * |date/time(time_t)| 0x20 fixed |header level(=3)|file CRC16| creator |
- * +-----------------+------------+----------------+----------+-----------+
- * *--------------------------------(*1)----------------------------------*
- *
- * +24 +28 +32 +32+(*3)
- * +---------------+----------------+-------------------+-----------------+
- * |header size(*1)|next header size|extended header(*3)| compressed data |
- * +---------------+----------------+-------------------+-----------------+
- * *------------------------(*1)-----------------------> <------(*2)----->
- *
- */
-#define H3_FIELD_LEN_OFFSET 0
-#define H3_COMP_SIZE_OFFSET 7
-#define H3_ORIG_SIZE_OFFSET 11
-#define H3_TIME_OFFSET 15
-#define H3_CRC_OFFSET 21
-#define H3_HEADER_SIZE_OFFSET 24
-#define H3_FIXED_SIZE 28
-static int
-lha_read_file_header_3(struct archive_read *a, struct lha *lha)
-{
- const unsigned char *p;
- size_t extdsize;
- int err;
- uint16_t header_crc;
-
- if ((p = __archive_read_ahead(a, H3_FIXED_SIZE, NULL)) == NULL)
- return (truncated_error(a));
-
- if (archive_le16dec(p + H3_FIELD_LEN_OFFSET) != 4)
- goto invalid;
- lha->header_size =archive_le32dec(p + H3_HEADER_SIZE_OFFSET);
- lha->compsize = archive_le32dec(p + H3_COMP_SIZE_OFFSET);
- lha->origsize = archive_le32dec(p + H3_ORIG_SIZE_OFFSET);
- lha->mtime = archive_le32dec(p + H3_TIME_OFFSET);
- lha->crc = archive_le16dec(p + H3_CRC_OFFSET);
- lha->setflag |= CRC_IS_SET;
-
- if (lha->header_size < H3_FIXED_SIZE + 4)
- goto invalid;
- header_crc = lha_crc16(0, p, H3_FIXED_SIZE);
- __archive_read_consume(a, H3_FIXED_SIZE);
-
- /* Read extended headers */
- err = lha_read_file_extended_header(a, lha, &header_crc, 4,
- lha->header_size - H3_FIXED_SIZE, &extdsize);
- if (err < ARCHIVE_WARN)
- return (err);
-
- if (header_crc != lha->header_crc) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "LHa header CRC error");
- return (ARCHIVE_FATAL);
- }
- return (err);
-invalid:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid LHa header");
- return (ARCHIVE_FATAL);
-}
-
-/*
- * Extended header format
- *
- * +0 +2 +3 -- used in header 1 and 2
- * +0 +4 +5 -- used in header 3
- * +--------------+---------+-------------------+--------------+--
- * |ex-header size|header id| data |ex-header size| .......
- * +--------------+---------+-------------------+--------------+--
- * <-------------( ex-header size)------------> <-- next extended header --*
- *
- * If the ex-header size is zero, it is the make of the end of extended
- * headers.
- *
- */
-static int
-lha_read_file_extended_header(struct archive_read *a, struct lha *lha,
- uint16_t *crc, int sizefield_length, size_t limitsize, size_t *total_size)
-{
- const void *h;
- const unsigned char *extdheader;
- size_t extdsize;
- size_t datasize;
- unsigned int i;
- unsigned char extdtype;
-
-#define EXT_HEADER_CRC 0x00 /* Header CRC and information*/
-#define EXT_FILENAME 0x01 /* Filename */
-#define EXT_DIRECTORY 0x02 /* Directory name */
-#define EXT_DOS_ATTR 0x40 /* MS-DOS attribute */
-#define EXT_TIMESTAMP 0x41 /* Windows time stamp */
-#define EXT_FILESIZE 0x42 /* Large file size */
-#define EXT_TIMEZONE 0x43 /* Time zone */
-#define EXT_UTF16_FILENAME 0x44 /* UTF-16 filename */
-#define EXT_UTF16_DIRECTORY 0x45 /* UTF-16 directory name */
-#define EXT_CODEPAGE 0x46 /* Codepage */
-#define EXT_UNIX_MODE 0x50 /* File permission */
-#define EXT_UNIX_GID_UID 0x51 /* gid,uid */
-#define EXT_UNIX_GNAME 0x52 /* Group name */
-#define EXT_UNIX_UNAME 0x53 /* User name */
-#define EXT_UNIX_MTIME 0x54 /* Modified time */
-#define EXT_OS2_NEW_ATTR 0x7f /* new attribute(OS/2 only) */
-#define EXT_NEW_ATTR 0xff /* new attribute */
-
- *total_size = sizefield_length;
-
- for (;;) {
- /* Read an extended header size. */
- if ((h =
- __archive_read_ahead(a, sizefield_length, NULL)) == NULL)
- return (truncated_error(a));
- /* Check if the size is the zero indicates the end of the
- * extended header. */
- if (sizefield_length == sizeof(uint16_t))
- extdsize = archive_le16dec(h);
- else
- extdsize = archive_le32dec(h);
- if (extdsize == 0) {
- /* End of extended header */
- if (crc != NULL)
- *crc = lha_crc16(*crc, h, sizefield_length);
- __archive_read_consume(a, sizefield_length);
- return (ARCHIVE_OK);
- }
-
- /* Sanity check to the extended header size. */
- if (((uint64_t)*total_size + extdsize) >
- (uint64_t)limitsize ||
- extdsize <= (size_t)sizefield_length)
- goto invalid;
-
- /* Read the extended header. */
- if ((h = __archive_read_ahead(a, extdsize, NULL)) == NULL)
- return (truncated_error(a));
- *total_size += extdsize;
-
- extdheader = (const unsigned char *)h;
- /* Get the extended header type. */
- extdtype = extdheader[sizefield_length];
- /* Calculate an extended data size. */
- datasize = extdsize - (1 + sizefield_length);
- /* Skip an extended header size field and type field. */
- extdheader += sizefield_length + 1;
-
- if (crc != NULL && extdtype != EXT_HEADER_CRC)
- *crc = lha_crc16(*crc, h, extdsize);
- switch (extdtype) {
- case EXT_HEADER_CRC:
- /* We only use a header CRC. Following data will not
- * be used. */
- if (datasize >= 2) {
- lha->header_crc = archive_le16dec(extdheader);
- if (crc != NULL) {
- static const char zeros[2] = {0, 0};
- *crc = lha_crc16(*crc, h,
- extdsize - datasize);
- /* CRC value itself as zero */
- *crc = lha_crc16(*crc, zeros, 2);
- *crc = lha_crc16(*crc,
- extdheader+2, datasize - 2);
- }
- }
- break;
- case EXT_FILENAME:
- if (datasize == 0) {
- /* maybe directory header */
- archive_string_empty(&lha->filename);
- break;
- }
- archive_strncpy(&lha->filename,
- (const char *)extdheader, datasize);
- break;
- case EXT_DIRECTORY:
- if (datasize == 0)
- /* no directory name data. exit this case. */
- break;
-
- archive_strncpy(&lha->dirname,
- (const char *)extdheader, datasize);
- /*
- * Convert directory delimiter from 0xFF
- * to '/' for local system.
- */
- for (i = 0; i < lha->dirname.length; i++) {
- if ((unsigned char)lha->dirname.s[i] == 0xFF)
- lha->dirname.s[i] = '/';
- }
- /* Is last character directory separator? */
- if (lha->dirname.s[lha->dirname.length-1] != '/')
- /* invalid directory data */
- goto invalid;
- break;
- case EXT_DOS_ATTR:
- if (datasize == 2)
- lha->dos_attr = (unsigned char)
- (archive_le16dec(extdheader) & 0xff);
- break;
- case EXT_TIMESTAMP:
- if (datasize == (sizeof(uint64_t) * 3)) {
- lha->birthtime = lha_win_time(
- archive_le64dec(extdheader),
- &lha->birthtime_tv_nsec);
- extdheader += sizeof(uint64_t);
- lha->mtime = lha_win_time(
- archive_le64dec(extdheader),
- &lha->mtime_tv_nsec);
- extdheader += sizeof(uint64_t);
- lha->atime = lha_win_time(
- archive_le64dec(extdheader),
- &lha->atime_tv_nsec);
- lha->setflag |= BIRTHTIME_IS_SET |
- ATIME_IS_SET;
- }
- break;
- case EXT_FILESIZE:
- if (datasize == sizeof(uint64_t) * 2) {
- lha->compsize = archive_le64dec(extdheader);
- extdheader += sizeof(uint64_t);
- lha->origsize = archive_le64dec(extdheader);
- }
- break;
- case EXT_CODEPAGE:
- /* Get an archived filename charset from codepage.
- * This overwrites the charset specified by
- * hdrcharset option. */
- if (datasize == sizeof(uint32_t)) {
- struct archive_string cp;
- const char *charset;
-
- archive_string_init(&cp);
- switch (archive_le32dec(extdheader)) {
- case 65001: /* UTF-8 */
- charset = "UTF-8";
- break;
- default:
- archive_string_sprintf(&cp, "CP%d",
- (int)archive_le32dec(extdheader));
- charset = cp.s;
- break;
- }
- lha->sconv =
- archive_string_conversion_from_charset(
- &(a->archive), charset, 1);
- archive_string_free(&cp);
- if (lha->sconv == NULL)
- return (ARCHIVE_FATAL);
- }
- break;
- case EXT_UNIX_MODE:
- if (datasize == sizeof(uint16_t)) {
- lha->mode = archive_le16dec(extdheader);
- lha->setflag |= UNIX_MODE_IS_SET;
- }
- break;
- case EXT_UNIX_GID_UID:
- if (datasize == (sizeof(uint16_t) * 2)) {
- lha->gid = archive_le16dec(extdheader);
- lha->uid = archive_le16dec(extdheader+2);
- }
- break;
- case EXT_UNIX_GNAME:
- if (datasize > 0)
- archive_strncpy(&lha->gname,
- (const char *)extdheader, datasize);
- break;
- case EXT_UNIX_UNAME:
- if (datasize > 0)
- archive_strncpy(&lha->uname,
- (const char *)extdheader, datasize);
- break;
- case EXT_UNIX_MTIME:
- if (datasize == sizeof(uint32_t))
- lha->mtime = archive_le32dec(extdheader);
- break;
- case EXT_OS2_NEW_ATTR:
- /* This extended header is OS/2 depend. */
- if (datasize == 16) {
- lha->dos_attr = (unsigned char)
- (archive_le16dec(extdheader) & 0xff);
- lha->mode = archive_le16dec(extdheader+2);
- lha->gid = archive_le16dec(extdheader+4);
- lha->uid = archive_le16dec(extdheader+6);
- lha->birthtime = archive_le32dec(extdheader+8);
- lha->atime = archive_le32dec(extdheader+12);
- lha->setflag |= UNIX_MODE_IS_SET
- | BIRTHTIME_IS_SET | ATIME_IS_SET;
- }
- break;
- case EXT_NEW_ATTR:
- if (datasize == 20) {
- lha->mode = (mode_t)archive_le32dec(extdheader);
- lha->gid = archive_le32dec(extdheader+4);
- lha->uid = archive_le32dec(extdheader+8);
- lha->birthtime = archive_le32dec(extdheader+12);
- lha->atime = archive_le32dec(extdheader+16);
- lha->setflag |= UNIX_MODE_IS_SET
- | BIRTHTIME_IS_SET | ATIME_IS_SET;
- }
- break;
- case EXT_TIMEZONE: /* Not supported */
- case EXT_UTF16_FILENAME: /* Not supported */
- case EXT_UTF16_DIRECTORY: /* Not supported */
- default:
- break;
- }
-
- __archive_read_consume(a, extdsize);
- }
-invalid:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid extended LHa header");
- return (ARCHIVE_FATAL);
-}
-
-static int
-archive_read_format_lha_read_data(struct archive_read *a,
- const void **buff, size_t *size, int64_t *offset)
-{
- struct lha *lha = (struct lha *)(a->format->data);
- int r;
-
- if (lha->entry_unconsumed) {
- /* Consume as much as the decompressor actually used. */
- __archive_read_consume(a, lha->entry_unconsumed);
- lha->entry_unconsumed = 0;
- }
- if (lha->end_of_entry) {
- if (!lha->end_of_entry_cleanup) {
- if ((lha->setflag & CRC_IS_SET) &&
- lha->crc != lha->entry_crc_calculated) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "LHa data CRC error");
- return (ARCHIVE_WARN);
- }
-
- /* End-of-entry cleanup done. */
- lha->end_of_entry_cleanup = 1;
- }
- *offset = lha->entry_offset;
- *size = 0;
- *buff = NULL;
- return (ARCHIVE_EOF);
- }
-
- if (lha->entry_is_compressed)
- r = lha_read_data_lzh(a, buff, size, offset);
- else
- /* No compression. */
- r = lha_read_data_none(a, buff, size, offset);
- return (r);
-}
-
-/*
- * Read a file content in no compression.
- *
- * Returns ARCHIVE_OK if successful, ARCHIVE_FATAL otherwise, sets
- * lha->end_of_entry if it consumes all of the data.
- */
-static int
-lha_read_data_none(struct archive_read *a, const void **buff,
- size_t *size, int64_t *offset)
-{
- struct lha *lha = (struct lha *)(a->format->data);
- ssize_t bytes_avail;
-
- if (lha->entry_bytes_remaining == 0) {
- *buff = NULL;
- *size = 0;
- *offset = lha->entry_offset;
- lha->end_of_entry = 1;
- return (ARCHIVE_OK);
- }
- /*
- * Note: '1' here is a performance optimization.
- * Recall that the decompression layer returns a count of
- * available bytes; asking for more than that forces the
- * decompressor to combine reads by copying data.
- */
- *buff = __archive_read_ahead(a, 1, &bytes_avail);
- if (bytes_avail <= 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated LHa file data");
- return (ARCHIVE_FATAL);
- }
- if (bytes_avail > lha->entry_bytes_remaining)
- bytes_avail = (ssize_t)lha->entry_bytes_remaining;
- lha->entry_crc_calculated =
- lha_crc16(lha->entry_crc_calculated, *buff, bytes_avail);
- *size = bytes_avail;
- *offset = lha->entry_offset;
- lha->entry_offset += bytes_avail;
- lha->entry_bytes_remaining -= bytes_avail;
- if (lha->entry_bytes_remaining == 0)
- lha->end_of_entry = 1;
- lha->entry_unconsumed = bytes_avail;
- return (ARCHIVE_OK);
-}
-
-/*
- * Read a file content in LZHUFF encoding.
- *
- * Returns ARCHIVE_OK if successful, returns ARCHIVE_WARN if compression is
- * unsupported, ARCHIVE_FATAL otherwise, sets lha->end_of_entry if it consumes
- * all of the data.
- */
-static int
-lha_read_data_lzh(struct archive_read *a, const void **buff,
- size_t *size, int64_t *offset)
-{
- struct lha *lha = (struct lha *)(a->format->data);
- ssize_t bytes_avail;
- int r;
-
- /* If the buffer hasn't been allocated, allocate it now. */
- if (lha->uncompressed_buffer == NULL) {
- lha->uncompressed_buffer_size = 64 * 1024;
- lha->uncompressed_buffer
- = (unsigned char *)malloc(lha->uncompressed_buffer_size);
- if (lha->uncompressed_buffer == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "No memory for lzh decompression");
- return (ARCHIVE_FATAL);
- }
- }
-
- /* If we haven't yet read any data, initialize the decompressor. */
- if (!lha->decompress_init) {
- r = lzh_decode_init(&(lha->strm), lha->method);
- switch (r) {
- case ARCHIVE_OK:
- break;
- case ARCHIVE_FAILED:
- /* Unsupported compression. */
- *buff = NULL;
- *size = 0;
- *offset = 0;
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Unsupported lzh compression method -%c%c%c-",
- lha->method[0], lha->method[1], lha->method[2]);
- /* We know compressed size; just skip it. */
- archive_read_format_lha_read_data_skip(a);
- return (ARCHIVE_WARN);
- default:
- archive_set_error(&a->archive, ENOMEM,
- "Couldn't allocate memory "
- "for lzh decompression");
- return (ARCHIVE_FATAL);
- }
- /* We've initialized decompression for this stream. */
- lha->decompress_init = 1;
- lha->strm.avail_out = 0;
- lha->strm.total_out = 0;
- }
-
- /*
- * Note: '1' here is a performance optimization.
- * Recall that the decompression layer returns a count of
- * available bytes; asking for more than that forces the
- * decompressor to combine reads by copying data.
- */
- lha->strm.next_in = __archive_read_ahead(a, 1, &bytes_avail);
- if (bytes_avail <= 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated LHa file body");
- return (ARCHIVE_FATAL);
- }
- if (bytes_avail > lha->entry_bytes_remaining)
- bytes_avail = (ssize_t)lha->entry_bytes_remaining;
-
- lha->strm.avail_in = bytes_avail;
- lha->strm.total_in = 0;
- if (lha->strm.avail_out == 0) {
- lha->strm.next_out = lha->uncompressed_buffer;
- lha->strm.avail_out = lha->uncompressed_buffer_size;
- }
-
- r = lzh_decode(&(lha->strm), bytes_avail == lha->entry_bytes_remaining);
- switch (r) {
- case ARCHIVE_OK:
- break;
- case ARCHIVE_EOF:
- lha->end_of_entry = 1;
- break;
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Bad lzh data");
- return (ARCHIVE_FAILED);
- }
- lha->entry_unconsumed = lha->strm.total_in;
- lha->entry_bytes_remaining -= lha->strm.total_in;
-
- if (lha->strm.avail_out == 0 || lha->end_of_entry) {
- *offset = lha->entry_offset;
- *size = lha->strm.next_out - lha->uncompressed_buffer;
- *buff = lha->uncompressed_buffer;
- lha->entry_crc_calculated =
- lha_crc16(lha->entry_crc_calculated, *buff, *size);
- lha->entry_offset += *size;
- } else {
- *offset = lha->entry_offset;
- *size = 0;
- *buff = NULL;
- }
- return (ARCHIVE_OK);
-}
-
-/*
- * Skip a file content.
- */
-static int
-archive_read_format_lha_read_data_skip(struct archive_read *a)
-{
- struct lha *lha;
- int64_t bytes_skipped;
-
- lha = (struct lha *)(a->format->data);
-
- if (lha->entry_unconsumed) {
- /* Consume as much as the decompressor actually used. */
- __archive_read_consume(a, lha->entry_unconsumed);
- lha->entry_unconsumed = 0;
- }
-
- /* if we've already read to end of data, we're done. */
- if (lha->end_of_entry_cleanup)
- return (ARCHIVE_OK);
-
- /*
- * If the length is at the beginning, we can skip the
- * compressed data much more quickly.
- */
- bytes_skipped = __archive_read_consume(a, lha->entry_bytes_remaining);
- if (bytes_skipped < 0)
- return (ARCHIVE_FATAL);
-
- /* This entry is finished and done. */
- lha->end_of_entry_cleanup = lha->end_of_entry = 1;
- return (ARCHIVE_OK);
-}
-
-static int
-archive_read_format_lha_cleanup(struct archive_read *a)
-{
- struct lha *lha = (struct lha *)(a->format->data);
-
- lzh_decode_free(&(lha->strm));
- free(lha->uncompressed_buffer);
- archive_string_free(&(lha->dirname));
- archive_string_free(&(lha->filename));
- archive_string_free(&(lha->uname));
- archive_string_free(&(lha->gname));
- archive_wstring_free(&(lha->ws));
- free(lha);
- (a->format->data) = NULL;
- return (ARCHIVE_OK);
-}
-
-/*
- * 'LHa for UNIX' utility has archived a symbolic-link name after
- * a pathname with '|' character.
- * This function extracts the symbolic-link name from the pathname.
- *
- * example.
- * 1. a symbolic-name is 'aaa/bb/cc'
- * 2. a filename is 'xxx/bbb'
- * then a archived pathname is 'xxx/bbb|aaa/bb/cc'
- */
-static int
-lha_parse_linkname(struct archive_string *linkname,
- struct archive_string *pathname)
-{
- char * linkptr;
- size_t symlen;
-
- linkptr = strchr(pathname->s, '|');
- if (linkptr != NULL) {
- symlen = strlen(linkptr + 1);
- archive_strncpy(linkname, linkptr+1, symlen);
-
- *linkptr = 0;
- pathname->length = strlen(pathname->s);
-
- return (1);
- }
- return (0);
-}
-
-/* Convert an MSDOS-style date/time into Unix-style time. */
-static time_t
-lha_dos_time(const unsigned char *p)
-{
- int msTime, msDate;
- struct tm ts;
-
- msTime = archive_le16dec(p);
- msDate = archive_le16dec(p+2);
-
- memset(&ts, 0, sizeof(ts));
- ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */
- ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */
- ts.tm_mday = msDate & 0x1f; /* Day of month. */
- ts.tm_hour = (msTime >> 11) & 0x1f;
- ts.tm_min = (msTime >> 5) & 0x3f;
- ts.tm_sec = (msTime << 1) & 0x3e;
- ts.tm_isdst = -1;
- return (mktime(&ts));
-}
-
-/* Convert an MS-Windows-style date/time into Unix-style time. */
-static time_t
-lha_win_time(uint64_t wintime, long *ns)
-{
-#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
-
- if (wintime >= EPOC_TIME) {
- wintime -= EPOC_TIME; /* 1970-01-01 00:00:00 (UTC) */
- if (ns != NULL)
- *ns = (long)(wintime % 10000000) * 100;
- return (wintime / 10000000);
- } else {
- if (ns != NULL)
- *ns = 0;
- return (0);
- }
-}
-
-static unsigned char
-lha_calcsum(unsigned char sum, const void *pp, int offset, size_t size)
-{
- unsigned char const *p = (unsigned char const *)pp;
-
- p += offset;
- for (;size > 0; --size)
- sum += *p++;
- return (sum);
-}
-
-#define CRC16(crc, v) do { \
- (crc) = crc16tbl[((crc) ^ v) & 0xFF] ^ ((crc) >> 8); \
-} while (0)
-
-static uint16_t
-lha_crc16(uint16_t crc, const void *pp, size_t len)
-{
- const unsigned char *buff = (const unsigned char *)pp;
-
- while (len >= 8) {
- CRC16(crc, *buff++); CRC16(crc, *buff++);
- CRC16(crc, *buff++); CRC16(crc, *buff++);
- CRC16(crc, *buff++); CRC16(crc, *buff++);
- CRC16(crc, *buff++); CRC16(crc, *buff++);
- len -= 8;
- }
- switch (len) {
- case 7:
- CRC16(crc, *buff++);
- /* FALL THROUGH */
- case 6:
- CRC16(crc, *buff++);
- /* FALL THROUGH */
- case 5:
- CRC16(crc, *buff++);
- /* FALL THROUGH */
- case 4:
- CRC16(crc, *buff++);
- /* FALL THROUGH */
- case 3:
- CRC16(crc, *buff++);
- /* FALL THROUGH */
- case 2:
- CRC16(crc, *buff++);
- /* FALL THROUGH */
- case 1:
- CRC16(crc, *buff);
- /* FALL THROUGH */
- case 0:
- break;
- }
- return (crc);
-}
-
-
-/*
- * Initialize LZHUF decoder.
- *
- * Returns ARCHIVE_OK if initialization was successful.
- * Returns ARCHIVE_FAILED if method is unsupported.
- * Returns ARCHIVE_FATAL if initialization failed; memory allocation
- * error occurred.
- */
-static int
-lzh_decode_init(struct lzh_stream *strm, const char *method)
-{
- struct lzh_dec *ds;
- int w_bits, w_size;
-
- if (strm->ds == NULL) {
- strm->ds = calloc(1, sizeof(*strm->ds));
- if (strm->ds == NULL)
- return (ARCHIVE_FATAL);
- }
- ds = strm->ds;
- ds->error = ARCHIVE_FAILED;
- if (method == NULL || method[0] != 'l' || method[1] != 'h')
- return (ARCHIVE_FAILED);
- switch (method[2]) {
- case '5':
- w_bits = 13;/* 8KiB for window */
- break;
- case '6':
- w_bits = 15;/* 32KiB for window */
- break;
- case '7':
- w_bits = 16;/* 64KiB for window */
- break;
- default:
- return (ARCHIVE_FAILED);/* Not supported. */
- }
- ds->error = ARCHIVE_FATAL;
- w_size = ds->w_size;
- ds->w_size = 1U << w_bits;
- ds->w_mask = ds->w_size -1;
- if (ds->w_buff == NULL || w_size != ds->w_size) {
- free(ds->w_buff);
- ds->w_buff = malloc(ds->w_size);
- if (ds->w_buff == NULL)
- return (ARCHIVE_FATAL);
- }
- memset(ds->w_buff, 0x20, ds->w_size);
- ds->w_pos = 0;
- ds->w_remaining = 0;
- ds->state = 0;
- ds->pos_pt_len_size = w_bits + 1;
- ds->pos_pt_len_bits = (w_bits == 15 || w_bits == 16)? 5: 4;
- ds->literal_pt_len_size = PT_BITLEN_SIZE;
- ds->literal_pt_len_bits = 5;
- ds->br.cache_buffer = 0;
- ds->br.cache_avail = 0;
-
- if (lzh_huffman_init(&(ds->lt), LT_BITLEN_SIZE, 16)
- != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- ds->lt.len_bits = 9;
- if (lzh_huffman_init(&(ds->pt), PT_BITLEN_SIZE, 16)
- != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- ds->error = 0;
-
- return (ARCHIVE_OK);
-}
-
-/*
- * Release LZHUF decoder.
- */
-static void
-lzh_decode_free(struct lzh_stream *strm)
-{
-
- if (strm->ds == NULL)
- return;
- free(strm->ds->w_buff);
- lzh_huffman_free(&(strm->ds->lt));
- lzh_huffman_free(&(strm->ds->pt));
- free(strm->ds);
- strm->ds = NULL;
-}
-
-/*
- * Bit stream reader.
- */
-/* Check that the cache buffer has enough bits. */
-#define lzh_br_has(br, n) ((br)->cache_avail >= n)
-/* Get compressed data by bit. */
-#define lzh_br_bits(br, n) \
- (((uint16_t)((br)->cache_buffer >> \
- ((br)->cache_avail - (n)))) & cache_masks[n])
-#define lzh_br_bits_forced(br, n) \
- (((uint16_t)((br)->cache_buffer << \
- ((n) - (br)->cache_avail))) & cache_masks[n])
-/* Read ahead to make sure the cache buffer has enough compressed data we
- * will use.
- * True : completed, there is enough data in the cache buffer.
- * False : we met that strm->next_in is empty, we have to get following
- * bytes. */
-#define lzh_br_read_ahead_0(strm, br, n) \
- (lzh_br_has(br, (n)) || lzh_br_fillup(strm, br))
-/* True : the cache buffer has some bits as much as we need.
- * False : there are no enough bits in the cache buffer to be used,
- * we have to get following bytes if we could. */
-#define lzh_br_read_ahead(strm, br, n) \
- (lzh_br_read_ahead_0((strm), (br), (n)) || lzh_br_has((br), (n)))
-
-/* Notify how many bits we consumed. */
-#define lzh_br_consume(br, n) ((br)->cache_avail -= (n))
-#define lzh_br_unconsume(br, n) ((br)->cache_avail += (n))
-
-static const uint16_t cache_masks[] = {
- 0x0000, 0x0001, 0x0003, 0x0007,
- 0x000F, 0x001F, 0x003F, 0x007F,
- 0x00FF, 0x01FF, 0x03FF, 0x07FF,
- 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF,
- 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF
-};
-
-/*
- * Shift away used bits in the cache data and fill it up with following bits.
- * Call this when cache buffer does not have enough bits you need.
- *
- * Returns 1 if the cache buffer is full.
- * Returns 0 if the cache buffer is not full; input buffer is empty.
- */
-static int
-lzh_br_fillup(struct lzh_stream *strm, struct lzh_br *br)
-{
- int n = CACHE_BITS - br->cache_avail;
-
- for (;;) {
- switch (n >> 3) {
- case 8:
- if (strm->avail_in >= 8) {
- br->cache_buffer =
- ((uint64_t)strm->next_in[0]) << 56 |
- ((uint64_t)strm->next_in[1]) << 48 |
- ((uint64_t)strm->next_in[2]) << 40 |
- ((uint64_t)strm->next_in[3]) << 32 |
- ((uint32_t)strm->next_in[4]) << 24 |
- ((uint32_t)strm->next_in[5]) << 16 |
- ((uint32_t)strm->next_in[6]) << 8 |
- (uint32_t)strm->next_in[7];
- strm->next_in += 8;
- strm->avail_in -= 8;
- br->cache_avail += 8 * 8;
- return (1);
- }
- break;
- case 7:
- if (strm->avail_in >= 7) {
- br->cache_buffer =
- (br->cache_buffer << 56) |
- ((uint64_t)strm->next_in[0]) << 48 |
- ((uint64_t)strm->next_in[1]) << 40 |
- ((uint64_t)strm->next_in[2]) << 32 |
- ((uint32_t)strm->next_in[3]) << 24 |
- ((uint32_t)strm->next_in[4]) << 16 |
- ((uint32_t)strm->next_in[5]) << 8 |
- (uint32_t)strm->next_in[6];
- strm->next_in += 7;
- strm->avail_in -= 7;
- br->cache_avail += 7 * 8;
- return (1);
- }
- break;
- case 6:
- if (strm->avail_in >= 6) {
- br->cache_buffer =
- (br->cache_buffer << 48) |
- ((uint64_t)strm->next_in[0]) << 40 |
- ((uint64_t)strm->next_in[1]) << 32 |
- ((uint32_t)strm->next_in[2]) << 24 |
- ((uint32_t)strm->next_in[3]) << 16 |
- ((uint32_t)strm->next_in[4]) << 8 |
- (uint32_t)strm->next_in[5];
- strm->next_in += 6;
- strm->avail_in -= 6;
- br->cache_avail += 6 * 8;
- return (1);
- }
- break;
- case 0:
- /* We have enough compressed data in
- * the cache buffer.*/
- return (1);
- default:
- break;
- }
- if (strm->avail_in == 0) {
- /* There is not enough compressed data to fill up the
- * cache buffer. */
- return (0);
- }
- br->cache_buffer =
- (br->cache_buffer << 8) | *strm->next_in++;
- strm->avail_in--;
- br->cache_avail += 8;
- n -= 8;
- }
-}
-
-/*
- * Decode LZHUF.
- *
- * 1. Returns ARCHIVE_OK if output buffer or input buffer are empty.
- * Please set available buffer and call this function again.
- * 2. Returns ARCHIVE_EOF if decompression has been completed.
- * 3. Returns ARCHIVE_FAILED if an error occurred; compressed data
- * is broken or you do not set 'last' flag properly.
- * 4. 'last' flag is very important, you must set 1 to the flag if there
- * is no input data. The lha compressed data format does not provide how
- * to know the compressed data is really finished.
- * Note: lha command utility check if the total size of output bytes is
- * reached the uncompressed size recorded in its header. it does not mind
- * that the decoding process is properly finished.
- * GNU ZIP can decompress another compressed file made by SCO LZH compress.
- * it handles EOF as null to fill read buffer with zero until the decoding
- * process meet 2 bytes of zeros at reading a size of a next chunk, so the
- * zeros are treated as the mark of the end of the data although the zeros
- * is dummy, not the file data.
- */
-static int lzh_read_blocks(struct lzh_stream *, int);
-static int lzh_decode_blocks(struct lzh_stream *, int);
-#define ST_RD_BLOCK 0
-#define ST_RD_PT_1 1
-#define ST_RD_PT_2 2
-#define ST_RD_PT_3 3
-#define ST_RD_PT_4 4
-#define ST_RD_LITERAL_1 5
-#define ST_RD_LITERAL_2 6
-#define ST_RD_LITERAL_3 7
-#define ST_RD_POS_DATA_1 8
-#define ST_GET_LITERAL 9
-#define ST_GET_POS_1 10
-#define ST_GET_POS_2 11
-#define ST_COPY_DATA 12
-
-static int
-lzh_decode(struct lzh_stream *strm, int last)
-{
- struct lzh_dec *ds = strm->ds;
- int64_t avail_in;
- int r;
-
- if (ds->error)
- return (ds->error);
-
- avail_in = strm->avail_in;
- do {
- if (ds->state < ST_GET_LITERAL)
- r = lzh_read_blocks(strm, last);
- else
- r = lzh_decode_blocks(strm, last);
- } while (r == 100);
- strm->total_in += avail_in - strm->avail_in;
- return (r);
-}
-
-static int
-lzh_copy_from_window(struct lzh_stream *strm, struct lzh_dec *ds)
-{
- size_t copy_bytes;
-
- if (ds->w_remaining == 0 && ds->w_pos > 0) {
- if (ds->w_pos - ds->copy_pos <= strm->avail_out)
- copy_bytes = ds->w_pos - ds->copy_pos;
- else
- copy_bytes = (size_t)strm->avail_out;
- memcpy(strm->next_out,
- ds->w_buff + ds->copy_pos, copy_bytes);
- ds->copy_pos += (int)copy_bytes;
- } else {
- if (ds->w_remaining <= strm->avail_out)
- copy_bytes = ds->w_remaining;
- else
- copy_bytes = (size_t)strm->avail_out;
- memcpy(strm->next_out,
- ds->w_buff + ds->w_size - ds->w_remaining, copy_bytes);
- ds->w_remaining -= (int)copy_bytes;
- }
- strm->next_out += copy_bytes;
- strm->avail_out -= copy_bytes;
- strm->total_out += copy_bytes;
- if (strm->avail_out == 0)
- return (0);
- else
- return (1);
-}
-
-static int
-lzh_read_blocks(struct lzh_stream *strm, int last)
-{
- struct lzh_dec *ds = strm->ds;
- struct lzh_br *br = &(ds->br);
- int c = 0, i;
- unsigned rbits;
-
- for (;;) {
- switch (ds->state) {
- case ST_RD_BLOCK:
- /*
- * Read a block number indicates how many blocks
- * we will handle. The block is composed of a
- * literal and a match, sometimes a literal only
- * in particular, there are no reference data at
- * the beginning of the decompression.
- */
- if (!lzh_br_read_ahead_0(strm, br, 16)) {
- if (!last)
- /* We need following data. */
- return (ARCHIVE_OK);
- if (lzh_br_has(br, 8)) {
- /*
- * It seems there are extra bits.
- * 1. Compressed data is broken.
- * 2. `last' flag does not properly
- * set.
- */
- goto failed;
- }
- if (ds->w_pos > 0) {
- if (!lzh_copy_from_window(strm, ds))
- return (ARCHIVE_OK);
- }
- /* End of compressed data; we have completely
- * handled all compressed data. */
- return (ARCHIVE_EOF);
- }
- ds->blocks_avail = lzh_br_bits(br, 16);
- if (ds->blocks_avail == 0)
- goto failed;
- lzh_br_consume(br, 16);
- /*
- * Read a literal table compressed in huffman
- * coding.
- */
- ds->pt.len_size = ds->literal_pt_len_size;
- ds->pt.len_bits = ds->literal_pt_len_bits;
- ds->reading_position = 0;
- /* FALL THROUGH */
- case ST_RD_PT_1:
- /* Note: ST_RD_PT_1, ST_RD_PT_2 and ST_RD_PT_4 are
- * used in reading both a literal table and a
- * position table. */
- if (!lzh_br_read_ahead(strm, br, ds->pt.len_bits)) {
- if (last)
- goto failed;/* Truncated data. */
- ds->state = ST_RD_PT_1;
- return (ARCHIVE_OK);
- }
- ds->pt.len_avail = lzh_br_bits(br, ds->pt.len_bits);
- lzh_br_consume(br, ds->pt.len_bits);
- /* FALL THROUGH */
- case ST_RD_PT_2:
- if (ds->pt.len_avail == 0) {
- /* There is no bitlen. */
- if (!lzh_br_read_ahead(strm, br,
- ds->pt.len_bits)) {
- if (last)
- goto failed;/* Truncated data.*/
- ds->state = ST_RD_PT_2;
- return (ARCHIVE_OK);
- }
- if (!lzh_make_fake_table(&(ds->pt),
- lzh_br_bits(br, ds->pt.len_bits)))
- goto failed;/* Invalid data. */
- lzh_br_consume(br, ds->pt.len_bits);
- if (ds->reading_position)
- ds->state = ST_GET_LITERAL;
- else
- ds->state = ST_RD_LITERAL_1;
- break;
- } else if (ds->pt.len_avail > ds->pt.len_size)
- goto failed;/* Invalid data. */
- ds->loop = 0;
- memset(ds->pt.freq, 0, sizeof(ds->pt.freq));
- if (ds->pt.len_avail < 3 ||
- ds->pt.len_size == ds->pos_pt_len_size) {
- ds->state = ST_RD_PT_4;
- break;
- }
- /* FALL THROUGH */
- case ST_RD_PT_3:
- ds->loop = lzh_read_pt_bitlen(strm, ds->loop, 3);
- if (ds->loop < 3) {
- if (ds->loop < 0 || last)
- goto failed;/* Invalid data. */
- /* Not completed, get following data. */
- ds->state = ST_RD_PT_3;
- return (ARCHIVE_OK);
- }
- /* There are some null in bitlen of the literal. */
- if (!lzh_br_read_ahead(strm, br, 2)) {
- if (last)
- goto failed;/* Truncated data. */
- ds->state = ST_RD_PT_3;
- return (ARCHIVE_OK);
- }
- c = lzh_br_bits(br, 2);
- lzh_br_consume(br, 2);
- if (c > ds->pt.len_avail - 3)
- goto failed;/* Invalid data. */
- for (i = 3; c-- > 0 ;)
- ds->pt.bitlen[i++] = 0;
- ds->loop = i;
- /* FALL THROUGH */
- case ST_RD_PT_4:
- ds->loop = lzh_read_pt_bitlen(strm, ds->loop,
- ds->pt.len_avail);
- if (ds->loop < ds->pt.len_avail) {
- if (ds->loop < 0 || last)
- goto failed;/* Invalid data. */
- /* Not completed, get following data. */
- ds->state = ST_RD_PT_4;
- return (ARCHIVE_OK);
- }
- if (!lzh_make_huffman_table(&(ds->pt)))
- goto failed;/* Invalid data */
- if (ds->reading_position) {
- ds->state = ST_GET_LITERAL;
- break;
- }
- /* FALL THROUGH */
- case ST_RD_LITERAL_1:
- if (!lzh_br_read_ahead(strm, br, ds->lt.len_bits)) {
- if (last)
- goto failed;/* Truncated data. */
- ds->state = ST_RD_LITERAL_1;
- return (ARCHIVE_OK);
- }
- ds->lt.len_avail = lzh_br_bits(br, ds->lt.len_bits);
- lzh_br_consume(br, ds->lt.len_bits);
- /* FALL THROUGH */
- case ST_RD_LITERAL_2:
- if (ds->lt.len_avail == 0) {
- /* There is no bitlen. */
- if (!lzh_br_read_ahead(strm, br,
- ds->lt.len_bits)) {
- if (last)
- goto failed;/* Truncated data.*/
- ds->state = ST_RD_LITERAL_2;
- return (ARCHIVE_OK);
- }
- if (!lzh_make_fake_table(&(ds->lt),
- lzh_br_bits(br, ds->lt.len_bits)))
- goto failed;/* Invalid data */
- lzh_br_consume(br, ds->lt.len_bits);
- ds->state = ST_RD_POS_DATA_1;
- break;
- } else if (ds->lt.len_avail > ds->lt.len_size)
- goto failed;/* Invalid data */
- ds->loop = 0;
- memset(ds->lt.freq, 0, sizeof(ds->lt.freq));
- /* FALL THROUGH */
- case ST_RD_LITERAL_3:
- i = ds->loop;
- while (i < ds->lt.len_avail) {
- if (!lzh_br_read_ahead(strm, br,
- ds->pt.max_bits)) {
- if (last)
- goto failed;/* Truncated data.*/
- ds->loop = i;
- ds->state = ST_RD_LITERAL_3;
- return (ARCHIVE_OK);
- }
- rbits = lzh_br_bits(br, ds->pt.max_bits);
- c = lzh_decode_huffman(&(ds->pt), rbits);
- if (c > 2) {
- /* Note: 'c' will never be more than
- * eighteen since it's limited by
- * PT_BITLEN_SIZE, which is being set
- * to ds->pt.len_size through
- * ds->literal_pt_len_size. */
- lzh_br_consume(br, ds->pt.bitlen[c]);
- c -= 2;
- ds->lt.freq[c]++;
- ds->lt.bitlen[i++] = c;
- } else if (c == 0) {
- lzh_br_consume(br, ds->pt.bitlen[c]);
- ds->lt.bitlen[i++] = 0;
- } else {
- /* c == 1 or c == 2 */
- int n = (c == 1)?4:9;
- if (!lzh_br_read_ahead(strm, br,
- ds->pt.bitlen[c] + n)) {
- if (last) /* Truncated data. */
- goto failed;
- ds->loop = i;
- ds->state = ST_RD_LITERAL_3;
- return (ARCHIVE_OK);
- }
- lzh_br_consume(br, ds->pt.bitlen[c]);
- c = lzh_br_bits(br, n);
- lzh_br_consume(br, n);
- c += (n == 4)?3:20;
- if (i + c > ds->lt.len_avail)
- goto failed;/* Invalid data */
- memset(&(ds->lt.bitlen[i]), 0, c);
- i += c;
- }
- }
- if (i > ds->lt.len_avail ||
- !lzh_make_huffman_table(&(ds->lt)))
- goto failed;/* Invalid data */
- /* FALL THROUGH */
- case ST_RD_POS_DATA_1:
- /*
- * Read a position table compressed in huffman
- * coding.
- */
- ds->pt.len_size = ds->pos_pt_len_size;
- ds->pt.len_bits = ds->pos_pt_len_bits;
- ds->reading_position = 1;
- ds->state = ST_RD_PT_1;
- break;
- case ST_GET_LITERAL:
- return (100);
- }
- }
-failed:
- return (ds->error = ARCHIVE_FAILED);
-}
-
-static int
-lzh_decode_blocks(struct lzh_stream *strm, int last)
-{
- struct lzh_dec *ds = strm->ds;
- struct lzh_br bre = ds->br;
- struct huffman *lt = &(ds->lt);
- struct huffman *pt = &(ds->pt);
- unsigned char *w_buff = ds->w_buff;
- unsigned char *lt_bitlen = lt->bitlen;
- unsigned char *pt_bitlen = pt->bitlen;
- int blocks_avail = ds->blocks_avail, c = 0;
- int copy_len = ds->copy_len, copy_pos = ds->copy_pos;
- int w_pos = ds->w_pos, w_mask = ds->w_mask, w_size = ds->w_size;
- int lt_max_bits = lt->max_bits, pt_max_bits = pt->max_bits;
- int state = ds->state;
-
- if (ds->w_remaining > 0) {
- if (!lzh_copy_from_window(strm, ds))
- goto next_data;
- }
- for (;;) {
- switch (state) {
- case ST_GET_LITERAL:
- for (;;) {
- if (blocks_avail == 0) {
- /* We have decoded all blocks.
- * Let's handle next blocks. */
- ds->state = ST_RD_BLOCK;
- ds->br = bre;
- ds->blocks_avail = 0;
- ds->w_pos = w_pos;
- ds->copy_pos = 0;
- return (100);
- }
-
- /* lzh_br_read_ahead() always try to fill the
- * cache buffer up. In specific situation we
- * are close to the end of the data, the cache
- * buffer will not be full and thus we have to
- * determine if the cache buffer has some bits
- * as much as we need after lzh_br_read_ahead()
- * failed. */
- if (!lzh_br_read_ahead(strm, &bre,
- lt_max_bits)) {
- if (!last)
- goto next_data;
- /* Remaining bits are less than
- * maximum bits(lt.max_bits) but maybe
- * it still remains as much as we need,
- * so we should try to use it with
- * dummy bits. */
- c = lzh_decode_huffman(lt,
- lzh_br_bits_forced(&bre,
- lt_max_bits));
- lzh_br_consume(&bre, lt_bitlen[c]);
- if (!lzh_br_has(&bre, 0))
- goto failed;/* Over read. */
- } else {
- c = lzh_decode_huffman(lt,
- lzh_br_bits(&bre, lt_max_bits));
- lzh_br_consume(&bre, lt_bitlen[c]);
- }
- blocks_avail--;
- if (c > UCHAR_MAX)
- /* Current block is a match data. */
- break;
- /*
- * 'c' is exactly a literal code.
- */
- /* Save a decoded code to reference it
- * afterward. */
- w_buff[w_pos] = c;
- if (++w_pos >= w_size) {
- w_pos = 0;
- ds->w_remaining = w_size;
- if (!lzh_copy_from_window(strm, ds))
- goto next_data;
- }
- }
- /* 'c' is the length of a match pattern we have
- * already extracted, which has be stored in
- * window(ds->w_buff). */
- copy_len = c - (UCHAR_MAX + 1) + MINMATCH;
- /* FALL THROUGH */
- case ST_GET_POS_1:
- /*
- * Get a reference position.
- */
- if (!lzh_br_read_ahead(strm, &bre, pt_max_bits)) {
- if (!last) {
- state = ST_GET_POS_1;
- ds->copy_len = copy_len;
- goto next_data;
- }
- copy_pos = lzh_decode_huffman(pt,
- lzh_br_bits_forced(&bre, pt_max_bits));
- lzh_br_consume(&bre, pt_bitlen[copy_pos]);
- if (!lzh_br_has(&bre, 0))
- goto failed;/* Over read. */
- } else {
- copy_pos = lzh_decode_huffman(pt,
- lzh_br_bits(&bre, pt_max_bits));
- lzh_br_consume(&bre, pt_bitlen[copy_pos]);
- }
- /* FALL THROUGH */
- case ST_GET_POS_2:
- if (copy_pos > 1) {
- /* We need an additional adjustment number to
- * the position. */
- int p = copy_pos - 1;
- if (!lzh_br_read_ahead(strm, &bre, p)) {
- if (last)
- goto failed;/* Truncated data.*/
- state = ST_GET_POS_2;
- ds->copy_len = copy_len;
- ds->copy_pos = copy_pos;
- goto next_data;
- }
- copy_pos = (1 << p) + lzh_br_bits(&bre, p);
- lzh_br_consume(&bre, p);
- }
- /* The position is actually a distance from the last
- * code we had extracted and thus we have to convert
- * it to a position of the window. */
- copy_pos = (w_pos - copy_pos - 1) & w_mask;
- /* FALL THROUGH */
- case ST_COPY_DATA:
- /*
- * Copy `copy_len' bytes as extracted data from
- * the window into the output buffer.
- */
- for (;;) {
- int l;
-
- l = copy_len;
- if (copy_pos > w_pos) {
- if (l > w_size - copy_pos)
- l = w_size - copy_pos;
- } else {
- if (l > w_size - w_pos)
- l = w_size - w_pos;
- }
- if ((copy_pos + l < w_pos)
- || (w_pos + l < copy_pos)) {
- /* No overlap. */
- memcpy(w_buff + w_pos,
- w_buff + copy_pos, l);
- } else {
- const unsigned char *s;
- unsigned char *d;
- int li;
-
- d = w_buff + w_pos;
- s = w_buff + copy_pos;
- for (li = 0; li < l; li++)
- d[li] = s[li];
- }
- w_pos = (w_pos + l) & w_mask;
- if (w_pos == 0) {
- ds->w_remaining = w_size;
- if (!lzh_copy_from_window(strm, ds)) {
- if (copy_len <= l)
- state = ST_GET_LITERAL;
- else {
- state = ST_COPY_DATA;
- ds->copy_len =
- copy_len - l;
- ds->copy_pos =
- (copy_pos + l)
- & w_mask;
- }
- goto next_data;
- }
- }
- if (copy_len <= l)
- /* A copy of current pattern ended. */
- break;
- copy_len -= l;
- copy_pos = (copy_pos + l) & w_mask;
- }
- state = ST_GET_LITERAL;
- break;
- }
- }
-failed:
- return (ds->error = ARCHIVE_FAILED);
-next_data:
- ds->br = bre;
- ds->blocks_avail = blocks_avail;
- ds->state = state;
- ds->w_pos = w_pos;
- return (ARCHIVE_OK);
-}
-
-static int
-lzh_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
-{
- int bits;
-
- if (hf->bitlen == NULL) {
- hf->bitlen = malloc(len_size * sizeof(hf->bitlen[0]));
- if (hf->bitlen == NULL)
- return (ARCHIVE_FATAL);
- }
- if (hf->tbl == NULL) {
- if (tbl_bits < HTBL_BITS)
- bits = tbl_bits;
- else
- bits = HTBL_BITS;
- hf->tbl = malloc(((size_t)1 << bits) * sizeof(hf->tbl[0]));
- if (hf->tbl == NULL)
- return (ARCHIVE_FATAL);
- }
- if (hf->tree == NULL && tbl_bits > HTBL_BITS) {
- hf->tree_avail = 1 << (tbl_bits - HTBL_BITS + 4);
- hf->tree = malloc(hf->tree_avail * sizeof(hf->tree[0]));
- if (hf->tree == NULL)
- return (ARCHIVE_FATAL);
- }
- hf->len_size = (int)len_size;
- hf->tbl_bits = tbl_bits;
- return (ARCHIVE_OK);
-}
-
-static void
-lzh_huffman_free(struct huffman *hf)
-{
- free(hf->bitlen);
- free(hf->tbl);
- free(hf->tree);
-}
-
-static int
-lzh_read_pt_bitlen(struct lzh_stream *strm, int start, int end)
-{
- struct lzh_dec *ds = strm->ds;
- struct lzh_br * br = &(ds->br);
- int c, i;
-
- for (i = start; i < end;) {
- /*
- * bit pattern the number we need
- * 000 -> 0
- * 001 -> 1
- * 010 -> 2
- * ...
- * 110 -> 6
- * 1110 -> 7
- * 11110 -> 8
- * ...
- * 1111111111110 -> 16
- */
- if (!lzh_br_read_ahead(strm, br, 3))
- return (i);
- if ((c = lzh_br_bits(br, 3)) == 7) {
- int d;
- if (!lzh_br_read_ahead(strm, br, 13))
- return (i);
- d = lzh_br_bits(br, 13);
- while (d & 0x200) {
- c++;
- d <<= 1;
- }
- if (c > 16)
- return (-1);/* Invalid data. */
- lzh_br_consume(br, c - 3);
- } else
- lzh_br_consume(br, 3);
- ds->pt.bitlen[i++] = c;
- ds->pt.freq[c]++;
- }
- return (i);
-}
-
-static int
-lzh_make_fake_table(struct huffman *hf, uint16_t c)
-{
- if (c >= hf->len_size)
- return (0);
- hf->tbl[0] = c;
- hf->max_bits = 0;
- hf->shift_bits = 0;
- hf->bitlen[hf->tbl[0]] = 0;
- return (1);
-}
-
-/*
- * Make a huffman coding table.
- */
-static int
-lzh_make_huffman_table(struct huffman *hf)
-{
- uint16_t *tbl;
- const unsigned char *bitlen;
- int bitptn[17], weight[17];
- int i, maxbits = 0, ptn, tbl_size, w;
- int diffbits, len_avail;
-
- /*
- * Initialize bit patterns.
- */
- ptn = 0;
- for (i = 1, w = 1 << 15; i <= 16; i++, w >>= 1) {
- bitptn[i] = ptn;
- weight[i] = w;
- if (hf->freq[i]) {
- ptn += hf->freq[i] * w;
- maxbits = i;
- }
- }
- if (ptn != 0x10000 || maxbits > hf->tbl_bits)
- return (0);/* Invalid */
-
- hf->max_bits = maxbits;
-
- /*
- * Cut out extra bits which we won't house in the table.
- * This preparation reduces the same calculation in the for-loop
- * making the table.
- */
- if (maxbits < 16) {
- int ebits = 16 - maxbits;
- for (i = 1; i <= maxbits; i++) {
- bitptn[i] >>= ebits;
- weight[i] >>= ebits;
- }
- }
- if (maxbits > HTBL_BITS) {
- int htbl_max;
- uint16_t *p;
-
- diffbits = maxbits - HTBL_BITS;
- for (i = 1; i <= HTBL_BITS; i++) {
- bitptn[i] >>= diffbits;
- weight[i] >>= diffbits;
- }
- htbl_max = bitptn[HTBL_BITS] +
- weight[HTBL_BITS] * hf->freq[HTBL_BITS];
- p = &(hf->tbl[htbl_max]);
- while (p < &hf->tbl[1U<<HTBL_BITS])
- *p++ = 0;
- } else
- diffbits = 0;
- hf->shift_bits = diffbits;
-
- /*
- * Make the table.
- */
- tbl_size = 1 << HTBL_BITS;
- tbl = hf->tbl;
- bitlen = hf->bitlen;
- len_avail = hf->len_avail;
- hf->tree_used = 0;
- for (i = 0; i < len_avail; i++) {
- uint16_t *p;
- int len, cnt;
- uint16_t bit;
- int extlen;
- struct htree_t *ht;
-
- if (bitlen[i] == 0)
- continue;
- /* Get a bit pattern */
- len = bitlen[i];
- ptn = bitptn[len];
- cnt = weight[len];
- if (len <= HTBL_BITS) {
- /* Calculate next bit pattern */
- if ((bitptn[len] = ptn + cnt) > tbl_size)
- return (0);/* Invalid */
- /* Update the table */
- p = &(tbl[ptn]);
- while (--cnt >= 0)
- p[cnt] = (uint16_t)i;
- continue;
- }
-
- /*
- * A bit length is too big to be housed to a direct table,
- * so we use a tree model for its extra bits.
- */
- bitptn[len] = ptn + cnt;
- bit = 1U << (diffbits -1);
- extlen = len - HTBL_BITS;
-
- p = &(tbl[ptn >> diffbits]);
- if (*p == 0) {
- *p = len_avail + hf->tree_used;
- ht = &(hf->tree[hf->tree_used++]);
- if (hf->tree_used > hf->tree_avail)
- return (0);/* Invalid */
- ht->left = 0;
- ht->right = 0;
- } else {
- if (*p < len_avail ||
- *p >= (len_avail + hf->tree_used))
- return (0);/* Invalid */
- ht = &(hf->tree[*p - len_avail]);
- }
- while (--extlen > 0) {
- if (ptn & bit) {
- if (ht->left < len_avail) {
- ht->left = len_avail + hf->tree_used;
- ht = &(hf->tree[hf->tree_used++]);
- if (hf->tree_used > hf->tree_avail)
- return (0);/* Invalid */
- ht->left = 0;
- ht->right = 0;
- } else {
- ht = &(hf->tree[ht->left - len_avail]);
- }
- } else {
- if (ht->right < len_avail) {
- ht->right = len_avail + hf->tree_used;
- ht = &(hf->tree[hf->tree_used++]);
- if (hf->tree_used > hf->tree_avail)
- return (0);/* Invalid */
- ht->left = 0;
- ht->right = 0;
- } else {
- ht = &(hf->tree[ht->right - len_avail]);
- }
- }
- bit >>= 1;
- }
- if (ptn & bit) {
- if (ht->left != 0)
- return (0);/* Invalid */
- ht->left = (uint16_t)i;
- } else {
- if (ht->right != 0)
- return (0);/* Invalid */
- ht->right = (uint16_t)i;
- }
- }
- return (1);
-}
-
-static int
-lzh_decode_huffman_tree(struct huffman *hf, unsigned rbits, int c)
-{
- struct htree_t *ht;
- int extlen;
-
- ht = hf->tree;
- extlen = hf->shift_bits;
- while (c >= hf->len_avail) {
- c -= hf->len_avail;
- if (extlen-- <= 0 || c >= hf->tree_used)
- return (0);
- if (rbits & (1U << extlen))
- c = ht[c].left;
- else
- c = ht[c].right;
- }
- return (c);
-}
-
-static inline int
-lzh_decode_huffman(struct huffman *hf, unsigned rbits)
-{
- int c;
- /*
- * At first search an index table for a bit pattern.
- * If it fails, search a huffman tree for.
- */
- c = hf->tbl[rbits >> hf->shift_bits];
- if (c < hf->len_avail)
- return (c);
- /* This bit pattern needs to be found out at a huffman tree. */
- return (lzh_decode_huffman_tree(hf, rbits, c));
-}
-
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_format_mtree.c b/3rdparty/libarchive/libarchive/archive_read_support_format_mtree.c
deleted file mode 100644
index c4e7021a..00000000
--- a/3rdparty/libarchive/libarchive/archive_read_support_format_mtree.c
+++ /dev/null
@@ -1,1872 +0,0 @@
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * Copyright (c) 2008 Joerg Sonnenberger
- * Copyright (c) 2011-2012 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"
-__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_mtree.c 201165 2009-12-29 05:52:13Z kientzle $");
-
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#include <stddef.h>
-/* #include <stdint.h> */ /* See archive_platform.h */
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#include "archive.h"
-#include "archive_entry.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-#include "archive_string.h"
-
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-#ifndef O_CLOEXEC
-#define O_CLOEXEC 0
-#endif
-
-#define MTREE_HAS_DEVICE 0x0001
-#define MTREE_HAS_FFLAGS 0x0002
-#define MTREE_HAS_GID 0x0004
-#define MTREE_HAS_GNAME 0x0008
-#define MTREE_HAS_MTIME 0x0010
-#define MTREE_HAS_NLINK 0x0020
-#define MTREE_HAS_PERM 0x0040
-#define MTREE_HAS_SIZE 0x0080
-#define MTREE_HAS_TYPE 0x0100
-#define MTREE_HAS_UID 0x0200
-#define MTREE_HAS_UNAME 0x0400
-
-#define MTREE_HAS_OPTIONAL 0x0800
-#define MTREE_HAS_NOCHANGE 0x1000 /* FreeBSD specific */
-
-struct mtree_option {
- struct mtree_option *next;
- char *value;
-};
-
-struct mtree_entry {
- struct mtree_entry *next;
- struct mtree_option *options;
- char *name;
- char full;
- char used;
-};
-
-struct mtree {
- struct archive_string line;
- size_t buffsize;
- char *buff;
- int64_t offset;
- int fd;
- int archive_format;
- const char *archive_format_name;
- struct mtree_entry *entries;
- struct mtree_entry *this_entry;
- struct archive_string current_dir;
- struct archive_string contents_name;
-
- struct archive_entry_linkresolver *resolver;
-
- int64_t cur_size;
-};
-
-static int bid_keycmp(const char *, const char *, ssize_t);
-static int cleanup(struct archive_read *);
-static int detect_form(struct archive_read *, int *);
-static int mtree_bid(struct archive_read *, int);
-static int parse_file(struct archive_read *, struct archive_entry *,
- struct mtree *, struct mtree_entry *, int *);
-static void parse_escapes(char *, struct mtree_entry *);
-static int parse_line(struct archive_read *, struct archive_entry *,
- struct mtree *, struct mtree_entry *, int *);
-static int parse_keyword(struct archive_read *, struct mtree *,
- struct archive_entry *, struct mtree_option *, int *);
-static int read_data(struct archive_read *a,
- const void **buff, size_t *size, int64_t *offset);
-static ssize_t readline(struct archive_read *, struct mtree *, char **, ssize_t);
-static int skip(struct archive_read *a);
-static int read_header(struct archive_read *,
- struct archive_entry *);
-static int64_t mtree_atol10(char **);
-static int64_t mtree_atol8(char **);
-static int64_t mtree_atol(char **);
-
-/*
- * There's no standard for TIME_T_MAX/TIME_T_MIN. So we compute them
- * here. TODO: Move this to configure time, but be careful
- * about cross-compile environments.
- */
-static int64_t
-get_time_t_max(void)
-{
-#if defined(TIME_T_MAX)
- return TIME_T_MAX;
-#else
- static time_t t;
- time_t a;
- if (t == 0) {
- a = 1;
- while (a > t) {
- t = a;
- a = a * 2 + 1;
- }
- }
- return t;
-#endif
-}
-
-static int64_t
-get_time_t_min(void)
-{
-#if defined(TIME_T_MIN)
- return TIME_T_MIN;
-#else
- /* 't' will hold the minimum value, which will be zero (if
- * time_t is unsigned) or -2^n (if time_t is signed). */
- static int computed;
- static time_t t;
- time_t a;
- if (computed == 0) {
- a = (time_t)-1;
- while (a < t) {
- t = a;
- a = a * 2;
- }
- computed = 1;
- }
- return t;
-#endif
-}
-
-static void
-free_options(struct mtree_option *head)
-{
- struct mtree_option *next;
-
- for (; head != NULL; head = next) {
- next = head->next;
- free(head->value);
- free(head);
- }
-}
-
-int
-archive_read_support_format_mtree(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct mtree *mtree;
- int r;
-
- archive_check_magic(_a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_NEW, "archive_read_support_format_mtree");
-
- mtree = (struct mtree *)malloc(sizeof(*mtree));
- if (mtree == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate mtree data");
- return (ARCHIVE_FATAL);
- }
- memset(mtree, 0, sizeof(*mtree));
- mtree->fd = -1;
-
- r = __archive_read_register_format(a, mtree, "mtree",
- mtree_bid, NULL, read_header, read_data, skip, NULL, cleanup);
-
- if (r != ARCHIVE_OK)
- free(mtree);
- return (ARCHIVE_OK);
-}
-
-static int
-cleanup(struct archive_read *a)
-{
- struct mtree *mtree;
- struct mtree_entry *p, *q;
-
- mtree = (struct mtree *)(a->format->data);
-
- p = mtree->entries;
- while (p != NULL) {
- q = p->next;
- free(p->name);
- free_options(p->options);
- free(p);
- p = q;
- }
- archive_string_free(&mtree->line);
- archive_string_free(&mtree->current_dir);
- archive_string_free(&mtree->contents_name);
- archive_entry_linkresolver_free(mtree->resolver);
-
- free(mtree->buff);
- free(mtree);
- (a->format->data) = NULL;
- return (ARCHIVE_OK);
-}
-
-static ssize_t
-get_line_size(const char *b, ssize_t avail, ssize_t *nlsize)
-{
- ssize_t len;
-
- len = 0;
- while (len < avail) {
- switch (*b) {
- case '\0':/* Non-ascii character or control character. */
- if (nlsize != NULL)
- *nlsize = 0;
- return (-1);
- case '\r':
- if (avail-len > 1 && b[1] == '\n') {
- if (nlsize != NULL)
- *nlsize = 2;
- return (len+2);
- }
- /* FALL THROUGH */
- case '\n':
- if (nlsize != NULL)
- *nlsize = 1;
- return (len+1);
- default:
- b++;
- len++;
- break;
- }
- }
- if (nlsize != NULL)
- *nlsize = 0;
- return (avail);
-}
-
-static ssize_t
-next_line(struct archive_read *a,
- const char **b, ssize_t *avail, ssize_t *ravail, ssize_t *nl)
-{
- ssize_t len;
- int quit;
-
- quit = 0;
- if (*avail == 0) {
- *nl = 0;
- len = 0;
- } else
- len = get_line_size(*b, *avail, nl);
- /*
- * Read bytes more while it does not reach the end of line.
- */
- while (*nl == 0 && len == *avail && !quit) {
- ssize_t diff = *ravail - *avail;
- size_t nbytes_req = (*ravail+1023) & ~1023U;
- ssize_t tested;
-
- /* Increase reading bytes if it is not enough to at least
- * new two lines. */
- if (nbytes_req < (size_t)*ravail + 160)
- nbytes_req <<= 1;
-
- *b = __archive_read_ahead(a, nbytes_req, avail);
- if (*b == NULL) {
- if (*ravail >= *avail)
- return (0);
- /* Reading bytes reaches the end of file. */
- *b = __archive_read_ahead(a, *avail, avail);
- quit = 1;
- }
- *ravail = *avail;
- *b += diff;
- *avail -= diff;
- tested = len;/* Skip some bytes we already determinated. */
- len = get_line_size(*b, *avail, nl);
- if (len >= 0)
- len += tested;
- }
- return (len);
-}
-
-/*
- * Compare characters with a mtree keyword.
- * Returns the length of a mtree keyword if matched.
- * Returns 0 if not matched.
- */
-static int
-bid_keycmp(const char *p, const char *key, ssize_t len)
-{
- int match_len = 0;
-
- while (len > 0 && *p && *key) {
- if (*p == *key) {
- --len;
- ++p;
- ++key;
- ++match_len;
- continue;
- }
- return (0);/* Not match */
- }
- if (*key != '\0')
- return (0);/* Not match */
-
- /* A following character should be specified characters */
- if (p[0] == '=' || p[0] == ' ' || p[0] == '\t' ||
- p[0] == '\n' || p[0] == '\r' ||
- (p[0] == '\\' && (p[1] == '\n' || p[1] == '\r')))
- return (match_len);
- return (0);/* Not match */
-}
-
-/*
- * Test whether the characters 'p' has is mtree keyword.
- * Returns the length of a detected keyword.
- * Returns 0 if any keywords were not found.
- */
-static int
-bid_keyword(const char *p, ssize_t len)
-{
- static const char *keys_c[] = {
- "content", "contents", "cksum", NULL
- };
- static const char *keys_df[] = {
- "device", "flags", NULL
- };
- static const char *keys_g[] = {
- "gid", "gname", NULL
- };
- static const char *keys_il[] = {
- "ignore", "link", NULL
- };
- static const char *keys_m[] = {
- "md5", "md5digest", "mode", NULL
- };
- static const char *keys_no[] = {
- "nlink", "nochange", "optional", NULL
- };
- static const char *keys_r[] = {
- "rmd160", "rmd160digest", NULL
- };
- static const char *keys_s[] = {
- "sha1", "sha1digest",
- "sha256", "sha256digest",
- "sha384", "sha384digest",
- "sha512", "sha512digest",
- "size", NULL
- };
- static const char *keys_t[] = {
- "tags", "time", "type", NULL
- };
- static const char *keys_u[] = {
- "uid", "uname", NULL
- };
- const char **keys;
- int i;
-
- switch (*p) {
- case 'c': keys = keys_c; break;
- case 'd': case 'f': keys = keys_df; break;
- case 'g': keys = keys_g; break;
- case 'i': case 'l': keys = keys_il; break;
- case 'm': keys = keys_m; break;
- case 'n': case 'o': keys = keys_no; break;
- case 'r': keys = keys_r; break;
- case 's': keys = keys_s; break;
- case 't': keys = keys_t; break;
- case 'u': keys = keys_u; break;
- default: return (0);/* Unknown key */
- }
-
- for (i = 0; keys[i] != NULL; i++) {
- int l = bid_keycmp(p, keys[i], len);
- if (l > 0)
- return (l);
- }
- return (0);/* Unknown key */
-}
-
-/*
- * Test whether there is a set of mtree keywords.
- * Returns the number of keyword.
- * Returns -1 if we got incorrect sequence.
- * This function expects a set of "<space characters>keyword=value".
- * When "unset" is specified, expects a set of "<space characters>keyword".
- */
-static int
-bid_keyword_list(const char *p, ssize_t len, int unset, int last_is_path)
-{
- int l;
- int keycnt = 0;
-
- while (len > 0 && *p) {
- int blank = 0;
-
- /* Test whether there are blank characters in the line. */
- while (len >0 && (*p == ' ' || *p == '\t')) {
- ++p;
- --len;
- blank = 1;
- }
- if (*p == '\n' || *p == '\r')
- break;
- if (p[0] == '\\' && (p[1] == '\n' || p[1] == '\r'))
- break;
- if (!blank && !last_is_path) /* No blank character. */
- return (-1);
- if (last_is_path && len == 0)
- return (keycnt);
-
- if (unset) {
- l = bid_keycmp(p, "all", len);
- if (l > 0)
- return (1);
- }
- /* Test whether there is a correct key in the line. */
- l = bid_keyword(p, len);
- if (l == 0)
- return (-1);/* Unknown keyword was found. */
- p += l;
- len -= l;
- keycnt++;
-
- /* Skip value */
- if (*p == '=') {
- int value = 0;
- ++p;
- --len;
- while (len > 0 && *p != ' ' && *p != '\t') {
- ++p;
- --len;
- value = 1;
- }
- /* A keyword should have a its value unless
- * "/unset" operation. */
- if (!unset && value == 0)
- return (-1);
- }
- }
- return (keycnt);
-}
-
-static int
-bid_entry(const char *p, ssize_t len, ssize_t nl, int *last_is_path)
-{
- int f = 0;
- static const unsigned char safe_char[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
- /* !"$%&'()*+,-./ EXCLUSION:( )(#) */
- 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
- /* 0123456789:;<>? EXCLUSION:(=) */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, /* 30 - 3F */
- /* @ABCDEFGHIJKLMNO */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
- /* PQRSTUVWXYZ[\]^_ */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
- /* `abcdefghijklmno */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
- /* pqrstuvwxyz{|}~ */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
- };
- ssize_t ll = len;
- const char *pp = p;
-
- *last_is_path = 0;
- /*
- * Skip the path-name which is quoted.
- */
- while (ll > 0 && *pp != ' ' &&*pp != '\t' && *pp != '\r' &&
- *pp != '\n') {
- if (!safe_char[*(const unsigned char *)pp]) {
- f = 0;
- break;
- }
- ++pp;
- --ll;
- ++f;
- }
- /* If a path-name was not found at the first, try to check
- * a mtree format ``NetBSD's mtree -D'' creates, which
- * places the path-name at the last. */
- if (f == 0) {
- const char *pb = p + len - nl;
- int name_len = 0;
- int slash;
-
- /* Do not accept multi lines for form D. */
- if (pb-2 >= p &&
- pb[-1] == '\\' && (pb[-2] == ' ' || pb[-2] == '\t'))
- return (-1);
- if (pb-1 >= p && pb[-1] == '\\')
- return (-1);
-
- slash = 0;
- while (p <= --pb && *pb != ' ' && *pb != '\t') {
- if (!safe_char[*(const unsigned char *)pb])
- return (-1);
- name_len++;
- /* The pathname should have a slash in this
- * format. */
- if (*pb == '/')
- slash = 1;
- }
- if (name_len == 0 || slash == 0)
- return (-1);
- /* If '/' is placed at the first in this field, this is not
- * a valid filename. */
- if (pb[1] == '/')
- return (-1);
- ll = len - nl - name_len;
- pp = p;
- *last_is_path = 1;
- }
-
- return (bid_keyword_list(pp, ll, 0, *last_is_path));
-}
-
-#define MAX_BID_ENTRY 3
-
-static int
-mtree_bid(struct archive_read *a, int best_bid)
-{
- const char *signature = "#mtree";
- const char *p;
-
- (void)best_bid; /* UNUSED */
-
- /* Now let's look at the actual header and see if it matches. */
- p = __archive_read_ahead(a, strlen(signature), NULL);
- if (p == NULL)
- return (-1);
-
- if (memcmp(p, signature, strlen(signature)) == 0)
- return (8 * (int)strlen(signature));
-
- /*
- * There is not a mtree signature. Let's try to detect mtree format.
- */
- return (detect_form(a, NULL));
-}
-
-static int
-detect_form(struct archive_read *a, int *is_form_d)
-{
- const char *p;
- ssize_t avail, ravail;
- ssize_t detected_bytes = 0, len, nl;
- int entry_cnt = 0, multiline = 0;
- int form_D = 0;/* The archive is generated by `NetBSD mtree -D'
- * (In this source we call it `form D') . */
-
- if (is_form_d != NULL)
- *is_form_d = 0;
- p = __archive_read_ahead(a, 1, &avail);
- if (p == NULL)
- return (-1);
- ravail = avail;
- for (;;) {
- len = next_line(a, &p, &avail, &ravail, &nl);
- /* The terminal character of the line should be
- * a new line character, '\r\n' or '\n'. */
- if (len <= 0 || nl == 0)
- break;
- if (!multiline) {
- /* Leading whitespace is never significant,
- * ignore it. */
- while (len > 0 && (*p == ' ' || *p == '\t')) {
- ++p;
- --avail;
- --len;
- }
- /* Skip comment or empty line. */
- if (p[0] == '#' || p[0] == '\n' || p[0] == '\r') {
- p += len;
- avail -= len;
- continue;
- }
- } else {
- /* A continuance line; the terminal
- * character of previous line was '\' character. */
- if (bid_keyword_list(p, len, 0, 0) <= 0)
- break;
- if (multiline == 1)
- detected_bytes += len;
- if (p[len-nl-1] != '\\') {
- if (multiline == 1 &&
- ++entry_cnt >= MAX_BID_ENTRY)
- break;
- multiline = 0;
- }
- p += len;
- avail -= len;
- continue;
- }
- if (p[0] != '/') {
- int last_is_path, keywords;
-
- keywords = bid_entry(p, len, nl, &last_is_path);
- if (keywords >= 0) {
- detected_bytes += len;
- if (form_D == 0) {
- if (last_is_path)
- form_D = 1;
- else if (keywords > 0)
- /* This line is not `form D'. */
- form_D = -1;
- } else if (form_D == 1) {
- if (!last_is_path && keywords > 0)
- /* This this is not `form D'
- * and We cannot accept mixed
- * format. */
- break;
- }
- if (!last_is_path && p[len-nl-1] == '\\')
- /* This line continues. */
- multiline = 1;
- else {
- /* We've got plenty of correct lines
- * to assume that this file is a mtree
- * format. */
- if (++entry_cnt >= MAX_BID_ENTRY)
- break;
- }
- } else
- break;
- } else if (strncmp(p, "/set", 4) == 0) {
- if (bid_keyword_list(p+4, len-4, 0, 0) <= 0)
- break;
- /* This line continues. */
- if (p[len-nl-1] == '\\')
- multiline = 2;
- } else if (strncmp(p, "/unset", 6) == 0) {
- if (bid_keyword_list(p+6, len-6, 1, 0) <= 0)
- break;
- /* This line continues. */
- if (p[len-nl-1] == '\\')
- multiline = 2;
- } else
- break;
-
- /* Test next line. */
- p += len;
- avail -= len;
- }
- if (entry_cnt >= MAX_BID_ENTRY || (entry_cnt > 0 && len == 0)) {
- if (is_form_d != NULL) {
- if (form_D == 1)
- *is_form_d = 1;
- }
- return (32);
- }
-
- return (0);
-}
-
-/*
- * The extended mtree format permits multiple lines specifying
- * attributes for each file. For those entries, only the last line
- * is actually used. Practically speaking, that means we have
- * to read the entire mtree file into memory up front.
- *
- * The parsing is done in two steps. First, it is decided if a line
- * changes the global defaults and if it is, processed accordingly.
- * Otherwise, the options of the line are merged with the current
- * global options.
- */
-static int
-add_option(struct archive_read *a, struct mtree_option **global,
- const char *value, size_t len)
-{
- struct mtree_option *opt;
-
- if ((opt = malloc(sizeof(*opt))) == NULL) {
- archive_set_error(&a->archive, errno, "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- if ((opt->value = malloc(len + 1)) == NULL) {
- free(opt);
- archive_set_error(&a->archive, errno, "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- memcpy(opt->value, value, len);
- opt->value[len] = '\0';
- opt->next = *global;
- *global = opt;
- return (ARCHIVE_OK);
-}
-
-static void
-remove_option(struct mtree_option **global, const char *value, size_t len)
-{
- struct mtree_option *iter, *last;
-
- last = NULL;
- for (iter = *global; iter != NULL; last = iter, iter = iter->next) {
- if (strncmp(iter->value, value, len) == 0 &&
- (iter->value[len] == '\0' ||
- iter->value[len] == '='))
- break;
- }
- if (iter == NULL)
- return;
- if (last == NULL)
- *global = iter->next;
- else
- last->next = iter->next;
-
- free(iter->value);
- free(iter);
-}
-
-static int
-process_global_set(struct archive_read *a,
- struct mtree_option **global, const char *line)
-{
- const char *next, *eq;
- size_t len;
- int r;
-
- line += 4;
- for (;;) {
- next = line + strspn(line, " \t\r\n");
- if (*next == '\0')
- return (ARCHIVE_OK);
- line = next;
- next = line + strcspn(line, " \t\r\n");
- eq = strchr(line, '=');
- if (eq > next)
- len = next - line;
- else
- len = eq - line;
-
- remove_option(global, line, len);
- r = add_option(a, global, line, next - line);
- if (r != ARCHIVE_OK)
- return (r);
- line = next;
- }
-}
-
-static int
-process_global_unset(struct archive_read *a,
- struct mtree_option **global, const char *line)
-{
- const char *next;
- size_t len;
-
- line += 6;
- if (strchr(line, '=') != NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "/unset shall not contain `='");
- return ARCHIVE_FATAL;
- }
-
- for (;;) {
- next = line + strspn(line, " \t\r\n");
- if (*next == '\0')
- return (ARCHIVE_OK);
- line = next;
- len = strcspn(line, " \t\r\n");
-
- if (len == 3 && strncmp(line, "all", 3) == 0) {
- free_options(*global);
- *global = NULL;
- } else {
- remove_option(global, line, len);
- }
-
- line += len;
- }
-}
-
-static int
-process_add_entry(struct archive_read *a, struct mtree *mtree,
- struct mtree_option **global, const char *line, ssize_t line_len,
- struct mtree_entry **last_entry, int is_form_d)
-{
- struct mtree_entry *entry;
- struct mtree_option *iter;
- const char *next, *eq, *name, *end;
- size_t len;
- int r;
-
- if ((entry = malloc(sizeof(*entry))) == NULL) {
- archive_set_error(&a->archive, errno, "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- entry->next = NULL;
- entry->options = NULL;
- entry->name = NULL;
- entry->used = 0;
- entry->full = 0;
-
- /* Add this entry to list. */
- if (*last_entry == NULL)
- mtree->entries = entry;
- else
- (*last_entry)->next = entry;
- *last_entry = entry;
-
- if (is_form_d) {
- /*
- * This form places the file name as last parameter.
- */
- name = line + line_len -1;
- while (line_len > 0) {
- if (*name != '\r' && *name != '\n' &&
- *name != '\t' && *name != ' ')
- break;
- name--;
- line_len--;
- }
- len = 0;
- while (line_len > 0) {
- if (*name == '\r' || *name == '\n' ||
- *name == '\t' || *name == ' ') {
- name++;
- break;
- }
- name--;
- line_len--;
- len++;
- }
- end = name;
- } else {
- len = strcspn(line, " \t\r\n");
- name = line;
- line += len;
- end = line + line_len;
- }
-
- if ((entry->name = malloc(len + 1)) == NULL) {
- archive_set_error(&a->archive, errno, "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
-
- memcpy(entry->name, name, len);
- entry->name[len] = '\0';
- parse_escapes(entry->name, entry);
-
- for (iter = *global; iter != NULL; iter = iter->next) {
- r = add_option(a, &entry->options, iter->value,
- strlen(iter->value));
- if (r != ARCHIVE_OK)
- return (r);
- }
-
- for (;;) {
- next = line + strspn(line, " \t\r\n");
- if (*next == '\0')
- return (ARCHIVE_OK);
- if (next >= end)
- return (ARCHIVE_OK);
- line = next;
- next = line + strcspn(line, " \t\r\n");
- eq = strchr(line, '=');
- if (eq == NULL || eq > next)
- len = next - line;
- else
- len = eq - line;
-
- remove_option(&entry->options, line, len);
- r = add_option(a, &entry->options, line, next - line);
- if (r != ARCHIVE_OK)
- return (r);
- line = next;
- }
-}
-
-static int
-read_mtree(struct archive_read *a, struct mtree *mtree)
-{
- ssize_t len;
- uintmax_t counter;
- char *p;
- struct mtree_option *global;
- struct mtree_entry *last_entry;
- int r, is_form_d;
-
- mtree->archive_format = ARCHIVE_FORMAT_MTREE;
- mtree->archive_format_name = "mtree";
-
- global = NULL;
- last_entry = NULL;
-
- (void)detect_form(a, &is_form_d);
-
- for (counter = 1; ; ++counter) {
- len = readline(a, mtree, &p, 65536);
- if (len == 0) {
- mtree->this_entry = mtree->entries;
- free_options(global);
- return (ARCHIVE_OK);
- }
- if (len < 0) {
- free_options(global);
- return ((int)len);
- }
- /* Leading whitespace is never significant, ignore it. */
- while (*p == ' ' || *p == '\t') {
- ++p;
- --len;
- }
- /* Skip content lines and blank lines. */
- if (*p == '#')
- continue;
- if (*p == '\r' || *p == '\n' || *p == '\0')
- continue;
- if (*p != '/') {
- r = process_add_entry(a, mtree, &global, p, len,
- &last_entry, is_form_d);
- } else if (strncmp(p, "/set", 4) == 0) {
- if (p[4] != ' ' && p[4] != '\t')
- break;
- r = process_global_set(a, &global, p);
- } else if (strncmp(p, "/unset", 6) == 0) {
- if (p[6] != ' ' && p[6] != '\t')
- break;
- r = process_global_unset(a, &global, p);
- } else
- break;
-
- if (r != ARCHIVE_OK) {
- free_options(global);
- return r;
- }
- }
-
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't parse line %ju", counter);
- free_options(global);
- return (ARCHIVE_FATAL);
-}
-
-/*
- * Read in the entire mtree file into memory on the first request.
- * Then use the next unused file to satisfy each header request.
- */
-static int
-read_header(struct archive_read *a, struct archive_entry *entry)
-{
- struct mtree *mtree;
- char *p;
- int r, use_next;
-
- mtree = (struct mtree *)(a->format->data);
-
- if (mtree->fd >= 0) {
- close(mtree->fd);
- mtree->fd = -1;
- }
-
- if (mtree->entries == NULL) {
- mtree->resolver = archive_entry_linkresolver_new();
- if (mtree->resolver == NULL)
- return ARCHIVE_FATAL;
- archive_entry_linkresolver_set_strategy(mtree->resolver,
- ARCHIVE_FORMAT_MTREE);
- r = read_mtree(a, mtree);
- if (r != ARCHIVE_OK)
- return (r);
- }
-
- a->archive.archive_format = mtree->archive_format;
- a->archive.archive_format_name = mtree->archive_format_name;
-
- for (;;) {
- if (mtree->this_entry == NULL)
- return (ARCHIVE_EOF);
- if (strcmp(mtree->this_entry->name, "..") == 0) {
- mtree->this_entry->used = 1;
- if (archive_strlen(&mtree->current_dir) > 0) {
- /* Roll back current path. */
- p = mtree->current_dir.s
- + mtree->current_dir.length - 1;
- while (p >= mtree->current_dir.s && *p != '/')
- --p;
- if (p >= mtree->current_dir.s)
- --p;
- mtree->current_dir.length
- = p - mtree->current_dir.s + 1;
- }
- }
- if (!mtree->this_entry->used) {
- use_next = 0;
- r = parse_file(a, entry, mtree, mtree->this_entry, &use_next);
- if (use_next == 0)
- return (r);
- }
- mtree->this_entry = mtree->this_entry->next;
- }
-}
-
-/*
- * A single file can have multiple lines contribute specifications.
- * Parse as many lines as necessary, then pull additional information
- * from a backing file on disk as necessary.
- */
-static int
-parse_file(struct archive_read *a, struct archive_entry *entry,
- struct mtree *mtree, struct mtree_entry *mentry, int *use_next)
-{
- const char *path;
- struct stat st_storage, *st;
- struct mtree_entry *mp;
- struct archive_entry *sparse_entry;
- int r = ARCHIVE_OK, r1, parsed_kws;
-
- mentry->used = 1;
-
- /* Initialize reasonable defaults. */
- archive_entry_set_filetype(entry, AE_IFREG);
- archive_entry_set_size(entry, 0);
- archive_string_empty(&mtree->contents_name);
-
- /* Parse options from this line. */
- parsed_kws = 0;
- r = parse_line(a, entry, mtree, mentry, &parsed_kws);
-
- if (mentry->full) {
- archive_entry_copy_pathname(entry, mentry->name);
- /*
- * "Full" entries are allowed to have multiple lines
- * and those lines aren't required to be adjacent. We
- * don't support multiple lines for "relative" entries
- * nor do we make any attempt to merge data from
- * separate "relative" and "full" entries. (Merging
- * "relative" and "full" entries would require dealing
- * with pathname canonicalization, which is a very
- * tricky subject.)
- */
- for (mp = mentry->next; mp != NULL; mp = mp->next) {
- if (mp->full && !mp->used
- && strcmp(mentry->name, mp->name) == 0) {
- /* Later lines override earlier ones. */
- mp->used = 1;
- r1 = parse_line(a, entry, mtree, mp,
- &parsed_kws);
- if (r1 < r)
- r = r1;
- }
- }
- } else {
- /*
- * Relative entries require us to construct
- * the full path and possibly update the
- * current directory.
- */
- size_t n = archive_strlen(&mtree->current_dir);
- if (n > 0)
- archive_strcat(&mtree->current_dir, "/");
- archive_strcat(&mtree->current_dir, mentry->name);
- archive_entry_copy_pathname(entry, mtree->current_dir.s);
- if (archive_entry_filetype(entry) != AE_IFDIR)
- mtree->current_dir.length = n;
- }
-
- /*
- * Try to open and stat the file to get the real size
- * and other file info. It would be nice to avoid
- * this here so that getting a listing of an mtree
- * wouldn't require opening every referenced contents
- * file. But then we wouldn't know the actual
- * contents size, so I don't see a really viable way
- * around this. (Also, we may want to someday pull
- * other unspecified info from the contents file on
- * disk.)
- */
- mtree->fd = -1;
- if (archive_strlen(&mtree->contents_name) > 0)
- path = mtree->contents_name.s;
- else
- path = archive_entry_pathname(entry);
-
- if (archive_entry_filetype(entry) == AE_IFREG ||
- archive_entry_filetype(entry) == AE_IFDIR) {
- mtree->fd = open(path, O_RDONLY | O_BINARY | O_CLOEXEC);
- __archive_ensure_cloexec_flag(mtree->fd);
- if (mtree->fd == -1 &&
- (errno != ENOENT ||
- archive_strlen(&mtree->contents_name) > 0)) {
- archive_set_error(&a->archive, errno,
- "Can't open %s", path);
- r = ARCHIVE_WARN;
- }
- }
-
- st = &st_storage;
- if (mtree->fd >= 0) {
- if (fstat(mtree->fd, st) == -1) {
- archive_set_error(&a->archive, errno,
- "Could not fstat %s", path);
- r = ARCHIVE_WARN;
- /* If we can't stat it, don't keep it open. */
- close(mtree->fd);
- mtree->fd = -1;
- st = NULL;
- }
- } else if (lstat(path, st) == -1) {
- st = NULL;
- }
-
- /*
- * Check for a mismatch between the type in the specification and
- * the type of the contents object on disk.
- */
- if (st != NULL) {
- if (
- ((st->st_mode & S_IFMT) == S_IFREG &&
- archive_entry_filetype(entry) == AE_IFREG)
-#ifdef S_IFLNK
- || ((st->st_mode & S_IFMT) == S_IFLNK &&
- archive_entry_filetype(entry) == AE_IFLNK)
-#endif
-#ifdef S_IFSOCK
- || ((st->st_mode & S_IFSOCK) == S_IFSOCK &&
- archive_entry_filetype(entry) == AE_IFSOCK)
-#endif
-#ifdef S_IFCHR
- || ((st->st_mode & S_IFMT) == S_IFCHR &&
- archive_entry_filetype(entry) == AE_IFCHR)
-#endif
-#ifdef S_IFBLK
- || ((st->st_mode & S_IFMT) == S_IFBLK &&
- archive_entry_filetype(entry) == AE_IFBLK)
-#endif
- || ((st->st_mode & S_IFMT) == S_IFDIR &&
- archive_entry_filetype(entry) == AE_IFDIR)
-#ifdef S_IFIFO
- || ((st->st_mode & S_IFMT) == S_IFIFO &&
- archive_entry_filetype(entry) == AE_IFIFO)
-#endif
- ) {
- /* Types match. */
- } else {
- /* Types don't match; bail out gracefully. */
- if (mtree->fd >= 0)
- close(mtree->fd);
- mtree->fd = -1;
- if (parsed_kws & MTREE_HAS_OPTIONAL) {
- /* It's not an error for an optional entry
- to not match disk. */
- *use_next = 1;
- } else if (r == ARCHIVE_OK) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "mtree specification has different type for %s",
- archive_entry_pathname(entry));
- r = ARCHIVE_WARN;
- }
- return r;
- }
- }
-
- /*
- * If there is a contents file on disk, pick some of the metadata
- * from that file. For most of these, we only set it from the contents
- * if it wasn't already parsed from the specification.
- */
- if (st != NULL) {
- if (((parsed_kws & MTREE_HAS_DEVICE) == 0 ||
- (parsed_kws & MTREE_HAS_NOCHANGE) != 0) &&
- (archive_entry_filetype(entry) == AE_IFCHR ||
- archive_entry_filetype(entry) == AE_IFBLK))
- archive_entry_set_rdev(entry, st->st_rdev);
- if ((parsed_kws & (MTREE_HAS_GID | MTREE_HAS_GNAME)) == 0 ||
- (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
- archive_entry_set_gid(entry, st->st_gid);
- if ((parsed_kws & (MTREE_HAS_UID | MTREE_HAS_UNAME)) == 0 ||
- (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
- archive_entry_set_uid(entry, st->st_uid);
- if ((parsed_kws & MTREE_HAS_MTIME) == 0 ||
- (parsed_kws & MTREE_HAS_NOCHANGE) != 0) {
-#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
- archive_entry_set_mtime(entry, st->st_mtime,
- st->st_mtimespec.tv_nsec);
-#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
- archive_entry_set_mtime(entry, st->st_mtime,
- st->st_mtim.tv_nsec);
-#elif HAVE_STRUCT_STAT_ST_MTIME_N
- archive_entry_set_mtime(entry, st->st_mtime,
- st->st_mtime_n);
-#elif HAVE_STRUCT_STAT_ST_UMTIME
- archive_entry_set_mtime(entry, st->st_mtime,
- st->st_umtime*1000);
-#elif HAVE_STRUCT_STAT_ST_MTIME_USEC
- archive_entry_set_mtime(entry, st->st_mtime,
- st->st_mtime_usec*1000);
-#else
- archive_entry_set_mtime(entry, st->st_mtime, 0);
-#endif
- }
- if ((parsed_kws & MTREE_HAS_NLINK) == 0 ||
- (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
- archive_entry_set_nlink(entry, st->st_nlink);
- if ((parsed_kws & MTREE_HAS_PERM) == 0 ||
- (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
- archive_entry_set_perm(entry, st->st_mode);
- if ((parsed_kws & MTREE_HAS_SIZE) == 0 ||
- (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
- archive_entry_set_size(entry, st->st_size);
- archive_entry_set_ino(entry, st->st_ino);
- archive_entry_set_dev(entry, st->st_dev);
-
- archive_entry_linkify(mtree->resolver, &entry, &sparse_entry);
- } else if (parsed_kws & MTREE_HAS_OPTIONAL) {
- /*
- * Couldn't open the entry, stat it or the on-disk type
- * didn't match. If this entry is optional, just ignore it
- * and read the next header entry.
- */
- *use_next = 1;
- return ARCHIVE_OK;
- }
-
- mtree->cur_size = archive_entry_size(entry);
- mtree->offset = 0;
-
- return r;
-}
-
-/*
- * Each line contains a sequence of keywords.
- */
-static int
-parse_line(struct archive_read *a, struct archive_entry *entry,
- struct mtree *mtree, struct mtree_entry *mp, int *parsed_kws)
-{
- struct mtree_option *iter;
- int r = ARCHIVE_OK, r1;
-
- for (iter = mp->options; iter != NULL; iter = iter->next) {
- r1 = parse_keyword(a, mtree, entry, iter, parsed_kws);
- if (r1 < r)
- r = r1;
- }
- if (r == ARCHIVE_OK && (*parsed_kws & MTREE_HAS_TYPE) == 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Missing type keyword in mtree specification");
- return (ARCHIVE_WARN);
- }
- return (r);
-}
-
-/*
- * Device entries have one of the following forms:
- * raw dev_t
- * format,major,minor[,subdevice]
- *
- * Just use major and minor, no translation etc is done
- * between formats.
- */
-static int
-parse_device(struct archive *a, struct archive_entry *entry, char *val)
-{
- char *comma1, *comma2;
-
- comma1 = strchr(val, ',');
- if (comma1 == NULL) {
- archive_entry_set_dev(entry, (dev_t)mtree_atol10(&val));
- return (ARCHIVE_OK);
- }
- ++comma1;
- comma2 = strchr(comma1, ',');
- if (comma2 == NULL) {
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
- "Malformed device attribute");
- return (ARCHIVE_WARN);
- }
- ++comma2;
- archive_entry_set_rdevmajor(entry, (dev_t)mtree_atol(&comma1));
- archive_entry_set_rdevminor(entry, (dev_t)mtree_atol(&comma2));
- return (ARCHIVE_OK);
-}
-
-/*
- * Parse a single keyword and its value.
- */
-static int
-parse_keyword(struct archive_read *a, struct mtree *mtree,
- struct archive_entry *entry, struct mtree_option *opt, int *parsed_kws)
-{
- char *val, *key;
-
- key = opt->value;
-
- if (*key == '\0')
- return (ARCHIVE_OK);
-
- if (strcmp(key, "nochange") == 0) {
- *parsed_kws |= MTREE_HAS_NOCHANGE;
- return (ARCHIVE_OK);
- }
- if (strcmp(key, "optional") == 0) {
- *parsed_kws |= MTREE_HAS_OPTIONAL;
- return (ARCHIVE_OK);
- }
- if (strcmp(key, "ignore") == 0) {
- /*
- * The mtree processing is not recursive, so
- * recursion will only happen for explicitly listed
- * entries.
- */
- return (ARCHIVE_OK);
- }
-
- val = strchr(key, '=');
- if (val == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Malformed attribute \"%s\" (%d)", key, key[0]);
- return (ARCHIVE_WARN);
- }
-
- *val = '\0';
- ++val;
-
- switch (key[0]) {
- case 'c':
- if (strcmp(key, "content") == 0
- || strcmp(key, "contents") == 0) {
- parse_escapes(val, NULL);
- archive_strcpy(&mtree->contents_name, val);
- break;
- }
- if (strcmp(key, "cksum") == 0)
- break;
- case 'd':
- if (strcmp(key, "device") == 0) {
- *parsed_kws |= MTREE_HAS_DEVICE;
- return parse_device(&a->archive, entry, val);
- }
- case 'f':
- if (strcmp(key, "flags") == 0) {
- *parsed_kws |= MTREE_HAS_FFLAGS;
- archive_entry_copy_fflags_text(entry, val);
- break;
- }
- case 'g':
- if (strcmp(key, "gid") == 0) {
- *parsed_kws |= MTREE_HAS_GID;
- archive_entry_set_gid(entry, mtree_atol10(&val));
- break;
- }
- if (strcmp(key, "gname") == 0) {
- *parsed_kws |= MTREE_HAS_GNAME;
- archive_entry_copy_gname(entry, val);
- break;
- }
- case 'l':
- if (strcmp(key, "link") == 0) {
- archive_entry_copy_symlink(entry, val);
- break;
- }
- case 'm':
- if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0)
- break;
- if (strcmp(key, "mode") == 0) {
- if (val[0] >= '0' && val[0] <= '9') {
- *parsed_kws |= MTREE_HAS_PERM;
- archive_entry_set_perm(entry,
- (mode_t)mtree_atol8(&val));
- } else {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Symbolic mode \"%s\" unsupported", val);
- return ARCHIVE_WARN;
- }
- break;
- }
- case 'n':
- if (strcmp(key, "nlink") == 0) {
- *parsed_kws |= MTREE_HAS_NLINK;
- archive_entry_set_nlink(entry,
- (unsigned int)mtree_atol10(&val));
- break;
- }
- case 'r':
- if (strcmp(key, "rmd160") == 0 ||
- strcmp(key, "rmd160digest") == 0)
- break;
- case 's':
- if (strcmp(key, "sha1") == 0 || strcmp(key, "sha1digest") == 0)
- break;
- if (strcmp(key, "sha256") == 0 ||
- strcmp(key, "sha256digest") == 0)
- break;
- if (strcmp(key, "sha384") == 0 ||
- strcmp(key, "sha384digest") == 0)
- break;
- if (strcmp(key, "sha512") == 0 ||
- strcmp(key, "sha512digest") == 0)
- break;
- if (strcmp(key, "size") == 0) {
- archive_entry_set_size(entry, mtree_atol10(&val));
- break;
- }
- case 't':
- if (strcmp(key, "tags") == 0) {
- /*
- * Comma delimited list of tags.
- * Ignore the tags for now, but the interface
- * should be extended to allow inclusion/exclusion.
- */
- break;
- }
- if (strcmp(key, "time") == 0) {
- int64_t m;
- int64_t my_time_t_max = get_time_t_max();
- int64_t my_time_t_min = get_time_t_min();
- long ns;
-
- *parsed_kws |= MTREE_HAS_MTIME;
- m = mtree_atol10(&val);
- /* Replicate an old mtree bug:
- * 123456789.1 represents 123456789
- * seconds and 1 nanosecond. */
- if (*val == '.') {
- ++val;
- ns = (long)mtree_atol10(&val);
- } else
- ns = 0;
- if (m > my_time_t_max)
- m = my_time_t_max;
- else if (m < my_time_t_min)
- m = my_time_t_min;
- archive_entry_set_mtime(entry, (time_t)m, ns);
- break;
- }
- if (strcmp(key, "type") == 0) {
- switch (val[0]) {
- case 'b':
- if (strcmp(val, "block") == 0) {
- archive_entry_set_filetype(entry, AE_IFBLK);
- break;
- }
- case 'c':
- if (strcmp(val, "char") == 0) {
- archive_entry_set_filetype(entry, AE_IFCHR);
- break;
- }
- case 'd':
- if (strcmp(val, "dir") == 0) {
- archive_entry_set_filetype(entry, AE_IFDIR);
- break;
- }
- case 'f':
- if (strcmp(val, "fifo") == 0) {
- archive_entry_set_filetype(entry, AE_IFIFO);
- break;
- }
- if (strcmp(val, "file") == 0) {
- archive_entry_set_filetype(entry, AE_IFREG);
- break;
- }
- case 'l':
- if (strcmp(val, "link") == 0) {
- archive_entry_set_filetype(entry, AE_IFLNK);
- break;
- }
- default:
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Unrecognized file type \"%s\"; assuming \"file\"", val);
- archive_entry_set_filetype(entry, AE_IFREG);
- return (ARCHIVE_WARN);
- }
- *parsed_kws |= MTREE_HAS_TYPE;
- break;
- }
- case 'u':
- if (strcmp(key, "uid") == 0) {
- *parsed_kws |= MTREE_HAS_UID;
- archive_entry_set_uid(entry, mtree_atol10(&val));
- break;
- }
- if (strcmp(key, "uname") == 0) {
- *parsed_kws |= MTREE_HAS_UNAME;
- archive_entry_copy_uname(entry, val);
- break;
- }
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Unrecognized key %s=%s", key, val);
- return (ARCHIVE_WARN);
- }
- return (ARCHIVE_OK);
-}
-
-static int
-read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offset)
-{
- size_t bytes_to_read;
- ssize_t bytes_read;
- struct mtree *mtree;
-
- mtree = (struct mtree *)(a->format->data);
- if (mtree->fd < 0) {
- *buff = NULL;
- *offset = 0;
- *size = 0;
- return (ARCHIVE_EOF);
- }
- if (mtree->buff == NULL) {
- mtree->buffsize = 64 * 1024;
- mtree->buff = malloc(mtree->buffsize);
- if (mtree->buff == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- }
-
- *buff = mtree->buff;
- *offset = mtree->offset;
- if ((int64_t)mtree->buffsize > mtree->cur_size - mtree->offset)
- bytes_to_read = (size_t)(mtree->cur_size - mtree->offset);
- else
- bytes_to_read = mtree->buffsize;
- bytes_read = read(mtree->fd, mtree->buff, bytes_to_read);
- if (bytes_read < 0) {
- archive_set_error(&a->archive, errno, "Can't read");
- return (ARCHIVE_WARN);
- }
- if (bytes_read == 0) {
- *size = 0;
- return (ARCHIVE_EOF);
- }
- mtree->offset += bytes_read;
- *size = bytes_read;
- return (ARCHIVE_OK);
-}
-
-/* Skip does nothing except possibly close the contents file. */
-static int
-skip(struct archive_read *a)
-{
- struct mtree *mtree;
-
- mtree = (struct mtree *)(a->format->data);
- if (mtree->fd >= 0) {
- close(mtree->fd);
- mtree->fd = -1;
- }
- return (ARCHIVE_OK);
-}
-
-/*
- * Since parsing backslash sequences always makes strings shorter,
- * we can always do this conversion in-place.
- */
-static void
-parse_escapes(char *src, struct mtree_entry *mentry)
-{
- char *dest = src;
- char c;
-
- if (mentry != NULL && strcmp(src, ".") == 0)
- mentry->full = 1;
-
- while (*src != '\0') {
- c = *src++;
- if (c == '/' && mentry != NULL)
- mentry->full = 1;
- if (c == '\\') {
- switch (src[0]) {
- case '0':
- if (src[1] < '0' || src[1] > '7') {
- c = 0;
- ++src;
- break;
- }
- /* FALLTHROUGH */
- case '1':
- case '2':
- case '3':
- if (src[1] >= '0' && src[1] <= '7' &&
- src[2] >= '0' && src[2] <= '7') {
- c = (src[0] - '0') << 6;
- c |= (src[1] - '0') << 3;
- c |= (src[2] - '0');
- src += 3;
- }
- break;
- case 'a':
- c = '\a';
- ++src;
- break;
- case 'b':
- c = '\b';
- ++src;
- break;
- case 'f':
- c = '\f';
- ++src;
- break;
- case 'n':
- c = '\n';
- ++src;
- break;
- case 'r':
- c = '\r';
- ++src;
- break;
- case 's':
- c = ' ';
- ++src;
- break;
- case 't':
- c = '\t';
- ++src;
- break;
- case 'v':
- c = '\v';
- ++src;
- break;
- }
- }
- *dest++ = c;
- }
- *dest = '\0';
-}
-
-/*
- * Note that this implementation does not (and should not!) obey
- * locale settings; you cannot simply substitute strtol here, since
- * it does obey locale.
- */
-static int64_t
-mtree_atol8(char **p)
-{
- int64_t l, limit, last_digit_limit;
- int digit, base;
-
- base = 8;
- limit = INT64_MAX / base;
- last_digit_limit = INT64_MAX % base;
-
- l = 0;
- digit = **p - '0';
- while (digit >= 0 && digit < base) {
- if (l>limit || (l == limit && digit > last_digit_limit)) {
- l = INT64_MAX; /* Truncate on overflow. */
- break;
- }
- l = (l * base) + digit;
- digit = *++(*p) - '0';
- }
- return (l);
-}
-
-/*
- * Note that this implementation does not (and should not!) obey
- * locale settings; you cannot simply substitute strtol here, since
- * it does obey locale.
- */
-static int64_t
-mtree_atol10(char **p)
-{
- int64_t l, limit, last_digit_limit;
- int base, digit, sign;
-
- base = 10;
-
- if (**p == '-') {
- sign = -1;
- limit = ((uint64_t)(INT64_MAX) + 1) / base;
- last_digit_limit = ((uint64_t)(INT64_MAX) + 1) % base;
- ++(*p);
- } else {
- sign = 1;
- limit = INT64_MAX / base;
- last_digit_limit = INT64_MAX % base;
- }
-
- l = 0;
- digit = **p - '0';
- while (digit >= 0 && digit < base) {
- if (l > limit || (l == limit && digit > last_digit_limit))
- return (sign < 0) ? INT64_MIN : INT64_MAX;
- l = (l * base) + digit;
- digit = *++(*p) - '0';
- }
- return (sign < 0) ? -l : l;
-}
-
-/* Parse a hex digit. */
-static int
-parsehex(char c)
-{
- if (c >= '0' && c <= '9')
- return c - '0';
- else if (c >= 'a' && c <= 'f')
- return c - 'a';
- else if (c >= 'A' && c <= 'F')
- return c - 'A';
- else
- return -1;
-}
-
-/*
- * Note that this implementation does not (and should not!) obey
- * locale settings; you cannot simply substitute strtol here, since
- * it does obey locale.
- */
-static int64_t
-mtree_atol16(char **p)
-{
- int64_t l, limit, last_digit_limit;
- int base, digit, sign;
-
- base = 16;
-
- if (**p == '-') {
- sign = -1;
- limit = ((uint64_t)(INT64_MAX) + 1) / base;
- last_digit_limit = ((uint64_t)(INT64_MAX) + 1) % base;
- ++(*p);
- } else {
- sign = 1;
- limit = INT64_MAX / base;
- last_digit_limit = INT64_MAX % base;
- }
-
- l = 0;
- digit = parsehex(**p);
- while (digit >= 0 && digit < base) {
- if (l > limit || (l == limit && digit > last_digit_limit))
- return (sign < 0) ? INT64_MIN : INT64_MAX;
- l = (l * base) + digit;
- digit = parsehex(*++(*p));
- }
- return (sign < 0) ? -l : l;
-}
-
-static int64_t
-mtree_atol(char **p)
-{
- if (**p != '0')
- return mtree_atol10(p);
- if ((*p)[1] == 'x' || (*p)[1] == 'X') {
- *p += 2;
- return mtree_atol16(p);
- }
- return mtree_atol8(p);
-}
-
-/*
- * Returns length of line (including trailing newline)
- * or negative on error. 'start' argument is updated to
- * point to first character of line.
- */
-static ssize_t
-readline(struct archive_read *a, struct mtree *mtree, char **start, ssize_t limit)
-{
- ssize_t bytes_read;
- ssize_t total_size = 0;
- ssize_t find_off = 0;
- const void *t;
- const char *s;
- void *p;
- char *u;
-
- /* Accumulate line in a line buffer. */
- for (;;) {
- /* Read some more. */
- t = __archive_read_ahead(a, 1, &bytes_read);
- if (t == NULL)
- return (0);
- if (bytes_read < 0)
- return (ARCHIVE_FATAL);
- s = t; /* Start of line? */
- p = memchr(t, '\n', bytes_read);
- /* If we found '\n', trim the read. */
- if (p != NULL) {
- bytes_read = 1 + ((const char *)p) - s;
- }
- if (total_size + bytes_read + 1 > limit) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Line too long");
- return (ARCHIVE_FATAL);
- }
- if (archive_string_ensure(&mtree->line,
- total_size + bytes_read + 1) == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate working buffer");
- return (ARCHIVE_FATAL);
- }
- memcpy(mtree->line.s + total_size, t, bytes_read);
- __archive_read_consume(a, bytes_read);
- total_size += bytes_read;
- /* Null terminate. */
- mtree->line.s[total_size] = '\0';
- /* If we found an unescaped '\n', clean up and return. */
- for (u = mtree->line.s + find_off; *u; ++u) {
- if (u[0] == '\n') {
- *start = mtree->line.s;
- return total_size;
- }
- if (u[0] == '#') {
- if (p == NULL)
- break;
- *start = mtree->line.s;
- return total_size;
- }
- if (u[0] != '\\')
- continue;
- if (u[1] == '\\') {
- ++u;
- continue;
- }
- if (u[1] == '\n') {
- memmove(u, u + 1,
- total_size - (u - mtree->line.s) + 1);
- --total_size;
- ++u;
- break;
- }
- if (u[1] == '\0')
- break;
- }
- find_off = u - mtree->line.s;
- }
-}
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_format_rar.c b/3rdparty/libarchive/libarchive/archive_read_support_format_rar.c
deleted file mode 100644
index 99c57a0f..00000000
--- a/3rdparty/libarchive/libarchive/archive_read_support_format_rar.c
+++ /dev/null
@@ -1,2858 +0,0 @@
-/*-
-* 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.
-*/
-
-#include "archive_platform.h"
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#include <time.h>
-#include <limits.h>
-#ifdef HAVE_ZLIB_H
-#include <zlib.h> /* crc32 */
-#endif
-
-#include "archive.h"
-#ifndef HAVE_ZLIB_H
-#include "archive_crc32.h"
-#endif
-#include "archive_endian.h"
-#include "archive_entry.h"
-#include "archive_entry_locale.h"
-#include "archive_ppmd7_private.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-
-/* RAR signature, also known as the mark header */
-#define RAR_SIGNATURE "\x52\x61\x72\x21\x1A\x07\x00"
-
-/* Header types */
-#define MARK_HEAD 0x72
-#define MAIN_HEAD 0x73
-#define FILE_HEAD 0x74
-#define COMM_HEAD 0x75
-#define AV_HEAD 0x76
-#define SUB_HEAD 0x77
-#define PROTECT_HEAD 0x78
-#define SIGN_HEAD 0x79
-#define NEWSUB_HEAD 0x7a
-#define ENDARC_HEAD 0x7b
-
-/* Main Header Flags */
-#define MHD_VOLUME 0x0001
-#define MHD_COMMENT 0x0002
-#define MHD_LOCK 0x0004
-#define MHD_SOLID 0x0008
-#define MHD_NEWNUMBERING 0x0010
-#define MHD_AV 0x0020
-#define MHD_PROTECT 0x0040
-#define MHD_PASSWORD 0x0080
-#define MHD_FIRSTVOLUME 0x0100
-#define MHD_ENCRYPTVER 0x0200
-
-/* Flags common to all headers */
-#define HD_MARKDELETION 0x4000
-#define HD_ADD_SIZE_PRESENT 0x8000
-
-/* File Header Flags */
-#define FHD_SPLIT_BEFORE 0x0001
-#define FHD_SPLIT_AFTER 0x0002
-#define FHD_PASSWORD 0x0004
-#define FHD_COMMENT 0x0008
-#define FHD_SOLID 0x0010
-#define FHD_LARGE 0x0100
-#define FHD_UNICODE 0x0200
-#define FHD_SALT 0x0400
-#define FHD_VERSION 0x0800
-#define FHD_EXTTIME 0x1000
-#define FHD_EXTFLAGS 0x2000
-
-/* File dictionary sizes */
-#define DICTIONARY_SIZE_64 0x00
-#define DICTIONARY_SIZE_128 0x20
-#define DICTIONARY_SIZE_256 0x40
-#define DICTIONARY_SIZE_512 0x60
-#define DICTIONARY_SIZE_1024 0x80
-#define DICTIONARY_SIZE_2048 0xA0
-#define DICTIONARY_SIZE_4096 0xC0
-#define FILE_IS_DIRECTORY 0xE0
-#define DICTIONARY_MASK FILE_IS_DIRECTORY
-
-/* OS Flags */
-#define OS_MSDOS 0
-#define OS_OS2 1
-#define OS_WIN32 2
-#define OS_UNIX 3
-#define OS_MAC_OS 4
-#define OS_BEOS 5
-
-/* Compression Methods */
-#define COMPRESS_METHOD_STORE 0x30
-/* LZSS */
-#define COMPRESS_METHOD_FASTEST 0x31
-#define COMPRESS_METHOD_FAST 0x32
-#define COMPRESS_METHOD_NORMAL 0x33
-/* PPMd Variant H */
-#define COMPRESS_METHOD_GOOD 0x34
-#define COMPRESS_METHOD_BEST 0x35
-
-#define CRC_POLYNOMIAL 0xEDB88320
-
-#define NS_UNIT 10000000
-
-#define DICTIONARY_MAX_SIZE 0x400000
-
-#define MAINCODE_SIZE 299
-#define OFFSETCODE_SIZE 60
-#define LOWOFFSETCODE_SIZE 17
-#define LENGTHCODE_SIZE 28
-#define HUFFMAN_TABLE_SIZE \
- MAINCODE_SIZE + OFFSETCODE_SIZE + LOWOFFSETCODE_SIZE + LENGTHCODE_SIZE
-
-#define MAX_SYMBOL_LENGTH 0xF
-#define MAX_SYMBOLS 20
-
-/*
- * Considering L1,L2 cache miss and a calling of write system-call,
- * the best size of the output buffer(uncompressed buffer) is 128K.
- * If the structure of extracting process is changed, this value
- * might be researched again.
- */
-#define UNP_BUFFER_SIZE (128 * 1024)
-
-/* Define this here for non-Windows platforms */
-#if !((defined(__WIN32__) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__))
-#define FILE_ATTRIBUTE_DIRECTORY 0x10
-#endif
-
-/* Fields common to all headers */
-struct rar_header
-{
- char crc[2];
- char type;
- char flags[2];
- char size[2];
-};
-
-/* Fields common to all file headers */
-struct rar_file_header
-{
- char pack_size[4];
- char unp_size[4];
- char host_os;
- char file_crc[4];
- char file_time[4];
- char unp_ver;
- char method;
- char name_size[2];
- char file_attr[4];
-};
-
-struct huffman_tree_node
-{
- int branches[2];
-};
-
-struct huffman_table_entry
-{
- unsigned int length;
- int value;
-};
-
-struct huffman_code
-{
- struct huffman_tree_node *tree;
- int numentries;
- int minlength;
- int maxlength;
- int tablesize;
- struct huffman_table_entry *table;
-};
-
-struct lzss
-{
- unsigned char *window;
- int mask;
- int64_t position;
-};
-
-struct data_block_offsets
-{
- int64_t header_size;
- int64_t start_offset;
- int64_t end_offset;
-};
-
-struct rar
-{
- /* Entries from main RAR header */
- unsigned main_flags;
- unsigned long file_crc;
- char reserved1[2];
- char reserved2[4];
- char encryptver;
-
- /* File header entries */
- char compression_method;
- unsigned file_flags;
- int64_t packed_size;
- int64_t unp_size;
- time_t mtime;
- long mnsec;
- mode_t mode;
- char *filename;
- char *filename_save;
- size_t filename_allocated;
-
- /* File header optional entries */
- char salt[8];
- time_t atime;
- long ansec;
- time_t ctime;
- long cnsec;
- time_t arctime;
- long arcnsec;
-
- /* Fields to help with tracking decompression of files. */
- int64_t bytes_unconsumed;
- int64_t bytes_remaining;
- int64_t bytes_uncopied;
- int64_t offset;
- int64_t offset_outgoing;
- int64_t offset_seek;
- char valid;
- unsigned int unp_offset;
- unsigned int unp_buffer_size;
- unsigned char *unp_buffer;
- unsigned int dictionary_size;
- char start_new_block;
- char entry_eof;
- unsigned long crc_calculated;
- int found_first_header;
- char has_endarc_header;
- struct data_block_offsets *dbo;
- unsigned int cursor;
- unsigned int nodes;
-
- /* LZSS members */
- struct huffman_code maincode;
- struct huffman_code offsetcode;
- struct huffman_code lowoffsetcode;
- struct huffman_code lengthcode;
- unsigned char lengthtable[HUFFMAN_TABLE_SIZE];
- struct lzss lzss;
- char output_last_match;
- unsigned int lastlength;
- unsigned int lastoffset;
- unsigned int oldoffset[4];
- unsigned int lastlowoffset;
- unsigned int numlowoffsetrepeats;
- int64_t filterstart;
- char start_new_table;
-
- /* PPMd Variant H members */
- char ppmd_valid;
- char ppmd_eod;
- char is_ppmd_block;
- int ppmd_escape;
- CPpmd7 ppmd7_context;
- CPpmd7z_RangeDec range_dec;
- IByteIn bytein;
-
- /*
- * String conversion object.
- */
- int init_default_conversion;
- struct archive_string_conv *sconv_default;
- struct archive_string_conv *opt_sconv;
- struct archive_string_conv *sconv_utf8;
- struct archive_string_conv *sconv_utf16be;
-
- /*
- * Bit stream reader.
- */
- struct rar_br {
-#define CACHE_TYPE uint64_t
-#define CACHE_BITS (8 * sizeof(CACHE_TYPE))
- /* Cache buffer. */
- CACHE_TYPE cache_buffer;
- /* Indicates how many bits avail in cache_buffer. */
- int cache_avail;
- ssize_t avail_in;
- const unsigned char *next_in;
- } br;
-};
-
-static int archive_read_format_rar_bid(struct archive_read *, int);
-static int archive_read_format_rar_options(struct archive_read *,
- const char *, const char *);
-static int archive_read_format_rar_read_header(struct archive_read *,
- struct archive_entry *);
-static int archive_read_format_rar_read_data(struct archive_read *,
- const void **, size_t *, int64_t *);
-static int archive_read_format_rar_read_data_skip(struct archive_read *a);
-static int64_t archive_read_format_rar_seek_data(struct archive_read *, int64_t,
- int);
-static int archive_read_format_rar_cleanup(struct archive_read *);
-
-/* Support functions */
-static int read_header(struct archive_read *, struct archive_entry *, char);
-static time_t get_time(int);
-static int read_exttime(const char *, struct rar *, const char *);
-static int read_symlink_stored(struct archive_read *, struct archive_entry *,
- struct archive_string_conv *);
-static int read_data_stored(struct archive_read *, const void **, size_t *,
- int64_t *);
-static int read_data_compressed(struct archive_read *, const void **, size_t *,
- int64_t *);
-static int rar_br_preparation(struct archive_read *, struct rar_br *);
-static int parse_codes(struct archive_read *);
-static void free_codes(struct archive_read *);
-static int read_next_symbol(struct archive_read *, struct huffman_code *);
-static int create_code(struct archive_read *, struct huffman_code *,
- unsigned char *, int, char);
-static int add_value(struct archive_read *, struct huffman_code *, int, int,
- int);
-static int new_node(struct huffman_code *);
-static int make_table(struct archive_read *, struct huffman_code *);
-static int make_table_recurse(struct archive_read *, struct huffman_code *, int,
- struct huffman_table_entry *, int, int);
-static int64_t expand(struct archive_read *, int64_t);
-static int copy_from_lzss_window(struct archive_read *, const void **,
- int64_t, int);
-static const void *rar_read_ahead(struct archive_read *, size_t, ssize_t *);
-
-/*
- * Bit stream reader.
- */
-/* Check that the cache buffer has enough bits. */
-#define rar_br_has(br, n) ((br)->cache_avail >= n)
-/* Get compressed data by bit. */
-#define rar_br_bits(br, n) \
- (((uint32_t)((br)->cache_buffer >> \
- ((br)->cache_avail - (n)))) & cache_masks[n])
-#define rar_br_bits_forced(br, n) \
- (((uint32_t)((br)->cache_buffer << \
- ((n) - (br)->cache_avail))) & cache_masks[n])
-/* Read ahead to make sure the cache buffer has enough compressed data we
- * will use.
- * True : completed, there is enough data in the cache buffer.
- * False : there is no data in the stream. */
-#define rar_br_read_ahead(a, br, n) \
- ((rar_br_has(br, (n)) || rar_br_fillup(a, br)) || rar_br_has(br, (n)))
-/* Notify how many bits we consumed. */
-#define rar_br_consume(br, n) ((br)->cache_avail -= (n))
-#define rar_br_consume_unalined_bits(br) ((br)->cache_avail &= ~7)
-
-static const uint32_t cache_masks[] = {
- 0x00000000, 0x00000001, 0x00000003, 0x00000007,
- 0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F,
- 0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF,
- 0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF,
- 0x0000FFFF, 0x0001FFFF, 0x0003FFFF, 0x0007FFFF,
- 0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF,
- 0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF,
- 0x0FFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF,
- 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
-};
-
-/*
- * Shift away used bits in the cache data and fill it up with following bits.
- * Call this when cache buffer does not have enough bits you need.
- *
- * Returns 1 if the cache buffer is full.
- * Returns 0 if the cache buffer is not full; input buffer is empty.
- */
-static int
-rar_br_fillup(struct archive_read *a, struct rar_br *br)
-{
- struct rar *rar = (struct rar *)(a->format->data);
- int n = CACHE_BITS - br->cache_avail;
-
- for (;;) {
- switch (n >> 3) {
- case 8:
- if (br->avail_in >= 8) {
- br->cache_buffer =
- ((uint64_t)br->next_in[0]) << 56 |
- ((uint64_t)br->next_in[1]) << 48 |
- ((uint64_t)br->next_in[2]) << 40 |
- ((uint64_t)br->next_in[3]) << 32 |
- ((uint32_t)br->next_in[4]) << 24 |
- ((uint32_t)br->next_in[5]) << 16 |
- ((uint32_t)br->next_in[6]) << 8 |
- (uint32_t)br->next_in[7];
- br->next_in += 8;
- br->avail_in -= 8;
- br->cache_avail += 8 * 8;
- rar->bytes_unconsumed += 8;
- rar->bytes_remaining -= 8;
- return (1);
- }
- break;
- case 7:
- if (br->avail_in >= 7) {
- br->cache_buffer =
- (br->cache_buffer << 56) |
- ((uint64_t)br->next_in[0]) << 48 |
- ((uint64_t)br->next_in[1]) << 40 |
- ((uint64_t)br->next_in[2]) << 32 |
- ((uint32_t)br->next_in[3]) << 24 |
- ((uint32_t)br->next_in[4]) << 16 |
- ((uint32_t)br->next_in[5]) << 8 |
- (uint32_t)br->next_in[6];
- br->next_in += 7;
- br->avail_in -= 7;
- br->cache_avail += 7 * 8;
- rar->bytes_unconsumed += 7;
- rar->bytes_remaining -= 7;
- return (1);
- }
- break;
- case 6:
- if (br->avail_in >= 6) {
- br->cache_buffer =
- (br->cache_buffer << 48) |
- ((uint64_t)br->next_in[0]) << 40 |
- ((uint64_t)br->next_in[1]) << 32 |
- ((uint32_t)br->next_in[2]) << 24 |
- ((uint32_t)br->next_in[3]) << 16 |
- ((uint32_t)br->next_in[4]) << 8 |
- (uint32_t)br->next_in[5];
- br->next_in += 6;
- br->avail_in -= 6;
- br->cache_avail += 6 * 8;
- rar->bytes_unconsumed += 6;
- rar->bytes_remaining -= 6;
- return (1);
- }
- break;
- case 0:
- /* We have enough compressed data in
- * the cache buffer.*/
- return (1);
- default:
- break;
- }
- if (br->avail_in <= 0) {
-
- if (rar->bytes_unconsumed > 0) {
- /* Consume as much as the decompressor
- * actually used. */
- __archive_read_consume(a, rar->bytes_unconsumed);
- rar->bytes_unconsumed = 0;
- }
- br->next_in = rar_read_ahead(a, 1, &(br->avail_in));
- if (br->next_in == NULL)
- return (0);
- if (br->avail_in == 0)
- return (0);
- }
- br->cache_buffer =
- (br->cache_buffer << 8) | *br->next_in++;
- br->avail_in--;
- br->cache_avail += 8;
- n -= 8;
- rar->bytes_unconsumed++;
- rar->bytes_remaining--;
- }
-}
-
-static int
-rar_br_preparation(struct archive_read *a, struct rar_br *br)
-{
- struct rar *rar = (struct rar *)(a->format->data);
-
- if (rar->bytes_remaining > 0) {
- br->next_in = rar_read_ahead(a, 1, &(br->avail_in));
- if (br->next_in == NULL) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated RAR file data");
- return (ARCHIVE_FATAL);
- }
- if (br->cache_avail == 0)
- (void)rar_br_fillup(a, br);
- }
- return (ARCHIVE_OK);
-}
-
-/* Find last bit set */
-static inline int
-rar_fls(unsigned int word)
-{
- word |= (word >> 1);
- word |= (word >> 2);
- word |= (word >> 4);
- word |= (word >> 8);
- word |= (word >> 16);
- return word - (word >> 1);
-}
-
-/* LZSS functions */
-static inline int64_t
-lzss_position(struct lzss *lzss)
-{
- return lzss->position;
-}
-
-static inline int
-lzss_mask(struct lzss *lzss)
-{
- return lzss->mask;
-}
-
-static inline int
-lzss_size(struct lzss *lzss)
-{
- return lzss->mask + 1;
-}
-
-static inline int
-lzss_offset_for_position(struct lzss *lzss, int64_t pos)
-{
- return (int)(pos & lzss->mask);
-}
-
-static inline unsigned char *
-lzss_pointer_for_position(struct lzss *lzss, int64_t pos)
-{
- return &lzss->window[lzss_offset_for_position(lzss, pos)];
-}
-
-static inline int
-lzss_current_offset(struct lzss *lzss)
-{
- return lzss_offset_for_position(lzss, lzss->position);
-}
-
-static inline uint8_t *
-lzss_current_pointer(struct lzss *lzss)
-{
- return lzss_pointer_for_position(lzss, lzss->position);
-}
-
-static inline void
-lzss_emit_literal(struct rar *rar, uint8_t literal)
-{
- *lzss_current_pointer(&rar->lzss) = literal;
- rar->lzss.position++;
-}
-
-static inline void
-lzss_emit_match(struct rar *rar, int offset, int length)
-{
- int dstoffs = lzss_current_offset(&rar->lzss);
- int srcoffs = (dstoffs - offset) & lzss_mask(&rar->lzss);
- int l, li, remaining;
- unsigned char *d, *s;
-
- remaining = length;
- while (remaining > 0) {
- l = remaining;
- if (dstoffs > srcoffs) {
- if (l > lzss_size(&rar->lzss) - dstoffs)
- l = lzss_size(&rar->lzss) - dstoffs;
- } else {
- if (l > lzss_size(&rar->lzss) - srcoffs)
- l = lzss_size(&rar->lzss) - srcoffs;
- }
- d = &(rar->lzss.window[dstoffs]);
- s = &(rar->lzss.window[srcoffs]);
- if ((dstoffs + l < srcoffs) || (srcoffs + l < dstoffs))
- memcpy(d, s, l);
- else {
- for (li = 0; li < l; li++)
- d[li] = s[li];
- }
- remaining -= l;
- dstoffs = (dstoffs + l) & lzss_mask(&(rar->lzss));
- srcoffs = (srcoffs + l) & lzss_mask(&(rar->lzss));
- }
- rar->lzss.position += length;
-}
-
-static void *
-ppmd_alloc(void *p, size_t size)
-{
- (void)p;
- return malloc(size);
-}
-static void
-ppmd_free(void *p, void *address)
-{
- (void)p;
- free(address);
-}
-static ISzAlloc g_szalloc = { ppmd_alloc, ppmd_free };
-
-static Byte
-ppmd_read(void *p)
-{
- struct archive_read *a = ((IByteIn*)p)->a;
- struct rar *rar = (struct rar *)(a->format->data);
- struct rar_br *br = &(rar->br);
- Byte b;
- if (!rar_br_read_ahead(a, br, 8))
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated RAR file data");
- rar->valid = 0;
- return 0;
- }
- b = rar_br_bits(br, 8);
- rar_br_consume(br, 8);
- return b;
-}
-
-int
-archive_read_support_format_rar(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct rar *rar;
- int r;
-
- archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
- "archive_read_support_format_rar");
-
- rar = (struct rar *)malloc(sizeof(*rar));
- if (rar == NULL)
- {
- archive_set_error(&a->archive, ENOMEM, "Can't allocate rar data");
- return (ARCHIVE_FATAL);
- }
- memset(rar, 0, sizeof(*rar));
-
- r = __archive_read_register_format(a,
- rar,
- "rar",
- archive_read_format_rar_bid,
- archive_read_format_rar_options,
- archive_read_format_rar_read_header,
- archive_read_format_rar_read_data,
- archive_read_format_rar_read_data_skip,
- archive_read_format_rar_seek_data,
- archive_read_format_rar_cleanup);
-
- if (r != ARCHIVE_OK)
- free(rar);
- return (r);
-}
-
-static int
-archive_read_format_rar_bid(struct archive_read *a, int best_bid)
-{
- const char *p;
-
- /* If there's already a bid > 30, we'll never win. */
- if (best_bid > 30)
- return (-1);
-
- if ((p = __archive_read_ahead(a, 7, NULL)) == NULL)
- return (-1);
-
- if (memcmp(p, RAR_SIGNATURE, 7) == 0)
- return (30);
-
- if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {
- /* This is a PE file */
- ssize_t offset = 0x10000;
- ssize_t window = 4096;
- ssize_t bytes_avail;
- while (offset + window <= (1024 * 128)) {
- const char *buff = __archive_read_ahead(a, offset + window, &bytes_avail);
- if (buff == NULL) {
- /* Remaining bytes are less than window. */
- window >>= 1;
- if (window < 0x40)
- return (0);
- continue;
- }
- p = buff + offset;
- while (p + 7 < buff + bytes_avail) {
- if (memcmp(p, RAR_SIGNATURE, 7) == 0)
- return (30);
- p += 0x10;
- }
- offset = p - buff;
- }
- }
- return (0);
-}
-
-static int
-skip_sfx(struct archive_read *a)
-{
- const void *h;
- const char *p, *q;
- size_t skip, total;
- ssize_t bytes, window;
-
- total = 0;
- window = 4096;
- while (total + window <= (1024 * 128)) {
- h = __archive_read_ahead(a, window, &bytes);
- if (h == NULL) {
- /* Remaining bytes are less than window. */
- window >>= 1;
- if (window < 0x40)
- goto fatal;
- continue;
- }
- if (bytes < 0x40)
- goto fatal;
- p = h;
- q = p + bytes;
-
- /*
- * Scan ahead until we find something that looks
- * like the RAR header.
- */
- while (p + 7 < q) {
- if (memcmp(p, RAR_SIGNATURE, 7) == 0) {
- skip = p - (const char *)h;
- __archive_read_consume(a, skip);
- return (ARCHIVE_OK);
- }
- p += 0x10;
- }
- skip = p - (const char *)h;
- __archive_read_consume(a, skip);
- total += skip;
- }
-fatal:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Couldn't find out RAR header");
- return (ARCHIVE_FATAL);
-}
-
-static int
-archive_read_format_rar_options(struct archive_read *a,
- const char *key, const char *val)
-{
- struct rar *rar;
- int ret = ARCHIVE_FAILED;
-
- rar = (struct rar *)(a->format->data);
- if (strcmp(key, "hdrcharset") == 0) {
- if (val == NULL || val[0] == 0)
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "rar: hdrcharset option needs a character-set name");
- else {
- rar->opt_sconv =
- archive_string_conversion_from_charset(
- &a->archive, val, 0);
- if (rar->opt_sconv != NULL)
- ret = ARCHIVE_OK;
- else
- ret = ARCHIVE_FATAL;
- }
- return (ret);
- }
-
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
-}
-
-static int
-archive_read_format_rar_read_header(struct archive_read *a,
- struct archive_entry *entry)
-{
- const void *h;
- const char *p;
- struct rar *rar;
- size_t skip;
- char head_type;
- int ret;
- unsigned flags;
-
- a->archive.archive_format = ARCHIVE_FORMAT_RAR;
- if (a->archive.archive_format_name == NULL)
- a->archive.archive_format_name = "RAR";
-
- rar = (struct rar *)(a->format->data);
-
- /* RAR files can be generated without EOF headers, so return ARCHIVE_EOF if
- * this fails.
- */
- if ((h = __archive_read_ahead(a, 7, NULL)) == NULL)
- return (ARCHIVE_EOF);
-
- p = h;
- if (rar->found_first_header == 0 &&
- ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0)) {
- /* This is an executable ? Must be self-extracting... */
- ret = skip_sfx(a);
- if (ret < ARCHIVE_WARN)
- return (ret);
- }
- rar->found_first_header = 1;
-
- while (1)
- {
- unsigned long crc32_val;
-
- if ((h = __archive_read_ahead(a, 7, NULL)) == NULL)
- return (ARCHIVE_FATAL);
- p = h;
-
- head_type = p[2];
- switch(head_type)
- {
- case MARK_HEAD:
- if (memcmp(p, RAR_SIGNATURE, 7) != 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid marker header");
- return (ARCHIVE_FATAL);
- }
- __archive_read_consume(a, 7);
- break;
-
- case MAIN_HEAD:
- rar->main_flags = archive_le16dec(p + 3);
- skip = archive_le16dec(p + 5);
- if (skip < 7 + sizeof(rar->reserved1) + sizeof(rar->reserved2)) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid header size");
- return (ARCHIVE_FATAL);
- }
- if ((h = __archive_read_ahead(a, skip, NULL)) == NULL)
- return (ARCHIVE_FATAL);
- p = h;
- memcpy(rar->reserved1, p + 7, sizeof(rar->reserved1));
- memcpy(rar->reserved2, p + 7 + sizeof(rar->reserved1),
- sizeof(rar->reserved2));
- if (rar->main_flags & MHD_ENCRYPTVER) {
- if (skip < 7 + sizeof(rar->reserved1) + sizeof(rar->reserved2)+1) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid header size");
- return (ARCHIVE_FATAL);
- }
- rar->encryptver = *(p + 7 + sizeof(rar->reserved1) +
- sizeof(rar->reserved2));
- }
-
- if (rar->main_flags & MHD_PASSWORD)
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "RAR encryption support unavailable.");
- return (ARCHIVE_FATAL);
- }
-
- crc32_val = crc32(0, (const unsigned char *)p + 2, (unsigned)skip - 2);
- if ((crc32_val & 0xffff) != archive_le16dec(p)) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Header CRC error");
- return (ARCHIVE_FATAL);
- }
- __archive_read_consume(a, skip);
- break;
-
- case FILE_HEAD:
- return read_header(a, entry, head_type);
-
- case COMM_HEAD:
- case AV_HEAD:
- case SUB_HEAD:
- case PROTECT_HEAD:
- case SIGN_HEAD:
- case ENDARC_HEAD:
- flags = archive_le16dec(p + 3);
- skip = archive_le16dec(p + 5);
- if (skip < 7) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid header size");
- return (ARCHIVE_FATAL);
- }
- if (skip > 7) {
- if ((h = __archive_read_ahead(a, skip, NULL)) == NULL)
- return (ARCHIVE_FATAL);
- p = h;
- }
- if (flags & HD_ADD_SIZE_PRESENT)
- {
- if (skip < 7 + 4) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid header size");
- return (ARCHIVE_FATAL);
- }
- skip += archive_le32dec(p + 7);
- if ((h = __archive_read_ahead(a, skip, NULL)) == NULL)
- return (ARCHIVE_FATAL);
- p = h;
- }
-
- crc32_val = crc32(0, (const unsigned char *)p + 2, (unsigned)skip - 2);
- if ((crc32_val & 0xffff) != archive_le16dec(p)) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Header CRC error");
- return (ARCHIVE_FATAL);
- }
- __archive_read_consume(a, skip);
- if (head_type == ENDARC_HEAD)
- return (ARCHIVE_EOF);
- break;
-
- case NEWSUB_HEAD:
- if ((ret = read_header(a, entry, head_type)) < ARCHIVE_WARN)
- return ret;
- break;
-
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Bad RAR file");
- return (ARCHIVE_FATAL);
- }
- }
-}
-
-static int
-archive_read_format_rar_read_data(struct archive_read *a, const void **buff,
- size_t *size, int64_t *offset)
-{
- struct rar *rar = (struct rar *)(a->format->data);
- int ret;
-
- if (rar->bytes_unconsumed > 0) {
- /* Consume as much as the decompressor actually used. */
- __archive_read_consume(a, rar->bytes_unconsumed);
- rar->bytes_unconsumed = 0;
- }
-
- if (rar->entry_eof || rar->offset_seek >= rar->unp_size) {
- *buff = NULL;
- *size = 0;
- *offset = rar->offset;
- if (*offset < rar->unp_size)
- *offset = rar->unp_size;
- return (ARCHIVE_EOF);
- }
-
- switch (rar->compression_method)
- {
- case COMPRESS_METHOD_STORE:
- ret = read_data_stored(a, buff, size, offset);
- break;
-
- case COMPRESS_METHOD_FASTEST:
- case COMPRESS_METHOD_FAST:
- case COMPRESS_METHOD_NORMAL:
- case COMPRESS_METHOD_GOOD:
- case COMPRESS_METHOD_BEST:
- ret = read_data_compressed(a, buff, size, offset);
- if (ret != ARCHIVE_OK && ret != ARCHIVE_WARN)
- __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc);
- break;
-
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Unsupported compression method for RAR file.");
- ret = ARCHIVE_FATAL;
- break;
- }
- return (ret);
-}
-
-static int
-archive_read_format_rar_read_data_skip(struct archive_read *a)
-{
- struct rar *rar;
- int64_t bytes_skipped;
- int ret;
-
- rar = (struct rar *)(a->format->data);
-
- if (rar->bytes_unconsumed > 0) {
- /* Consume as much as the decompressor actually used. */
- __archive_read_consume(a, rar->bytes_unconsumed);
- rar->bytes_unconsumed = 0;
- }
-
- if (rar->bytes_remaining > 0) {
- bytes_skipped = __archive_read_consume(a, rar->bytes_remaining);
- if (bytes_skipped < 0)
- return (ARCHIVE_FATAL);
- }
-
- /* Compressed data to skip must be read from each header in a multivolume
- * archive.
- */
- if (rar->main_flags & MHD_VOLUME && rar->file_flags & FHD_SPLIT_AFTER)
- {
- ret = archive_read_format_rar_read_header(a, a->entry);
- if (ret == (ARCHIVE_EOF))
- ret = archive_read_format_rar_read_header(a, a->entry);
- if (ret != (ARCHIVE_OK))
- return ret;
- return archive_read_format_rar_read_data_skip(a);
- }
-
- return (ARCHIVE_OK);
-}
-
-static int64_t
-archive_read_format_rar_seek_data(struct archive_read *a, int64_t offset,
- int whence)
-{
- int64_t client_offset, ret;
- unsigned int i;
- struct rar *rar = (struct rar *)(a->format->data);
-
- if (rar->compression_method == COMPRESS_METHOD_STORE)
- {
- /* Modify the offset for use with SEEK_SET */
- switch (whence)
- {
- case SEEK_CUR:
- client_offset = rar->offset_seek;
- break;
- case SEEK_END:
- client_offset = rar->unp_size;
- break;
- case SEEK_SET:
- default:
- client_offset = 0;
- }
- client_offset += offset;
- if (client_offset < 0)
- {
- /* Can't seek past beginning of data block */
- return -1;
- }
- else if (client_offset > rar->unp_size)
- {
- /*
- * Set the returned offset but only seek to the end of
- * the data block.
- */
- rar->offset_seek = client_offset;
- client_offset = rar->unp_size;
- }
-
- client_offset += rar->dbo[0].start_offset;
- i = 0;
- while (i < rar->cursor)
- {
- i++;
- client_offset += rar->dbo[i].start_offset - rar->dbo[i-1].end_offset;
- }
- if (rar->main_flags & MHD_VOLUME)
- {
- /* Find the appropriate offset among the multivolume archive */
- while (1)
- {
- if (client_offset < rar->dbo[rar->cursor].start_offset &&
- rar->file_flags & FHD_SPLIT_BEFORE)
- {
- /* Search backwards for the correct data block */
- if (rar->cursor == 0)
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Attempt to seek past beginning of RAR data block");
- return (ARCHIVE_FAILED);
- }
- rar->cursor--;
- client_offset -= rar->dbo[rar->cursor+1].start_offset -
- rar->dbo[rar->cursor].end_offset;
- if (client_offset < rar->dbo[rar->cursor].start_offset)
- continue;
- ret = __archive_read_seek(a, rar->dbo[rar->cursor].start_offset -
- rar->dbo[rar->cursor].header_size, SEEK_SET);
- if (ret < (ARCHIVE_OK))
- return ret;
- ret = archive_read_format_rar_read_header(a, a->entry);
- if (ret != (ARCHIVE_OK))
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Error during seek of RAR file");
- return (ARCHIVE_FAILED);
- }
- rar->cursor--;
- break;
- }
- else if (client_offset > rar->dbo[rar->cursor].end_offset &&
- rar->file_flags & FHD_SPLIT_AFTER)
- {
- /* Search forward for the correct data block */
- rar->cursor++;
- if (rar->cursor < rar->nodes &&
- client_offset > rar->dbo[rar->cursor].end_offset)
- {
- client_offset += rar->dbo[rar->cursor].start_offset -
- rar->dbo[rar->cursor-1].end_offset;
- continue;
- }
- rar->cursor--;
- ret = __archive_read_seek(a, rar->dbo[rar->cursor].end_offset,
- SEEK_SET);
- if (ret < (ARCHIVE_OK))
- return ret;
- ret = archive_read_format_rar_read_header(a, a->entry);
- if (ret == (ARCHIVE_EOF))
- {
- rar->has_endarc_header = 1;
- ret = archive_read_format_rar_read_header(a, a->entry);
- }
- if (ret != (ARCHIVE_OK))
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Error during seek of RAR file");
- return (ARCHIVE_FAILED);
- }
- client_offset += rar->dbo[rar->cursor].start_offset -
- rar->dbo[rar->cursor-1].end_offset;
- continue;
- }
- break;
- }
- }
-
- ret = __archive_read_seek(a, client_offset, SEEK_SET);
- if (ret < (ARCHIVE_OK))
- return ret;
- rar->bytes_remaining = rar->dbo[rar->cursor].end_offset - ret;
- i = rar->cursor;
- while (i > 0)
- {
- i--;
- ret -= rar->dbo[i+1].start_offset - rar->dbo[i].end_offset;
- }
- ret -= rar->dbo[0].start_offset;
-
- /* Always restart reading the file after a seek */
- a->read_data_block = NULL;
- a->read_data_offset = 0;
- a->read_data_output_offset = 0;
- a->read_data_remaining = 0;
- rar->bytes_unconsumed = 0;
- rar->offset = 0;
-
- /*
- * If a seek past the end of file was requested, return the requested
- * offset.
- */
- if (ret == rar->unp_size && rar->offset_seek > rar->unp_size)
- return rar->offset_seek;
-
- /* Return the new offset */
- rar->offset_seek = ret;
- return rar->offset_seek;
- }
- else
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Seeking of compressed RAR files is unsupported");
- }
- return (ARCHIVE_FAILED);
-}
-
-static int
-archive_read_format_rar_cleanup(struct archive_read *a)
-{
- struct rar *rar;
-
- rar = (struct rar *)(a->format->data);
- free_codes(a);
- free(rar->filename);
- free(rar->filename_save);
- free(rar->dbo);
- free(rar->unp_buffer);
- free(rar->lzss.window);
- __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc);
- free(rar);
- (a->format->data) = NULL;
- return (ARCHIVE_OK);
-}
-
-static int
-read_header(struct archive_read *a, struct archive_entry *entry,
- char head_type)
-{
- const void *h;
- const char *p, *endp;
- struct rar *rar;
- struct rar_header rar_header;
- struct rar_file_header file_header;
- int64_t header_size;
- unsigned filename_size, end;
- char *filename;
- char *strp;
- char packed_size[8];
- char unp_size[8];
- int ttime;
- struct archive_string_conv *sconv, *fn_sconv;
- unsigned long crc32_val;
- int ret = (ARCHIVE_OK), ret2;
-
- rar = (struct rar *)(a->format->data);
-
- /* Setup a string conversion object for non-rar-unicode filenames. */
- sconv = rar->opt_sconv;
- if (sconv == NULL) {
- if (!rar->init_default_conversion) {
- rar->sconv_default =
- archive_string_default_conversion_for_read(
- &(a->archive));
- rar->init_default_conversion = 1;
- }
- sconv = rar->sconv_default;
- }
-
-
- if ((h = __archive_read_ahead(a, 7, NULL)) == NULL)
- return (ARCHIVE_FATAL);
- p = h;
- memcpy(&rar_header, p, sizeof(rar_header));
- rar->file_flags = archive_le16dec(rar_header.flags);
- header_size = archive_le16dec(rar_header.size);
- if (header_size < (int64_t)sizeof(file_header) + 7) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid header size");
- return (ARCHIVE_FATAL);
- }
- crc32_val = crc32(0, (const unsigned char *)p + 2, 7 - 2);
- __archive_read_consume(a, 7);
-
- if (!(rar->file_flags & FHD_SOLID))
- {
- rar->compression_method = 0;
- rar->packed_size = 0;
- rar->unp_size = 0;
- rar->mtime = 0;
- rar->ctime = 0;
- rar->atime = 0;
- rar->arctime = 0;
- rar->mode = 0;
- memset(&rar->salt, 0, sizeof(rar->salt));
- rar->atime = 0;
- rar->ansec = 0;
- rar->ctime = 0;
- rar->cnsec = 0;
- rar->mtime = 0;
- rar->mnsec = 0;
- rar->arctime = 0;
- rar->arcnsec = 0;
- }
- else
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "RAR solid archive support unavailable.");
- return (ARCHIVE_FATAL);
- }
-
- if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL)
- return (ARCHIVE_FATAL);
-
- /* File Header CRC check. */
- crc32_val = crc32(crc32_val, h, (unsigned)(header_size - 7));
- if ((crc32_val & 0xffff) != archive_le16dec(rar_header.crc)) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Header CRC error");
- return (ARCHIVE_FATAL);
- }
- /* If no CRC error, Go on parsing File Header. */
- p = h;
- endp = p + header_size - 7;
- memcpy(&file_header, p, sizeof(file_header));
- p += sizeof(file_header);
-
- rar->compression_method = file_header.method;
-
- ttime = archive_le32dec(file_header.file_time);
- rar->mtime = get_time(ttime);
-
- rar->file_crc = archive_le32dec(file_header.file_crc);
-
- if (rar->file_flags & FHD_PASSWORD)
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "RAR encryption support unavailable.");
- return (ARCHIVE_FATAL);
- }
-
- if (rar->file_flags & FHD_LARGE)
- {
- memcpy(packed_size, file_header.pack_size, 4);
- memcpy(packed_size + 4, p, 4); /* High pack size */
- p += 4;
- memcpy(unp_size, file_header.unp_size, 4);
- memcpy(unp_size + 4, p, 4); /* High unpack size */
- p += 4;
- rar->packed_size = archive_le64dec(&packed_size);
- rar->unp_size = archive_le64dec(&unp_size);
- }
- else
- {
- rar->packed_size = archive_le32dec(file_header.pack_size);
- rar->unp_size = archive_le32dec(file_header.unp_size);
- }
-
- if (rar->packed_size < 0 || rar->unp_size < 0)
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid sizes specified.");
- return (ARCHIVE_FATAL);
- }
-
- rar->bytes_remaining = rar->packed_size;
-
- /* TODO: RARv3 subblocks contain comments. For now the complete block is
- * consumed at the end.
- */
- if (head_type == NEWSUB_HEAD) {
- size_t distance = p - (const char *)h;
- header_size += rar->packed_size;
- /* Make sure we have the extended data. */
- if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL)
- return (ARCHIVE_FATAL);
- p = h;
- endp = p + header_size - 7;
- p += distance;
- }
-
- filename_size = archive_le16dec(file_header.name_size);
- if (p + filename_size > endp) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid filename size");
- return (ARCHIVE_FATAL);
- }
- if (rar->filename_allocated < filename_size * 2 + 2) {
- char *newptr;
- size_t newsize = filename_size * 2 + 2;
- newptr = realloc(rar->filename, newsize);
- if (newptr == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Couldn't allocate memory.");
- return (ARCHIVE_FATAL);
- }
- rar->filename = newptr;
- rar->filename_allocated = newsize;
- }
- filename = rar->filename;
- memcpy(filename, p, filename_size);
- filename[filename_size] = '\0';
- if (rar->file_flags & FHD_UNICODE)
- {
- if (filename_size != strlen(filename))
- {
- unsigned char highbyte, flagbits, flagbyte;
- unsigned fn_end, offset;
-
- end = filename_size;
- fn_end = filename_size * 2;
- filename_size = 0;
- offset = (unsigned)strlen(filename) + 1;
- highbyte = *(p + offset++);
- flagbits = 0;
- flagbyte = 0;
- while (offset < end && filename_size < fn_end)
- {
- if (!flagbits)
- {
- flagbyte = *(p + offset++);
- flagbits = 8;
- }
-
- flagbits -= 2;
- switch((flagbyte >> flagbits) & 3)
- {
- case 0:
- filename[filename_size++] = '\0';
- filename[filename_size++] = *(p + offset++);
- break;
- case 1:
- filename[filename_size++] = highbyte;
- filename[filename_size++] = *(p + offset++);
- break;
- case 2:
- filename[filename_size++] = *(p + offset + 1);
- filename[filename_size++] = *(p + offset);
- offset += 2;
- break;
- case 3:
- {
- char extra, high;
- uint8_t length = *(p + offset++);
-
- if (length & 0x80) {
- extra = *(p + offset++);
- high = (char)highbyte;
- } else
- extra = high = 0;
- length = (length & 0x7f) + 2;
- while (length && filename_size < fn_end) {
- unsigned cp = filename_size >> 1;
- filename[filename_size++] = high;
- filename[filename_size++] = p[cp] + extra;
- length--;
- }
- }
- break;
- }
- }
- if (filename_size > fn_end) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid filename");
- return (ARCHIVE_FATAL);
- }
- filename[filename_size++] = '\0';
- filename[filename_size++] = '\0';
-
- /* Decoded unicode form is UTF-16BE, so we have to update a string
- * conversion object for it. */
- if (rar->sconv_utf16be == NULL) {
- rar->sconv_utf16be = archive_string_conversion_from_charset(
- &a->archive, "UTF-16BE", 1);
- if (rar->sconv_utf16be == NULL)
- return (ARCHIVE_FATAL);
- }
- fn_sconv = rar->sconv_utf16be;
-
- strp = filename;
- while (memcmp(strp, "\x00\x00", 2))
- {
- if (!memcmp(strp, "\x00\\", 2))
- *(strp + 1) = '/';
- strp += 2;
- }
- p += offset;
- } else {
- /*
- * If FHD_UNICODE is set but no unicode data, this file name form
- * is UTF-8, so we have to update a string conversion object for
- * it accordingly.
- */
- if (rar->sconv_utf8 == NULL) {
- rar->sconv_utf8 = archive_string_conversion_from_charset(
- &a->archive, "UTF-8", 1);
- if (rar->sconv_utf8 == NULL)
- return (ARCHIVE_FATAL);
- }
- fn_sconv = rar->sconv_utf8;
- while ((strp = strchr(filename, '\\')) != NULL)
- *strp = '/';
- p += filename_size;
- }
- }
- else
- {
- fn_sconv = sconv;
- while ((strp = strchr(filename, '\\')) != NULL)
- *strp = '/';
- p += filename_size;
- }
-
- /* Split file in multivolume RAR. No more need to process header. */
- if (rar->filename_save &&
- !memcmp(rar->filename, rar->filename_save, filename_size + 1))
- {
- __archive_read_consume(a, header_size - 7);
- rar->cursor++;
- if (rar->cursor >= rar->nodes)
- {
- rar->nodes++;
- if ((rar->dbo =
- realloc(rar->dbo, sizeof(*rar->dbo) * rar->nodes)) == NULL)
- {
- archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory.");
- return (ARCHIVE_FATAL);
- }
- rar->dbo[rar->cursor].header_size = header_size;
- rar->dbo[rar->cursor].start_offset = -1;
- rar->dbo[rar->cursor].end_offset = -1;
- }
- if (rar->dbo[rar->cursor].start_offset < 0)
- {
- rar->dbo[rar->cursor].start_offset = a->filter->position;
- rar->dbo[rar->cursor].end_offset = rar->dbo[rar->cursor].start_offset +
- rar->packed_size;
- }
- return ret;
- }
-
- rar->filename_save = (char*)realloc(rar->filename_save,
- filename_size + 1);
- memcpy(rar->filename_save, rar->filename, filename_size + 1);
-
- /* Set info for seeking */
- free(rar->dbo);
- if ((rar->dbo = calloc(1, sizeof(*rar->dbo))) == NULL)
- {
- archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory.");
- return (ARCHIVE_FATAL);
- }
- rar->dbo[0].header_size = header_size;
- rar->dbo[0].start_offset = -1;
- rar->dbo[0].end_offset = -1;
- rar->cursor = 0;
- rar->nodes = 1;
-
- if (rar->file_flags & FHD_SALT)
- {
- if (p + 8 > endp) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid header size");
- return (ARCHIVE_FATAL);
- }
- memcpy(rar->salt, p, 8);
- p += 8;
- }
-
- if (rar->file_flags & FHD_EXTTIME) {
- if (read_exttime(p, rar, endp) < 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid header size");
- return (ARCHIVE_FATAL);
- }
- }
-
- __archive_read_consume(a, header_size - 7);
- rar->dbo[0].start_offset = a->filter->position;
- rar->dbo[0].end_offset = rar->dbo[0].start_offset + rar->packed_size;
-
- switch(file_header.host_os)
- {
- case OS_MSDOS:
- case OS_OS2:
- case OS_WIN32:
- rar->mode = archive_le32dec(file_header.file_attr);
- if (rar->mode & FILE_ATTRIBUTE_DIRECTORY)
- rar->mode = AE_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
- else
- rar->mode = AE_IFREG;
- rar->mode |= S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
- break;
-
- case OS_UNIX:
- case OS_MAC_OS:
- case OS_BEOS:
- rar->mode = archive_le32dec(file_header.file_attr);
- break;
-
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Unknown file attributes from RAR file's host OS");
- return (ARCHIVE_FATAL);
- }
-
- rar->bytes_uncopied = rar->bytes_unconsumed = 0;
- rar->lzss.position = rar->offset = 0;
- rar->offset_seek = 0;
- rar->dictionary_size = 0;
- rar->offset_outgoing = 0;
- rar->br.cache_avail = 0;
- rar->br.avail_in = 0;
- rar->crc_calculated = 0;
- rar->entry_eof = 0;
- rar->valid = 1;
- rar->is_ppmd_block = 0;
- rar->start_new_table = 1;
- free(rar->unp_buffer);
- rar->unp_buffer = NULL;
- rar->unp_offset = 0;
- rar->unp_buffer_size = UNP_BUFFER_SIZE;
- memset(rar->lengthtable, 0, sizeof(rar->lengthtable));
- __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc);
- rar->ppmd_valid = rar->ppmd_eod = 0;
-
- /* Don't set any archive entries for non-file header types */
- if (head_type == NEWSUB_HEAD)
- return ret;
-
- archive_entry_set_mtime(entry, rar->mtime, rar->mnsec);
- archive_entry_set_ctime(entry, rar->ctime, rar->cnsec);
- archive_entry_set_atime(entry, rar->atime, rar->ansec);
- archive_entry_set_size(entry, rar->unp_size);
- archive_entry_set_mode(entry, rar->mode);
-
- if (archive_entry_copy_pathname_l(entry, filename, filename_size, fn_sconv))
- {
- if (errno == ENOMEM)
- {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Pathname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Pathname cannot be converted from %s to current locale.",
- archive_string_conversion_charset_name(fn_sconv));
- ret = (ARCHIVE_WARN);
- }
-
- if (((rar->mode) & AE_IFMT) == AE_IFLNK)
- {
- /* Make sure a symbolic-link file does not have its body. */
- rar->bytes_remaining = 0;
- archive_entry_set_size(entry, 0);
-
- /* Read a symbolic-link name. */
- if ((ret2 = read_symlink_stored(a, entry, sconv)) < (ARCHIVE_WARN))
- return ret2;
- if (ret > ret2)
- ret = ret2;
- }
-
- if (rar->bytes_remaining == 0)
- rar->entry_eof = 1;
-
- return ret;
-}
-
-static time_t
-get_time(int ttime)
-{
- struct tm tm;
- tm.tm_sec = 2 * (ttime & 0x1f);
- tm.tm_min = (ttime >> 5) & 0x3f;
- tm.tm_hour = (ttime >> 11) & 0x1f;
- tm.tm_mday = (ttime >> 16) & 0x1f;
- tm.tm_mon = ((ttime >> 21) & 0x0f) - 1;
- tm.tm_year = ((ttime >> 25) & 0x7f) + 80;
- tm.tm_isdst = -1;
- return mktime(&tm);
-}
-
-static int
-read_exttime(const char *p, struct rar *rar, const char *endp)
-{
- unsigned rmode, flags, rem, j, count;
- int ttime, i;
- struct tm *tm;
- time_t t;
- long nsec;
-
- if (p + 2 > endp)
- return (-1);
- flags = archive_le16dec(p);
- p += 2;
-
- for (i = 3; i >= 0; i--)
- {
- t = 0;
- if (i == 3)
- t = rar->mtime;
- rmode = flags >> i * 4;
- if (rmode & 8)
- {
- if (!t)
- {
- if (p + 4 > endp)
- return (-1);
- ttime = archive_le32dec(p);
- t = get_time(ttime);
- p += 4;
- }
- rem = 0;
- count = rmode & 3;
- if (p + count > endp)
- return (-1);
- for (j = 0; j < count; j++)
- {
- rem = ((*p) << 16) | (rem >> 8);
- p++;
- }
- tm = localtime(&t);
- nsec = tm->tm_sec + rem / NS_UNIT;
- if (rmode & 4)
- {
- tm->tm_sec++;
- t = mktime(tm);
- }
- if (i == 3)
- {
- rar->mtime = t;
- rar->mnsec = nsec;
- }
- else if (i == 2)
- {
- rar->ctime = t;
- rar->cnsec = nsec;
- }
- else if (i == 1)
- {
- rar->atime = t;
- rar->ansec = nsec;
- }
- else
- {
- rar->arctime = t;
- rar->arcnsec = nsec;
- }
- }
- }
- return (0);
-}
-
-static int
-read_symlink_stored(struct archive_read *a, struct archive_entry *entry,
- struct archive_string_conv *sconv)
-{
- const void *h;
- const char *p;
- struct rar *rar;
- int ret = (ARCHIVE_OK);
-
- rar = (struct rar *)(a->format->data);
- if ((h = rar_read_ahead(a, (size_t)rar->packed_size, NULL)) == NULL)
- return (ARCHIVE_FATAL);
- p = h;
-
- if (archive_entry_copy_symlink_l(entry,
- p, (size_t)rar->packed_size, sconv))
- {
- if (errno == ENOMEM)
- {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for link");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "link cannot be converted from %s to current locale.",
- archive_string_conversion_charset_name(sconv));
- ret = (ARCHIVE_WARN);
- }
- __archive_read_consume(a, rar->packed_size);
- return ret;
-}
-
-static int
-read_data_stored(struct archive_read *a, const void **buff, size_t *size,
- int64_t *offset)
-{
- struct rar *rar;
- ssize_t bytes_avail;
-
- rar = (struct rar *)(a->format->data);
- if (rar->bytes_remaining == 0 &&
- !(rar->main_flags & MHD_VOLUME && rar->file_flags & FHD_SPLIT_AFTER))
- {
- *buff = NULL;
- *size = 0;
- *offset = rar->offset;
- if (rar->file_crc != rar->crc_calculated) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "File CRC error");
- return (ARCHIVE_FATAL);
- }
- rar->entry_eof = 1;
- return (ARCHIVE_EOF);
- }
-
- *buff = rar_read_ahead(a, 1, &bytes_avail);
- if (bytes_avail <= 0)
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated RAR file data");
- return (ARCHIVE_FATAL);
- }
-
- *size = bytes_avail;
- *offset = rar->offset;
- rar->offset += bytes_avail;
- rar->offset_seek += bytes_avail;
- rar->bytes_remaining -= bytes_avail;
- rar->bytes_unconsumed = bytes_avail;
- /* Calculate File CRC. */
- rar->crc_calculated = crc32(rar->crc_calculated, *buff,
- (unsigned)bytes_avail);
- return (ARCHIVE_OK);
-}
-
-static int
-read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
- int64_t *offset)
-{
- struct rar *rar;
- int64_t start, end, actualend;
- size_t bs;
- int ret = (ARCHIVE_OK), sym, code, lzss_offset, length, i;
-
- rar = (struct rar *)(a->format->data);
-
- do {
- if (!rar->valid)
- return (ARCHIVE_FATAL);
- if (rar->ppmd_eod ||
- (rar->dictionary_size && rar->offset >= rar->unp_size))
- {
- if (rar->unp_offset > 0) {
- /*
- * We have unprocessed extracted data. write it out.
- */
- *buff = rar->unp_buffer;
- *size = rar->unp_offset;
- *offset = rar->offset_outgoing;
- rar->offset_outgoing += *size;
- /* Calculate File CRC. */
- rar->crc_calculated = crc32(rar->crc_calculated, *buff,
- (unsigned)*size);
- rar->unp_offset = 0;
- return (ARCHIVE_OK);
- }
- *buff = NULL;
- *size = 0;
- *offset = rar->offset;
- if (rar->file_crc != rar->crc_calculated) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "File CRC error");
- return (ARCHIVE_FATAL);
- }
- rar->entry_eof = 1;
- return (ARCHIVE_EOF);
- }
-
- if (!rar->is_ppmd_block && rar->dictionary_size && rar->bytes_uncopied > 0)
- {
- if (rar->bytes_uncopied > (rar->unp_buffer_size - rar->unp_offset))
- bs = rar->unp_buffer_size - rar->unp_offset;
- else
- bs = (size_t)rar->bytes_uncopied;
- ret = copy_from_lzss_window(a, buff, rar->offset, (int)bs);
- if (ret != ARCHIVE_OK)
- return (ret);
- rar->offset += bs;
- rar->bytes_uncopied -= bs;
- if (*buff != NULL) {
- rar->unp_offset = 0;
- *size = rar->unp_buffer_size;
- *offset = rar->offset_outgoing;
- rar->offset_outgoing += *size;
- /* Calculate File CRC. */
- rar->crc_calculated = crc32(rar->crc_calculated, *buff,
- (unsigned)*size);
- return (ret);
- }
- continue;
- }
-
- if (!rar->br.next_in &&
- (ret = rar_br_preparation(a, &(rar->br))) < ARCHIVE_WARN)
- return (ret);
- if (rar->start_new_table && ((ret = parse_codes(a)) < (ARCHIVE_WARN)))
- return (ret);
-
- if (rar->is_ppmd_block)
- {
- if ((sym = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(
- &rar->ppmd7_context, &rar->range_dec.p)) < 0)
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid symbol");
- return (ARCHIVE_FATAL);
- }
- if(sym != rar->ppmd_escape)
- {
- lzss_emit_literal(rar, sym);
- rar->bytes_uncopied++;
- }
- else
- {
- if ((code = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(
- &rar->ppmd7_context, &rar->range_dec.p)) < 0)
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid symbol");
- return (ARCHIVE_FATAL);
- }
-
- switch(code)
- {
- case 0:
- rar->start_new_table = 1;
- return read_data_compressed(a, buff, size, offset);
-
- case 2:
- rar->ppmd_eod = 1;/* End Of ppmd Data. */
- continue;
-
- case 3:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Parsing filters is unsupported.");
- return (ARCHIVE_FAILED);
-
- case 4:
- lzss_offset = 0;
- for (i = 2; i >= 0; i--)
- {
- if ((code = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(
- &rar->ppmd7_context, &rar->range_dec.p)) < 0)
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid symbol");
- return (ARCHIVE_FATAL);
- }
- lzss_offset |= code << (i * 8);
- }
- if ((length = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(
- &rar->ppmd7_context, &rar->range_dec.p)) < 0)
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid symbol");
- return (ARCHIVE_FATAL);
- }
- lzss_emit_match(rar, lzss_offset + 2, length + 32);
- rar->bytes_uncopied += length + 32;
- break;
-
- case 5:
- if ((length = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(
- &rar->ppmd7_context, &rar->range_dec.p)) < 0)
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid symbol");
- return (ARCHIVE_FATAL);
- }
- lzss_emit_match(rar, 1, length + 4);
- rar->bytes_uncopied += length + 4;
- break;
-
- default:
- lzss_emit_literal(rar, sym);
- rar->bytes_uncopied++;
- }
- }
- }
- else
- {
- start = rar->offset;
- end = start + rar->dictionary_size;
- rar->filterstart = INT64_MAX;
-
- if ((actualend = expand(a, end)) < 0)
- return ((int)actualend);
-
- rar->bytes_uncopied = actualend - start;
- if (rar->bytes_uncopied == 0) {
- /* Broken RAR files cause this case.
- * NOTE: If this case were possible on a normal RAR file
- * we would find out where it was actually bad and
- * what we would do to solve it. */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Internal error extracting RAR file");
- return (ARCHIVE_FATAL);
- }
- }
- if (rar->bytes_uncopied > (rar->unp_buffer_size - rar->unp_offset))
- bs = rar->unp_buffer_size - rar->unp_offset;
- else
- bs = (size_t)rar->bytes_uncopied;
- ret = copy_from_lzss_window(a, buff, rar->offset, (int)bs);
- if (ret != ARCHIVE_OK)
- return (ret);
- rar->offset += bs;
- rar->bytes_uncopied -= bs;
- /*
- * If *buff is NULL, it means unp_buffer is not full.
- * So we have to continue extracting a RAR file.
- */
- } while (*buff == NULL);
-
- rar->unp_offset = 0;
- *size = rar->unp_buffer_size;
- *offset = rar->offset_outgoing;
- rar->offset_outgoing += *size;
- /* Calculate File CRC. */
- rar->crc_calculated = crc32(rar->crc_calculated, *buff, (unsigned)*size);
- return ret;
-}
-
-static int
-parse_codes(struct archive_read *a)
-{
- int i, j, val, n, r;
- unsigned char bitlengths[MAX_SYMBOLS], zerocount, ppmd_flags;
- unsigned int maxorder;
- struct huffman_code precode;
- struct rar *rar = (struct rar *)(a->format->data);
- struct rar_br *br = &(rar->br);
-
- free_codes(a);
-
- /* Skip to the next byte */
- rar_br_consume_unalined_bits(br);
-
- /* PPMd block flag */
- if (!rar_br_read_ahead(a, br, 1))
- goto truncated_data;
- if ((rar->is_ppmd_block = rar_br_bits(br, 1)) != 0)
- {
- rar_br_consume(br, 1);
- if (!rar_br_read_ahead(a, br, 7))
- goto truncated_data;
- ppmd_flags = rar_br_bits(br, 7);
- rar_br_consume(br, 7);
-
- /* Memory is allocated in MB */
- if (ppmd_flags & 0x20)
- {
- if (!rar_br_read_ahead(a, br, 8))
- goto truncated_data;
- rar->dictionary_size = (rar_br_bits(br, 8) + 1) << 20;
- rar_br_consume(br, 8);
- }
-
- if (ppmd_flags & 0x40)
- {
- if (!rar_br_read_ahead(a, br, 8))
- goto truncated_data;
- rar->ppmd_escape = rar->ppmd7_context.InitEsc = rar_br_bits(br, 8);
- rar_br_consume(br, 8);
- }
- else
- rar->ppmd_escape = 2;
-
- if (ppmd_flags & 0x20)
- {
- maxorder = (ppmd_flags & 0x1F) + 1;
- if(maxorder > 16)
- maxorder = 16 + (maxorder - 16) * 3;
-
- if (maxorder == 1)
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated RAR file data");
- return (ARCHIVE_FATAL);
- }
-
- /* Make sure ppmd7_contest is freed before Ppmd7_Construct
- * because reading a broken file cause this abnormal sequence. */
- __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc);
-
- rar->bytein.a = a;
- rar->bytein.Read = &ppmd_read;
- __archive_ppmd7_functions.PpmdRAR_RangeDec_CreateVTable(&rar->range_dec);
- rar->range_dec.Stream = &rar->bytein;
- __archive_ppmd7_functions.Ppmd7_Construct(&rar->ppmd7_context);
-
- if (!__archive_ppmd7_functions.Ppmd7_Alloc(&rar->ppmd7_context,
- rar->dictionary_size, &g_szalloc))
- {
- archive_set_error(&a->archive, ENOMEM,
- "Out of memory");
- return (ARCHIVE_FATAL);
- }
- if (!__archive_ppmd7_functions.PpmdRAR_RangeDec_Init(&rar->range_dec))
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Unable to initialize PPMd range decoder");
- return (ARCHIVE_FATAL);
- }
- __archive_ppmd7_functions.Ppmd7_Init(&rar->ppmd7_context, maxorder);
- rar->ppmd_valid = 1;
- }
- else
- {
- if (!rar->ppmd_valid) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid PPMd sequence");
- return (ARCHIVE_FATAL);
- }
- if (!__archive_ppmd7_functions.PpmdRAR_RangeDec_Init(&rar->range_dec))
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Unable to initialize PPMd range decoder");
- return (ARCHIVE_FATAL);
- }
- }
- }
- else
- {
- rar_br_consume(br, 1);
-
- /* Keep existing table flag */
- if (!rar_br_read_ahead(a, br, 1))
- goto truncated_data;
- if (!rar_br_bits(br, 1))
- memset(rar->lengthtable, 0, sizeof(rar->lengthtable));
- rar_br_consume(br, 1);
-
- memset(&bitlengths, 0, sizeof(bitlengths));
- for (i = 0; i < MAX_SYMBOLS;)
- {
- if (!rar_br_read_ahead(a, br, 4))
- goto truncated_data;
- bitlengths[i++] = rar_br_bits(br, 4);
- rar_br_consume(br, 4);
- if (bitlengths[i-1] == 0xF)
- {
- if (!rar_br_read_ahead(a, br, 4))
- goto truncated_data;
- zerocount = rar_br_bits(br, 4);
- rar_br_consume(br, 4);
- if (zerocount)
- {
- i--;
- for (j = 0; j < zerocount + 2 && i < MAX_SYMBOLS; j++)
- bitlengths[i++] = 0;
- }
- }
- }
-
- memset(&precode, 0, sizeof(precode));
- r = create_code(a, &precode, bitlengths, MAX_SYMBOLS, MAX_SYMBOL_LENGTH);
- if (r != ARCHIVE_OK) {
- free(precode.tree);
- free(precode.table);
- return (r);
- }
-
- for (i = 0; i < HUFFMAN_TABLE_SIZE;)
- {
- if ((val = read_next_symbol(a, &precode)) < 0) {
- free(precode.tree);
- free(precode.table);
- return (ARCHIVE_FATAL);
- }
- if (val < 16)
- {
- rar->lengthtable[i] = (rar->lengthtable[i] + val) & 0xF;
- i++;
- }
- else if (val < 18)
- {
- if (i == 0)
- {
- free(precode.tree);
- free(precode.table);
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Internal error extracting RAR file.");
- return (ARCHIVE_FATAL);
- }
-
- if(val == 16) {
- if (!rar_br_read_ahead(a, br, 3)) {
- free(precode.tree);
- free(precode.table);
- goto truncated_data;
- }
- n = rar_br_bits(br, 3) + 3;
- rar_br_consume(br, 3);
- } else {
- if (!rar_br_read_ahead(a, br, 7)) {
- free(precode.tree);
- free(precode.table);
- goto truncated_data;
- }
- n = rar_br_bits(br, 7) + 11;
- rar_br_consume(br, 7);
- }
-
- for (j = 0; j < n && i < HUFFMAN_TABLE_SIZE; j++)
- {
- rar->lengthtable[i] = rar->lengthtable[i-1];
- i++;
- }
- }
- else
- {
- if(val == 18) {
- if (!rar_br_read_ahead(a, br, 3)) {
- free(precode.tree);
- free(precode.table);
- goto truncated_data;
- }
- n = rar_br_bits(br, 3) + 3;
- rar_br_consume(br, 3);
- } else {
- if (!rar_br_read_ahead(a, br, 7)) {
- free(precode.tree);
- free(precode.table);
- goto truncated_data;
- }
- n = rar_br_bits(br, 7) + 11;
- rar_br_consume(br, 7);
- }
-
- for(j = 0; j < n && i < HUFFMAN_TABLE_SIZE; j++)
- rar->lengthtable[i++] = 0;
- }
- }
- free(precode.tree);
- free(precode.table);
-
- r = create_code(a, &rar->maincode, &rar->lengthtable[0], MAINCODE_SIZE,
- MAX_SYMBOL_LENGTH);
- if (r != ARCHIVE_OK)
- return (r);
- r = create_code(a, &rar->offsetcode, &rar->lengthtable[MAINCODE_SIZE],
- OFFSETCODE_SIZE, MAX_SYMBOL_LENGTH);
- if (r != ARCHIVE_OK)
- return (r);
- r = create_code(a, &rar->lowoffsetcode,
- &rar->lengthtable[MAINCODE_SIZE + OFFSETCODE_SIZE],
- LOWOFFSETCODE_SIZE, MAX_SYMBOL_LENGTH);
- if (r != ARCHIVE_OK)
- return (r);
- r = create_code(a, &rar->lengthcode,
- &rar->lengthtable[MAINCODE_SIZE + OFFSETCODE_SIZE +
- LOWOFFSETCODE_SIZE], LENGTHCODE_SIZE, MAX_SYMBOL_LENGTH);
- if (r != ARCHIVE_OK)
- return (r);
- }
-
- if (!rar->dictionary_size || !rar->lzss.window)
- {
- /* Seems as though dictionary sizes are not used. Even so, minimize
- * memory usage as much as possible.
- */
- void *new_window;
- unsigned int new_size;
-
- if (rar->unp_size >= DICTIONARY_MAX_SIZE)
- new_size = DICTIONARY_MAX_SIZE;
- else
- new_size = rar_fls((unsigned int)rar->unp_size) << 1;
- new_window = realloc(rar->lzss.window, new_size);
- if (new_window == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Unable to allocate memory for uncompressed data.");
- return (ARCHIVE_FATAL);
- }
- rar->lzss.window = (unsigned char *)new_window;
- rar->dictionary_size = new_size;
- memset(rar->lzss.window, 0, rar->dictionary_size);
- rar->lzss.mask = rar->dictionary_size - 1;
- }
-
- rar->start_new_table = 0;
- return (ARCHIVE_OK);
-truncated_data:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated RAR file data");
- rar->valid = 0;
- return (ARCHIVE_FATAL);
-}
-
-static void
-free_codes(struct archive_read *a)
-{
- struct rar *rar = (struct rar *)(a->format->data);
- free(rar->maincode.tree);
- free(rar->offsetcode.tree);
- free(rar->lowoffsetcode.tree);
- free(rar->lengthcode.tree);
- free(rar->maincode.table);
- free(rar->offsetcode.table);
- free(rar->lowoffsetcode.table);
- free(rar->lengthcode.table);
- memset(&rar->maincode, 0, sizeof(rar->maincode));
- memset(&rar->offsetcode, 0, sizeof(rar->offsetcode));
- memset(&rar->lowoffsetcode, 0, sizeof(rar->lowoffsetcode));
- memset(&rar->lengthcode, 0, sizeof(rar->lengthcode));
-}
-
-
-static int
-read_next_symbol(struct archive_read *a, struct huffman_code *code)
-{
- unsigned char bit;
- unsigned int bits;
- int length, value, node;
- struct rar *rar;
- struct rar_br *br;
-
- if (!code->table)
- {
- if (make_table(a, code) != (ARCHIVE_OK))
- return -1;
- }
-
- rar = (struct rar *)(a->format->data);
- br = &(rar->br);
-
- /* Look ahead (peek) at bits */
- if (!rar_br_read_ahead(a, br, code->tablesize)) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated RAR file data");
- rar->valid = 0;
- return -1;
- }
- bits = rar_br_bits(br, code->tablesize);
-
- length = code->table[bits].length;
- value = code->table[bits].value;
-
- if (length < 0)
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid prefix code in bitstream");
- return -1;
- }
-
- if (length <= code->tablesize)
- {
- /* Skip length bits */
- rar_br_consume(br, length);
- return value;
- }
-
- /* Skip tablesize bits */
- rar_br_consume(br, code->tablesize);
-
- node = value;
- while (!(code->tree[node].branches[0] ==
- code->tree[node].branches[1]))
- {
- if (!rar_br_read_ahead(a, br, 1)) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated RAR file data");
- rar->valid = 0;
- return -1;
- }
- bit = rar_br_bits(br, 1);
- rar_br_consume(br, 1);
-
- if (code->tree[node].branches[bit] < 0)
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid prefix code in bitstream");
- return -1;
- }
- node = code->tree[node].branches[bit];
- }
-
- return code->tree[node].branches[0];
-}
-
-static int
-create_code(struct archive_read *a, struct huffman_code *code,
- unsigned char *lengths, int numsymbols, char maxlength)
-{
- int i, j, codebits = 0, symbolsleft = numsymbols;
-
- if (new_node(code) < 0) {
- archive_set_error(&a->archive, ENOMEM,
- "Unable to allocate memory for node data.");
- return (ARCHIVE_FATAL);
- }
- code->numentries = 1;
- code->minlength = INT_MAX;
- code->maxlength = INT_MIN;
- codebits = 0;
- for(i = 1; i <= maxlength; i++)
- {
- for(j = 0; j < numsymbols; j++)
- {
- if (lengths[j] != i) continue;
- if (add_value(a, code, j, codebits, i) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- codebits++;
- if (--symbolsleft <= 0) { break; break; }
- }
- codebits <<= 1;
- }
- return (ARCHIVE_OK);
-}
-
-static int
-add_value(struct archive_read *a, struct huffman_code *code, int value,
- int codebits, int length)
-{
- int repeatpos, lastnode, bitpos, bit, repeatnode, nextnode;
-
- free(code->table);
- code->table = NULL;
-
- if(length > code->maxlength)
- code->maxlength = length;
- if(length < code->minlength)
- code->minlength = length;
-
- repeatpos = -1;
- if (repeatpos == 0 || (repeatpos >= 0
- && (((codebits >> (repeatpos - 1)) & 3) == 0
- || ((codebits >> (repeatpos - 1)) & 3) == 3)))
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid repeat position");
- return (ARCHIVE_FATAL);
- }
-
- lastnode = 0;
- for (bitpos = length - 1; bitpos >= 0; bitpos--)
- {
- bit = (codebits >> bitpos) & 1;
-
- /* Leaf node check */
- if (code->tree[lastnode].branches[0] ==
- code->tree[lastnode].branches[1])
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Prefix found");
- return (ARCHIVE_FATAL);
- }
-
- if (bitpos == repeatpos)
- {
- /* Open branch check */
- if (!(code->tree[lastnode].branches[bit] < 0))
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid repeating code");
- return (ARCHIVE_FATAL);
- }
-
- if ((repeatnode = new_node(code)) < 0) {
- archive_set_error(&a->archive, ENOMEM,
- "Unable to allocate memory for node data.");
- return (ARCHIVE_FATAL);
- }
- if ((nextnode = new_node(code)) < 0) {
- archive_set_error(&a->archive, ENOMEM,
- "Unable to allocate memory for node data.");
- return (ARCHIVE_FATAL);
- }
-
- /* Set branches */
- code->tree[lastnode].branches[bit] = repeatnode;
- code->tree[repeatnode].branches[bit] = repeatnode;
- code->tree[repeatnode].branches[bit^1] = nextnode;
- lastnode = nextnode;
-
- bitpos++; /* terminating bit already handled, skip it */
- }
- else
- {
- /* Open branch check */
- if (code->tree[lastnode].branches[bit] < 0)
- {
- if (new_node(code) < 0) {
- archive_set_error(&a->archive, ENOMEM,
- "Unable to allocate memory for node data.");
- return (ARCHIVE_FATAL);
- }
- code->tree[lastnode].branches[bit] = code->numentries++;
- }
-
- /* set to branch */
- lastnode = code->tree[lastnode].branches[bit];
- }
- }
-
- if (!(code->tree[lastnode].branches[0] == -1
- && code->tree[lastnode].branches[1] == -2))
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Prefix found");
- return (ARCHIVE_FATAL);
- }
-
- /* Set leaf value */
- code->tree[lastnode].branches[0] = value;
- code->tree[lastnode].branches[1] = value;
-
- return (ARCHIVE_OK);
-}
-
-static int
-new_node(struct huffman_code *code)
-{
- void *new_tree;
-
- new_tree = realloc(code->tree, (code->numentries + 1) * sizeof(*code->tree));
- if (new_tree == NULL)
- return (-1);
- code->tree = (struct huffman_tree_node *)new_tree;
- code->tree[code->numentries].branches[0] = -1;
- code->tree[code->numentries].branches[1] = -2;
- return 1;
-}
-
-static int
-make_table(struct archive_read *a, struct huffman_code *code)
-{
- if (code->maxlength < code->minlength || code->maxlength > 10)
- code->tablesize = 10;
- else
- code->tablesize = code->maxlength;
-
- code->table =
- (struct huffman_table_entry *)calloc(1, sizeof(*code->table)
- * ((size_t)1 << code->tablesize));
-
- return make_table_recurse(a, code, 0, code->table, 0, code->tablesize);
-}
-
-static int
-make_table_recurse(struct archive_read *a, struct huffman_code *code, int node,
- struct huffman_table_entry *table, int depth,
- int maxdepth)
-{
- int currtablesize, i, ret = (ARCHIVE_OK);
-
- if (!code->tree)
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Huffman tree was not created.");
- return (ARCHIVE_FATAL);
- }
- if (node < 0 || node >= code->numentries)
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid location to Huffman tree specified.");
- return (ARCHIVE_FATAL);
- }
-
- currtablesize = 1 << (maxdepth - depth);
-
- if (code->tree[node].branches[0] ==
- code->tree[node].branches[1])
- {
- for(i = 0; i < currtablesize; i++)
- {
- table[i].length = depth;
- table[i].value = code->tree[node].branches[0];
- }
- }
- else if (node < 0)
- {
- for(i = 0; i < currtablesize; i++)
- table[i].length = -1;
- }
- else
- {
- if(depth == maxdepth)
- {
- table[0].length = maxdepth + 1;
- table[0].value = node;
- }
- else
- {
- ret |= make_table_recurse(a, code, code->tree[node].branches[0], table,
- depth + 1, maxdepth);
- ret |= make_table_recurse(a, code, code->tree[node].branches[1],
- table + currtablesize / 2, depth + 1, maxdepth);
- }
- }
- return ret;
-}
-
-static int64_t
-expand(struct archive_read *a, int64_t end)
-{
- static const unsigned char lengthbases[] =
- { 0, 1, 2, 3, 4, 5, 6,
- 7, 8, 10, 12, 14, 16, 20,
- 24, 28, 32, 40, 48, 56, 64,
- 80, 96, 112, 128, 160, 192, 224 };
- static const unsigned char lengthbits[] =
- { 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 1, 1, 1, 2, 2,
- 2, 2, 3, 3, 3, 3, 4,
- 4, 4, 4, 5, 5, 5, 5 };
- static const unsigned int offsetbases[] =
- { 0, 1, 2, 3, 4, 6,
- 8, 12, 16, 24, 32, 48,
- 64, 96, 128, 192, 256, 384,
- 512, 768, 1024, 1536, 2048, 3072,
- 4096, 6144, 8192, 12288, 16384, 24576,
- 32768, 49152, 65536, 98304, 131072, 196608,
- 262144, 327680, 393216, 458752, 524288, 589824,
- 655360, 720896, 786432, 851968, 917504, 983040,
- 1048576, 1310720, 1572864, 1835008, 2097152, 2359296,
- 2621440, 2883584, 3145728, 3407872, 3670016, 3932160 };
- static const unsigned char offsetbits[] =
- { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4,
- 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
- 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18 };
- static const unsigned char shortbases[] =
- { 0, 4, 8, 16, 32, 64, 128, 192 };
- static const unsigned char shortbits[] =
- { 2, 2, 3, 4, 5, 6, 6, 6 };
-
- int symbol, offs, len, offsindex, lensymbol, i, offssymbol, lowoffsetsymbol;
- unsigned char newfile;
- struct rar *rar = (struct rar *)(a->format->data);
- struct rar_br *br = &(rar->br);
-
- if (rar->filterstart < end)
- end = rar->filterstart;
-
- while (1)
- {
- if (rar->output_last_match &&
- lzss_position(&rar->lzss) + rar->lastlength <= end)
- {
- lzss_emit_match(rar, rar->lastoffset, rar->lastlength);
- rar->output_last_match = 0;
- }
-
- if(rar->is_ppmd_block || rar->output_last_match ||
- lzss_position(&rar->lzss) >= end)
- return lzss_position(&rar->lzss);
-
- if ((symbol = read_next_symbol(a, &rar->maincode)) < 0)
- return (ARCHIVE_FATAL);
- rar->output_last_match = 0;
-
- if (symbol < 256)
- {
- lzss_emit_literal(rar, symbol);
- continue;
- }
- else if (symbol == 256)
- {
- if (!rar_br_read_ahead(a, br, 1))
- goto truncated_data;
- newfile = !rar_br_bits(br, 1);
- rar_br_consume(br, 1);
-
- if(newfile)
- {
- rar->start_new_block = 1;
- if (!rar_br_read_ahead(a, br, 1))
- goto truncated_data;
- rar->start_new_table = rar_br_bits(br, 1);
- rar_br_consume(br, 1);
- return lzss_position(&rar->lzss);
- }
- else
- {
- if (parse_codes(a) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- continue;
- }
- }
- else if(symbol==257)
- {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Parsing filters is unsupported.");
- return (ARCHIVE_FAILED);
- }
- else if(symbol==258)
- {
- if(rar->lastlength == 0)
- continue;
-
- offs = rar->lastoffset;
- len = rar->lastlength;
- }
- else if (symbol <= 262)
- {
- offsindex = symbol - 259;
- offs = rar->oldoffset[offsindex];
-
- if ((lensymbol = read_next_symbol(a, &rar->lengthcode)) < 0)
- goto bad_data;
- if (lensymbol > (int)(sizeof(lengthbases)/sizeof(lengthbases[0])))
- goto bad_data;
- if (lensymbol > (int)(sizeof(lengthbits)/sizeof(lengthbits[0])))
- goto bad_data;
- len = lengthbases[lensymbol] + 2;
- if (lengthbits[lensymbol] > 0) {
- if (!rar_br_read_ahead(a, br, lengthbits[lensymbol]))
- goto truncated_data;
- len += rar_br_bits(br, lengthbits[lensymbol]);
- rar_br_consume(br, lengthbits[lensymbol]);
- }
-
- for (i = offsindex; i > 0; i--)
- rar->oldoffset[i] = rar->oldoffset[i-1];
- rar->oldoffset[0] = offs;
- }
- else if(symbol<=270)
- {
- offs = shortbases[symbol-263] + 1;
- if(shortbits[symbol-263] > 0) {
- if (!rar_br_read_ahead(a, br, shortbits[symbol-263]))
- goto truncated_data;
- offs += rar_br_bits(br, shortbits[symbol-263]);
- rar_br_consume(br, shortbits[symbol-263]);
- }
-
- len = 2;
-
- for(i = 3; i > 0; i--)
- rar->oldoffset[i] = rar->oldoffset[i-1];
- rar->oldoffset[0] = offs;
- }
- else
- {
- if (symbol-271 > (int)(sizeof(lengthbases)/sizeof(lengthbases[0])))
- goto bad_data;
- if (symbol-271 > (int)(sizeof(lengthbits)/sizeof(lengthbits[0])))
- goto bad_data;
- len = lengthbases[symbol-271]+3;
- if(lengthbits[symbol-271] > 0) {
- if (!rar_br_read_ahead(a, br, lengthbits[symbol-271]))
- goto truncated_data;
- len += rar_br_bits(br, lengthbits[symbol-271]);
- rar_br_consume(br, lengthbits[symbol-271]);
- }
-
- if ((offssymbol = read_next_symbol(a, &rar->offsetcode)) < 0)
- goto bad_data;
- if (offssymbol > (int)(sizeof(offsetbases)/sizeof(offsetbases[0])))
- goto bad_data;
- if (offssymbol > (int)(sizeof(offsetbits)/sizeof(offsetbits[0])))
- goto bad_data;
- offs = offsetbases[offssymbol]+1;
- if(offsetbits[offssymbol] > 0)
- {
- if(offssymbol > 9)
- {
- if(offsetbits[offssymbol] > 4) {
- if (!rar_br_read_ahead(a, br, offsetbits[offssymbol] - 4))
- goto truncated_data;
- offs += rar_br_bits(br, offsetbits[offssymbol] - 4) << 4;
- rar_br_consume(br, offsetbits[offssymbol] - 4);
- }
-
- if(rar->numlowoffsetrepeats > 0)
- {
- rar->numlowoffsetrepeats--;
- offs += rar->lastlowoffset;
- }
- else
- {
- if ((lowoffsetsymbol =
- read_next_symbol(a, &rar->lowoffsetcode)) < 0)
- return (ARCHIVE_FATAL);
- if(lowoffsetsymbol == 16)
- {
- rar->numlowoffsetrepeats = 15;
- offs += rar->lastlowoffset;
- }
- else
- {
- offs += lowoffsetsymbol;
- rar->lastlowoffset = lowoffsetsymbol;
- }
- }
- }
- else {
- if (!rar_br_read_ahead(a, br, offsetbits[offssymbol]))
- goto truncated_data;
- offs += rar_br_bits(br, offsetbits[offssymbol]);
- rar_br_consume(br, offsetbits[offssymbol]);
- }
- }
-
- if (offs >= 0x40000)
- len++;
- if (offs >= 0x2000)
- len++;
-
- for(i = 3; i > 0; i--)
- rar->oldoffset[i] = rar->oldoffset[i-1];
- rar->oldoffset[0] = offs;
- }
-
- rar->lastoffset = offs;
- rar->lastlength = len;
- rar->output_last_match = 1;
- }
-truncated_data:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated RAR file data");
- rar->valid = 0;
- return (ARCHIVE_FATAL);
-bad_data:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Bad RAR file data");
- return (ARCHIVE_FATAL);
-}
-
-static int
-copy_from_lzss_window(struct archive_read *a, const void **buffer,
- int64_t startpos, int length)
-{
- int windowoffs, firstpart;
- struct rar *rar = (struct rar *)(a->format->data);
-
- if (!rar->unp_buffer)
- {
- if ((rar->unp_buffer = malloc(rar->unp_buffer_size)) == NULL)
- {
- archive_set_error(&a->archive, ENOMEM,
- "Unable to allocate memory for uncompressed data.");
- return (ARCHIVE_FATAL);
- }
- }
-
- windowoffs = lzss_offset_for_position(&rar->lzss, startpos);
- if(windowoffs + length <= lzss_size(&rar->lzss))
- memcpy(&rar->unp_buffer[rar->unp_offset], &rar->lzss.window[windowoffs],
- length);
- else
- {
- firstpart = lzss_size(&rar->lzss) - windowoffs;
- if (firstpart < 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Bad RAR file data");
- return (ARCHIVE_FATAL);
- }
- if (firstpart < length) {
- memcpy(&rar->unp_buffer[rar->unp_offset],
- &rar->lzss.window[windowoffs], firstpart);
- memcpy(&rar->unp_buffer[rar->unp_offset + firstpart],
- &rar->lzss.window[0], length - firstpart);
- } else
- memcpy(&rar->unp_buffer[rar->unp_offset],
- &rar->lzss.window[windowoffs], length);
- }
- rar->unp_offset += length;
- if (rar->unp_offset >= rar->unp_buffer_size)
- *buffer = rar->unp_buffer;
- else
- *buffer = NULL;
- return (ARCHIVE_OK);
-}
-
-static const void *
-rar_read_ahead(struct archive_read *a, size_t min, ssize_t *avail)
-{
- struct rar *rar = (struct rar *)(a->format->data);
- const void *h = __archive_read_ahead(a, min, avail);
- int ret;
- if (avail)
- {
- if (a->read_data_is_posix_read && *avail > (ssize_t)a->read_data_requested)
- *avail = a->read_data_requested;
- if (*avail > rar->bytes_remaining)
- *avail = (ssize_t)rar->bytes_remaining;
- if (*avail < 0)
- return NULL;
- else if (*avail == 0 && rar->main_flags & MHD_VOLUME &&
- rar->file_flags & FHD_SPLIT_AFTER)
- {
- ret = archive_read_format_rar_read_header(a, a->entry);
- if (ret == (ARCHIVE_EOF))
- {
- rar->has_endarc_header = 1;
- ret = archive_read_format_rar_read_header(a, a->entry);
- }
- if (ret != (ARCHIVE_OK))
- return NULL;
- return rar_read_ahead(a, min, avail);
- }
- }
- return h;
-}
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_format_raw.c b/3rdparty/libarchive/libarchive/archive_read_support_format_raw.c
deleted file mode 100644
index 84349787..00000000
--- a/3rdparty/libarchive/libarchive/archive_read_support_format_raw.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*-
- * Copyright (c) 2003-2009 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: head/lib/libarchive/archive_read_support_format_raw.c 201107 2009-12-28 03:25:33Z kientzle $");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#include <stdio.h>
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-
-#include "archive.h"
-#include "archive_entry.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-
-struct raw_info {
- int64_t offset; /* Current position in the file. */
- int64_t unconsumed;
- int end_of_file;
-};
-
-static int archive_read_format_raw_bid(struct archive_read *, int);
-static int archive_read_format_raw_cleanup(struct archive_read *);
-static int archive_read_format_raw_read_data(struct archive_read *,
- const void **, size_t *, int64_t *);
-static int archive_read_format_raw_read_data_skip(struct archive_read *);
-static int archive_read_format_raw_read_header(struct archive_read *,
- struct archive_entry *);
-
-int
-archive_read_support_format_raw(struct archive *_a)
-{
- struct raw_info *info;
- struct archive_read *a = (struct archive_read *)_a;
- int r;
-
- archive_check_magic(_a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_NEW, "archive_read_support_format_raw");
-
- info = (struct raw_info *)calloc(1, sizeof(*info));
- if (info == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate raw_info data");
- return (ARCHIVE_FATAL);
- }
-
- r = __archive_read_register_format(a,
- info,
- "raw",
- archive_read_format_raw_bid,
- NULL,
- archive_read_format_raw_read_header,
- archive_read_format_raw_read_data,
- archive_read_format_raw_read_data_skip,
- NULL,
- archive_read_format_raw_cleanup);
- if (r != ARCHIVE_OK)
- free(info);
- return (r);
-}
-
-/*
- * Bid 1 if this is a non-empty file. Anyone who can really support
- * this should outbid us, so it should generally be safe to use "raw"
- * in conjunction with other formats. But, this could really confuse
- * folks if there are bid errors or minor file damage, so we don't
- * include "raw" as part of support_format_all().
- */
-static int
-archive_read_format_raw_bid(struct archive_read *a, int best_bid)
-{
- if (best_bid < 1 && __archive_read_ahead(a, 1, NULL) != NULL)
- return (1);
- return (-1);
-}
-
-/*
- * Mock up a fake header.
- */
-static int
-archive_read_format_raw_read_header(struct archive_read *a,
- struct archive_entry *entry)
-{
- struct raw_info *info;
-
- info = (struct raw_info *)(a->format->data);
- if (info->end_of_file)
- return (ARCHIVE_EOF);
-
- a->archive.archive_format = ARCHIVE_FORMAT_RAW;
- a->archive.archive_format_name = "raw";
- archive_entry_set_pathname(entry, "data");
- archive_entry_set_filetype(entry, AE_IFREG);
- archive_entry_set_perm(entry, 0644);
- /* I'm deliberately leaving most fields unset here. */
- return (ARCHIVE_OK);
-}
-
-static int
-archive_read_format_raw_read_data(struct archive_read *a,
- const void **buff, size_t *size, int64_t *offset)
-{
- struct raw_info *info;
- ssize_t avail;
-
- info = (struct raw_info *)(a->format->data);
-
- /* Consume the bytes we read last time. */
- if (info->unconsumed) {
- __archive_read_consume(a, info->unconsumed);
- info->unconsumed = 0;
- }
-
- if (info->end_of_file)
- return (ARCHIVE_EOF);
-
- /* Get whatever bytes are immediately available. */
- *buff = __archive_read_ahead(a, 1, &avail);
- if (avail > 0) {
- /* Return the bytes we just read */
- *size = avail;
- *offset = info->offset;
- info->offset += *size;
- info->unconsumed = avail;
- return (ARCHIVE_OK);
- } else if (0 == avail) {
- /* Record and return end-of-file. */
- info->end_of_file = 1;
- *size = 0;
- *offset = info->offset;
- return (ARCHIVE_EOF);
- } else {
- /* Record and return an error. */
- *size = 0;
- *offset = info->offset;
- return ((int)avail);
- }
-}
-
-static int
-archive_read_format_raw_read_data_skip(struct archive_read *a)
-{
- struct raw_info *info = (struct raw_info *)(a->format->data);
-
- /* Consume the bytes we read last time. */
- if (info->unconsumed) {
- __archive_read_consume(a, info->unconsumed);
- info->unconsumed = 0;
- }
- info->end_of_file = 1;
- return (ARCHIVE_OK);
-}
-
-static int
-archive_read_format_raw_cleanup(struct archive_read *a)
-{
- struct raw_info *info;
-
- info = (struct raw_info *)(a->format->data);
- free(info);
- a->format->data = NULL;
- return (ARCHIVE_OK);
-}
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_format_tar.c b/3rdparty/libarchive/libarchive/archive_read_support_format_tar.c
index e9523cb6..30d5bc83 100644
--- a/3rdparty/libarchive/libarchive/archive_read_support_format_tar.c
+++ b/3rdparty/libarchive/libarchive/archive_read_support_format_tar.c
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* Copyright (c) 2011-2012 Michihiro NAKAJIMA
+ * Copyright (c) 2016 Martin Matuska
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -136,6 +137,7 @@ struct tar {
int64_t entry_padding;
int64_t entry_bytes_unconsumed;
int64_t realsize;
+ int sparse_allowed;
struct sparse_block *sparse_list;
struct sparse_block *sparse_last;
int64_t sparse_offset;
@@ -151,6 +153,9 @@ struct tar {
struct archive_string_conv *sconv_default;
int init_default_conversion;
int compat_2x;
+ int process_mac_extensions;
+ int read_concatenated_archives;
+ int realsize_override;
};
static int archive_block_is_null(const char *p);
@@ -200,9 +205,14 @@ static int archive_read_format_tar_read_header(struct archive_read *,
struct archive_entry *);
static int checksum(struct archive_read *, const void *);
static int pax_attribute(struct archive_read *, struct tar *,
- struct archive_entry *, char *key, char *value);
+ struct archive_entry *, const char *key, const char *value,
+ size_t value_length);
+static int pax_attribute_acl(struct archive_read *, struct tar *,
+ struct archive_entry *, const char *, int);
+static int pax_attribute_xattr(struct archive_entry *, const char *,
+ const char *);
static int pax_header(struct archive_read *, struct tar *,
- struct archive_entry *, char *attr);
+ struct archive_entry *, struct archive_string *);
static void pax_time(const char *, int64_t *sec, long *nanos);
static ssize_t readline(struct archive_read *, struct tar *, const char **,
ssize_t limit, size_t *);
@@ -241,6 +251,10 @@ archive_read_support_format_tar(struct archive *_a)
ARCHIVE_STATE_NEW, "archive_read_support_format_tar");
tar = (struct tar *)calloc(1, sizeof(*tar));
+#ifdef HAVE_COPYFILE_H
+ /* Set this by default on Mac OS. */
+ tar->process_mac_extensions = 1;
+#endif
if (tar == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate tar data");
@@ -254,7 +268,9 @@ archive_read_support_format_tar(struct archive *_a)
archive_read_format_tar_read_data,
archive_read_format_tar_skip,
NULL,
- archive_read_format_tar_cleanup);
+ archive_read_format_tar_cleanup,
+ NULL,
+ NULL);
if (r != ARCHIVE_OK)
free(tar);
@@ -285,6 +301,57 @@ archive_read_format_tar_cleanup(struct archive_read *a)
return (ARCHIVE_OK);
}
+/*
+ * Validate number field
+ *
+ * This has to be pretty lenient in order to accommodate the enormous
+ * variety of tar writers in the world:
+ * = POSIX (IEEE Std 1003.1-1988) ustar requires octal values with leading
+ * zeros and allows fields to be terminated with space or null characters
+ * = Many writers use different termination (in particular, libarchive
+ * omits terminator bytes to squeeze one or two more digits)
+ * = Many writers pad with space and omit leading zeros
+ * = GNU tar and star write base-256 values if numbers are too
+ * big to be represented in octal
+ *
+ * Examples of specific tar headers that we should support:
+ * = Perl Archive::Tar terminates uid, gid, devminor and devmajor with two
+ * null bytes, pads size with spaces and other numeric fields with zeroes
+ * = plexus-archiver prior to 2.6.3 (before switching to commons-compress)
+ * may have uid and gid fields filled with spaces without any octal digits
+ * at all and pads all numeric fields with spaces
+ *
+ * This should tolerate all variants in use. It will reject a field
+ * where the writer just left garbage after a trailing NUL.
+ */
+static int
+validate_number_field(const char* p_field, size_t i_size)
+{
+ unsigned char marker = (unsigned char)p_field[0];
+ if (marker == 128 || marker == 255 || marker == 0) {
+ /* Base-256 marker, there's nothing we can check. */
+ return 1;
+ } else {
+ /* Must be octal */
+ size_t i = 0;
+ /* Skip any leading spaces */
+ while (i < i_size && p_field[i] == ' ') {
+ ++i;
+ }
+ /* Skip octal digits. */
+ while (i < i_size && p_field[i] >= '0' && p_field[i] <= '7') {
+ ++i;
+ }
+ /* Any remaining characters must be space or NUL padding. */
+ while (i < i_size) {
+ if (p_field[i] != ' ' && p_field[i] != 0) {
+ return 0;
+ }
+ ++i;
+ }
+ return 1;
+ }
+}
static int
archive_read_format_tar_bid(struct archive_read *a, int best_bid)
@@ -337,23 +404,19 @@ archive_read_format_tar_bid(struct archive_read *a, int best_bid)
return (0);
bid += 2; /* 6 bits of variation in an 8-bit field leaves 2 bits. */
- /* Sanity check: Look at first byte of mode field. */
- switch (255 & (unsigned)header->mode[0]) {
- case 0: case 255:
- /* Base-256 value: No further verification possible! */
- break;
- case ' ': /* Not recommended, but not illegal, either. */
- break;
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- /* Octal Value. */
- /* TODO: Check format of remainder of this field. */
- break;
- default:
- /* Not a valid mode; bail out here. */
- return (0);
+ /*
+ * Check format of mode/uid/gid/mtime/size/rdevmajor/rdevminor fields.
+ */
+ if (bid > 0 && (
+ validate_number_field(header->mode, sizeof(header->mode)) == 0
+ || validate_number_field(header->uid, sizeof(header->uid)) == 0
+ || validate_number_field(header->gid, sizeof(header->gid)) == 0
+ || validate_number_field(header->mtime, sizeof(header->mtime)) == 0
+ || validate_number_field(header->size, sizeof(header->size)) == 0
+ || validate_number_field(header->rdevmajor, sizeof(header->rdevmajor)) == 0
+ || validate_number_field(header->rdevminor, sizeof(header->rdevminor)) == 0)) {
+ bid = 0;
}
- /* TODO: Sanity test uid/gid/size/mtime/rdevmajor/rdevminor fields. */
return (bid);
}
@@ -367,8 +430,8 @@ archive_read_format_tar_options(struct archive_read *a,
tar = (struct tar *)(a->format->data);
if (strcmp(key, "compat-2x") == 0) {
- /* Handle UTF-8 filnames as libarchive 2.x */
- tar->compat_2x = (val != NULL)?1:0;
+ /* Handle UTF-8 filenames as libarchive 2.x */
+ tar->compat_2x = (val != NULL && val[0] != 0);
tar->init_default_conversion = tar->compat_2x;
return (ARCHIVE_OK);
} else if (strcmp(key, "hdrcharset") == 0) {
@@ -385,6 +448,12 @@ archive_read_format_tar_options(struct archive_read *a,
ret = ARCHIVE_FATAL;
}
return (ret);
+ } else if (strcmp(key, "mac-ext") == 0) {
+ tar->process_mac_extensions = (val != NULL && val[0] != 0);
+ return (ARCHIVE_OK);
+ } else if (strcmp(key, "read_concatenated_archives") == 0) {
+ tar->read_concatenated_archives = (val != NULL && val[0] != 0);
+ return (ARCHIVE_OK);
}
/* Note: The "warn" return is just to inform the options
@@ -397,7 +466,7 @@ archive_read_format_tar_options(struct archive_read *a,
* how much unconsumed data we have floating around, and to consume
* anything outstanding since we're going to do read_aheads
*/
-static void
+static void
tar_flush_unconsumed(struct archive_read *a, size_t *unconsumed)
{
if (*unconsumed) {
@@ -442,6 +511,7 @@ archive_read_format_tar_read_header(struct archive_read *a,
static int default_dev;
struct tar *tar;
const char *p;
+ const wchar_t *wp;
int r;
size_t l, unconsumed = 0;
@@ -458,6 +528,7 @@ archive_read_format_tar_read_header(struct archive_read *a,
tar->entry_offset = 0;
gnu_clear_sparse_list(tar);
tar->realsize = -1; /* Mark this as "unset" */
+ tar->realsize_override = 0;
/* Setup default string conversion. */
tar->sconv = tar->opt_sconv;
@@ -492,27 +563,22 @@ archive_read_format_tar_read_header(struct archive_read *a,
}
}
- if (r == ARCHIVE_OK) {
+ if (r == ARCHIVE_OK && archive_entry_filetype(entry) == AE_IFREG) {
/*
* "Regular" entry with trailing '/' is really
* directory: This is needed for certain old tar
* variants and even for some broken newer ones.
*/
- const wchar_t *wp;
- wp = archive_entry_pathname_w(entry);
- if (wp != NULL) {
+ if ((wp = archive_entry_pathname_w(entry)) != NULL) {
l = wcslen(wp);
- if (archive_entry_filetype(entry) == AE_IFREG
- && wp[l-1] == L'/')
+ if (l > 0 && wp[l - 1] == L'/') {
archive_entry_set_filetype(entry, AE_IFDIR);
- } else {
- p = archive_entry_pathname(entry);
- if (p == NULL)
- return (ARCHIVE_FAILED);
+ }
+ } else if ((p = archive_entry_pathname(entry)) != NULL) {
l = strlen(p);
- if (archive_entry_filetype(entry) == AE_IFREG
- && p[l-1] == '/')
+ if (l > 0 && p[l - 1] == '/') {
archive_entry_set_filetype(entry, AE_IFDIR);
+ }
}
}
return (r);
@@ -585,13 +651,27 @@ static int
archive_read_format_tar_skip(struct archive_read *a)
{
int64_t bytes_skipped;
+ int64_t request;
+ struct sparse_block *p;
struct tar* tar;
tar = (struct tar *)(a->format->data);
- bytes_skipped = __archive_read_consume(a,
- tar->entry_bytes_remaining + tar->entry_padding +
- tar->entry_bytes_unconsumed);
+ /* Do not consume the hole of a sparse file. */
+ request = 0;
+ for (p = tar->sparse_list; p != NULL; p = p->next) {
+ if (!p->hole) {
+ if (p->remaining >= INT64_MAX - request) {
+ return ARCHIVE_FATAL;
+ }
+ request += p->remaining;
+ }
+ }
+ if (request > tar->entry_bytes_remaining)
+ request = tar->entry_bytes_remaining;
+ request += tar->entry_padding + tar->entry_bytes_unconsumed;
+
+ bytes_skipped = __archive_read_consume(a, request);
if (bytes_skipped < 0)
return (ARCHIVE_FATAL);
@@ -619,36 +699,50 @@ tar_read_header(struct archive_read *a, struct tar *tar,
const struct archive_entry_header_ustar *header;
const struct archive_entry_header_gnutar *gnuheader;
- tar_flush_unconsumed(a, unconsumed);
+ /* Loop until we find a workable header record. */
+ for (;;) {
+ tar_flush_unconsumed(a, unconsumed);
- /* Read 512-byte header record */
- h = __archive_read_ahead(a, 512, &bytes);
- if (bytes < 0)
- return ((int)bytes);
- if (bytes == 0) { /* EOF at a block boundary. */
- /* Some writers do omit the block of nulls. <sigh> */
- return (ARCHIVE_EOF);
- }
- if (bytes < 512) { /* Short block at EOF; this is bad. */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated tar archive");
- return (ARCHIVE_FATAL);
- }
- *unconsumed = 512;
+ /* Read 512-byte header record */
+ h = __archive_read_ahead(a, 512, &bytes);
+ if (bytes < 0)
+ return ((int)bytes);
+ if (bytes == 0) { /* EOF at a block boundary. */
+ /* Some writers do omit the block of nulls. <sigh> */
+ return (ARCHIVE_EOF);
+ }
+ if (bytes < 512) { /* Short block at EOF; this is bad. */
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated tar archive");
+ return (ARCHIVE_FATAL);
+ }
+ *unconsumed = 512;
- /* Check for end-of-archive mark. */
- if (h[0] == 0 && archive_block_is_null(h)) {
- /* Try to consume a second all-null record, as well. */
- tar_flush_unconsumed(a, unconsumed);
- h = __archive_read_ahead(a, 512, NULL);
- if (h != NULL)
- __archive_read_consume(a, 512);
- archive_clear_error(&a->archive);
+ /* Header is workable if it's not an end-of-archive mark. */
+ if (h[0] != 0 || !archive_block_is_null(h))
+ break;
+
+ /* Ensure format is set for archives with only null blocks. */
if (a->archive.archive_format_name == NULL) {
a->archive.archive_format = ARCHIVE_FORMAT_TAR;
a->archive.archive_format_name = "tar";
}
- return (ARCHIVE_EOF);
+
+ if (!tar->read_concatenated_archives) {
+ /* Try to consume a second all-null record, as well. */
+ tar_flush_unconsumed(a, unconsumed);
+ h = __archive_read_ahead(a, 512, NULL);
+ if (h != NULL && h[0] == 0 && archive_block_is_null(h))
+ __archive_read_consume(a, 512);
+ archive_clear_error(&a->archive);
+ return (ARCHIVE_EOF);
+ }
+
+ /*
+ * We're reading concatenated archives, ignore this block and
+ * loop to get the next.
+ */
}
/*
@@ -683,6 +777,8 @@ tar_read_header(struct archive_read *a, struct tar *tar,
a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
a->archive.archive_format_name = "POSIX pax interchange format";
err = header_pax_global(a, tar, entry, h, unconsumed);
+ if (err == ARCHIVE_EOF)
+ return (err);
break;
case 'K': /* Long link name (GNU tar, others) */
err = header_longlink(a, tar, entry, h, unconsumed);
@@ -735,9 +831,9 @@ tar_read_header(struct archive_read *a, struct tar *tar,
* extensions for both the AppleDouble extension entry and the
* regular entry.
*/
- /* TODO: Should this be disabled on non-Mac platforms? */
if ((err == ARCHIVE_WARN || err == ARCHIVE_OK) &&
- tar->header_recursion_depth == 0) {
+ tar->header_recursion_depth == 0 &&
+ tar->process_mac_extensions) {
int err2 = read_mac_metadata_blob(a, tar, entry, h, unconsumed);
if (err2 < err)
err = err2;
@@ -753,9 +849,9 @@ tar_read_header(struct archive_read *a, struct tar *tar,
tar->sparse_gnu_pending = 0;
/* Read initial sparse map. */
bytes_read = gnu_sparse_10_read(a, tar, unconsumed);
- tar->entry_bytes_remaining -= bytes_read;
if (bytes_read < 0)
return ((int)bytes_read);
+ tar->entry_bytes_remaining -= bytes_read;
} else {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
@@ -780,12 +876,20 @@ checksum(struct archive_read *a, const void *h)
{
const unsigned char *bytes;
const struct archive_entry_header_ustar *header;
- int check, i, sum;
+ int check, sum;
+ size_t i;
(void)a; /* UNUSED */
bytes = (const unsigned char *)h;
header = (const struct archive_entry_header_ustar *)h;
+ /* Checksum field must hold an octal number */
+ for (i = 0; i < sizeof(header->checksum); ++i) {
+ char c = header->checksum[i];
+ if (c != ' ' && c != '\0' && (c < '0' || c > '7'))
+ return 0;
+ }
+
/*
* Test the checksum. Note that POSIX specifies _unsigned_
* bytes for this calculation.
@@ -842,7 +946,7 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar,
{
const struct archive_entry_header_ustar *header;
size_t size;
- int err;
+ int err, acl_type;
int64_t type;
char *acl, *p;
@@ -887,11 +991,12 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar,
switch ((int)type & ~0777777) {
case 01000000:
/* POSIX.1e ACL */
+ acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
break;
case 03000000:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Solaris NFSv4 ACLs not supported");
- return (ARCHIVE_WARN);
+ /* NFSv4 ACL */
+ acl_type = ARCHIVE_ENTRY_ACL_TYPE_NFS4;
+ break;
default:
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Malformed Solaris ACL attribute (unsupported type %o)",
@@ -920,8 +1025,8 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar,
return (ARCHIVE_FATAL);
}
archive_strncpy(&(tar->localname), acl, p - acl);
- err = archive_acl_parse_l(archive_entry_acl(entry),
- tar->localname.s, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, tar->sconv_acl);
+ err = archive_acl_from_text_l(archive_entry_acl(entry),
+ tar->localname.s, acl_type, tar->sconv_acl);
if (err != ARCHIVE_OK) {
if (errno == ENOMEM) {
archive_set_error(&a->archive, ENOMEM,
@@ -1080,8 +1185,15 @@ header_common(struct archive_read *a, struct tar *tar,
if (tar->entry_bytes_remaining < 0) {
tar->entry_bytes_remaining = 0;
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Tar entry has negative size?");
- err = ARCHIVE_WARN;
+ "Tar entry has negative size");
+ return (ARCHIVE_FATAL);
+ }
+ if (tar->entry_bytes_remaining == INT64_MAX) {
+ /* Note: tar_atol returns INT64_MAX on overflow */
+ tar->entry_bytes_remaining = 0;
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Tar entry size overflow");
+ return (ARCHIVE_FATAL);
}
tar->realsize = tar->entry_bytes_remaining;
archive_entry_set_size(entry, tar->entry_bytes_remaining);
@@ -1216,6 +1328,14 @@ header_common(struct archive_read *a, struct tar *tar,
* sparse information in the extended area.
*/
/* FALLTHROUGH */
+ case '0':
+ /*
+ * Enable sparse file "read" support only for regular
+ * files and explicit GNU sparse files. However, we
+ * don't allow non-standard file types to be sparse.
+ */
+ tar->sparse_allowed = 1;
+ /* FALLTHROUGH */
default: /* Regular file and non-standard types */
/*
* Per POSIX: non-recognized types should always be
@@ -1277,7 +1397,7 @@ read_mac_metadata_blob(struct archive_read *a, struct tar *tar,
if (wp[0] == '/' && wp[1] != L'\0')
wname = wp + 1;
}
- /*
+ /*
* If last path element starts with "._", then
* this is a Mac extension.
*/
@@ -1292,7 +1412,7 @@ read_mac_metadata_blob(struct archive_read *a, struct tar *tar,
if (p[0] == '/' && p[1] != '\0')
name = p + 1;
}
- /*
+ /*
* If last path element starts with "._", then
* this is a Mac extension.
*/
@@ -1367,7 +1487,7 @@ header_pax_extensions(struct archive_read *a, struct tar *tar,
* and then skip any fields in the standard header that were
* defined in the pax header.
*/
- err2 = pax_header(a, tar, entry, tar->pax_header.s);
+ err2 = pax_header(a, tar, entry, &tar->pax_header);
err = err_combine(err, err2);
tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
return (err);
@@ -1448,16 +1568,17 @@ header_ustar(struct archive_read *a, struct tar *tar,
*/
static int
pax_header(struct archive_read *a, struct tar *tar,
- struct archive_entry *entry, char *attr)
+ struct archive_entry *entry, struct archive_string *in_as)
{
- size_t attr_length, l, line_length;
+ size_t attr_length, l, line_length, value_length;
char *p;
char *key, *value;
struct archive_string *as;
struct archive_string_conv *sconv;
int err, err2;
+ char *attr = in_as->s;
- attr_length = strlen(attr);
+ attr_length = in_as->length;
tar->pax_hdrcharset_binary = 0;
archive_string_empty(&(tar->entry_gname));
archive_string_empty(&(tar->entry_linkpath));
@@ -1522,11 +1643,13 @@ pax_header(struct archive_read *a, struct tar *tar,
}
*p = '\0';
- /* Identify null-terminated 'value' portion. */
value = p + 1;
+ /* Some values may be binary data */
+ value_length = attr + line_length - 1 - value;
+
/* Identify this attribute and set it in the entry. */
- err2 = pax_attribute(a, tar, entry, key, value);
+ err2 = pax_attribute(a, tar, entry, key, value, value_length);
if (err2 == ARCHIVE_FATAL)
return (err2);
err = err_combine(err, err2);
@@ -1616,7 +1739,7 @@ pax_header(struct archive_read *a, struct tar *tar,
static int
pax_attribute_xattr(struct archive_entry *entry,
- char *name, char *value)
+ const char *name, const char *value)
{
char *name_decoded;
void *value_decoded;
@@ -1647,6 +1770,66 @@ pax_attribute_xattr(struct archive_entry *entry,
return 0;
}
+static int
+pax_attribute_schily_xattr(struct archive_entry *entry,
+ const char *name, const char *value, size_t value_length)
+{
+ if (strlen(name) < 14 || (memcmp(name, "SCHILY.xattr.", 13)) != 0)
+ return 1;
+
+ name += 13;
+
+ archive_entry_xattr_add_entry(entry, name, value, value_length);
+
+ return 0;
+}
+
+static int
+pax_attribute_acl(struct archive_read *a, struct tar *tar,
+ struct archive_entry *entry, const char *value, int type)
+{
+ int r;
+ const char* errstr;
+
+ switch (type) {
+ case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
+ errstr = "SCHILY.acl.access";
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
+ errstr = "SCHILY.acl.default";
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_NFS4:
+ errstr = "SCHILY.acl.ace";
+ break;
+ default:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Unknown ACL type: %d", type);
+ return(ARCHIVE_FATAL);
+ }
+
+ if (tar->sconv_acl == NULL) {
+ tar->sconv_acl =
+ archive_string_conversion_from_charset(
+ &(a->archive), "UTF-8", 1);
+ if (tar->sconv_acl == NULL)
+ return (ARCHIVE_FATAL);
+ }
+
+ r = archive_acl_from_text_l(archive_entry_acl(entry), value, type,
+ tar->sconv_acl);
+ if (r != ARCHIVE_OK) {
+ if (r == ARCHIVE_FATAL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "%s %s", "Can't allocate memory for ",
+ errstr);
+ return (r);
+ }
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC, "%s %s", "Parse error: ", errstr);
+ }
+ return (r);
+}
+
/*
* Parse a single key=value attribute. key/value pointers are
* assumed to point into reasonably long-lived storage.
@@ -1662,7 +1845,7 @@ pax_attribute_xattr(struct archive_entry *entry,
*/
static int
pax_attribute(struct archive_read *a, struct tar *tar,
- struct archive_entry *entry, char *key, char *value)
+ struct archive_entry *entry, const char *key, const char *value, size_t value_length)
{
int64_t s;
long n;
@@ -1673,6 +1856,14 @@ pax_attribute(struct archive_read *a, struct tar *tar,
* NULL pointer to strlen(). */
switch (key[0]) {
case 'G':
+ /* Reject GNU.sparse.* headers on non-regular files. */
+ if (strncmp(key, "GNU.sparse", 10) == 0 &&
+ !tar->sparse_allowed) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Non-regular file cannot be sparse");
+ return (ARCHIVE_FATAL);
+ }
+
/* GNU "0.0" sparse pax format. */
if (strcmp(key, "GNU.sparse.numblocks") == 0) {
tar->sparse_offset = -1;
@@ -1705,6 +1896,7 @@ pax_attribute(struct archive_read *a, struct tar *tar,
if (strcmp(key, "GNU.sparse.size") == 0) {
tar->realsize = tar_atol10(value, strlen(value));
archive_entry_set_size(entry, tar->realsize);
+ tar->realsize_override = 1;
}
/* GNU "0.1" sparse pax format. */
@@ -1736,6 +1928,7 @@ pax_attribute(struct archive_read *a, struct tar *tar,
if (strcmp(key, "GNU.sparse.realsize") == 0) {
tar->realsize = tar_atol10(value, strlen(value));
archive_entry_set_size(entry, tar->realsize);
+ tar->realsize_override = 1;
}
break;
case 'L':
@@ -1755,53 +1948,20 @@ pax_attribute(struct archive_read *a, struct tar *tar,
case 'S':
/* We support some keys used by the "star" archiver */
if (strcmp(key, "SCHILY.acl.access") == 0) {
- if (tar->sconv_acl == NULL) {
- tar->sconv_acl =
- archive_string_conversion_from_charset(
- &(a->archive), "UTF-8", 1);
- if (tar->sconv_acl == NULL)
- return (ARCHIVE_FATAL);
- }
-
- r = archive_acl_parse_l(archive_entry_acl(entry),
- value, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
- tar->sconv_acl);
- if (r != ARCHIVE_OK) {
- err = r;
- if (err == ARCHIVE_FATAL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for "
- "SCHILY.acl.access");
- return (err);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Parse error: SCHILY.acl.access");
- }
+ r = pax_attribute_acl(a, tar, entry, value,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+ if (r == ARCHIVE_FATAL)
+ return (r);
} else if (strcmp(key, "SCHILY.acl.default") == 0) {
- if (tar->sconv_acl == NULL) {
- tar->sconv_acl =
- archive_string_conversion_from_charset(
- &(a->archive), "UTF-8", 1);
- if (tar->sconv_acl == NULL)
- return (ARCHIVE_FATAL);
- }
-
- r = archive_acl_parse_l(archive_entry_acl(entry),
- value, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT,
- tar->sconv_acl);
- if (r != ARCHIVE_OK) {
- err = r;
- if (err == ARCHIVE_FATAL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for "
- "SCHILY.acl.default");
- return (err);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Parse error: SCHILY.acl.default");
- }
+ r = pax_attribute_acl(a, tar, entry, value,
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
+ if (r == ARCHIVE_FATAL)
+ return (r);
+ } else if (strcmp(key, "SCHILY.acl.ace") == 0) {
+ r = pax_attribute_acl(a, tar, entry, value,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4);
+ if (r == ARCHIVE_FATAL)
+ return (r);
} else if (strcmp(key, "SCHILY.devmajor") == 0) {
archive_entry_set_rdevmajor(entry,
(dev_t)tar_atol10(value, strlen(value)));
@@ -1821,7 +1981,11 @@ pax_attribute(struct archive_read *a, struct tar *tar,
tar_atol10(value, strlen(value)));
} else if (strcmp(key, "SCHILY.realsize") == 0) {
tar->realsize = tar_atol10(value, strlen(value));
+ tar->realsize_override = 1;
archive_entry_set_size(entry, tar->realsize);
+ } else if (strncmp(key, "SCHILY.xattr.", 13) == 0) {
+ pax_attribute_schily_xattr(entry, key, value,
+ value_length);
} else if (strcmp(key, "SUN.holesdata") == 0) {
/* A Solaris extension for sparse. */
r = solaris_sparse_parse(a, tar, entry, value);
@@ -1896,14 +2060,12 @@ pax_attribute(struct archive_read *a, struct tar *tar,
tar->entry_bytes_remaining
= tar_atol10(value, strlen(value));
/*
- * But, "size" is not necessarily the size of
- * the file on disk; if this is a sparse file,
- * the disk size may have already been set from
- * GNU.sparse.realsize or GNU.sparse.size or
- * an old GNU header field or SCHILY.realsize
- * or ....
+ * The "size" pax header keyword always overrides the
+ * "size" field in the tar header.
+ * GNU.sparse.realsize, GNU.sparse.size and
+ * SCHILY.realsize override this value.
*/
- if (tar->realsize < 0) {
+ if (!tar->realsize_override) {
archive_entry_set_size(entry,
tar->entry_bytes_remaining);
tar->realsize
@@ -2047,6 +2209,7 @@ header_gnutar(struct archive_read *a, struct tar *tar,
tar->realsize
= tar_atol(header->realsize, sizeof(header->realsize));
archive_entry_set_size(entry, tar->realsize);
+ tar->realsize_override = 1;
}
if (header->sparse[0].offset[0] != 0) {
@@ -2068,17 +2231,20 @@ gnu_add_sparse_entry(struct archive_read *a, struct tar *tar,
{
struct sparse_block *p;
- p = (struct sparse_block *)malloc(sizeof(*p));
+ p = (struct sparse_block *)calloc(1, sizeof(*p));
if (p == NULL) {
archive_set_error(&a->archive, ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
- memset(p, 0, sizeof(*p));
if (tar->sparse_last != NULL)
tar->sparse_last->next = p;
else
tar->sparse_list = p;
tar->sparse_last = p;
+ if (remaining < 0 || offset < 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Malformed sparse map data");
+ return (ARCHIVE_FATAL);
+ }
p->offset = offset;
p->remaining = remaining;
return (ARCHIVE_OK);
@@ -2325,6 +2491,9 @@ gnu_sparse_10_read(struct archive_read *a, struct tar *tar, size_t *unconsumed)
tar_flush_unconsumed(a, unconsumed);
bytes_read = (ssize_t)(tar->entry_bytes_remaining - remaining);
to_skip = 0x1ff & -bytes_read;
+ /* Fail if tar->entry_bytes_remaing would get negative */
+ if (to_skip > remaining)
+ return (ARCHIVE_FATAL);
if (to_skip != __archive_read_consume(a, to_skip))
return (ARCHIVE_FATAL);
return ((ssize_t)(bytes_read + to_skip));
@@ -2412,14 +2581,15 @@ tar_atol(const char *p, size_t char_cnt)
static int64_t
tar_atol_base_n(const char *p, size_t char_cnt, int base)
{
- int64_t l, limit, last_digit_limit;
+ int64_t l, maxval, limit, last_digit_limit;
int digit, sign;
+ maxval = INT64_MAX;
limit = INT64_MAX / base;
last_digit_limit = INT64_MAX % base;
/* the pointer will not be dereferenced if char_cnt is zero
- * due to the way the && operator is evaulated.
+ * due to the way the && operator is evaluated.
*/
while (char_cnt != 0 && (*p == ' ' || *p == '\t')) {
p++;
@@ -2431,6 +2601,10 @@ tar_atol_base_n(const char *p, size_t char_cnt, int base)
sign = -1;
p++;
char_cnt--;
+
+ maxval = INT64_MIN;
+ limit = -(INT64_MIN / base);
+ last_digit_limit = INT64_MIN % base;
}
l = 0;
@@ -2438,8 +2612,7 @@ tar_atol_base_n(const char *p, size_t char_cnt, int base)
digit = *p - '0';
while (digit >= 0 && digit < base && char_cnt != 0) {
if (l>limit || (l == limit && digit > last_digit_limit)) {
- l = INT64_MAX; /* Truncate on overflow. */
- break;
+ return maxval; /* Truncate on overflow. */
}
l = (l * base) + digit;
digit = *++p - '0';
@@ -2462,36 +2635,56 @@ tar_atol10(const char *p, size_t char_cnt)
}
/*
- * Parse a base-256 integer. This is just a straight signed binary
- * value in big-endian order, except that the high-order bit is
- * ignored.
+ * Parse a base-256 integer. This is just a variable-length
+ * twos-complement signed binary value in big-endian order, except
+ * that the high-order bit is ignored. The values here can be up to
+ * 12 bytes, so we need to be careful about overflowing 64-bit
+ * (8-byte) integers.
+ *
+ * This code unashamedly assumes that the local machine uses 8-bit
+ * bytes and twos-complement arithmetic.
*/
static int64_t
tar_atol256(const char *_p, size_t char_cnt)
{
- int64_t l, upper_limit, lower_limit;
+ uint64_t l;
const unsigned char *p = (const unsigned char *)_p;
+ unsigned char c, neg;
+
+ /* Extend 7-bit 2s-comp to 8-bit 2s-comp, decide sign. */
+ c = *p;
+ if (c & 0x40) {
+ neg = 0xff;
+ c |= 0x80;
+ l = ~ARCHIVE_LITERAL_ULL(0);
+ } else {
+ neg = 0;
+ c &= 0x7f;
+ l = 0;
+ }
- upper_limit = INT64_MAX / 256;
- lower_limit = INT64_MIN / 256;
+ /* If more than 8 bytes, check that we can ignore
+ * high-order bits without overflow. */
+ while (char_cnt > sizeof(int64_t)) {
+ --char_cnt;
+ if (c != neg)
+ return neg ? INT64_MIN : INT64_MAX;
+ c = *++p;
+ }
- /* Pad with 1 or 0 bits, depending on sign. */
- if ((0x40 & *p) == 0x40)
- l = (int64_t)-1;
- else
- l = 0;
- l = (l << 6) | (0x3f & *p++);
+ /* c is first byte that fits; if sign mismatch, return overflow */
+ if ((c ^ neg) & 0x80) {
+ return neg ? INT64_MIN : INT64_MAX;
+ }
+
+ /* Accumulate remaining bytes. */
while (--char_cnt > 0) {
- if (l > upper_limit) {
- l = INT64_MAX; /* Truncate on overflow */
- break;
- } else if (l < lower_limit) {
- l = INT64_MIN;
- break;
- }
- l = (l << 8) | (0xff & (int64_t)*p++);
+ l = (l << 8) | c;
+ c = *++p;
}
- return (l);
+ l = (l << 8) | c;
+ /* Return signed twos-complement value. */
+ return (int64_t)(l);
}
/*
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_format_xar.c b/3rdparty/libarchive/libarchive/archive_read_support_format_xar.c
deleted file mode 100644
index 780e749d..00000000
--- a/3rdparty/libarchive/libarchive/archive_read_support_format_xar.c
+++ /dev/null
@@ -1,3331 +0,0 @@
-/*-
- * Copyright (c) 2009 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"
-__FBSDID("$FreeBSD$");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#if HAVE_LIBXML_XMLREADER_H
-#include <libxml/xmlreader.h>
-#elif HAVE_BSDXML_H
-#include <bsdxml.h>
-#elif HAVE_EXPAT_H
-#include <expat.h>
-#endif
-#ifdef HAVE_BZLIB_H
-#include <bzlib.h>
-#endif
-#if HAVE_LZMA_H
-#include <lzma.h>
-#elif HAVE_LZMADEC_H
-#include <lzmadec.h>
-#endif
-#ifdef HAVE_ZLIB_H
-#include <zlib.h>
-#endif
-
-#include "archive.h"
-#include "archive_crypto_private.h"
-#include "archive_endian.h"
-#include "archive_entry.h"
-#include "archive_entry_locale.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-
-#if (!defined(HAVE_LIBXML_XMLREADER_H) && \
- !defined(HAVE_BSDXML_H) && !defined(HAVE_EXPAT_H)) ||\
- !defined(HAVE_ZLIB_H) || \
- !defined(ARCHIVE_HAS_MD5) || !defined(ARCHIVE_HAS_SHA1)
-/*
- * xar needs several external libraries.
- * o libxml2 or expat --- XML parser
- * o openssl or MD5/SHA1 hash function
- * o zlib
- * o bzlib2 (option)
- * o liblzma (option)
- */
-int
-archive_read_support_format_xar(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- archive_check_magic(_a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_NEW, "archive_read_support_format_xar");
-
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Xar not supported on this platform");
- return (ARCHIVE_WARN);
-}
-
-#else /* Support xar format */
-
-/* #define DEBUG 1 */
-/* #define DEBUG_PRINT_TOC 1 */
-#if DEBUG_PRINT_TOC
-#define PRINT_TOC(d, outbytes) do { \
- unsigned char *x = (unsigned char *)(uintptr_t)d; \
- unsigned char c = x[outbytes-1]; \
- x[outbytes - 1] = 0; \
- fprintf(stderr, "%s", x); \
- fprintf(stderr, "%c", c); \
- x[outbytes - 1] = c; \
-} while (0)
-#else
-#define PRINT_TOC(d, outbytes)
-#endif
-
-#define HEADER_MAGIC 0x78617221
-#define HEADER_SIZE 28
-#define HEADER_VERSION 1
-#define CKSUM_NONE 0
-#define CKSUM_SHA1 1
-#define CKSUM_MD5 2
-
-#define MD5_SIZE 16
-#define SHA1_SIZE 20
-#define MAX_SUM_SIZE 20
-
-enum enctype {
- NONE,
- GZIP,
- BZIP2,
- LZMA,
- XZ,
-};
-
-struct chksumval {
- int alg;
- size_t len;
- unsigned char val[MAX_SUM_SIZE];
-};
-
-struct chksumwork {
- int alg;
-#ifdef ARCHIVE_HAS_MD5
- archive_md5_ctx md5ctx;
-#endif
-#ifdef ARCHIVE_HAS_SHA1
- archive_sha1_ctx sha1ctx;
-#endif
-};
-
-struct xattr {
- struct xattr *next;
- struct archive_string name;
- uint64_t id;
- uint64_t length;
- uint64_t offset;
- uint64_t size;
- enum enctype encoding;
- struct chksumval a_sum;
- struct chksumval e_sum;
- struct archive_string fstype;
-};
-
-struct xar_file {
- struct xar_file *next;
- struct xar_file *hdnext;
- struct xar_file *parent;
- int subdirs;
-
- unsigned int has;
-#define HAS_DATA 0x00001
-#define HAS_PATHNAME 0x00002
-#define HAS_SYMLINK 0x00004
-#define HAS_TIME 0x00008
-#define HAS_UID 0x00010
-#define HAS_GID 0x00020
-#define HAS_MODE 0x00040
-#define HAS_TYPE 0x00080
-#define HAS_DEV 0x00100
-#define HAS_DEVMAJOR 0x00200
-#define HAS_DEVMINOR 0x00400
-#define HAS_INO 0x00800
-#define HAS_FFLAGS 0x01000
-#define HAS_XATTR 0x02000
-#define HAS_ACL 0x04000
-
- uint64_t id;
- uint64_t length;
- uint64_t offset;
- uint64_t size;
- enum enctype encoding;
- struct chksumval a_sum;
- struct chksumval e_sum;
- struct archive_string pathname;
- struct archive_string symlink;
- time_t ctime;
- time_t mtime;
- time_t atime;
- struct archive_string uname;
- int64_t uid;
- struct archive_string gname;
- int64_t gid;
- mode_t mode;
- dev_t dev;
- dev_t devmajor;
- dev_t devminor;
- int64_t ino64;
- struct archive_string fflags_text;
- unsigned int link;
- unsigned int nlink;
- struct archive_string hardlink;
- struct xattr *xattr_list;
-};
-
-struct hdlink {
- struct hdlink *next;
-
- unsigned int id;
- int cnt;
- struct xar_file *files;
-};
-
-struct heap_queue {
- struct xar_file **files;
- int allocated;
- int used;
-};
-
-enum xmlstatus {
- INIT,
- XAR,
- TOC,
- TOC_CREATION_TIME,
- TOC_CHECKSUM,
- TOC_CHECKSUM_OFFSET,
- TOC_CHECKSUM_SIZE,
- TOC_FILE,
- FILE_DATA,
- FILE_DATA_LENGTH,
- FILE_DATA_OFFSET,
- FILE_DATA_SIZE,
- FILE_DATA_ENCODING,
- FILE_DATA_A_CHECKSUM,
- FILE_DATA_E_CHECKSUM,
- FILE_DATA_CONTENT,
- FILE_EA,
- FILE_EA_LENGTH,
- FILE_EA_OFFSET,
- FILE_EA_SIZE,
- FILE_EA_ENCODING,
- FILE_EA_A_CHECKSUM,
- FILE_EA_E_CHECKSUM,
- FILE_EA_NAME,
- FILE_EA_FSTYPE,
- FILE_CTIME,
- FILE_MTIME,
- FILE_ATIME,
- FILE_GROUP,
- FILE_GID,
- FILE_USER,
- FILE_UID,
- FILE_MODE,
- FILE_DEVICE,
- FILE_DEVICE_MAJOR,
- FILE_DEVICE_MINOR,
- FILE_DEVICENO,
- FILE_INODE,
- FILE_LINK,
- FILE_TYPE,
- FILE_NAME,
- FILE_ACL,
- FILE_ACL_DEFAULT,
- FILE_ACL_ACCESS,
- FILE_ACL_APPLEEXTENDED,
- /* BSD file flags. */
- FILE_FLAGS,
- FILE_FLAGS_USER_NODUMP,
- FILE_FLAGS_USER_IMMUTABLE,
- FILE_FLAGS_USER_APPEND,
- FILE_FLAGS_USER_OPAQUE,
- FILE_FLAGS_USER_NOUNLINK,
- FILE_FLAGS_SYS_ARCHIVED,
- FILE_FLAGS_SYS_IMMUTABLE,
- FILE_FLAGS_SYS_APPEND,
- FILE_FLAGS_SYS_NOUNLINK,
- FILE_FLAGS_SYS_SNAPSHOT,
- /* Linux file flags. */
- FILE_EXT2,
- FILE_EXT2_SecureDeletion,
- FILE_EXT2_Undelete,
- FILE_EXT2_Compress,
- FILE_EXT2_Synchronous,
- FILE_EXT2_Immutable,
- FILE_EXT2_AppendOnly,
- FILE_EXT2_NoDump,
- FILE_EXT2_NoAtime,
- FILE_EXT2_CompDirty,
- FILE_EXT2_CompBlock,
- FILE_EXT2_NoCompBlock,
- FILE_EXT2_CompError,
- FILE_EXT2_BTree,
- FILE_EXT2_HashIndexed,
- FILE_EXT2_iMagic,
- FILE_EXT2_Journaled,
- FILE_EXT2_NoTail,
- FILE_EXT2_DirSync,
- FILE_EXT2_TopDir,
- FILE_EXT2_Reserved,
- UNKNOWN,
-};
-
-struct unknown_tag {
- struct unknown_tag *next;
- struct archive_string name;
-};
-
-struct xar {
- uint64_t offset; /* Current position in the file. */
- int64_t total;
- uint64_t h_base;
- int end_of_file;
-#define OUTBUFF_SIZE (1024 * 64)
- unsigned char *outbuff;
-
- enum xmlstatus xmlsts;
- enum xmlstatus xmlsts_unknown;
- struct unknown_tag *unknowntags;
- int base64text;
-
- /*
- * TOC
- */
- uint64_t toc_remaining;
- uint64_t toc_total;
- uint64_t toc_chksum_offset;
- uint64_t toc_chksum_size;
-
- /*
- * For Decoding data.
- */
- enum enctype rd_encoding;
- z_stream stream;
- int stream_valid;
-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
- bz_stream bzstream;
- int bzstream_valid;
-#endif
-#if HAVE_LZMA_H && HAVE_LIBLZMA
- lzma_stream lzstream;
- int lzstream_valid;
-#elif HAVE_LZMADEC_H && HAVE_LIBLZMADEC
- lzmadec_stream lzstream;
- int lzstream_valid;
-#endif
- /*
- * For Checksum data.
- */
- struct chksumwork a_sumwrk;
- struct chksumwork e_sumwrk;
-
- struct xar_file *file; /* current reading file. */
- struct xattr *xattr; /* current reading extended attribute. */
- struct heap_queue file_queue;
- struct xar_file *hdlink_orgs;
- struct hdlink *hdlink_list;
-
- int entry_init;
- uint64_t entry_total;
- uint64_t entry_remaining;
- size_t entry_unconsumed;
- uint64_t entry_size;
- enum enctype entry_encoding;
- struct chksumval entry_a_sum;
- struct chksumval entry_e_sum;
-
- struct archive_string_conv *sconv;
-};
-
-struct xmlattr {
- struct xmlattr *next;
- char *name;
- char *value;
-};
-
-struct xmlattr_list {
- struct xmlattr *first;
- struct xmlattr **last;
-};
-
-static int xar_bid(struct archive_read *, int);
-static int xar_read_header(struct archive_read *,
- struct archive_entry *);
-static int xar_read_data(struct archive_read *,
- const void **, size_t *, int64_t *);
-static int xar_read_data_skip(struct archive_read *);
-static int xar_cleanup(struct archive_read *);
-static int move_reading_point(struct archive_read *, uint64_t);
-static int rd_contents_init(struct archive_read *,
- enum enctype, int, int);
-static int rd_contents(struct archive_read *, const void **,
- size_t *, size_t *, uint64_t);
-static uint64_t atol10(const char *, size_t);
-static int64_t atol8(const char *, size_t);
-static size_t atohex(unsigned char *, size_t, const char *, size_t);
-static time_t parse_time(const char *p, size_t n);
-static int heap_add_entry(struct archive_read *a,
- struct heap_queue *, struct xar_file *);
-static struct xar_file *heap_get_entry(struct heap_queue *);
-static int add_link(struct archive_read *,
- struct xar *, struct xar_file *);
-static void checksum_init(struct archive_read *, int, int);
-static void checksum_update(struct archive_read *, const void *,
- size_t, const void *, size_t);
-static int checksum_final(struct archive_read *, const void *,
- size_t, const void *, size_t);
-static int decompression_init(struct archive_read *, enum enctype);
-static int decompress(struct archive_read *, const void **,
- size_t *, const void *, size_t *);
-static int decompression_cleanup(struct archive_read *);
-static void xmlattr_cleanup(struct xmlattr_list *);
-static int file_new(struct archive_read *,
- struct xar *, struct xmlattr_list *);
-static void file_free(struct xar_file *);
-static int xattr_new(struct archive_read *,
- struct xar *, struct xmlattr_list *);
-static void xattr_free(struct xattr *);
-static int getencoding(struct xmlattr_list *);
-static int getsumalgorithm(struct xmlattr_list *);
-static int unknowntag_start(struct archive_read *,
- struct xar *, const char *);
-static void unknowntag_end(struct xar *, const char *);
-static int xml_start(struct archive_read *,
- const char *, struct xmlattr_list *);
-static void xml_end(void *, const char *);
-static void xml_data(void *, const char *, int);
-static int xml_parse_file_flags(struct xar *, const char *);
-static int xml_parse_file_ext2(struct xar *, const char *);
-#if defined(HAVE_LIBXML_XMLREADER_H)
-static int xml2_xmlattr_setup(struct archive_read *,
- struct xmlattr_list *, xmlTextReaderPtr);
-static int xml2_read_cb(void *, char *, int);
-static int xml2_close_cb(void *);
-static void xml2_error_hdr(void *, const char *, xmlParserSeverities,
- xmlTextReaderLocatorPtr);
-static int xml2_read_toc(struct archive_read *);
-#elif defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H)
-struct expat_userData {
- int state;
- struct archive_read *archive;
-};
-static int expat_xmlattr_setup(struct archive_read *,
- struct xmlattr_list *, const XML_Char **);
-static void expat_start_cb(void *, const XML_Char *, const XML_Char **);
-static void expat_end_cb(void *, const XML_Char *);
-static void expat_data_cb(void *, const XML_Char *, int);
-static int expat_read_toc(struct archive_read *);
-#endif
-
-int
-archive_read_support_format_xar(struct archive *_a)
-{
- struct xar *xar;
- struct archive_read *a = (struct archive_read *)_a;
- int r;
-
- archive_check_magic(_a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_NEW, "archive_read_support_format_xar");
-
- xar = (struct xar *)calloc(1, sizeof(*xar));
- if (xar == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate xar data");
- return (ARCHIVE_FATAL);
- }
-
- r = __archive_read_register_format(a,
- xar,
- "xar",
- xar_bid,
- NULL,
- xar_read_header,
- xar_read_data,
- xar_read_data_skip,
- NULL,
- xar_cleanup);
- if (r != ARCHIVE_OK)
- free(xar);
- return (r);
-}
-
-static int
-xar_bid(struct archive_read *a, int best_bid)
-{
- const unsigned char *b;
- int bid;
-
- (void)best_bid; /* UNUSED */
-
- b = __archive_read_ahead(a, HEADER_SIZE, NULL);
- if (b == NULL)
- return (-1);
-
- bid = 0;
- /*
- * Verify magic code
- */
- if (archive_be32dec(b) != HEADER_MAGIC)
- return (0);
- bid += 32;
- /*
- * Verify header size
- */
- if (archive_be16dec(b+4) != HEADER_SIZE)
- return (0);
- bid += 16;
- /*
- * Verify header version
- */
- if (archive_be16dec(b+6) != HEADER_VERSION)
- return (0);
- bid += 16;
- /*
- * Verify type of checksum
- */
- switch (archive_be32dec(b+24)) {
- case CKSUM_NONE:
- case CKSUM_SHA1:
- case CKSUM_MD5:
- bid += 32;
- break;
- default:
- return (0);
- }
-
- return (bid);
-}
-
-static int
-read_toc(struct archive_read *a)
-{
- struct xar *xar;
- struct xar_file *file;
- const unsigned char *b;
- uint64_t toc_compressed_size;
- uint64_t toc_uncompressed_size;
- uint32_t toc_chksum_alg;
- ssize_t bytes;
- int r;
-
- xar = (struct xar *)(a->format->data);
-
- /*
- * Read xar header.
- */
- b = __archive_read_ahead(a, HEADER_SIZE, &bytes);
- if (bytes < 0)
- return ((int)bytes);
- if (bytes < HEADER_SIZE) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated archive header");
- return (ARCHIVE_FATAL);
- }
-
- if (archive_be32dec(b) != HEADER_MAGIC) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid header magic");
- return (ARCHIVE_FATAL);
- }
- if (archive_be16dec(b+6) != HEADER_VERSION) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Unsupported header version(%d)",
- archive_be16dec(b+6));
- return (ARCHIVE_FATAL);
- }
- toc_compressed_size = archive_be64dec(b+8);
- xar->toc_remaining = toc_compressed_size;
- toc_uncompressed_size = archive_be64dec(b+16);
- toc_chksum_alg = archive_be32dec(b+24);
- __archive_read_consume(a, HEADER_SIZE);
- xar->offset += HEADER_SIZE;
- xar->toc_total = 0;
-
- /*
- * Read TOC(Table of Contents).
- */
- /* Initialize reading contents. */
- r = move_reading_point(a, HEADER_SIZE);
- if (r != ARCHIVE_OK)
- return (r);
- r = rd_contents_init(a, GZIP, toc_chksum_alg, CKSUM_NONE);
- if (r != ARCHIVE_OK)
- return (r);
-
-#ifdef HAVE_LIBXML_XMLREADER_H
- r = xml2_read_toc(a);
-#elif defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H)
- r = expat_read_toc(a);
-#endif
- if (r != ARCHIVE_OK)
- return (r);
-
- /* Set 'The HEAP' base. */
- xar->h_base = xar->offset;
- if (xar->toc_total != toc_uncompressed_size) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "TOC uncompressed size error");
- return (ARCHIVE_FATAL);
- }
-
- /*
- * Checksum TOC
- */
- if (toc_chksum_alg != CKSUM_NONE) {
- r = move_reading_point(a, xar->toc_chksum_offset);
- if (r != ARCHIVE_OK)
- return (r);
- b = __archive_read_ahead(a,
- (size_t)xar->toc_chksum_size, &bytes);
- if (bytes < 0)
- return ((int)bytes);
- if ((uint64_t)bytes < xar->toc_chksum_size) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated archive file");
- return (ARCHIVE_FATAL);
- }
- r = checksum_final(a, b,
- (size_t)xar->toc_chksum_size, NULL, 0);
- __archive_read_consume(a, xar->toc_chksum_size);
- xar->offset += xar->toc_chksum_size;
- if (r != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
-
- /*
- * Connect hardlinked files.
- */
- for (file = xar->hdlink_orgs; file != NULL; file = file->hdnext) {
- struct hdlink **hdlink;
-
- for (hdlink = &(xar->hdlink_list); *hdlink != NULL;
- hdlink = &((*hdlink)->next)) {
- if ((*hdlink)->id == file->id) {
- struct hdlink *hltmp;
- struct xar_file *f2;
- int nlink = (*hdlink)->cnt + 1;
-
- file->nlink = nlink;
- for (f2 = (*hdlink)->files; f2 != NULL;
- f2 = f2->hdnext) {
- f2->nlink = nlink;
- archive_string_copy(
- &(f2->hardlink), &(file->pathname));
- }
- /* Remove resolved files from hdlist_list. */
- hltmp = *hdlink;
- *hdlink = hltmp->next;
- free(hltmp);
- break;
- }
- }
- }
- a->archive.archive_format = ARCHIVE_FORMAT_XAR;
- a->archive.archive_format_name = "xar";
-
- return (ARCHIVE_OK);
-}
-
-static int
-xar_read_header(struct archive_read *a, struct archive_entry *entry)
-{
- struct xar *xar;
- struct xar_file *file;
- struct xattr *xattr;
- int r;
-
- xar = (struct xar *)(a->format->data);
- r = ARCHIVE_OK;
-
- if (xar->offset == 0) {
- /* Create a character conversion object. */
- if (xar->sconv == NULL) {
- xar->sconv = archive_string_conversion_from_charset(
- &(a->archive), "UTF-8", 1);
- if (xar->sconv == NULL)
- return (ARCHIVE_FATAL);
- }
-
- /* Read TOC. */
- r = read_toc(a);
- if (r != ARCHIVE_OK)
- return (r);
- }
-
- for (;;) {
- file = xar->file = heap_get_entry(&(xar->file_queue));
- if (file == NULL) {
- xar->end_of_file = 1;
- return (ARCHIVE_EOF);
- }
- if ((file->mode & AE_IFMT) != AE_IFDIR)
- break;
- if (file->has != (HAS_PATHNAME | HAS_TYPE))
- break;
- /*
- * If a file type is a directory and it does not have
- * any metadata, do not export.
- */
- file_free(file);
- }
- archive_entry_set_atime(entry, file->atime, 0);
- archive_entry_set_ctime(entry, file->ctime, 0);
- archive_entry_set_mtime(entry, file->mtime, 0);
- archive_entry_set_gid(entry, file->gid);
- if (file->gname.length > 0 &&
- archive_entry_copy_gname_l(entry, file->gname.s,
- archive_strlen(&(file->gname)), xar->sconv) != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Gname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Gname cannot be converted from %s to current locale.",
- archive_string_conversion_charset_name(xar->sconv));
- r = ARCHIVE_WARN;
- }
- archive_entry_set_uid(entry, file->uid);
- if (file->uname.length > 0 &&
- archive_entry_copy_uname_l(entry, file->uname.s,
- archive_strlen(&(file->uname)), xar->sconv) != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Uname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Uname cannot be converted from %s to current locale.",
- archive_string_conversion_charset_name(xar->sconv));
- r = ARCHIVE_WARN;
- }
- archive_entry_set_mode(entry, file->mode);
- if (archive_entry_copy_pathname_l(entry, file->pathname.s,
- archive_strlen(&(file->pathname)), xar->sconv) != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Pathname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Pathname cannot be converted from %s to current locale.",
- archive_string_conversion_charset_name(xar->sconv));
- r = ARCHIVE_WARN;
- }
-
-
- if (file->symlink.length > 0 &&
- archive_entry_copy_symlink_l(entry, file->symlink.s,
- archive_strlen(&(file->symlink)), xar->sconv) != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Linkname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Linkname cannot be converted from %s to current locale.",
- archive_string_conversion_charset_name(xar->sconv));
- r = ARCHIVE_WARN;
- }
- /* Set proper nlink. */
- if ((file->mode & AE_IFMT) == AE_IFDIR)
- archive_entry_set_nlink(entry, file->subdirs + 2);
- else
- archive_entry_set_nlink(entry, file->nlink);
- archive_entry_set_size(entry, file->size);
- if (archive_strlen(&(file->hardlink)) > 0)
- archive_entry_set_hardlink(entry, file->hardlink.s);
- archive_entry_set_ino64(entry, file->ino64);
- if (file->has & HAS_DEV)
- archive_entry_set_dev(entry, file->dev);
- if (file->has & HAS_DEVMAJOR)
- archive_entry_set_devmajor(entry, file->devmajor);
- if (file->has & HAS_DEVMINOR)
- archive_entry_set_devminor(entry, file->devminor);
- if (archive_strlen(&(file->fflags_text)) > 0)
- archive_entry_copy_fflags_text(entry, file->fflags_text.s);
-
- xar->entry_init = 1;
- xar->entry_total = 0;
- xar->entry_remaining = file->length;
- xar->entry_size = file->size;
- xar->entry_encoding = file->encoding;
- xar->entry_a_sum = file->a_sum;
- xar->entry_e_sum = file->e_sum;
- /*
- * Read extended attributes.
- */
- xattr = file->xattr_list;
- while (xattr != NULL) {
- const void *d;
- size_t outbytes, used;
-
- r = move_reading_point(a, xattr->offset);
- if (r != ARCHIVE_OK)
- break;
- r = rd_contents_init(a, xattr->encoding,
- xattr->a_sum.alg, xattr->e_sum.alg);
- if (r != ARCHIVE_OK)
- break;
- d = NULL;
- r = rd_contents(a, &d, &outbytes, &used, xattr->length);
- if (r != ARCHIVE_OK)
- break;
- if (outbytes != xattr->size) {
- archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
- "Decompressed size error");
- r = ARCHIVE_FATAL;
- break;
- }
- r = checksum_final(a,
- xattr->a_sum.val, xattr->a_sum.len,
- xattr->e_sum.val, xattr->e_sum.len);
- if (r != ARCHIVE_OK)
- break;
- archive_entry_xattr_add_entry(entry,
- xattr->name.s, d, outbytes);
- xattr = xattr->next;
- }
- if (r != ARCHIVE_OK) {
- file_free(file);
- return (r);
- }
-
- if (xar->entry_remaining > 0)
- /* Move reading point to the beginning of current
- * file contents. */
- r = move_reading_point(a, file->offset);
- else
- r = ARCHIVE_OK;
-
- file_free(file);
- return (r);
-}
-
-static int
-xar_read_data(struct archive_read *a,
- const void **buff, size_t *size, int64_t *offset)
-{
- struct xar *xar;
- size_t used;
- int r;
-
- xar = (struct xar *)(a->format->data);
-
- if (xar->entry_unconsumed) {
- __archive_read_consume(a, xar->entry_unconsumed);
- xar->entry_unconsumed = 0;
- }
-
- if (xar->end_of_file || xar->entry_remaining <= 0) {
- r = ARCHIVE_EOF;
- goto abort_read_data;
- }
-
- if (xar->entry_init) {
- r = rd_contents_init(a, xar->entry_encoding,
- xar->entry_a_sum.alg, xar->entry_e_sum.alg);
- if (r != ARCHIVE_OK) {
- xar->entry_remaining = 0;
- return (r);
- }
- xar->entry_init = 0;
- }
-
- *buff = NULL;
- r = rd_contents(a, buff, size, &used, xar->entry_remaining);
- if (r != ARCHIVE_OK)
- goto abort_read_data;
-
- *offset = xar->entry_total;
- xar->entry_total += *size;
- xar->total += *size;
- xar->offset += used;
- xar->entry_remaining -= used;
- xar->entry_unconsumed = used;
-
- if (xar->entry_remaining == 0) {
- if (xar->entry_total != xar->entry_size) {
- archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
- "Decompressed size error");
- r = ARCHIVE_FATAL;
- goto abort_read_data;
- }
- r = checksum_final(a,
- xar->entry_a_sum.val, xar->entry_a_sum.len,
- xar->entry_e_sum.val, xar->entry_e_sum.len);
- if (r != ARCHIVE_OK)
- goto abort_read_data;
- }
-
- return (ARCHIVE_OK);
-abort_read_data:
- *buff = NULL;
- *size = 0;
- *offset = xar->total;
- return (r);
-}
-
-static int
-xar_read_data_skip(struct archive_read *a)
-{
- struct xar *xar;
- int64_t bytes_skipped;
-
- xar = (struct xar *)(a->format->data);
- if (xar->end_of_file)
- return (ARCHIVE_EOF);
- bytes_skipped = __archive_read_consume(a, xar->entry_remaining +
- xar->entry_unconsumed);
- if (bytes_skipped < 0)
- return (ARCHIVE_FATAL);
- xar->offset += bytes_skipped;
- xar->entry_unconsumed = 0;
- return (ARCHIVE_OK);
-}
-
-static int
-xar_cleanup(struct archive_read *a)
-{
- struct xar *xar;
- struct hdlink *hdlink;
- int i;
- int r;
-
- xar = (struct xar *)(a->format->data);
- r = decompression_cleanup(a);
- hdlink = xar->hdlink_list;
- while (hdlink != NULL) {
- struct hdlink *next = hdlink->next;
-
- free(hdlink);
- hdlink = next;
- }
- for (i = 0; i < xar->file_queue.used; i++)
- file_free(xar->file_queue.files[i]);
- while (xar->unknowntags != NULL) {
- struct unknown_tag *tag;
-
- tag = xar->unknowntags;
- xar->unknowntags = tag->next;
- archive_string_free(&(tag->name));
- free(tag);
- }
- free(xar->outbuff);
- free(xar);
- a->format->data = NULL;
- return (r);
-}
-
-static int
-move_reading_point(struct archive_read *a, uint64_t offset)
-{
- struct xar *xar;
-
- xar = (struct xar *)(a->format->data);
- if (xar->offset - xar->h_base != offset) {
- /* Seek forward to the start of file contents. */
- int64_t step;
-
- step = offset - (xar->offset - xar->h_base);
- if (step > 0) {
- step = __archive_read_consume(a, step);
- if (step < 0)
- return ((int)step);
- xar->offset += step;
- } else {
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "Cannot seek.");
- return (ARCHIVE_FAILED);
- }
- }
- return (ARCHIVE_OK);
-}
-
-static int
-rd_contents_init(struct archive_read *a, enum enctype encoding,
- int a_sum_alg, int e_sum_alg)
-{
- int r;
-
- /* Init decompress library. */
- if ((r = decompression_init(a, encoding)) != ARCHIVE_OK)
- return (r);
- /* Init checksum library. */
- checksum_init(a, a_sum_alg, e_sum_alg);
- return (ARCHIVE_OK);
-}
-
-static int
-rd_contents(struct archive_read *a, const void **buff, size_t *size,
- size_t *used, uint64_t remaining)
-{
- const unsigned char *b;
- ssize_t bytes;
-
- /* Get whatever bytes are immediately available. */
- b = __archive_read_ahead(a, 1, &bytes);
- if (bytes < 0)
- return ((int)bytes);
- if (bytes == 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Truncated archive file");
- return (ARCHIVE_FATAL);
- }
- if ((uint64_t)bytes > remaining)
- bytes = (ssize_t)remaining;
-
- /*
- * Decompress contents of file.
- */
- *used = bytes;
- if (decompress(a, buff, size, b, used) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- /*
- * Update checksum of a compressed data and a extracted data.
- */
- checksum_update(a, b, *used, *buff, *size);
-
- return (ARCHIVE_OK);
-}
-
-/*
- * Note that this implementation does not (and should not!) obey
- * locale settings; you cannot simply substitute strtol here, since
- * it does obey locale.
- */
-
-static uint64_t
-atol10(const char *p, size_t char_cnt)
-{
- uint64_t l;
- int digit;
-
- l = 0;
- digit = *p - '0';
- while (digit >= 0 && digit < 10 && char_cnt-- > 0) {
- l = (l * 10) + digit;
- digit = *++p - '0';
- }
- return (l);
-}
-
-static int64_t
-atol8(const char *p, size_t char_cnt)
-{
- int64_t l;
- int digit;
-
- l = 0;
- while (char_cnt-- > 0) {
- if (*p >= '0' && *p <= '7')
- digit = *p - '0';
- else
- break;
- p++;
- l <<= 3;
- l |= digit;
- }
- return (l);
-}
-
-static size_t
-atohex(unsigned char *b, size_t bsize, const char *p, size_t psize)
-{
- size_t fbsize = bsize;
-
- while (bsize && psize > 1) {
- unsigned char x;
-
- if (p[0] >= 'a' && p[0] <= 'z')
- x = (p[0] - 'a' + 0x0a) << 4;
- else if (p[0] >= 'A' && p[0] <= 'Z')
- x = (p[0] - 'A' + 0x0a) << 4;
- else if (p[0] >= '0' && p[0] <= '9')
- x = (p[0] - '0') << 4;
- else
- return (-1);
- if (p[1] >= 'a' && p[1] <= 'z')
- x |= p[1] - 'a' + 0x0a;
- else if (p[1] >= 'A' && p[1] <= 'Z')
- x |= p[1] - 'A' + 0x0a;
- else if (p[1] >= '0' && p[1] <= '9')
- x |= p[1] - '0';
- else
- return (-1);
-
- *b++ = x;
- bsize--;
- p += 2;
- psize -= 2;
- }
- return (fbsize - bsize);
-}
-
-static time_t
-time_from_tm(struct tm *t)
-{
-#if HAVE_TIMEGM
- /* Use platform timegm() if available. */
- return (timegm(t));
-#elif HAVE__MKGMTIME64
- return (_mkgmtime64(t));
-#else
- /* Else use direct calculation using POSIX assumptions. */
- /* First, fix up tm_yday based on the year/month/day. */
- mktime(t);
- /* Then we can compute timegm() from first principles. */
- return (t->tm_sec + t->tm_min * 60 + t->tm_hour * 3600
- + t->tm_yday * 86400 + (t->tm_year - 70) * 31536000
- + ((t->tm_year - 69) / 4) * 86400 -
- ((t->tm_year - 1) / 100) * 86400
- + ((t->tm_year + 299) / 400) * 86400);
-#endif
-}
-
-static time_t
-parse_time(const char *p, size_t n)
-{
- struct tm tm;
- time_t t = 0;
- int64_t data;
-
- memset(&tm, 0, sizeof(tm));
- if (n != 20)
- return (t);
- data = atol10(p, 4);
- if (data < 1900)
- return (t);
- tm.tm_year = (int)data - 1900;
- p += 4;
- if (*p++ != '-')
- return (t);
- data = atol10(p, 2);
- if (data < 1 || data > 12)
- return (t);
- tm.tm_mon = (int)data -1;
- p += 2;
- if (*p++ != '-')
- return (t);
- data = atol10(p, 2);
- if (data < 1 || data > 31)
- return (t);
- tm.tm_mday = (int)data;
- p += 2;
- if (*p++ != 'T')
- return (t);
- data = atol10(p, 2);
- if (data < 0 || data > 23)
- return (t);
- tm.tm_hour = (int)data;
- p += 2;
- if (*p++ != ':')
- return (t);
- data = atol10(p, 2);
- if (data < 0 || data > 59)
- return (t);
- tm.tm_min = (int)data;
- p += 2;
- if (*p++ != ':')
- return (t);
- data = atol10(p, 2);
- if (data < 0 || data > 60)
- return (t);
- tm.tm_sec = (int)data;
-#if 0
- p += 2;
- if (*p != 'Z')
- return (t);
-#endif
-
- t = time_from_tm(&tm);
-
- return (t);
-}
-
-static int
-heap_add_entry(struct archive_read *a,
- struct heap_queue *heap, struct xar_file *file)
-{
- uint64_t file_id, parent_id;
- int hole, parent;
-
- /* Expand our pending files list as necessary. */
- if (heap->used >= heap->allocated) {
- struct xar_file **new_pending_files;
- int new_size = heap->allocated * 2;
-
- if (heap->allocated < 1024)
- new_size = 1024;
- /* Overflow might keep us from growing the list. */
- if (new_size <= heap->allocated) {
- archive_set_error(&a->archive,
- ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- new_pending_files = (struct xar_file **)
- malloc(new_size * sizeof(new_pending_files[0]));
- if (new_pending_files == NULL) {
- archive_set_error(&a->archive,
- ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- memcpy(new_pending_files, heap->files,
- heap->allocated * sizeof(new_pending_files[0]));
- if (heap->files != NULL)
- free(heap->files);
- heap->files = new_pending_files;
- heap->allocated = new_size;
- }
-
- file_id = file->id;
-
- /*
- * Start with hole at end, walk it up tree to find insertion point.
- */
- hole = heap->used++;
- while (hole > 0) {
- parent = (hole - 1)/2;
- parent_id = heap->files[parent]->id;
- if (file_id >= parent_id) {
- heap->files[hole] = file;
- return (ARCHIVE_OK);
- }
- /* Move parent into hole <==> move hole up tree. */
- heap->files[hole] = heap->files[parent];
- hole = parent;
- }
- heap->files[0] = file;
-
- return (ARCHIVE_OK);
-}
-
-static struct xar_file *
-heap_get_entry(struct heap_queue *heap)
-{
- uint64_t a_id, b_id, c_id;
- int a, b, c;
- struct xar_file *r, *tmp;
-
- if (heap->used < 1)
- return (NULL);
-
- /*
- * The first file in the list is the earliest; we'll return this.
- */
- r = heap->files[0];
-
- /*
- * Move the last item in the heap to the root of the tree
- */
- heap->files[0] = heap->files[--(heap->used)];
-
- /*
- * Rebalance the heap.
- */
- a = 0; /* Starting element and its heap key */
- a_id = heap->files[a]->id;
- for (;;) {
- b = a + a + 1; /* First child */
- if (b >= heap->used)
- return (r);
- b_id = heap->files[b]->id;
- c = b + 1; /* Use second child if it is smaller. */
- if (c < heap->used) {
- c_id = heap->files[c]->id;
- if (c_id < b_id) {
- b = c;
- b_id = c_id;
- }
- }
- if (a_id <= b_id)
- return (r);
- tmp = heap->files[a];
- heap->files[a] = heap->files[b];
- heap->files[b] = tmp;
- a = b;
- }
-}
-
-static int
-add_link(struct archive_read *a, struct xar *xar, struct xar_file *file)
-{
- struct hdlink *hdlink;
-
- for (hdlink = xar->hdlink_list; hdlink != NULL; hdlink = hdlink->next) {
- if (hdlink->id == file->link) {
- file->hdnext = hdlink->files;
- hdlink->cnt++;
- hdlink->files = file;
- return (ARCHIVE_OK);
- }
- }
- hdlink = malloc(sizeof(*hdlink));
- if (hdlink == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- file->hdnext = NULL;
- hdlink->id = file->link;
- hdlink->cnt = 1;
- hdlink->files = file;
- hdlink->next = xar->hdlink_list;
- xar->hdlink_list = hdlink;
- return (ARCHIVE_OK);
-}
-
-static void
-_checksum_init(struct chksumwork *sumwrk, int sum_alg)
-{
- sumwrk->alg = sum_alg;
- switch (sum_alg) {
- case CKSUM_NONE:
- break;
- case CKSUM_SHA1:
- archive_sha1_init(&(sumwrk->sha1ctx));
- break;
- case CKSUM_MD5:
- archive_md5_init(&(sumwrk->md5ctx));
- break;
- }
-}
-
-static void
-_checksum_update(struct chksumwork *sumwrk, const void *buff, size_t size)
-{
-
- switch (sumwrk->alg) {
- case CKSUM_NONE:
- break;
- case CKSUM_SHA1:
- archive_sha1_update(&(sumwrk->sha1ctx), buff, size);
- break;
- case CKSUM_MD5:
- archive_md5_update(&(sumwrk->md5ctx), buff, size);
- break;
- }
-}
-
-static int
-_checksum_final(struct chksumwork *sumwrk, const void *val, size_t len)
-{
- unsigned char sum[MAX_SUM_SIZE];
- int r = ARCHIVE_OK;
-
- switch (sumwrk->alg) {
- case CKSUM_NONE:
- break;
- case CKSUM_SHA1:
- archive_sha1_final(&(sumwrk->sha1ctx), sum);
- if (len != SHA1_SIZE ||
- memcmp(val, sum, SHA1_SIZE) != 0)
- r = ARCHIVE_FAILED;
- break;
- case CKSUM_MD5:
- archive_md5_final(&(sumwrk->md5ctx), sum);
- if (len != MD5_SIZE ||
- memcmp(val, sum, MD5_SIZE) != 0)
- r = ARCHIVE_FAILED;
- break;
- }
- return (r);
-}
-
-static void
-checksum_init(struct archive_read *a, int a_sum_alg, int e_sum_alg)
-{
- struct xar *xar;
-
- xar = (struct xar *)(a->format->data);
- _checksum_init(&(xar->a_sumwrk), a_sum_alg);
- _checksum_init(&(xar->e_sumwrk), e_sum_alg);
-}
-
-static void
-checksum_update(struct archive_read *a, const void *abuff, size_t asize,
- const void *ebuff, size_t esize)
-{
- struct xar *xar;
-
- xar = (struct xar *)(a->format->data);
- _checksum_update(&(xar->a_sumwrk), abuff, asize);
- _checksum_update(&(xar->e_sumwrk), ebuff, esize);
-}
-
-static int
-checksum_final(struct archive_read *a, const void *a_sum_val,
- size_t a_sum_len, const void *e_sum_val, size_t e_sum_len)
-{
- struct xar *xar;
- int r;
-
- xar = (struct xar *)(a->format->data);
- r = _checksum_final(&(xar->a_sumwrk), a_sum_val, a_sum_len);
- if (r == ARCHIVE_OK)
- r = _checksum_final(&(xar->e_sumwrk), e_sum_val, e_sum_len);
- if (r != ARCHIVE_OK)
- archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
- "Sumcheck error");
- return (r);
-}
-
-static int
-decompression_init(struct archive_read *a, enum enctype encoding)
-{
- struct xar *xar;
- const char *detail;
- int r;
-
- xar = (struct xar *)(a->format->data);
- xar->rd_encoding = encoding;
- switch (encoding) {
- case NONE:
- break;
- case GZIP:
- if (xar->stream_valid)
- r = inflateReset(&(xar->stream));
- else
- r = inflateInit(&(xar->stream));
- if (r != Z_OK) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Couldn't initialize zlib stream.");
- return (ARCHIVE_FATAL);
- }
- xar->stream_valid = 1;
- xar->stream.total_in = 0;
- xar->stream.total_out = 0;
- break;
-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
- case BZIP2:
- if (xar->bzstream_valid) {
- BZ2_bzDecompressEnd(&(xar->bzstream));
- xar->bzstream_valid = 0;
- }
- r = BZ2_bzDecompressInit(&(xar->bzstream), 0, 0);
- if (r == BZ_MEM_ERROR)
- r = BZ2_bzDecompressInit(&(xar->bzstream), 0, 1);
- if (r != BZ_OK) {
- int err = ARCHIVE_ERRNO_MISC;
- detail = NULL;
- switch (r) {
- case BZ_PARAM_ERROR:
- detail = "invalid setup parameter";
- break;
- case BZ_MEM_ERROR:
- err = ENOMEM;
- detail = "out of memory";
- break;
- case BZ_CONFIG_ERROR:
- detail = "mis-compiled library";
- break;
- }
- archive_set_error(&a->archive, err,
- "Internal error initializing decompressor: %s",
- detail == NULL ? "??" : detail);
- xar->bzstream_valid = 0;
- return (ARCHIVE_FATAL);
- }
- xar->bzstream_valid = 1;
- xar->bzstream.total_in_lo32 = 0;
- xar->bzstream.total_in_hi32 = 0;
- xar->bzstream.total_out_lo32 = 0;
- xar->bzstream.total_out_hi32 = 0;
- break;
-#endif
-#if defined(HAVE_LZMA_H) && defined(HAVE_LIBLZMA)
-#if LZMA_VERSION_MAJOR >= 5
-/* Effectively disable the limiter. */
-#define LZMA_MEMLIMIT UINT64_MAX
-#else
-/* NOTE: This needs to check memory size which running system has. */
-#define LZMA_MEMLIMIT (1U << 30)
-#endif
- case XZ:
- case LZMA:
- if (xar->lzstream_valid) {
- lzma_end(&(xar->lzstream));
- xar->lzstream_valid = 0;
- }
- if (xar->entry_encoding == XZ)
- r = lzma_stream_decoder(&(xar->lzstream),
- LZMA_MEMLIMIT,/* memlimit */
- LZMA_CONCATENATED);
- else
- r = lzma_alone_decoder(&(xar->lzstream),
- LZMA_MEMLIMIT);/* memlimit */
- if (r != LZMA_OK) {
- switch (r) {
- case LZMA_MEM_ERROR:
- archive_set_error(&a->archive,
- ENOMEM,
- "Internal error initializing "
- "compression library: "
- "Cannot allocate memory");
- break;
- case LZMA_OPTIONS_ERROR:
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Internal error initializing "
- "compression library: "
- "Invalid or unsupported options");
- break;
- default:
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Internal error initializing "
- "lzma library");
- break;
- }
- return (ARCHIVE_FATAL);
- }
- xar->lzstream_valid = 1;
- xar->lzstream.total_in = 0;
- xar->lzstream.total_out = 0;
- break;
-#elif defined(HAVE_LZMADEC_H) && defined(HAVE_LIBLZMADEC)
- case LZMA:
- if (xar->lzstream_valid)
- lzmadec_end(&(xar->lzstream));
- r = lzmadec_init(&(xar->lzstream));
- if (r != LZMADEC_OK) {
- switch (r) {
- case LZMADEC_HEADER_ERROR:
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Internal error initializing "
- "compression library: "
- "invalid header");
- break;
- case LZMADEC_MEM_ERROR:
- archive_set_error(&a->archive,
- ENOMEM,
- "Internal error initializing "
- "compression library: "
- "out of memory");
- break;
- }
- return (ARCHIVE_FATAL);
- }
- xar->lzstream_valid = 1;
- xar->lzstream.total_in = 0;
- xar->lzstream.total_out = 0;
- break;
-#endif
- /*
- * Unsupported compression.
- */
- default:
-#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR)
- case BZIP2:
-#endif
-#if !defined(HAVE_LZMA_H) || !defined(HAVE_LIBLZMA)
-#if !defined(HAVE_LZMADEC_H) || !defined(HAVE_LIBLZMADEC)
- case LZMA:
-#endif
- case XZ:
-#endif
- switch (xar->entry_encoding) {
- case BZIP2: detail = "bzip2"; break;
- case LZMA: detail = "lzma"; break;
- case XZ: detail = "xz"; break;
- default: detail = "??"; break;
- }
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "%s compression not supported on this platform",
- detail);
- return (ARCHIVE_FAILED);
- }
- return (ARCHIVE_OK);
-}
-
-static int
-decompress(struct archive_read *a, const void **buff, size_t *outbytes,
- const void *b, size_t *used)
-{
- struct xar *xar;
- void *outbuff;
- size_t avail_in, avail_out;
- int r;
-
- xar = (struct xar *)(a->format->data);
- avail_in = *used;
- outbuff = (void *)(uintptr_t)*buff;
- if (outbuff == NULL) {
- if (xar->outbuff == NULL) {
- xar->outbuff = malloc(OUTBUFF_SIZE);
- if (xar->outbuff == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Couldn't allocate memory for out buffer");
- return (ARCHIVE_FATAL);
- }
- }
- outbuff = xar->outbuff;
- *buff = outbuff;
- avail_out = OUTBUFF_SIZE;
- } else
- avail_out = *outbytes;
- switch (xar->rd_encoding) {
- case GZIP:
- xar->stream.next_in = (Bytef *)(uintptr_t)b;
- xar->stream.avail_in = avail_in;
- xar->stream.next_out = (unsigned char *)outbuff;
- xar->stream.avail_out = avail_out;
- r = inflate(&(xar->stream), 0);
- switch (r) {
- case Z_OK: /* Decompressor made some progress.*/
- case Z_STREAM_END: /* Found end of stream. */
- break;
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "File decompression failed (%d)", r);
- return (ARCHIVE_FATAL);
- }
- *used = avail_in - xar->stream.avail_in;
- *outbytes = avail_out - xar->stream.avail_out;
- break;
-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
- case BZIP2:
- xar->bzstream.next_in = (char *)(uintptr_t)b;
- xar->bzstream.avail_in = avail_in;
- xar->bzstream.next_out = (char *)outbuff;
- xar->bzstream.avail_out = avail_out;
- r = BZ2_bzDecompress(&(xar->bzstream));
- switch (r) {
- case BZ_STREAM_END: /* Found end of stream. */
- switch (BZ2_bzDecompressEnd(&(xar->bzstream))) {
- case BZ_OK:
- break;
- default:
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "Failed to clean up decompressor");
- return (ARCHIVE_FATAL);
- }
- xar->bzstream_valid = 0;
- /* FALLTHROUGH */
- case BZ_OK: /* Decompressor made some progress. */
- break;
- default:
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "bzip decompression failed");
- return (ARCHIVE_FATAL);
- }
- *used = avail_in - xar->bzstream.avail_in;
- *outbytes = avail_out - xar->bzstream.avail_out;
- break;
-#endif
-#if defined(HAVE_LZMA_H) && defined(HAVE_LIBLZMA)
- case LZMA:
- case XZ:
- xar->lzstream.next_in = b;
- xar->lzstream.avail_in = avail_in;
- xar->lzstream.next_out = (unsigned char *)outbuff;
- xar->lzstream.avail_out = avail_out;
- r = lzma_code(&(xar->lzstream), LZMA_RUN);
- switch (r) {
- case LZMA_STREAM_END: /* Found end of stream. */
- lzma_end(&(xar->lzstream));
- xar->lzstream_valid = 0;
- /* FALLTHROUGH */
- case LZMA_OK: /* Decompressor made some progress. */
- break;
- default:
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "%s decompression failed(%d)",
- (xar->entry_encoding == XZ)?"xz":"lzma",
- r);
- return (ARCHIVE_FATAL);
- }
- *used = avail_in - xar->lzstream.avail_in;
- *outbytes = avail_out - xar->lzstream.avail_out;
- break;
-#elif defined(HAVE_LZMADEC_H) && defined(HAVE_LIBLZMADEC)
- case LZMA:
- xar->lzstream.next_in = (unsigned char *)(uintptr_t)b;
- xar->lzstream.avail_in = avail_in;
- xar->lzstream.next_out = (unsigned char *)outbuff;
- xar->lzstream.avail_out = avail_out;
- r = lzmadec_decode(&(xar->lzstream), 0);
- switch (r) {
- case LZMADEC_STREAM_END: /* Found end of stream. */
- switch (lzmadec_end(&(xar->lzstream))) {
- case LZMADEC_OK:
- break;
- default:
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "Failed to clean up lzmadec decompressor");
- return (ARCHIVE_FATAL);
- }
- xar->lzstream_valid = 0;
- /* FALLTHROUGH */
- case LZMADEC_OK: /* Decompressor made some progress. */
- break;
- default:
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "lzmadec decompression failed(%d)",
- r);
- return (ARCHIVE_FATAL);
- }
- *used = avail_in - xar->lzstream.avail_in;
- *outbytes = avail_out - xar->lzstream.avail_out;
- break;
-#endif
-#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR)
- case BZIP2:
-#endif
-#if !defined(HAVE_LZMA_H) || !defined(HAVE_LIBLZMA)
-#if !defined(HAVE_LZMADEC_H) || !defined(HAVE_LIBLZMADEC)
- case LZMA:
-#endif
- case XZ:
-#endif
- case NONE:
- default:
- if (outbuff == xar->outbuff) {
- *buff = b;
- *used = avail_in;
- *outbytes = avail_in;
- } else {
- if (avail_out > avail_in)
- avail_out = avail_in;
- memcpy(outbuff, b, avail_out);
- *used = avail_out;
- *outbytes = avail_out;
- }
- break;
- }
- return (ARCHIVE_OK);
-}
-
-static int
-decompression_cleanup(struct archive_read *a)
-{
- struct xar *xar;
- int r;
-
- xar = (struct xar *)(a->format->data);
- r = ARCHIVE_OK;
- if (xar->stream_valid) {
- if (inflateEnd(&(xar->stream)) != Z_OK) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Failed to clean up zlib decompressor");
- r = ARCHIVE_FATAL;
- }
- }
-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
- if (xar->bzstream_valid) {
- if (BZ2_bzDecompressEnd(&(xar->bzstream)) != BZ_OK) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Failed to clean up bzip2 decompressor");
- r = ARCHIVE_FATAL;
- }
- }
-#endif
-#if defined(HAVE_LZMA_H) && defined(HAVE_LIBLZMA)
- if (xar->lzstream_valid)
- lzma_end(&(xar->lzstream));
-#elif defined(HAVE_LZMA_H) && defined(HAVE_LIBLZMA)
- if (xar->lzstream_valid) {
- if (lzmadec_end(&(xar->lzstream)) != LZMADEC_OK) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Failed to clean up lzmadec decompressor");
- r = ARCHIVE_FATAL;
- }
- }
-#endif
- return (r);
-}
-
-static void
-xmlattr_cleanup(struct xmlattr_list *list)
-{
- struct xmlattr *attr, *next;
-
- attr = list->first;
- while (attr != NULL) {
- next = attr->next;
- free(attr->name);
- free(attr->value);
- free(attr);
- attr = next;
- }
- list->first = NULL;
- list->last = &(list->first);
-}
-
-static int
-file_new(struct archive_read *a, struct xar *xar, struct xmlattr_list *list)
-{
- struct xar_file *file;
- struct xmlattr *attr;
-
- file = calloc(1, sizeof(*file));
- if (file == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- file->parent = xar->file;
- file->mode = 0777 | AE_IFREG;
- file->atime = time(NULL);
- file->mtime = time(NULL);
- xar->file = file;
- xar->xattr = NULL;
- for (attr = list->first; attr != NULL; attr = attr->next) {
- if (strcmp(attr->name, "id") == 0)
- file->id = atol10(attr->value, strlen(attr->value));
- }
- file->nlink = 1;
- if (heap_add_entry(a, &(xar->file_queue), file) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- return (ARCHIVE_OK);
-}
-
-static void
-file_free(struct xar_file *file)
-{
- struct xattr *xattr;
-
- archive_string_free(&(file->pathname));
- archive_string_free(&(file->symlink));
- archive_string_free(&(file->uname));
- archive_string_free(&(file->gname));
- archive_string_free(&(file->hardlink));
- xattr = file->xattr_list;
- while (xattr != NULL) {
- struct xattr *next;
-
- next = xattr->next;
- xattr_free(xattr);
- xattr = next;
- }
-
- free(file);
-}
-
-static int
-xattr_new(struct archive_read *a, struct xar *xar, struct xmlattr_list *list)
-{
- struct xattr *xattr, **nx;
- struct xmlattr *attr;
-
- xattr = calloc(1, sizeof(*xattr));
- if (xattr == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- xar->xattr = xattr;
- for (attr = list->first; attr != NULL; attr = attr->next) {
- if (strcmp(attr->name, "id") == 0)
- xattr->id = atol10(attr->value, strlen(attr->value));
- }
- /* Chain to xattr list. */
- for (nx = &(xar->file->xattr_list);
- *nx != NULL; nx = &((*nx)->next)) {
- if (xattr->id < (*nx)->id)
- break;
- }
- xattr->next = *nx;
- *nx = xattr;
-
- return (ARCHIVE_OK);
-}
-
-static void
-xattr_free(struct xattr *xattr)
-{
- archive_string_free(&(xattr->name));
- free(xattr);
-}
-
-static int
-getencoding(struct xmlattr_list *list)
-{
- struct xmlattr *attr;
- enum enctype encoding = NONE;
-
- for (attr = list->first; attr != NULL; attr = attr->next) {
- if (strcmp(attr->name, "style") == 0) {
- if (strcmp(attr->value, "application/octet-stream") == 0)
- encoding = NONE;
- else if (strcmp(attr->value, "application/x-gzip") == 0)
- encoding = GZIP;
- else if (strcmp(attr->value, "application/x-bzip2") == 0)
- encoding = BZIP2;
- else if (strcmp(attr->value, "application/x-lzma") == 0)
- encoding = LZMA;
- else if (strcmp(attr->value, "application/x-xz") == 0)
- encoding = XZ;
- }
- }
- return (encoding);
-}
-
-static int
-getsumalgorithm(struct xmlattr_list *list)
-{
- struct xmlattr *attr;
- int alg = CKSUM_NONE;
-
- for (attr = list->first; attr != NULL; attr = attr->next) {
- if (strcmp(attr->name, "style") == 0) {
- const char *v = attr->value;
- if ((v[0] == 'S' || v[0] == 's') &&
- (v[1] == 'H' || v[1] == 'h') &&
- (v[2] == 'A' || v[2] == 'a') &&
- v[3] == '1' && v[4] == '\0')
- alg = CKSUM_SHA1;
- if ((v[0] == 'M' || v[0] == 'm') &&
- (v[1] == 'D' || v[1] == 'd') &&
- v[2] == '5' && v[3] == '\0')
- alg = CKSUM_MD5;
- }
- }
- return (alg);
-}
-
-static int
-unknowntag_start(struct archive_read *a, struct xar *xar, const char *name)
-{
- struct unknown_tag *tag;
-
-#if DEBUG
- fprintf(stderr, "unknowntag_start:%s\n", name);
-#endif
- tag = malloc(sizeof(*tag));
- if (tag == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- tag->next = xar->unknowntags;
- archive_string_init(&(tag->name));
- archive_strcpy(&(tag->name), name);
- if (xar->unknowntags == NULL) {
- xar->xmlsts_unknown = xar->xmlsts;
- xar->xmlsts = UNKNOWN;
- }
- xar->unknowntags = tag;
- return (ARCHIVE_OK);
-}
-
-static void
-unknowntag_end(struct xar *xar, const char *name)
-{
- struct unknown_tag *tag;
-
-#if DEBUG
- fprintf(stderr, "unknowntag_end:%s\n", name);
-#endif
- tag = xar->unknowntags;
- if (tag == NULL || name == NULL)
- return;
- if (strcmp(tag->name.s, name) == 0) {
- xar->unknowntags = tag->next;
- archive_string_free(&(tag->name));
- free(tag);
- if (xar->unknowntags == NULL)
- xar->xmlsts = xar->xmlsts_unknown;
- }
-}
-
-static int
-xml_start(struct archive_read *a, const char *name, struct xmlattr_list *list)
-{
- struct xar *xar;
- struct xmlattr *attr;
-
- xar = (struct xar *)(a->format->data);
-
-#if DEBUG
- fprintf(stderr, "xml_sta:[%s]\n", name);
- for (attr = list->first; attr != NULL; attr = attr->next)
- fprintf(stderr, " attr:\"%s\"=\"%s\"\n",
- attr->name, attr->value);
-#endif
- xar->base64text = 0;
- switch (xar->xmlsts) {
- case INIT:
- if (strcmp(name, "xar") == 0)
- xar->xmlsts = XAR;
- else
- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- break;
- case XAR:
- if (strcmp(name, "toc") == 0)
- xar->xmlsts = TOC;
- else
- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- break;
- case TOC:
- if (strcmp(name, "creation-time") == 0)
- xar->xmlsts = TOC_CREATION_TIME;
- else if (strcmp(name, "checksum") == 0)
- xar->xmlsts = TOC_CHECKSUM;
- else if (strcmp(name, "file") == 0) {
- if (file_new(a, xar, list) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- xar->xmlsts = TOC_FILE;
- }
- else
- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- break;
- case TOC_CHECKSUM:
- if (strcmp(name, "offset") == 0)
- xar->xmlsts = TOC_CHECKSUM_OFFSET;
- else if (strcmp(name, "size") == 0)
- xar->xmlsts = TOC_CHECKSUM_SIZE;
- else
- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- break;
- case TOC_FILE:
- if (strcmp(name, "file") == 0) {
- if (file_new(a, xar, list) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
- else if (strcmp(name, "data") == 0)
- xar->xmlsts = FILE_DATA;
- else if (strcmp(name, "ea") == 0) {
- if (xattr_new(a, xar, list) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- xar->xmlsts = FILE_EA;
- }
- else if (strcmp(name, "ctime") == 0)
- xar->xmlsts = FILE_CTIME;
- else if (strcmp(name, "mtime") == 0)
- xar->xmlsts = FILE_MTIME;
- else if (strcmp(name, "atime") == 0)
- xar->xmlsts = FILE_ATIME;
- else if (strcmp(name, "group") == 0)
- xar->xmlsts = FILE_GROUP;
- else if (strcmp(name, "gid") == 0)
- xar->xmlsts = FILE_GID;
- else if (strcmp(name, "user") == 0)
- xar->xmlsts = FILE_USER;
- else if (strcmp(name, "uid") == 0)
- xar->xmlsts = FILE_UID;
- else if (strcmp(name, "mode") == 0)
- xar->xmlsts = FILE_MODE;
- else if (strcmp(name, "device") == 0)
- xar->xmlsts = FILE_DEVICE;
- else if (strcmp(name, "deviceno") == 0)
- xar->xmlsts = FILE_DEVICENO;
- else if (strcmp(name, "inode") == 0)
- xar->xmlsts = FILE_INODE;
- else if (strcmp(name, "link") == 0)
- xar->xmlsts = FILE_LINK;
- else if (strcmp(name, "type") == 0) {
- xar->xmlsts = FILE_TYPE;
- for (attr = list->first; attr != NULL;
- attr = attr->next) {
- if (strcmp(attr->name, "link") != 0)
- continue;
- if (strcmp(attr->value, "original") == 0) {
- xar->file->hdnext = xar->hdlink_orgs;
- xar->hdlink_orgs = xar->file;
- } else {
- xar->file->link = (unsigned)atol10(attr->value,
- strlen(attr->value));
- if (xar->file->link > 0)
- if (add_link(a, xar, xar->file) != ARCHIVE_OK) {
- return (ARCHIVE_FATAL);
- };
- }
- }
- }
- else if (strcmp(name, "name") == 0) {
- xar->xmlsts = FILE_NAME;
- for (attr = list->first; attr != NULL;
- attr = attr->next) {
- if (strcmp(attr->name, "enctype") == 0 &&
- strcmp(attr->value, "base64") == 0)
- xar->base64text = 1;
- }
- }
- else if (strcmp(name, "acl") == 0)
- xar->xmlsts = FILE_ACL;
- else if (strcmp(name, "flags") == 0)
- xar->xmlsts = FILE_FLAGS;
- else if (strcmp(name, "ext2") == 0)
- xar->xmlsts = FILE_EXT2;
- else
- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- break;
- case FILE_DATA:
- if (strcmp(name, "length") == 0)
- xar->xmlsts = FILE_DATA_LENGTH;
- else if (strcmp(name, "offset") == 0)
- xar->xmlsts = FILE_DATA_OFFSET;
- else if (strcmp(name, "size") == 0)
- xar->xmlsts = FILE_DATA_SIZE;
- else if (strcmp(name, "encoding") == 0) {
- xar->xmlsts = FILE_DATA_ENCODING;
- xar->file->encoding = getencoding(list);
- }
- else if (strcmp(name, "archived-checksum") == 0) {
- xar->xmlsts = FILE_DATA_A_CHECKSUM;
- xar->file->a_sum.alg = getsumalgorithm(list);
- }
- else if (strcmp(name, "extracted-checksum") == 0) {
- xar->xmlsts = FILE_DATA_E_CHECKSUM;
- xar->file->e_sum.alg = getsumalgorithm(list);
- }
- else if (strcmp(name, "content") == 0)
- xar->xmlsts = FILE_DATA_CONTENT;
- else
- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- break;
- case FILE_DEVICE:
- if (strcmp(name, "major") == 0)
- xar->xmlsts = FILE_DEVICE_MAJOR;
- else if (strcmp(name, "minor") == 0)
- xar->xmlsts = FILE_DEVICE_MINOR;
- else
- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- break;
- case FILE_DATA_CONTENT:
- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- break;
- case FILE_EA:
- if (strcmp(name, "length") == 0)
- xar->xmlsts = FILE_EA_LENGTH;
- else if (strcmp(name, "offset") == 0)
- xar->xmlsts = FILE_EA_OFFSET;
- else if (strcmp(name, "size") == 0)
- xar->xmlsts = FILE_EA_SIZE;
- else if (strcmp(name, "encoding") == 0) {
- xar->xmlsts = FILE_EA_ENCODING;
- xar->xattr->encoding = getencoding(list);
- } else if (strcmp(name, "archived-checksum") == 0)
- xar->xmlsts = FILE_EA_A_CHECKSUM;
- else if (strcmp(name, "extracted-checksum") == 0)
- xar->xmlsts = FILE_EA_E_CHECKSUM;
- else if (strcmp(name, "name") == 0)
- xar->xmlsts = FILE_EA_NAME;
- else if (strcmp(name, "fstype") == 0)
- xar->xmlsts = FILE_EA_FSTYPE;
- else
- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- break;
- case FILE_ACL:
- if (strcmp(name, "appleextended") == 0)
- xar->xmlsts = FILE_ACL_APPLEEXTENDED;
- if (strcmp(name, "default") == 0)
- xar->xmlsts = FILE_ACL_DEFAULT;
- else if (strcmp(name, "access") == 0)
- xar->xmlsts = FILE_ACL_ACCESS;
- else
- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- break;
- case FILE_FLAGS:
- if (!xml_parse_file_flags(xar, name))
- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- break;
- case FILE_EXT2:
- if (!xml_parse_file_ext2(xar, name))
- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- break;
- case TOC_CREATION_TIME:
- case TOC_CHECKSUM_OFFSET:
- case TOC_CHECKSUM_SIZE:
- case FILE_DATA_LENGTH:
- case FILE_DATA_OFFSET:
- case FILE_DATA_SIZE:
- case FILE_DATA_ENCODING:
- case FILE_DATA_A_CHECKSUM:
- case FILE_DATA_E_CHECKSUM:
- case FILE_EA_LENGTH:
- case FILE_EA_OFFSET:
- case FILE_EA_SIZE:
- case FILE_EA_ENCODING:
- case FILE_EA_A_CHECKSUM:
- case FILE_EA_E_CHECKSUM:
- case FILE_EA_NAME:
- case FILE_EA_FSTYPE:
- case FILE_CTIME:
- case FILE_MTIME:
- case FILE_ATIME:
- case FILE_GROUP:
- case FILE_GID:
- case FILE_USER:
- case FILE_UID:
- case FILE_INODE:
- case FILE_DEVICE_MAJOR:
- case FILE_DEVICE_MINOR:
- case FILE_DEVICENO:
- case FILE_MODE:
- case FILE_TYPE:
- case FILE_LINK:
- case FILE_NAME:
- case FILE_ACL_DEFAULT:
- case FILE_ACL_ACCESS:
- case FILE_ACL_APPLEEXTENDED:
- case FILE_FLAGS_USER_NODUMP:
- case FILE_FLAGS_USER_IMMUTABLE:
- case FILE_FLAGS_USER_APPEND:
- case FILE_FLAGS_USER_OPAQUE:
- case FILE_FLAGS_USER_NOUNLINK:
- case FILE_FLAGS_SYS_ARCHIVED:
- case FILE_FLAGS_SYS_IMMUTABLE:
- case FILE_FLAGS_SYS_APPEND:
- case FILE_FLAGS_SYS_NOUNLINK:
- case FILE_FLAGS_SYS_SNAPSHOT:
- case FILE_EXT2_SecureDeletion:
- case FILE_EXT2_Undelete:
- case FILE_EXT2_Compress:
- case FILE_EXT2_Synchronous:
- case FILE_EXT2_Immutable:
- case FILE_EXT2_AppendOnly:
- case FILE_EXT2_NoDump:
- case FILE_EXT2_NoAtime:
- case FILE_EXT2_CompDirty:
- case FILE_EXT2_CompBlock:
- case FILE_EXT2_NoCompBlock:
- case FILE_EXT2_CompError:
- case FILE_EXT2_BTree:
- case FILE_EXT2_HashIndexed:
- case FILE_EXT2_iMagic:
- case FILE_EXT2_Journaled:
- case FILE_EXT2_NoTail:
- case FILE_EXT2_DirSync:
- case FILE_EXT2_TopDir:
- case FILE_EXT2_Reserved:
- case UNKNOWN:
- if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- break;
- }
- return (ARCHIVE_OK);
-}
-
-static void
-xml_end(void *userData, const char *name)
-{
- struct archive_read *a;
- struct xar *xar;
-
- a = (struct archive_read *)userData;
- xar = (struct xar *)(a->format->data);
-
-#if DEBUG
- fprintf(stderr, "xml_end:[%s]\n", name);
-#endif
- switch (xar->xmlsts) {
- case INIT:
- break;
- case XAR:
- if (strcmp(name, "xar") == 0)
- xar->xmlsts = INIT;
- break;
- case TOC:
- if (strcmp(name, "toc") == 0)
- xar->xmlsts = XAR;
- break;
- case TOC_CREATION_TIME:
- if (strcmp(name, "creation-time") == 0)
- xar->xmlsts = TOC;
- break;
- case TOC_CHECKSUM:
- if (strcmp(name, "checksum") == 0)
- xar->xmlsts = TOC;
- break;
- case TOC_CHECKSUM_OFFSET:
- if (strcmp(name, "offset") == 0)
- xar->xmlsts = TOC_CHECKSUM;
- break;
- case TOC_CHECKSUM_SIZE:
- if (strcmp(name, "size") == 0)
- xar->xmlsts = TOC_CHECKSUM;
- break;
- case TOC_FILE:
- if (strcmp(name, "file") == 0) {
- if (xar->file->parent != NULL &&
- ((xar->file->mode & AE_IFMT) == AE_IFDIR))
- xar->file->parent->subdirs++;
- xar->file = xar->file->parent;
- if (xar->file == NULL)
- xar->xmlsts = TOC;
- }
- break;
- case FILE_DATA:
- if (strcmp(name, "data") == 0)
- xar->xmlsts = TOC_FILE;
- break;
- case FILE_DATA_LENGTH:
- if (strcmp(name, "length") == 0)
- xar->xmlsts = FILE_DATA;
- break;
- case FILE_DATA_OFFSET:
- if (strcmp(name, "offset") == 0)
- xar->xmlsts = FILE_DATA;
- break;
- case FILE_DATA_SIZE:
- if (strcmp(name, "size") == 0)
- xar->xmlsts = FILE_DATA;
- break;
- case FILE_DATA_ENCODING:
- if (strcmp(name, "encoding") == 0)
- xar->xmlsts = FILE_DATA;
- break;
- case FILE_DATA_A_CHECKSUM:
- if (strcmp(name, "archived-checksum") == 0)
- xar->xmlsts = FILE_DATA;
- break;
- case FILE_DATA_E_CHECKSUM:
- if (strcmp(name, "extracted-checksum") == 0)
- xar->xmlsts = FILE_DATA;
- break;
- case FILE_DATA_CONTENT:
- if (strcmp(name, "content") == 0)
- xar->xmlsts = FILE_DATA;
- break;
- case FILE_EA:
- if (strcmp(name, "ea") == 0) {
- xar->xmlsts = TOC_FILE;
- xar->xattr = NULL;
- }
- break;
- case FILE_EA_LENGTH:
- if (strcmp(name, "length") == 0)
- xar->xmlsts = FILE_EA;
- break;
- case FILE_EA_OFFSET:
- if (strcmp(name, "offset") == 0)
- xar->xmlsts = FILE_EA;
- break;
- case FILE_EA_SIZE:
- if (strcmp(name, "size") == 0)
- xar->xmlsts = FILE_EA;
- break;
- case FILE_EA_ENCODING:
- if (strcmp(name, "encoding") == 0)
- xar->xmlsts = FILE_EA;
- break;
- case FILE_EA_A_CHECKSUM:
- if (strcmp(name, "archived-checksum") == 0)
- xar->xmlsts = FILE_EA;
- break;
- case FILE_EA_E_CHECKSUM:
- if (strcmp(name, "extracted-checksum") == 0)
- xar->xmlsts = FILE_EA;
- break;
- case FILE_EA_NAME:
- if (strcmp(name, "name") == 0)
- xar->xmlsts = FILE_EA;
- break;
- case FILE_EA_FSTYPE:
- if (strcmp(name, "fstype") == 0)
- xar->xmlsts = FILE_EA;
- break;
- case FILE_CTIME:
- if (strcmp(name, "ctime") == 0)
- xar->xmlsts = TOC_FILE;
- break;
- case FILE_MTIME:
- if (strcmp(name, "mtime") == 0)
- xar->xmlsts = TOC_FILE;
- break;
- case FILE_ATIME:
- if (strcmp(name, "atime") == 0)
- xar->xmlsts = TOC_FILE;
- break;
- case FILE_GROUP:
- if (strcmp(name, "group") == 0)
- xar->xmlsts = TOC_FILE;
- break;
- case FILE_GID:
- if (strcmp(name, "gid") == 0)
- xar->xmlsts = TOC_FILE;
- break;
- case FILE_USER:
- if (strcmp(name, "user") == 0)
- xar->xmlsts = TOC_FILE;
- break;
- case FILE_UID:
- if (strcmp(name, "uid") == 0)
- xar->xmlsts = TOC_FILE;
- break;
- case FILE_MODE:
- if (strcmp(name, "mode") == 0)
- xar->xmlsts = TOC_FILE;
- break;
- case FILE_DEVICE:
- if (strcmp(name, "device") == 0)
- xar->xmlsts = TOC_FILE;
- break;
- case FILE_DEVICE_MAJOR:
- if (strcmp(name, "major") == 0)
- xar->xmlsts = FILE_DEVICE;
- break;
- case FILE_DEVICE_MINOR:
- if (strcmp(name, "minor") == 0)
- xar->xmlsts = FILE_DEVICE;
- break;
- case FILE_DEVICENO:
- if (strcmp(name, "deviceno") == 0)
- xar->xmlsts = TOC_FILE;
- break;
- case FILE_INODE:
- if (strcmp(name, "inode") == 0)
- xar->xmlsts = TOC_FILE;
- break;
- case FILE_LINK:
- if (strcmp(name, "link") == 0)
- xar->xmlsts = TOC_FILE;
- break;
- case FILE_TYPE:
- if (strcmp(name, "type") == 0)
- xar->xmlsts = TOC_FILE;
- break;
- case FILE_NAME:
- if (strcmp(name, "name") == 0)
- xar->xmlsts = TOC_FILE;
- break;
- case FILE_ACL:
- if (strcmp(name, "acl") == 0)
- xar->xmlsts = TOC_FILE;
- break;
- case FILE_ACL_DEFAULT:
- if (strcmp(name, "default") == 0)
- xar->xmlsts = FILE_ACL;
- break;
- case FILE_ACL_ACCESS:
- if (strcmp(name, "access") == 0)
- xar->xmlsts = FILE_ACL;
- break;
- case FILE_ACL_APPLEEXTENDED:
- if (strcmp(name, "appleextended") == 0)
- xar->xmlsts = FILE_ACL;
- break;
- case FILE_FLAGS:
- if (strcmp(name, "flags") == 0)
- xar->xmlsts = TOC_FILE;
- break;
- case FILE_FLAGS_USER_NODUMP:
- if (strcmp(name, "UserNoDump") == 0)
- xar->xmlsts = FILE_FLAGS;
- break;
- case FILE_FLAGS_USER_IMMUTABLE:
- if (strcmp(name, "UserImmutable") == 0)
- xar->xmlsts = FILE_FLAGS;
- break;
- case FILE_FLAGS_USER_APPEND:
- if (strcmp(name, "UserAppend") == 0)
- xar->xmlsts = FILE_FLAGS;
- break;
- case FILE_FLAGS_USER_OPAQUE:
- if (strcmp(name, "UserOpaque") == 0)
- xar->xmlsts = FILE_FLAGS;
- break;
- case FILE_FLAGS_USER_NOUNLINK:
- if (strcmp(name, "UserNoUnlink") == 0)
- xar->xmlsts = FILE_FLAGS;
- break;
- case FILE_FLAGS_SYS_ARCHIVED:
- if (strcmp(name, "SystemArchived") == 0)
- xar->xmlsts = FILE_FLAGS;
- break;
- case FILE_FLAGS_SYS_IMMUTABLE:
- if (strcmp(name, "SystemImmutable") == 0)
- xar->xmlsts = FILE_FLAGS;
- break;
- case FILE_FLAGS_SYS_APPEND:
- if (strcmp(name, "SystemAppend") == 0)
- xar->xmlsts = FILE_FLAGS;
- break;
- case FILE_FLAGS_SYS_NOUNLINK:
- if (strcmp(name, "SystemNoUnlink") == 0)
- xar->xmlsts = FILE_FLAGS;
- break;
- case FILE_FLAGS_SYS_SNAPSHOT:
- if (strcmp(name, "SystemSnapshot") == 0)
- xar->xmlsts = FILE_FLAGS;
- break;
- case FILE_EXT2:
- if (strcmp(name, "ext2") == 0)
- xar->xmlsts = TOC_FILE;
- break;
- case FILE_EXT2_SecureDeletion:
- if (strcmp(name, "SecureDeletion") == 0)
- xar->xmlsts = FILE_EXT2;
- break;
- case FILE_EXT2_Undelete:
- if (strcmp(name, "Undelete") == 0)
- xar->xmlsts = FILE_EXT2;
- break;
- case FILE_EXT2_Compress:
- if (strcmp(name, "Compress") == 0)
- xar->xmlsts = FILE_EXT2;
- break;
- case FILE_EXT2_Synchronous:
- if (strcmp(name, "Synchronous") == 0)
- xar->xmlsts = FILE_EXT2;
- break;
- case FILE_EXT2_Immutable:
- if (strcmp(name, "Immutable") == 0)
- xar->xmlsts = FILE_EXT2;
- break;
- case FILE_EXT2_AppendOnly:
- if (strcmp(name, "AppendOnly") == 0)
- xar->xmlsts = FILE_EXT2;
- break;
- case FILE_EXT2_NoDump:
- if (strcmp(name, "NoDump") == 0)
- xar->xmlsts = FILE_EXT2;
- break;
- case FILE_EXT2_NoAtime:
- if (strcmp(name, "NoAtime") == 0)
- xar->xmlsts = FILE_EXT2;
- break;
- case FILE_EXT2_CompDirty:
- if (strcmp(name, "CompDirty") == 0)
- xar->xmlsts = FILE_EXT2;
- break;
- case FILE_EXT2_CompBlock:
- if (strcmp(name, "CompBlock") == 0)
- xar->xmlsts = FILE_EXT2;
- break;
- case FILE_EXT2_NoCompBlock:
- if (strcmp(name, "NoCompBlock") == 0)
- xar->xmlsts = FILE_EXT2;
- break;
- case FILE_EXT2_CompError:
- if (strcmp(name, "CompError") == 0)
- xar->xmlsts = FILE_EXT2;
- break;
- case FILE_EXT2_BTree:
- if (strcmp(name, "BTree") == 0)
- xar->xmlsts = FILE_EXT2;
- break;
- case FILE_EXT2_HashIndexed:
- if (strcmp(name, "HashIndexed") == 0)
- xar->xmlsts = FILE_EXT2;
- break;
- case FILE_EXT2_iMagic:
- if (strcmp(name, "iMagic") == 0)
- xar->xmlsts = FILE_EXT2;
- break;
- case FILE_EXT2_Journaled:
- if (strcmp(name, "Journaled") == 0)
- xar->xmlsts = FILE_EXT2;
- break;
- case FILE_EXT2_NoTail:
- if (strcmp(name, "NoTail") == 0)
- xar->xmlsts = FILE_EXT2;
- break;
- case FILE_EXT2_DirSync:
- if (strcmp(name, "DirSync") == 0)
- xar->xmlsts = FILE_EXT2;
- break;
- case FILE_EXT2_TopDir:
- if (strcmp(name, "TopDir") == 0)
- xar->xmlsts = FILE_EXT2;
- break;
- case FILE_EXT2_Reserved:
- if (strcmp(name, "Reserved") == 0)
- xar->xmlsts = FILE_EXT2;
- break;
- case UNKNOWN:
- unknowntag_end(xar, name);
- break;
- }
-}
-
-static const int base64[256] = {
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, /* 00 - 0F */
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, /* 10 - 1F */
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 62, -1, -1, -1, 63, /* 20 - 2F */
- 52, 53, 54, 55, 56, 57, 58, 59,
- 60, 61, -1, -1, -1, -1, -1, -1, /* 30 - 3F */
- -1, 0, 1, 2, 3, 4, 5, 6,
- 7, 8, 9, 10, 11, 12, 13, 14, /* 40 - 4F */
- 15, 16, 17, 18, 19, 20, 21, 22,
- 23, 24, 25, -1, -1, -1, -1, -1, /* 50 - 5F */
- -1, 26, 27, 28, 29, 30, 31, 32,
- 33, 34, 35, 36, 37, 38, 39, 40, /* 60 - 6F */
- 41, 42, 43, 44, 45, 46, 47, 48,
- 49, 50, 51, -1, -1, -1, -1, -1, /* 70 - 7F */
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, /* 80 - 8F */
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, /* 90 - 9F */
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, /* A0 - AF */
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, /* B0 - BF */
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, /* C0 - CF */
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, /* D0 - DF */
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, /* E0 - EF */
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, /* F0 - FF */
-};
-
-static void
-strappend_base64(struct xar *xar,
- struct archive_string *as, const char *s, size_t l)
-{
- unsigned char buff[256];
- unsigned char *out;
- const unsigned char *b;
- size_t len;
-
- (void)xar; /* UNUSED */
- len = 0;
- out = buff;
- b = (const unsigned char *)s;
- while (l > 0) {
- int n = 0;
-
- if (l > 0) {
- if (base64[b[0]] < 0 || base64[b[1]] < 0)
- break;
- n = base64[*b++] << 18;
- n |= base64[*b++] << 12;
- *out++ = n >> 16;
- len++;
- l -= 2;
- }
- if (l > 0) {
- if (base64[*b] < 0)
- break;
- n |= base64[*b++] << 6;
- *out++ = (n >> 8) & 0xFF;
- len++;
- --l;
- }
- if (l > 0) {
- if (base64[*b] < 0)
- break;
- n |= base64[*b++];
- *out++ = n & 0xFF;
- len++;
- --l;
- }
- if (len+3 >= sizeof(buff)) {
- archive_strncat(as, (const char *)buff, len);
- len = 0;
- out = buff;
- }
- }
- if (len > 0)
- archive_strncat(as, (const char *)buff, len);
-}
-
-static void
-xml_data(void *userData, const char *s, int len)
-{
- struct archive_read *a;
- struct xar *xar;
-
- a = (struct archive_read *)userData;
- xar = (struct xar *)(a->format->data);
-
-#if DEBUG
- {
- char buff[1024];
- if (len > sizeof(buff)-1)
- len = sizeof(buff)-1;
- memcpy(buff, s, len);
- buff[len] = 0;
- fprintf(stderr, "\tlen=%d:\"%s\"\n", len, buff);
- }
-#endif
- switch (xar->xmlsts) {
- case TOC_CHECKSUM_OFFSET:
- xar->toc_chksum_offset = atol10(s, len);
- break;
- case TOC_CHECKSUM_SIZE:
- xar->toc_chksum_size = atol10(s, len);
- break;
- default:
- break;
- }
- if (xar->file == NULL)
- return;
-
- switch (xar->xmlsts) {
- case FILE_NAME:
- if (xar->file->parent != NULL) {
- archive_string_concat(&(xar->file->pathname),
- &(xar->file->parent->pathname));
- archive_strappend_char(&(xar->file->pathname), '/');
- }
- xar->file->has |= HAS_PATHNAME;
- if (xar->base64text) {
- strappend_base64(xar,
- &(xar->file->pathname), s, len);
- } else
- archive_strncat(&(xar->file->pathname), s, len);
- break;
- case FILE_LINK:
- xar->file->has |= HAS_SYMLINK;
- archive_strncpy(&(xar->file->symlink), s, len);
- break;
- case FILE_TYPE:
- if (strncmp("file", s, len) == 0 ||
- strncmp("hardlink", s, len) == 0)
- xar->file->mode =
- (xar->file->mode & ~AE_IFMT) | AE_IFREG;
- if (strncmp("directory", s, len) == 0)
- xar->file->mode =
- (xar->file->mode & ~AE_IFMT) | AE_IFDIR;
- if (strncmp("symlink", s, len) == 0)
- xar->file->mode =
- (xar->file->mode & ~AE_IFMT) | AE_IFLNK;
- if (strncmp("character special", s, len) == 0)
- xar->file->mode =
- (xar->file->mode & ~AE_IFMT) | AE_IFCHR;
- if (strncmp("block special", s, len) == 0)
- xar->file->mode =
- (xar->file->mode & ~AE_IFMT) | AE_IFBLK;
- if (strncmp("socket", s, len) == 0)
- xar->file->mode =
- (xar->file->mode & ~AE_IFMT) | AE_IFSOCK;
- if (strncmp("fifo", s, len) == 0)
- xar->file->mode =
- (xar->file->mode & ~AE_IFMT) | AE_IFIFO;
- xar->file->has |= HAS_TYPE;
- break;
- case FILE_INODE:
- xar->file->has |= HAS_INO;
- xar->file->ino64 = atol10(s, len);
- break;
- case FILE_DEVICE_MAJOR:
- xar->file->has |= HAS_DEVMAJOR;
- xar->file->devmajor = (dev_t)atol10(s, len);
- break;
- case FILE_DEVICE_MINOR:
- xar->file->has |= HAS_DEVMINOR;
- xar->file->devminor = (dev_t)atol10(s, len);
- break;
- case FILE_DEVICENO:
- xar->file->has |= HAS_DEV;
- xar->file->dev = (dev_t)atol10(s, len);
- break;
- case FILE_MODE:
- xar->file->has |= HAS_MODE;
- xar->file->mode =
- (xar->file->mode & AE_IFMT) |
- ((mode_t)(atol8(s, len)) & ~AE_IFMT);
- break;
- case FILE_GROUP:
- xar->file->has |= HAS_GID;
- archive_strncpy(&(xar->file->gname), s, len);
- break;
- case FILE_GID:
- xar->file->has |= HAS_GID;
- xar->file->gid = atol10(s, len);
- break;
- case FILE_USER:
- xar->file->has |= HAS_UID;
- archive_strncpy(&(xar->file->uname), s, len);
- break;
- case FILE_UID:
- xar->file->has |= HAS_UID;
- xar->file->uid = atol10(s, len);
- break;
- case FILE_CTIME:
- xar->file->has |= HAS_TIME;
- xar->file->ctime = parse_time(s, len);
- break;
- case FILE_MTIME:
- xar->file->has |= HAS_TIME;
- xar->file->mtime = parse_time(s, len);
- break;
- case FILE_ATIME:
- xar->file->has |= HAS_TIME;
- xar->file->atime = parse_time(s, len);
- break;
- case FILE_DATA_LENGTH:
- xar->file->has |= HAS_DATA;
- xar->file->length = atol10(s, len);
- break;
- case FILE_DATA_OFFSET:
- xar->file->has |= HAS_DATA;
- xar->file->offset = atol10(s, len);
- break;
- case FILE_DATA_SIZE:
- xar->file->has |= HAS_DATA;
- xar->file->size = atol10(s, len);
- break;
- case FILE_DATA_A_CHECKSUM:
- xar->file->a_sum.len = atohex(xar->file->a_sum.val,
- sizeof(xar->file->a_sum.val), s, len);
- break;
- case FILE_DATA_E_CHECKSUM:
- xar->file->e_sum.len = atohex(xar->file->e_sum.val,
- sizeof(xar->file->e_sum.val), s, len);
- break;
- case FILE_EA_LENGTH:
- xar->file->has |= HAS_XATTR;
- xar->xattr->length = atol10(s, len);
- break;
- case FILE_EA_OFFSET:
- xar->file->has |= HAS_XATTR;
- xar->xattr->offset = atol10(s, len);
- break;
- case FILE_EA_SIZE:
- xar->file->has |= HAS_XATTR;
- xar->xattr->size = atol10(s, len);
- break;
- case FILE_EA_A_CHECKSUM:
- xar->file->has |= HAS_XATTR;
- xar->xattr->a_sum.len = atohex(xar->xattr->a_sum.val,
- sizeof(xar->xattr->a_sum.val), s, len);
- break;
- case FILE_EA_E_CHECKSUM:
- xar->file->has |= HAS_XATTR;
- xar->xattr->e_sum.len = atohex(xar->xattr->e_sum.val,
- sizeof(xar->xattr->e_sum.val), s, len);
- break;
- case FILE_EA_NAME:
- xar->file->has |= HAS_XATTR;
- archive_strncpy(&(xar->xattr->name), s, len);
- break;
- case FILE_EA_FSTYPE:
- xar->file->has |= HAS_XATTR;
- archive_strncpy(&(xar->xattr->fstype), s, len);
- break;
- break;
- case FILE_ACL_DEFAULT:
- case FILE_ACL_ACCESS:
- case FILE_ACL_APPLEEXTENDED:
- xar->file->has |= HAS_ACL;
- /* TODO */
- break;
- case INIT:
- case XAR:
- case TOC:
- case TOC_CREATION_TIME:
- case TOC_CHECKSUM:
- case TOC_CHECKSUM_OFFSET:
- case TOC_CHECKSUM_SIZE:
- case TOC_FILE:
- case FILE_DATA:
- case FILE_DATA_ENCODING:
- case FILE_DATA_CONTENT:
- case FILE_DEVICE:
- case FILE_EA:
- case FILE_EA_ENCODING:
- case FILE_ACL:
- case FILE_FLAGS:
- case FILE_FLAGS_USER_NODUMP:
- case FILE_FLAGS_USER_IMMUTABLE:
- case FILE_FLAGS_USER_APPEND:
- case FILE_FLAGS_USER_OPAQUE:
- case FILE_FLAGS_USER_NOUNLINK:
- case FILE_FLAGS_SYS_ARCHIVED:
- case FILE_FLAGS_SYS_IMMUTABLE:
- case FILE_FLAGS_SYS_APPEND:
- case FILE_FLAGS_SYS_NOUNLINK:
- case FILE_FLAGS_SYS_SNAPSHOT:
- case FILE_EXT2:
- case FILE_EXT2_SecureDeletion:
- case FILE_EXT2_Undelete:
- case FILE_EXT2_Compress:
- case FILE_EXT2_Synchronous:
- case FILE_EXT2_Immutable:
- case FILE_EXT2_AppendOnly:
- case FILE_EXT2_NoDump:
- case FILE_EXT2_NoAtime:
- case FILE_EXT2_CompDirty:
- case FILE_EXT2_CompBlock:
- case FILE_EXT2_NoCompBlock:
- case FILE_EXT2_CompError:
- case FILE_EXT2_BTree:
- case FILE_EXT2_HashIndexed:
- case FILE_EXT2_iMagic:
- case FILE_EXT2_Journaled:
- case FILE_EXT2_NoTail:
- case FILE_EXT2_DirSync:
- case FILE_EXT2_TopDir:
- case FILE_EXT2_Reserved:
- case UNKNOWN:
- break;
- }
-}
-
-/*
- * BSD file flags.
- */
-static int
-xml_parse_file_flags(struct xar *xar, const char *name)
-{
- const char *flag = NULL;
-
- if (strcmp(name, "UserNoDump") == 0) {
- xar->xmlsts = FILE_FLAGS_USER_NODUMP;
- flag = "nodump";
- }
- else if (strcmp(name, "UserImmutable") == 0) {
- xar->xmlsts = FILE_FLAGS_USER_IMMUTABLE;
- flag = "uimmutable";
- }
- else if (strcmp(name, "UserAppend") == 0) {
- xar->xmlsts = FILE_FLAGS_USER_APPEND;
- flag = "uappend";
- }
- else if (strcmp(name, "UserOpaque") == 0) {
- xar->xmlsts = FILE_FLAGS_USER_OPAQUE;
- flag = "opaque";
- }
- else if (strcmp(name, "UserNoUnlink") == 0) {
- xar->xmlsts = FILE_FLAGS_USER_NOUNLINK;
- flag = "nouunlink";
- }
- else if (strcmp(name, "SystemArchived") == 0) {
- xar->xmlsts = FILE_FLAGS_SYS_ARCHIVED;
- flag = "archived";
- }
- else if (strcmp(name, "SystemImmutable") == 0) {
- xar->xmlsts = FILE_FLAGS_SYS_IMMUTABLE;
- flag = "simmutable";
- }
- else if (strcmp(name, "SystemAppend") == 0) {
- xar->xmlsts = FILE_FLAGS_SYS_APPEND;
- flag = "sappend";
- }
- else if (strcmp(name, "SystemNoUnlink") == 0) {
- xar->xmlsts = FILE_FLAGS_SYS_NOUNLINK;
- flag = "nosunlink";
- }
- else if (strcmp(name, "SystemSnapshot") == 0) {
- xar->xmlsts = FILE_FLAGS_SYS_SNAPSHOT;
- flag = "snapshot";
- }
-
- if (flag == NULL)
- return (0);
- xar->file->has |= HAS_FFLAGS;
- if (archive_strlen(&(xar->file->fflags_text)) > 0)
- archive_strappend_char(&(xar->file->fflags_text), ',');
- archive_strcat(&(xar->file->fflags_text), flag);
- return (1);
-}
-
-/*
- * Linux file flags.
- */
-static int
-xml_parse_file_ext2(struct xar *xar, const char *name)
-{
- const char *flag = NULL;
-
- if (strcmp(name, "SecureDeletion") == 0) {
- xar->xmlsts = FILE_EXT2_SecureDeletion;
- flag = "securedeletion";
- }
- else if (strcmp(name, "Undelete") == 0) {
- xar->xmlsts = FILE_EXT2_Undelete;
- flag = "nouunlink";
- }
- else if (strcmp(name, "Compress") == 0) {
- xar->xmlsts = FILE_EXT2_Compress;
- flag = "compress";
- }
- else if (strcmp(name, "Synchronous") == 0) {
- xar->xmlsts = FILE_EXT2_Synchronous;
- flag = "sync";
- }
- else if (strcmp(name, "Immutable") == 0) {
- xar->xmlsts = FILE_EXT2_Immutable;
- flag = "simmutable";
- }
- else if (strcmp(name, "AppendOnly") == 0) {
- xar->xmlsts = FILE_EXT2_AppendOnly;
- flag = "sappend";
- }
- else if (strcmp(name, "NoDump") == 0) {
- xar->xmlsts = FILE_EXT2_NoDump;
- flag = "nodump";
- }
- else if (strcmp(name, "NoAtime") == 0) {
- xar->xmlsts = FILE_EXT2_NoAtime;
- flag = "noatime";
- }
- else if (strcmp(name, "CompDirty") == 0) {
- xar->xmlsts = FILE_EXT2_CompDirty;
- flag = "compdirty";
- }
- else if (strcmp(name, "CompBlock") == 0) {
- xar->xmlsts = FILE_EXT2_CompBlock;
- flag = "comprblk";
- }
- else if (strcmp(name, "NoCompBlock") == 0) {
- xar->xmlsts = FILE_EXT2_NoCompBlock;
- flag = "nocomprblk";
- }
- else if (strcmp(name, "CompError") == 0) {
- xar->xmlsts = FILE_EXT2_CompError;
- flag = "comperr";
- }
- else if (strcmp(name, "BTree") == 0) {
- xar->xmlsts = FILE_EXT2_BTree;
- flag = "btree";
- }
- else if (strcmp(name, "HashIndexed") == 0) {
- xar->xmlsts = FILE_EXT2_HashIndexed;
- flag = "hashidx";
- }
- else if (strcmp(name, "iMagic") == 0) {
- xar->xmlsts = FILE_EXT2_iMagic;
- flag = "imagic";
- }
- else if (strcmp(name, "Journaled") == 0) {
- xar->xmlsts = FILE_EXT2_Journaled;
- flag = "journal";
- }
- else if (strcmp(name, "NoTail") == 0) {
- xar->xmlsts = FILE_EXT2_NoTail;
- flag = "notail";
- }
- else if (strcmp(name, "DirSync") == 0) {
- xar->xmlsts = FILE_EXT2_DirSync;
- flag = "dirsync";
- }
- else if (strcmp(name, "TopDir") == 0) {
- xar->xmlsts = FILE_EXT2_TopDir;
- flag = "topdir";
- }
- else if (strcmp(name, "Reserved") == 0) {
- xar->xmlsts = FILE_EXT2_Reserved;
- flag = "reserved";
- }
-
- if (flag == NULL)
- return (0);
- if (archive_strlen(&(xar->file->fflags_text)) > 0)
- archive_strappend_char(&(xar->file->fflags_text), ',');
- archive_strcat(&(xar->file->fflags_text), flag);
- return (1);
-}
-
-#ifdef HAVE_LIBXML_XMLREADER_H
-
-static int
-xml2_xmlattr_setup(struct archive_read *a,
- struct xmlattr_list *list, xmlTextReaderPtr reader)
-{
- struct xmlattr *attr;
- int r;
-
- list->first = NULL;
- list->last = &(list->first);
- r = xmlTextReaderMoveToFirstAttribute(reader);
- while (r == 1) {
- attr = malloc(sizeof*(attr));
- if (attr == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- attr->name = strdup(
- (const char *)xmlTextReaderConstLocalName(reader));
- if (attr->name == NULL) {
- free(attr);
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- attr->value = strdup(
- (const char *)xmlTextReaderConstValue(reader));
- if (attr->value == NULL) {
- free(attr->name);
- free(attr);
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- attr->next = NULL;
- *list->last = attr;
- list->last = &(attr->next);
- r = xmlTextReaderMoveToNextAttribute(reader);
- }
- return (r);
-}
-
-static int
-xml2_read_cb(void *context, char *buffer, int len)
-{
- struct archive_read *a;
- struct xar *xar;
- const void *d;
- size_t outbytes;
- size_t used;
- int r;
-
- a = (struct archive_read *)context;
- xar = (struct xar *)(a->format->data);
-
- if (xar->toc_remaining <= 0)
- return (0);
- d = buffer;
- outbytes = len;
- r = rd_contents(a, &d, &outbytes, &used, xar->toc_remaining);
- if (r != ARCHIVE_OK)
- return (r);
- __archive_read_consume(a, used);
- xar->toc_remaining -= used;
- xar->offset += used;
- xar->toc_total += outbytes;
- PRINT_TOC(buffer, len);
-
- return ((int)outbytes);
-}
-
-static int
-xml2_close_cb(void *context)
-{
-
- (void)context; /* UNUSED */
- return (0);
-}
-
-static void
-xml2_error_hdr(void *arg, const char *msg, xmlParserSeverities severity,
- xmlTextReaderLocatorPtr locator)
-{
- struct archive_read *a;
-
- (void)locator; /* UNUSED */
- a = (struct archive_read *)arg;
- switch (severity) {
- case XML_PARSER_SEVERITY_VALIDITY_WARNING:
- case XML_PARSER_SEVERITY_WARNING:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "XML Parsing error: %s", msg);
- break;
- case XML_PARSER_SEVERITY_VALIDITY_ERROR:
- case XML_PARSER_SEVERITY_ERROR:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "XML Parsing error: %s", msg);
- break;
- }
-}
-
-static int
-xml2_read_toc(struct archive_read *a)
-{
- xmlTextReaderPtr reader;
- struct xmlattr_list list;
- int r;
-
- reader = xmlReaderForIO(xml2_read_cb, xml2_close_cb, a, NULL, NULL, 0);
- if (reader == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Couldn't allocate memory for xml parser");
- return (ARCHIVE_FATAL);
- }
- xmlTextReaderSetErrorHandler(reader, xml2_error_hdr, a);
-
- while ((r = xmlTextReaderRead(reader)) == 1) {
- const char *name, *value;
- int type, empty;
-
- type = xmlTextReaderNodeType(reader);
- name = (const char *)xmlTextReaderConstLocalName(reader);
- switch (type) {
- case XML_READER_TYPE_ELEMENT:
- empty = xmlTextReaderIsEmptyElement(reader);
- r = xml2_xmlattr_setup(a, &list, reader);
- if (r != ARCHIVE_OK)
- return (r);
- r = xml_start(a, name, &list);
- xmlattr_cleanup(&list);
- if (r != ARCHIVE_OK)
- return (r);
- if (empty)
- xml_end(a, name);
- break;
- case XML_READER_TYPE_END_ELEMENT:
- xml_end(a, name);
- break;
- case XML_READER_TYPE_TEXT:
- value = (const char *)xmlTextReaderConstValue(reader);
- xml_data(a, value, strlen(value));
- break;
- case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
- default:
- break;
- }
- if (r < 0)
- break;
- }
- xmlFreeTextReader(reader);
- xmlCleanupParser();
-
- return ((r == 0)?ARCHIVE_OK:ARCHIVE_FATAL);
-}
-
-#elif defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H)
-
-static int
-expat_xmlattr_setup(struct archive_read *a,
- struct xmlattr_list *list, const XML_Char **atts)
-{
- struct xmlattr *attr;
- char *name, *value;
-
- list->first = NULL;
- list->last = &(list->first);
- if (atts == NULL)
- return (ARCHIVE_OK);
- while (atts[0] != NULL && atts[1] != NULL) {
- attr = malloc(sizeof*(attr));
- name = strdup(atts[0]);
- value = strdup(atts[1]);
- if (attr == NULL || name == NULL || value == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- attr->name = name;
- attr->value = value;
- attr->next = NULL;
- *list->last = attr;
- list->last = &(attr->next);
- atts += 2;
- }
- return (ARCHIVE_OK);
-}
-
-static void
-expat_start_cb(void *userData, const XML_Char *name, const XML_Char **atts)
-{
- struct expat_userData *ud = (struct expat_userData *)userData;
- struct archive_read *a = ud->archive;
- struct xmlattr_list list;
- int r;
-
- r = expat_xmlattr_setup(a, &list, atts);
- if (r == ARCHIVE_OK)
- r = xml_start(a, (const char *)name, &list);
- xmlattr_cleanup(&list);
- ud->state = r;
-}
-
-static void
-expat_end_cb(void *userData, const XML_Char *name)
-{
- struct expat_userData *ud = (struct expat_userData *)userData;
-
- xml_end(ud->archive, (const char *)name);
-}
-
-static void
-expat_data_cb(void *userData, const XML_Char *s, int len)
-{
- struct expat_userData *ud = (struct expat_userData *)userData;
-
- xml_data(ud->archive, s, len);
-}
-
-static int
-expat_read_toc(struct archive_read *a)
-{
- struct xar *xar;
- XML_Parser parser;
- struct expat_userData ud;
-
- ud.state = ARCHIVE_OK;
- ud.archive = a;
-
- xar = (struct xar *)(a->format->data);
-
- /* Initialize XML Parser library. */
- parser = XML_ParserCreate(NULL);
- if (parser == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Couldn't allocate memory for xml parser");
- return (ARCHIVE_FATAL);
- }
- XML_SetUserData(parser, &ud);
- XML_SetElementHandler(parser, expat_start_cb, expat_end_cb);
- XML_SetCharacterDataHandler(parser, expat_data_cb);
- xar->xmlsts = INIT;
-
- while (xar->toc_remaining && ud.state == ARCHIVE_OK) {
- enum XML_Status xr;
- const void *d;
- size_t outbytes;
- size_t used;
- int r;
-
- d = NULL;
- r = rd_contents(a, &d, &outbytes, &used, xar->toc_remaining);
- if (r != ARCHIVE_OK)
- return (r);
- xar->toc_remaining -= used;
- xar->offset += used;
- xar->toc_total += outbytes;
- PRINT_TOC(d, outbytes);
-
- xr = XML_Parse(parser, d, outbytes, xar->toc_remaining == 0);
- __archive_read_consume(a, used);
- if (xr == XML_STATUS_ERROR) {
- XML_ParserFree(parser);
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "XML Parsing failed");
- return (ARCHIVE_FATAL);
- }
- }
- XML_ParserFree(parser);
- return (ud.state);
-}
-#endif /* defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H) */
-
-#endif /* Support xar format */
diff --git a/3rdparty/libarchive/libarchive/archive_read_support_format_zip.c b/3rdparty/libarchive/libarchive/archive_read_support_format_zip.c
deleted file mode 100644
index 450a6f7d..00000000
--- a/3rdparty/libarchive/libarchive/archive_read_support_format_zip.c
+++ /dev/null
@@ -1,1742 +0,0 @@
-/*-
- * Copyright (c) 2004 Tim Kientzle
- * Copyright (c) 2011-2012 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"
-__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_zip.c 201102 2009-12-28 03:11:36Z kientzle $");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_ZLIB_H
-#include <zlib.h>
-#endif
-
-#include "archive.h"
-#include "archive_endian.h"
-#include "archive_entry.h"
-#include "archive_entry_locale.h"
-#include "archive_private.h"
-#include "archive_rb.h"
-#include "archive_read_private.h"
-
-#ifndef HAVE_ZLIB_H
-#include "archive_crc32.h"
-#endif
-
-struct zip_entry {
- struct archive_rb_node node;
- int64_t local_header_offset;
- int64_t compressed_size;
- int64_t uncompressed_size;
- int64_t gid;
- int64_t uid;
- struct archive_entry *entry;
- struct archive_string rsrcname;
- time_t mtime;
- time_t atime;
- time_t ctime;
- uint32_t crc32;
- uint16_t mode;
- uint16_t flags;
- char compression;
- char system;
-};
-
-struct zip {
- /* Structural information about the archive. */
- int64_t end_of_central_directory_offset;
- int64_t central_directory_offset;
- size_t central_directory_size;
- size_t central_directory_entries;
- char have_central_directory;
- int64_t offset;
-
- /* List of entries (seekable Zip only) */
- size_t entries_remaining;
- struct zip_entry *zip_entries;
- struct zip_entry *entry;
- struct archive_rb_tree tree;
- struct archive_rb_tree tree_rsrc;
-
- size_t unconsumed;
-
- /* entry_bytes_remaining is the number of bytes we expect. */
- int64_t entry_bytes_remaining;
-
- /* These count the number of bytes actually read for the entry. */
- int64_t entry_compressed_bytes_read;
- int64_t entry_uncompressed_bytes_read;
-
- /* Running CRC32 of the decompressed data */
- unsigned long entry_crc32;
-
- /* Flags to mark progress of decompression. */
- char decompress_init;
- char end_of_entry;
-
- ssize_t filename_length;
- ssize_t extra_length;
-
- unsigned char *uncompressed_buffer;
- size_t uncompressed_buffer_size;
-#ifdef HAVE_ZLIB_H
- z_stream stream;
- char stream_valid;
-#endif
-
- struct archive_string extra;
- struct archive_string_conv *sconv;
- struct archive_string_conv *sconv_default;
- struct archive_string_conv *sconv_utf8;
- int init_default_conversion;
- char format_name[64];
-};
-
-#define ZIP_LENGTH_AT_END 8
-#define ZIP_ENCRYPTED (1<<0)
-#define ZIP_STRONG_ENCRYPTED (1<<6)
-#define ZIP_UTF8_NAME (1<<11)
-
-static int archive_read_format_zip_streamable_bid(struct archive_read *,
- int);
-static int archive_read_format_zip_seekable_bid(struct archive_read *,
- int);
-static int archive_read_format_zip_options(struct archive_read *,
- const char *, const char *);
-static int archive_read_format_zip_cleanup(struct archive_read *);
-static int archive_read_format_zip_read_data(struct archive_read *,
- const void **, size_t *, int64_t *);
-static int archive_read_format_zip_read_data_skip(struct archive_read *a);
-static int archive_read_format_zip_seekable_read_header(
- struct archive_read *, struct archive_entry *);
-static int archive_read_format_zip_streamable_read_header(
- struct archive_read *, struct archive_entry *);
-static ssize_t zip_get_local_file_header_size(struct archive_read *, size_t);
-#ifdef HAVE_ZLIB_H
-static int zip_deflate_init(struct archive_read *, struct zip *);
-static int zip_read_data_deflate(struct archive_read *a, const void **buff,
- size_t *size, int64_t *offset);
-#endif
-static int zip_read_data_none(struct archive_read *a, const void **buff,
- size_t *size, int64_t *offset);
-static int zip_read_local_file_header(struct archive_read *a,
- struct archive_entry *entry, struct zip *);
-static time_t zip_time(const char *);
-static const char *compression_name(int compression);
-static void process_extra(const char *, size_t, struct zip_entry *);
-
-int archive_read_support_format_zip_streamable(struct archive *);
-int archive_read_support_format_zip_seekable(struct archive *);
-
-int
-archive_read_support_format_zip_streamable(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct zip *zip;
- int r;
-
- archive_check_magic(_a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_NEW, "archive_read_support_format_zip");
-
- zip = (struct zip *)malloc(sizeof(*zip));
- if (zip == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate zip data");
- return (ARCHIVE_FATAL);
- }
- memset(zip, 0, sizeof(*zip));
-
- r = __archive_read_register_format(a,
- zip,
- "zip",
- archive_read_format_zip_streamable_bid,
- archive_read_format_zip_options,
- archive_read_format_zip_streamable_read_header,
- archive_read_format_zip_read_data,
- archive_read_format_zip_read_data_skip,
- NULL,
- archive_read_format_zip_cleanup);
-
- if (r != ARCHIVE_OK)
- free(zip);
- return (ARCHIVE_OK);
-}
-
-int
-archive_read_support_format_zip_seekable(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct zip *zip;
- int r;
-
- archive_check_magic(_a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_NEW, "archive_read_support_format_zip_seekable");
-
- zip = (struct zip *)malloc(sizeof(*zip));
- if (zip == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate zip data");
- return (ARCHIVE_FATAL);
- }
- memset(zip, 0, sizeof(*zip));
-
- r = __archive_read_register_format(a,
- zip,
- "zip",
- archive_read_format_zip_seekable_bid,
- archive_read_format_zip_options,
- archive_read_format_zip_seekable_read_header,
- archive_read_format_zip_read_data,
- archive_read_format_zip_read_data_skip,
- NULL,
- archive_read_format_zip_cleanup);
-
- if (r != ARCHIVE_OK)
- free(zip);
- return (ARCHIVE_OK);
-}
-
-int
-archive_read_support_format_zip(struct archive *a)
-{
- int r;
- r = archive_read_support_format_zip_streamable(a);
- if (r != ARCHIVE_OK)
- return r;
- return (archive_read_support_format_zip_seekable(a));
-}
-
-/*
- * TODO: This is a performance sink because it forces the read core to
- * drop buffered data from the start of file, which will then have to
- * be re-read again if this bidder loses.
- *
- * We workaround this a little by passing in the best bid so far so
- * that later bidders can do nothing if they know they'll never
- * outbid. But we can certainly do better...
- */
-static int
-archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid)
-{
- struct zip *zip = (struct zip *)a->format->data;
- int64_t filesize;
- const char *p;
-
- /* If someone has already bid more than 32, then avoid
- trashing the look-ahead buffers with a seek. */
- if (best_bid > 32)
- return (-1);
-
- filesize = __archive_read_seek(a, -22, SEEK_END);
- /* If we can't seek, then we can't bid. */
- if (filesize <= 0)
- return 0;
-
- /* TODO: More robust search for end of central directory record. */
- if ((p = __archive_read_ahead(a, 22, NULL)) == NULL)
- return 0;
- /* First four bytes are signature for end of central directory
- record. Four zero bytes ensure this isn't a multi-volume
- Zip file (which we don't yet support). */
- if (memcmp(p, "PK\005\006\000\000\000\000", 8) != 0) {
- int64_t i, tail;
- int found;
-
- /*
- * If there is a comment in end of central directory
- * record, 22 bytes are too short. we have to read more
- * to properly detect the record. Hopefully, a length
- * of the comment is not longer than 16362 bytes(16K-22).
- */
- if (filesize + 22 > 1024 * 16) {
- tail = 1024 * 16;
- filesize = __archive_read_seek(a, tail * -1, SEEK_END);
- } else {
- tail = filesize + 22;
- filesize = __archive_read_seek(a, 0, SEEK_SET);
- }
- if (filesize < 0)
- return 0;
- if ((p = __archive_read_ahead(a, (size_t)tail, NULL)) == NULL)
- return 0;
- for (found = 0, i = 0;!found && i < tail - 22;) {
- switch (p[i]) {
- case 'P':
- if (memcmp(p+i,
- "PK\005\006\000\000\000\000", 8) == 0) {
- p += i;
- filesize += tail -
- (22 + archive_le16dec(p+20));
- found = 1;
- } else
- i += 8;
- break;
- case 'K': i += 7; break;
- case 005: i += 6; break;
- case 006: i += 5; break;
- default: i += 1; break;
- }
- }
- if (!found)
- return 0;
- }
-
- /* Since we've already done the hard work of finding the
- end of central directory record, let's save the important
- information. */
- zip->central_directory_entries = archive_le16dec(p + 10);
- zip->central_directory_size = archive_le32dec(p + 12);
- zip->central_directory_offset = archive_le32dec(p + 16);
- zip->end_of_central_directory_offset = filesize;
-
- /* Just one volume, so central dir must all be on this volume. */
- if (zip->central_directory_entries != archive_le16dec(p + 8))
- return 0;
- /* Central directory can't extend beyond end of this file. */
- if (zip->central_directory_offset +
- (int64_t)zip->central_directory_size > filesize)
- return 0;
-
- /* This is just a tiny bit higher than the maximum returned by
- the streaming Zip bidder. This ensures that the more accurate
- seeking Zip parser wins whenever seek is available. */
- return 32;
-}
-
-static int
-cmp_node(const struct archive_rb_node *n1, const struct archive_rb_node *n2)
-{
- const struct zip_entry *e1 = (const struct zip_entry *)n1;
- const struct zip_entry *e2 = (const struct zip_entry *)n2;
-
- return ((int)(e2->local_header_offset - e1->local_header_offset));
-}
-
-static int
-cmp_key(const struct archive_rb_node *n, const void *key)
-{
- /* This function won't be called */
- (void)n; /* UNUSED */
- (void)key; /* UNUSED */
- return 1;
-}
-
-static int
-rsrc_cmp_node(const struct archive_rb_node *n1,
- const struct archive_rb_node *n2)
-{
- const struct zip_entry *e1 = (const struct zip_entry *)n1;
- const struct zip_entry *e2 = (const struct zip_entry *)n2;
-
- return (strcmp(e2->rsrcname.s, e1->rsrcname.s));
-}
-
-static int
-rsrc_cmp_key(const struct archive_rb_node *n, const void *key)
-{
- const struct zip_entry *e = (const struct zip_entry *)n;
- return (strcmp((const char *)key, e->rsrcname.s));
-}
-
-static const char *
-rsrc_basename(const char *name, size_t name_length)
-{
- const char *s, *r;
-
- r = s = name;
- for (;;) {
- s = memchr(s, '/', name_length - (s - name));
- if (s == NULL)
- break;
- r = ++s;
- }
- return (r);
-}
-
-static void
-expose_parent_dirs(struct zip *zip, const char *name, size_t name_length)
-{
- struct archive_string str;
- struct zip_entry *dir;
- char *s;
-
- archive_string_init(&str);
- archive_strncpy(&str, name, name_length);
- for (;;) {
- s = strrchr(str.s, '/');
- if (s == NULL)
- break;
- *s = '\0';
- /* Transfer the parent directory from zip->tree_rsrc RB
- * tree to zip->tree RB tree to expose. */
- dir = (struct zip_entry *)
- __archive_rb_tree_find_node(&zip->tree_rsrc, str.s);
- if (dir == NULL)
- break;
- __archive_rb_tree_remove_node(&zip->tree_rsrc, &dir->node);
- archive_string_free(&dir->rsrcname);
- __archive_rb_tree_insert_node(&zip->tree, &dir->node);
- }
- archive_string_free(&str);
-}
-
-static int
-slurp_central_directory(struct archive_read *a, struct zip *zip)
-{
- unsigned i;
- int64_t correction;
- static const struct archive_rb_tree_ops rb_ops = {
- &cmp_node, &cmp_key
- };
- static const struct archive_rb_tree_ops rb_rsrc_ops = {
- &rsrc_cmp_node, &rsrc_cmp_key
- };
-
- /*
- * Consider the archive file we are reading may be SFX.
- * So we have to calculate a SFX header size to revise
- * ZIP header offsets.
- */
- correction = zip->end_of_central_directory_offset -
- (zip->central_directory_offset + zip->central_directory_size);
- /* The central directory offset is relative value, and so
- * we revise this offset for SFX. */
- zip->central_directory_offset += correction;
-
- __archive_read_seek(a, zip->central_directory_offset, SEEK_SET);
- zip->offset = zip->central_directory_offset;
- __archive_rb_tree_init(&zip->tree, &rb_ops);
- __archive_rb_tree_init(&zip->tree_rsrc, &rb_rsrc_ops);
-
- zip->zip_entries = calloc(zip->central_directory_entries,
- sizeof(struct zip_entry));
- for (i = 0; i < zip->central_directory_entries; ++i) {
- struct zip_entry *zip_entry = &zip->zip_entries[i];
- size_t filename_length, extra_length, comment_length;
- uint32_t external_attributes;
- const char *name, *p, *r;
-
- if ((p = __archive_read_ahead(a, 46, NULL)) == NULL)
- return ARCHIVE_FATAL;
- if (memcmp(p, "PK\001\002", 4) != 0) {
- archive_set_error(&a->archive,
- -1, "Invalid central directory signature");
- return ARCHIVE_FATAL;
- }
- zip->have_central_directory = 1;
- /* version = p[4]; */
- zip_entry->system = p[5];
- /* version_required = archive_le16dec(p + 6); */
- zip_entry->flags = archive_le16dec(p + 8);
- zip_entry->compression = (char)archive_le16dec(p + 10);
- zip_entry->mtime = zip_time(p + 12);
- zip_entry->crc32 = archive_le32dec(p + 16);
- zip_entry->compressed_size = archive_le32dec(p + 20);
- zip_entry->uncompressed_size = archive_le32dec(p + 24);
- filename_length = archive_le16dec(p + 28);
- extra_length = archive_le16dec(p + 30);
- comment_length = archive_le16dec(p + 32);
- /* disk_start = archive_le16dec(p + 34); */ /* Better be zero. */
- /* internal_attributes = archive_le16dec(p + 36); */ /* text bit */
- external_attributes = archive_le32dec(p + 38);
- zip_entry->local_header_offset =
- archive_le32dec(p + 42) + correction;
-
- /* If we can't guess the mode, leave it zero here;
- when we read the local file header we might get
- more information. */
- zip_entry->mode = 0;
- if (zip_entry->system == 3) {
- zip_entry->mode = external_attributes >> 16;
- }
-
- /*
- * Mac resource fork files are stored under the
- * "__MACOSX/" directory, so we should check if
- * it is.
- */
- /* Make sure we have the file name. */
- if ((p = __archive_read_ahead(a, 46 + filename_length, NULL))
- == NULL)
- return ARCHIVE_FATAL;
- name = p + 46;
- r = rsrc_basename(name, filename_length);
- if (filename_length >= 9 &&
- strncmp("__MACOSX/", name, 9) == 0) {
- /* If this file is not a resource fork nor
- * a directory. We should treat it as a non
- * resource fork file to expose it. */
- if (name[filename_length-1] != '/' &&
- (r - name < 3 || r[0] != '.' || r[1] != '_')) {
- __archive_rb_tree_insert_node(&zip->tree,
- &zip_entry->node);
- /* Expose its parent directories. */
- expose_parent_dirs(zip, name, filename_length);
- } else {
- /* This file is a resource fork file or
- * a directory. */
- archive_strncpy(&(zip_entry->rsrcname), name,
- filename_length);
- __archive_rb_tree_insert_node(&zip->tree_rsrc,
- &zip_entry->node);
- }
- } else {
- /* Generate resource fork name to find its resource
- * file at zip->tree_rsrc. */
- archive_strcpy(&(zip_entry->rsrcname), "__MACOSX/");
- archive_strncat(&(zip_entry->rsrcname), name, r - name);
- archive_strcat(&(zip_entry->rsrcname), "._");
- archive_strncat(&(zip_entry->rsrcname),
- name + (r - name), filename_length - (r - name));
- /* Register an entry to RB tree to sort it by
- * file offset. */
- __archive_rb_tree_insert_node(&zip->tree,
- &zip_entry->node);
- }
-
- /* We don't read the filename until we get to the
- local file header. Reading it here would speed up
- table-of-contents operations (removing the need to
- find and read local file header to get the
- filename) at the cost of requiring a lot of extra
- space. */
- /* We don't read the extra block here. We assume it
- will be duplicated at the local file header. */
- __archive_read_consume(a,
- 46 + filename_length + extra_length + comment_length);
- }
-
- return ARCHIVE_OK;
-}
-
-static int64_t
-zip_read_consume(struct archive_read *a, int64_t bytes)
-{
- struct zip *zip = (struct zip *)a->format->data;
- int64_t skip;
-
- skip = __archive_read_consume(a, bytes);
- if (skip > 0)
- zip->offset += skip;
- return (skip);
-}
-
-static int
-zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry,
- struct zip_entry *rsrc)
-{
- struct zip *zip = (struct zip *)a->format->data;
- unsigned char *metadata, *mp;
- int64_t offset = zip->offset;
- size_t remaining_bytes, metadata_bytes;
- ssize_t hsize;
- int ret = ARCHIVE_OK, eof;
-
- switch(rsrc->compression) {
- case 0: /* No compression. */
-#ifdef HAVE_ZLIB_H
- case 8: /* Deflate compression. */
-#endif
- break;
- default: /* Unsupported compression. */
- /* Return a warning. */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Unsupported ZIP compression method (%s)",
- compression_name(rsrc->compression));
- /* We can't decompress this entry, but we will
- * be able to skip() it and try the next entry. */
- return (ARCHIVE_WARN);
- }
-
- if (rsrc->uncompressed_size > (128 * 1024)) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Mac metadata is too large: %jd > 128K bytes",
- (intmax_t)rsrc->uncompressed_size);
- return (ARCHIVE_WARN);
- }
-
- metadata = malloc((size_t)rsrc->uncompressed_size);
- if (metadata == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Mac metadata");
- return (ARCHIVE_FATAL);
- }
-
- if (zip->offset < rsrc->local_header_offset)
- zip_read_consume(a, rsrc->local_header_offset - zip->offset);
- else if (zip->offset != rsrc->local_header_offset) {
- __archive_read_seek(a, rsrc->local_header_offset, SEEK_SET);
- zip->offset = zip->entry->local_header_offset;
- }
-
- hsize = zip_get_local_file_header_size(a, 0);
- zip_read_consume(a, hsize);
-
- remaining_bytes = (size_t)rsrc->compressed_size;
- metadata_bytes = (size_t)rsrc->uncompressed_size;
- mp = metadata;
- eof = 0;
- while (!eof && remaining_bytes) {
- const unsigned char *p;
- ssize_t bytes_avail;
- size_t bytes_used;
-
- p = __archive_read_ahead(a, 1, &bytes_avail);
- if (p == NULL) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated ZIP file header");
- ret = ARCHIVE_WARN;
- goto exit_mac_metadata;
- }
- if ((size_t)bytes_avail > remaining_bytes)
- bytes_avail = remaining_bytes;
- switch(rsrc->compression) {
- case 0: /* No compression. */
- memcpy(mp, p, bytes_avail);
- bytes_used = (size_t)bytes_avail;
- metadata_bytes -= bytes_used;
- mp += bytes_used;
- if (metadata_bytes == 0)
- eof = 1;
- break;
-#ifdef HAVE_ZLIB_H
- case 8: /* Deflate compression. */
- {
- int r;
-
- ret = zip_deflate_init(a, zip);
- if (ret != ARCHIVE_OK)
- goto exit_mac_metadata;
- zip->stream.next_in =
- (Bytef *)(uintptr_t)(const void *)p;
- zip->stream.avail_in = (uInt)bytes_avail;
- zip->stream.total_in = 0;
- zip->stream.next_out = mp;
- zip->stream.avail_out = (uInt)metadata_bytes;
- zip->stream.total_out = 0;
-
- r = inflate(&zip->stream, 0);
- switch (r) {
- case Z_OK:
- break;
- case Z_STREAM_END:
- eof = 1;
- break;
- case Z_MEM_ERROR:
- archive_set_error(&a->archive, ENOMEM,
- "Out of memory for ZIP decompression");
- ret = ARCHIVE_FATAL;
- goto exit_mac_metadata;
- default:
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "ZIP decompression failed (%d)", r);
- ret = ARCHIVE_FATAL;
- goto exit_mac_metadata;
- }
- bytes_used = zip->stream.total_in;
- metadata_bytes -= zip->stream.total_out;
- mp += zip->stream.total_out;
- break;
- }
-#endif
- default:
- bytes_used = 0;
- break;
- }
- zip_read_consume(a, bytes_used);
- remaining_bytes -= bytes_used;
- }
- archive_entry_copy_mac_metadata(entry, metadata,
- (size_t)rsrc->uncompressed_size - metadata_bytes);
-
- __archive_read_seek(a, offset, SEEK_SET);
- zip->offset = offset;
-exit_mac_metadata:
- zip->decompress_init = 0;
- free(metadata);
- return (ret);
-}
-
-static int
-archive_read_format_zip_seekable_read_header(struct archive_read *a,
- struct archive_entry *entry)
-{
- struct zip *zip = (struct zip *)a->format->data;
- struct zip_entry *rsrc;
- int r, ret = ARCHIVE_OK;
-
- a->archive.archive_format = ARCHIVE_FORMAT_ZIP;
- if (a->archive.archive_format_name == NULL)
- a->archive.archive_format_name = "ZIP";
-
- if (zip->zip_entries == NULL) {
- r = slurp_central_directory(a, zip);
- zip->entries_remaining = zip->central_directory_entries;
- if (r != ARCHIVE_OK)
- return r;
- /* Get first entry whose local header offset is lower than
- * other entries in the archive file. */
- zip->entry =
- (struct zip_entry *)ARCHIVE_RB_TREE_MIN(&zip->tree);
- } else if (zip->entry != NULL) {
- /* Get next entry in local header offset order. */
- zip->entry = (struct zip_entry *)__archive_rb_tree_iterate(
- &zip->tree, &zip->entry->node, ARCHIVE_RB_DIR_RIGHT);
- }
-
- if (zip->entries_remaining <= 0 || zip->entry == NULL)
- return ARCHIVE_EOF;
- --zip->entries_remaining;
-
- if (zip->entry->rsrcname.s)
- rsrc = (struct zip_entry *)__archive_rb_tree_find_node(
- &zip->tree_rsrc, zip->entry->rsrcname.s);
- else
- rsrc = NULL;
-
- /* File entries are sorted by the header offset, we should mostly
- * use zip_read_consume to advance a read point to avoid redundant
- * data reading. */
- if (zip->offset < zip->entry->local_header_offset)
- zip_read_consume(a,
- zip->entry->local_header_offset - zip->offset);
- else if (zip->offset != zip->entry->local_header_offset) {
- __archive_read_seek(a, zip->entry->local_header_offset,
- SEEK_SET);
- zip->offset = zip->entry->local_header_offset;
- }
- zip->unconsumed = 0;
- r = zip_read_local_file_header(a, entry, zip);
- if (r != ARCHIVE_OK)
- return r;
- if ((zip->entry->mode & AE_IFMT) == AE_IFLNK) {
- const void *p;
- struct archive_string_conv *sconv;
- size_t linkname_length = (size_t)archive_entry_size(entry);
-
- archive_entry_set_size(entry, 0);
- p = __archive_read_ahead(a, linkname_length, NULL);
- if (p == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Truncated Zip file");
- return ARCHIVE_FATAL;
- }
-
- sconv = zip->sconv;
- if (sconv == NULL && (zip->entry->flags & ZIP_UTF8_NAME))
- sconv = zip->sconv_utf8;
- if (sconv == NULL)
- sconv = zip->sconv_default;
- if (archive_entry_copy_symlink_l(entry, p, linkname_length,
- sconv) != 0) {
- if (errno != ENOMEM && sconv == zip->sconv_utf8 &&
- (zip->entry->flags & ZIP_UTF8_NAME))
- archive_entry_copy_symlink_l(entry, p,
- linkname_length, NULL);
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Symlink");
- return (ARCHIVE_FATAL);
- }
- /*
- * Since there is no character-set regulation for
- * symlink name, do not report the conversion error
- * in an automatic conversion.
- */
- if (sconv != zip->sconv_utf8 ||
- (zip->entry->flags & ZIP_UTF8_NAME) == 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Symlink cannot be converted "
- "from %s to current locale.",
- archive_string_conversion_charset_name(
- sconv));
- ret = ARCHIVE_WARN;
- }
- }
- }
- if (rsrc) {
- int ret2 = zip_read_mac_metadata(a, entry, rsrc);
- if (ret2 < ret)
- ret = ret2;
- }
- return (ret);
-}
-
-static int
-archive_read_format_zip_streamable_bid(struct archive_read *a, int best_bid)
-{
- const char *p;
-
- (void)best_bid; /* UNUSED */
-
- if ((p = __archive_read_ahead(a, 4, NULL)) == NULL)
- return (-1);
-
- /*
- * Bid of 30 here is: 16 bits for "PK",
- * next 16-bit field has four options (-2 bits).
- * 16 + 16-2 = 30.
- */
- if (p[0] == 'P' && p[1] == 'K') {
- if ((p[2] == '\001' && p[3] == '\002')
- || (p[2] == '\003' && p[3] == '\004')
- || (p[2] == '\005' && p[3] == '\006')
- || (p[2] == '\007' && p[3] == '\010')
- || (p[2] == '0' && p[3] == '0'))
- return (30);
- }
-
- /* TODO: It's worth looking ahead a little bit for a valid
- * PK signature. In particular, that would make it possible
- * to read some UUEncoded SFX files or SFX files coming from
- * a network socket. */
-
- return (0);
-}
-
-static int
-archive_read_format_zip_options(struct archive_read *a,
- const char *key, const char *val)
-{
- struct zip *zip;
- int ret = ARCHIVE_FAILED;
-
- zip = (struct zip *)(a->format->data);
- if (strcmp(key, "compat-2x") == 0) {
- /* Handle filnames as libarchive 2.x */
- zip->init_default_conversion = (val != NULL) ? 1 : 0;
- return (ARCHIVE_OK);
- } else if (strcmp(key, "hdrcharset") == 0) {
- if (val == NULL || val[0] == 0)
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "zip: hdrcharset option needs a character-set name"
- );
- else {
- zip->sconv = archive_string_conversion_from_charset(
- &a->archive, val, 0);
- if (zip->sconv != NULL) {
- if (strcmp(val, "UTF-8") == 0)
- zip->sconv_utf8 = zip->sconv;
- ret = ARCHIVE_OK;
- } else
- ret = ARCHIVE_FATAL;
- }
- return (ret);
- }
-
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
-}
-
-static int
-archive_read_format_zip_streamable_read_header(struct archive_read *a,
- struct archive_entry *entry)
-{
- struct zip *zip;
-
- a->archive.archive_format = ARCHIVE_FORMAT_ZIP;
- if (a->archive.archive_format_name == NULL)
- a->archive.archive_format_name = "ZIP";
-
- zip = (struct zip *)(a->format->data);
-
- /* Make sure we have a zip_entry structure to use. */
- if (zip->zip_entries == NULL) {
- zip->zip_entries = malloc(sizeof(struct zip_entry));
- if (zip->zip_entries == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Out of memory");
- return ARCHIVE_FATAL;
- }
- }
- zip->entry = zip->zip_entries;
- memset(zip->entry, 0, sizeof(struct zip_entry));
-
- /* Search ahead for the next local file header. */
- zip_read_consume(a, zip->unconsumed);
- zip->unconsumed = 0;
- for (;;) {
- int64_t skipped = 0;
- const char *p, *end;
- ssize_t bytes;
-
- p = __archive_read_ahead(a, 4, &bytes);
- if (p == NULL)
- return (ARCHIVE_FATAL);
- end = p + bytes;
-
- while (p + 4 <= end) {
- if (p[0] == 'P' && p[1] == 'K') {
- if (p[2] == '\001' && p[3] == '\002')
- /* Beginning of central directory. */
- return (ARCHIVE_EOF);
-
- if (p[2] == '\003' && p[3] == '\004') {
- /* Regular file entry. */
- zip_read_consume(a, skipped);
- return zip_read_local_file_header(a,
- entry, zip);
- }
-
- if (p[2] == '\005' && p[3] == '\006')
- /* End of central directory. */
- return (ARCHIVE_EOF);
- }
- ++p;
- ++skipped;
- }
- zip_read_consume(a, skipped);
- }
-}
-
-static ssize_t
-zip_get_local_file_header_size(struct archive_read *a, size_t extra)
-{
- const char *p;
- ssize_t filename_length, extra_length;
-
- if ((p = __archive_read_ahead(a, extra + 30, NULL)) == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated ZIP file header");
- return (ARCHIVE_WARN);
- }
- p += extra;
-
- if (memcmp(p, "PK\003\004", 4) != 0) {
- archive_set_error(&a->archive, -1, "Damaged Zip archive");
- return ARCHIVE_WARN;
- }
- filename_length = archive_le16dec(p + 26);
- extra_length = archive_le16dec(p + 28);
-
- return (30 + filename_length + extra_length);
-}
-
-/*
- * Assumes file pointer is at beginning of local file header.
- */
-static int
-zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
- struct zip *zip)
-{
- const char *p;
- const void *h;
- const wchar_t *wp;
- const char *cp;
- size_t len, filename_length, extra_length;
- struct archive_string_conv *sconv;
- struct zip_entry *zip_entry = zip->entry;
- uint32_t local_crc32;
- int64_t compressed_size, uncompressed_size;
- int ret = ARCHIVE_OK;
- char version;
-
- zip->decompress_init = 0;
- zip->end_of_entry = 0;
- zip->entry_uncompressed_bytes_read = 0;
- zip->entry_compressed_bytes_read = 0;
- zip->entry_crc32 = crc32(0, NULL, 0);
-
- /* Setup default conversion. */
- if (zip->sconv == NULL && !zip->init_default_conversion) {
- zip->sconv_default =
- archive_string_default_conversion_for_read(&(a->archive));
- zip->init_default_conversion = 1;
- }
-
- if ((p = __archive_read_ahead(a, 30, NULL)) == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated ZIP file header");
- return (ARCHIVE_FATAL);
- }
-
- if (memcmp(p, "PK\003\004", 4) != 0) {
- archive_set_error(&a->archive, -1, "Damaged Zip archive");
- return ARCHIVE_FATAL;
- }
- version = p[4];
- zip_entry->system = p[5];
- zip_entry->flags = archive_le16dec(p + 6);
- zip_entry->compression = (char)archive_le16dec(p + 8);
- zip_entry->mtime = zip_time(p + 10);
- local_crc32 = archive_le32dec(p + 14);
- compressed_size = archive_le32dec(p + 18);
- uncompressed_size = archive_le32dec(p + 22);
- filename_length = archive_le16dec(p + 26);
- extra_length = archive_le16dec(p + 28);
-
- zip_read_consume(a, 30);
-
- if (zip->have_central_directory) {
- /* If we read the central dir entry, we must have size
- * information as well, so ignore the length-at-end flag. */
- zip_entry->flags &= ~ZIP_LENGTH_AT_END;
- /* If we have values from both the local file header
- and the central directory, warn about mismatches
- which might indicate a damaged file. But some
- writers always put zero in the local header; don't
- bother warning about that. */
- if (local_crc32 != 0 && local_crc32 != zip_entry->crc32) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Inconsistent CRC32 values");
- ret = ARCHIVE_WARN;
- }
- if (compressed_size != 0
- && compressed_size != zip_entry->compressed_size) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Inconsistent compressed size");
- ret = ARCHIVE_WARN;
- }
- if (uncompressed_size != 0
- && uncompressed_size != zip_entry->uncompressed_size) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Inconsistent uncompressed size");
- ret = ARCHIVE_WARN;
- }
- } else {
- /* If we don't have the CD info, use whatever we do have. */
- zip_entry->crc32 = local_crc32;
- zip_entry->compressed_size = compressed_size;
- zip_entry->uncompressed_size = uncompressed_size;
- }
-
- /* Read the filename. */
- if ((h = __archive_read_ahead(a, filename_length, NULL)) == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated ZIP file header");
- return (ARCHIVE_FATAL);
- }
- if (zip_entry->flags & ZIP_UTF8_NAME) {
- /* The filename is stored to be UTF-8. */
- if (zip->sconv_utf8 == NULL) {
- zip->sconv_utf8 =
- archive_string_conversion_from_charset(
- &a->archive, "UTF-8", 1);
- if (zip->sconv_utf8 == NULL)
- return (ARCHIVE_FATAL);
- }
- sconv = zip->sconv_utf8;
- } else if (zip->sconv != NULL)
- sconv = zip->sconv;
- else
- sconv = zip->sconv_default;
-
- if (archive_entry_copy_pathname_l(entry,
- h, filename_length, sconv) != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Pathname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Pathname cannot be converted "
- "from %s to current locale.",
- archive_string_conversion_charset_name(sconv));
- ret = ARCHIVE_WARN;
- }
- zip_read_consume(a, filename_length);
-
- if (zip_entry->mode == 0) {
- /* Especially in streaming mode, we can end up
- here without having seen any mode information.
- Guess from the filename. */
- wp = archive_entry_pathname_w(entry);
- if (wp != NULL) {
- len = wcslen(wp);
- if (len > 0 && wp[len - 1] == L'/')
- zip_entry->mode = AE_IFDIR | 0777;
- else
- zip_entry->mode = AE_IFREG | 0666;
- } else {
- cp = archive_entry_pathname(entry);
- len = (cp != NULL)?strlen(cp):0;
- if (len > 0 && cp[len - 1] == '/')
- zip_entry->mode = AE_IFDIR | 0777;
- else
- zip_entry->mode = AE_IFREG | 0666;
- }
- }
-
- /* Read the extra data. */
- if ((h = __archive_read_ahead(a, extra_length, NULL)) == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated ZIP file header");
- return (ARCHIVE_FATAL);
- }
- process_extra(h, extra_length, zip_entry);
- zip_read_consume(a, extra_length);
-
- /* Populate some additional entry fields: */
- archive_entry_set_mode(entry, zip_entry->mode);
- archive_entry_set_uid(entry, zip_entry->uid);
- archive_entry_set_gid(entry, zip_entry->gid);
- archive_entry_set_mtime(entry, zip_entry->mtime, 0);
- archive_entry_set_ctime(entry, zip_entry->ctime, 0);
- archive_entry_set_atime(entry, zip_entry->atime, 0);
- /* Set the size only if it's meaningful. */
- if (0 == (zip_entry->flags & ZIP_LENGTH_AT_END))
- archive_entry_set_size(entry, zip_entry->uncompressed_size);
-
- zip->entry_bytes_remaining = zip_entry->compressed_size;
-
- /* If there's no body, force read_data() to return EOF immediately. */
- if (0 == (zip_entry->flags & ZIP_LENGTH_AT_END)
- && zip->entry_bytes_remaining < 1)
- zip->end_of_entry = 1;
-
- /* Set up a more descriptive format name. */
- sprintf(zip->format_name, "ZIP %d.%d (%s)",
- version / 10, version % 10,
- compression_name(zip->entry->compression));
- a->archive.archive_format_name = zip->format_name;
-
- return (ret);
-}
-
-static const char *
-compression_name(int compression)
-{
- static const char *compression_names[] = {
- "uncompressed",
- "shrinking",
- "reduced-1",
- "reduced-2",
- "reduced-3",
- "reduced-4",
- "imploded",
- "reserved",
- "deflation"
- };
-
- if (0 <= compression && compression <
- (int)(sizeof(compression_names)/sizeof(compression_names[0])))
- return compression_names[compression];
- else
- return "??";
-}
-
-/* Convert an MSDOS-style date/time into Unix-style time. */
-static time_t
-zip_time(const char *p)
-{
- int msTime, msDate;
- struct tm ts;
-
- msTime = (0xff & (unsigned)p[0]) + 256 * (0xff & (unsigned)p[1]);
- msDate = (0xff & (unsigned)p[2]) + 256 * (0xff & (unsigned)p[3]);
-
- memset(&ts, 0, sizeof(ts));
- ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */
- ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */
- ts.tm_mday = msDate & 0x1f; /* Day of month. */
- ts.tm_hour = (msTime >> 11) & 0x1f;
- ts.tm_min = (msTime >> 5) & 0x3f;
- ts.tm_sec = (msTime << 1) & 0x3e;
- ts.tm_isdst = -1;
- return mktime(&ts);
-}
-
-static int
-archive_read_format_zip_read_data(struct archive_read *a,
- const void **buff, size_t *size, int64_t *offset)
-{
- int r;
- struct zip *zip = (struct zip *)(a->format->data);
-
- *offset = zip->entry_uncompressed_bytes_read;
- *size = 0;
- *buff = NULL;
-
- /* If we hit end-of-entry last time, return ARCHIVE_EOF. */
- if (zip->end_of_entry)
- return (ARCHIVE_EOF);
-
- /* Return EOF immediately if this is a non-regular file. */
- if (AE_IFREG != (zip->entry->mode & AE_IFMT))
- return (ARCHIVE_EOF);
-
- if (zip->entry->flags & (ZIP_ENCRYPTED | ZIP_STRONG_ENCRYPTED)) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Encrypted file is unsupported");
- return (ARCHIVE_FAILED);
- }
-
- zip_read_consume(a, zip->unconsumed);
- zip->unconsumed = 0;
-
- switch(zip->entry->compression) {
- case 0: /* No compression. */
- r = zip_read_data_none(a, buff, size, offset);
- break;
-#ifdef HAVE_ZLIB_H
- case 8: /* Deflate compression. */
- r = zip_read_data_deflate(a, buff, size, offset);
- break;
-#endif
- default: /* Unsupported compression. */
- /* Return a warning. */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Unsupported ZIP compression method (%s)",
- compression_name(zip->entry->compression));
- /* We can't decompress this entry, but we will
- * be able to skip() it and try the next entry. */
- return (ARCHIVE_FAILED);
- break;
- }
- if (r != ARCHIVE_OK)
- return (r);
- /* Update checksum */
- if (*size)
- zip->entry_crc32 = crc32(zip->entry_crc32, *buff,
- (unsigned)*size);
- /* If we hit the end, swallow any end-of-data marker. */
- if (zip->end_of_entry) {
- /* Check file size, CRC against these values. */
- if (zip->entry->compressed_size !=
- zip->entry_compressed_bytes_read) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "ZIP compressed data is wrong size "
- "(read %jd, expected %jd)",
- (intmax_t)zip->entry_compressed_bytes_read,
- (intmax_t)zip->entry->compressed_size);
- return (ARCHIVE_WARN);
- }
- /* Size field only stores the lower 32 bits of the actual
- * size. */
- if ((zip->entry->uncompressed_size & UINT32_MAX)
- != (zip->entry_uncompressed_bytes_read & UINT32_MAX)) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "ZIP uncompressed data is wrong size "
- "(read %jd, expected %jd)",
- (intmax_t)zip->entry_uncompressed_bytes_read,
- (intmax_t)zip->entry->uncompressed_size);
- return (ARCHIVE_WARN);
- }
- /* Check computed CRC against header */
- if (zip->entry->crc32 != zip->entry_crc32) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "ZIP bad CRC: 0x%lx should be 0x%lx",
- (unsigned long)zip->entry_crc32,
- (unsigned long)zip->entry->crc32);
- return (ARCHIVE_WARN);
- }
- }
-
- return (ARCHIVE_OK);
-}
-
-/*
- * Read "uncompressed" data. There are three cases:
- * 1) We know the size of the data. This is always true for the
- * seeking reader (we've examined the Central Directory already).
- * 2) ZIP_LENGTH_AT_END was set, but only the CRC was deferred.
- * Info-ZIP seems to do this; we know the size but have to grab
- * the CRC from the data descriptor afterwards.
- * 3) We're streaming and ZIP_LENGTH_AT_END was specified and
- * we have no size information. In this case, we can do pretty
- * well by watching for the data descriptor record. The data
- * descriptor is 16 bytes and includes a computed CRC that should
- * provide a strong check.
- *
- * TODO: Technically, the PK\007\010 signature is optional.
- * In the original spec, the data descriptor contained CRC
- * and size fields but had no leading signature. In practice,
- * newer writers seem to provide the signature pretty consistently,
- * but we might need to do something more complex here if
- * we want to handle older archives that lack that signature.
- *
- * Returns ARCHIVE_OK if successful, ARCHIVE_FATAL otherwise, sets
- * zip->end_of_entry if it consumes all of the data.
- */
-static int
-zip_read_data_none(struct archive_read *a, const void **_buff,
- size_t *size, int64_t *offset)
-{
- struct zip *zip;
- const char *buff;
- ssize_t bytes_avail;
-
- (void)offset; /* UNUSED */
-
- zip = (struct zip *)(a->format->data);
-
- if (zip->entry->flags & ZIP_LENGTH_AT_END) {
- const char *p;
-
- /* Grab at least 16 bytes. */
- buff = __archive_read_ahead(a, 16, &bytes_avail);
- if (bytes_avail < 16) {
- /* Zip archives have end-of-archive markers
- that are longer than this, so a failure to get at
- least 16 bytes really does indicate a truncated
- file. */
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated ZIP file data");
- return (ARCHIVE_FATAL);
- }
- /* Check for a complete PK\007\010 signature. */
- p = buff;
- if (p[0] == 'P' && p[1] == 'K'
- && p[2] == '\007' && p[3] == '\010'
- && archive_le32dec(p + 4) == zip->entry_crc32
- && archive_le32dec(p + 8) ==
- zip->entry_compressed_bytes_read
- && archive_le32dec(p + 12) ==
- zip->entry_uncompressed_bytes_read) {
- zip->entry->crc32 = archive_le32dec(p + 4);
- zip->entry->compressed_size = archive_le32dec(p + 8);
- zip->entry->uncompressed_size = archive_le32dec(p + 12);
- zip->end_of_entry = 1;
- zip->unconsumed = 16;
- return (ARCHIVE_OK);
- }
- /* If not at EOF, ensure we consume at least one byte. */
- ++p;
-
- /* Scan forward until we see where a PK\007\010 signature
- * might be. */
- /* Return bytes up until that point. On the next call,
- * the code above will verify the data descriptor. */
- while (p < buff + bytes_avail - 4) {
- if (p[3] == 'P') { p += 3; }
- else if (p[3] == 'K') { p += 2; }
- else if (p[3] == '\007') { p += 1; }
- else if (p[3] == '\010' && p[2] == '\007'
- && p[1] == 'K' && p[0] == 'P') {
- break;
- } else { p += 4; }
- }
- bytes_avail = p - buff;
- } else {
- if (zip->entry_bytes_remaining == 0) {
- zip->end_of_entry = 1;
- return (ARCHIVE_OK);
- }
- /* Grab a bunch of bytes. */
- buff = __archive_read_ahead(a, 1, &bytes_avail);
- if (bytes_avail <= 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated ZIP file data");
- return (ARCHIVE_FATAL);
- }
- if (bytes_avail > zip->entry_bytes_remaining)
- bytes_avail = (ssize_t)zip->entry_bytes_remaining;
- }
- *size = bytes_avail;
- zip->entry_bytes_remaining -= bytes_avail;
- zip->entry_uncompressed_bytes_read += bytes_avail;
- zip->entry_compressed_bytes_read += bytes_avail;
- zip->unconsumed += bytes_avail;
- *_buff = buff;
- return (ARCHIVE_OK);
-}
-
-#ifdef HAVE_ZLIB_H
-static int
-zip_deflate_init(struct archive_read *a, struct zip *zip)
-{
- int r;
-
- /* If we haven't yet read any data, initialize the decompressor. */
- if (!zip->decompress_init) {
- if (zip->stream_valid)
- r = inflateReset(&zip->stream);
- else
- r = inflateInit2(&zip->stream,
- -15 /* Don't check for zlib header */);
- if (r != Z_OK) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Can't initialize ZIP decompression.");
- return (ARCHIVE_FATAL);
- }
- /* Stream structure has been set up. */
- zip->stream_valid = 1;
- /* We've initialized decompression for this stream. */
- zip->decompress_init = 1;
- }
- return (ARCHIVE_OK);
-}
-
-static int
-zip_read_data_deflate(struct archive_read *a, const void **buff,
- size_t *size, int64_t *offset)
-{
- struct zip *zip;
- ssize_t bytes_avail;
- const void *compressed_buff;
- int r;
-
- (void)offset; /* UNUSED */
-
- zip = (struct zip *)(a->format->data);
-
- /* If the buffer hasn't been allocated, allocate it now. */
- if (zip->uncompressed_buffer == NULL) {
- zip->uncompressed_buffer_size = 256 * 1024;
- zip->uncompressed_buffer
- = (unsigned char *)malloc(zip->uncompressed_buffer_size);
- if (zip->uncompressed_buffer == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "No memory for ZIP decompression");
- return (ARCHIVE_FATAL);
- }
- }
-
- r = zip_deflate_init(a, zip);
- if (r != ARCHIVE_OK)
- return (r);
-
- /*
- * Note: '1' here is a performance optimization.
- * Recall that the decompression layer returns a count of
- * available bytes; asking for more than that forces the
- * decompressor to combine reads by copying data.
- */
- compressed_buff = __archive_read_ahead(a, 1, &bytes_avail);
- if (0 == (zip->entry->flags & ZIP_LENGTH_AT_END)
- && bytes_avail > zip->entry_bytes_remaining) {
- bytes_avail = (ssize_t)zip->entry_bytes_remaining;
- }
- if (bytes_avail <= 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated ZIP file body");
- return (ARCHIVE_FATAL);
- }
-
- /*
- * A bug in zlib.h: stream.next_in should be marked 'const'
- * but isn't (the library never alters data through the
- * next_in pointer, only reads it). The result: this ugly
- * cast to remove 'const'.
- */
- zip->stream.next_in = (Bytef *)(uintptr_t)(const void *)compressed_buff;
- zip->stream.avail_in = (uInt)bytes_avail;
- zip->stream.total_in = 0;
- zip->stream.next_out = zip->uncompressed_buffer;
- zip->stream.avail_out = (uInt)zip->uncompressed_buffer_size;
- zip->stream.total_out = 0;
-
- r = inflate(&zip->stream, 0);
- switch (r) {
- case Z_OK:
- break;
- case Z_STREAM_END:
- zip->end_of_entry = 1;
- break;
- case Z_MEM_ERROR:
- archive_set_error(&a->archive, ENOMEM,
- "Out of memory for ZIP decompression");
- return (ARCHIVE_FATAL);
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "ZIP decompression failed (%d)", r);
- return (ARCHIVE_FATAL);
- }
-
- /* Consume as much as the compressor actually used. */
- bytes_avail = zip->stream.total_in;
- zip_read_consume(a, bytes_avail);
- zip->entry_bytes_remaining -= bytes_avail;
- zip->entry_compressed_bytes_read += bytes_avail;
-
- *size = zip->stream.total_out;
- zip->entry_uncompressed_bytes_read += zip->stream.total_out;
- *buff = zip->uncompressed_buffer;
-
- if (zip->end_of_entry && (zip->entry->flags & ZIP_LENGTH_AT_END)) {
- const char *p;
-
- if (NULL == (p = __archive_read_ahead(a, 16, NULL))) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated ZIP end-of-file record");
- return (ARCHIVE_FATAL);
- }
- /* Consume the optional PK\007\010 marker. */
- if (p[0] == 'P' && p[1] == 'K' &&
- p[2] == '\007' && p[3] == '\010') {
- zip->entry->crc32 = archive_le32dec(p + 4);
- zip->entry->compressed_size = archive_le32dec(p + 8);
- zip->entry->uncompressed_size = archive_le32dec(p + 12);
- zip->unconsumed = 16;
- }
- }
-
- return (ARCHIVE_OK);
-}
-#endif
-
-static int
-archive_read_format_zip_read_data_skip(struct archive_read *a)
-{
- struct zip *zip;
-
- zip = (struct zip *)(a->format->data);
-
- /* If we've already read to end of data, we're done. */
- if (zip->end_of_entry)
- return (ARCHIVE_OK);
-
- /* So we know we're streaming... */
- if (0 == (zip->entry->flags & ZIP_LENGTH_AT_END)) {
- /* We know the compressed length, so we can just skip. */
- int64_t bytes_skipped = zip_read_consume(a,
- zip->entry_bytes_remaining + zip->unconsumed);
- if (bytes_skipped < 0)
- return (ARCHIVE_FATAL);
- zip->unconsumed = 0;
- return (ARCHIVE_OK);
- }
-
- /* We're streaming and we don't know the length. */
- /* If the body is compressed and we know the format, we can
- * find an exact end-of-entry by decompressing it. */
- switch (zip->entry->compression) {
-#ifdef HAVE_ZLIB_H
- case 8: /* Deflate compression. */
- while (!zip->end_of_entry) {
- int64_t offset = 0;
- const void *buff = NULL;
- size_t size = 0;
- int r;
- r = zip_read_data_deflate(a, &buff, &size, &offset);
- if (r != ARCHIVE_OK)
- return (r);
- }
- return ARCHIVE_OK;
-#endif
- default: /* Uncompressed or unknown. */
- /* Scan for a PK\007\010 signature. */
- zip_read_consume(a, zip->unconsumed);
- zip->unconsumed = 0;
- for (;;) {
- const char *p, *buff;
- ssize_t bytes_avail;
- buff = __archive_read_ahead(a, 16, &bytes_avail);
- if (bytes_avail < 16) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated ZIP file data");
- return (ARCHIVE_FATAL);
- }
- p = buff;
- while (p <= buff + bytes_avail - 16) {
- if (p[3] == 'P') { p += 3; }
- else if (p[3] == 'K') { p += 2; }
- else if (p[3] == '\007') { p += 1; }
- else if (p[3] == '\010' && p[2] == '\007'
- && p[1] == 'K' && p[0] == 'P') {
- zip_read_consume(a, p - buff + 16);
- return ARCHIVE_OK;
- } else { p += 4; }
- }
- zip_read_consume(a, p - buff);
- }
- }
-}
-
-static int
-archive_read_format_zip_cleanup(struct archive_read *a)
-{
- struct zip *zip;
-
- zip = (struct zip *)(a->format->data);
-#ifdef HAVE_ZLIB_H
- if (zip->stream_valid)
- inflateEnd(&zip->stream);
-#endif
- if (zip->zip_entries && zip->central_directory_entries) {
- unsigned i;
- for (i = 0; i < zip->central_directory_entries; i++)
- archive_string_free(&(zip->zip_entries[i].rsrcname));
- }
- free(zip->zip_entries);
- free(zip->uncompressed_buffer);
- archive_string_free(&(zip->extra));
- free(zip);
- (a->format->data) = NULL;
- return (ARCHIVE_OK);
-}
-
-/*
- * The extra data is stored as a list of
- * id1+size1+data1 + id2+size2+data2 ...
- * triplets. id and size are 2 bytes each.
- */
-static void
-process_extra(const char *p, size_t extra_length, struct zip_entry* zip_entry)
-{
- unsigned offset = 0;
-
- while (offset < extra_length - 4)
- {
- unsigned short headerid = archive_le16dec(p + offset);
- unsigned short datasize = archive_le16dec(p + offset + 2);
- offset += 4;
- if (offset + datasize > extra_length)
- break;
-#ifdef DEBUG
- fprintf(stderr, "Header id 0x%x, length %d\n",
- headerid, datasize);
-#endif
- switch (headerid) {
- case 0x0001:
- /* Zip64 extended information extra field. */
- if (datasize >= 8)
- zip_entry->uncompressed_size =
- archive_le64dec(p + offset);
- if (datasize >= 16)
- zip_entry->compressed_size =
- archive_le64dec(p + offset + 8);
- break;
- case 0x5455:
- {
- /* Extended time field "UT". */
- int flags = p[offset];
- offset++;
- datasize--;
- /* Flag bits indicate which dates are present. */
- if (flags & 0x01)
- {
-#ifdef DEBUG
- fprintf(stderr, "mtime: %lld -> %d\n",
- (long long)zip_entry->mtime,
- archive_le32dec(p + offset));
-#endif
- if (datasize < 4)
- break;
- zip_entry->mtime = archive_le32dec(p + offset);
- offset += 4;
- datasize -= 4;
- }
- if (flags & 0x02)
- {
- if (datasize < 4)
- break;
- zip_entry->atime = archive_le32dec(p + offset);
- offset += 4;
- datasize -= 4;
- }
- if (flags & 0x04)
- {
- if (datasize < 4)
- break;
- zip_entry->ctime = archive_le32dec(p + offset);
- offset += 4;
- datasize -= 4;
- }
- break;
- }
- case 0x5855:
- {
- /* Info-ZIP Unix Extra Field (old version) "UX". */
- if (datasize >= 8) {
- zip_entry->atime = archive_le32dec(p + offset);
- zip_entry->mtime =
- archive_le32dec(p + offset + 4);
- }
- if (datasize >= 12) {
- zip_entry->uid =
- archive_le16dec(p + offset + 8);
- zip_entry->gid =
- archive_le16dec(p + offset + 10);
- }
- break;
- }
- case 0x7855:
- /* Info-ZIP Unix Extra Field (type 2) "Ux". */
-#ifdef DEBUG
- fprintf(stderr, "uid %d gid %d\n",
- archive_le16dec(p + offset),
- archive_le16dec(p + offset + 2));
-#endif
- if (datasize >= 2)
- zip_entry->uid = archive_le16dec(p + offset);
- if (datasize >= 4)
- zip_entry->gid =
- archive_le16dec(p + offset + 2);
- break;
- case 0x7875:
- {
- /* Info-Zip Unix Extra Field (type 3) "ux". */
- int uidsize = 0, gidsize = 0;
-
- if (datasize >= 1 && p[offset] == 1) {/* version=1 */
- if (datasize >= 4) {
- /* get a uid size. */
- uidsize = p[offset+1];
- if (uidsize == 2)
- zip_entry->uid =
- archive_le16dec(
- p + offset + 2);
- else if (uidsize == 4 && datasize >= 6)
- zip_entry->uid =
- archive_le32dec(
- p + offset + 2);
- }
- if (datasize >= (2 + uidsize + 3)) {
- /* get a gid size. */
- gidsize = p[offset+2+uidsize];
- if (gidsize == 2)
- zip_entry->gid =
- archive_le16dec(
- p+offset+2+uidsize+1);
- else if (gidsize == 4 &&
- datasize >= (2 + uidsize + 5))
- zip_entry->gid =
- archive_le32dec(
- p+offset+2+uidsize+1);
- }
- }
- break;
- }
- default:
- break;
- }
- offset += datasize;
- }
-#ifdef DEBUG
- if (offset != extra_length)
- {
- fprintf(stderr,
- "Extra data field contents do not match reported size!\n");
- }
-#endif
-}
diff --git a/3rdparty/libarchive/libarchive/archive_string.c b/3rdparty/libarchive/libarchive/archive_string.c
index 87f9288f..5ae09b62 100644
--- a/3rdparty/libarchive/libarchive/archive_string.c
+++ b/3rdparty/libarchive/libarchive/archive_string.c
@@ -71,6 +71,10 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_string.c 201095 2009-12-28 02:33
#define wmemcpy(a,b,i) (wchar_t *)memcpy((a), (b), (i) * sizeof(wchar_t))
#endif
+#if !defined(HAVE_WMEMMOVE) && !defined(wmemmove)
+#define wmemmove(a,b,i) (wchar_t *)memmove((a), (b), (i) * sizeof(wchar_t))
+#endif
+
struct archive_string_conv {
struct archive_string_conv *next;
char *from_charset;
@@ -127,12 +131,7 @@ struct archive_string_conv {
#define UNICODE_MAX 0x10FFFF
#define UNICODE_R_CHAR 0xFFFD /* Replacement character. */
/* Set U+FFFD(Replacement character) in UTF-8. */
-#define UTF8_SET_R_CHAR(outp) do { \
- (outp)[0] = 0xef; \
- (outp)[1] = 0xbf; \
- (outp)[2] = 0xbd; \
-} while (0)
-#define UTF8_R_CHAR_SIZE 3
+static const char utf8_replacement_char[] = {0xef, 0xbf, 0xbd};
static struct archive_string_conv *find_sconv_object(struct archive *,
const char *, const char *);
@@ -203,7 +202,8 @@ archive_string_append(struct archive_string *as, const char *p, size_t s)
{
if (archive_string_ensure(as, as->length + s + 1) == NULL)
return (NULL);
- memcpy(as->s + as->length, p, s);
+ if (s)
+ memmove(as->s + as->length, p, s);
as->length += s;
as->s[as->length] = 0;
return (as);
@@ -214,12 +214,18 @@ archive_wstring_append(struct archive_wstring *as, const wchar_t *p, size_t s)
{
if (archive_wstring_ensure(as, as->length + s + 1) == NULL)
return (NULL);
- wmemcpy(as->s + as->length, p, s);
+ wmemmove(as->s + as->length, p, s);
as->length += s;
as->s[as->length] = 0;
return (as);
}
+struct archive_string *
+archive_array_append(struct archive_string *as, const char *p, size_t s)
+{
+ return archive_string_append(as, p, s);
+}
+
void
archive_string_concat(struct archive_string *dest, struct archive_string *src)
{
@@ -560,7 +566,8 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest,
}
if (count == 0 && length != 0)
ret = -1;
- } while (0);
+ break;
+ } while (1);
}
dest->length += count;
dest->s[dest->length] = L'\0';
@@ -597,7 +604,7 @@ archive_wstring_append_from_mbs(struct archive_wstring *dest,
wcs = dest->s + dest->length;
/*
* We cannot use mbsrtowcs/mbstowcs here because those may convert
- * extra MBS when strlen(p) > len and one wide character consis of
+ * extra MBS when strlen(p) > len and one wide character consists of
* multi bytes.
*/
while (*mbs && mbs_length > 0) {
@@ -738,7 +745,8 @@ archive_string_append_from_wcs_in_codepage(struct archive_string *as,
}
if (count == 0)
ret = -1;
- } while (0);
+ break;
+ } while (1);
}
as->length += count;
as->s[as->length] = '\0';
@@ -1247,7 +1255,7 @@ create_sconv_object(const char *fc, const char *tc,
sc->cd = iconv_open(tc, fc);
if (sc->cd == (iconv_t)-1 && (sc->flag & SCONV_BEST_EFFORT)) {
/*
- * Unfortunaly, all of iconv implements do support
+ * Unfortunately, all of iconv implements do support
* "CP932" character-set, so we should use "SJIS"
* instead if iconv_open failed.
*/
@@ -1260,7 +1268,7 @@ create_sconv_object(const char *fc, const char *tc,
/*
* archive_mstring on Windows directly convert multi-bytes
* into archive_wstring in order not to depend on locale
- * so that you can do a I18N programing. This will be
+ * so that you can do a I18N programming. This will be
* used only in archive_mstring_copy_mbs_len_l so far.
*/
if (flag & SCONV_FROM_CHARSET) {
@@ -1725,7 +1733,7 @@ archive_string_conversion_from_charset(struct archive *a, const char *charset,
* in tar or zip files. But mbstowcs/wcstombs(CRT) usually use CP_ACP
* unless you use setlocale(LC_ALL, ".OCP")(specify CP_OEMCP).
* So we should make a string conversion between CP_ACP and CP_OEMCP
- * for compatibillty.
+ * for compatibility.
*/
#if defined(_WIN32) && !defined(__CYGWIN__)
struct archive_string_conv *
@@ -1826,7 +1834,7 @@ archive_string_conversion_set_opt(struct archive_string_conv *sc, int opt)
* A filename in UTF-8 was made with libarchive 2.x in a wrong
* assumption that wchar_t was Unicode.
* This option enables simulating the assumption in order to read
- * that filname correctly.
+ * that filename correctly.
*/
case SCONV_SET_OPT_UTF8_LIBARCHIVE2X:
#if (defined(_WIN32) && !defined(__CYGWIN__)) \
@@ -1938,12 +1946,19 @@ archive_strncat_l(struct archive_string *as, const void *_p, size_t n,
struct archive_string_conv *sc)
{
const void *s;
- size_t length;
+ size_t length = 0;
int i, r = 0, r2;
+ if (_p != NULL && n > 0) {
+ if (sc != NULL && (sc->flag & SCONV_FROM_UTF16))
+ length = utf16nbytes(_p, n);
+ else
+ length = mbsnbytes(_p, n);
+ }
+
/* We must allocate memory even if there is no data for conversion
* or copy. This simulates archive_string_append behavior. */
- if (_p == NULL || n == 0) {
+ if (length == 0) {
int tn = 1;
if (sc != NULL && (sc->flag & SCONV_TO_UTF16))
tn = 2;
@@ -1959,16 +1974,11 @@ archive_strncat_l(struct archive_string *as, const void *_p, size_t n,
* If sc is NULL, we just make a copy.
*/
if (sc == NULL) {
- length = mbsnbytes(_p, n);
if (archive_string_append(as, _p, length) == NULL)
return (-1);/* No memory */
return (0);
}
- if (sc->flag & SCONV_FROM_UTF16)
- length = utf16nbytes(_p, n);
- else
- length = mbsnbytes(_p, n);
s = _p;
i = 0;
if (sc->nconverter > 1) {
@@ -1991,7 +2001,7 @@ archive_strncat_l(struct archive_string *as, const void *_p, size_t n,
#if HAVE_ICONV
/*
- * Return -1 if conversion failes.
+ * Return -1 if conversion fails.
*/
static int
iconv_strncat_in_locale(struct archive_string *as, const void *_p,
@@ -2037,7 +2047,7 @@ iconv_strncat_in_locale(struct archive_string *as, const void *_p,
if (sc->flag & (SCONV_TO_UTF8 | SCONV_TO_UTF16)) {
size_t rbytes;
if (sc->flag & SCONV_TO_UTF8)
- rbytes = UTF8_R_CHAR_SIZE;
+ rbytes = sizeof(utf8_replacement_char);
else
rbytes = 2;
@@ -2053,7 +2063,7 @@ iconv_strncat_in_locale(struct archive_string *as, const void *_p,
- as->length - to_size;
}
if (sc->flag & SCONV_TO_UTF8)
- UTF8_SET_R_CHAR(outp);
+ memcpy(outp, utf8_replacement_char, sizeof(utf8_replacement_char));
else if (sc->flag & SCONV_TO_UTF16BE)
archive_be16enc(outp, UNICODE_R_CHAR);
else
@@ -2093,7 +2103,7 @@ iconv_strncat_in_locale(struct archive_string *as, const void *_p,
/*
* Translate a string from a some CodePage to an another CodePage by
- * Windows APIs, and copy the result. Return -1 if conversion failes.
+ * Windows APIs, and copy the result. Return -1 if conversion fails.
*/
static int
strncat_in_codepage(struct archive_string *as,
@@ -2202,9 +2212,7 @@ best_effort_strncat_in_locale(struct archive_string *as, const void *_p,
size_t length, struct archive_string_conv *sc)
{
size_t remaining;
- char *otp;
const uint8_t *itp;
- size_t avail;
int return_value = 0; /* success */
/*
@@ -2219,50 +2227,29 @@ best_effort_strncat_in_locale(struct archive_string *as, const void *_p,
/*
* If a character is ASCII, this just copies it. If not, this
- * assigns '?' charater instead but in UTF-8 locale this assigns
+ * assigns '?' character instead but in UTF-8 locale this assigns
* byte sequence 0xEF 0xBD 0xBD, which are code point U+FFFD,
* a Replacement Character in Unicode.
*/
- if (archive_string_ensure(as, as->length + length + 1) == NULL)
- return (-1);
remaining = length;
itp = (const uint8_t *)_p;
- otp = as->s + as->length;
- avail = as->buffer_length - as->length -1;
while (*itp && remaining > 0) {
- if (*itp > 127 && (sc->flag & SCONV_TO_UTF8)) {
- if (avail < UTF8_R_CHAR_SIZE) {
- as->length = otp - as->s;
- if (NULL == archive_string_ensure(as,
- as->buffer_length + remaining +
- UTF8_R_CHAR_SIZE))
- return (-1);
- otp = as->s + as->length;
- avail = as->buffer_length - as->length -1;
+ if (*itp > 127) {
+ // Non-ASCII: Substitute with suitable replacement
+ if (sc->flag & SCONV_TO_UTF8) {
+ if (archive_string_append(as, utf8_replacement_char, sizeof(utf8_replacement_char)) == NULL) {
+ __archive_errx(1, "Out of memory");
+ }
+ } else {
+ archive_strappend_char(as, '?');
}
- /*
- * When coping a string in UTF-8, unknown character
- * should be U+FFFD (replacement character).
- */
- UTF8_SET_R_CHAR(otp);
- otp += UTF8_R_CHAR_SIZE;
- avail -= UTF8_R_CHAR_SIZE;
- itp++;
- remaining--;
- return_value = -1;
- } else if (*itp > 127) {
- *otp++ = '?';
- itp++;
- remaining--;
return_value = -1;
} else {
- *otp++ = (char)*itp++;
- remaining--;
+ archive_strappend_char(as, *itp);
}
+ ++itp;
}
- as->length = otp - as->s;
- as->s[as->length] = '\0';
return (return_value);
}
@@ -2320,7 +2307,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
return (0); /* Standard: return 0 for end-of-string. */
cnt = utf8_count[ch];
- /* Invalide sequence or there are not plenty bytes. */
+ /* Invalid sequence or there are not plenty bytes. */
if ((int)n < cnt) {
cnt = (int)n;
for (i = 1; i < cnt; i++) {
@@ -2401,7 +2388,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
goto invalid_sequence;
}
- /* The code point larger than 0x10FFFF is not leagal
+ /* The code point larger than 0x10FFFF is not legal
* Unicode values. */
if (wc > UNICODE_MAX)
goto invalid_sequence;
@@ -2419,7 +2406,7 @@ utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
int cnt;
cnt = _utf8_to_unicode(pwc, s, n);
- /* Any of Surrogate pair is not leagal Unicode values. */
+ /* Any of Surrogate pair is not legal Unicode values. */
if (cnt == 3 && IS_SURROGATE_PAIR_LA(*pwc))
return (-3);
return (cnt);
@@ -2480,7 +2467,7 @@ invalid_sequence:
/*
* Convert a Unicode code point to a single UTF-8 sequence.
*
- * NOTE:This function does not check if the Unicode is leagal or not.
+ * NOTE:This function does not check if the Unicode is legal or not.
* Please you definitely check it before calling this.
*/
static size_t
@@ -2488,6 +2475,9 @@ unicode_to_utf8(char *p, size_t remaining, uint32_t uc)
{
char *_p = p;
+ /* Invalid Unicode char maps to Replacement character */
+ if (uc > UNICODE_MAX)
+ uc = UNICODE_R_CHAR;
/* Translate code point to UTF8 */
if (uc <= 0x7f) {
if (remaining == 0)
@@ -2504,22 +2494,13 @@ unicode_to_utf8(char *p, size_t remaining, uint32_t uc)
*p++ = 0xe0 | ((uc >> 12) & 0x0f);
*p++ = 0x80 | ((uc >> 6) & 0x3f);
*p++ = 0x80 | (uc & 0x3f);
- } else if (uc <= UNICODE_MAX) {
+ } else {
if (remaining < 4)
return (0);
*p++ = 0xf0 | ((uc >> 18) & 0x07);
*p++ = 0x80 | ((uc >> 12) & 0x3f);
*p++ = 0x80 | ((uc >> 6) & 0x3f);
*p++ = 0x80 | (uc & 0x3f);
- } else {
- /*
- * Undescribed code point should be U+FFFD
- * (replacement character).
- */
- if (remaining < UTF8_R_CHAR_SIZE)
- return (0);
- UTF8_SET_R_CHAR(p);
- p += UTF8_R_CHAR_SIZE;
}
return (p - _p);
}
@@ -2580,9 +2561,9 @@ utf16_to_unicode(uint32_t *pwc, const char *s, size_t n, int be)
/*
* Surrogate pair values(0xd800 through 0xdfff) are only
- * used by UTF-16, so, after above culculation, the code
+ * used by UTF-16, so, after above calculation, the code
* must not be surrogate values, and Unicode has no codes
- * larger than 0x10ffff. Thus, those are not leagal Unicode
+ * larger than 0x10ffff. Thus, those are not legal Unicode
* values.
*/
if (IS_SURROGATE_PAIR_LA(uc) || uc > UNICODE_MAX) {
@@ -2929,7 +2910,7 @@ get_nfc(uint32_t uc, uint32_t uc2)
/*
* Normalize UTF-8/UTF-16BE characters to Form C and copy the result.
*
- * TODO: Convert composition exclusions,which are never converted
+ * TODO: Convert composition exclusions, which are never converted
* from NFC,NFD,NFKC and NFKD, to Form C.
*/
static int
@@ -3463,7 +3444,7 @@ strncat_from_utf8_libarchive2(struct archive_string *as,
}
/*
- * As libarchie 2.x, translates the UTF-8 characters into
+ * As libarchive 2.x, translates the UTF-8 characters into
* wide-characters in the assumption that WCS is Unicode.
*/
if (n < 0) {
@@ -3502,7 +3483,7 @@ strncat_from_utf8_libarchive2(struct archive_string *as,
/*
* Convert a UTF-16BE/LE string to current locale and copy the result.
- * Return -1 if conversion failes.
+ * Return -1 if conversion fails.
*/
static int
win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes,
@@ -3581,18 +3562,19 @@ win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes,
ll = WideCharToMultiByte(sc->to_cp, 0,
(LPCWSTR)u16, (int)bytes>>1, mbs, (int)mbs_size,
NULL, &defchar);
- if (ll == 0 &&
- GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
- /* Need more buffer for MBS. */
- ll = WideCharToMultiByte(sc->to_cp, 0,
- (LPCWSTR)u16, (int)bytes, NULL, 0, NULL, NULL);
- if (archive_string_ensure(as, ll +1) == NULL)
- return (-1);
- mbs = as->s + as->length;
- mbs_size = as->buffer_length - as->length -1;
- continue;
+ /* Exit loop if we succeeded */
+ if (ll != 0 ||
+ GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ break;
}
- } while (0);
+ /* Else expand buffer and loop to try again. */
+ ll = WideCharToMultiByte(sc->to_cp, 0,
+ (LPCWSTR)u16, (int)bytes, NULL, 0, NULL, NULL);
+ if (archive_string_ensure(as, ll +1) == NULL)
+ return (-1);
+ mbs = as->s + as->length;
+ mbs_size = as->buffer_length - as->length -1;
+ } while (1);
archive_string_free(&tmp);
as->length += ll;
as->s[as->length] = '\0';
@@ -3625,7 +3607,7 @@ is_big_endian(void)
/*
* Convert a current locale string to UTF-16BE/LE and copy the result.
- * Return -1 if conversion failes.
+ * Return -1 if conversion fails.
*/
static int
win_strncat_to_utf16(struct archive_string *as16, const void *_p,
@@ -3663,19 +3645,20 @@ win_strncat_to_utf16(struct archive_string *as16, const void *_p,
do {
count = MultiByteToWideChar(sc->from_cp,
MB_PRECOMPOSED, s, (int)length, (LPWSTR)u16, (int)avail>>1);
- if (count == 0 &&
- GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
- /* Need more buffer for UTF-16 string */
- count = MultiByteToWideChar(sc->from_cp,
- MB_PRECOMPOSED, s, (int)length, NULL, 0);
- if (archive_string_ensure(as16, (count +1) * 2)
- == NULL)
- return (-1);
- u16 = as16->s + as16->length;
- avail = as16->buffer_length - 2;
- continue;
+ /* Exit loop if we succeeded */
+ if (count != 0 ||
+ GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ break;
}
- } while (0);
+ /* Expand buffer and try again */
+ count = MultiByteToWideChar(sc->from_cp,
+ MB_PRECOMPOSED, s, (int)length, NULL, 0);
+ if (archive_string_ensure(as16, (count +1) * 2)
+ == NULL)
+ return (-1);
+ u16 = as16->s + as16->length;
+ avail = as16->buffer_length - 2;
+ } while (1);
as16->length += count * 2;
as16->s[as16->length] = 0;
as16->s[as16->length+1] = 0;
@@ -3729,7 +3712,7 @@ win_strncat_to_utf16le(struct archive_string *as16, const void *_p,
/*
* Convert a UTF-16BE string to current locale and copy the result.
- * Return -1 if conversion failes.
+ * Return -1 if conversion fails.
*/
static int
best_effort_strncat_from_utf16(struct archive_string *as, const void *_p,
@@ -3787,7 +3770,7 @@ best_effort_strncat_from_utf16le(struct archive_string *as, const void *_p,
/*
* Convert a current locale string to UTF-16BE/LE and copy the result.
- * Return -1 if conversion failes.
+ * Return -1 if conversion fails.
*/
static int
best_effort_strncat_to_utf16(struct archive_string *as16, const void *_p,
@@ -3887,7 +3870,7 @@ archive_mstring_get_utf8(struct archive *a, struct archive_mstring *aes,
sc = archive_string_conversion_to_charset(a, "UTF-8", 1);
if (sc == NULL)
return (-1);/* Couldn't allocate memory for sc. */
- r = archive_strncpy_l(&(aes->aes_mbs), aes->aes_mbs.s,
+ r = archive_strncpy_l(&(aes->aes_utf8), aes->aes_mbs.s,
aes->aes_mbs.length, sc);
if (a == NULL)
free_sconv_object(sc);
@@ -3971,7 +3954,7 @@ archive_mstring_get_mbs_l(struct archive_mstring *aes,
#if defined(_WIN32) && !defined(__CYGWIN__)
/*
- * Internationalization programing on Windows must use Wide
+ * Internationalization programming on Windows must use Wide
* characters because Windows platform cannot make locale UTF-8.
*/
if (sc != NULL && (aes->aes_set & AES_SET_WCS) != 0) {
@@ -4062,6 +4045,19 @@ archive_mstring_copy_wcs(struct archive_mstring *aes, const wchar_t *wcs)
}
int
+archive_mstring_copy_utf8(struct archive_mstring *aes, const char *utf8)
+{
+ if (utf8 == NULL) {
+ aes->aes_set = 0;
+ }
+ aes->aes_set = AES_SET_UTF8;
+ archive_string_empty(&(aes->aes_mbs));
+ archive_string_empty(&(aes->aes_wcs));
+ archive_strncpy(&(aes->aes_utf8), utf8, strlen(utf8));
+ return (int)strlen(utf8);
+}
+
+int
archive_mstring_copy_wcs_len(struct archive_mstring *aes, const wchar_t *wcs,
size_t len)
{
@@ -4090,7 +4086,7 @@ archive_mstring_copy_mbs_len_l(struct archive_mstring *aes,
archive_string_empty(&(aes->aes_utf8));
#if defined(_WIN32) && !defined(__CYGWIN__)
/*
- * Internationalization programing on Windows must use Wide
+ * Internationalization programming on Windows must use Wide
* characters because Windows platform cannot make locale UTF-8.
*/
if (sc == NULL) {
diff --git a/3rdparty/libarchive/libarchive/archive_string.h b/3rdparty/libarchive/libarchive/archive_string.h
index 23f49165..56dfbb28 100644
--- a/3rdparty/libarchive/libarchive/archive_string.h
+++ b/3rdparty/libarchive/libarchive/archive_string.h
@@ -81,6 +81,10 @@ archive_strappend_char(struct archive_string *, char);
struct archive_wstring *
archive_wstrappend_wchar(struct archive_wstring *, wchar_t);
+/* Append a raw array to an archive_string, resizing as necessary */
+struct archive_string *
+archive_array_append(struct archive_string *, const char *, size_t);
+
/* Convert a Unicode string to current locale and append the result. */
/* Returns -1 if conversion fails. */
int
@@ -115,13 +119,13 @@ archive_string_conversion_set_opt(struct archive_string_conv *, int);
/* Copy one archive_string to another in locale conversion.
- * Return -1 if conversion failes. */
+ * Return -1 if conversion fails. */
int
archive_strncpy_l(struct archive_string *, const void *, size_t,
struct archive_string_conv *);
/* Copy one archive_string to another in locale conversion.
- * Return -1 if conversion failes. */
+ * Return -1 if conversion fails. */
int
archive_strncat_l(struct archive_string *, const void *, size_t,
struct archive_string_conv *);
diff --git a/3rdparty/libarchive/libarchive/archive_string_composition.h b/3rdparty/libarchive/libarchive/archive_string_composition.h
index be41e336..8902ac1f 100644
--- a/3rdparty/libarchive/libarchive/archive_string_composition.h
+++ b/3rdparty/libarchive/libarchive/archive_string_composition.h
@@ -1009,7 +1009,7 @@ static const char u_decomposable_blocks[0x1D2+1] = {
(((uc) > 0x1D244)?0:\
ccc_val[ccc_val_index[ccc_index[(uc)>>8]][((uc)>>4)&0x0F]][(uc)&0x0F])
-/* The table of the value of Canonical Cimbining Class */
+/* The table of the value of Canonical Combining Class */
static const unsigned char ccc_val[][16] = {
/* idx=0: XXXX0 - XXXXF */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
diff --git a/3rdparty/libarchive/libarchive/archive_string_sprintf.c b/3rdparty/libarchive/libarchive/archive_string_sprintf.c
index 964ea2be..969a5603 100644
--- a/3rdparty/libarchive/libarchive/archive_string_sprintf.c
+++ b/3rdparty/libarchive/libarchive/archive_string_sprintf.c
@@ -53,7 +53,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_string_sprintf.c 189435 2009-03-
static void
append_uint(struct archive_string *as, uintmax_t d, unsigned base)
{
- static const char *digits = "0123456789abcdef";
+ static const char digits[] = "0123456789abcdef";
if (d >= base)
append_uint(as, d/base, base);
archive_strappend_char(as, digits[d % base]);
diff --git a/3rdparty/libarchive/libarchive/archive_util.c b/3rdparty/libarchive/libarchive/archive_util.c
index 34d8081c..bac9ba1c 100644
--- a/3rdparty/libarchive/libarchive/archive_util.c
+++ b/3rdparty/libarchive/libarchive/archive_util.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2009-2012 Michihiro NAKAJIMA
+ * Copyright (c) 2009-2012,2014 Michihiro NAKAJIMA
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
@@ -45,15 +45,30 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:1
#if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__)
#include <wincrypt.h>
#endif
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+#ifdef HAVE_LZMA_H
+#include <lzma.h>
+#endif
+#ifdef HAVE_BZLIB_H
+#include <bzlib.h>
+#endif
+#ifdef HAVE_LZ4_H
+#include <lz4.h>
+#endif
#include "archive.h"
#include "archive_private.h"
+#include "archive_random_private.h"
#include "archive_string.h"
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
+static int archive_utility_string_sort_helper(char **, unsigned int);
+
/* Generic initialization of 'struct archive' objects. */
int
__archive_clean(struct archive *a)
@@ -178,7 +193,7 @@ archive_copy_error(struct archive *dest, struct archive *src)
void
__archive_errx(int retvalue, const char *msg)
{
- static const char *msg1 = "Fatal Internal Error in libarchive: ";
+ static const char msg1[] = "Fatal Internal Error in libarchive: ";
size_t s;
s = write(2, msg1, strlen(msg1));
@@ -206,6 +221,8 @@ __archive_errx(int retvalue, const char *msg)
int
__archive_mktemp(const char *tmpdir)
{
+ static const wchar_t prefix[] = L"libarchive_";
+ static const wchar_t suffix[] = L"XXXXXXXXXX";
static const wchar_t num[] = {
L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7',
L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F',
@@ -280,10 +297,10 @@ __archive_mktemp(const char *tmpdir)
/*
* Create a temporary file.
*/
- archive_wstrcat(&temp_name, L"libarchive_");
- xp = temp_name.s + archive_strlen(&temp_name);
- archive_wstrcat(&temp_name, L"XXXXXXXXXX");
+ archive_wstrcat(&temp_name, prefix);
+ archive_wstrcat(&temp_name, suffix);
ep = temp_name.s + archive_strlen(&temp_name);
+ xp = ep - wcslen(suffix);
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)) {
@@ -420,7 +437,6 @@ __archive_mktemp(const char *tmpdir)
struct stat st;
int fd;
char *tp, *ep;
- unsigned seed;
fd = -1;
archive_string_init(&temp_name);
@@ -444,21 +460,15 @@ __archive_mktemp(const char *tmpdir)
archive_strcat(&temp_name, "XXXXXXXXXX");
ep = temp_name.s + archive_strlen(&temp_name);
- fd = open("/dev/random", O_RDONLY | O_CLOEXEC);
- __archive_ensure_cloexec_flag(fd);
- if (fd < 0)
- seed = time(NULL);
- else {
- if (read(fd, &seed, sizeof(seed)) < 0)
- seed = time(NULL);
- close(fd);
- }
do {
char *p;
p = tp;
- while (p < ep)
- *p++ = num[((unsigned)rand_r(&seed)) % sizeof(num)];
+ archive_random(p, ep - p);
+ while (p < ep) {
+ int d = *((unsigned char *)p) % sizeof(num);
+ *p++ = num[d];
+ }
fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
0600);
} while (fd < 0 && errno == EEXIST);
@@ -488,7 +498,7 @@ void
__archive_ensure_cloexec_flag(int fd)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
- (void)fd; /* UNSED */
+ (void)fd; /* UNUSED */
#else
int flags;
@@ -499,3 +509,77 @@ __archive_ensure_cloexec_flag(int fd)
}
#endif
}
+
+/*
+ * Utility function to sort a group of strings using quicksort.
+ */
+static int
+archive_utility_string_sort_helper(char **strings, unsigned int n)
+{
+ unsigned int i, lesser_count, greater_count;
+ char **lesser, **greater, **tmp, *pivot;
+ int retval1, retval2;
+
+ /* A list of 0 or 1 elements is already sorted */
+ if (n <= 1)
+ return (ARCHIVE_OK);
+
+ lesser_count = greater_count = 0;
+ lesser = greater = NULL;
+ pivot = strings[0];
+ for (i = 1; i < n; i++)
+ {
+ if (strcmp(strings[i], pivot) < 0)
+ {
+ lesser_count++;
+ tmp = (char **)realloc(lesser,
+ lesser_count * sizeof(char *));
+ if (!tmp) {
+ free(greater);
+ free(lesser);
+ return (ARCHIVE_FATAL);
+ }
+ lesser = tmp;
+ lesser[lesser_count - 1] = strings[i];
+ }
+ else
+ {
+ greater_count++;
+ tmp = (char **)realloc(greater,
+ greater_count * sizeof(char *));
+ if (!tmp) {
+ free(greater);
+ free(lesser);
+ return (ARCHIVE_FATAL);
+ }
+ greater = tmp;
+ greater[greater_count - 1] = strings[i];
+ }
+ }
+
+ /* quicksort(lesser) */
+ retval1 = archive_utility_string_sort_helper(lesser, lesser_count);
+ for (i = 0; i < lesser_count; i++)
+ strings[i] = lesser[i];
+ free(lesser);
+
+ /* pivot */
+ strings[lesser_count] = pivot;
+
+ /* quicksort(greater) */
+ retval2 = archive_utility_string_sort_helper(greater, greater_count);
+ for (i = 0; i < greater_count; i++)
+ strings[lesser_count + 1 + i] = greater[i];
+ free(greater);
+
+ return (retval1 < retval2) ? retval1 : retval2;
+}
+
+int
+archive_utility_string_sort(char **strings)
+{
+ unsigned int size = 0;
+ while (strings[size] != NULL)
+ size++;
+ return archive_utility_string_sort_helper(strings, size);
+}
diff --git a/3rdparty/libarchive/libarchive/archive_virtual.c b/3rdparty/libarchive/libarchive/archive_virtual.c
index 0c4155f2..de2595a9 100644
--- a/3rdparty/libarchive/libarchive/archive_virtual.c
+++ b/3rdparty/libarchive/libarchive/archive_virtual.c
@@ -55,6 +55,14 @@ archive_filter_bytes(struct archive *a, int n)
}
int
+archive_free(struct archive *a)
+{
+ if (a == NULL)
+ return (ARCHIVE_OK);
+ return ((a->vtable->archive_free)(a));
+}
+
+int
archive_write_close(struct archive *a)
{
return ((a->vtable->archive_close)(a));
@@ -76,9 +84,7 @@ archive_write_fail(struct archive *a)
int
archive_write_free(struct archive *a)
{
- if (a == NULL)
- return (ARCHIVE_OK);
- return ((a->vtable->archive_free)(a));
+ return archive_free(a);
}
#if ARCHIVE_VERSION_NUMBER < 4000000
@@ -93,9 +99,7 @@ archive_write_finish(struct archive *a)
int
archive_read_free(struct archive *a)
{
- if (a == NULL)
- return (ARCHIVE_OK);
- return ((a->vtable->archive_free)(a));
+ return archive_free(a);
}
#if ARCHIVE_VERSION_NUMBER < 4000000
diff --git a/3rdparty/libarchive/libarchive/archive_windows.c b/3rdparty/libarchive/libarchive/archive_windows.c
index d3bf758b..6ff8749a 100644
--- a/3rdparty/libarchive/libarchive/archive_windows.c
+++ b/3rdparty/libarchive/libarchive/archive_windows.c
@@ -301,7 +301,7 @@ __la_open(const char *path, int flags, ...)
ws = NULL;
if ((flags & ~O_BINARY) == O_RDONLY) {
/*
- * When we open a directory, _open function returns
+ * When we open a directory, _open function returns
* "Permission denied" error.
*/
attr = GetFileAttributesA(path);
@@ -515,9 +515,9 @@ __hstat(HANDLE handle, struct ustat *st)
else
mode |= S_IFREG;
st->st_mode = mode;
-
+
fileTimeToUTC(&info.ftLastAccessTime, &t, &ns);
- st->st_atime = t;
+ st->st_atime = t;
st->st_atime_nsec = ns;
fileTimeToUTC(&info.ftLastWriteTime, &t, &ns);
st->st_mtime = t;
@@ -525,7 +525,7 @@ __hstat(HANDLE handle, struct ustat *st)
fileTimeToUTC(&info.ftCreationTime, &t, &ns);
st->st_ctime = t;
st->st_ctime_nsec = ns;
- st->st_size =
+ st->st_size =
((int64_t)(info.nFileSizeHigh) * ((int64_t)MAXDWORD + 1))
+ (int64_t)(info.nFileSizeLow);
#ifdef SIMULATE_WIN_STAT
@@ -599,7 +599,7 @@ __la_stat(const char *path, struct stat *st)
struct ustat u;
int ret;
- handle = la_CreateFile(path, 0, 0, NULL, OPEN_EXISTING,
+ handle = la_CreateFile(path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
if (handle == INVALID_HANDLE_VALUE) {
@@ -766,7 +766,7 @@ __la_win_entry_in_posix_pathseparator(struct archive_entry *entry)
has_backslash = 1;
}
/*
- * If there is no backslach chars, return the original.
+ * If there is no backslash chars, return the original.
*/
if (!has_backslash)
return (entry);
@@ -891,7 +891,7 @@ __la_dosmaperr(unsigned long e)
return;
}
- for (i = 0; i < (int)sizeof(doserrors); i++)
+ for (i = 0; i < (int)(sizeof(doserrors)/sizeof(doserrors[0])); i++)
{
if (doserrors[i].winerr == e)
{
diff --git a/3rdparty/libarchive/libarchive/archive_windows.h b/3rdparty/libarchive/libarchive/archive_windows.h
index c6f5bc51..e77cd08f 100644
--- a/3rdparty/libarchive/libarchive/archive_windows.h
+++ b/3rdparty/libarchive/libarchive/archive_windows.h
@@ -89,7 +89,7 @@
/* Alias the Windows _function to the POSIX equivalent. */
#define close _close
-#define fcntl(fd, cmd, flg) /* No operation. */
+#define fcntl(fd, cmd, flg) /* No operation. */
#ifndef fileno
#define fileno _fileno
#endif
@@ -109,13 +109,14 @@
#define lstat __la_stat
#define open __la_open
#define read __la_read
-#if !defined(__BORLANDC__)
+#if !defined(__BORLANDC__) && !defined(__WATCOMC__)
#define setmode _setmode
#endif
#ifdef stat
#undef stat
#endif
#define stat(path,stref) __la_stat(path,stref)
+#if !defined(__WATCOMC__)
#if !defined(__BORLANDC__)
#define strdup _strdup
#endif
@@ -123,9 +124,12 @@
#if !defined(__BORLANDC__)
#define umask _umask
#endif
+#endif
#define waitpid __la_waitpid
#define write __la_write
+#if !defined(__WATCOMC__)
+
#ifndef O_RDONLY
#define O_RDONLY _O_RDONLY
#define O_WRONLY _O_WRONLY
@@ -203,7 +207,7 @@
#define _S_IXGRP (_S_IXUSR >> 3) /* read permission, group */
#define _S_IWGRP (_S_IWUSR >> 3) /* write permission, group */
#define _S_IRGRP (_S_IRUSR >> 3) /* execute/search permission, group */
-#define _S_IRWXO (_S_IRWXG >> 3)
+#define _S_IRWXO (_S_IRWXG >> 3)
#define _S_IXOTH (_S_IXGRP >> 3) /* read permission, other */
#define _S_IWOTH (_S_IWGRP >> 3) /* write permission, other */
#define _S_IROTH (_S_IRGRP >> 3) /* execute/search permission, other */
@@ -214,14 +218,22 @@
#define S_IWUSR _S_IWUSR
#define S_IRUSR _S_IRUSR
#endif
+#ifndef S_IRWXG
#define S_IRWXG _S_IRWXG
#define S_IXGRP _S_IXGRP
#define S_IWGRP _S_IWGRP
+#endif
+#ifndef S_IRGRP
#define S_IRGRP _S_IRGRP
+#endif
+#ifndef S_IRWXO
#define S_IRWXO _S_IRWXO
#define S_IXOTH _S_IXOTH
#define S_IWOTH _S_IWOTH
#define S_IROTH _S_IROTH
+#endif
+
+#endif
#define F_DUPFD 0 /* Duplicate file descriptor. */
#define F_GETFD 1 /* Get file descriptor flags. */
diff --git a/3rdparty/libarchive/libarchive/archive_write.c b/3rdparty/libarchive/libarchive/archive_write.c
index a3d1a338..0634a229 100644
--- a/3rdparty/libarchive/libarchive/archive_write.c
+++ b/3rdparty/libarchive/libarchive/archive_write.c
@@ -109,10 +109,9 @@ archive_write_new(void)
struct archive_write *a;
unsigned char *nulls;
- a = (struct archive_write *)malloc(sizeof(*a));
+ a = (struct archive_write *)calloc(1, sizeof(*a));
if (a == NULL)
return (NULL);
- memset(a, 0, sizeof(*a));
a->archive.magic = ARCHIVE_WRITE_MAGIC;
a->archive.state = ARCHIVE_STATE_NEW;
a->archive.vtable = archive_write_vtable();
@@ -126,12 +125,11 @@ archive_write_new(void)
/* Initialize a block of nulls for padding purposes. */
a->null_length = 1024;
- nulls = (unsigned char *)malloc(a->null_length);
+ nulls = (unsigned char *)calloc(1, a->null_length);
if (nulls == NULL) {
free(a);
return (NULL);
}
- memset(nulls, 0, a->null_length);
a->nulls = nulls;
return (&a->archive);
}
@@ -233,7 +231,7 @@ __archive_write_filter(struct archive_write_filter *f,
if (length == 0)
return(ARCHIVE_OK);
if (f->write == NULL)
- /* If unset, a fatal error has already ocuured, so this filter
+ /* If unset, a fatal error has already occurred, so this filter
* didn't open. We cannot write anything. */
return(ARCHIVE_FATAL);
r = (f->write)(f, buff, length);
@@ -444,6 +442,12 @@ archive_write_client_close(struct archive_write_filter *f)
/* Clear the close handler myself not to be called again. */
f->close = NULL;
a->client_data = NULL;
+ /* Clear passphrase. */
+ if (a->passphrase != NULL) {
+ memset(a->passphrase, 0, strlen(a->passphrase));
+ free(a->passphrase);
+ a->passphrase = NULL;
+ }
return (ret);
}
@@ -503,8 +507,9 @@ _archive_write_close(struct archive *_a)
archive_clear_error(&a->archive);
- /* Finish the last entry. */
- if (a->archive.state == ARCHIVE_STATE_DATA)
+ /* Finish the last entry if a finish callback is specified */
+ if (a->archive.state == ARCHIVE_STATE_DATA
+ && a->format_finish_entry != NULL)
r = ((a->format_finish_entry)(a));
/* Finish off the archive. */
@@ -591,6 +596,11 @@ _archive_write_free(struct archive *_a)
/* Release various dynamic buffers. */
free((void *)(uintptr_t)(const void *)a->nulls);
archive_string_free(&a->archive.error_string);
+ if (a->passphrase != NULL) {
+ /* A passphrase should be cleaned. */
+ memset(a->passphrase, 0, strlen(a->passphrase));
+ free(a->passphrase);
+ }
a->archive.magic = 0;
__archive_clean(&a->archive);
free(a);
@@ -638,6 +648,9 @@ _archive_write_header(struct archive *_a, struct archive_entry *entry)
/* Format and write header. */
r2 = ((a->format_write_header)(a, entry));
+ if (r2 == ARCHIVE_FAILED) {
+ return (ARCHIVE_FAILED);
+ }
if (r2 == ARCHIVE_FATAL) {
a->archive.state = ARCHIVE_STATE_FATAL;
return (ARCHIVE_FATAL);
@@ -658,7 +671,8 @@ _archive_write_finish_entry(struct archive *_a)
archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
"archive_write_finish_entry");
- if (a->archive.state & ARCHIVE_STATE_DATA)
+ if (a->archive.state & ARCHIVE_STATE_DATA
+ && a->format_finish_entry != NULL)
ret = (a->format_finish_entry)(a);
a->archive.state = ARCHIVE_STATE_HEADER;
return (ret);
@@ -671,8 +685,13 @@ static ssize_t
_archive_write_data(struct archive *_a, const void *buff, size_t s)
{
struct archive_write *a = (struct archive_write *)_a;
+ const size_t max_write = INT_MAX;
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_DATA, "archive_write_data");
+ /* In particular, this catches attempts to pass negative values. */
+ if (s > max_write)
+ s = max_write;
archive_clear_error(&a->archive);
return ((a->format_write_data)(a, buff, s));
}
@@ -704,7 +723,7 @@ static const char *
_archive_filter_name(struct archive *_a, int n)
{
struct archive_write_filter *f = filter_lookup(_a, n);
- return f == NULL ? NULL : f->name;
+ return f != NULL ? f->name : NULL;
}
static int64_t
diff --git a/3rdparty/libarchive/libarchive/archive_write_add_filter.c b/3rdparty/libarchive/libarchive/archive_write_add_filter.c
index 81dd683a..08f518ad 100644
--- a/3rdparty/libarchive/libarchive/archive_write_add_filter.c
+++ b/3rdparty/libarchive/libarchive/archive_write_add_filter.c
@@ -38,7 +38,7 @@ __FBSDID("$FreeBSD$");
#include "archive_private.h"
/* A table that maps filter codes to functions. */
-static
+static const
struct { int code; int (*setter)(struct archive *); } codes[] =
{
{ ARCHIVE_FILTER_NONE, archive_write_add_filter_none },
@@ -47,6 +47,7 @@ struct { int code; int (*setter)(struct archive *); } codes[] =
{ ARCHIVE_FILTER_COMPRESS, archive_write_add_filter_compress },
{ ARCHIVE_FILTER_GRZIP, archive_write_add_filter_grzip },
{ ARCHIVE_FILTER_LRZIP, archive_write_add_filter_lrzip },
+ { ARCHIVE_FILTER_LZ4, archive_write_add_filter_lz4 },
{ ARCHIVE_FILTER_LZIP, archive_write_add_filter_lzip },
{ ARCHIVE_FILTER_LZMA, archive_write_add_filter_lzma },
{ ARCHIVE_FILTER_LZOP, archive_write_add_filter_lzip },
diff --git a/3rdparty/libarchive/libarchive/archive_write_add_filter_by_name.c b/3rdparty/libarchive/libarchive/archive_write_add_filter_by_name.c
index e4cba4af..85a8d475 100644
--- a/3rdparty/libarchive/libarchive/archive_write_add_filter_by_name.c
+++ b/3rdparty/libarchive/libarchive/archive_write_add_filter_by_name.c
@@ -42,7 +42,7 @@ __FBSDID("$FreeBSD$");
#include "archive_private.h"
/* A table that maps names to functions. */
-static
+static const
struct { const char *name; int (*setter)(struct archive *); } names[] =
{
{ "b64encode", archive_write_add_filter_b64encode },
@@ -51,6 +51,7 @@ struct { const char *name; int (*setter)(struct archive *); } names[] =
{ "grzip", archive_write_add_filter_grzip },
{ "gzip", archive_write_add_filter_gzip },
{ "lrzip", archive_write_add_filter_lrzip },
+ { "lz4", archive_write_add_filter_lz4 },
{ "lzip", archive_write_add_filter_lzip },
{ "lzma", archive_write_add_filter_lzma },
{ "lzop", archive_write_add_filter_lzop },
diff --git a/3rdparty/libarchive/libarchive/archive_write_add_filter_bzip2.c b/3rdparty/libarchive/libarchive/archive_write_add_filter_bzip2.c
index 88da803a..68ed9579 100644
--- a/3rdparty/libarchive/libarchive/archive_write_add_filter_bzip2.c
+++ b/3rdparty/libarchive/libarchive/archive_write_add_filter_bzip2.c
@@ -105,7 +105,7 @@ archive_write_add_filter_bzip2(struct archive *_a)
#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
return (ARCHIVE_OK);
#else
- data->pdata = __archive_write_program_allocate();
+ data->pdata = __archive_write_program_allocate("bzip2");
if (data->pdata == NULL) {
free(data);
archive_set_error(&a->archive, ENOMEM, "Out of memory");
diff --git a/3rdparty/libarchive/libarchive/archive_write_add_filter_compress.c b/3rdparty/libarchive/libarchive/archive_write_add_filter_compress.c
deleted file mode 100644
index 26fcef4d..00000000
--- a/3rdparty/libarchive/libarchive/archive_write_add_filter_compress.c
+++ /dev/null
@@ -1,455 +0,0 @@
-/*-
- * Copyright (c) 2008 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(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.
- */
-
-/*-
- * Copyright (c) 1985, 1986, 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Diomidis Spinellis and James A. Woods, derived from original
- * work by Spencer Thomas and Joseph Orost.
- *
- * 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.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- */
-
-#include "archive_platform.h"
-
-__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_compress.c 201111 2009-12-28 03:33:05Z kientzle $");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#include "archive.h"
-#include "archive_private.h"
-#include "archive_write_private.h"
-
-#define HSIZE 69001 /* 95% occupancy */
-#define HSHIFT 8 /* 8 - trunc(log2(HSIZE / 65536)) */
-#define CHECK_GAP 10000 /* Ratio check interval. */
-
-#define MAXCODE(bits) ((1 << (bits)) - 1)
-
-/*
- * the next two codes should not be changed lightly, as they must not
- * lie within the contiguous general code space.
- */
-#define FIRST 257 /* First free entry. */
-#define CLEAR 256 /* Table clear output code. */
-
-struct private_data {
- int64_t in_count, out_count, checkpoint;
-
- int code_len; /* Number of bits/code. */
- int cur_maxcode; /* Maximum code, given n_bits. */
- int max_maxcode; /* Should NEVER generate this code. */
- int hashtab [HSIZE];
- unsigned short codetab [HSIZE];
- int first_free; /* First unused entry. */
- int compress_ratio;
-
- int cur_code, cur_fcode;
-
- int bit_offset;
- unsigned char bit_buf;
-
- unsigned char *compressed;
- size_t compressed_buffer_size;
- size_t compressed_offset;
-};
-
-static int archive_compressor_compress_open(struct archive_write_filter *);
-static int archive_compressor_compress_write(struct archive_write_filter *,
- const void *, size_t);
-static int archive_compressor_compress_close(struct archive_write_filter *);
-static int archive_compressor_compress_free(struct archive_write_filter *);
-
-#if ARCHIVE_VERSION_NUMBER < 4000000
-int
-archive_write_set_compression_compress(struct archive *a)
-{
- __archive_write_filters_free(a);
- return (archive_write_add_filter_compress(a));
-}
-#endif
-
-/*
- * Add a compress filter to this write handle.
- */
-int
-archive_write_add_filter_compress(struct archive *_a)
-{
- struct archive_write *a = (struct archive_write *)_a;
- struct archive_write_filter *f = __archive_write_allocate_filter(_a);
-
- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_add_filter_compress");
- f->open = &archive_compressor_compress_open;
- f->code = ARCHIVE_FILTER_COMPRESS;
- f->name = "compress";
- return (ARCHIVE_OK);
-}
-
-/*
- * Setup callback.
- */
-static int
-archive_compressor_compress_open(struct archive_write_filter *f)
-{
- int ret;
- struct private_data *state;
- size_t bs = 65536, bpb;
-
- f->code = ARCHIVE_FILTER_COMPRESS;
- f->name = "compress";
-
- ret = __archive_write_open_filter(f->next_filter);
- if (ret != ARCHIVE_OK)
- return (ret);
-
- state = (struct private_data *)calloc(1, sizeof(*state));
- if (state == NULL) {
- archive_set_error(f->archive, ENOMEM,
- "Can't allocate data for compression");
- return (ARCHIVE_FATAL);
- }
-
- if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
- /* Buffer size should be a multiple number of the of bytes
- * per block for performance. */
- bpb = archive_write_get_bytes_per_block(f->archive);
- if (bpb > bs)
- bs = bpb;
- else if (bpb != 0)
- bs -= bs % bpb;
- }
- state->compressed_buffer_size = bs;
- state->compressed = malloc(state->compressed_buffer_size);
-
- if (state->compressed == NULL) {
- archive_set_error(f->archive, ENOMEM,
- "Can't allocate data for compression buffer");
- free(state);
- return (ARCHIVE_FATAL);
- }
-
- f->write = archive_compressor_compress_write;
- f->close = archive_compressor_compress_close;
- f->free = archive_compressor_compress_free;
-
- state->max_maxcode = 0x10000; /* Should NEVER generate this code. */
- state->in_count = 0; /* Length of input. */
- state->bit_buf = 0;
- state->bit_offset = 0;
- state->out_count = 3; /* Includes 3-byte header mojo. */
- state->compress_ratio = 0;
- state->checkpoint = CHECK_GAP;
- state->code_len = 9;
- state->cur_maxcode = MAXCODE(state->code_len);
- state->first_free = FIRST;
-
- memset(state->hashtab, 0xff, sizeof(state->hashtab));
-
- /* Prime output buffer with a gzip header. */
- state->compressed[0] = 0x1f; /* Compress */
- state->compressed[1] = 0x9d;
- state->compressed[2] = 0x90; /* Block mode, 16bit max */
- state->compressed_offset = 3;
-
- f->data = state;
- return (0);
-}
-
-/*-
- * Output the given code.
- * Inputs:
- * code: A n_bits-bit integer. If == -1, then EOF. This assumes
- * that n_bits <= (long)wordsize - 1.
- * Outputs:
- * Outputs code to the file.
- * Assumptions:
- * Chars are 8 bits long.
- * Algorithm:
- * Maintain a BITS character long buffer (so that 8 codes will
- * fit in it exactly). Use the VAX insv instruction to insert each
- * code in turn. When the buffer fills up empty it and start over.
- */
-
-static const unsigned char rmask[9] =
- {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
-
-static int
-output_byte(struct archive_write_filter *f, unsigned char c)
-{
- struct private_data *state = f->data;
-
- state->compressed[state->compressed_offset++] = c;
- ++state->out_count;
-
- if (state->compressed_buffer_size == state->compressed_offset) {
- int ret = __archive_write_filter(f->next_filter,
- state->compressed, state->compressed_buffer_size);
- if (ret != ARCHIVE_OK)
- return ARCHIVE_FATAL;
- state->compressed_offset = 0;
- }
-
- return ARCHIVE_OK;
-}
-
-static int
-output_code(struct archive_write_filter *f, int ocode)
-{
- struct private_data *state = f->data;
- int bits, ret, clear_flg, bit_offset;
-
- clear_flg = ocode == CLEAR;
-
- /*
- * Since ocode is always >= 8 bits, only need to mask the first
- * hunk on the left.
- */
- bit_offset = state->bit_offset % 8;
- state->bit_buf |= (ocode << bit_offset) & 0xff;
- output_byte(f, state->bit_buf);
-
- bits = state->code_len - (8 - bit_offset);
- ocode >>= 8 - bit_offset;
- /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
- if (bits >= 8) {
- output_byte(f, ocode & 0xff);
- ocode >>= 8;
- bits -= 8;
- }
- /* Last bits. */
- state->bit_offset += state->code_len;
- state->bit_buf = ocode & rmask[bits];
- if (state->bit_offset == state->code_len * 8)
- state->bit_offset = 0;
-
- /*
- * If the next entry is going to be too big for the ocode size,
- * then increase it, if possible.
- */
- if (clear_flg || state->first_free > state->cur_maxcode) {
- /*
- * Write the whole buffer, because the input side won't
- * discover the size increase until after it has read it.
- */
- if (state->bit_offset > 0) {
- while (state->bit_offset < state->code_len * 8) {
- ret = output_byte(f, state->bit_buf);
- if (ret != ARCHIVE_OK)
- return ret;
- state->bit_offset += 8;
- state->bit_buf = 0;
- }
- }
- state->bit_buf = 0;
- state->bit_offset = 0;
-
- if (clear_flg) {
- state->code_len = 9;
- state->cur_maxcode = MAXCODE(state->code_len);
- } else {
- state->code_len++;
- if (state->code_len == 16)
- state->cur_maxcode = state->max_maxcode;
- else
- state->cur_maxcode = MAXCODE(state->code_len);
- }
- }
-
- return (ARCHIVE_OK);
-}
-
-static int
-output_flush(struct archive_write_filter *f)
-{
- struct private_data *state = f->data;
- int ret;
-
- /* At EOF, write the rest of the buffer. */
- if (state->bit_offset % 8) {
- state->code_len = (state->bit_offset % 8 + 7) / 8;
- ret = output_byte(f, state->bit_buf);
- if (ret != ARCHIVE_OK)
- return ret;
- }
-
- return (ARCHIVE_OK);
-}
-
-/*
- * Write data to the compressed stream.
- */
-static int
-archive_compressor_compress_write(struct archive_write_filter *f,
- const void *buff, size_t length)
-{
- struct private_data *state = (struct private_data *)f->data;
- int i;
- int ratio;
- int c, disp, ret;
- const unsigned char *bp;
-
- if (length == 0)
- return ARCHIVE_OK;
-
- bp = buff;
-
- if (state->in_count == 0) {
- state->cur_code = *bp++;
- ++state->in_count;
- --length;
- }
-
- while (length--) {
- c = *bp++;
- state->in_count++;
- state->cur_fcode = (c << 16) + state->cur_code;
- i = ((c << HSHIFT) ^ state->cur_code); /* Xor hashing. */
-
- if (state->hashtab[i] == state->cur_fcode) {
- state->cur_code = state->codetab[i];
- continue;
- }
- if (state->hashtab[i] < 0) /* Empty slot. */
- goto nomatch;
- /* Secondary hash (after G. Knott). */
- if (i == 0)
- disp = 1;
- else
- disp = HSIZE - i;
- probe:
- if ((i -= disp) < 0)
- i += HSIZE;
-
- if (state->hashtab[i] == state->cur_fcode) {
- state->cur_code = state->codetab[i];
- continue;
- }
- if (state->hashtab[i] >= 0)
- goto probe;
- nomatch:
- ret = output_code(f, state->cur_code);
- if (ret != ARCHIVE_OK)
- return ret;
- state->cur_code = c;
- if (state->first_free < state->max_maxcode) {
- state->codetab[i] = state->first_free++; /* code -> hashtable */
- state->hashtab[i] = state->cur_fcode;
- continue;
- }
- if (state->in_count < state->checkpoint)
- continue;
-
- state->checkpoint = state->in_count + CHECK_GAP;
-
- if (state->in_count <= 0x007fffff && state->out_count != 0)
- ratio = (int)(state->in_count * 256 / state->out_count);
- else if ((ratio = (int)(state->out_count / 256)) == 0)
- ratio = 0x7fffffff;
- else
- ratio = (int)(state->in_count / ratio);
-
- if (ratio > state->compress_ratio)
- state->compress_ratio = ratio;
- else {
- state->compress_ratio = 0;
- memset(state->hashtab, 0xff, sizeof(state->hashtab));
- state->first_free = FIRST;
- ret = output_code(f, CLEAR);
- if (ret != ARCHIVE_OK)
- return ret;
- }
- }
-
- return (ARCHIVE_OK);
-}
-
-
-/*
- * Finish the compression...
- */
-static int
-archive_compressor_compress_close(struct archive_write_filter *f)
-{
- struct private_data *state = (struct private_data *)f->data;
- int ret, ret2;
-
- ret = output_code(f, state->cur_code);
- if (ret != ARCHIVE_OK)
- goto cleanup;
- ret = output_flush(f);
- if (ret != ARCHIVE_OK)
- goto cleanup;
-
- /* Write the last block */
- ret = __archive_write_filter(f->next_filter,
- state->compressed, state->compressed_offset);
-cleanup:
- ret2 = __archive_write_close_filter(f->next_filter);
- if (ret > ret2)
- ret = ret2;
- free(state->compressed);
- free(state);
- return (ret);
-}
-
-static int
-archive_compressor_compress_free(struct archive_write_filter *f)
-{
- (void)f; /* UNUSED */
- return (ARCHIVE_OK);
-}
diff --git a/3rdparty/libarchive/libarchive/archive_write_add_filter_grzip.c b/3rdparty/libarchive/libarchive/archive_write_add_filter_grzip.c
deleted file mode 100644
index 8dc287ea..00000000
--- a/3rdparty/libarchive/libarchive/archive_write_add_filter_grzip.c
+++ /dev/null
@@ -1,135 +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$");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-
-#include "archive.h"
-#include "archive_write_private.h"
-
-struct write_grzip {
- struct archive_write_program_data *pdata;
-};
-
-static int archive_write_grzip_open(struct archive_write_filter *);
-static int archive_write_grzip_options(struct archive_write_filter *,
- const char *, const char *);
-static int archive_write_grzip_write(struct archive_write_filter *,
- const void *, size_t);
-static int archive_write_grzip_close(struct archive_write_filter *);
-static int archive_write_grzip_free(struct archive_write_filter *);
-
-int
-archive_write_add_filter_grzip(struct archive *_a)
-{
- struct archive_write_filter *f = __archive_write_allocate_filter(_a);
- struct write_grzip *data;
-
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_add_filter_grzip");
-
- data = calloc(1, sizeof(*data));
- if (data == NULL) {
- archive_set_error(_a, ENOMEM, "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- data->pdata = __archive_write_program_allocate();
- if (data->pdata == NULL) {
- free(data);
- archive_set_error(_a, ENOMEM, "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
-
- f->name = "grzip";
- f->code = ARCHIVE_FILTER_GRZIP;
- f->data = data;
- f->open = archive_write_grzip_open;
- f->options = archive_write_grzip_options;
- f->write = archive_write_grzip_write;
- f->close = archive_write_grzip_close;
- f->free = archive_write_grzip_free;
-
- /* Note: This filter always uses an external program, so we
- * return "warn" to inform of the fact. */
- archive_set_error(_a, ARCHIVE_ERRNO_MISC,
- "Using external grzip program for grzip compression");
- return (ARCHIVE_WARN);
-}
-
-static int
-archive_write_grzip_options(struct archive_write_filter *f, const char *key,
- const char *value)
-{
- (void)f; /* UNUSED */
- (void)key; /* UNUSED */
- (void)value; /* UNUSED */
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
-}
-
-static int
-archive_write_grzip_open(struct archive_write_filter *f)
-{
- struct write_grzip *data = (struct write_grzip *)f->data;
-
- return __archive_write_program_open(f, data->pdata, "grzip");
-}
-
-static int
-archive_write_grzip_write(struct archive_write_filter *f,
- const void *buff, size_t length)
-{
- struct write_grzip *data = (struct write_grzip *)f->data;
-
- return __archive_write_program_write(f, data->pdata, buff, length);
-}
-
-static int
-archive_write_grzip_close(struct archive_write_filter *f)
-{
- struct write_grzip *data = (struct write_grzip *)f->data;
-
- return __archive_write_program_close(f, data->pdata);
-}
-
-static int
-archive_write_grzip_free(struct archive_write_filter *f)
-{
- struct write_grzip *data = (struct write_grzip *)f->data;
-
- __archive_write_program_free(data->pdata);
- free(data);
- return (ARCHIVE_OK);
-}
diff --git a/3rdparty/libarchive/libarchive/archive_write_add_filter_gzip.c b/3rdparty/libarchive/libarchive/archive_write_add_filter_gzip.c
index da4607bb..04eb06c1 100644
--- a/3rdparty/libarchive/libarchive/archive_write_add_filter_gzip.c
+++ b/3rdparty/libarchive/libarchive/archive_write_add_filter_gzip.c
@@ -119,7 +119,7 @@ archive_write_add_filter_gzip(struct archive *_a)
data->compression_level = Z_DEFAULT_COMPRESSION;
return (ARCHIVE_OK);
#else
- data->pdata = __archive_write_program_allocate();
+ data->pdata = __archive_write_program_allocate("gzip");
if (data->pdata == NULL) {
free(data);
archive_set_error(&a->archive, ENOMEM, "Out of memory");
diff --git a/3rdparty/libarchive/libarchive/archive_write_add_filter_lrzip.c b/3rdparty/libarchive/libarchive/archive_write_add_filter_lrzip.c
deleted file mode 100644
index 85fdf6af..00000000
--- a/3rdparty/libarchive/libarchive/archive_write_add_filter_lrzip.c
+++ /dev/null
@@ -1,192 +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$");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#include "archive.h"
-#include "archive_string.h"
-#include "archive_write_private.h"
-
-struct write_lrzip {
- struct archive_write_program_data *pdata;
- int compression_level;
- enum { lzma = 0, bzip2, gzip, lzo, zpaq } compression;
-};
-
-static int archive_write_lrzip_open(struct archive_write_filter *);
-static int archive_write_lrzip_options(struct archive_write_filter *,
- const char *, const char *);
-static int archive_write_lrzip_write(struct archive_write_filter *,
- const void *, size_t);
-static int archive_write_lrzip_close(struct archive_write_filter *);
-static int archive_write_lrzip_free(struct archive_write_filter *);
-
-int
-archive_write_add_filter_lrzip(struct archive *_a)
-{
- struct archive_write_filter *f = __archive_write_allocate_filter(_a);
- struct write_lrzip *data;
-
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_add_filter_lrzip");
-
- data = calloc(1, sizeof(*data));
- if (data == NULL) {
- archive_set_error(_a, ENOMEM, "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- data->pdata = __archive_write_program_allocate();
- if (data->pdata == NULL) {
- free(data);
- archive_set_error(_a, ENOMEM, "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
-
- f->name = "lrzip";
- f->code = ARCHIVE_FILTER_LRZIP;
- f->data = data;
- f->open = archive_write_lrzip_open;
- f->options = archive_write_lrzip_options;
- f->write = archive_write_lrzip_write;
- f->close = archive_write_lrzip_close;
- f->free = archive_write_lrzip_free;
-
- /* Note: This filter always uses an external program, so we
- * return "warn" to inform of the fact. */
- archive_set_error(_a, ARCHIVE_ERRNO_MISC,
- "Using external lrzip program for lrzip compression");
- return (ARCHIVE_WARN);
-}
-
-static int
-archive_write_lrzip_options(struct archive_write_filter *f, const char *key,
- const char *value)
-{
- struct write_lrzip *data = (struct write_lrzip *)f->data;
-
- if (strcmp(key, "compression") == 0) {
- if (value == NULL)
- return (ARCHIVE_WARN);
- else if (strcmp(value, "bzip2") == 0)
- data->compression = bzip2;
- else if (strcmp(value, "gzip") == 0)
- data->compression = gzip;
- else if (strcmp(value, "lzo") == 0)
- data->compression = lzo;
- else if (strcmp(value, "zpaq") == 0)
- data->compression = zpaq;
- else
- return (ARCHIVE_WARN);
- return (ARCHIVE_OK);
- } else if (strcmp(key, "compression-level") == 0) {
- if (value == NULL || !(value[0] >= '1' && value[0] <= '9') ||
- value[1] != '\0')
- return (ARCHIVE_WARN);
- data->compression_level = value[0] - '0';
- return (ARCHIVE_OK);
- }
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
-}
-
-static int
-archive_write_lrzip_open(struct archive_write_filter *f)
-{
- struct write_lrzip *data = (struct write_lrzip *)f->data;
- struct archive_string as;
- int r;
-
- archive_string_init(&as);
- archive_strcpy(&as, "lrzip -q");
-
- /* Specify compression type. */
- switch (data->compression) {
- case lzma:/* default compression */
- break;
- case bzip2:
- archive_strcat(&as, " -b");
- break;
- case gzip:
- archive_strcat(&as, " -g");
- break;
- case lzo:
- archive_strcat(&as, " -l");
- break;
- case zpaq:
- archive_strcat(&as, " -z");
- break;
- }
-
- /* Specify compression level. */
- if (data->compression_level > 0) {
- archive_strcat(&as, " -L ");
- archive_strappend_char(&as, '0' + data->compression_level);
- }
-
- r = __archive_write_program_open(f, data->pdata, as.s);
- archive_string_free(&as);
- return (r);
-}
-
-static int
-archive_write_lrzip_write(struct archive_write_filter *f,
- const void *buff, size_t length)
-{
- struct write_lrzip *data = (struct write_lrzip *)f->data;
-
- return __archive_write_program_write(f, data->pdata, buff, length);
-}
-
-static int
-archive_write_lrzip_close(struct archive_write_filter *f)
-{
- struct write_lrzip *data = (struct write_lrzip *)f->data;
-
- return __archive_write_program_close(f, data->pdata);
-}
-
-static int
-archive_write_lrzip_free(struct archive_write_filter *f)
-{
- struct write_lrzip *data = (struct write_lrzip *)f->data;
-
- __archive_write_program_free(data->pdata);
- free(data);
- return (ARCHIVE_OK);
-}
diff --git a/3rdparty/libarchive/libarchive/archive_write_add_filter_lzop.c b/3rdparty/libarchive/libarchive/archive_write_add_filter_lzop.c
deleted file mode 100644
index 088ecea5..00000000
--- a/3rdparty/libarchive/libarchive/archive_write_add_filter_lzop.c
+++ /dev/null
@@ -1,486 +0,0 @@
-/*-
- * Copyright (c) 2012 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"
-
-__FBSDID("$FreeBSD$");
-//#undef HAVE_LZO_LZOCONF_H
-//#undef HAVE_LZO_LZO1X_H
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#include <time.h>
-#ifdef HAVE_LZO_LZOCONF_H
-#include <lzo/lzoconf.h>
-#endif
-#ifdef HAVE_LZO_LZO1X_H
-#include <lzo/lzo1x.h>
-#endif
-
-#include "archive.h"
-#include "archive_string.h"
-#include "archive_endian.h"
-#include "archive_write_private.h"
-
-enum lzo_method {
- METHOD_LZO1X_1 = 1,
- METHOD_LZO1X_1_15 = 2,
- METHOD_LZO1X_999 = 3
-};
-struct write_lzop {
- int compression_level;
-#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
- unsigned char *uncompressed;
- size_t uncompressed_buffer_size;
- size_t uncompressed_avail_bytes;
- unsigned char *compressed;
- size_t compressed_buffer_size;
- enum lzo_method method;
- unsigned char level;
- lzo_voidp work_buffer;
- lzo_uint32 work_buffer_size;
- char header_written;
-#else
- struct archive_write_program_data *pdata;
-#endif
-};
-
-static int archive_write_lzop_open(struct archive_write_filter *);
-static int archive_write_lzop_options(struct archive_write_filter *,
- const char *, const char *);
-static int archive_write_lzop_write(struct archive_write_filter *,
- const void *, size_t);
-static int archive_write_lzop_close(struct archive_write_filter *);
-static int archive_write_lzop_free(struct archive_write_filter *);
-
-#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
-/* Maximum block size. */
-#define BLOCK_SIZE (256 * 1024)
-/* Block infomation is composed of uncompressed size(4 bytes),
- * compressed size(4 bytes) and the checksum of uncompressed data(4 bytes)
- * in this lzop writer. */
-#define BLOCK_INfO_SIZE 12
-
-#define HEADER_VERSION 9
-#define HEADER_LIBVERSION 11
-#define HEADER_METHOD 15
-#define HEADER_LEVEL 16
-#define HEADER_MTIME_LOW 25
-#define HEADER_MTIME_HIGH 29
-#define HEADER_H_CHECKSUM 34
-
-/*
- * Header template.
- */
-static const unsigned char header[] = {
- /* LZOP Magic code 9 bytes */
- 0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a,
- /* LZOP utility version(fake data) 2 bytes */
- 0x10, 0x30,
- /* LZO library version 2 bytes */
- 0x09, 0x40,
- /* Minimum required LZO library version 2 bytes */
- 0x09, 0x40,
- /* Method */
- 1,
- /* Level */
- 5,
- /* Flags 4 bytes
- * -OS Unix
- * -Stdout
- * -Stdin
- * -Adler32 used for uncompressed data 4 bytes */
- 0x03, 0x00, 0x00, 0x0d,
- /* Mode (AE_IFREG | 0644) 4 bytes */
- 0x00, 0x00, 0x81, 0xa4,
- /* Mtime low 4 bytes */
- 0x00, 0x00, 0x00, 0x00,
- /* Mtime high 4 bytes */
- 0x00, 0x00, 0x00, 0x00,
- /* Filename length */
- 0x00,
- /* Header checksum 4 bytes */
- 0x00, 0x00, 0x00, 0x00,
-};
-#endif
-
-int
-archive_write_add_filter_lzop(struct archive *_a)
-{
- struct archive_write_filter *f = __archive_write_allocate_filter(_a);
- struct write_lzop *data;
-
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_add_filter_lzop");
-
- data = calloc(1, sizeof(*data));
- if (data == NULL) {
- archive_set_error(_a, ENOMEM, "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
-
- f->name = "lzop";
- f->code = ARCHIVE_FILTER_LZOP;
- f->data = data;
- f->open = archive_write_lzop_open;
- f->options = archive_write_lzop_options;
- f->write = archive_write_lzop_write;
- f->close = archive_write_lzop_close;
- f->free = archive_write_lzop_free;
-#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
- if (lzo_init() != LZO_E_OK) {
- free(data);
- archive_set_error(_a, ARCHIVE_ERRNO_MISC,
- "lzo_init(type check) failed");
- return (ARCHIVE_FATAL);
- }
- if (lzo_version() < 0x940) {
- free(data);
- archive_set_error(_a, ARCHIVE_ERRNO_MISC,
- "liblzo library is too old(%s < 0.940)",
- lzo_version_string());
- return (ARCHIVE_FATAL);
- }
- data->compression_level = 5;
- return (ARCHIVE_OK);
-#else
- data->pdata = __archive_write_program_allocate();
- if (data->pdata == NULL) {
- free(data);
- archive_set_error(_a, ENOMEM, "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- data->compression_level = 0;
- /* Note: We return "warn" to inform of using an external lzop
- * program. */
- archive_set_error(_a, ARCHIVE_ERRNO_MISC,
- "Using external lzop program for lzop compression");
- return (ARCHIVE_WARN);
-#endif
-}
-
-static int
-archive_write_lzop_free(struct archive_write_filter *f)
-{
- struct write_lzop *data = (struct write_lzop *)f->data;
-
-#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
- free(data->uncompressed);
- free(data->compressed);
- free(data->work_buffer);
-#else
- __archive_write_program_free(data->pdata);
-#endif
- free(data);
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_lzop_options(struct archive_write_filter *f, const char *key,
- const char *value)
-{
- struct write_lzop *data = (struct write_lzop *)f->data;
-
- if (strcmp(key, "compression-level") == 0) {
- if (value == NULL || !(value[0] >= '1' && value[0] <= '9') ||
- value[1] != '\0')
- return (ARCHIVE_WARN);
- data->compression_level = value[0] - '0';
- return (ARCHIVE_OK);
- }
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
-}
-
-#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
-static int
-archive_write_lzop_open(struct archive_write_filter *f)
-{
- struct write_lzop *data = (struct write_lzop *)f->data;
- int ret;
-
- ret = __archive_write_open_filter(f->next_filter);
- if (ret != ARCHIVE_OK)
- return (ret);
-
- switch (data->compression_level) {
- case 1:
- data->method = METHOD_LZO1X_1_15; data->level = 1; break;
- default:
- case 2: case 3: case 4: case 5: case 6:
- data->method = METHOD_LZO1X_1; data->level = 5; break;
- case 7:
- data->method = METHOD_LZO1X_999; data->level = 7; break;
- case 8:
- data->method = METHOD_LZO1X_999; data->level = 8; break;
- case 9:
- data->method = METHOD_LZO1X_999; data->level = 9; break;
- }
- switch (data->method) {
- case METHOD_LZO1X_1:
- data->work_buffer_size = LZO1X_1_MEM_COMPRESS; break;
- case METHOD_LZO1X_1_15:
- data->work_buffer_size = LZO1X_1_15_MEM_COMPRESS; break;
- case METHOD_LZO1X_999:
- data->work_buffer_size = LZO1X_999_MEM_COMPRESS; break;
- }
- if (data->work_buffer == NULL) {
- data->work_buffer = (lzo_voidp)malloc(data->work_buffer_size);
- if (data->work_buffer == NULL) {
- archive_set_error(f->archive, ENOMEM,
- "Can't allocate data for compression buffer");
- return (ARCHIVE_FATAL);
- }
- }
- if (data->compressed == NULL) {
- data->compressed_buffer_size = sizeof(header) +
- BLOCK_SIZE + (BLOCK_SIZE >> 4) + 64 + 3;
- data->compressed = (unsigned char *)
- malloc(data->compressed_buffer_size);
- if (data->compressed == NULL) {
- archive_set_error(f->archive, ENOMEM,
- "Can't allocate data for compression buffer");
- return (ARCHIVE_FATAL);
- }
- }
- if (data->uncompressed == NULL) {
- data->uncompressed_buffer_size = BLOCK_SIZE;
- data->uncompressed = (unsigned char *)
- malloc(data->uncompressed_buffer_size);
- if (data->uncompressed == NULL) {
- archive_set_error(f->archive, ENOMEM,
- "Can't allocate data for compression buffer");
- return (ARCHIVE_FATAL);
- }
- data->uncompressed_avail_bytes = BLOCK_SIZE;
- }
- return (ARCHIVE_OK);
-}
-
-static int
-make_header(struct archive_write_filter *f)
-{
- struct write_lzop *data = (struct write_lzop *)f->data;
- int64_t t;
- uint32_t checksum;
-
- memcpy(data->compressed, header, sizeof(header));
- /* Overwrite library version. */
- data->compressed[HEADER_LIBVERSION] = (unsigned char )
- (lzo_version() >> 8) & 0xff;
- data->compressed[HEADER_LIBVERSION + 1] = (unsigned char )
- lzo_version() & 0xff;
- /* Overwrite method and level. */
- data->compressed[HEADER_METHOD] = (unsigned char)data->method;
- data->compressed[HEADER_LEVEL] = data->level;
- /* Overwrite mtime with current time. */
- t = (int64_t)time(NULL);
- archive_be32enc(&data->compressed[HEADER_MTIME_LOW],
- (uint32_t)(t & 0xffffffff));
- archive_be32enc(&data->compressed[HEADER_MTIME_HIGH],
- (uint32_t)((t >> 32) & 0xffffffff));
- /* Overwrite header checksum with calculated value. */
- checksum = lzo_adler32(1, data->compressed + HEADER_VERSION,
- (lzo_uint)(HEADER_H_CHECKSUM - HEADER_VERSION));
- archive_be32enc(&data->compressed[HEADER_H_CHECKSUM], checksum);
- return (sizeof(header));
-}
-
-static int
-drive_compressor(struct archive_write_filter *f)
-{
- struct write_lzop *data = (struct write_lzop *)f->data;
- unsigned char *p;
- const int block_info_bytes = 12;
- int header_bytes, r;
- lzo_uint usize, csize;
- uint32_t checksum;
-
- if (!data->header_written) {
- header_bytes = make_header(f);
- data->header_written = 1;
- } else
- header_bytes = 0;
- p = data->compressed;
-
- usize = (lzo_uint)
- (data->uncompressed_buffer_size - data->uncompressed_avail_bytes);
- csize = 0;
- switch (data->method) {
- default:
- case METHOD_LZO1X_1:
- r = lzo1x_1_compress(data->uncompressed, usize,
- p + header_bytes + block_info_bytes, &csize,
- data->work_buffer);
- break;
- case METHOD_LZO1X_1_15:
- r = lzo1x_1_15_compress(data->uncompressed, usize,
- p + header_bytes + block_info_bytes, &csize,
- data->work_buffer);
- break;
- case METHOD_LZO1X_999:
- r = lzo1x_999_compress_level(data->uncompressed, usize,
- p + header_bytes + block_info_bytes, &csize,
- data->work_buffer, NULL, 0, 0, data->level);
- break;
- }
- if (r != LZO_E_OK) {
- archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
- "Lzop compression failed: returned status %d", r);
- return (ARCHIVE_FATAL);
- }
-
- /* Store uncompressed size. */
- archive_be32enc(p + header_bytes, (uint32_t)usize);
- /* Store the checksum of the uncompressed data. */
- checksum = lzo_adler32(1, data->uncompressed, usize);
- archive_be32enc(p + header_bytes + 8, checksum);
-
- if (csize < usize) {
- /* Store compressed size. */
- archive_be32enc(p + header_bytes + 4, (uint32_t)csize);
- r = __archive_write_filter(f->next_filter, data->compressed,
- header_bytes + block_info_bytes + csize);
- } else {
- /*
- * This case, we output uncompressed data instead.
- */
- /* Store uncompressed size as compressed size. */
- archive_be32enc(p + header_bytes + 4, (uint32_t)usize);
- r = __archive_write_filter(f->next_filter, data->compressed,
- header_bytes + block_info_bytes);
- if (r != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- r = __archive_write_filter(f->next_filter, data->uncompressed,
- usize);
- }
-
- if (r != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_lzop_write(struct archive_write_filter *f,
- const void *buff, size_t length)
-{
- struct write_lzop *data = (struct write_lzop *)f->data;
- const char *p = buff;
- int r;
-
- do {
- if (data->uncompressed_avail_bytes > length) {
- memcpy(data->uncompressed
- + data->uncompressed_buffer_size
- - data->uncompressed_avail_bytes,
- p, length);
- data->uncompressed_avail_bytes -= length;
- return (ARCHIVE_OK);
- }
-
- memcpy(data->uncompressed + data->uncompressed_buffer_size
- - data->uncompressed_avail_bytes,
- p, data->uncompressed_avail_bytes);
- length -= data->uncompressed_avail_bytes;
- p += data->uncompressed_avail_bytes;
- data->uncompressed_avail_bytes = 0;
-
- r = drive_compressor(f);
- if (r != ARCHIVE_OK) return (r);
- data->uncompressed_avail_bytes = BLOCK_SIZE;
- } while (length);
-
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_lzop_close(struct archive_write_filter *f)
-{
- struct write_lzop *data = (struct write_lzop *)f->data;
- const uint32_t endmark = 0;
- int r;
-
- if (data->uncompressed_avail_bytes < BLOCK_SIZE) {
- /* Compress and output remaining data. */
- r = drive_compressor(f);
- if (r != ARCHIVE_OK)
- return (r);
- }
- /* Write a zero uncompressed size as the end mark of the series of
- * compressed block. */
- r = __archive_write_filter(f->next_filter, &endmark, sizeof(endmark));
- if (r != ARCHIVE_OK)
- return (r);
- return (__archive_write_close_filter(f->next_filter));
-}
-
-#else
-static int
-archive_write_lzop_open(struct archive_write_filter *f)
-{
- struct write_lzop *data = (struct write_lzop *)f->data;
- struct archive_string as;
- int r;
-
- archive_string_init(&as);
- archive_strcpy(&as, "lzop");
- /* Specify compression level. */
- if (data->compression_level > 0) {
- archive_strappend_char(&as, ' ');
- archive_strappend_char(&as, '-');
- archive_strappend_char(&as, '0' + data->compression_level);
- }
-
- r = __archive_write_program_open(f, data->pdata, as.s);
- archive_string_free(&as);
- return (r);
-}
-
-static int
-archive_write_lzop_write(struct archive_write_filter *f,
- const void *buff, size_t length)
-{
- struct write_lzop *data = (struct write_lzop *)f->data;
-
- return __archive_write_program_write(f, data->pdata, buff, length);
-}
-
-static int
-archive_write_lzop_close(struct archive_write_filter *f)
-{
- struct write_lzop *data = (struct write_lzop *)f->data;
-
- return __archive_write_program_close(f, data->pdata);
-}
-#endif
diff --git a/3rdparty/libarchive/libarchive/archive_write_add_filter_program.c b/3rdparty/libarchive/libarchive/archive_write_add_filter_program.c
index fc232da0..660f693f 100644
--- a/3rdparty/libarchive/libarchive/archive_write_add_filter_program.c
+++ b/3rdparty/libarchive/libarchive/archive_write_add_filter_program.c
@@ -68,6 +68,7 @@ struct archive_write_program_data {
char *child_buf;
size_t child_buf_len, child_buf_avail;
+ char *program_name;
};
struct private_data {
@@ -91,7 +92,7 @@ archive_write_add_filter_program(struct archive *_a, const char *cmd)
{
struct archive_write_filter *f = __archive_write_allocate_filter(_a);
struct private_data *data;
- static const char *prefix = "Program: ";
+ static const char prefix[] = "Program: ";
archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_add_filter_program");
@@ -105,7 +106,7 @@ archive_write_add_filter_program(struct archive *_a, const char *cmd)
if (data->cmd == NULL)
goto memerr;
- data->pdata = __archive_write_program_allocate();
+ data->pdata = __archive_write_program_allocate(cmd);
if (data->pdata == NULL)
goto memerr;
@@ -174,7 +175,7 @@ archive_compressor_program_free(struct archive_write_filter *f)
* Allocate resources for executing an external program.
*/
struct archive_write_program_data *
-__archive_write_program_allocate(void)
+__archive_write_program_allocate(const char *program)
{
struct archive_write_program_data *data;
@@ -183,6 +184,7 @@ __archive_write_program_allocate(void)
return (data);
data->child_stdin = -1;
data->child_stdout = -1;
+ data->program_name = strdup(program);
return (data);
}
@@ -198,6 +200,7 @@ __archive_write_program_free(struct archive_write_program_data *data)
if (data->child)
CloseHandle(data->child);
#endif
+ free(data->program_name);
free(data->child_buf);
free(data);
}
@@ -231,7 +234,7 @@ __archive_write_program_open(struct archive_write_filter *f,
&data->child_stdout);
if (child == -1) {
archive_set_error(f->archive, EINVAL,
- "Can't initialise filter");
+ "Can't launch external program: %s", cmd);
return (ARCHIVE_FATAL);
}
#if defined(_WIN32) && !defined(__CYGWIN__)
@@ -242,7 +245,7 @@ __archive_write_program_open(struct archive_write_filter *f,
close(data->child_stdout);
data->child_stdout = -1;
archive_set_error(f->archive, EINVAL,
- "Can't initialise filter");
+ "Can't launch external program: %s", cmd);
return (ARCHIVE_FATAL);
}
#else
@@ -334,7 +337,7 @@ __archive_write_program_write(struct archive_write_filter *f,
ret = child_write(f, data, buf, length);
if (ret == -1 || ret == 0) {
archive_set_error(f->archive, EIO,
- "Can't write to filter");
+ "Can't write to program: %s", data->program_name);
return (ARCHIVE_FATAL);
}
length -= ret;
@@ -373,7 +376,7 @@ __archive_write_program_close(struct archive_write_filter *f,
if (bytes_read == -1) {
archive_set_error(f->archive, errno,
- "Read from filter failed unexpectedly.");
+ "Error reading from program: %s", data->program_name);
ret = ARCHIVE_FATAL;
goto cleanup;
}
@@ -403,7 +406,7 @@ cleanup:
if (status != 0) {
archive_set_error(f->archive, EIO,
- "Filter exited with failure.");
+ "Error closing program: %s", data->program_name);
ret = ARCHIVE_FATAL;
}
r1 = __archive_write_close_filter(f->next_filter);
diff --git a/3rdparty/libarchive/libarchive/archive_write_add_filter_uuencode.c b/3rdparty/libarchive/libarchive/archive_write_add_filter_uuencode.c
deleted file mode 100644
index 23d9c150..00000000
--- a/3rdparty/libarchive/libarchive/archive_write_add_filter_uuencode.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/*-
- * Copyright (c) 2012 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"
-
-__FBSDID("$FreeBSD$");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#include "archive.h"
-#include "archive_private.h"
-#include "archive_string.h"
-#include "archive_write_private.h"
-
-#define LBYTES 45
-
-struct private_uuencode {
- int mode;
- struct archive_string name;
- struct archive_string encoded_buff;
- size_t bs;
- size_t hold_len;
- unsigned char hold[LBYTES];
-};
-
-static int archive_filter_uuencode_options(struct archive_write_filter *,
- const char *, const char *);
-static int archive_filter_uuencode_open(struct archive_write_filter *);
-static int archive_filter_uuencode_write(struct archive_write_filter *,
- const void *, size_t);
-static int archive_filter_uuencode_close(struct archive_write_filter *);
-static int archive_filter_uuencode_free(struct archive_write_filter *);
-static void uu_encode(struct archive_string *, const unsigned char *, size_t);
-static int64_t atol8(const char *, size_t);
-
-/*
- * Add a compress filter to this write handle.
- */
-int
-archive_write_add_filter_uuencode(struct archive *_a)
-{
- struct archive_write *a = (struct archive_write *)_a;
- struct archive_write_filter *f = __archive_write_allocate_filter(_a);
- struct private_uuencode *state;
-
- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_add_filter_uu");
-
- state = (struct private_uuencode *)calloc(1, sizeof(*state));
- if (state == NULL) {
- archive_set_error(f->archive, ENOMEM,
- "Can't allocate data for uuencode filter");
- return (ARCHIVE_FATAL);
- }
- archive_strcpy(&state->name, "-");
- state->mode = 0644;
-
- f->data = state;
- f->name = "uuencode";
- f->code = ARCHIVE_FILTER_UU;
- f->open = archive_filter_uuencode_open;
- f->options = archive_filter_uuencode_options;
- f->write = archive_filter_uuencode_write;
- f->close = archive_filter_uuencode_close;
- f->free = archive_filter_uuencode_free;
-
- return (ARCHIVE_OK);
-}
-
-/*
- * Set write options.
- */
-static int
-archive_filter_uuencode_options(struct archive_write_filter *f, const char *key,
- const char *value)
-{
- struct private_uuencode *state = (struct private_uuencode *)f->data;
-
- if (strcmp(key, "mode") == 0) {
- if (value == NULL) {
- archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
- "mode option requires octal digits");
- return (ARCHIVE_FAILED);
- }
- state->mode = (int)atol8(value, strlen(value)) & 0777;
- return (ARCHIVE_OK);
- } else if (strcmp(key, "name") == 0) {
- if (value == NULL) {
- archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
- "name option requires a string");
- return (ARCHIVE_FAILED);
- }
- archive_strcpy(&state->name, value);
- return (ARCHIVE_OK);
- }
-
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
-}
-
-/*
- * Setup callback.
- */
-static int
-archive_filter_uuencode_open(struct archive_write_filter *f)
-{
- struct private_uuencode *state = (struct private_uuencode *)f->data;
- size_t bs = 65536, bpb;
- int ret;
-
- ret = __archive_write_open_filter(f->next_filter);
- if (ret != ARCHIVE_OK)
- return (ret);
-
- if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
- /* Buffer size should be a multiple number of the of bytes
- * per block for performance. */
- bpb = archive_write_get_bytes_per_block(f->archive);
- if (bpb > bs)
- bs = bpb;
- else if (bpb != 0)
- bs -= bs % bpb;
- }
-
- state->bs = bs;
- if (archive_string_ensure(&state->encoded_buff, bs + 512) == NULL) {
- archive_set_error(f->archive, ENOMEM,
- "Can't allocate data for uuencode buffer");
- return (ARCHIVE_FATAL);
- }
-
- archive_string_sprintf(&state->encoded_buff, "begin %o %s\n",
- state->mode, state->name.s);
-
- f->data = state;
- return (0);
-}
-
-static void
-uu_encode(struct archive_string *as, const unsigned char *p, size_t len)
-{
- int c;
-
- c = (int)len;
- archive_strappend_char(as, c?c + 0x20:'`');
- for (; len >= 3; p += 3, len -= 3) {
- c = p[0] >> 2;
- archive_strappend_char(as, c?c + 0x20:'`');
- c = ((p[0] & 0x03) << 4) | ((p[1] & 0xf0) >> 4);
- archive_strappend_char(as, c?c + 0x20:'`');
- c = ((p[1] & 0x0f) << 2) | ((p[2] & 0xc0) >> 6);
- archive_strappend_char(as, c?c + 0x20:'`');
- c = p[2] & 0x3f;
- archive_strappend_char(as, c?c + 0x20:'`');
- }
- if (len > 0) {
- c = p[0] >> 2;
- archive_strappend_char(as, c?c + 0x20:'`');
- c = (p[0] & 0x03) << 4;
- if (len == 1) {
- archive_strappend_char(as, c?c + 0x20:'`');
- archive_strappend_char(as, '`');
- archive_strappend_char(as, '`');
- } else {
- c |= (p[1] & 0xf0) >> 4;
- archive_strappend_char(as, c?c + 0x20:'`');
- c = (p[1] & 0x0f) << 2;
- archive_strappend_char(as, c?c + 0x20:'`');
- archive_strappend_char(as, '`');
- }
- }
- archive_strappend_char(as, '\n');
-}
-
-/*
- * Write data to the encoded stream.
- */
-static int
-archive_filter_uuencode_write(struct archive_write_filter *f, const void *buff,
- size_t length)
-{
- struct private_uuencode *state = (struct private_uuencode *)f->data;
- const unsigned char *p = buff;
- int ret = ARCHIVE_OK;
-
- if (length == 0)
- return (ret);
-
- if (state->hold_len) {
- while (state->hold_len < LBYTES && length > 0) {
- state->hold[state->hold_len++] = *p++;
- length--;
- }
- if (state->hold_len < LBYTES)
- return (ret);
- uu_encode(&state->encoded_buff, state->hold, LBYTES);
- state->hold_len = 0;
- }
-
- for (; length >= LBYTES; length -= LBYTES, p += LBYTES)
- uu_encode(&state->encoded_buff, p, LBYTES);
-
- /* Save remaining bytes. */
- if (length > 0) {
- memcpy(state->hold, p, length);
- state->hold_len = length;
- }
- while (archive_strlen(&state->encoded_buff) >= state->bs) {
- ret = __archive_write_filter(f->next_filter,
- state->encoded_buff.s, state->bs);
- memmove(state->encoded_buff.s,
- state->encoded_buff.s + state->bs,
- state->encoded_buff.length - state->bs);
- state->encoded_buff.length -= state->bs;
- }
-
- return (ret);
-}
-
-
-/*
- * Finish the compression...
- */
-static int
-archive_filter_uuencode_close(struct archive_write_filter *f)
-{
- struct private_uuencode *state = (struct private_uuencode *)f->data;
- int ret, ret2;
-
- /* Flush remaining bytes. */
- if (state->hold_len != 0)
- uu_encode(&state->encoded_buff, state->hold, state->hold_len);
- archive_string_sprintf(&state->encoded_buff, "`\nend\n");
- /* Write the last block */
- archive_write_set_bytes_in_last_block(f->archive, 1);
- ret = __archive_write_filter(f->next_filter,
- state->encoded_buff.s, archive_strlen(&state->encoded_buff));
- ret2 = __archive_write_close_filter(f->next_filter);
- if (ret > ret2)
- ret = ret2;
- return (ret);
-}
-
-static int
-archive_filter_uuencode_free(struct archive_write_filter *f)
-{
- struct private_uuencode *state = (struct private_uuencode *)f->data;
-
- archive_string_free(&state->name);
- archive_string_free(&state->encoded_buff);
- free(state);
- return (ARCHIVE_OK);
-}
-
-static int64_t
-atol8(const char *p, size_t char_cnt)
-{
- int64_t l;
- int digit;
-
- l = 0;
- while (char_cnt-- > 0) {
- if (*p >= '0' && *p <= '7')
- digit = *p - '0';
- else
- break;
- p++;
- l <<= 3;
- l |= digit;
- }
- return (l);
-}
-
diff --git a/3rdparty/libarchive/libarchive/archive_write_add_filter_xz.c b/3rdparty/libarchive/libarchive/archive_write_add_filter_xz.c
index fa73311e..b0f25a6e 100644
--- a/3rdparty/libarchive/libarchive/archive_write_add_filter_xz.c
+++ b/3rdparty/libarchive/libarchive/archive_write_add_filter_xz.c
@@ -100,6 +100,7 @@ archive_write_add_filter_lzip(struct archive *a)
struct private_data {
int compression_level;
+ uint32_t threads;
lzma_stream stream;
lzma_filter lzmafilters[2];
lzma_options_lzma lzma_opt;
@@ -151,6 +152,7 @@ common_setup(struct archive_write_filter *f)
}
f->data = data;
data->compression_level = LZMA_PRESET_DEFAULT;
+ data->threads = 1;
f->open = &archive_compressor_xz_open;
f->close = archive_compressor_xz_close;
f->free = archive_compressor_xz_free;
@@ -221,23 +223,37 @@ archive_compressor_xz_init_stream(struct archive_write_filter *f,
{
static const lzma_stream lzma_stream_init_data = LZMA_STREAM_INIT;
int ret;
+#ifdef HAVE_LZMA_STREAM_ENCODER_MT
+ lzma_mt mt_options;
+#endif
data->stream = lzma_stream_init_data;
data->stream.next_out = data->compressed;
data->stream.avail_out = data->compressed_buffer_size;
- if (f->code == ARCHIVE_FILTER_XZ)
- ret = lzma_stream_encoder(&(data->stream),
- data->lzmafilters, LZMA_CHECK_CRC64);
- else if (f->code == ARCHIVE_FILTER_LZMA)
+ if (f->code == ARCHIVE_FILTER_XZ) {
+#ifdef HAVE_LZMA_STREAM_ENCODER_MT
+ if (data->threads != 1) {
+ memset(&mt_options, 0, sizeof(mt_options));
+ mt_options.threads = data->threads;
+ mt_options.timeout = 300;
+ mt_options.filters = data->lzmafilters;
+ mt_options.check = LZMA_CHECK_CRC64;
+ ret = lzma_stream_encoder_mt(&(data->stream),
+ &mt_options);
+ } else
+#endif
+ ret = lzma_stream_encoder(&(data->stream),
+ data->lzmafilters, LZMA_CHECK_CRC64);
+ } else if (f->code == ARCHIVE_FILTER_LZMA) {
ret = lzma_alone_encoder(&(data->stream), &data->lzma_opt);
- else { /* ARCHIVE_FILTER_LZIP */
+ } else { /* ARCHIVE_FILTER_LZIP */
int dict_size = data->lzma_opt.dict_size;
int ds, log2dic, wedges;
/* Calculate a coded dictionary size */
if (dict_size < (1 << 12) || dict_size > (1 << 27)) {
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
- "Unacceptable dictionary dize for lzip: %d",
+ "Unacceptable dictionary size for lzip: %d",
dict_size);
return (ARCHIVE_FATAL);
}
@@ -373,6 +389,22 @@ archive_compressor_xz_options(struct archive_write_filter *f,
if (data->compression_level > 6)
data->compression_level = 6;
return (ARCHIVE_OK);
+ } else if (strcmp(key, "threads") == 0) {
+ if (value == NULL)
+ return (ARCHIVE_WARN);
+ data->threads = (int)strtoul(value, NULL, 10);
+ if (data->threads == 0 && errno != 0) {
+ data->threads = 1;
+ return (ARCHIVE_WARN);
+ }
+ if (data->threads == 0) {
+#ifdef HAVE_LZMA_STREAM_ENCODER_MT
+ data->threads = lzma_cputhreads();
+#else
+ data->threads = 1;
+#endif
+ }
+ return (ARCHIVE_OK);
}
/* Note: The "warn" return is just to inform the options
diff --git a/3rdparty/libarchive/libarchive/archive_write_disk_acl.c b/3rdparty/libarchive/libarchive/archive_write_disk_acl.c
deleted file mode 100644
index 97972033..00000000
--- a/3rdparty/libarchive/libarchive/archive_write_disk_acl.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*-
- * 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
- * in this position and unchanged.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "archive_platform.h"
-__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_disk.c 201159 2009-12-29 05:35:40Z kientzle $");
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_ACL_H
-#define _ACL_PRIVATE /* For debugging */
-#include <sys/acl.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-
-#include "archive.h"
-#include "archive_entry.h"
-#include "archive_acl_private.h"
-#include "archive_write_disk_private.h"
-
-#if !defined(HAVE_POSIX_ACL) || !defined(ACL_TYPE_NFS4)
-/* Default empty function body to satisfy mainline code. */
-int
-archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
- struct archive_acl *abstract_acl)
-{
- (void)a; /* UNUSED */
- (void)fd; /* UNUSED */
- (void)name; /* UNUSED */
- (void)abstract_acl; /* UNUSED */
- return (ARCHIVE_OK);
-}
-
-#else
-
-static int set_acl(struct archive *, int fd, const char *,
- struct archive_acl *,
- acl_type_t, int archive_entry_acl_type, const char *tn);
-
-/*
- * XXX TODO: What about ACL types other than ACCESS and DEFAULT?
- */
-int
-archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
- struct archive_acl *abstract_acl)
-{
- int ret;
-
- if (archive_acl_count(abstract_acl, ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) > 0) {
- ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_ACCESS,
- ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
- if (ret != ARCHIVE_OK)
- return (ret);
- ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_DEFAULT,
- ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
- return (ret);
- } else if (archive_acl_count(abstract_acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4) > 0) {
- ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_NFS4,
- ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
- return (ret);
- } else
- return ARCHIVE_OK;
-}
-
-static struct {
- int archive_perm;
- int platform_perm;
-} acl_perm_map[] = {
- {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
- {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
- {ARCHIVE_ENTRY_ACL_READ, ACL_READ},
- {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
- {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
- {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
- {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
- {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
- {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
- {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
- {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
- {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
- {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
- {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
- {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
- {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
- {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
- {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
- {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
-};
-
-static struct {
- int archive_inherit;
- int platform_inherit;
-} acl_inherit_map[] = {
- {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
- {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
- {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
- {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY}
-};
-
-static int
-set_acl(struct archive *a, int fd, const char *name,
- struct archive_acl *abstract_acl,
- acl_type_t acl_type, int ae_requested_type, const char *tname)
-{
- acl_t acl;
- acl_entry_t acl_entry;
- acl_permset_t acl_permset;
- acl_flagset_t acl_flagset;
- int ret;
- int ae_type, ae_permset, ae_tag, ae_id;
- uid_t ae_uid;
- gid_t ae_gid;
- const char *ae_name;
- int entries;
- int i;
-
- ret = ARCHIVE_OK;
- entries = archive_acl_reset(abstract_acl, ae_requested_type);
- if (entries == 0)
- return (ARCHIVE_OK);
- acl = acl_init(entries);
- while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
- &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {
- acl_create_entry(&acl, &acl_entry);
-
- switch (ae_tag) {
- case ARCHIVE_ENTRY_ACL_USER:
- acl_set_tag_type(acl_entry, ACL_USER);
- ae_uid = archive_write_disk_uid(a, ae_name, ae_id);
- acl_set_qualifier(acl_entry, &ae_uid);
- break;
- case ARCHIVE_ENTRY_ACL_GROUP:
- acl_set_tag_type(acl_entry, ACL_GROUP);
- ae_gid = archive_write_disk_gid(a, ae_name, ae_id);
- acl_set_qualifier(acl_entry, &ae_gid);
- break;
- case ARCHIVE_ENTRY_ACL_USER_OBJ:
- acl_set_tag_type(acl_entry, ACL_USER_OBJ);
- break;
- case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
- acl_set_tag_type(acl_entry, ACL_GROUP_OBJ);
- break;
- case ARCHIVE_ENTRY_ACL_MASK:
- acl_set_tag_type(acl_entry, ACL_MASK);
- break;
- case ARCHIVE_ENTRY_ACL_OTHER:
- acl_set_tag_type(acl_entry, ACL_OTHER);
- break;
- case ARCHIVE_ENTRY_ACL_EVERYONE:
- acl_set_tag_type(acl_entry, ACL_EVERYONE);
- break;
- default:
- /* XXX */
- break;
- }
-
- switch (ae_type) {
- case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
- acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALLOW);
- break;
- case ARCHIVE_ENTRY_ACL_TYPE_DENY:
- acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_DENY);
- break;
- case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
- acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_AUDIT);
- break;
- case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
- acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALARM);
- break;
- case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
- case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
- // These don't translate directly into the system ACL.
- break;
- default:
- // XXX error handling here.
- break;
- }
-
- acl_get_permset(acl_entry, &acl_permset);
- acl_clear_perms(acl_permset);
-
- for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
- if (ae_permset & acl_perm_map[i].archive_perm)
- acl_add_perm(acl_permset,
- acl_perm_map[i].platform_perm);
- }
-
- acl_get_flagset_np(acl_entry, &acl_flagset);
- acl_clear_flags_np(acl_flagset);
- for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) {
- if (ae_permset & acl_inherit_map[i].archive_inherit)
- acl_add_flag_np(acl_flagset,
- acl_inherit_map[i].platform_inherit);
- }
- }
-
- /* Try restoring the ACL through 'fd' if we can. */
-#if HAVE_ACL_SET_FD
- if (fd >= 0 && acl_type == ACL_TYPE_ACCESS && acl_set_fd(fd, acl) == 0)
- ret = ARCHIVE_OK;
- else
-#else
-#if HAVE_ACL_SET_FD_NP
- if (fd >= 0 && acl_set_fd_np(fd, acl, acl_type) == 0)
- ret = ARCHIVE_OK;
- else
-#endif
-#endif
-#if HAVE_ACL_SET_LINK_NP
- if (acl_set_link_np(name, acl_type, acl) != 0) {
- archive_set_error(a, errno, "Failed to set %s acl", tname);
- ret = ARCHIVE_WARN;
- }
-#else
- /* TODO: Skip this if 'name' is a symlink. */
- if (acl_set_file(name, acl_type, acl) != 0) {
- archive_set_error(a, errno, "Failed to set %s acl", tname);
- ret = ARCHIVE_WARN;
- }
-#endif
- acl_free(acl);
- return (ret);
-}
-#endif
diff --git a/3rdparty/libarchive/libarchive/archive_write_disk_posix.c b/3rdparty/libarchive/libarchive/archive_write_disk_posix.c
index bbd50a63..6ad53992 100644
--- a/3rdparty/libarchive/libarchive/archive_write_disk_posix.c
+++ b/3rdparty/libarchive/libarchive/archive_write_disk_posix.c
@@ -39,9 +39,9 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_SYS_EXTATTR_H
#include <sys/extattr.h>
#endif
-#if defined(HAVE_SYS_XATTR_H)
+#if HAVE_SYS_XATTR_H
#include <sys/xattr.h>
-#elif defined(HAVE_ATTR_XATTR_H)
+#elif HAVE_ATTR_XATTR_H
#include <attr/xattr.h>
#endif
#ifdef HAVE_SYS_EA_H
@@ -110,6 +110,18 @@ __FBSDID("$FreeBSD$");
#include <sys/fcntl1.h>
#endif
+/*
+ * Macro to cast st_mtime and time_t to an int64 so that 2 numbers can reliably be compared.
+ *
+ * It assumes that the input is an integer type of no more than 64 bits.
+ * If the number is less than zero, t must be a signed type, so it fits in
+ * int64_t. Otherwise, it's a nonnegative value so we can cast it to uint64_t
+ * without loss. But it could be a large unsigned value, so we have to clip it
+ * to INT64_MAX.*
+ */
+#define to_int64_time(t) \
+ ((t) < 0 ? (int64_t)(t) : (uint64_t)(t) > (uint64_t)INT64_MAX ? INT64_MAX : (int64_t)(t))
+
#if __APPLE__
#include <TargetConditionals.h>
#if TARGET_OS_MAC && !TARGET_OS_EMBEDDED && HAVE_QUARANTINE_H
@@ -140,7 +152,17 @@ __FBSDID("$FreeBSD$");
#define O_BINARY 0
#endif
#ifndef O_CLOEXEC
-#define O_CLOEXEC 0
+#define O_CLOEXEC 0
+#endif
+
+/* Ignore non-int O_NOFOLLOW constant. */
+/* gnulib's fcntl.h does this on AIX, but it seems practical everywhere */
+#if defined O_NOFOLLOW && !(INT_MIN <= O_NOFOLLOW && O_NOFOLLOW <= INT_MAX)
+#undef O_NOFOLLOW
+#endif
+
+#ifndef O_NOFOLLOW
+#define O_NOFOLLOW 0
#endif
struct fixup_entry {
@@ -298,7 +320,7 @@ struct archive_write_disk {
#define MAXIMUM_DIR_MODE 0775
/*
- * Maxinum uncompressed size of a decmpfs block.
+ * Maximum uncompressed size of a decmpfs block.
*/
#define MAX_DECMPFS_BLOCK_SIZE (64 * 1024)
/*
@@ -313,7 +335,7 @@ struct archive_write_disk {
#define RSRC_F_SIZE 50 /* Size of Resource fork footer. */
/* Size to write compressed data to resource fork. */
#define COMPRESSED_W_SIZE (64 * 1024)
-/* decmpfs difinitions. */
+/* decmpfs definitions. */
#define MAX_DECMPFS_XATTR_SIZE 3802
#ifndef DECMPFS_XATTR_NAME
#define DECMPFS_XATTR_NAME "com.apple.decmpfs"
@@ -326,12 +348,19 @@ struct archive_write_disk {
#define HFS_BLOCKS(s) ((s) >> 12)
+static void fsobj_error(int *, struct archive_string *, int, const char *,
+ const char *);
+static int check_symlinks_fsobj(char *, int *, struct archive_string *,
+ int);
static int check_symlinks(struct archive_write_disk *);
static int create_filesystem_object(struct archive_write_disk *);
-static struct fixup_entry *current_fixup(struct archive_write_disk *, const char *pathname);
+static struct fixup_entry *current_fixup(struct archive_write_disk *,
+ const char *pathname);
#if defined(HAVE_FCHDIR) && defined(PATH_MAX)
static void edit_deep_directories(struct archive_write_disk *ad);
#endif
+static int cleanup_pathname_fsobj(char *, int *, struct archive_string *,
+ int);
static int cleanup_pathname(struct archive_write_disk *);
static int create_dir(struct archive_write_disk *, char *);
static int create_parent_dir(struct archive_write_disk *, char *);
@@ -343,6 +372,7 @@ static int restore_entry(struct archive_write_disk *);
static int set_mac_metadata(struct archive_write_disk *, const char *,
const void *, size_t);
static int set_xattrs(struct archive_write_disk *);
+static int clear_nochange_fflags(struct archive_write_disk *);
static int set_fflags(struct archive_write_disk *);
static int set_fflags_platform(struct archive_write_disk *, int fd,
const char *name, mode_t mode,
@@ -361,11 +391,14 @@ static struct archive_vtable *archive_write_disk_vtable(void);
static int _archive_write_disk_close(struct archive *);
static int _archive_write_disk_free(struct archive *);
-static int _archive_write_disk_header(struct archive *, struct archive_entry *);
+static int _archive_write_disk_header(struct archive *,
+ struct archive_entry *);
static int64_t _archive_write_disk_filter_bytes(struct archive *, int);
static int _archive_write_disk_finish_entry(struct archive *);
-static ssize_t _archive_write_disk_data(struct archive *, const void *, size_t);
-static ssize_t _archive_write_disk_data_block(struct archive *, const void *, size_t, int64_t);
+static ssize_t _archive_write_disk_data(struct archive *, const void *,
+ size_t);
+static ssize_t _archive_write_disk_data_block(struct archive *, const void *,
+ size_t, int64_t);
static int
lazy_stat(struct archive_write_disk *a)
@@ -542,10 +575,55 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
if (a->flags & ARCHIVE_EXTRACT_TIME)
a->todo |= TODO_TIMES;
if (a->flags & ARCHIVE_EXTRACT_ACL) {
+#if ARCHIVE_ACL_DARWIN
+ /*
+ * On MacOS, platform ACLs get stored in mac_metadata, too.
+ * If we intend to extract mac_metadata and it is present
+ * we skip extracting libarchive NFSv4 ACLs.
+ */
+ size_t metadata_size;
+
+ if ((a->flags & ARCHIVE_EXTRACT_MAC_METADATA) == 0 ||
+ archive_entry_mac_metadata(a->entry,
+ &metadata_size) == NULL || metadata_size == 0)
+#endif
+#if ARCHIVE_ACL_LIBRICHACL
+ /*
+ * RichACLs are stored in an extended attribute.
+ * If we intend to extract extended attributes and have this
+ * attribute we skip extracting libarchive NFSv4 ACLs.
+ */
+ short extract_acls = 1;
+ if (a->flags & ARCHIVE_EXTRACT_XATTR && (
+ archive_entry_acl_types(a->entry) &
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4)) {
+ const char *attr_name;
+ const void *attr_value;
+ size_t attr_size;
+ int i = archive_entry_xattr_reset(a->entry);
+ while (i--) {
+ archive_entry_xattr_next(a->entry, &attr_name,
+ &attr_value, &attr_size);
+ if (attr_name != NULL && attr_value != NULL &&
+ attr_size > 0 && strcmp(attr_name,
+ "trusted.richacl") == 0) {
+ extract_acls = 0;
+ break;
+ }
+ }
+ }
+ if (extract_acls)
+#endif
+#if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL
+ {
+#endif
if (archive_entry_filetype(a->entry) == AE_IFDIR)
a->deferred |= TODO_ACLS;
else
a->todo |= TODO_ACLS;
+#if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL
+ }
+#endif
}
if (a->flags & ARCHIVE_EXTRACT_MAC_METADATA) {
if (archive_entry_filetype(a->entry) == AE_IFDIR)
@@ -586,8 +664,21 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
}
#endif
- if (a->flags & ARCHIVE_EXTRACT_XATTR)
+ if (a->flags & ARCHIVE_EXTRACT_XATTR) {
+#if ARCHIVE_XATTR_DARWIN
+ /*
+ * On MacOS, extended attributes get stored in mac_metadata,
+ * too. If we intend to extract mac_metadata and it is present
+ * we skip extracting extended attributes.
+ */
+ size_t metadata_size;
+
+ if ((a->flags & ARCHIVE_EXTRACT_MAC_METADATA) == 0 ||
+ archive_entry_mac_metadata(a->entry,
+ &metadata_size) == NULL || metadata_size == 0)
+#endif
a->todo |= TODO_XATTR;
+ }
if (a->flags & ARCHIVE_EXTRACT_FFLAGS)
a->todo |= TODO_FFLAGS;
if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) {
@@ -611,9 +702,9 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
/*
* NOTE: UF_COMPRESSED is ignored even if the filesystem
* supports HFS+ Compression because the file should
- * have at least an extended attriute "com.apple.decmpfs"
+ * have at least an extended attribute "com.apple.decmpfs"
* before the flag is set to indicate that the file have
- * been compressed. If hte filesystem does not support
+ * been compressed. If the filesystem does not support
* HFS+ Compression the system call will fail.
*/
if (a->fd < 0 || fchflags(a->fd, UF_COMPRESSED) != 0)
@@ -636,7 +727,8 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
if (a->restore_pwd >= 0) {
r = fchdir(a->restore_pwd);
if (r != 0) {
- archive_set_error(&a->archive, errno, "chdir() failure");
+ archive_set_error(&a->archive, errno,
+ "chdir() failure");
ret = ARCHIVE_FATAL;
}
close(a->restore_pwd);
@@ -684,7 +776,8 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
}
if (archive_entry_birthtime_is_set(entry)) {
fe->birthtime = archive_entry_birthtime(entry);
- fe->birthtime_nanos = archive_entry_birthtime_nsec(entry);
+ fe->birthtime_nanos = archive_entry_birthtime_nsec(
+ entry);
} else {
/* If birthtime is unset, use mtime. */
fe->birthtime = fe->mtime;
@@ -710,7 +803,8 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
return (ARCHIVE_FATAL);
fe->mac_metadata = malloc(metadata_size);
if (fe->mac_metadata != NULL) {
- memcpy(fe->mac_metadata, metadata, metadata_size);
+ memcpy(fe->mac_metadata, metadata,
+ metadata_size);
fe->mac_metadata_size = metadata_size;
fe->fixup |= TODO_MAC_METADATA;
}
@@ -1223,7 +1317,7 @@ hfs_drive_compressor(struct archive_write_disk *a, const char *buff,
ret = hfs_write_compressed_data(a, bytes_used + rsrc_size);
a->compressed_buffer_remaining = a->compressed_buffer_size;
- /* If the compressed size is not enouph smaller than
+ /* If the compressed size is not enough smaller than
* the uncompressed size. cancel HFS+ compression.
* TODO: study a behavior of ditto utility and improve
* the condition to fall back into no HFS+ compression. */
@@ -1328,7 +1422,7 @@ hfs_write_decmpfs_block(struct archive_write_disk *a, const char *buff,
(uint32_t *)(a->resource_fork + RSRC_H_SIZE);
/* Set the block count to the resource fork. */
archive_le32enc(a->decmpfs_block_info++, block_count);
- /* Get the position where we are goint to set compressed
+ /* Get the position where we are going to set compressed
* data. */
a->compressed_rsrc_position =
RSRC_H_SIZE + 4 + (block_count * 8);
@@ -1401,7 +1495,7 @@ hfs_write_data_block(struct archive_write_disk *a, const char *buff,
bytes_to_write = size;
/* Seek if necessary to the specified offset. */
if (a->offset < a->fd_offset) {
- /* Can't support backword move. */
+ /* Can't support backward move. */
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Seek failed");
return (ARCHIVE_FATAL);
@@ -1467,10 +1561,15 @@ _archive_write_disk_data_block(struct archive *_a,
return (r);
if ((size_t)r < size) {
archive_set_error(&a->archive, 0,
- "Write request too large");
+ "Too much data: Truncating file at %ju bytes",
+ (uintmax_t)a->filesize);
return (ARCHIVE_WARN);
}
+#if ARCHIVE_VERSION_NUMBER < 3999000
return (ARCHIVE_OK);
+#else
+ return (size);
+#endif
}
static ssize_t
@@ -1661,9 +1760,11 @@ _archive_write_disk_finish_entry(struct archive *_a)
* ACLs that prevent attribute changes (including time).
*/
if (a->todo & TODO_ACLS) {
- int r2 = archive_write_disk_set_acls(&a->archive, a->fd,
- archive_entry_pathname(a->entry),
- archive_entry_acl(a->entry));
+ int r2;
+ r2 = archive_write_disk_set_acls(&a->archive, a->fd,
+ archive_entry_pathname(a->entry),
+ archive_entry_acl(a->entry),
+ archive_entry_mode(a->entry));
if (r2 < ret) ret = r2;
}
@@ -1750,10 +1851,9 @@ archive_write_disk_new(void)
{
struct archive_write_disk *a;
- a = (struct archive_write_disk *)malloc(sizeof(*a));
+ a = (struct archive_write_disk *)calloc(1, sizeof(*a));
if (a == NULL)
return (NULL);
- memset(a, 0, sizeof(*a));
a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC;
/* We're ready to write a header immediately. */
a->archive.state = ARCHIVE_STATE_HEADER;
@@ -1791,7 +1891,7 @@ edit_deep_directories(struct archive_write_disk *a)
char *tail = a->name;
/* If path is short, avoid the open() below. */
- if (strlen(tail) <= PATH_MAX)
+ if (strlen(tail) < PATH_MAX)
return;
/* Try to record our starting dir. */
@@ -1801,7 +1901,7 @@ edit_deep_directories(struct archive_write_disk *a)
return;
/* As long as the path is too long... */
- while (strlen(tail) > PATH_MAX) {
+ while (strlen(tail) >= PATH_MAX) {
/* Locate a dir prefix shorter than PATH_MAX. */
tail += PATH_MAX - 8;
while (tail > a->name && *tail != '/')
@@ -1842,6 +1942,8 @@ restore_entry(struct archive_write_disk *a)
* object is a dir, but that doesn't mean the old
* object isn't a dir.
*/
+ if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS)
+ (void)clear_nochange_fflags(a);
if (unlink(a->name) == 0) {
/* We removed it, reset cached stat. */
a->pst = NULL;
@@ -1869,6 +1971,13 @@ restore_entry(struct archive_write_disk *a)
en = create_filesystem_object(a);
}
+ if ((en == ENOENT) && (archive_entry_hardlink(a->entry) != NULL)) {
+ archive_set_error(&a->archive, en,
+ "Hard-link target '%s' does not exist.",
+ archive_entry_hardlink(a->entry));
+ return (ARCHIVE_FAILED);
+ }
+
if ((en == EISDIR || en == EEXIST)
&& (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
/* If we're not overwriting, we're done. */
@@ -1940,6 +2049,8 @@ restore_entry(struct archive_write_disk *a)
if (!S_ISDIR(a->st.st_mode)) {
/* A non-dir is in the way, unlink it. */
+ if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS)
+ (void)clear_nochange_fflags(a);
if (unlink(a->name) != 0) {
archive_set_error(&a->archive, errno,
"Can't unlink already-existing object");
@@ -1950,6 +2061,8 @@ restore_entry(struct archive_write_disk *a)
en = create_filesystem_object(a);
} else if (!S_ISDIR(a->mode)) {
/* A dir is in the way of a non-dir, rmdir it. */
+ if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS)
+ (void)clear_nochange_fflags(a);
if (rmdir(a->name) != 0) {
archive_set_error(&a->archive, errno,
"Can't replace existing directory with non-directory");
@@ -1975,8 +2088,9 @@ restore_entry(struct archive_write_disk *a)
if (en) {
/* Everything failed; give up here. */
- archive_set_error(&a->archive, en, "Can't create '%s'",
- a->name);
+ if ((&a->archive)->error == NULL)
+ archive_set_error(&a->archive, en, "Can't create '%s'",
+ a->name);
return (ARCHIVE_FAILED);
}
@@ -1996,6 +2110,11 @@ create_filesystem_object(struct archive_write_disk *a)
const char *linkname;
mode_t final_mode, mode;
int r;
+ /* these for check_symlinks_fsobj */
+ char *linkname_copy; /* non-const copy of linkname */
+ struct stat st;
+ struct archive_string error_string;
+ int error_number;
/* We identify hard/symlinks according to the link names. */
/* Since link(2) and symlink(2) don't handle modes, we're done here. */
@@ -2004,6 +2123,43 @@ create_filesystem_object(struct archive_write_disk *a)
#if !HAVE_LINK
return (EPERM);
#else
+ archive_string_init(&error_string);
+ linkname_copy = strdup(linkname);
+ if (linkname_copy == NULL) {
+ return (EPERM);
+ }
+ /*
+ * TODO: consider using the cleaned-up path as the link
+ * target?
+ */
+ r = cleanup_pathname_fsobj(linkname_copy, &error_number,
+ &error_string, a->flags);
+ if (r != ARCHIVE_OK) {
+ archive_set_error(&a->archive, error_number, "%s",
+ error_string.s);
+ free(linkname_copy);
+ archive_string_free(&error_string);
+ /*
+ * EPERM is more appropriate than error_number for our
+ * callers
+ */
+ return (EPERM);
+ }
+ r = check_symlinks_fsobj(linkname_copy, &error_number,
+ &error_string, a->flags);
+ if (r != ARCHIVE_OK) {
+ archive_set_error(&a->archive, error_number, "%s",
+ error_string.s);
+ free(linkname_copy);
+ archive_string_free(&error_string);
+ /*
+ * EPERM is more appropriate than error_number for our
+ * callers
+ */
+ return (EPERM);
+ }
+ free(linkname_copy);
+ archive_string_free(&error_string);
r = link(linkname, a->name) ? errno : 0;
/*
* New cpio and pax formats allow hardlink entries
@@ -2021,11 +2177,20 @@ create_filesystem_object(struct archive_write_disk *a)
a->todo = 0;
a->deferred = 0;
} else if (r == 0 && a->filesize > 0) {
- a->fd = open(a->name,
- O_WRONLY | O_TRUNC | O_BINARY | O_CLOEXEC);
- __archive_ensure_cloexec_flag(a->fd);
- if (a->fd < 0)
+#ifdef HAVE_LSTAT
+ r = lstat(a->name, &st);
+#else
+ r = stat(a->name, &st);
+#endif
+ if (r != 0)
r = errno;
+ else if ((st.st_mode & AE_IFMT) == AE_IFREG) {
+ a->fd = open(a->name, O_WRONLY | O_TRUNC |
+ O_BINARY | O_CLOEXEC | O_NOFOLLOW);
+ __archive_ensure_cloexec_flag(a->fd);
+ if (a->fd < 0)
+ r = errno;
+ }
}
return (r);
#endif
@@ -2172,8 +2337,8 @@ _archive_write_disk_close(struct archive *_a)
if (p->fixup & TODO_MODE_BASE)
chmod(p->name, p->mode);
if (p->fixup & TODO_ACLS)
- archive_write_disk_set_acls(&a->archive,
- -1, p->name, &p->acl);
+ archive_write_disk_set_acls(&a->archive, -1, p->name,
+ &p->acl, p->mode);
if (p->fixup & TODO_FFLAGS)
set_fflags_platform(a, -1, p->name,
p->mode, p->fflags_set, 0);
@@ -2215,7 +2380,8 @@ _archive_write_disk_free(struct archive *_a)
free(a->resource_fork);
free(a->compressed_buffer);
free(a->uncompressed_buffer);
-#ifdef HAVE_ZLIB_H
+#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\
+ && defined(HAVE_ZLIB_H)
if (a->stream_valid) {
switch (deflateEnd(&a->stream)) {
case Z_OK:
@@ -2332,110 +2498,283 @@ current_fixup(struct archive_write_disk *a, const char *pathname)
return (a->current_fixup);
}
-/* TODO: Make this work. */
-/*
- * TODO: The deep-directory support bypasses this; disable deep directory
- * support if we're doing symlink checks.
- */
+/* Error helper for new *_fsobj functions */
+static void
+fsobj_error(int *a_eno, struct archive_string *a_estr,
+ int err, const char *errstr, const char *path)
+{
+ if (a_eno)
+ *a_eno = err;
+ if (a_estr)
+ archive_string_sprintf(a_estr, "%s%s", errstr, path);
+}
+
/*
* TODO: Someday, integrate this with the deep dir support; they both
* scan the path and both can be optimized by comparing against other
* recent paths.
*/
/* TODO: Extend this to support symlinks on Windows Vista and later. */
+
+/*
+ * Checks the given path to see if any elements along it are symlinks. Returns
+ * ARCHIVE_OK if there are none, otherwise puts an error in errmsg.
+ */
static int
-check_symlinks(struct archive_write_disk *a)
+check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
+ int flags)
{
#if !defined(HAVE_LSTAT)
/* Platform doesn't have lstat, so we can't look for symlinks. */
- (void)a; /* UNUSED */
+ (void)path; /* UNUSED */
+ (void)error_number; /* UNUSED */
+ (void)error_string; /* UNUSED */
+ (void)flags; /* UNUSED */
return (ARCHIVE_OK);
#else
- char *pn;
+ int res = ARCHIVE_OK;
+ char *tail;
+ char *head;
+ int last;
char c;
int r;
struct stat st;
+ int restore_pwd;
+
+ /* Nothing to do here if name is empty */
+ if(path[0] == '\0')
+ return (ARCHIVE_OK);
/*
* Guard against symlink tricks. Reject any archive entry whose
* destination would be altered by a symlink.
+ *
+ * Walk the filename in chunks separated by '/'. For each segment:
+ * - if it doesn't exist, continue
+ * - if it's symlink, abort or remove it
+ * - if it's a directory and it's not the last chunk, cd into it
+ * As we go:
+ * head points to the current (relative) path
+ * tail points to the temporary \0 terminating the segment we're
+ * currently examining
+ * c holds what used to be in *tail
+ * last is 1 if this is the last tail
+ */
+ restore_pwd = open(".", O_RDONLY | O_BINARY | O_CLOEXEC);
+ __archive_ensure_cloexec_flag(restore_pwd);
+ if (restore_pwd < 0)
+ return (ARCHIVE_FATAL);
+ head = path;
+ tail = path;
+ last = 0;
+ /* TODO: reintroduce a safe cache here? */
+ /* Skip the root directory if the path is absolute. */
+ if(tail == path && tail[0] == '/')
+ ++tail;
+ /* Keep going until we've checked the entire name.
+ * head, tail, path all alias the same string, which is
+ * temporarily zeroed at tail, so be careful restoring the
+ * stashed (c=tail[0]) for error messages.
+ * Exiting the loop with break is okay; continue is not.
*/
- /* Whatever we checked last time doesn't need to be re-checked. */
- pn = a->name;
- if (archive_strlen(&(a->path_safe)) > 0) {
- char *p = a->path_safe.s;
- while ((*pn != '\0') && (*p == *pn))
- ++p, ++pn;
- }
- c = pn[0];
- /* Keep going until we've checked the entire name. */
- while (pn[0] != '\0' && (pn[0] != '/' || pn[1] != '\0')) {
+ while (!last) {
+ /*
+ * Skip the separator we just consumed, plus any adjacent ones
+ */
+ while (*tail == '/')
+ ++tail;
/* Skip the next path element. */
- while (*pn != '\0' && *pn != '/')
- ++pn;
- c = pn[0];
- pn[0] = '\0';
+ while (*tail != '\0' && *tail != '/')
+ ++tail;
+ /* is this the last path component? */
+ last = (tail[0] == '\0') || (tail[0] == '/' && tail[1] == '\0');
+ /* temporarily truncate the string here */
+ c = tail[0];
+ tail[0] = '\0';
/* Check that we haven't hit a symlink. */
- r = lstat(a->name, &st);
+ r = lstat(head, &st);
if (r != 0) {
+ tail[0] = c;
/* We've hit a dir that doesn't exist; stop now. */
- if (errno == ENOENT)
+ if (errno == ENOENT) {
break;
+ } else {
+ /*
+ * Treat any other error as fatal - best to be
+ * paranoid here.
+ * Note: This effectively disables deep
+ * directory support when security checks are
+ * enabled. Otherwise, very long pathnames that
+ * trigger an error here could evade the
+ * sandbox.
+ * TODO: We could do better, but it would
+ * probably require merging the symlink checks
+ * with the deep-directory editing.
+ */
+ fsobj_error(a_eno, a_estr, errno,
+ "Could not stat ", path);
+ res = ARCHIVE_FAILED;
+ break;
+ }
+ } else if (S_ISDIR(st.st_mode)) {
+ if (!last) {
+ if (chdir(head) != 0) {
+ tail[0] = c;
+ fsobj_error(a_eno, a_estr, errno,
+ "Could not chdir ", path);
+ res = (ARCHIVE_FATAL);
+ break;
+ }
+ /* Our view is now from inside this dir: */
+ head = tail + 1;
+ }
} else if (S_ISLNK(st.st_mode)) {
- if (c == '\0') {
+ if (last) {
/*
* Last element is symlink; remove it
* so we can overwrite it with the
* item being extracted.
*/
- if (unlink(a->name)) {
- archive_set_error(&a->archive, errno,
- "Could not remove symlink %s",
- a->name);
- pn[0] = c;
- return (ARCHIVE_FAILED);
+ if (unlink(head)) {
+ tail[0] = c;
+ fsobj_error(a_eno, a_estr, errno,
+ "Could not remove symlink ",
+ path);
+ res = ARCHIVE_FAILED;
+ break;
}
- a->pst = NULL;
/*
* Even if we did remove it, a warning
* is in order. The warning is silly,
* though, if we're just replacing one
* symlink with another symlink.
*/
- if (!S_ISLNK(a->mode)) {
- archive_set_error(&a->archive, 0,
- "Removing symlink %s",
- a->name);
+ tail[0] = c;
+ /*
+ * FIXME: not sure how important this is to
+ * restore
+ */
+ /*
+ if (!S_ISLNK(path)) {
+ fsobj_error(a_eno, a_estr, 0,
+ "Removing symlink ", path);
}
+ */
/* Symlink gone. No more problem! */
- pn[0] = c;
- return (0);
- } else if (a->flags & ARCHIVE_EXTRACT_UNLINK) {
+ res = ARCHIVE_OK;
+ break;
+ } else if (flags & ARCHIVE_EXTRACT_UNLINK) {
/* User asked us to remove problems. */
- if (unlink(a->name) != 0) {
- archive_set_error(&a->archive, 0,
- "Cannot remove intervening symlink %s",
- a->name);
- pn[0] = c;
- return (ARCHIVE_FAILED);
+ if (unlink(head) != 0) {
+ tail[0] = c;
+ fsobj_error(a_eno, a_estr, 0,
+ "Cannot remove intervening "
+ "symlink ", path);
+ res = ARCHIVE_FAILED;
+ break;
+ }
+ tail[0] = c;
+ } else if ((flags &
+ ARCHIVE_EXTRACT_SECURE_SYMLINKS) == 0) {
+ /*
+ * We are not the last element and we want to
+ * follow symlinks if they are a directory.
+ *
+ * This is needed to extract hardlinks over
+ * symlinks.
+ */
+ r = stat(head, &st);
+ if (r != 0) {
+ tail[0] = c;
+ if (errno == ENOENT) {
+ break;
+ } else {
+ fsobj_error(a_eno, a_estr,
+ errno,
+ "Could not stat ", path);
+ res = (ARCHIVE_FAILED);
+ break;
+ }
+ } else if (S_ISDIR(st.st_mode)) {
+ if (chdir(head) != 0) {
+ tail[0] = c;
+ fsobj_error(a_eno, a_estr,
+ errno,
+ "Could not chdir ", path);
+ res = (ARCHIVE_FATAL);
+ break;
+ }
+ /*
+ * Our view is now from inside
+ * this dir:
+ */
+ head = tail + 1;
+ } else {
+ tail[0] = c;
+ fsobj_error(a_eno, a_estr, 0,
+ "Cannot extract through "
+ "symlink ", path);
+ res = ARCHIVE_FAILED;
+ break;
}
- a->pst = NULL;
} else {
- archive_set_error(&a->archive, 0,
- "Cannot extract through symlink %s",
- a->name);
- pn[0] = c;
- return (ARCHIVE_FAILED);
+ tail[0] = c;
+ fsobj_error(a_eno, a_estr, 0,
+ "Cannot extract through symlink ", path);
+ res = ARCHIVE_FAILED;
+ break;
}
}
+ /* be sure to always maintain this */
+ tail[0] = c;
+ if (tail[0] != '\0')
+ tail++; /* Advance to the next segment. */
}
- pn[0] = c;
- /* We've checked and/or cleaned the whole path, so remember it. */
- archive_strcpy(&a->path_safe, a->name);
- return (ARCHIVE_OK);
+ /* Catches loop exits via break */
+ tail[0] = c;
+#ifdef HAVE_FCHDIR
+ /* If we changed directory above, restore it here. */
+ if (restore_pwd >= 0) {
+ r = fchdir(restore_pwd);
+ if (r != 0) {
+ fsobj_error(a_eno, a_estr, errno,
+ "chdir() failure", "");
+ }
+ close(restore_pwd);
+ restore_pwd = -1;
+ if (r != 0) {
+ res = (ARCHIVE_FATAL);
+ }
+ }
+#endif
+ /* TODO: reintroduce a safe cache here? */
+ return res;
#endif
}
+/*
+ * Check a->name for symlinks, returning ARCHIVE_OK if its clean, otherwise
+ * calls archive_set_error and returns ARCHIVE_{FATAL,FAILED}
+ */
+static int
+check_symlinks(struct archive_write_disk *a)
+{
+ struct archive_string error_string;
+ int error_number;
+ int rc;
+ archive_string_init(&error_string);
+ rc = check_symlinks_fsobj(a->name, &error_number, &error_string,
+ a->flags);
+ if (rc != ARCHIVE_OK) {
+ archive_set_error(&a->archive, error_number, "%s",
+ error_string.s);
+ }
+ archive_string_free(&error_string);
+ a->pst = NULL; /* to be safe */
+ return rc;
+}
+
+
#if defined(__CYGWIN__)
/*
* 1. Convert a path separator from '\' to '/' .
@@ -2446,7 +2785,7 @@ check_symlinks(struct archive_write_disk *a)
* See also : http://msdn.microsoft.com/en-us/library/aa365247.aspx
*/
static void
-cleanup_pathname_win(struct archive_write_disk *a)
+cleanup_pathname_win(char *path)
{
wchar_t wc;
char *p;
@@ -2457,7 +2796,7 @@ cleanup_pathname_win(struct archive_write_disk *a)
mb = 0;
complete = 1;
utf8 = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)? 1: 0;
- for (p = a->name; *p != '\0'; p++) {
+ for (p = path; *p != '\0'; p++) {
++alen;
if (*p == '\\') {
/* If previous byte is smaller than 128,
@@ -2482,7 +2821,7 @@ cleanup_pathname_win(struct archive_write_disk *a)
/*
* Convert path separator in wide-character.
*/
- p = a->name;
+ p = path;
while (*p != '\0' && alen) {
l = mbtowc(&wc, p, alen);
if (l == (size_t)-1) {
@@ -2504,28 +2843,37 @@ cleanup_pathname_win(struct archive_write_disk *a)
/*
* Canonicalize the pathname. In particular, this strips duplicate
* '/' characters, '.' elements, and trailing '/'. It also raises an
- * error for an empty path, a trailing '..' or (if _SECURE_NODOTDOT is
- * set) any '..' in the path.
+ * error for an empty path, a trailing '..', (if _SECURE_NODOTDOT is
+ * set) any '..' in the path or (if ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS
+ * is set) if the path is absolute.
*/
static int
-cleanup_pathname(struct archive_write_disk *a)
+cleanup_pathname_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
+ int flags)
{
char *dest, *src;
char separator = '\0';
- dest = src = a->name;
+ dest = src = path;
if (*src == '\0') {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid empty pathname");
+ fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC,
+ "Invalid empty ", "pathname");
return (ARCHIVE_FAILED);
}
#if defined(__CYGWIN__)
- cleanup_pathname_win(a);
+ cleanup_pathname_win(path);
#endif
/* Skip leading '/'. */
- if (*src == '/')
+ if (*src == '/') {
+ if (flags & ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS) {
+ fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC,
+ "Path is ", "absolute");
+ return (ARCHIVE_FAILED);
+ }
+
separator = *src++;
+ }
/* Scan the pathname one element at a time. */
for (;;) {
@@ -2547,10 +2895,11 @@ cleanup_pathname(struct archive_write_disk *a)
} else if (src[1] == '.') {
if (src[2] == '/' || src[2] == '\0') {
/* Conditionally warn about '..' */
- if (a->flags & ARCHIVE_EXTRACT_SECURE_NODOTDOT) {
- archive_set_error(&a->archive,
+ if (flags
+ & ARCHIVE_EXTRACT_SECURE_NODOTDOT) {
+ fsobj_error(a_eno, a_estr,
ARCHIVE_ERRNO_MISC,
- "Path contains '..'");
+ "Path contains ", "'..'");
return (ARCHIVE_FAILED);
}
}
@@ -2581,7 +2930,7 @@ cleanup_pathname(struct archive_write_disk *a)
* We've just copied zero or more path elements, not including the
* final '/'.
*/
- if (dest == a->name) {
+ if (dest == path) {
/*
* Nothing got copied. The path must have been something
* like '.' or '/' or './' or '/././././/./'.
@@ -2596,6 +2945,23 @@ cleanup_pathname(struct archive_write_disk *a)
return (ARCHIVE_OK);
}
+static int
+cleanup_pathname(struct archive_write_disk *a)
+{
+ struct archive_string error_string;
+ int error_number;
+ int rc;
+ archive_string_init(&error_string);
+ rc = cleanup_pathname_fsobj(a->name, &error_number, &error_string,
+ a->flags);
+ if (rc != ARCHIVE_OK) {
+ archive_set_error(&a->archive, error_number, "%s",
+ error_string.s);
+ }
+ archive_string_free(&error_string);
+ return rc;
+}
+
/*
* Create the parent directory of the specified path, assuming path
* is already in mutable storage.
@@ -2674,7 +3040,8 @@ create_dir(struct archive_write_disk *a, char *path)
}
} else if (errno != ENOENT && errno != ENOTDIR) {
/* Stat failed? */
- archive_set_error(&a->archive, errno, "Can't test directory '%s'", path);
+ archive_set_error(&a->archive, errno,
+ "Can't test directory '%s'", path);
return (ARCHIVE_FAILED);
} else if (slash != NULL) {
*slash = '\0';
@@ -2861,7 +3228,7 @@ set_time(int fd, int mode, const char *name,
#endif
}
-#ifdef F_SETTIMES /* Tru64 */
+#ifdef F_SETTIMES
static int
set_time_tru64(int fd, int mode, const char *name,
time_t atime, long atime_nsec,
@@ -2869,19 +3236,21 @@ set_time_tru64(int fd, int mode, const char *name,
time_t ctime, long ctime_nsec)
{
struct attr_timbuf tstamp;
- struct timeval times[3];
- times[0].tv_sec = atime;
- times[0].tv_usec = atime_nsec / 1000;
- times[1].tv_sec = mtime;
- times[1].tv_usec = mtime_nsec / 1000;
- times[2].tv_sec = ctime;
- times[2].tv_usec = ctime_nsec / 1000;
- tstamp.atime = times[0];
- tstamp.mtime = times[1];
- tstamp.ctime = times[2];
+ tstamp.atime.tv_sec = atime;
+ tstamp.mtime.tv_sec = mtime;
+ tstamp.ctime.tv_sec = ctime;
+#if defined (__hpux) && defined (__ia64)
+ tstamp.atime.tv_nsec = atime_nsec;
+ tstamp.mtime.tv_nsec = mtime_nsec;
+ tstamp.ctime.tv_nsec = ctime_nsec;
+#else
+ tstamp.atime.tv_usec = atime_nsec / 1000;
+ tstamp.mtime.tv_usec = mtime_nsec / 1000;
+ tstamp.ctime.tv_usec = ctime_nsec / 1000;
+#endif
return (fcntl(fd,F_SETTIMES,&tstamp));
}
-#endif /* Tru64 */
+#endif /* F_SETTIMES */
static int
set_times(struct archive_write_disk *a,
@@ -3053,9 +3422,23 @@ set_mode(struct archive_write_disk *a, int mode)
* impact.
*/
if (lchmod(a->name, mode) != 0) {
- archive_set_error(&a->archive, errno,
- "Can't set permissions to 0%o", (int)mode);
- r = ARCHIVE_WARN;
+ switch (errno) {
+ case ENOTSUP:
+ case ENOSYS:
+#if ENOTSUP != EOPNOTSUPP
+ case EOPNOTSUPP:
+#endif
+ /*
+ * if lchmod is defined but the platform
+ * doesn't support it, silently ignore
+ * error
+ */
+ break;
+ default:
+ archive_set_error(&a->archive, errno,
+ "Can't set permissions to 0%o", (int)mode);
+ r = ARCHIVE_WARN;
+ }
}
#endif
} else if (!S_ISDIR(a->mode)) {
@@ -3123,12 +3506,19 @@ set_fflags(struct archive_write_disk *a)
#ifdef UF_APPEND
critical_flags |= UF_APPEND;
#endif
-#ifdef EXT2_APPEND_FL
+#if defined(FS_APPEND_FL)
+ critical_flags |= FS_APPEND_FL;
+#elif defined(EXT2_APPEND_FL)
critical_flags |= EXT2_APPEND_FL;
#endif
-#ifdef EXT2_IMMUTABLE_FL
+#if defined(FS_IMMUTABLE_FL)
+ critical_flags |= FS_IMMUTABLE_FL;
+#elif defined(EXT2_IMMUTABLE_FL)
critical_flags |= EXT2_IMMUTABLE_FL;
#endif
+#ifdef FS_JOURNAL_DATA_FL
+ critical_flags |= FS_JOURNAL_DATA_FL;
+#endif
if (a->todo & TODO_FFLAGS) {
archive_entry_fflags(a->entry, &set, &clear);
@@ -3156,6 +3546,37 @@ set_fflags(struct archive_write_disk *a)
return (ARCHIVE_OK);
}
+static int
+clear_nochange_fflags(struct archive_write_disk *a)
+{
+ int nochange_flags;
+ mode_t mode = archive_entry_mode(a->entry);
+
+ /* Hopefully, the compiler will optimize this mess into a constant. */
+ nochange_flags = 0;
+#ifdef SF_IMMUTABLE
+ nochange_flags |= SF_IMMUTABLE;
+#endif
+#ifdef UF_IMMUTABLE
+ nochange_flags |= UF_IMMUTABLE;
+#endif
+#ifdef SF_APPEND
+ nochange_flags |= SF_APPEND;
+#endif
+#ifdef UF_APPEND
+ nochange_flags |= UF_APPEND;
+#endif
+#ifdef EXT2_APPEND_FL
+ nochange_flags |= EXT2_APPEND_FL;
+#endif
+#ifdef EXT2_IMMUTABLE_FL
+ nochange_flags |= EXT2_IMMUTABLE_FL;
+#endif
+
+ return (set_fflags_platform(a, a->fd, a->name, mode, 0,
+ nochange_flags));
+}
+
#if ( defined(HAVE_LCHFLAGS) || defined(HAVE_CHFLAGS) || defined(HAVE_FCHFLAGS) ) && defined(HAVE_STRUCT_STAT_ST_FLAGS)
/*
@@ -3209,7 +3630,10 @@ set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
return (ARCHIVE_WARN);
}
-#elif defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)
+#elif (defined(FS_IOC_GETFLAGS) && defined(FS_IOC_SETFLAGS) && \
+ defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \
+ (defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS) && \
+ defined(HAVE_WORKING_EXT2_IOC_GETFLAGS))
/*
* Linux uses ioctl() to read and write file flags.
*/
@@ -3222,7 +3646,7 @@ set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
int newflags, oldflags;
int sf_mask = 0;
- if (set == 0 && clear == 0)
+ if (set == 0 && clear == 0)
return (ARCHIVE_OK);
/* Only regular files and dirs can have flags. */
if (!S_ISREG(mode) && !S_ISDIR(mode))
@@ -3243,12 +3667,19 @@ set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
* defines. (?) The code below degrades reasonably gracefully
* if sf_mask is incomplete.
*/
-#ifdef EXT2_IMMUTABLE_FL
+#if defined(FS_IMMUTABLE_FL)
+ sf_mask |= FS_IMMUTABLE_FL;
+#elif defined(EXT2_IMMUTABLE_FL)
sf_mask |= EXT2_IMMUTABLE_FL;
#endif
-#ifdef EXT2_APPEND_FL
+#if defined(FS_APPEND_FL)
+ sf_mask |= FS_APPEND_FL;
+#elif defined(EXT2_APPEND_FL)
sf_mask |= EXT2_APPEND_FL;
#endif
+#if defined(FS_JOURNAL_DATA_FL)
+ sf_mask |= FS_JOURNAL_DATA_FL;
+#endif
/*
* XXX As above, this would be way simpler if we didn't have
* to read the current flags from disk. XXX
@@ -3256,12 +3687,24 @@ set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
ret = ARCHIVE_OK;
/* Read the current file flags. */
- if (ioctl(myfd, EXT2_IOC_GETFLAGS, &oldflags) < 0)
+ if (ioctl(myfd,
+#ifdef FS_IOC_GETFLAGS
+ FS_IOC_GETFLAGS,
+#else
+ EXT2_IOC_GETFLAGS,
+#endif
+ &oldflags) < 0)
goto fail;
/* Try setting the flags as given. */
newflags = (oldflags & ~clear) | set;
- if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0)
+ if (ioctl(myfd,
+#ifdef FS_IOC_SETFLAGS
+ FS_IOC_SETFLAGS,
+#else
+ EXT2_IOC_SETFLAGS,
+#endif
+ &newflags) >= 0)
goto cleanup;
if (errno != EPERM)
goto fail;
@@ -3270,7 +3713,13 @@ set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
newflags &= ~sf_mask;
oldflags &= sf_mask;
newflags |= oldflags;
- if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0)
+ if (ioctl(myfd,
+#ifdef FS_IOC_SETFLAGS
+ FS_IOC_SETFLAGS,
+#else
+ EXT2_IOC_SETFLAGS,
+#endif
+ &newflags) >= 0)
goto cleanup;
/* We couldn't set the flags, so report the failure. */
@@ -3363,6 +3812,7 @@ copy_xattrs(struct archive_write_disk *a, int tmpfd, int dffd)
}
for (xattr_i = 0; xattr_i < xattr_size;
xattr_i += strlen(xattr_names + xattr_i) + 1) {
+ char *xattr_val_saved;
ssize_t s;
int f;
@@ -3373,11 +3823,13 @@ copy_xattrs(struct archive_write_disk *a, int tmpfd, int dffd)
ret = ARCHIVE_WARN;
goto exit_xattr;
}
+ xattr_val_saved = xattr_val;
xattr_val = realloc(xattr_val, s);
if (xattr_val == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Failed to get metadata(xattr)");
ret = ARCHIVE_WARN;
+ free(xattr_val_saved);
goto exit_xattr;
}
s = fgetxattr(tmpfd, xattr_names + xattr_i, xattr_val, s, 0, 0);
@@ -3405,6 +3857,9 @@ exit_xattr:
static int
copy_acls(struct archive_write_disk *a, int tmpfd, int dffd)
{
+#ifndef HAVE_SYS_ACL_H
+ return 0;
+#else
acl_t acl, dfacl = NULL;
int acl_r, ret = ARCHIVE_OK;
@@ -3432,6 +3887,7 @@ exit_acl:
if (dfacl)
acl_free(dfacl);
return (ret);
+#endif
}
static int
@@ -3627,69 +4083,98 @@ skip_appledouble:
}
#endif
-#if HAVE_LSETXATTR || HAVE_LSETEA
+#if ARCHIVE_XATTR_LINUX || ARCHIVE_XATTR_DARWIN || ARCHIVE_XATTR_AIX
/*
- * Restore extended attributes - Linux and AIX implementations:
+ * Restore extended attributes - Linux, Darwin and AIX implementations:
* AIX' ea interface is syntaxwise identical to the Linux xattr interface.
*/
static int
set_xattrs(struct archive_write_disk *a)
{
struct archive_entry *entry = a->entry;
- static int warning_done = 0;
+ struct archive_string errlist;
int ret = ARCHIVE_OK;
int i = archive_entry_xattr_reset(entry);
+ short fail = 0;
+
+ archive_string_init(&errlist);
while (i--) {
const char *name;
const void *value;
size_t size;
+ int e;
+
archive_entry_xattr_next(entry, &name, &value, &size);
- if (name != NULL &&
- strncmp(name, "xfsroot.", 8) != 0 &&
- strncmp(name, "system.", 7) != 0) {
- int e;
-#if HAVE_FSETXATTR
- if (a->fd >= 0)
- e = fsetxattr(a->fd, name, value, size, 0);
- else
-#elif HAVE_FSETEA
- if (a->fd >= 0)
- e = fsetea(a->fd, name, value, size, 0);
- else
+
+ if (name == NULL)
+ continue;
+#if ARCHIVE_XATTR_LINUX
+ /* Linux: quietly skip POSIX.1e ACL extended attributes */
+ if (strncmp(name, "system.", 7) == 0 &&
+ (strcmp(name + 7, "posix_acl_access") == 0 ||
+ strcmp(name + 7, "posix_acl_default") == 0))
+ continue;
+ if (strncmp(name, "trusted.SGI_", 12) == 0 &&
+ (strcmp(name + 12, "ACL_DEFAULT") == 0 ||
+ strcmp(name + 12, "ACL_FILE") == 0))
+ continue;
+
+ /* Linux: xfsroot namespace is obsolete and unsupported */
+ if (strncmp(name, "xfsroot.", 8) == 0) {
+ fail = 1;
+ archive_strcat(&errlist, name);
+ archive_strappend_char(&errlist, ' ');
+ continue;
+ }
#endif
- {
-#if HAVE_LSETXATTR
- e = lsetxattr(archive_entry_pathname(entry),
- name, value, size, 0);
-#elif HAVE_LSETEA
- e = lsetea(archive_entry_pathname(entry),
- name, value, size, 0);
+
+ if (a->fd >= 0) {
+#if ARCHIVE_XATTR_LINUX
+ e = fsetxattr(a->fd, name, value, size, 0);
+#elif ARCHIVE_XATTR_DARWIN
+ e = fsetxattr(a->fd, name, value, size, 0, 0);
+#elif ARCHIVE_XATTR_AIX
+ e = fsetea(a->fd, name, value, size, 0);
#endif
- }
- if (e == -1) {
- if (errno == ENOTSUP || errno == ENOSYS) {
- if (!warning_done) {
- warning_done = 1;
- archive_set_error(&a->archive, errno,
- "Cannot restore extended "
- "attributes on this file "
- "system");
- }
- } else
- archive_set_error(&a->archive, errno,
- "Failed to set extended attribute");
- ret = ARCHIVE_WARN;
- }
} else {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid extended attribute encountered");
+#if ARCHIVE_XATTR_LINUX
+ e = lsetxattr(archive_entry_pathname(entry),
+ name, value, size, 0);
+#elif ARCHIVE_XATTR_DARWIN
+ e = setxattr(archive_entry_pathname(entry),
+ name, value, size, 0, XATTR_NOFOLLOW);
+#elif ARCHIVE_XATTR_AIX
+ e = lsetea(archive_entry_pathname(entry),
+ name, value, size, 0);
+#endif
+ }
+ if (e == -1) {
ret = ARCHIVE_WARN;
+ archive_strcat(&errlist, name);
+ archive_strappend_char(&errlist, ' ');
+ if (errno != ENOTSUP && errno != ENOSYS)
+ fail = 1;
}
}
+
+ if (ret == ARCHIVE_WARN) {
+ if (fail && errlist.length > 0) {
+ errlist.length--;
+ errlist.s[errlist.length] = '\0';
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Cannot restore extended attributes: %s",
+ errlist.s);
+ } else
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Cannot restore extended "
+ "attributes on this file system.");
+ }
+
+ archive_string_free(&errlist);
return (ret);
}
-#elif HAVE_EXTATTR_SET_FILE && HAVE_DECL_EXTATTR_NAMESPACE_USER
+#elif ARCHIVE_XATTR_FREEBSD
/*
* Restore extended attributes - FreeBSD implementation
*/
@@ -3697,9 +4182,12 @@ static int
set_xattrs(struct archive_write_disk *a)
{
struct archive_entry *entry = a->entry;
- static int warning_done = 0;
+ struct archive_string errlist;
int ret = ARCHIVE_OK;
int i = archive_entry_xattr_reset(entry);
+ short fail = 0;
+
+ archive_string_init(&errlist);
while (i--) {
const char *name;
@@ -3715,43 +4203,47 @@ set_xattrs(struct archive_write_disk *a)
name += 5;
namespace = EXTATTR_NAMESPACE_USER;
} else {
- /* Warn about other extended attributes. */
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't restore extended attribute ``%s''",
- name);
+ /* Other namespaces are unsupported */
+ archive_strcat(&errlist, name);
+ archive_strappend_char(&errlist, ' ');
+ fail = 1;
ret = ARCHIVE_WARN;
continue;
}
- errno = 0;
-#if HAVE_EXTATTR_SET_FD
- if (a->fd >= 0)
- e = extattr_set_fd(a->fd, namespace, name, value, size);
- else
-#endif
- /* TODO: should we use extattr_set_link() instead? */
- {
- e = extattr_set_file(archive_entry_pathname(entry),
- namespace, name, value, size);
+
+ if (a->fd >= 0) {
+ e = extattr_set_fd(a->fd, namespace, name,
+ value, size);
+ } else {
+ e = extattr_set_link(
+ archive_entry_pathname(entry), namespace,
+ name, value, size);
}
if (e != (int)size) {
- if (errno == ENOTSUP || errno == ENOSYS) {
- if (!warning_done) {
- warning_done = 1;
- archive_set_error(&a->archive, errno,
- "Cannot restore extended "
- "attributes on this file "
- "system");
- }
- } else {
- archive_set_error(&a->archive, errno,
- "Failed to set extended attribute");
- }
-
+ archive_strcat(&errlist, name);
+ archive_strappend_char(&errlist, ' ');
ret = ARCHIVE_WARN;
+ if (errno != ENOTSUP && errno != ENOSYS)
+ fail = 1;
}
}
}
+
+ if (ret == ARCHIVE_WARN) {
+ if (fail && errlist.length > 0) {
+ errlist.length--;
+ errlist.s[errlist.length] = '\0';
+
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Cannot restore extended attributes: %s",
+ errlist.s);
+ } else
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Cannot restore extended "
+ "attributes on this file system.");
+ }
+
+ archive_string_free(&errlist);
return (ret);
}
#else
@@ -3784,10 +4276,10 @@ older(struct stat *st, struct archive_entry *entry)
{
/* First, test the seconds and return if we have a definite answer. */
/* Definitely older. */
- if (st->st_mtime < archive_entry_mtime(entry))
+ if (to_int64_time(st->st_mtime) < to_int64_time(archive_entry_mtime(entry)))
return (1);
/* Definitely younger. */
- if (st->st_mtime > archive_entry_mtime(entry))
+ if (to_int64_time(st->st_mtime) > to_int64_time(archive_entry_mtime(entry)))
return (0);
/* If this platform supports fractional seconds, try those. */
#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
@@ -3817,5 +4309,19 @@ older(struct stat *st, struct archive_entry *entry)
return (0);
}
+#ifndef ARCHIVE_ACL_SUPPORT
+int
+archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
+ struct archive_acl *abstract_acl, __LA_MODE_T mode)
+{
+ (void)a; /* UNUSED */
+ (void)fd; /* UNUSED */
+ (void)name; /* UNUSED */
+ (void)abstract_acl; /* UNUSED */
+ (void)mode; /* UNUSED */
+ return (ARCHIVE_OK);
+}
+#endif
+
#endif /* !_WIN32 || __CYGWIN__ */
diff --git a/3rdparty/libarchive/libarchive/archive_write_disk_private.h b/3rdparty/libarchive/libarchive/archive_write_disk_private.h
index d84e7e1c..b655dea2 100644
--- a/3rdparty/libarchive/libarchive/archive_write_disk_private.h
+++ b/3rdparty/libarchive/libarchive/archive_write_disk_private.h
@@ -33,11 +33,13 @@
#ifndef ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED
#define ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED
+#include "archive_platform_acl.h"
#include "archive_acl_private.h"
+#include "archive_entry.h"
struct archive_write_disk;
-int
-archive_write_disk_set_acls(struct archive *, int /* fd */, const char * /* pathname */, struct archive_acl *);
+int archive_write_disk_set_acls(struct archive *, int, const char *,
+ struct archive_acl *, __LA_MODE_T);
#endif
diff --git a/3rdparty/libarchive/libarchive/archive_write_disk_set_standard_lookup.c b/3rdparty/libarchive/libarchive/archive_write_disk_set_standard_lookup.c
index e79008ef..5c766d75 100644
--- a/3rdparty/libarchive/libarchive/archive_write_disk_set_standard_lookup.c
+++ b/3rdparty/libarchive/libarchive/archive_write_disk_set_standard_lookup.c
@@ -67,7 +67,7 @@ static void cleanup(void *);
* a simple cache to accelerate such lookups---into the archive_write_disk
* object. This is in a separate file because getpwnam()/getgrnam()
* can pull in a LOT of library code (including NIS/LDAP functions, which
- * pull in DNS resolveers, etc). This can easily top 500kB, which makes
+ * pull in DNS resolvers, etc). This can easily top 500kB, which makes
* it inappropriate for some space-constrained applications.
*
* Applications that are size-sensitive may want to just use the
@@ -84,10 +84,13 @@ static void cleanup(void *);
int
archive_write_disk_set_standard_lookup(struct archive *a)
{
- struct bucket *ucache = malloc(cache_size * sizeof(struct bucket));
- struct bucket *gcache = malloc(cache_size * sizeof(struct bucket));
- memset(ucache, 0, cache_size * sizeof(struct bucket));
- memset(gcache, 0, cache_size * sizeof(struct bucket));
+ struct bucket *ucache = calloc(cache_size, sizeof(struct bucket));
+ struct bucket *gcache = calloc(cache_size, sizeof(struct bucket));
+ if (ucache == NULL || gcache == NULL) {
+ free(ucache);
+ free(gcache);
+ return (ARCHIVE_FATAL);
+ }
archive_write_disk_set_group_lookup(a, gcache, lookup_gid, cleanup);
archive_write_disk_set_user_lookup(a, ucache, lookup_uid, cleanup);
return (ARCHIVE_OK);
diff --git a/3rdparty/libarchive/libarchive/archive_write_disk_windows.c b/3rdparty/libarchive/libarchive/archive_write_disk_windows.c
index 0f0780a8..94b016ed 100644
--- a/3rdparty/libarchive/libarchive/archive_write_disk_windows.c
+++ b/3rdparty/libarchive/libarchive/archive_write_disk_windows.c
@@ -192,7 +192,7 @@ struct archive_write_disk {
/*
* Default mode for dirs created automatically (will be modified by umask).
- * Note that POSIX specifies 0777 for implicity-created dirs, "modified
+ * Note that POSIX specifies 0777 for implicitly-created dirs, "modified
* by the process' file creation mask."
*/
#define DEFAULT_DIR_MODE 0777
@@ -330,8 +330,6 @@ file_information(struct archive_write_disk *a, wchar_t *path,
break;
case L'C': case L'c':
if (((p[2] == L'M' || p[2] == L'm' ) &&
- (p[3] == L'D' || p[3] == L'd' )) ||
- ((p[2] == L'M' || p[2] == L'm' ) &&
(p[3] == L'D' || p[3] == L'd' )))
*mode |= S_IXUSR | S_IXGRP | S_IXOTH;
break;
@@ -398,7 +396,7 @@ permissive_name_w(struct archive_write_disk *a)
}
/*
- * A full-pathname pointig a network drive
+ * A full-pathname pointing to a network drive
* like "\\<server-name>\<share-name>\file".
*/
if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') {
@@ -470,9 +468,17 @@ permissive_name_w(struct archive_write_disk *a)
return (-1);
archive_wstring_ensure(&(a->_name_data), 4 + l + 1 + wcslen(wn) + 1);
a->name = a->_name_data.s;
- /* Prepend "\\?\" and drive name. */
- archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4);
- archive_wstrncat(&(a->_name_data), wsp, l);
+ /* Prepend "\\?\" and drive name if not already added. */
+ if (l > 3 && wsp[0] == L'\\' && wsp[1] == L'\\' &&
+ wsp[2] == L'?' && wsp[3] == L'\\')
+ {
+ archive_wstrncpy(&(a->_name_data), wsp, l);
+ }
+ else
+ {
+ archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4);
+ archive_wstrncat(&(a->_name_data), wsp, l);
+ }
archive_wstrncat(&(a->_name_data), L"\\", 1);
archive_wstrcat(&(a->_name_data), wn);
a->name = a->_name_data.s;
@@ -525,7 +531,7 @@ la_GetFunctionKernel32(const char *name)
static int set;
if (!set) {
set = 1;
- lib = LoadLibrary("kernel32.dll");
+ lib = LoadLibrary(TEXT("kernel32.dll"));
}
if (lib == NULL) {
fprintf(stderr, "Can't load kernel32.dll?!\n");
@@ -1011,7 +1017,11 @@ _archive_write_disk_data_block(struct archive *_a,
"Write request too large");
return (ARCHIVE_WARN);
}
+#if ARCHIVE_VERSION_NUMBER < 3999000
return (ARCHIVE_OK);
+#else
+ return (size);
+#endif
}
static ssize_t
@@ -1211,10 +1221,9 @@ archive_write_disk_new(void)
{
struct archive_write_disk *a;
- a = (struct archive_write_disk *)malloc(sizeof(*a));
+ a = (struct archive_write_disk *)calloc(1, sizeof(*a));
if (a == NULL)
return (NULL);
- memset(a, 0, sizeof(*a));
a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC;
/* We're ready to write a header immediately. */
a->archive.state = ARCHIVE_STATE_HEADER;
diff --git a/3rdparty/libarchive/libarchive/archive_write_open_filename.c b/3rdparty/libarchive/libarchive/archive_write_open_filename.c
index 196b770e..66e0dfee 100644
--- a/3rdparty/libarchive/libarchive/archive_write_open_filename.c
+++ b/3rdparty/libarchive/libarchive/archive_write_open_filename.c
@@ -243,7 +243,10 @@ file_close(struct archive *a, void *client_data)
struct write_file_data *mine = (struct write_file_data *)client_data;
(void)a; /* UNUSED */
- close(mine->fd);
+
+ if (mine->fd >= 0)
+ close(mine->fd);
+
archive_mstring_clean(&mine->filename);
free(mine);
return (ARCHIVE_OK);
diff --git a/3rdparty/libarchive/libarchive/archive_write_open_memory.c b/3rdparty/libarchive/libarchive/archive_write_open_memory.c
index 4f8d679e..ea6ae0ac 100644
--- a/3rdparty/libarchive/libarchive/archive_write_open_memory.c
+++ b/3rdparty/libarchive/libarchive/archive_write_open_memory.c
@@ -53,12 +53,11 @@ archive_write_open_memory(struct archive *a, void *buff, size_t buffSize, size_t
{
struct write_memory_data *mine;
- mine = (struct write_memory_data *)malloc(sizeof(*mine));
+ mine = (struct write_memory_data *)calloc(1, sizeof(*mine));
if (mine == NULL) {
archive_set_error(a, ENOMEM, "No memory");
return (ARCHIVE_FATAL);
}
- memset(mine, 0, sizeof(*mine));
mine->buff = buff;
mine->size = buffSize;
mine->client_size = used;
diff --git a/3rdparty/libarchive/libarchive/archive_write_private.h b/3rdparty/libarchive/libarchive/archive_write_private.h
index e600d547..0dfd1b1b 100644
--- a/3rdparty/libarchive/libarchive/archive_write_private.h
+++ b/3rdparty/libarchive/libarchive/archive_write_private.h
@@ -26,8 +26,10 @@
*/
#ifndef __LIBARCHIVE_BUILD
+#ifndef __LIBARCHIVE_TEST
#error This header is only to be used internally to libarchive.
#endif
+#endif
#ifndef ARCHIVE_WRITE_PRIVATE_H_INCLUDED
#define ARCHIVE_WRITE_PRIVATE_H_INCLUDED
@@ -116,6 +118,14 @@ struct archive_write {
const void *buff, size_t);
int (*format_close)(struct archive_write *);
int (*format_free)(struct archive_write *);
+
+
+ /*
+ * Encryption passphrase.
+ */
+ char *passphrase;
+ archive_passphrase_callback *passphrase_callback;
+ void *passphrase_client_data;
};
/*
@@ -134,7 +144,7 @@ __archive_write_format_header_ustar(struct archive_write *, char buff[512],
struct archive_string_conv *);
struct archive_write_program_data;
-struct archive_write_program_data * __archive_write_program_allocate(void);
+struct archive_write_program_data * __archive_write_program_allocate(const char *program_name);
int __archive_write_program_free(struct archive_write_program_data *);
int __archive_write_program_open(struct archive_write_filter *,
struct archive_write_program_data *, const char *);
@@ -142,4 +152,9 @@ int __archive_write_program_close(struct archive_write_filter *,
struct archive_write_program_data *);
int __archive_write_program_write(struct archive_write_filter *,
struct archive_write_program_data *, const void *, size_t);
+
+/*
+ * Get a encryption passphrase.
+ */
+const char * __archive_write_get_passphrase(struct archive_write *a);
#endif
diff --git a/3rdparty/libarchive/libarchive/archive_write_set_format.c b/3rdparty/libarchive/libarchive/archive_write_set_format.c
index 641d56f6..0f706231 100644
--- a/3rdparty/libarchive/libarchive/archive_write_set_format.c
+++ b/3rdparty/libarchive/libarchive/archive_write_set_format.c
@@ -38,7 +38,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format.c 201168 2009-1
#include "archive_private.h"
/* A table that maps format codes to functions. */
-static
+static const
struct { int code; int (*setter)(struct archive *); } codes[] =
{
{ ARCHIVE_FORMAT_7ZIP, archive_write_set_format_7zip },
@@ -47,6 +47,7 @@ struct { int code; int (*setter)(struct archive *); } codes[] =
{ ARCHIVE_FORMAT_CPIO_SVR4_NOCRC, archive_write_set_format_cpio_newc },
{ ARCHIVE_FORMAT_ISO9660, archive_write_set_format_iso9660 },
{ ARCHIVE_FORMAT_MTREE, archive_write_set_format_mtree },
+ { ARCHIVE_FORMAT_RAW, archive_write_set_format_raw },
{ ARCHIVE_FORMAT_SHAR, archive_write_set_format_shar },
{ ARCHIVE_FORMAT_SHAR_BASE, archive_write_set_format_shar },
{ ARCHIVE_FORMAT_SHAR_DUMP, archive_write_set_format_shar_dump },
@@ -56,8 +57,9 @@ struct { int code; int (*setter)(struct archive *); } codes[] =
{ ARCHIVE_FORMAT_TAR_PAX_RESTRICTED,
archive_write_set_format_pax_restricted },
{ ARCHIVE_FORMAT_TAR_USTAR, archive_write_set_format_ustar },
+ { ARCHIVE_FORMAT_WARC, archive_write_set_format_warc },
{ ARCHIVE_FORMAT_XAR, archive_write_set_format_xar },
- { ARCHIVE_FORMAT_ZIP, archive_write_set_format_zip },
+ { ARCHIVE_FORMAT_ZIP, archive_write_set_format_zip },
{ 0, NULL }
};
diff --git a/3rdparty/libarchive/libarchive/archive_write_set_format_7zip.c b/3rdparty/libarchive/libarchive/archive_write_set_format_7zip.c
deleted file mode 100644
index 7847cb3c..00000000
--- a/3rdparty/libarchive/libarchive/archive_write_set_format_7zip.c
+++ /dev/null
@@ -1,2324 +0,0 @@
-/*-
- * Copyright (c) 2011-2012 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"
-__FBSDID("$FreeBSD$");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#include <stdlib.h>
-#ifdef HAVE_BZLIB_H
-#include <bzlib.h>
-#endif
-#if HAVE_LZMA_H
-#include <lzma.h>
-#endif
-#ifdef HAVE_ZLIB_H
-#include <zlib.h>
-#endif
-
-#include "archive.h"
-#ifndef HAVE_ZLIB_H
-#include "archive_crc32.h"
-#endif
-#include "archive_endian.h"
-#include "archive_entry.h"
-#include "archive_entry_locale.h"
-#include "archive_ppmd7_private.h"
-#include "archive_private.h"
-#include "archive_rb.h"
-#include "archive_string.h"
-#include "archive_write_private.h"
-
-/*
- * Codec ID
- */
-#define _7Z_COPY 0
-#define _7Z_LZMA1 0x030101
-#define _7Z_LZMA2 0x21
-#define _7Z_DEFLATE 0x040108
-#define _7Z_BZIP2 0x040202
-#define _7Z_PPMD 0x030401
-
-/*
- * 7-Zip header property IDs.
- */
-#define kEnd 0x00
-#define kHeader 0x01
-#define kArchiveProperties 0x02
-#define kAdditionalStreamsInfo 0x03
-#define kMainStreamsInfo 0x04
-#define kFilesInfo 0x05
-#define kPackInfo 0x06
-#define kUnPackInfo 0x07
-#define kSubStreamsInfo 0x08
-#define kSize 0x09
-#define kCRC 0x0A
-#define kFolder 0x0B
-#define kCodersUnPackSize 0x0C
-#define kNumUnPackStream 0x0D
-#define kEmptyStream 0x0E
-#define kEmptyFile 0x0F
-#define kAnti 0x10
-#define kName 0x11
-#define kCTime 0x12
-#define kATime 0x13
-#define kMTime 0x14
-#define kAttributes 0x15
-#define kEncodedHeader 0x17
-
-enum la_zaction {
- ARCHIVE_Z_FINISH,
- ARCHIVE_Z_RUN
-};
-
-/*
- * A stream object of universal compressor.
- */
-struct la_zstream {
- const uint8_t *next_in;
- size_t avail_in;
- uint64_t total_in;
-
- uint8_t *next_out;
- size_t avail_out;
- uint64_t total_out;
-
- uint32_t prop_size;
- uint8_t *props;
-
- int valid;
- void *real_stream;
- int (*code) (struct archive *a,
- struct la_zstream *lastrm,
- enum la_zaction action);
- int (*end)(struct archive *a,
- struct la_zstream *lastrm);
-};
-
-#define PPMD7_DEFAULT_ORDER 6
-#define PPMD7_DEFAULT_MEM_SIZE (1 << 24)
-
-struct ppmd_stream {
- int stat;
- CPpmd7 ppmd7_context;
- CPpmd7z_RangeEnc range_enc;
- IByteOut byteout;
- uint8_t *buff;
- uint8_t *buff_ptr;
- uint8_t *buff_end;
- size_t buff_bytes;
-};
-
-struct coder {
- unsigned codec;
- size_t prop_size;
- uint8_t *props;
-};
-
-struct file {
- struct archive_rb_node rbnode;
-
- struct file *next;
- unsigned name_len;
- uint8_t *utf16name;/* UTF16-LE name. */
- uint64_t size;
- unsigned flg;
-#define MTIME_IS_SET (1<<0)
-#define ATIME_IS_SET (1<<1)
-#define CTIME_IS_SET (1<<2)
-#define CRC32_IS_SET (1<<3)
-#define HAS_STREAM (1<<4)
-
- struct {
- time_t time;
- long time_ns;
- } times[3];
-#define MTIME 0
-#define ATIME 1
-#define CTIME 2
-
- mode_t mode;
- uint32_t crc32;
-
- int dir:1;
-};
-
-struct _7zip {
- int temp_fd;
- uint64_t temp_offset;
-
- struct file *cur_file;
- size_t total_number_entry;
- size_t total_number_nonempty_entry;
- size_t total_number_empty_entry;
- size_t total_number_dir_entry;
- size_t total_bytes_entry_name;
- size_t total_number_time_defined[3];
- uint64_t total_bytes_compressed;
- uint64_t total_bytes_uncompressed;
- uint64_t entry_bytes_remaining;
- uint32_t entry_crc32;
- uint32_t precode_crc32;
- uint32_t encoded_crc32;
- int crc32flg;
-#define PRECODE_CRC32 1
-#define ENCODED_CRC32 2
-
- unsigned opt_compression;
- int opt_compression_level;
-
- struct la_zstream stream;
- struct coder coder;
-
- struct archive_string_conv *sconv;
-
- /*
- * Compressed data buffer.
- */
- unsigned char wbuff[512 * 20 * 6];
- size_t wbuff_remaining;
-
- /*
- * The list of the file entries which has its contents is used to
- * manage struct file objects.
- * We use 'next' a menber of struct file to chain.
- */
- struct {
- struct file *first;
- struct file **last;
- } file_list, empty_list;
- struct archive_rb_tree rbtree;/* for empty files */
-};
-
-static int _7z_options(struct archive_write *,
- const char *, const char *);
-static int _7z_write_header(struct archive_write *,
- struct archive_entry *);
-static ssize_t _7z_write_data(struct archive_write *,
- const void *, size_t);
-static int _7z_finish_entry(struct archive_write *);
-static int _7z_close(struct archive_write *);
-static int _7z_free(struct archive_write *);
-static int file_cmp_node(const struct archive_rb_node *,
- const struct archive_rb_node *);
-static int file_cmp_key(const struct archive_rb_node *, const void *);
-static int file_new(struct archive_write *a, struct archive_entry *,
- struct file **);
-static void file_free(struct file *);
-static void file_register(struct _7zip *, struct file *);
-static void file_register_empty(struct _7zip *, struct file *);
-static void file_init_register(struct _7zip *);
-static void file_init_register_empty(struct _7zip *);
-static void file_free_register(struct _7zip *);
-static ssize_t compress_out(struct archive_write *, const void *, size_t ,
- enum la_zaction);
-static int compression_init_encoder_copy(struct archive *,
- struct la_zstream *);
-static int compression_code_copy(struct archive *,
- struct la_zstream *, enum la_zaction);
-static int compression_end_copy(struct archive *, struct la_zstream *);
-static int compression_init_encoder_deflate(struct archive *,
- struct la_zstream *, int, int);
-#ifdef HAVE_ZLIB_H
-static int compression_code_deflate(struct archive *,
- struct la_zstream *, enum la_zaction);
-static int compression_end_deflate(struct archive *, struct la_zstream *);
-#endif
-static int compression_init_encoder_bzip2(struct archive *,
- struct la_zstream *, int);
-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
-static int compression_code_bzip2(struct archive *,
- struct la_zstream *, enum la_zaction);
-static int compression_end_bzip2(struct archive *, struct la_zstream *);
-#endif
-static int compression_init_encoder_lzma1(struct archive *,
- struct la_zstream *, int);
-static int compression_init_encoder_lzma2(struct archive *,
- struct la_zstream *, int);
-#if defined(HAVE_LZMA_H)
-static int compression_code_lzma(struct archive *,
- struct la_zstream *, enum la_zaction);
-static int compression_end_lzma(struct archive *, struct la_zstream *);
-#endif
-static int compression_init_encoder_ppmd(struct archive *,
- struct la_zstream *, unsigned, uint32_t);
-static int compression_code_ppmd(struct archive *,
- struct la_zstream *, enum la_zaction);
-static int compression_end_ppmd(struct archive *, struct la_zstream *);
-static int _7z_compression_init_encoder(struct archive_write *, unsigned,
- int);
-static int compression_code(struct archive *,
- struct la_zstream *, enum la_zaction);
-static int compression_end(struct archive *,
- struct la_zstream *);
-static int enc_uint64(struct archive_write *, uint64_t);
-static int make_header(struct archive_write *, uint64_t, uint64_t,
- uint64_t, int, struct coder *);
-static int make_streamsInfo(struct archive_write *, uint64_t, uint64_t,
- uint64_t, int, struct coder *, int, uint32_t);
-
-int
-archive_write_set_format_7zip(struct archive *_a)
-{
- static const struct archive_rb_tree_ops rb_ops = {
- file_cmp_node, file_cmp_key
- };
- struct archive_write *a = (struct archive_write *)_a;
- struct _7zip *zip;
-
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_set_format_7zip");
-
- /* If another format was already registered, unregister it. */
- if (a->format_free != NULL)
- (a->format_free)(a);
-
- zip = calloc(1, sizeof(*zip));
- if (zip == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate 7-Zip data");
- return (ARCHIVE_FATAL);
- }
- zip->temp_fd = -1;
- __archive_rb_tree_init(&(zip->rbtree), &rb_ops);
- file_init_register(zip);
- file_init_register_empty(zip);
-
- /* Set default compression type and its level. */
-#if HAVE_LZMA_H
- zip->opt_compression = _7Z_LZMA1;
-#elif defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
- zip->opt_compression = _7Z_BZIP2;
-#elif defined(HAVE_ZLIB_H)
- zip->opt_compression = _7Z_DEFLATE;
-#else
- zip->opt_compression = _7Z_COPY;
-#endif
- zip->opt_compression_level = 6;
-
- a->format_data = zip;
-
- a->format_name = "7zip";
- a->format_options = _7z_options;
- a->format_write_header = _7z_write_header;
- a->format_write_data = _7z_write_data;
- a->format_finish_entry = _7z_finish_entry;
- a->format_close = _7z_close;
- a->format_free = _7z_free;
- a->archive.archive_format = ARCHIVE_FORMAT_7ZIP;
- a->archive.archive_format_name = "7zip";
-
- return (ARCHIVE_OK);
-}
-
-static int
-_7z_options(struct archive_write *a, const char *key, const char *value)
-{
- struct _7zip *zip;
-
- zip = (struct _7zip *)a->format_data;
-
- if (strcmp(key, "compression") == 0) {
- const char *name = NULL;
-
- if (value == NULL || strcmp(value, "copy") == 0 ||
- strcmp(value, "COPY") == 0 ||
- strcmp(value, "store") == 0 ||
- strcmp(value, "STORE") == 0)
- zip->opt_compression = _7Z_COPY;
- else if (strcmp(value, "deflate") == 0 ||
- strcmp(value, "DEFLATE") == 0)
-#if HAVE_ZLIB_H
- zip->opt_compression = _7Z_DEFLATE;
-#else
- name = "deflate";
-#endif
- else if (strcmp(value, "bzip2") == 0 ||
- strcmp(value, "BZIP2") == 0)
-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
- zip->opt_compression = _7Z_BZIP2;
-#else
- name = "bzip2";
-#endif
- else if (strcmp(value, "lzma1") == 0 ||
- strcmp(value, "LZMA1") == 0)
-#if HAVE_LZMA_H
- zip->opt_compression = _7Z_LZMA1;
-#else
- name = "lzma1";
-#endif
- else if (strcmp(value, "lzma2") == 0 ||
- strcmp(value, "LZMA2") == 0)
-#if HAVE_LZMA_H
- zip->opt_compression = _7Z_LZMA2;
-#else
- name = "lzma2";
-#endif
- else if (strcmp(value, "ppmd") == 0 ||
- strcmp(value, "PPMD") == 0 ||
- strcmp(value, "PPMd") == 0)
- zip->opt_compression = _7Z_PPMD;
- else {
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "Unknown compression name: `%s'",
- value);
- return (ARCHIVE_FAILED);
- }
- if (name != NULL) {
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "`%s' compression not supported "
- "on this platform",
- name);
- return (ARCHIVE_FAILED);
- }
- return (ARCHIVE_OK);
- }
- if (strcmp(key, "compression-level") == 0) {
- if (value == NULL ||
- !(value[0] >= '0' && value[0] <= '9') ||
- value[1] != '\0') {
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "Illegal value `%s'",
- value);
- return (ARCHIVE_FAILED);
- }
- zip->opt_compression_level = value[0] - '0';
- return (ARCHIVE_OK);
- }
-
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
-}
-
-static int
-_7z_write_header(struct archive_write *a, struct archive_entry *entry)
-{
- struct _7zip *zip;
- struct file *file;
- int r;
-
- zip = (struct _7zip *)a->format_data;
- zip->cur_file = NULL;
- zip->entry_bytes_remaining = 0;
-
- if (zip->sconv == NULL) {
- zip->sconv = archive_string_conversion_to_charset(
- &a->archive, "UTF-16LE", 1);
- if (zip->sconv == NULL)
- return (ARCHIVE_FATAL);
- }
-
- r = file_new(a, entry, &file);
- if (r < ARCHIVE_WARN) {
- file_free(file);
- return (r);
- }
- if (file->size == 0 && file->dir) {
- if (!__archive_rb_tree_insert_node(&(zip->rbtree),
- (struct archive_rb_node *)file)) {
- /* We have already had the same file. */
- file_free(file);
- return (ARCHIVE_OK);
- }
- }
-
- if (file->flg & MTIME_IS_SET)
- zip->total_number_time_defined[MTIME]++;
- if (file->flg & CTIME_IS_SET)
- zip->total_number_time_defined[CTIME]++;
- if (file->flg & ATIME_IS_SET)
- zip->total_number_time_defined[ATIME]++;
-
- zip->total_number_entry++;
- zip->total_bytes_entry_name += file->name_len + 2;
- if (file->size == 0) {
- /* Count up the number of empty files. */
- zip->total_number_empty_entry++;
- if (file->dir)
- zip->total_number_dir_entry++;
- else
- file_register_empty(zip, file);
- return (r);
- }
-
- /*
- * Init compression.
- */
- if ((zip->total_number_entry - zip->total_number_empty_entry) == 1) {
- r = _7z_compression_init_encoder(a, zip->opt_compression,
- zip->opt_compression_level);
- if (r < 0) {
- file_free(file);
- return (ARCHIVE_FATAL);
- }
- }
-
- /* Register a non-empty file. */
- file_register(zip, file);
-
- /*
- * Set the current file to cur_file to read its contents.
- */
- zip->cur_file = file;
-
-
- /* Save a offset of current file in temporary file. */
- zip->entry_bytes_remaining = file->size;
- zip->entry_crc32 = 0;
-
- /*
- * Store a symbolic link name as file contents.
- */
- if (archive_entry_filetype(entry) == AE_IFLNK) {
- ssize_t bytes;
- const void *p = (const void *)archive_entry_symlink(entry);
- bytes = compress_out(a, p, (size_t)file->size, ARCHIVE_Z_RUN);
- if (bytes < 0)
- return ((int)bytes);
- zip->entry_crc32 = crc32(zip->entry_crc32, p, (unsigned)bytes);
- zip->entry_bytes_remaining -= bytes;
- }
-
- return (r);
-}
-
-/*
- * Write data to a temporary file.
- */
-static int
-write_to_temp(struct archive_write *a, const void *buff, size_t s)
-{
- struct _7zip *zip;
- const unsigned char *p;
- ssize_t ws;
-
- zip = (struct _7zip *)a->format_data;
-
- /*
- * Open a temporary file.
- */
- if (zip->temp_fd == -1) {
- zip->temp_offset = 0;
- zip->temp_fd = __archive_mktemp(NULL);
- if (zip->temp_fd < 0) {
- archive_set_error(&a->archive, errno,
- "Couldn't create temporary file");
- return (ARCHIVE_FATAL);
- }
- }
-
- p = (const unsigned char *)buff;
- while (s) {
- ws = write(zip->temp_fd, p, s);
- if (ws < 0) {
- archive_set_error(&(a->archive), errno,
- "fwrite function failed");
- return (ARCHIVE_FATAL);
- }
- s -= ws;
- p += ws;
- zip->temp_offset += ws;
- }
- return (ARCHIVE_OK);
-}
-
-static ssize_t
-compress_out(struct archive_write *a, const void *buff, size_t s,
- enum la_zaction run)
-{
- struct _7zip *zip = (struct _7zip *)a->format_data;
- int r;
-
- if (run == ARCHIVE_Z_FINISH && zip->stream.total_in == 0 && s == 0)
- return (0);
-
- if ((zip->crc32flg & PRECODE_CRC32) && s)
- zip->precode_crc32 = crc32(zip->precode_crc32, buff,
- (unsigned)s);
- zip->stream.next_in = (const unsigned char *)buff;
- zip->stream.avail_in = s;
- for (;;) {
- /* Compress file data. */
- r = compression_code(&(a->archive), &(zip->stream), run);
- if (r != ARCHIVE_OK && r != ARCHIVE_EOF)
- return (ARCHIVE_FATAL);
- if (zip->stream.avail_out == 0) {
- if (write_to_temp(a, zip->wbuff, sizeof(zip->wbuff))
- != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- zip->stream.next_out = zip->wbuff;
- zip->stream.avail_out = sizeof(zip->wbuff);
- if (zip->crc32flg & ENCODED_CRC32)
- zip->encoded_crc32 = crc32(zip->encoded_crc32,
- zip->wbuff, sizeof(zip->wbuff));
- if (run == ARCHIVE_Z_FINISH && r != ARCHIVE_EOF)
- continue;
- }
- if (zip->stream.avail_in == 0)
- break;
- }
- if (run == ARCHIVE_Z_FINISH) {
- uint64_t bytes = sizeof(zip->wbuff) - zip->stream.avail_out;
- if (write_to_temp(a, zip->wbuff, (size_t)bytes) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- if ((zip->crc32flg & ENCODED_CRC32) && bytes)
- zip->encoded_crc32 = crc32(zip->encoded_crc32,
- zip->wbuff, (unsigned)bytes);
- }
-
- return (s);
-}
-
-static ssize_t
-_7z_write_data(struct archive_write *a, const void *buff, size_t s)
-{
- struct _7zip *zip;
- ssize_t bytes;
-
- zip = (struct _7zip *)a->format_data;
-
- if (s > zip->entry_bytes_remaining)
- s = (size_t)zip->entry_bytes_remaining;
- if (s == 0 || zip->cur_file == NULL)
- return (0);
- bytes = compress_out(a, buff, s, ARCHIVE_Z_RUN);
- if (bytes < 0)
- return (bytes);
- zip->entry_crc32 = crc32(zip->entry_crc32, buff, (unsigned)bytes);
- zip->entry_bytes_remaining -= bytes;
- return (bytes);
-}
-
-static int
-_7z_finish_entry(struct archive_write *a)
-{
- struct _7zip *zip;
- size_t s;
- ssize_t r;
-
- zip = (struct _7zip *)a->format_data;
- if (zip->cur_file == NULL)
- return (ARCHIVE_OK);
-
- while (zip->entry_bytes_remaining > 0) {
- s = (size_t)zip->entry_bytes_remaining;
- if (s > a->null_length)
- s = a->null_length;
- r = _7z_write_data(a, a->nulls, s);
- if (r < 0)
- return ((int)r);
- }
- zip->total_bytes_compressed += zip->stream.total_in;
- zip->total_bytes_uncompressed += zip->stream.total_out;
- zip->cur_file->crc32 = zip->entry_crc32;
- zip->cur_file = NULL;
-
- return (ARCHIVE_OK);
-}
-
-static int
-flush_wbuff(struct archive_write *a)
-{
- struct _7zip *zip;
- int r;
- size_t s;
-
- zip = (struct _7zip *)a->format_data;
- s = sizeof(zip->wbuff) - zip->wbuff_remaining;
- r = __archive_write_output(a, zip->wbuff, s);
- if (r != ARCHIVE_OK)
- return (r);
- zip->wbuff_remaining = sizeof(zip->wbuff);
- return (r);
-}
-
-static int
-copy_out(struct archive_write *a, uint64_t offset, uint64_t length)
-{
- struct _7zip *zip;
- int r;
-
- zip = (struct _7zip *)a->format_data;
- if (zip->temp_offset > 0 &&
- lseek(zip->temp_fd, offset, SEEK_SET) < 0) {
- archive_set_error(&(a->archive), errno, "lseek failed");
- return (ARCHIVE_FATAL);
- }
- while (length) {
- size_t rsize;
- ssize_t rs;
- unsigned char *wb;
-
- if (length > zip->wbuff_remaining)
- rsize = zip->wbuff_remaining;
- else
- rsize = (size_t)length;
- wb = zip->wbuff + (sizeof(zip->wbuff) - zip->wbuff_remaining);
- rs = read(zip->temp_fd, wb, rsize);
- if (rs < 0) {
- archive_set_error(&(a->archive), errno,
- "Can't read temporary file(%jd)",
- (intmax_t)rs);
- return (ARCHIVE_FATAL);
- }
- if (rs == 0) {
- archive_set_error(&(a->archive), 0,
- "Truncated 7-Zip archive");
- return (ARCHIVE_FATAL);
- }
- zip->wbuff_remaining -= rs;
- length -= rs;
- if (zip->wbuff_remaining == 0) {
- r = flush_wbuff(a);
- if (r != ARCHIVE_OK)
- return (r);
- }
- }
- return (ARCHIVE_OK);
-}
-
-static int
-_7z_close(struct archive_write *a)
-{
- struct _7zip *zip;
- unsigned char *wb;
- uint64_t header_offset, header_size, header_unpacksize;
- uint64_t length;
- uint32_t header_crc32;
- int r;
-
- zip = (struct _7zip *)a->format_data;
-
- if (zip->total_number_entry > 0) {
- struct archive_rb_node *n;
- uint64_t data_offset, data_size, data_unpacksize;
- unsigned header_compression;
-
- r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);
- if (r < 0)
- return (r);
- data_offset = 0;
- data_size = zip->stream.total_out;
- data_unpacksize = zip->stream.total_in;
- zip->coder.codec = zip->opt_compression;
- zip->coder.prop_size = zip->stream.prop_size;
- zip->coder.props = zip->stream.props;
- zip->stream.prop_size = 0;
- zip->stream.props = NULL;
- zip->total_number_nonempty_entry =
- zip->total_number_entry - zip->total_number_empty_entry;
-
- /* Connect an empty file list. */
- if (zip->empty_list.first != NULL) {
- *zip->file_list.last = zip->empty_list.first;
- zip->file_list.last = zip->empty_list.last;
- }
- /* Connect a directory file list. */
- ARCHIVE_RB_TREE_FOREACH(n, &(zip->rbtree)) {
- file_register(zip, (struct file *)n);
- }
-
- /*
- * NOTE: 7z command supports just LZMA1, LZMA2 and COPY for
- * the compression type for encoding the header.
- */
-#if HAVE_LZMA_H
- header_compression = _7Z_LZMA1;
- /* If the stored file is only one, do not encode the header.
- * This is the same way 7z command does. */
- if (zip->total_number_entry == 1)
- header_compression = _7Z_COPY;
-#else
- header_compression = _7Z_COPY;
-#endif
- r = _7z_compression_init_encoder(a, header_compression, 6);
- if (r < 0)
- return (r);
- zip->crc32flg = PRECODE_CRC32;
- zip->precode_crc32 = 0;
- r = make_header(a, data_offset, data_size, data_unpacksize,
- 1, &(zip->coder));
- if (r < 0)
- return (r);
- r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);
- if (r < 0)
- return (r);
- header_offset = data_offset + data_size;
- header_size = zip->stream.total_out;
- header_crc32 = zip->precode_crc32;
- header_unpacksize = zip->stream.total_in;
-
- if (header_compression != _7Z_COPY) {
- /*
- * Encode the header in order to reduce the size
- * of the archive.
- */
- free(zip->coder.props);
- zip->coder.codec = header_compression;
- zip->coder.prop_size = zip->stream.prop_size;
- zip->coder.props = zip->stream.props;
- zip->stream.prop_size = 0;
- zip->stream.props = NULL;
-
- r = _7z_compression_init_encoder(a, _7Z_COPY, 0);
- if (r < 0)
- return (r);
- zip->crc32flg = ENCODED_CRC32;
- zip->encoded_crc32 = 0;
-
- /*
- * Make EncodedHeader.
- */
- r = enc_uint64(a, kEncodedHeader);
- if (r < 0)
- return (r);
- r = make_streamsInfo(a, header_offset, header_size,
- header_unpacksize, 1, &(zip->coder), 0,
- header_crc32);
- if (r < 0)
- return (r);
- r = (int)compress_out(a, NULL, 0, ARCHIVE_Z_FINISH);
- if (r < 0)
- return (r);
- header_offset = header_offset + header_size;
- header_size = zip->stream.total_out;
- header_crc32 = zip->encoded_crc32;
- }
- zip->crc32flg = 0;
- } else {
- header_offset = header_size = 0;
- header_crc32 = 0;
- }
-
- length = zip->temp_offset;
-
- /*
- * Make the zip header on wbuff(write buffer).
- */
- wb = zip->wbuff;
- zip->wbuff_remaining = sizeof(zip->wbuff);
- memcpy(&wb[0], "7z\xBC\xAF\x27\x1C", 6);
- wb[6] = 0;/* Major version. */
- wb[7] = 3;/* Minor version. */
- archive_le64enc(&wb[12], header_offset);/* Next Header Offset */
- archive_le64enc(&wb[20], header_size);/* Next Header Size */
- archive_le32enc(&wb[28], header_crc32);/* Next Header CRC */
- archive_le32enc(&wb[8], crc32(0, &wb[12], 20));/* Start Header CRC */
- zip->wbuff_remaining -= 32;
-
- /*
- * Read all file contents and an encoded header from the temporary
- * file and write out it.
- */
- r = copy_out(a, 0, length);
- if (r != ARCHIVE_OK)
- return (r);
- r = flush_wbuff(a);
- return (r);
-}
-
-/*
- * Encode 64 bits value into 7-Zip's encoded UINT64 value.
- */
-static int
-enc_uint64(struct archive_write *a, uint64_t val)
-{
- unsigned mask = 0x80;
- uint8_t numdata[9];
- int i;
-
- numdata[0] = 0;
- for (i = 1; i < (int)sizeof(numdata); i++) {
- if (val < mask) {
- numdata[0] |= (uint8_t)val;
- break;
- }
- numdata[i] = (uint8_t)val;
- val >>= 8;
- numdata[0] |= mask;
- mask >>= 1;
- }
- return ((int)compress_out(a, numdata, i, ARCHIVE_Z_RUN));
-}
-
-static int
-make_substreamsInfo(struct archive_write *a, struct coder *coders)
-{
- struct _7zip *zip = (struct _7zip *)a->format_data;
- struct file *file;
- int r;
-
- /*
- * Make SubStreamsInfo.
- */
- r = enc_uint64(a, kSubStreamsInfo);
- if (r < 0)
- return (r);
-
- if (zip->total_number_nonempty_entry > 1 && coders->codec != _7Z_COPY) {
- /*
- * Make NumUnPackStream.
- */
- r = enc_uint64(a, kNumUnPackStream);
- if (r < 0)
- return (r);
-
- /* Write numUnpackStreams */
- r = enc_uint64(a, zip->total_number_nonempty_entry);
- if (r < 0)
- return (r);
-
- /*
- * Make kSize.
- */
- r = enc_uint64(a, kSize);
- if (r < 0)
- return (r);
- file = zip->file_list.first;
- for (;file != NULL; file = file->next) {
- if (file->next == NULL ||
- file->next->size == 0)
- break;
- r = enc_uint64(a, file->size);
- if (r < 0)
- return (r);
- }
- }
-
- /*
- * Make CRC.
- */
- r = enc_uint64(a, kCRC);
- if (r < 0)
- return (r);
-
-
- /* All are defined */
- r = enc_uint64(a, 1);
- if (r < 0)
- return (r);
- file = zip->file_list.first;
- for (;file != NULL; file = file->next) {
- uint8_t crc[4];
- if (file->size == 0)
- break;
- archive_le32enc(crc, file->crc32);
- r = (int)compress_out(a, crc, 4, ARCHIVE_Z_RUN);
- if (r < 0)
- return (r);
- }
-
- /* Write End. */
- r = enc_uint64(a, kEnd);
- if (r < 0)
- return (r);
- return (ARCHIVE_OK);
-}
-
-static int
-make_streamsInfo(struct archive_write *a, uint64_t offset, uint64_t pack_size,
- uint64_t unpack_size, int num_coder, struct coder *coders, int substrm,
- uint32_t header_crc)
-{
- struct _7zip *zip = (struct _7zip *)a->format_data;
- uint8_t codec_buff[8];
- int numFolders, fi;
- int codec_size;
- int i, r;
-
- if (coders->codec == _7Z_COPY)
- numFolders = (int)zip->total_number_nonempty_entry;
- else
- numFolders = 1;
-
- /*
- * Make PackInfo.
- */
- r = enc_uint64(a, kPackInfo);
- if (r < 0)
- return (r);
-
- /* Write PackPos. */
- r = enc_uint64(a, offset);
- if (r < 0)
- return (r);
-
- /* Write NumPackStreams. */
- r = enc_uint64(a, numFolders);
- if (r < 0)
- return (r);
-
- /* Make Size. */
- r = enc_uint64(a, kSize);
- if (r < 0)
- return (r);
-
- if (numFolders > 1) {
- struct file *file = zip->file_list.first;
- for (;file != NULL; file = file->next) {
- if (file->size == 0)
- break;
- r = enc_uint64(a, file->size);
- if (r < 0)
- return (r);
- }
- } else {
- /* Write size. */
- r = enc_uint64(a, pack_size);
- if (r < 0)
- return (r);
- }
-
- r = enc_uint64(a, kEnd);
- if (r < 0)
- return (r);
-
- /*
- * Make UnPackInfo.
- */
- r = enc_uint64(a, kUnPackInfo);
- if (r < 0)
- return (r);
-
- /*
- * Make Folder.
- */
- r = enc_uint64(a, kFolder);
- if (r < 0)
- return (r);
-
- /* Write NumFolders. */
- r = enc_uint64(a, numFolders);
- if (r < 0)
- return (r);
-
- /* Write External. */
- r = enc_uint64(a, 0);
- if (r < 0)
- return (r);
-
- for (fi = 0; fi < numFolders; fi++) {
- /* Write NumCoders. */
- r = enc_uint64(a, num_coder);
- if (r < 0)
- return (r);
-
- for (i = 0; i < num_coder; i++) {
- unsigned codec_id = coders[i].codec;
-
- /* Write Codec flag. */
- archive_be64enc(codec_buff, codec_id);
- for (codec_size = 8; codec_size > 0; codec_size--) {
- if (codec_buff[8 - codec_size])
- break;
- }
- if (codec_size == 0)
- codec_size = 1;
- if (coders[i].prop_size)
- r = enc_uint64(a, codec_size | 0x20);
- else
- r = enc_uint64(a, codec_size);
- if (r < 0)
- return (r);
-
- /* Write Codec ID. */
- codec_size &= 0x0f;
- r = (int)compress_out(a, &codec_buff[8-codec_size],
- codec_size, ARCHIVE_Z_RUN);
- if (r < 0)
- return (r);
-
- if (coders[i].prop_size) {
- /* Write Codec property size. */
- r = enc_uint64(a, coders[i].prop_size);
- if (r < 0)
- return (r);
-
- /* Write Codec properties. */
- r = (int)compress_out(a, coders[i].props,
- coders[i].prop_size, ARCHIVE_Z_RUN);
- if (r < 0)
- return (r);
- }
- }
- }
-
- /*
- * Make CodersUnPackSize.
- */
- r = enc_uint64(a, kCodersUnPackSize);
- if (r < 0)
- return (r);
-
- if (numFolders > 1) {
- struct file *file = zip->file_list.first;
- for (;file != NULL; file = file->next) {
- if (file->size == 0)
- break;
- r = enc_uint64(a, file->size);
- if (r < 0)
- return (r);
- }
-
- } else {
- /* Write UnPackSize. */
- r = enc_uint64(a, unpack_size);
- if (r < 0)
- return (r);
- }
-
- if (!substrm) {
- uint8_t crc[4];
- /*
- * Make CRC.
- */
- r = enc_uint64(a, kCRC);
- if (r < 0)
- return (r);
-
- /* All are defined */
- r = enc_uint64(a, 1);
- if (r < 0)
- return (r);
- archive_le32enc(crc, header_crc);
- r = (int)compress_out(a, crc, 4, ARCHIVE_Z_RUN);
- if (r < 0)
- return (r);
- }
-
- /* Write End. */
- r = enc_uint64(a, kEnd);
- if (r < 0)
- return (r);
-
- if (substrm) {
- /*
- * Make SubStreamsInfo.
- */
- r = make_substreamsInfo(a, coders);
- if (r < 0)
- return (r);
- }
-
-
- /* Write End. */
- r = enc_uint64(a, kEnd);
- if (r < 0)
- return (r);
-
- return (ARCHIVE_OK);
-}
-
-
-#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
-static uint64_t
-utcToFiletime(time_t t, long ns)
-{
- uint64_t fileTime;
-
- fileTime = t;
- fileTime *= 10000000;
- fileTime += ns / 100;
- fileTime += EPOC_TIME;
- return (fileTime);
-}
-
-static int
-make_time(struct archive_write *a, uint8_t type, unsigned flg, int ti)
-{
- uint8_t filetime[8];
- struct _7zip *zip = (struct _7zip *)a->format_data;
- struct file *file;
- int r;
- uint8_t b, mask;
-
- /*
- * Make Time Bools.
- */
- if (zip->total_number_time_defined[ti] == zip->total_number_entry) {
- /* Write Time Type. */
- r = enc_uint64(a, type);
- if (r < 0)
- return (r);
- /* Write EmptyStream Size. */
- r = enc_uint64(a, 2 + zip->total_number_entry * 8);
- if (r < 0)
- return (r);
- /* All are defined. */
- r = enc_uint64(a, 1);
- if (r < 0)
- return (r);
- } else {
- if (zip->total_number_time_defined[ti] == 0)
- return (ARCHIVE_OK);
-
- /* Write Time Type. */
- r = enc_uint64(a, type);
- if (r < 0)
- return (r);
- /* Write EmptyStream Size. */
- r = enc_uint64(a, 2 + ((zip->total_number_entry + 7) >> 3)
- + zip->total_number_time_defined[ti] * 8);
- if (r < 0)
- return (r);
-
- /* All are not defined. */
- r = enc_uint64(a, 0);
- if (r < 0)
- return (r);
-
- b = 0;
- mask = 0x80;
- file = zip->file_list.first;
- for (;file != NULL; file = file->next) {
- if (file->flg & flg)
- b |= mask;
- mask >>= 1;
- if (mask == 0) {
- r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
- if (r < 0)
- return (r);
- mask = 0x80;
- b = 0;
- }
- }
- if (mask != 0x80) {
- r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
- if (r < 0)
- return (r);
- }
- }
-
- /* External. */
- r = enc_uint64(a, 0);
- if (r < 0)
- return (r);
-
-
- /*
- * Make Times.
- */
- file = zip->file_list.first;
- for (;file != NULL; file = file->next) {
- if ((file->flg & flg) == 0)
- continue;
- archive_le64enc(filetime, utcToFiletime(file->times[ti].time,
- file->times[ti].time_ns));
- r = (int)compress_out(a, filetime, 8, ARCHIVE_Z_RUN);
- if (r < 0)
- return (r);
- }
-
- return (ARCHIVE_OK);
-}
-
-static int
-make_header(struct archive_write *a, uint64_t offset, uint64_t pack_size,
- uint64_t unpack_size, int codernum, struct coder *coders)
-{
- struct _7zip *zip = (struct _7zip *)a->format_data;
- struct file *file;
- int r;
- uint8_t b, mask;
-
- /*
- * Make FilesInfo.
- */
- r = enc_uint64(a, kHeader);
- if (r < 0)
- return (r);
-
- /*
- * If there are empty files only, do not write MainStreamInfo.
- */
- if (zip->total_number_nonempty_entry) {
- /*
- * Make MainStreamInfo.
- */
- r = enc_uint64(a, kMainStreamsInfo);
- if (r < 0)
- return (r);
- r = make_streamsInfo(a, offset, pack_size, unpack_size,
- codernum, coders, 1, 0);
- if (r < 0)
- return (r);
- }
-
- /*
- * Make FilesInfo.
- */
- r = enc_uint64(a, kFilesInfo);
- if (r < 0)
- return (r);
-
- /* Write numFiles. */
- r = enc_uint64(a, zip->total_number_entry);
- if (r < 0)
- return (r);
-
- if (zip->total_number_empty_entry > 0) {
- /* Make EmptyStream. */
- r = enc_uint64(a, kEmptyStream);
- if (r < 0)
- return (r);
-
- /* Write EmptyStream Size. */
- r = enc_uint64(a, (zip->total_number_entry+7)>>3);
- if (r < 0)
- return (r);
-
- b = 0;
- mask = 0x80;
- file = zip->file_list.first;
- for (;file != NULL; file = file->next) {
- if (file->size == 0)
- b |= mask;
- mask >>= 1;
- if (mask == 0) {
- r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
- if (r < 0)
- return (r);
- mask = 0x80;
- b = 0;
- }
- }
- if (mask != 0x80) {
- r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
- if (r < 0)
- return (r);
- }
- }
-
- if (zip->total_number_empty_entry > zip->total_number_dir_entry) {
- /* Make EmptyFile. */
- r = enc_uint64(a, kEmptyFile);
- if (r < 0)
- return (r);
-
- /* Write EmptyFile Size. */
- r = enc_uint64(a, (zip->total_number_empty_entry + 7) >> 3);
- if (r < 0)
- return (r);
-
- b = 0;
- mask = 0x80;
- file = zip->file_list.first;
- for (;file != NULL; file = file->next) {
- if (file->size)
- continue;
- if (!file->dir)
- b |= mask;
- mask >>= 1;
- if (mask == 0) {
- r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
- if (r < 0)
- return (r);
- mask = 0x80;
- b = 0;
- }
- }
- if (mask != 0x80) {
- r = (int)compress_out(a, &b, 1, ARCHIVE_Z_RUN);
- if (r < 0)
- return (r);
- }
- }
-
- /* Make Name. */
- r = enc_uint64(a, kName);
- if (r < 0)
- return (r);
-
- /* Write Nume size. */
- r = enc_uint64(a, zip->total_bytes_entry_name+1);
- if (r < 0)
- return (r);
-
- /* Write dmy byte. */
- r = enc_uint64(a, 0);
- if (r < 0)
- return (r);
-
- file = zip->file_list.first;
- for (;file != NULL; file = file->next) {
- r = (int)compress_out(a, file->utf16name, file->name_len+2,
- ARCHIVE_Z_RUN);
- if (r < 0)
- return (r);
- }
-
- /* Make MTime. */
- r = make_time(a, kMTime, MTIME_IS_SET, MTIME);
- if (r < 0)
- return (r);
-
- /* Make CTime. */
- r = make_time(a, kCTime, CTIME_IS_SET, CTIME);
- if (r < 0)
- return (r);
-
- /* Make ATime. */
- r = make_time(a, kATime, ATIME_IS_SET, ATIME);
- if (r < 0)
- return (r);
-
- /* Make Attributes. */
- r = enc_uint64(a, kAttributes);
- if (r < 0)
- return (r);
-
- /* Write Attributes size. */
- r = enc_uint64(a, 2 + zip->total_number_entry * 4);
- if (r < 0)
- return (r);
-
- /* Write "All Are Defined". */
- r = enc_uint64(a, 1);
- if (r < 0)
- return (r);
-
- /* Write dmy byte. */
- r = enc_uint64(a, 0);
- if (r < 0)
- return (r);
-
- file = zip->file_list.first;
- for (;file != NULL; file = file->next) {
- /*
- * High 16bits is unix mode.
- * Low 16bits is Windows attributes.
- */
- uint32_t encattr, attr;
- if (file->dir)
- attr = 0x8010;
- else
- attr = 0x8020;
- if ((file->mode & 0222) == 0)
- attr |= 1;/* Read Only. */
- attr |= ((uint32_t)file->mode) << 16;
- archive_le32enc(&encattr, attr);
- r = (int)compress_out(a, &encattr, 4, ARCHIVE_Z_RUN);
- if (r < 0)
- return (r);
- }
-
- /* Write End. */
- r = enc_uint64(a, kEnd);
- if (r < 0)
- return (r);
-
- /* Write End. */
- r = enc_uint64(a, kEnd);
- if (r < 0)
- return (r);
-
- return (ARCHIVE_OK);
-}
-
-
-static int
-_7z_free(struct archive_write *a)
-{
- struct _7zip *zip = (struct _7zip *)a->format_data;
-
- file_free_register(zip);
- compression_end(&(a->archive), &(zip->stream));
- free(zip->coder.props);
- free(zip);
-
- return (ARCHIVE_OK);
-}
-
-static int
-file_cmp_node(const struct archive_rb_node *n1,
- const struct archive_rb_node *n2)
-{
- const struct file *f1 = (const struct file *)n1;
- const struct file *f2 = (const struct file *)n2;
-
- if (f1->name_len == f2->name_len)
- return (memcmp(f1->utf16name, f2->utf16name, f1->name_len));
- return (f1->name_len > f2->name_len)?1:-1;
-}
-
-static int
-file_cmp_key(const struct archive_rb_node *n, const void *key)
-{
- const struct file *f = (const struct file *)n;
-
- return (f->name_len - *(const char *)key);
-}
-
-static int
-file_new(struct archive_write *a, struct archive_entry *entry,
- struct file **newfile)
-{
- struct _7zip *zip;
- struct file *file;
- const char *u16;
- size_t u16len;
- int ret = ARCHIVE_OK;
-
- zip = (struct _7zip *)a->format_data;
- *newfile = NULL;
-
- file = calloc(1, sizeof(*file));
- if (file == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
-
- if (0 > archive_entry_pathname_l(entry, &u16, &u16len, zip->sconv)) {
- if (errno == ENOMEM) {
- free(file);
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for UTF-16LE");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "A filename cannot be converted to UTF-16LE;"
- "You should disable making Joliet extension");
- ret = ARCHIVE_WARN;
- }
- file->utf16name = malloc(u16len + 2);
- if (file->utf16name == NULL) {
- free(file);
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Name");
- return (ARCHIVE_FATAL);
- }
- memcpy(file->utf16name, u16, u16len);
- file->utf16name[u16len+0] = 0;
- file->utf16name[u16len+1] = 0;
- file->name_len = (unsigned)u16len;
- file->mode = archive_entry_mode(entry);
- if (archive_entry_filetype(entry) == AE_IFREG)
- file->size = archive_entry_size(entry);
- else
- archive_entry_set_size(entry, 0);
- if (archive_entry_filetype(entry) == AE_IFDIR)
- file->dir = 1;
- else if (archive_entry_filetype(entry) == AE_IFLNK)
- file->size = strlen(archive_entry_symlink(entry));
- if (archive_entry_mtime_is_set(entry)) {
- file->flg |= MTIME_IS_SET;
- file->times[MTIME].time = archive_entry_mtime(entry);
- file->times[MTIME].time_ns = archive_entry_mtime_nsec(entry);
- }
- if (archive_entry_atime_is_set(entry)) {
- file->flg |= ATIME_IS_SET;
- file->times[ATIME].time = archive_entry_atime(entry);
- file->times[ATIME].time_ns = archive_entry_atime_nsec(entry);
- }
- if (archive_entry_ctime_is_set(entry)) {
- file->flg |= CTIME_IS_SET;
- file->times[CTIME].time = archive_entry_ctime(entry);
- file->times[CTIME].time_ns = archive_entry_ctime_nsec(entry);
- }
-
- *newfile = file;
- return (ret);
-}
-
-static void
-file_free(struct file *file)
-{
- free(file->utf16name);
- free(file);
-}
-
-static void
-file_register(struct _7zip *zip, struct file *file)
-{
- file->next = NULL;
- *zip->file_list.last = file;
- zip->file_list.last = &(file->next);
-}
-
-static void
-file_init_register(struct _7zip *zip)
-{
- zip->file_list.first = NULL;
- zip->file_list.last = &(zip->file_list.first);
-}
-
-static void
-file_free_register(struct _7zip *zip)
-{
- struct file *file, *file_next;
-
- file = zip->file_list.first;
- while (file != NULL) {
- file_next = file->next;
- file_free(file);
- file = file_next;
- }
-}
-
-static void
-file_register_empty(struct _7zip *zip, struct file *file)
-{
- file->next = NULL;
- *zip->empty_list.last = file;
- zip->empty_list.last = &(file->next);
-}
-
-static void
-file_init_register_empty(struct _7zip *zip)
-{
- zip->empty_list.first = NULL;
- zip->empty_list.last = &(zip->empty_list.first);
-}
-
-#if !defined(HAVE_ZLIB_H) || !defined(HAVE_BZLIB_H) ||\
- !defined(BZ_CONFIG_ERROR) || !defined(HAVE_LZMA_H)
-static int
-compression_unsupported_encoder(struct archive *a,
- struct la_zstream *lastrm, const char *name)
-{
-
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "%s compression not supported on this platform", name);
- lastrm->valid = 0;
- lastrm->real_stream = NULL;
- return (ARCHIVE_FAILED);
-}
-#endif
-
-/*
- * _7_COPY compressor.
- */
-static int
-compression_init_encoder_copy(struct archive *a, struct la_zstream *lastrm)
-{
-
- if (lastrm->valid)
- compression_end(a, lastrm);
- lastrm->valid = 1;
- lastrm->code = compression_code_copy;
- lastrm->end = compression_end_copy;
- return (ARCHIVE_OK);
-}
-
-static int
-compression_code_copy(struct archive *a,
- struct la_zstream *lastrm, enum la_zaction action)
-{
- size_t bytes;
-
- (void)a; /* UNUSED */
- if (lastrm->avail_out > lastrm->avail_in)
- bytes = lastrm->avail_in;
- else
- bytes = lastrm->avail_out;
- if (bytes) {
- memcpy(lastrm->next_out, lastrm->next_in, bytes);
- lastrm->next_in += bytes;
- lastrm->avail_in -= bytes;
- lastrm->total_in += bytes;
- lastrm->next_out += bytes;
- lastrm->avail_out -= bytes;
- lastrm->total_out += bytes;
- }
- if (action == ARCHIVE_Z_FINISH && lastrm->avail_in == 0)
- return (ARCHIVE_EOF);
- return (ARCHIVE_OK);
-}
-
-static int
-compression_end_copy(struct archive *a, struct la_zstream *lastrm)
-{
- (void)a; /* UNUSED */
- lastrm->valid = 0;
- return (ARCHIVE_OK);
-}
-
-/*
- * _7_DEFLATE compressor.
- */
-#ifdef HAVE_ZLIB_H
-static int
-compression_init_encoder_deflate(struct archive *a,
- struct la_zstream *lastrm, int level, int withheader)
-{
- z_stream *strm;
-
- if (lastrm->valid)
- compression_end(a, lastrm);
- strm = calloc(1, sizeof(*strm));
- if (strm == NULL) {
- archive_set_error(a, ENOMEM,
- "Can't allocate memory for gzip stream");
- return (ARCHIVE_FATAL);
- }
- /* zlib.h is not const-correct, so we need this one bit
- * of ugly hackery to convert a const * pointer to
- * a non-const pointer. */
- strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
- strm->avail_in = (uInt)lastrm->avail_in;
- strm->total_in = (uLong)lastrm->total_in;
- strm->next_out = lastrm->next_out;
- strm->avail_out = (uInt)lastrm->avail_out;
- strm->total_out = (uLong)lastrm->total_out;
- if (deflateInit2(strm, level, Z_DEFLATED,
- (withheader)?15:-15,
- 8, Z_DEFAULT_STRATEGY) != Z_OK) {
- free(strm);
- lastrm->real_stream = NULL;
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library");
- return (ARCHIVE_FATAL);
- }
- lastrm->real_stream = strm;
- lastrm->valid = 1;
- lastrm->code = compression_code_deflate;
- lastrm->end = compression_end_deflate;
- return (ARCHIVE_OK);
-}
-
-static int
-compression_code_deflate(struct archive *a,
- struct la_zstream *lastrm, enum la_zaction action)
-{
- z_stream *strm;
- int r;
-
- strm = (z_stream *)lastrm->real_stream;
- /* zlib.h is not const-correct, so we need this one bit
- * of ugly hackery to convert a const * pointer to
- * a non-const pointer. */
- strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
- strm->avail_in = (uInt)lastrm->avail_in;
- strm->total_in = (uLong)lastrm->total_in;
- strm->next_out = lastrm->next_out;
- strm->avail_out = (uInt)lastrm->avail_out;
- strm->total_out = (uLong)lastrm->total_out;
- r = deflate(strm,
- (action == ARCHIVE_Z_FINISH)? Z_FINISH: Z_NO_FLUSH);
- lastrm->next_in = strm->next_in;
- lastrm->avail_in = strm->avail_in;
- lastrm->total_in = strm->total_in;
- lastrm->next_out = strm->next_out;
- lastrm->avail_out = strm->avail_out;
- lastrm->total_out = strm->total_out;
- switch (r) {
- case Z_OK:
- return (ARCHIVE_OK);
- case Z_STREAM_END:
- return (ARCHIVE_EOF);
- default:
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "GZip compression failed:"
- " deflate() call returned status %d", r);
- return (ARCHIVE_FATAL);
- }
-}
-
-static int
-compression_end_deflate(struct archive *a, struct la_zstream *lastrm)
-{
- z_stream *strm;
- int r;
-
- strm = (z_stream *)lastrm->real_stream;
- r = deflateEnd(strm);
- free(strm);
- lastrm->real_stream = NULL;
- lastrm->valid = 0;
- if (r != Z_OK) {
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "Failed to clean up compressor");
- return (ARCHIVE_FATAL);
- }
- return (ARCHIVE_OK);
-}
-#else
-static int
-compression_init_encoder_deflate(struct archive *a,
- struct la_zstream *lastrm, int level, int withheader)
-{
-
- (void) level; /* UNUSED */
- (void) withheader; /* UNUSED */
- if (lastrm->valid)
- compression_end(a, lastrm);
- return (compression_unsupported_encoder(a, lastrm, "deflate"));
-}
-#endif
-
-/*
- * _7_BZIP2 compressor.
- */
-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
-static int
-compression_init_encoder_bzip2(struct archive *a,
- struct la_zstream *lastrm, int level)
-{
- bz_stream *strm;
-
- if (lastrm->valid)
- compression_end(a, lastrm);
- strm = calloc(1, sizeof(*strm));
- if (strm == NULL) {
- archive_set_error(a, ENOMEM,
- "Can't allocate memory for bzip2 stream");
- return (ARCHIVE_FATAL);
- }
- /* bzlib.h is not const-correct, so we need this one bit
- * of ugly hackery to convert a const * pointer to
- * a non-const pointer. */
- strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
- strm->avail_in = lastrm->avail_in;
- strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
- strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
- strm->next_out = (char *)lastrm->next_out;
- strm->avail_out = lastrm->avail_out;
- strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
- strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
- if (BZ2_bzCompressInit(strm, level, 0, 30) != BZ_OK) {
- free(strm);
- lastrm->real_stream = NULL;
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library");
- return (ARCHIVE_FATAL);
- }
- lastrm->real_stream = strm;
- lastrm->valid = 1;
- lastrm->code = compression_code_bzip2;
- lastrm->end = compression_end_bzip2;
- return (ARCHIVE_OK);
-}
-
-static int
-compression_code_bzip2(struct archive *a,
- struct la_zstream *lastrm, enum la_zaction action)
-{
- bz_stream *strm;
- int r;
-
- strm = (bz_stream *)lastrm->real_stream;
- /* bzlib.h is not const-correct, so we need this one bit
- * of ugly hackery to convert a const * pointer to
- * a non-const pointer. */
- strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
- strm->avail_in = lastrm->avail_in;
- strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
- strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
- strm->next_out = (char *)lastrm->next_out;
- strm->avail_out = lastrm->avail_out;
- strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
- strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
- r = BZ2_bzCompress(strm,
- (action == ARCHIVE_Z_FINISH)? BZ_FINISH: BZ_RUN);
- lastrm->next_in = (const unsigned char *)strm->next_in;
- lastrm->avail_in = strm->avail_in;
- lastrm->total_in =
- (((uint64_t)(uint32_t)strm->total_in_hi32) << 32)
- + (uint64_t)(uint32_t)strm->total_in_lo32;
- lastrm->next_out = (unsigned char *)strm->next_out;
- lastrm->avail_out = strm->avail_out;
- lastrm->total_out =
- (((uint64_t)(uint32_t)strm->total_out_hi32) << 32)
- + (uint64_t)(uint32_t)strm->total_out_lo32;
- switch (r) {
- case BZ_RUN_OK: /* Non-finishing */
- case BZ_FINISH_OK: /* Finishing: There's more work to do */
- return (ARCHIVE_OK);
- case BZ_STREAM_END: /* Finishing: all done */
- /* Only occurs in finishing case */
- return (ARCHIVE_EOF);
- default:
- /* Any other return value indicates an error */
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "Bzip2 compression failed:"
- " BZ2_bzCompress() call returned status %d", r);
- return (ARCHIVE_FATAL);
- }
-}
-
-static int
-compression_end_bzip2(struct archive *a, struct la_zstream *lastrm)
-{
- bz_stream *strm;
- int r;
-
- strm = (bz_stream *)lastrm->real_stream;
- r = BZ2_bzCompressEnd(strm);
- free(strm);
- lastrm->real_stream = NULL;
- lastrm->valid = 0;
- if (r != BZ_OK) {
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "Failed to clean up compressor");
- return (ARCHIVE_FATAL);
- }
- return (ARCHIVE_OK);
-}
-
-#else
-static int
-compression_init_encoder_bzip2(struct archive *a,
- struct la_zstream *lastrm, int level)
-{
-
- (void) level; /* UNUSED */
- if (lastrm->valid)
- compression_end(a, lastrm);
- return (compression_unsupported_encoder(a, lastrm, "bzip2"));
-}
-#endif
-
-/*
- * _7_LZMA1, _7_LZMA2 compressor.
- */
-#if defined(HAVE_LZMA_H)
-static int
-compression_init_encoder_lzma(struct archive *a,
- struct la_zstream *lastrm, int level, uint64_t filter_id)
-{
- static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;
- lzma_stream *strm;
- lzma_filter *lzmafilters;
- lzma_options_lzma lzma_opt;
- int r;
-
- if (lastrm->valid)
- compression_end(a, lastrm);
- strm = calloc(1, sizeof(*strm) + sizeof(*lzmafilters) * 2);
- if (strm == NULL) {
- archive_set_error(a, ENOMEM,
- "Can't allocate memory for lzma stream");
- return (ARCHIVE_FATAL);
- }
- lzmafilters = (lzma_filter *)(strm+1);
- if (level > 6)
- level = 6;
- if (lzma_lzma_preset(&lzma_opt, level)) {
- free(strm);
- lastrm->real_stream = NULL;
- archive_set_error(a, ENOMEM,
- "Internal error initializing compression library");
- return (ARCHIVE_FATAL);
- }
- lzmafilters[0].id = filter_id;
- lzmafilters[0].options = &lzma_opt;
- lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
-
- r = lzma_properties_size(&(lastrm->prop_size), lzmafilters);
- if (r != LZMA_OK) {
- free(strm);
- lastrm->real_stream = NULL;
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "lzma_properties_size failed");
- return (ARCHIVE_FATAL);
- }
- if (lastrm->prop_size) {
- lastrm->props = malloc(lastrm->prop_size);
- if (lastrm->props == NULL) {
- free(strm);
- lastrm->real_stream = NULL;
- archive_set_error(a, ENOMEM,
- "Cannot allocate memory");
- return (ARCHIVE_FATAL);
- }
- r = lzma_properties_encode(lzmafilters, lastrm->props);
- if (r != LZMA_OK) {
- free(strm);
- lastrm->real_stream = NULL;
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "lzma_properties_encode failed");
- return (ARCHIVE_FATAL);
- }
- }
-
- *strm = lzma_init_data;
- r = lzma_raw_encoder(strm, lzmafilters);
- switch (r) {
- case LZMA_OK:
- lastrm->real_stream = strm;
- lastrm->valid = 1;
- lastrm->code = compression_code_lzma;
- lastrm->end = compression_end_lzma;
- r = ARCHIVE_OK;
- break;
- case LZMA_MEM_ERROR:
- free(strm);
- lastrm->real_stream = NULL;
- archive_set_error(a, ENOMEM,
- "Internal error initializing compression library: "
- "Cannot allocate memory");
- r = ARCHIVE_FATAL;
- break;
- default:
- free(strm);
- lastrm->real_stream = NULL;
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library: "
- "It's a bug in liblzma");
- r = ARCHIVE_FATAL;
- break;
- }
- return (r);
-}
-
-static int
-compression_init_encoder_lzma1(struct archive *a,
- struct la_zstream *lastrm, int level)
-{
- return compression_init_encoder_lzma(a, lastrm, level,
- LZMA_FILTER_LZMA1);
-}
-
-static int
-compression_init_encoder_lzma2(struct archive *a,
- struct la_zstream *lastrm, int level)
-{
- return compression_init_encoder_lzma(a, lastrm, level,
- LZMA_FILTER_LZMA2);
-}
-
-static int
-compression_code_lzma(struct archive *a,
- struct la_zstream *lastrm, enum la_zaction action)
-{
- lzma_stream *strm;
- int r;
-
- strm = (lzma_stream *)lastrm->real_stream;
- strm->next_in = lastrm->next_in;
- strm->avail_in = lastrm->avail_in;
- strm->total_in = lastrm->total_in;
- strm->next_out = lastrm->next_out;
- strm->avail_out = lastrm->avail_out;
- strm->total_out = lastrm->total_out;
- r = lzma_code(strm,
- (action == ARCHIVE_Z_FINISH)? LZMA_FINISH: LZMA_RUN);
- lastrm->next_in = strm->next_in;
- lastrm->avail_in = strm->avail_in;
- lastrm->total_in = strm->total_in;
- lastrm->next_out = strm->next_out;
- lastrm->avail_out = strm->avail_out;
- lastrm->total_out = strm->total_out;
- switch (r) {
- case LZMA_OK:
- /* Non-finishing case */
- return (ARCHIVE_OK);
- case LZMA_STREAM_END:
- /* This return can only occur in finishing case. */
- return (ARCHIVE_EOF);
- case LZMA_MEMLIMIT_ERROR:
- archive_set_error(a, ENOMEM,
- "lzma compression error:"
- " %ju MiB would have been needed",
- (uintmax_t)((lzma_memusage(strm) + 1024 * 1024 -1)
- / (1024 * 1024)));
- return (ARCHIVE_FATAL);
- default:
- /* Any other return value indicates an error */
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "lzma compression failed:"
- " lzma_code() call returned status %d", r);
- return (ARCHIVE_FATAL);
- }
-}
-
-static int
-compression_end_lzma(struct archive *a, struct la_zstream *lastrm)
-{
- lzma_stream *strm;
-
- (void)a; /* UNUSED */
- strm = (lzma_stream *)lastrm->real_stream;
- lzma_end(strm);
- free(strm);
- lastrm->valid = 0;
- lastrm->real_stream = NULL;
- return (ARCHIVE_OK);
-}
-#else
-static int
-compression_init_encoder_lzma1(struct archive *a,
- struct la_zstream *lastrm, int level)
-{
-
- (void) level; /* UNUSED */
- if (lastrm->valid)
- compression_end(a, lastrm);
- return (compression_unsupported_encoder(a, lastrm, "lzma"));
-}
-static int
-compression_init_encoder_lzma2(struct archive *a,
- struct la_zstream *lastrm, int level)
-{
-
- (void) level; /* UNUSED */
- if (lastrm->valid)
- compression_end(a, lastrm);
- return (compression_unsupported_encoder(a, lastrm, "lzma"));
-}
-#endif
-
-/*
- * _7_PPMD compressor.
- */
-static void *
-ppmd_alloc(void *p, size_t size)
-{
- (void)p;
- return malloc(size);
-}
-static void
-ppmd_free(void *p, void *address)
-{
- (void)p;
- free(address);
-}
-static ISzAlloc g_szalloc = { ppmd_alloc, ppmd_free };
-static void
-ppmd_write(void *p, Byte b)
-{
- struct archive_write *a = ((IByteOut *)p)->a;
- struct _7zip *zip = (struct _7zip *)(a->format_data);
- struct la_zstream *lastrm = &(zip->stream);
- struct ppmd_stream *strm;
-
- if (lastrm->avail_out) {
- *lastrm->next_out++ = b;
- lastrm->avail_out--;
- lastrm->total_out++;
- return;
- }
- strm = (struct ppmd_stream *)lastrm->real_stream;
- if (strm->buff_ptr < strm->buff_end) {
- *strm->buff_ptr++ = b;
- strm->buff_bytes++;
- }
-}
-
-static int
-compression_init_encoder_ppmd(struct archive *a,
- struct la_zstream *lastrm, unsigned maxOrder, uint32_t msize)
-{
- struct ppmd_stream *strm;
- uint8_t *props;
- int r;
-
- if (lastrm->valid)
- compression_end(a, lastrm);
- strm = calloc(1, sizeof(*strm));
- if (strm == NULL) {
- archive_set_error(a, ENOMEM,
- "Can't allocate memory for PPMd");
- return (ARCHIVE_FATAL);
- }
- strm->buff = malloc(32);
- if (strm->buff == NULL) {
- free(strm);
- archive_set_error(a, ENOMEM,
- "Can't allocate memory for PPMd");
- return (ARCHIVE_FATAL);
- }
- strm->buff_ptr = strm->buff;
- strm->buff_end = strm->buff + 32;
-
- props = malloc(1+4);
- if (props == NULL) {
- free(strm->buff);
- free(strm);
- archive_set_error(a, ENOMEM,
- "Coludn't allocate memory for PPMd");
- return (ARCHIVE_FATAL);
- }
- props[0] = maxOrder;
- archive_le32enc(props+1, msize);
- __archive_ppmd7_functions.Ppmd7_Construct(&strm->ppmd7_context);
- r = __archive_ppmd7_functions.Ppmd7_Alloc(
- &strm->ppmd7_context, msize, &g_szalloc);
- if (r == 0) {
- free(strm->buff);
- free(strm);
- free(props);
- archive_set_error(a, ENOMEM,
- "Coludn't allocate memory for PPMd");
- return (ARCHIVE_FATAL);
- }
- __archive_ppmd7_functions.Ppmd7_Init(&(strm->ppmd7_context), maxOrder);
- strm->byteout.a = (struct archive_write *)a;
- strm->byteout.Write = ppmd_write;
- strm->range_enc.Stream = &(strm->byteout);
- __archive_ppmd7_functions.Ppmd7z_RangeEnc_Init(&(strm->range_enc));
- strm->stat = 0;
-
- lastrm->real_stream = strm;
- lastrm->valid = 1;
- lastrm->code = compression_code_ppmd;
- lastrm->end = compression_end_ppmd;
- lastrm->prop_size = 5;
- lastrm->props = props;
- return (ARCHIVE_OK);
-}
-
-static int
-compression_code_ppmd(struct archive *a,
- struct la_zstream *lastrm, enum la_zaction action)
-{
- struct ppmd_stream *strm;
-
- (void)a; /* UNUSED */
-
- strm = (struct ppmd_stream *)lastrm->real_stream;
-
- /* Copy encoded data if there are remaining bytes from previous call. */
- if (strm->buff_bytes) {
- uint8_t *p = strm->buff_ptr - strm->buff_bytes;
- while (lastrm->avail_out && strm->buff_bytes) {
- *lastrm->next_out++ = *p++;
- lastrm->avail_out--;
- lastrm->total_out++;
- strm->buff_bytes--;
- }
- if (strm->buff_bytes)
- return (ARCHIVE_OK);
- if (strm->stat == 1)
- return (ARCHIVE_EOF);
- strm->buff_ptr = strm->buff;
- }
- while (lastrm->avail_in && lastrm->avail_out) {
- __archive_ppmd7_functions.Ppmd7_EncodeSymbol(
- &(strm->ppmd7_context), &(strm->range_enc),
- *lastrm->next_in++);
- lastrm->avail_in--;
- lastrm->total_in++;
- }
- if (lastrm->avail_in == 0 && action == ARCHIVE_Z_FINISH) {
- __archive_ppmd7_functions.Ppmd7z_RangeEnc_FlushData(
- &(strm->range_enc));
- strm->stat = 1;
- /* Return EOF if there are no remaining bytes. */
- if (strm->buff_bytes == 0)
- return (ARCHIVE_EOF);
- }
- return (ARCHIVE_OK);
-}
-
-static int
-compression_end_ppmd(struct archive *a, struct la_zstream *lastrm)
-{
- struct ppmd_stream *strm;
-
- (void)a; /* UNUSED */
-
- strm = (struct ppmd_stream *)lastrm->real_stream;
- __archive_ppmd7_functions.Ppmd7_Free(&strm->ppmd7_context, &g_szalloc);
- free(strm->buff);
- free(strm);
- lastrm->real_stream = NULL;
- lastrm->valid = 0;
- return (ARCHIVE_OK);
-}
-
-/*
- * Universal compressor initializer.
- */
-static int
-_7z_compression_init_encoder(struct archive_write *a, unsigned compression,
- int compression_level)
-{
- struct _7zip *zip;
- int r;
-
- zip = (struct _7zip *)a->format_data;
- switch (compression) {
- case _7Z_DEFLATE:
- r = compression_init_encoder_deflate(
- &(a->archive), &(zip->stream),
- compression_level, 0);
- break;
- case _7Z_BZIP2:
- r = compression_init_encoder_bzip2(
- &(a->archive), &(zip->stream),
- compression_level);
- break;
- case _7Z_LZMA1:
- r = compression_init_encoder_lzma1(
- &(a->archive), &(zip->stream),
- compression_level);
- break;
- case _7Z_LZMA2:
- r = compression_init_encoder_lzma2(
- &(a->archive), &(zip->stream),
- compression_level);
- break;
- case _7Z_PPMD:
- r = compression_init_encoder_ppmd(
- &(a->archive), &(zip->stream),
- PPMD7_DEFAULT_ORDER, PPMD7_DEFAULT_MEM_SIZE);
- break;
- case _7Z_COPY:
- default:
- r = compression_init_encoder_copy(
- &(a->archive), &(zip->stream));
- break;
- }
- if (r == ARCHIVE_OK) {
- zip->stream.total_in = 0;
- zip->stream.next_out = zip->wbuff;
- zip->stream.avail_out = sizeof(zip->wbuff);
- zip->stream.total_out = 0;
- }
-
- return (r);
-}
-
-static int
-compression_code(struct archive *a, struct la_zstream *lastrm,
- enum la_zaction action)
-{
- if (lastrm->valid)
- return (lastrm->code(a, lastrm, action));
- return (ARCHIVE_OK);
-}
-
-static int
-compression_end(struct archive *a, struct la_zstream *lastrm)
-{
- if (lastrm->valid) {
- lastrm->prop_size = 0;
- free(lastrm->props);
- lastrm->props = NULL;
- return (lastrm->end(a, lastrm));
- }
- return (ARCHIVE_OK);
-}
-
-
diff --git a/3rdparty/libarchive/libarchive/archive_write_set_format_ar.c b/3rdparty/libarchive/libarchive/archive_write_set_format_ar.c
deleted file mode 100644
index 9f17564c..00000000
--- a/3rdparty/libarchive/libarchive/archive_write_set_format_ar.c
+++ /dev/null
@@ -1,564 +0,0 @@
-/*-
- * Copyright (c) 2007 Kai Wang
- * Copyright (c) 2007 Tim Kientzle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer
- * in this position and unchanged.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "archive_platform.h"
-__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_ar.c 201108 2009-12-28 03:28:21Z kientzle $");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#include "archive.h"
-#include "archive_entry.h"
-#include "archive_private.h"
-#include "archive_write_private.h"
-
-struct ar_w {
- uint64_t entry_bytes_remaining;
- uint64_t entry_padding;
- int is_strtab;
- int has_strtab;
- char wrote_global_header;
- char *strtab;
-};
-
-/*
- * Define structure of the "ar" header.
- */
-#define AR_name_offset 0
-#define AR_name_size 16
-#define AR_date_offset 16
-#define AR_date_size 12
-#define AR_uid_offset 28
-#define AR_uid_size 6
-#define AR_gid_offset 34
-#define AR_gid_size 6
-#define AR_mode_offset 40
-#define AR_mode_size 8
-#define AR_size_offset 48
-#define AR_size_size 10
-#define AR_fmag_offset 58
-#define AR_fmag_size 2
-
-static int archive_write_set_format_ar(struct archive_write *);
-static int archive_write_ar_header(struct archive_write *,
- struct archive_entry *);
-static ssize_t archive_write_ar_data(struct archive_write *,
- const void *buff, size_t s);
-static int archive_write_ar_free(struct archive_write *);
-static int archive_write_ar_close(struct archive_write *);
-static int archive_write_ar_finish_entry(struct archive_write *);
-static const char *ar_basename(const char *path);
-static int format_octal(int64_t v, char *p, int s);
-static int format_decimal(int64_t v, char *p, int s);
-
-int
-archive_write_set_format_ar_bsd(struct archive *_a)
-{
- struct archive_write *a = (struct archive_write *)_a;
- int r;
-
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_set_format_ar_bsd");
- r = archive_write_set_format_ar(a);
- if (r == ARCHIVE_OK) {
- a->archive.archive_format = ARCHIVE_FORMAT_AR_BSD;
- a->archive.archive_format_name = "ar (BSD)";
- }
- return (r);
-}
-
-int
-archive_write_set_format_ar_svr4(struct archive *_a)
-{
- struct archive_write *a = (struct archive_write *)_a;
- int r;
-
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_set_format_ar_svr4");
- r = archive_write_set_format_ar(a);
- if (r == ARCHIVE_OK) {
- a->archive.archive_format = ARCHIVE_FORMAT_AR_GNU;
- a->archive.archive_format_name = "ar (GNU/SVR4)";
- }
- return (r);
-}
-
-/*
- * Generic initialization.
- */
-static int
-archive_write_set_format_ar(struct archive_write *a)
-{
- struct ar_w *ar;
-
- /* If someone else was already registered, unregister them. */
- if (a->format_free != NULL)
- (a->format_free)(a);
-
- ar = (struct ar_w *)malloc(sizeof(*ar));
- if (ar == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Can't allocate ar data");
- return (ARCHIVE_FATAL);
- }
- memset(ar, 0, sizeof(*ar));
- a->format_data = ar;
-
- a->format_name = "ar";
- a->format_write_header = archive_write_ar_header;
- a->format_write_data = archive_write_ar_data;
- a->format_close = archive_write_ar_close;
- a->format_free = archive_write_ar_free;
- a->format_finish_entry = archive_write_ar_finish_entry;
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
-{
- int ret, append_fn;
- char buff[60];
- char *ss, *se;
- struct ar_w *ar;
- const char *pathname;
- const char *filename;
- int64_t size;
-
- append_fn = 0;
- ar = (struct ar_w *)a->format_data;
- ar->is_strtab = 0;
- filename = NULL;
- size = archive_entry_size(entry);
-
-
- /*
- * Reject files with empty name.
- */
- pathname = archive_entry_pathname(entry);
- if (pathname == NULL || *pathname == '\0') {
- archive_set_error(&a->archive, EINVAL,
- "Invalid filename");
- return (ARCHIVE_WARN);
- }
-
- /*
- * If we are now at the beginning of the archive,
- * we need first write the ar global header.
- */
- if (!ar->wrote_global_header) {
- __archive_write_output(a, "!<arch>\n", 8);
- ar->wrote_global_header = 1;
- }
-
- memset(buff, ' ', 60);
- strncpy(&buff[AR_fmag_offset], "`\n", 2);
-
- if (strcmp(pathname, "/") == 0 ) {
- /* Entry is archive symbol table in GNU format */
- buff[AR_name_offset] = '/';
- goto stat;
- }
- if (strcmp(pathname, "__.SYMDEF") == 0) {
- /* Entry is archive symbol table in BSD format */
- strncpy(buff + AR_name_offset, "__.SYMDEF", 9);
- goto stat;
- }
- if (strcmp(pathname, "//") == 0) {
- /*
- * Entry is archive filename table, inform that we should
- * collect strtab in next _data call.
- */
- ar->is_strtab = 1;
- buff[AR_name_offset] = buff[AR_name_offset + 1] = '/';
- /*
- * For archive string table, only ar_size field should
- * be set.
- */
- goto size;
- }
-
- /*
- * Otherwise, entry is a normal archive member.
- * Strip leading paths from filenames, if any.
- */
- if ((filename = ar_basename(pathname)) == NULL) {
- /* Reject filenames with trailing "/" */
- archive_set_error(&a->archive, EINVAL,
- "Invalid filename");
- return (ARCHIVE_WARN);
- }
-
- if (a->archive.archive_format == ARCHIVE_FORMAT_AR_GNU) {
- /*
- * SVR4/GNU variant use a "/" to mark then end of the filename,
- * make it possible to have embedded spaces in the filename.
- * So, the longest filename here (without extension) is
- * actually 15 bytes.
- */
- if (strlen(filename) <= 15) {
- strncpy(&buff[AR_name_offset],
- filename, strlen(filename));
- buff[AR_name_offset + strlen(filename)] = '/';
- } else {
- /*
- * For filename longer than 15 bytes, GNU variant
- * makes use of a string table and instead stores the
- * offset of the real filename to in the ar_name field.
- * The string table should have been written before.
- */
- if (ar->has_strtab <= 0) {
- archive_set_error(&a->archive, EINVAL,
- "Can't find string table");
- return (ARCHIVE_WARN);
- }
-
- se = (char *)malloc(strlen(filename) + 3);
- if (se == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate filename buffer");
- return (ARCHIVE_FATAL);
- }
-
- strncpy(se, filename, strlen(filename));
- strcpy(se + strlen(filename), "/\n");
-
- ss = strstr(ar->strtab, se);
- free(se);
-
- if (ss == NULL) {
- archive_set_error(&a->archive, EINVAL,
- "Invalid string table");
- return (ARCHIVE_WARN);
- }
-
- /*
- * GNU variant puts "/" followed by digits into
- * ar_name field. These digits indicates the real
- * filename string's offset to the string table.
- */
- buff[AR_name_offset] = '/';
- if (format_decimal(ss - ar->strtab,
- buff + AR_name_offset + 1,
- AR_name_size - 1)) {
- archive_set_error(&a->archive, ERANGE,
- "string table offset too large");
- return (ARCHIVE_WARN);
- }
- }
- } else if (a->archive.archive_format == ARCHIVE_FORMAT_AR_BSD) {
- /*
- * BSD variant: for any file name which is more than
- * 16 chars or contains one or more embedded space(s), the
- * string "#1/" followed by the ASCII length of the name is
- * put into the ar_name field. The file size (stored in the
- * ar_size field) is incremented by the length of the name.
- * The name is then written immediately following the
- * archive header.
- */
- if (strlen(filename) <= 16 && strchr(filename, ' ') == NULL) {
- strncpy(&buff[AR_name_offset], filename, strlen(filename));
- buff[AR_name_offset + strlen(filename)] = ' ';
- }
- else {
- strncpy(buff + AR_name_offset, "#1/", 3);
- if (format_decimal(strlen(filename),
- buff + AR_name_offset + 3,
- AR_name_size - 3)) {
- archive_set_error(&a->archive, ERANGE,
- "File name too long");
- return (ARCHIVE_WARN);
- }
- append_fn = 1;
- size += strlen(filename);
- }
- }
-
-stat:
- if (format_decimal(archive_entry_mtime(entry), buff + AR_date_offset, AR_date_size)) {
- archive_set_error(&a->archive, ERANGE,
- "File modification time too large");
- return (ARCHIVE_WARN);
- }
- if (format_decimal(archive_entry_uid(entry), buff + AR_uid_offset, AR_uid_size)) {
- archive_set_error(&a->archive, ERANGE,
- "Numeric user ID too large");
- return (ARCHIVE_WARN);
- }
- if (format_decimal(archive_entry_gid(entry), buff + AR_gid_offset, AR_gid_size)) {
- archive_set_error(&a->archive, ERANGE,
- "Numeric group ID too large");
- return (ARCHIVE_WARN);
- }
- if (format_octal(archive_entry_mode(entry), buff + AR_mode_offset, AR_mode_size)) {
- archive_set_error(&a->archive, ERANGE,
- "Numeric mode too large");
- return (ARCHIVE_WARN);
- }
- /*
- * Sanity Check: A non-pseudo archive member should always be
- * a regular file.
- */
- if (filename != NULL && archive_entry_filetype(entry) != AE_IFREG) {
- archive_set_error(&a->archive, EINVAL,
- "Regular file required for non-pseudo member");
- return (ARCHIVE_WARN);
- }
-
-size:
- if (format_decimal(size, buff + AR_size_offset, AR_size_size)) {
- archive_set_error(&a->archive, ERANGE,
- "File size out of range");
- return (ARCHIVE_WARN);
- }
-
- ret = __archive_write_output(a, buff, 60);
- if (ret != ARCHIVE_OK)
- return (ret);
-
- ar->entry_bytes_remaining = size;
- ar->entry_padding = ar->entry_bytes_remaining % 2;
-
- if (append_fn > 0) {
- ret = __archive_write_output(a, filename, strlen(filename));
- if (ret != ARCHIVE_OK)
- return (ret);
- ar->entry_bytes_remaining -= strlen(filename);
- }
-
- return (ARCHIVE_OK);
-}
-
-static ssize_t
-archive_write_ar_data(struct archive_write *a, const void *buff, size_t s)
-{
- struct ar_w *ar;
- int ret;
-
- ar = (struct ar_w *)a->format_data;
- if (s > ar->entry_bytes_remaining)
- s = (size_t)ar->entry_bytes_remaining;
-
- if (ar->is_strtab > 0) {
- if (ar->has_strtab > 0) {
- archive_set_error(&a->archive, EINVAL,
- "More than one string tables exist");
- return (ARCHIVE_WARN);
- }
-
- ar->strtab = (char *)malloc(s);
- if (ar->strtab == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate strtab buffer");
- return (ARCHIVE_FATAL);
- }
- strncpy(ar->strtab, buff, s);
- ar->has_strtab = 1;
- }
-
- ret = __archive_write_output(a, buff, s);
- if (ret != ARCHIVE_OK)
- return (ret);
-
- ar->entry_bytes_remaining -= s;
- return (s);
-}
-
-static int
-archive_write_ar_free(struct archive_write *a)
-{
- struct ar_w *ar;
-
- ar = (struct ar_w *)a->format_data;
-
- if (ar == NULL)
- return (ARCHIVE_OK);
-
- if (ar->has_strtab > 0) {
- free(ar->strtab);
- ar->strtab = NULL;
- }
-
- free(ar);
- a->format_data = NULL;
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_ar_close(struct archive_write *a)
-{
- struct ar_w *ar;
- int ret;
-
- /*
- * If we haven't written anything yet, we need to write
- * the ar global header now to make it a valid ar archive.
- */
- ar = (struct ar_w *)a->format_data;
- if (!ar->wrote_global_header) {
- ar->wrote_global_header = 1;
- ret = __archive_write_output(a, "!<arch>\n", 8);
- return (ret);
- }
-
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_ar_finish_entry(struct archive_write *a)
-{
- struct ar_w *ar;
- int ret;
-
- ar = (struct ar_w *)a->format_data;
-
- if (ar->entry_bytes_remaining != 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Entry remaining bytes larger than 0");
- return (ARCHIVE_WARN);
- }
-
- if (ar->entry_padding == 0) {
- return (ARCHIVE_OK);
- }
-
- if (ar->entry_padding != 1) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Padding wrong size: %ju should be 1 or 0",
- (uintmax_t)ar->entry_padding);
- return (ARCHIVE_WARN);
- }
-
- ret = __archive_write_output(a, "\n", 1);
- return (ret);
-}
-
-/*
- * Format a number into the specified field using base-8.
- * NB: This version is slightly different from the one in
- * _ustar.c
- */
-static int
-format_octal(int64_t v, char *p, int s)
-{
- int len;
- char *h;
-
- len = s;
- h = p;
-
- /* Octal values can't be negative, so use 0. */
- if (v < 0) {
- while (len-- > 0)
- *p++ = '0';
- return (-1);
- }
-
- p += s; /* Start at the end and work backwards. */
- do {
- *--p = (char)('0' + (v & 7));
- v >>= 3;
- } while (--s > 0 && v > 0);
-
- if (v == 0) {
- memmove(h, p, len - s);
- p = h + len - s;
- while (s-- > 0)
- *p++ = ' ';
- return (0);
- }
- /* If it overflowed, fill field with max value. */
- while (len-- > 0)
- *p++ = '7';
-
- return (-1);
-}
-
-/*
- * Format a number into the specified field using base-10.
- */
-static int
-format_decimal(int64_t v, char *p, int s)
-{
- int len;
- char *h;
-
- len = s;
- h = p;
-
- /* Negative values in ar header are meaningless, so use 0. */
- if (v < 0) {
- while (len-- > 0)
- *p++ = '0';
- return (-1);
- }
-
- p += s;
- do {
- *--p = (char)('0' + (v % 10));
- v /= 10;
- } while (--s > 0 && v > 0);
-
- if (v == 0) {
- memmove(h, p, len - s);
- p = h + len - s;
- while (s-- > 0)
- *p++ = ' ';
- return (0);
- }
- /* If it overflowed, fill field with max value. */
- while (len-- > 0)
- *p++ = '9';
-
- return (-1);
-}
-
-static const char *
-ar_basename(const char *path)
-{
- const char *endp, *startp;
-
- endp = path + strlen(path) - 1;
- /*
- * For filename with trailing slash(es), we return
- * NULL indicating an error.
- */
- if (*endp == '/')
- return (NULL);
-
- /* Find the start of the base */
- startp = endp;
- while (startp > path && *(startp - 1) != '/')
- startp--;
-
- return (startp);
-}
diff --git a/3rdparty/libarchive/libarchive/archive_write_set_format_by_name.c b/3rdparty/libarchive/libarchive/archive_write_set_format_by_name.c
index af3105e4..86e8621e 100644
--- a/3rdparty/libarchive/libarchive/archive_write_set_format_by_name.c
+++ b/3rdparty/libarchive/libarchive/archive_write_set_format_by_name.c
@@ -41,7 +41,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_by_name.c 20116
#include "archive_private.h"
/* A table that maps names to functions. */
-static
+static const
struct { const char *name; int (*setter)(struct archive *); } names[] =
{
{ "7zip", archive_write_set_format_7zip },
@@ -63,12 +63,14 @@ struct { const char *name; int (*setter)(struct archive *); } names[] =
{ "pax", archive_write_set_format_pax },
{ "paxr", archive_write_set_format_pax_restricted },
{ "posix", archive_write_set_format_pax },
+ { "raw", archive_write_set_format_raw },
{ "rpax", archive_write_set_format_pax_restricted },
{ "shar", archive_write_set_format_shar },
{ "shardump", archive_write_set_format_shar_dump },
{ "ustar", archive_write_set_format_ustar },
{ "v7tar", archive_write_set_format_v7tar },
{ "v7", archive_write_set_format_v7tar },
+ { "warc", archive_write_set_format_warc },
{ "xar", archive_write_set_format_xar },
{ "zip", archive_write_set_format_zip },
{ NULL, NULL }
diff --git a/3rdparty/libarchive/libarchive/archive_write_set_format_cpio.c b/3rdparty/libarchive/libarchive/archive_write_set_format_cpio.c
deleted file mode 100644
index 35264936..00000000
--- a/3rdparty/libarchive/libarchive/archive_write_set_format_cpio.c
+++ /dev/null
@@ -1,500 +0,0 @@
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * Copyright (c) 2011-2012 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"
-__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_cpio.c 201170 2009-12-29 06:34:23Z kientzle $");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#include <stdio.h>
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#include "archive.h"
-#include "archive_entry.h"
-#include "archive_entry_locale.h"
-#include "archive_private.h"
-#include "archive_write_private.h"
-
-static ssize_t archive_write_cpio_data(struct archive_write *,
- const void *buff, size_t s);
-static int archive_write_cpio_close(struct archive_write *);
-static int archive_write_cpio_free(struct archive_write *);
-static int archive_write_cpio_finish_entry(struct archive_write *);
-static int archive_write_cpio_header(struct archive_write *,
- struct archive_entry *);
-static int archive_write_cpio_options(struct archive_write *,
- const char *, const char *);
-static int format_octal(int64_t, void *, int);
-static int64_t format_octal_recursive(int64_t, char *, int);
-static int write_header(struct archive_write *, struct archive_entry *);
-
-struct cpio {
- uint64_t entry_bytes_remaining;
-
- int64_t ino_next;
-
- struct { int64_t old; int new;} *ino_list;
- size_t ino_list_size;
- size_t ino_list_next;
-
- struct archive_string_conv *opt_sconv;
- struct archive_string_conv *sconv_default;
- int init_default_conversion;
-};
-
-#define c_magic_offset 0
-#define c_magic_size 6
-#define c_dev_offset 6
-#define c_dev_size 6
-#define c_ino_offset 12
-#define c_ino_size 6
-#define c_mode_offset 18
-#define c_mode_size 6
-#define c_uid_offset 24
-#define c_uid_size 6
-#define c_gid_offset 30
-#define c_gid_size 6
-#define c_nlink_offset 36
-#define c_nlink_size 6
-#define c_rdev_offset 42
-#define c_rdev_size 6
-#define c_mtime_offset 48
-#define c_mtime_size 11
-#define c_namesize_offset 59
-#define c_namesize_size 6
-#define c_filesize_offset 65
-#define c_filesize_size 11
-
-/*
- * Set output format to 'cpio' format.
- */
-int
-archive_write_set_format_cpio(struct archive *_a)
-{
- struct archive_write *a = (struct archive_write *)_a;
- struct cpio *cpio;
-
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_set_format_cpio");
-
- /* If someone else was already registered, unregister them. */
- if (a->format_free != NULL)
- (a->format_free)(a);
-
- cpio = (struct cpio *)calloc(1, sizeof(*cpio));
- if (cpio == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");
- return (ARCHIVE_FATAL);
- }
- a->format_data = cpio;
- a->format_name = "cpio";
- a->format_options = archive_write_cpio_options;
- a->format_write_header = archive_write_cpio_header;
- a->format_write_data = archive_write_cpio_data;
- a->format_finish_entry = archive_write_cpio_finish_entry;
- a->format_close = archive_write_cpio_close;
- a->format_free = archive_write_cpio_free;
- a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
- a->archive.archive_format_name = "POSIX cpio";
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_cpio_options(struct archive_write *a, const char *key,
- const char *val)
-{
- struct cpio *cpio = (struct cpio *)a->format_data;
- int ret = ARCHIVE_FAILED;
-
- if (strcmp(key, "hdrcharset") == 0) {
- if (val == NULL || val[0] == 0)
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "%s: hdrcharset option needs a character-set name",
- a->format_name);
- else {
- cpio->opt_sconv = archive_string_conversion_to_charset(
- &a->archive, val, 0);
- if (cpio->opt_sconv != NULL)
- ret = ARCHIVE_OK;
- else
- ret = ARCHIVE_FATAL;
- }
- return (ret);
- }
-
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
-}
-
-/*
- * Ino values are as long as 64 bits on some systems; cpio format
- * only allows 18 bits and relies on the ino values to identify hardlinked
- * files. So, we can't merely "hash" the ino numbers since collisions
- * would corrupt the archive. Instead, we generate synthetic ino values
- * to store in the archive and maintain a map of original ino values to
- * synthetic ones so we can preserve hardlink information.
- *
- * TODO: Make this more efficient. It's not as bad as it looks (most
- * files don't have any hardlinks and we don't do any work here for those),
- * but it wouldn't be hard to do better.
- *
- * TODO: Work with dev/ino pairs here instead of just ino values.
- */
-static int
-synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry)
-{
- int64_t ino = archive_entry_ino64(entry);
- int ino_new;
- size_t i;
-
- /*
- * If no index number was given, don't assign one. In
- * particular, this handles the end-of-archive marker
- * correctly by giving it a zero index value. (This is also
- * why we start our synthetic index numbers with one below.)
- */
- if (ino == 0)
- return (0);
-
- /* Don't store a mapping if we don't need to. */
- if (archive_entry_nlink(entry) < 2) {
- return (int)(++cpio->ino_next);
- }
-
- /* Look up old ino; if we have it, this is a hardlink
- * and we reuse the same value. */
- for (i = 0; i < cpio->ino_list_next; ++i) {
- if (cpio->ino_list[i].old == ino)
- return (cpio->ino_list[i].new);
- }
-
- /* Assign a new index number. */
- ino_new = (int)(++cpio->ino_next);
-
- /* Ensure space for the new mapping. */
- if (cpio->ino_list_size <= cpio->ino_list_next) {
- size_t newsize = cpio->ino_list_size < 512
- ? 512 : cpio->ino_list_size * 2;
- void *newlist = realloc(cpio->ino_list,
- sizeof(cpio->ino_list[0]) * newsize);
- if (newlist == NULL)
- return (-1);
-
- cpio->ino_list_size = newsize;
- cpio->ino_list = newlist;
- }
-
- /* Record and return the new value. */
- cpio->ino_list[cpio->ino_list_next].old = ino;
- cpio->ino_list[cpio->ino_list_next].new = ino_new;
- ++cpio->ino_list_next;
- return (ino_new);
-}
-
-
-static struct archive_string_conv *
-get_sconv(struct archive_write *a)
-{
- struct cpio *cpio;
- struct archive_string_conv *sconv;
-
- cpio = (struct cpio *)a->format_data;
- sconv = cpio->opt_sconv;
- if (sconv == NULL) {
- if (!cpio->init_default_conversion) {
- cpio->sconv_default =
- archive_string_default_conversion_for_write(
- &(a->archive));
- cpio->init_default_conversion = 1;
- }
- sconv = cpio->sconv_default;
- }
- return (sconv);
-}
-
-static int
-archive_write_cpio_header(struct archive_write *a, struct archive_entry *entry)
-{
- const char *path;
- size_t len;
-
- if (archive_entry_filetype(entry) == 0) {
- archive_set_error(&a->archive, -1, "Filetype required");
- return (ARCHIVE_FAILED);
- }
-
- if (archive_entry_pathname_l(entry, &path, &len, get_sconv(a)) != 0
- && errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Pathname");
- return (ARCHIVE_FATAL);
- }
- if (len == 0 || path == NULL || path[0] == '\0') {
- archive_set_error(&a->archive, -1, "Pathname required");
- return (ARCHIVE_FAILED);
- }
-
- if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) < 0) {
- archive_set_error(&a->archive, -1, "Size required");
- return (ARCHIVE_FAILED);
- }
- return write_header(a, entry);
-}
-
-static int
-write_header(struct archive_write *a, struct archive_entry *entry)
-{
- struct cpio *cpio;
- const char *p, *path;
- int pathlength, ret, ret_final;
- int64_t ino;
- char h[76];
- struct archive_string_conv *sconv;
- struct archive_entry *entry_main;
- size_t len;
-
- cpio = (struct cpio *)a->format_data;
- ret_final = ARCHIVE_OK;
- sconv = get_sconv(a);
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
- /* Make sure the path separators in pahtname, hardlink and symlink
- * are all slash '/', not the Windows path separator '\'. */
- entry_main = __la_win_entry_in_posix_pathseparator(entry);
- if (entry_main == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate ustar data");
- return(ARCHIVE_FATAL);
- }
- if (entry != entry_main)
- entry = entry_main;
- else
- entry_main = NULL;
-#else
- entry_main = NULL;
-#endif
-
- ret = archive_entry_pathname_l(entry, &path, &len, sconv);
- if (ret != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Pathname");
- ret_final = ARCHIVE_FATAL;
- goto exit_write_header;
- }
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate pathname '%s' to %s",
- archive_entry_pathname(entry),
- archive_string_conversion_charset_name(sconv));
- ret_final = ARCHIVE_WARN;
- }
- /* Include trailing null. */
- pathlength = (int)len + 1;
-
- memset(h, 0, sizeof(h));
- format_octal(070707, h + c_magic_offset, c_magic_size);
- format_octal(archive_entry_dev(entry), h + c_dev_offset, c_dev_size);
-
- ino = synthesize_ino_value(cpio, entry);
- if (ino < 0) {
- archive_set_error(&a->archive, ENOMEM,
- "No memory for ino translation table");
- ret_final = ARCHIVE_FATAL;
- goto exit_write_header;
- } else if (ino > 0777777) {
- archive_set_error(&a->archive, ERANGE,
- "Too many files for this cpio format");
- ret_final = ARCHIVE_FATAL;
- goto exit_write_header;
- }
- format_octal(ino & 0777777, h + c_ino_offset, c_ino_size);
-
- /* TODO: Set ret_final to ARCHIVE_WARN if any of these overflow. */
- format_octal(archive_entry_mode(entry), h + c_mode_offset, c_mode_size);
- format_octal(archive_entry_uid(entry), h + c_uid_offset, c_uid_size);
- format_octal(archive_entry_gid(entry), h + c_gid_offset, c_gid_size);
- format_octal(archive_entry_nlink(entry), h + c_nlink_offset, c_nlink_size);
- if (archive_entry_filetype(entry) == AE_IFBLK
- || archive_entry_filetype(entry) == AE_IFCHR)
- format_octal(archive_entry_dev(entry), h + c_rdev_offset, c_rdev_size);
- else
- format_octal(0, h + c_rdev_offset, c_rdev_size);
- format_octal(archive_entry_mtime(entry), h + c_mtime_offset, c_mtime_size);
- format_octal(pathlength, h + c_namesize_offset, c_namesize_size);
-
- /* Non-regular files don't store bodies. */
- if (archive_entry_filetype(entry) != AE_IFREG)
- archive_entry_set_size(entry, 0);
-
- /* Symlinks get the link written as the body of the entry. */
- ret = archive_entry_symlink_l(entry, &p, &len, sconv);
- if (ret != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Linkname");
- ret_final = ARCHIVE_FATAL;
- goto exit_write_header;
- }
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate linkname '%s' to %s",
- archive_entry_symlink(entry),
- archive_string_conversion_charset_name(sconv));
- ret_final = ARCHIVE_WARN;
- }
- if (len > 0 && p != NULL && *p != '\0')
- ret = format_octal(strlen(p), h + c_filesize_offset,
- c_filesize_size);
- else
- ret = format_octal(archive_entry_size(entry),
- h + c_filesize_offset, c_filesize_size);
- if (ret) {
- archive_set_error(&a->archive, ERANGE,
- "File is too large for cpio format.");
- ret_final = ARCHIVE_FAILED;
- goto exit_write_header;
- }
-
- ret = __archive_write_output(a, h, sizeof(h));
- if (ret != ARCHIVE_OK) {
- ret_final = ARCHIVE_FATAL;
- goto exit_write_header;
- }
-
- ret = __archive_write_output(a, path, pathlength);
- if (ret != ARCHIVE_OK) {
- ret_final = ARCHIVE_FATAL;
- goto exit_write_header;
- }
-
- cpio->entry_bytes_remaining = archive_entry_size(entry);
-
- /* Write the symlink now. */
- if (p != NULL && *p != '\0') {
- ret = __archive_write_output(a, p, strlen(p));
- if (ret != ARCHIVE_OK) {
- ret_final = ARCHIVE_FATAL;
- goto exit_write_header;
- }
- }
-exit_write_header:
- if (entry_main)
- archive_entry_free(entry_main);
- return (ret_final);
-}
-
-static ssize_t
-archive_write_cpio_data(struct archive_write *a, const void *buff, size_t s)
-{
- struct cpio *cpio;
- int ret;
-
- cpio = (struct cpio *)a->format_data;
- if (s > cpio->entry_bytes_remaining)
- s = (size_t)cpio->entry_bytes_remaining;
-
- ret = __archive_write_output(a, buff, s);
- cpio->entry_bytes_remaining -= s;
- if (ret >= 0)
- return (s);
- else
- return (ret);
-}
-
-/*
- * Format a number into the specified field.
- */
-static int
-format_octal(int64_t v, void *p, int digits)
-{
- int64_t max;
- int ret;
-
- max = (((int64_t)1) << (digits * 3)) - 1;
- if (v >= 0 && v <= max) {
- format_octal_recursive(v, (char *)p, digits);
- ret = 0;
- } else {
- format_octal_recursive(max, (char *)p, digits);
- ret = -1;
- }
- return (ret);
-}
-
-static int64_t
-format_octal_recursive(int64_t v, char *p, int s)
-{
- if (s == 0)
- return (v);
- v = format_octal_recursive(v, p+1, s-1);
- *p = '0' + ((char)v & 7);
- return (v >> 3);
-}
-
-static int
-archive_write_cpio_close(struct archive_write *a)
-{
- int er;
- struct archive_entry *trailer;
-
- trailer = archive_entry_new2(NULL);
- /* nlink = 1 here for GNU cpio compat. */
- archive_entry_set_nlink(trailer, 1);
- archive_entry_set_size(trailer, 0);
- archive_entry_set_pathname(trailer, "TRAILER!!!");
- er = write_header(a, trailer);
- archive_entry_free(trailer);
- return (er);
-}
-
-static int
-archive_write_cpio_free(struct archive_write *a)
-{
- struct cpio *cpio;
-
- cpio = (struct cpio *)a->format_data;
- free(cpio->ino_list);
- free(cpio);
- a->format_data = NULL;
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_cpio_finish_entry(struct archive_write *a)
-{
- struct cpio *cpio;
-
- cpio = (struct cpio *)a->format_data;
- return (__archive_write_nulls(a,
- (size_t)cpio->entry_bytes_remaining));
-}
diff --git a/3rdparty/libarchive/libarchive/archive_write_set_format_cpio_newc.c b/3rdparty/libarchive/libarchive/archive_write_set_format_cpio_newc.c
deleted file mode 100644
index a9bfa808..00000000
--- a/3rdparty/libarchive/libarchive/archive_write_set_format_cpio_newc.c
+++ /dev/null
@@ -1,458 +0,0 @@
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * Copyright (c) 2006 Rudolf Marek SYSGO s.r.o.
- * Copyright (c) 2011-2012 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"
-__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_cpio_newc.c 201160 2009-12-29 05:41:57Z kientzle $");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#include <stdio.h>
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#include "archive.h"
-#include "archive_entry.h"
-#include "archive_entry_locale.h"
-#include "archive_private.h"
-#include "archive_write_private.h"
-
-static ssize_t archive_write_newc_data(struct archive_write *,
- const void *buff, size_t s);
-static int archive_write_newc_close(struct archive_write *);
-static int archive_write_newc_free(struct archive_write *);
-static int archive_write_newc_finish_entry(struct archive_write *);
-static int archive_write_newc_header(struct archive_write *,
- struct archive_entry *);
-static int archive_write_newc_options(struct archive_write *,
- const char *, const char *);
-static int format_hex(int64_t, void *, int);
-static int64_t format_hex_recursive(int64_t, char *, int);
-static int write_header(struct archive_write *, struct archive_entry *);
-
-struct cpio {
- uint64_t entry_bytes_remaining;
- int padding;
-
- struct archive_string_conv *opt_sconv;
- struct archive_string_conv *sconv_default;
- int init_default_conversion;
-};
-
-#define c_magic_offset 0
-#define c_magic_size 6
-#define c_ino_offset 6
-#define c_ino_size 8
-#define c_mode_offset 14
-#define c_mode_size 8
-#define c_uid_offset 22
-#define c_uid_size 8
-#define c_gid_offset 30
-#define c_gid_size 8
-#define c_nlink_offset 38
-#define c_nlink_size 8
-#define c_mtime_offset 46
-#define c_mtime_size 8
-#define c_filesize_offset 54
-#define c_filesize_size 8
-#define c_devmajor_offset 62
-#define c_devmajor_size 8
-#define c_devminor_offset 70
-#define c_devminor_size 8
-#define c_rdevmajor_offset 78
-#define c_rdevmajor_size 8
-#define c_rdevminor_offset 86
-#define c_rdevminor_size 8
-#define c_namesize_offset 94
-#define c_namesize_size 8
-#define c_checksum_offset 102
-#define c_checksum_size 8
-#define c_header_size 110
-
-/* Logic trick: difference between 'n' and next multiple of 4 */
-#define PAD4(n) (3 & (1 + ~(n)))
-
-/*
- * Set output format to 'cpio' format.
- */
-int
-archive_write_set_format_cpio_newc(struct archive *_a)
-{
- struct archive_write *a = (struct archive_write *)_a;
- struct cpio *cpio;
-
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_newc");
-
- /* If someone else was already registered, unregister them. */
- if (a->format_free != NULL)
- (a->format_free)(a);
-
- cpio = (struct cpio *)malloc(sizeof(*cpio));
- if (cpio == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");
- return (ARCHIVE_FATAL);
- }
- memset(cpio, 0, sizeof(*cpio));
- a->format_data = cpio;
- a->format_name = "cpio";
- a->format_options = archive_write_newc_options;
- a->format_write_header = archive_write_newc_header;
- a->format_write_data = archive_write_newc_data;
- a->format_finish_entry = archive_write_newc_finish_entry;
- a->format_close = archive_write_newc_close;
- a->format_free = archive_write_newc_free;
- a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC;
- a->archive.archive_format_name = "SVR4 cpio nocrc";
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_newc_options(struct archive_write *a, const char *key,
- const char *val)
-{
- struct cpio *cpio = (struct cpio *)a->format_data;
- int ret = ARCHIVE_FAILED;
-
- if (strcmp(key, "hdrcharset") == 0) {
- if (val == NULL || val[0] == 0)
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "%s: hdrcharset option needs a character-set name",
- a->format_name);
- else {
- cpio->opt_sconv = archive_string_conversion_to_charset(
- &a->archive, val, 0);
- if (cpio->opt_sconv != NULL)
- ret = ARCHIVE_OK;
- else
- ret = ARCHIVE_FATAL;
- }
- return (ret);
- }
-
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
-}
-
-static struct archive_string_conv *
-get_sconv(struct archive_write *a)
-{
- struct cpio *cpio;
- struct archive_string_conv *sconv;
-
- cpio = (struct cpio *)a->format_data;
- sconv = cpio->opt_sconv;
- if (sconv == NULL) {
- if (!cpio->init_default_conversion) {
- cpio->sconv_default =
- archive_string_default_conversion_for_write(
- &(a->archive));
- cpio->init_default_conversion = 1;
- }
- sconv = cpio->sconv_default;
- }
- return (sconv);
-}
-
-static int
-archive_write_newc_header(struct archive_write *a, struct archive_entry *entry)
-{
- const char *path;
- size_t len;
-
- if (archive_entry_filetype(entry) == 0) {
- archive_set_error(&a->archive, -1, "Filetype required");
- return (ARCHIVE_FAILED);
- }
-
- if (archive_entry_pathname_l(entry, &path, &len, get_sconv(a)) != 0
- && errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Pathname");
- return (ARCHIVE_FATAL);
- }
- if (len == 0 || path == NULL || path[0] == '\0') {
- archive_set_error(&a->archive, -1, "Pathname required");
- return (ARCHIVE_FAILED);
- }
-
- if (archive_entry_hardlink(entry) == NULL
- && (!archive_entry_size_is_set(entry) || archive_entry_size(entry) < 0)) {
- archive_set_error(&a->archive, -1, "Size required");
- return (ARCHIVE_FAILED);
- }
- return write_header(a, entry);
-}
-
-static int
-write_header(struct archive_write *a, struct archive_entry *entry)
-{
- int64_t ino;
- struct cpio *cpio;
- const char *p, *path;
- int pathlength, ret, ret_final;
- char h[c_header_size];
- struct archive_string_conv *sconv;
- struct archive_entry *entry_main;
- size_t len;
- int pad;
-
- cpio = (struct cpio *)a->format_data;
- ret_final = ARCHIVE_OK;
- sconv = get_sconv(a);
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
- /* Make sure the path separators in pahtname, hardlink and symlink
- * are all slash '/', not the Windows path separator '\'. */
- entry_main = __la_win_entry_in_posix_pathseparator(entry);
- if (entry_main == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate ustar data");
- return(ARCHIVE_FATAL);
- }
- if (entry != entry_main)
- entry = entry_main;
- else
- entry_main = NULL;
-#else
- entry_main = NULL;
-#endif
-
- ret = archive_entry_pathname_l(entry, &path, &len, sconv);
- if (ret != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Pathname");
- ret_final = ARCHIVE_FATAL;
- goto exit_write_header;
- }
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate pathname '%s' to %s",
- archive_entry_pathname(entry),
- archive_string_conversion_charset_name(sconv));
- ret_final = ARCHIVE_WARN;
- }
- pathlength = (int)len + 1; /* Include trailing null. */
-
- memset(h, 0, c_header_size);
- format_hex(0x070701, h + c_magic_offset, c_magic_size);
- format_hex(archive_entry_devmajor(entry), h + c_devmajor_offset,
- c_devmajor_size);
- format_hex(archive_entry_devminor(entry), h + c_devminor_offset,
- c_devminor_size);
-
- ino = archive_entry_ino64(entry);
- if (ino > 0xffffffff) {
- archive_set_error(&a->archive, ERANGE,
- "large inode number truncated");
- ret_final = ARCHIVE_WARN;
- }
-
- /* TODO: Set ret_final to ARCHIVE_WARN if any of these overflow. */
- format_hex(ino & 0xffffffff, h + c_ino_offset, c_ino_size);
- format_hex(archive_entry_mode(entry), h + c_mode_offset, c_mode_size);
- format_hex(archive_entry_uid(entry), h + c_uid_offset, c_uid_size);
- format_hex(archive_entry_gid(entry), h + c_gid_offset, c_gid_size);
- format_hex(archive_entry_nlink(entry), h + c_nlink_offset, c_nlink_size);
- if (archive_entry_filetype(entry) == AE_IFBLK
- || archive_entry_filetype(entry) == AE_IFCHR) {
- format_hex(archive_entry_rdevmajor(entry), h + c_rdevmajor_offset, c_rdevmajor_size);
- format_hex(archive_entry_rdevminor(entry), h + c_rdevminor_offset, c_rdevminor_size);
- } else {
- format_hex(0, h + c_rdevmajor_offset, c_rdevmajor_size);
- format_hex(0, h + c_rdevminor_offset, c_rdevminor_size);
- }
- format_hex(archive_entry_mtime(entry), h + c_mtime_offset, c_mtime_size);
- format_hex(pathlength, h + c_namesize_offset, c_namesize_size);
- format_hex(0, h + c_checksum_offset, c_checksum_size);
-
- /* Non-regular files don't store bodies. */
- if (archive_entry_filetype(entry) != AE_IFREG)
- archive_entry_set_size(entry, 0);
-
- /* Symlinks get the link written as the body of the entry. */
- ret = archive_entry_symlink_l(entry, &p, &len, sconv);
- if (ret != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Likname");
- ret_final = ARCHIVE_FATAL;
- goto exit_write_header;
- }
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate linkname '%s' to %s",
- archive_entry_symlink(entry),
- archive_string_conversion_charset_name(sconv));
- ret_final = ARCHIVE_WARN;
- }
- if (len > 0 && p != NULL && *p != '\0')
- ret = format_hex(strlen(p), h + c_filesize_offset,
- c_filesize_size);
- else
- ret = format_hex(archive_entry_size(entry),
- h + c_filesize_offset, c_filesize_size);
- if (ret) {
- archive_set_error(&a->archive, ERANGE,
- "File is too large for this format.");
- ret_final = ARCHIVE_FAILED;
- goto exit_write_header;
- }
-
- ret = __archive_write_output(a, h, c_header_size);
- if (ret != ARCHIVE_OK) {
- ret_final = ARCHIVE_FATAL;
- goto exit_write_header;
- }
-
- /* Pad pathname to even length. */
- ret = __archive_write_output(a, path, pathlength);
- if (ret != ARCHIVE_OK) {
- ret_final = ARCHIVE_FATAL;
- goto exit_write_header;
- }
- pad = PAD4(pathlength + c_header_size);
- if (pad) {
- ret = __archive_write_output(a, "\0\0\0", pad);
- if (ret != ARCHIVE_OK) {
- ret_final = ARCHIVE_FATAL;
- goto exit_write_header;
- }
- }
-
- cpio->entry_bytes_remaining = archive_entry_size(entry);
- cpio->padding = (int)PAD4(cpio->entry_bytes_remaining);
-
- /* Write the symlink now. */
- if (p != NULL && *p != '\0') {
- ret = __archive_write_output(a, p, strlen(p));
- if (ret != ARCHIVE_OK) {
- ret_final = ARCHIVE_FATAL;
- goto exit_write_header;
- }
- pad = PAD4(strlen(p));
- ret = __archive_write_output(a, "\0\0\0", pad);
- if (ret != ARCHIVE_OK) {
- ret_final = ARCHIVE_FATAL;
- goto exit_write_header;
- }
- }
-exit_write_header:
- if (entry_main)
- archive_entry_free(entry_main);
- return (ret_final);
-}
-
-static ssize_t
-archive_write_newc_data(struct archive_write *a, const void *buff, size_t s)
-{
- struct cpio *cpio;
- int ret;
-
- cpio = (struct cpio *)a->format_data;
- if (s > cpio->entry_bytes_remaining)
- s = (size_t)cpio->entry_bytes_remaining;
-
- ret = __archive_write_output(a, buff, s);
- cpio->entry_bytes_remaining -= s;
- if (ret >= 0)
- return (s);
- else
- return (ret);
-}
-
-/*
- * Format a number into the specified field.
- */
-static int
-format_hex(int64_t v, void *p, int digits)
-{
- int64_t max;
- int ret;
-
- max = (((int64_t)1) << (digits * 4)) - 1;
- if (v >= 0 && v <= max) {
- format_hex_recursive(v, (char *)p, digits);
- ret = 0;
- } else {
- format_hex_recursive(max, (char *)p, digits);
- ret = -1;
- }
- return (ret);
-}
-
-static int64_t
-format_hex_recursive(int64_t v, char *p, int s)
-{
- if (s == 0)
- return (v);
- v = format_hex_recursive(v, p+1, s-1);
- *p = "0123456789abcdef"[v & 0xf];
- return (v >> 4);
-}
-
-static int
-archive_write_newc_close(struct archive_write *a)
-{
- int er;
- struct archive_entry *trailer;
-
- trailer = archive_entry_new();
- archive_entry_set_nlink(trailer, 1);
- archive_entry_set_size(trailer, 0);
- archive_entry_set_pathname(trailer, "TRAILER!!!");
- /* Bypass the required data checks. */
- er = write_header(a, trailer);
- archive_entry_free(trailer);
- return (er);
-}
-
-static int
-archive_write_newc_free(struct archive_write *a)
-{
- struct cpio *cpio;
-
- cpio = (struct cpio *)a->format_data;
- free(cpio);
- a->format_data = NULL;
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_newc_finish_entry(struct archive_write *a)
-{
- struct cpio *cpio;
-
- cpio = (struct cpio *)a->format_data;
- return (__archive_write_nulls(a,
- (size_t)cpio->entry_bytes_remaining + cpio->padding));
-}
diff --git a/3rdparty/libarchive/libarchive/archive_write_set_format_gnutar.c b/3rdparty/libarchive/libarchive/archive_write_set_format_gnutar.c
index 13942c13..2d858c9f 100644
--- a/3rdparty/libarchive/libarchive/archive_write_set_format_gnutar.c
+++ b/3rdparty/libarchive/libarchive/archive_write_set_format_gnutar.c
@@ -119,9 +119,9 @@ static const char template_header[] = {
'0','0','0','0','0','0', '0','\0',
/* gid, null termination: 8 bytes */
'0','0','0','0','0','0', '0','\0',
- /* size, space termation: 12 bytes */
+ /* size, space termination: 12 bytes */
'0','0','0','0','0','0','0','0','0','0','0', '\0',
- /* mtime, space termation: 12 bytes */
+ /* mtime, space termination: 12 bytes */
'0','0','0','0','0','0','0','0','0','0','0', '\0',
/* Initial checksum value: 8 spaces */
' ',' ',' ',' ',' ',' ',' ',' ',
@@ -368,7 +368,7 @@ archive_write_gnutar_header(struct archive_write *a,
}
#if defined(_WIN32) && !defined(__CYGWIN__)
- /* Make sure the path separators in pahtname, hardlink and symlink
+ /* Make sure the path separators in pathname, hardlink and symlink
* are all slash '/', not the Windows path separator '\'. */
entry_main = __la_win_entry_in_posix_pathseparator(entry);
if (entry_main == NULL) {
@@ -467,7 +467,7 @@ archive_write_gnutar_header(struct archive_write *a,
}
}
if (gnutar->linkname_length > GNUTAR_linkname_size) {
- size_t todo = gnutar->linkname_length;
+ size_t length = gnutar->linkname_length + 1;
struct archive_entry *temp = archive_entry_new2(&a->archive);
/* Uname/gname here don't really matter since no one reads them;
@@ -476,19 +476,20 @@ archive_write_gnutar_header(struct archive_write *a,
archive_entry_set_gname(temp, "wheel");
archive_entry_set_pathname(temp, "././@LongLink");
- archive_entry_set_size(temp, gnutar->linkname_length + 1);
+ archive_entry_set_size(temp, length);
ret = archive_format_gnutar_header(a, buff, temp, 'K');
+ archive_entry_free(temp);
if (ret < ARCHIVE_WARN)
goto exit_write_header;
ret = __archive_write_output(a, buff, 512);
- if(ret < ARCHIVE_WARN)
+ if (ret < ARCHIVE_WARN)
goto exit_write_header;
- archive_entry_free(temp);
- /* Write as many 512 bytes blocks as needed to write full name. */
- ret = __archive_write_output(a, gnutar->linkname, todo);
- if(ret < ARCHIVE_WARN)
+ /* Write name and trailing null byte. */
+ ret = __archive_write_output(a, gnutar->linkname, length);
+ if (ret < ARCHIVE_WARN)
goto exit_write_header;
- ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)todo));
+ /* Pad to 512 bytes */
+ ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)length));
if (ret < ARCHIVE_WARN)
goto exit_write_header;
}
@@ -496,7 +497,7 @@ archive_write_gnutar_header(struct archive_write *a,
/* If pathname is longer than 100 chars we need to add an 'L' header. */
if (gnutar->pathname_length > GNUTAR_name_size) {
const char *pathname = gnutar->pathname;
- size_t todo = gnutar->pathname_length;
+ size_t length = gnutar->pathname_length + 1;
struct archive_entry *temp = archive_entry_new2(&a->archive);
/* Uname/gname here don't really matter since no one reads them;
@@ -505,19 +506,20 @@ archive_write_gnutar_header(struct archive_write *a,
archive_entry_set_gname(temp, "wheel");
archive_entry_set_pathname(temp, "././@LongLink");
- archive_entry_set_size(temp, gnutar->pathname_length + 1);
+ archive_entry_set_size(temp, length);
ret = archive_format_gnutar_header(a, buff, temp, 'L');
+ archive_entry_free(temp);
if (ret < ARCHIVE_WARN)
goto exit_write_header;
ret = __archive_write_output(a, buff, 512);
if(ret < ARCHIVE_WARN)
goto exit_write_header;
- archive_entry_free(temp);
- /* Write as many 512 bytes blocks as needed to write full name. */
- ret = __archive_write_output(a, pathname, todo);
+ /* Write pathname + trailing null byte. */
+ ret = __archive_write_output(a, pathname, length);
if(ret < ARCHIVE_WARN)
goto exit_write_header;
- ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)todo));
+ /* Pad to multiple of 512 bytes. */
+ ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)length));
if (ret < ARCHIVE_WARN)
goto exit_write_header;
}
@@ -644,18 +646,18 @@ archive_format_gnutar_header(struct archive_write *a, char h[512],
format_octal(archive_entry_mode(entry) & 07777,
h + GNUTAR_mode_offset, GNUTAR_mode_size);
- /* TODO: How does GNU tar handle large UIDs? */
- if (format_octal(archive_entry_uid(entry),
- h + GNUTAR_uid_offset, GNUTAR_uid_size)) {
+ /* GNU tar supports base-256 here, so should never overflow. */
+ if (format_number(archive_entry_uid(entry), h + GNUTAR_uid_offset,
+ GNUTAR_uid_size, GNUTAR_uid_max_size)) {
archive_set_error(&a->archive, ERANGE,
"Numeric user ID %jd too large",
(intmax_t)archive_entry_uid(entry));
ret = ARCHIVE_FAILED;
}
- /* TODO: How does GNU tar handle large GIDs? */
- if (format_octal(archive_entry_gid(entry),
- h + GNUTAR_gid_offset, GNUTAR_gid_size)) {
+ /* GNU tar supports base-256 here, so should never overflow. */
+ if (format_number(archive_entry_gid(entry), h + GNUTAR_gid_offset,
+ GNUTAR_gid_size, GNUTAR_gid_max_size)) {
archive_set_error(&a->archive, ERANGE,
"Numeric group ID %jd too large",
(intmax_t)archive_entry_gid(entry));
diff --git a/3rdparty/libarchive/libarchive/archive_write_set_format_iso9660.c b/3rdparty/libarchive/libarchive/archive_write_set_format_iso9660.c
deleted file mode 100644
index 59137029..00000000
--- a/3rdparty/libarchive/libarchive/archive_write_set_format_iso9660.c
+++ /dev/null
@@ -1,8148 +0,0 @@
-/*-
- * Copyright (c) 2009-2012 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"
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_UTSNAME_H
-#include <sys/utsname.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#endif
-#include <stdio.h>
-#include <stdarg.h>
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#include <time.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_ZLIB_H
-#include <zlib.h>
-#endif
-
-#include "archive.h"
-#include "archive_endian.h"
-#include "archive_entry.h"
-#include "archive_entry_locale.h"
-#include "archive_private.h"
-#include "archive_rb.h"
-#include "archive_write_private.h"
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-#define getuid() 0
-#define getgid() 0
-#endif
-
-/*#define DEBUG 1*/
-#ifdef DEBUG
-/* To compare to the ISO image file made by mkisofs. */
-#define COMPAT_MKISOFS 1
-#endif
-
-#define LOGICAL_BLOCK_BITS 11
-#define LOGICAL_BLOCK_SIZE 2048
-#define PATH_TABLE_BLOCK_SIZE 4096
-
-#define SYSTEM_AREA_BLOCK 16
-#define PRIMARY_VOLUME_DESCRIPTOR_BLOCK 1
-#define SUPPLEMENTARY_VOLUME_DESCRIPTOR_BLOCK 1
-#define BOOT_RECORD_DESCRIPTOR_BLOCK 1
-#define VOLUME_DESCRIPTOR_SET_TERMINATOR_BLOCK 1
-#define NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK 1
-#define RRIP_ER_BLOCK 1
-#define PADDING_BLOCK 150
-
-#define FD_1_2M_SIZE (1024 * 1200)
-#define FD_1_44M_SIZE (1024 * 1440)
-#define FD_2_88M_SIZE (1024 * 2880)
-#define MULTI_EXTENT_SIZE (ARCHIVE_LITERAL_LL(1) << 32) /* 4Gi bytes. */
-#define MAX_DEPTH 8
-#define RR_CE_SIZE 28 /* SUSP "CE" extension size */
-
-#define FILE_FLAG_EXISTENCE 0x01
-#define FILE_FLAG_DIRECTORY 0x02
-#define FILE_FLAG_ASSOCIATED 0x04
-#define FILE_FLAG_RECORD 0x08
-#define FILE_FLAG_PROTECTION 0x10
-#define FILE_FLAG_MULTI_EXTENT 0x80
-
-static const char rrip_identifier[] =
- "RRIP_1991A";
-static const char rrip_descriptor[] =
- "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR "
- "POSIX FILE SYSTEM SEMANTICS";
-static const char rrip_source[] =
- "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE. "
- "SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR "
- "CONTACT INFORMATION.";
-#define RRIP_ER_ID_SIZE (sizeof(rrip_identifier)-1)
-#define RRIP_ER_DSC_SIZE (sizeof(rrip_descriptor)-1)
-#define RRIP_ER_SRC_SIZE (sizeof(rrip_source)-1)
-#define RRIP_ER_SIZE (8 + RRIP_ER_ID_SIZE + \
- RRIP_ER_DSC_SIZE + RRIP_ER_SRC_SIZE)
-
-static const unsigned char zisofs_magic[8] = {
- 0x37, 0xE4, 0x53, 0x96, 0xC9, 0xDB, 0xD6, 0x07
-};
-
-#define ZF_HEADER_SIZE 16 /* zisofs header size. */
-#define ZF_LOG2_BS 15 /* log2 block size; 32K bytes. */
-#define ZF_BLOCK_SIZE (1UL << ZF_LOG2_BS)
-
-/*
- * Manage extra records.
- */
-struct extr_rec {
- int location;
- int offset;
- unsigned char buf[LOGICAL_BLOCK_SIZE];
- struct extr_rec *next;
-};
-
-struct ctl_extr_rec {
- int use_extr;
- unsigned char *bp;
- struct isoent *isoent;
- unsigned char *ce_ptr;
- int cur_len;
- int dr_len;
- int limit;
- int extr_off;
- int extr_loc;
-};
-#define DR_SAFETY RR_CE_SIZE
-#define DR_LIMIT (254 - DR_SAFETY)
-
-/*
- * The relation of struct isofile and isoent and archive_entry.
- *
- * Primary volume tree --> struct isoent
- * |
- * v
- * struct isofile --> archive_entry
- * ^
- * |
- * Joliet volume tree --> struct isoent
- *
- * struct isoent has specific information for volume.
- */
-
-struct isofile {
- /* Used for managing struct isofile list. */
- struct isofile *allnext;
- struct isofile *datanext;
- /* Used for managing a hardlined struct isofile list. */
- struct isofile *hlnext;
- struct isofile *hardlink_target;
-
- struct archive_entry *entry;
-
- /*
- * Used for making a directory tree.
- */
- struct archive_string parentdir;
- struct archive_string basename;
- struct archive_string basename_utf16;
- struct archive_string symlink;
- int dircnt; /* The number of elements of
- * its parent directory */
-
- /*
- * Used for a Directory Record.
- */
- struct content {
- int64_t offset_of_temp;
- int64_t size;
- int blocks;
- uint32_t location;
- /*
- * One extent equals one content.
- * If this entry has multi extent, `next' variable points
- * next content data.
- */
- struct content *next; /* next content */
- } content, *cur_content;
- int write_content;
-
- enum {
- NO = 0,
- BOOT_CATALOG,
- BOOT_IMAGE,
- } boot;
-
- /*
- * Used for a zisofs.
- */
- struct {
- unsigned char header_size;
- unsigned char log2_bs;
- uint32_t uncompressed_size;
- } zisofs;
-};
-
-struct isoent {
- /* Keep `rbnode' at the first member of struct isoent. */
- struct archive_rb_node rbnode;
-
- struct isofile *file;
-
- struct isoent *parent;
- /* A list of children.(use chnext) */
- struct {
- struct isoent *first;
- struct isoent **last;
- int cnt;
- } children;
- struct archive_rb_tree rbtree;
-
- /* A list of sub directories.(use drnext) */
- struct {
- struct isoent *first;
- struct isoent **last;
- int cnt;
- } subdirs;
- /* A sorted list of sub directories. */
- struct isoent **children_sorted;
- /* Used for managing struct isoent list. */
- struct isoent *chnext;
- struct isoent *drnext;
- struct isoent *ptnext;
-
- /*
- * Used for making a Directory Record.
- */
- int dir_number;
- struct {
- int vd;
- int self;
- int parent;
- int normal;
- } dr_len;
- uint32_t dir_location;
- int dir_block;
-
- /*
- * Identifier:
- * on primary, ISO9660 file/directory name.
- * on joliet, UCS2 file/directory name.
- * ext_off : offset of identifier extension.
- * ext_len : length of identifier extension.
- * id_len : byte size of identifier.
- * on primary, this is ext_off + ext_len + version length.
- * on joliet, this is ext_off + ext_len.
- * mb_len : length of multibyte-character of identifier.
- * on primary, mb_len and id_len are always the same.
- * on joliet, mb_len and id_len are different.
- */
- char *identifier;
- int ext_off;
- int ext_len;
- int id_len;
- int mb_len;
-
- /*
- * Used for making a Rockridge extension.
- * This is a part of Directory Records.
- */
- struct isoent *rr_parent;
- struct isoent *rr_child;
-
- /* Extra Record.(which we call in this source file)
- * A maximum size of the Directory Record is 254.
- * so, if generated RRIP data of a file cannot into a Directory
- * Record because of its size, that surplus data relocate this
- * Extra Record.
- */
- struct {
- struct extr_rec *first;
- struct extr_rec **last;
- struct extr_rec *current;
- } extr_rec_list;
-
- int virtual:1;
- /* If set to one, this file type is a directory.
- * A convenience flag to be used as
- * "archive_entry_filetype(isoent->file->entry) == AE_IFDIR".
- */
- int dir:1;
-};
-
-struct hardlink {
- struct archive_rb_node rbnode;
- int nlink;
- struct {
- struct isofile *first;
- struct isofile **last;
- } file_list;
-};
-
-/*
- * ISO writer options
- */
-struct iso_option {
- /*
- * Usage : abstract-file=<value>
- * Type : string, max 37 bytes
- * Default: Not specified
- * COMPAT : mkisofs -abstract <value>
- *
- * Specifies Abstract Filename.
- * This file shall be described in the Root Directory
- * and containing a abstract statement.
- */
- unsigned int abstract_file:1;
-#define OPT_ABSTRACT_FILE_DEFAULT 0 /* Not specified */
-#define ABSTRACT_FILE_SIZE 37
-
- /*
- * Usage : application-id=<value>
- * Type : string, max 128 bytes
- * Default: Not specified
- * COMPAT : mkisofs -A/-appid <value>.
- *
- * Specifies Application Identifier.
- * If the first byte is set to '_'(5F), the remaining
- * bytes of this option shall specify an identifier
- * for a file containing the identification of the
- * application.
- * This file shall be described in the Root Directory.
- */
- unsigned int application_id:1;
-#define OPT_APPLICATION_ID_DEFAULT 0 /* Use default identifier */
-#define APPLICATION_IDENTIFIER_SIZE 128
-
- /*
- * Usage : !allow-vernum
- * Type : boolean
- * Default: Enabled
- * : Violates the ISO9660 standard if disable.
- * COMPAT: mkisofs -N
- *
- * Allow filenames to use version numbers.
- */
- unsigned int allow_vernum:1;
-#define OPT_ALLOW_VERNUM_DEFAULT 1 /* Enabled */
-
- /*
- * Usage : biblio-file=<value>
- * Type : string, max 37 bytes
- * Default: Not specified
- * COMPAT : mkisofs -biblio <value>
- *
- * Specifies Bibliographic Filename.
- * This file shall be described in the Root Directory
- * and containing bibliographic records.
- */
- unsigned int biblio_file:1;
-#define OPT_BIBLIO_FILE_DEFAULT 0 /* Not specified */
-#define BIBLIO_FILE_SIZE 37
-
- /*
- * Usage : boot=<value>
- * Type : string
- * Default: Not specified
- * COMPAT : mkisofs -b/-eltorito-boot <value>
- *
- * Specifies "El Torito" boot image file to make
- * a bootable CD.
- */
- unsigned int boot:1;
-#define OPT_BOOT_DEFAULT 0 /* Not specified */
-
- /*
- * Usage : boot-catalog=<value>
- * Type : string
- * Default: "boot.catalog"
- * COMPAT : mkisofs -c/-eltorito-catalog <value>
- *
- * Specifies a fullpath of El Torito boot catalog.
- */
- unsigned int boot_catalog:1;
-#define OPT_BOOT_CATALOG_DEFAULT 0 /* Not specified */
-
- /*
- * Usage : boot-info-table
- * Type : boolean
- * Default: Disabled
- * COMPAT : mkisofs -boot-info-table
- *
- * Modify the boot image file specified by `boot'
- * option; ISO writer stores boot file information
- * into the boot file in ISO image at offset 8
- * through offset 64.
- */
- unsigned int boot_info_table:1;
-#define OPT_BOOT_INFO_TABLE_DEFAULT 0 /* Disabled */
-
- /*
- * Usage : boot-load-seg=<value>
- * Type : hexadecimal
- * Default: Not specified
- * COMPAT : mkisofs -boot-load-seg <value>
- *
- * Specifies a load segment for boot image.
- * This is used with no-emulation mode.
- */
- unsigned int boot_load_seg:1;
-#define OPT_BOOT_LOAD_SEG_DEFAULT 0 /* Not specified */
-
- /*
- * Usage : boot-load-size=<value>
- * Type : decimal
- * Default: Not specified
- * COMPAT : mkisofs -boot-load-size <value>
- *
- * Specifies a sector count for boot image.
- * This is used with no-emulation mode.
- */
- unsigned int boot_load_size:1;
-#define OPT_BOOT_LOAD_SIZE_DEFAULT 0 /* Not specified */
-
- /*
- * Usage : boot-type=<boot-media-type>
- * : 'no-emulation' : 'no emulation' image
- * : 'fd' : floppy disk image
- * : 'hard-disk' : hard disk image
- * Type : string
- * Default: Auto detect
- * : We check a size of boot image;
- * : If ths size is just 1.22M/1.44M/2.88M,
- * : we assume boot_type is 'fd';
- * : otherwise boot_type is 'no-emulation'.
- * COMPAT :
- * boot=no-emulation
- * mkisofs -no-emul-boot
- * boot=fd
- * This is a default on the mkisofs.
- * boot=hard-disk
- * mkisofs -hard-disk-boot
- *
- * Specifies a type of "El Torito" boot image.
- */
- unsigned int boot_type:2;
-#define OPT_BOOT_TYPE_AUTO 0 /* auto detect */
-#define OPT_BOOT_TYPE_NO_EMU 1 /* ``no emulation'' image */
-#define OPT_BOOT_TYPE_FD 2 /* floppy disk image */
-#define OPT_BOOT_TYPE_HARD_DISK 3 /* hard disk image */
-#define OPT_BOOT_TYPE_DEFAULT OPT_BOOT_TYPE_AUTO
-
- /*
- * Usage : compression-level=<value>
- * Type : decimal
- * Default: Not specified
- * COMPAT : NONE
- *
- * Specifies compression level for option zisofs=direct.
- */
- unsigned int compression_level:1;
-#define OPT_COMPRESSION_LEVEL_DEFAULT 0 /* Not specified */
-
- /*
- * Usage : copyright-file=<value>
- * Type : string, max 37 bytes
- * Default: Not specified
- * COMPAT : mkisofs -copyright <value>
- *
- * Specifies Copyright Filename.
- * This file shall be described in the Root Directory
- * and containing a copyright statement.
- */
- unsigned int copyright_file:1;
-#define OPT_COPYRIGHT_FILE_DEFAULT 0 /* Not specified */
-#define COPYRIGHT_FILE_SIZE 37
-
- /*
- * Usage : gid=<value>
- * Type : decimal
- * Default: Not specified
- * COMPAT : mkisofs -gid <value>
- *
- * Specifies a group id to rewrite the group id of all files.
- */
- unsigned int gid:1;
-#define OPT_GID_DEFAULT 0 /* Not specified */
-
- /*
- * Usage : iso-level=[1234]
- * Type : decimal
- * Default: 1
- * COMPAT : mkisofs -iso-level <value>
- *
- * Specifies ISO9600 Level.
- * Level 1: [DEFAULT]
- * - limits each file size less than 4Gi bytes;
- * - a File Name shall not contain more than eight
- * d-characters or eight d1-characters;
- * - a File Name Extension shall not contain more than
- * three d-characters or three d1-characters;
- * - a Directory Identifier shall not contain more
- * than eight d-characters or eight d1-characters.
- * Level 2:
- * - limits each file size less than 4Giga bytes;
- * - a File Name shall not contain more than thirty
- * d-characters or thirty d1-characters;
- * - a File Name Extension shall not contain more than
- * thirty d-characters or thirty d1-characters;
- * - a Directory Identifier shall not contain more
- * than thirty-one d-characters or thirty-one
- * d1-characters.
- * Level 3:
- * - no limit of file size; use multi extent.
- * Level 4:
- * - this level 4 simulates mkisofs option
- * '-iso-level 4';
- * - crate a enhanced volume as mkisofs doing;
- * - allow a File Name to have leading dot;
- * - allow a File Name to have all ASCII letters;
- * - allow a File Name to have multiple dots;
- * - allow more then 8 depths of directory trees;
- * - disable a version number to a File Name;
- * - disable a forced period to the tail of a File Name;
- * - the maxinum length of files and directories is raised to 193.
- * if rockridge option is disabled, raised to 207.
- */
- unsigned int iso_level:3;
-#define OPT_ISO_LEVEL_DEFAULT 1 /* ISO Level 1 */
-
- /*
- * Usage : joliet[=long]
- * : !joliet
- * : Do not generate Joliet Volume and Records.
- * : joliet [DEFAULT]
- * : Generates Joliet Volume and Directory Records.
- * : [COMPAT: mkisofs -J/-joliet]
- * : joliet=long
- * : The joliet filenames are up to 103 Unicode
- * : characters.
- * : This option breaks the Joliet specification.
- * : [COMPAT: mkisofs -J -joliet-long]
- * Type : boolean/string
- * Default: Enabled
- * COMPAT : mkisofs -J / -joliet-long
- *
- * Generates Joliet Volume and Directory Records.
- */
- unsigned int joliet:2;
-#define OPT_JOLIET_DISABLE 0 /* Not generate Joliet Records. */
-#define OPT_JOLIET_ENABLE 1 /* Generate Joliet Records. */
-#define OPT_JOLIET_LONGNAME 2 /* Use long joliet filenames.*/
-#define OPT_JOLIET_DEFAULT OPT_JOLIET_ENABLE
-
- /*
- * Usage : !limit-depth
- * Type : boolean
- * Default: Enabled
- * : Violates the ISO9660 standard if disable.
- * COMPAT : mkisofs -D/-disable-deep-relocation
- *
- * The number of levels in hierarchy cannot exceed eight.
- */
- unsigned int limit_depth:1;
-#define OPT_LIMIT_DEPTH_DEFAULT 1 /* Enabled */
-
- /*
- * Usage : !limit-dirs
- * Type : boolean
- * Default: Enabled
- * : Violates the ISO9660 standard if disable.
- * COMPAT : mkisofs -no-limit-pathtables
- *
- * Limits the number of directories less than 65536 due
- * to the size of the Parent Directory Number of Path
- * Table.
- */
- unsigned int limit_dirs:1;
-#define OPT_LIMIT_DIRS_DEFAULT 1 /* Enabled */
-
- /*
- * Usage : !pad
- * Type : boolean
- * Default: Enabled
- * COMPAT : -pad/-no-pad
- *
- * Pads the end of the ISO image by null of 300Ki bytes.
- */
- unsigned int pad:1;
-#define OPT_PAD_DEFAULT 1 /* Enabled */
-
- /*
- * Usage : publisher=<value>
- * Type : string, max 128 bytes
- * Default: Not specified
- * COMPAT : mkisofs -publisher <value>
- *
- * Specifies Publisher Identifier.
- * If the first byte is set to '_'(5F), the remaining
- * bytes of this option shall specify an identifier
- * for a file containing the identification of the user.
- * This file shall be described in the Root Directory.
- */
- unsigned int publisher:1;
-#define OPT_PUBLISHER_DEFAULT 0 /* Not specified */
-#define PUBLISHER_IDENTIFIER_SIZE 128
-
- /*
- * Usage : rockridge
- * : !rockridge
- * : disable to generate SUSP and RR records.
- * : rockridge
- * : the same as 'rockridge=useful'.
- * : rockridge=strict
- * : generate SUSP and RR records.
- * : [COMPAT: mkisofs -R]
- * : rockridge=useful [DEFAULT]
- * : generate SUSP and RR records.
- * : [COMPAT: mkisofs -r]
- * : NOTE Our rockridge=useful option does not set a zero
- * : to uid and gid, you should use application
- * : option such as --gid,--gname,--uid and --uname
- * : badtar options instead.
- * Type : boolean/string
- * Default: Enabled as rockridge=useful
- * COMPAT : mkisofs -r / -R
- *
- * Generates SUSP and RR records.
- */
- unsigned int rr:2;
-#define OPT_RR_DISABLED 0
-#define OPT_RR_STRICT 1
-#define OPT_RR_USEFUL 2
-#define OPT_RR_DEFAULT OPT_RR_USEFUL
-
- /*
- * Usage : volume-id=<value>
- * Type : string, max 32 bytes
- * Default: Not specified
- * COMPAT : mkisofs -V <value>
- *
- * Specifies Volume Identifier.
- */
- unsigned int volume_id:1;
-#define OPT_VOLUME_ID_DEFAULT 0 /* Use default identifier */
-#define VOLUME_IDENTIFIER_SIZE 32
-
- /*
- * Usage : !zisofs [DEFAULT]
- * : Disable to generate RRIP 'ZF' extension.
- * : zisofs
- * : Make files zisofs file and generate RRIP 'ZF'
- * : extension. So you do not need mkzftree utility
- * : for making zisofs.
- * : When the file size is less than one Logical Block
- * : size, that file will not zisofs'ed since it does
- * : reduece an ISO-image size.
- * :
- * : When you specify option 'boot=<boot-image>', that
- * : 'boot-image' file won't be converted to zisofs file.
- * Type : boolean
- * Default: Disabled
- *
- * Generates RRIP 'ZF' System Use Entry.
- */
- unsigned int zisofs:1;
-#define OPT_ZISOFS_DISABLED 0
-#define OPT_ZISOFS_DIRECT 1
-#define OPT_ZISOFS_DEFAULT OPT_ZISOFS_DISABLED
-
-};
-
-struct iso9660 {
- /* The creation time of ISO image. */
- time_t birth_time;
- /* A file stream of a temporary file, which file contents
- * save to until ISO iamge can be created. */
- int temp_fd;
-
- struct isofile *cur_file;
- struct isoent *cur_dirent;
- struct archive_string cur_dirstr;
- uint64_t bytes_remaining;
- int need_multi_extent;
-
- /* Temporary string buffer for Joliet extension. */
- struct archive_string utf16be;
- struct archive_string mbs;
-
- struct archive_string_conv *sconv_to_utf16be;
- struct archive_string_conv *sconv_from_utf16be;
-
- /* A list of all of struct isofile entries. */
- struct {
- struct isofile *first;
- struct isofile **last;
- } all_file_list;
-
- /* A list of struct isofile entries which have its
- * contents and are not a directory, a hardlined file
- * and a symlink file. */
- struct {
- struct isofile *first;
- struct isofile **last;
- } data_file_list;
-
- /* Used for managing to find hardlinking files. */
- struct archive_rb_tree hardlink_rbtree;
-
- /* Used for making the Path Table Record. */
- struct vdd {
- /* the root of entry tree. */
- struct isoent *rootent;
- enum vdd_type {
- VDD_PRIMARY,
- VDD_JOLIET,
- VDD_ENHANCED
- } vdd_type;
-
- struct path_table {
- struct isoent *first;
- struct isoent **last;
- struct isoent **sorted;
- int cnt;
- } *pathtbl;
- int max_depth;
-
- int path_table_block;
- int path_table_size;
- int location_type_L_path_table;
- int location_type_M_path_table;
- int total_dir_block;
- } primary, joliet;
-
- /* Used for making a Volume Descriptor. */
- int volume_space_size;
- int volume_sequence_number;
- int total_file_block;
- struct archive_string volume_identifier;
- struct archive_string publisher_identifier;
- struct archive_string data_preparer_identifier;
- struct archive_string application_identifier;
- struct archive_string copyright_file_identifier;
- struct archive_string abstract_file_identifier;
- struct archive_string bibliographic_file_identifier;
-
- /* Used for making rockridge extensions. */
- int location_rrip_er;
-
- /* Used for making zisofs. */
- struct {
- int detect_magic:1;
- int making:1;
- int allzero:1;
- unsigned char magic_buffer[64];
- int magic_cnt;
-
-#ifdef HAVE_ZLIB_H
- /*
- * Copy a compressed file to iso9660.zisofs.temp_fd
- * and also copy a uncompressed file(original file) to
- * iso9660.temp_fd . If the number of logical block
- * of the compressed file is less than the number of
- * logical block of the uncompressed file, use it and
- * remove the copy of the uncompressed file.
- * but if not, we use uncompressed file and remove
- * the copy of the compressed file.
- */
- uint32_t *block_pointers;
- size_t block_pointers_allocated;
- int block_pointers_cnt;
- int block_pointers_idx;
- int64_t total_size;
- int64_t block_offset;
-
- z_stream stream;
- int stream_valid;
- int64_t remaining;
- int compression_level;
-#endif
- } zisofs;
-
- struct isoent *directories_too_deep;
- int dircnt_max;
-
- /* Write buffer. */
-#define wb_buffmax() (LOGICAL_BLOCK_SIZE * 32)
-#define wb_remaining(a) (((struct iso9660 *)(a)->format_data)->wbuff_remaining)
-#define wb_offset(a) (((struct iso9660 *)(a)->format_data)->wbuff_offset \
- + wb_buffmax() - wb_remaining(a))
- unsigned char wbuff[LOGICAL_BLOCK_SIZE * 32];
- size_t wbuff_remaining;
- enum {
- WB_TO_STREAM,
- WB_TO_TEMP
- } wbuff_type;
- int64_t wbuff_offset;
- int64_t wbuff_written;
- int64_t wbuff_tail;
-
- /* 'El Torito' boot data. */
- struct {
- /* boot catalog file */
- struct archive_string catalog_filename;
- struct isoent *catalog;
- /* boot image file */
- struct archive_string boot_filename;
- struct isoent *boot;
-
- unsigned char platform_id;
-#define BOOT_PLATFORM_X86 0
-#define BOOT_PLATFORM_PPC 1
-#define BOOT_PLATFORM_MAC 2
- struct archive_string id;
- unsigned char media_type;
-#define BOOT_MEDIA_NO_EMULATION 0
-#define BOOT_MEDIA_1_2M_DISKETTE 1
-#define BOOT_MEDIA_1_44M_DISKETTE 2
-#define BOOT_MEDIA_2_88M_DISKETTE 3
-#define BOOT_MEDIA_HARD_DISK 4
- unsigned char system_type;
- uint16_t boot_load_seg;
- uint16_t boot_load_size;
-#define BOOT_LOAD_SIZE 4
- } el_torito;
-
- struct iso_option opt;
-};
-
-/*
- * Types of Volume Descriptor
- */
-enum VD_type {
- VDT_BOOT_RECORD=0, /* Boot Record Volume Descriptor */
- VDT_PRIMARY=1, /* Primary Volume Descriptor */
- VDT_SUPPLEMENTARY=2, /* Supplementary Volume Descriptor */
- VDT_TERMINATOR=255 /* Volume Descriptor Set Terminator */
-};
-
-/*
- * Types of Directory Record
- */
-enum dir_rec_type {
- DIR_REC_VD, /* Stored in Volume Descriptor. */
- DIR_REC_SELF, /* Stored as Current Directory. */
- DIR_REC_PARENT, /* Stored as Parent Directory. */
- DIR_REC_NORMAL, /* Stored as Child. */
-};
-
-/*
- * Kinds of Volume Descriptor Character
- */
-enum vdc {
- VDC_STD,
- VDC_LOWERCASE,
- VDC_UCS2,
- VDC_UCS2_DIRECT,
-};
-
-/*
- * IDentifier Resolver.
- * Used for resolving duplicated filenames.
- */
-struct idr {
- struct idrent {
- struct archive_rb_node rbnode;
- /* Used in wait_list. */
- struct idrent *wnext;
- struct idrent *avail;
-
- struct isoent *isoent;
- int weight;
- int noff;
- int rename_num;
- } *idrent_pool;
-
- struct archive_rb_tree rbtree;
-
- struct {
- struct idrent *first;
- struct idrent **last;
- } wait_list;
-
- int pool_size;
- int pool_idx;
- int num_size;
- int null_size;
-
- char char_map[0x80];
-};
-
-enum char_type {
- A_CHAR,
- D_CHAR,
-};
-
-
-static int iso9660_options(struct archive_write *,
- const char *, const char *);
-static int iso9660_write_header(struct archive_write *,
- struct archive_entry *);
-static ssize_t iso9660_write_data(struct archive_write *,
- const void *, size_t);
-static int iso9660_finish_entry(struct archive_write *);
-static int iso9660_close(struct archive_write *);
-static int iso9660_free(struct archive_write *);
-
-static void get_system_identitier(char *, size_t);
-static void set_str(unsigned char *, const char *, size_t, char,
- const char *);
-static inline int joliet_allowed_char(unsigned char, unsigned char);
-static int set_str_utf16be(struct archive_write *, unsigned char *,
- const char *, size_t, uint16_t, enum vdc);
-static int set_str_a_characters_bp(struct archive_write *,
- unsigned char *, int, int, const char *, enum vdc);
-static int set_str_d_characters_bp(struct archive_write *,
- unsigned char *, int, int, const char *, enum vdc);
-static void set_VD_bp(unsigned char *, enum VD_type, unsigned char);
-static inline void set_unused_field_bp(unsigned char *, int, int);
-
-static unsigned char *extra_open_record(unsigned char *, int,
- struct isoent *, struct ctl_extr_rec *);
-static void extra_close_record(struct ctl_extr_rec *, int);
-static unsigned char * extra_next_record(struct ctl_extr_rec *, int);
-static unsigned char *extra_get_record(struct isoent *, int *, int *, int *);
-static void extra_tell_used_size(struct ctl_extr_rec *, int);
-static int extra_setup_location(struct isoent *, int);
-static int set_directory_record_rr(unsigned char *, int,
- struct isoent *, struct iso9660 *, enum dir_rec_type);
-static int set_directory_record(unsigned char *, size_t,
- struct isoent *, struct iso9660 *, enum dir_rec_type,
- enum vdd_type);
-static inline int get_dir_rec_size(struct iso9660 *, struct isoent *,
- enum dir_rec_type, enum vdd_type);
-static inline unsigned char *wb_buffptr(struct archive_write *);
-static int wb_write_out(struct archive_write *);
-static int wb_consume(struct archive_write *, size_t);
-#ifdef HAVE_ZLIB_H
-static int wb_set_offset(struct archive_write *, int64_t);
-#endif
-static int write_null(struct archive_write *, size_t);
-static int write_VD_terminator(struct archive_write *);
-static int set_file_identifier(unsigned char *, int, int, enum vdc,
- struct archive_write *, struct vdd *,
- struct archive_string *, const char *, int,
- enum char_type);
-static int write_VD(struct archive_write *, struct vdd *);
-static int write_VD_boot_record(struct archive_write *);
-static int write_information_block(struct archive_write *);
-static int write_path_table(struct archive_write *, int,
- struct vdd *);
-static int write_directory_descriptors(struct archive_write *,
- struct vdd *);
-static int write_file_descriptors(struct archive_write *);
-static int write_rr_ER(struct archive_write *);
-static void calculate_path_table_size(struct vdd *);
-
-static void isofile_init_entry_list(struct iso9660 *);
-static void isofile_add_entry(struct iso9660 *, struct isofile *);
-static void isofile_free_all_entries(struct iso9660 *);
-static void isofile_init_entry_data_file_list(struct iso9660 *);
-static void isofile_add_data_file(struct iso9660 *, struct isofile *);
-static struct isofile * isofile_new(struct archive_write *,
- struct archive_entry *);
-static void isofile_free(struct isofile *);
-static int isofile_gen_utility_names(struct archive_write *,
- struct isofile *);
-static int isofile_register_hardlink(struct archive_write *,
- struct isofile *);
-static void isofile_connect_hardlink_files(struct iso9660 *);
-static void isofile_init_hardlinks(struct iso9660 *);
-static void isofile_free_hardlinks(struct iso9660 *);
-
-static struct isoent *isoent_new(struct isofile *);
-static int isoent_clone_tree(struct archive_write *,
- struct isoent **, struct isoent *);
-static void _isoent_free(struct isoent *isoent);
-static void isoent_free_all(struct isoent *);
-static struct isoent * isoent_create_virtual_dir(struct archive_write *,
- struct iso9660 *, const char *);
-static int isoent_cmp_node(const struct archive_rb_node *,
- const struct archive_rb_node *);
-static int isoent_cmp_key(const struct archive_rb_node *,
- const void *);
-static int isoent_add_child_head(struct isoent *, struct isoent *);
-static int isoent_add_child_tail(struct isoent *, struct isoent *);
-static void isoent_remove_child(struct isoent *, struct isoent *);
-static void isoent_setup_directory_location(struct iso9660 *,
- int, struct vdd *);
-static void isoent_setup_file_location(struct iso9660 *, int);
-static int get_path_component(char *, size_t, const char *);
-static int isoent_tree(struct archive_write *, struct isoent **);
-static struct isoent *isoent_find_child(struct isoent *, const char *);
-static struct isoent *isoent_find_entry(struct isoent *, const char *);
-static void idr_relaxed_filenames(char *);
-static void idr_init(struct iso9660 *, struct vdd *, struct idr *);
-static void idr_cleanup(struct idr *);
-static int idr_ensure_poolsize(struct archive_write *, struct idr *,
- int);
-static int idr_start(struct archive_write *, struct idr *,
- int, int, int, int, const struct archive_rb_tree_ops *);
-static void idr_register(struct idr *, struct isoent *, int,
- int);
-static void idr_extend_identifier(struct idrent *, int, int);
-static void idr_resolve(struct idr *, void (*)(unsigned char *, int));
-static void idr_set_num(unsigned char *, int);
-static void idr_set_num_beutf16(unsigned char *, int);
-static int isoent_gen_iso9660_identifier(struct archive_write *,
- struct isoent *, struct idr *);
-static int isoent_gen_joliet_identifier(struct archive_write *,
- struct isoent *, struct idr *);
-static int isoent_cmp_iso9660_identifier(const struct isoent *,
- const struct isoent *);
-static int isoent_cmp_node_iso9660(const struct archive_rb_node *,
- const struct archive_rb_node *);
-static int isoent_cmp_key_iso9660(const struct archive_rb_node *,
- const void *);
-static int isoent_cmp_joliet_identifier(const struct isoent *,
- const struct isoent *);
-static int isoent_cmp_node_joliet(const struct archive_rb_node *,
- const struct archive_rb_node *);
-static int isoent_cmp_key_joliet(const struct archive_rb_node *,
- const void *);
-static inline void path_table_add_entry(struct path_table *, struct isoent *);
-static inline struct isoent * path_table_last_entry(struct path_table *);
-static int isoent_make_path_table(struct archive_write *);
-static int isoent_find_out_boot_file(struct archive_write *,
- struct isoent *);
-static int isoent_create_boot_catalog(struct archive_write *,
- struct isoent *);
-static size_t fd_boot_image_size(int);
-static int make_boot_catalog(struct archive_write *);
-static int setup_boot_information(struct archive_write *);
-
-static int zisofs_init(struct archive_write *, struct isofile *);
-static void zisofs_detect_magic(struct archive_write *,
- const void *, size_t);
-static int zisofs_write_to_temp(struct archive_write *,
- const void *, size_t);
-static int zisofs_finish_entry(struct archive_write *);
-static int zisofs_rewind_boot_file(struct archive_write *);
-static int zisofs_free(struct archive_write *);
-
-int
-archive_write_set_format_iso9660(struct archive *_a)
-{
- struct archive_write *a = (struct archive_write *)_a;
- struct iso9660 *iso9660;
-
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_set_format_iso9660");
-
- /* If another format was already registered, unregister it. */
- if (a->format_free != NULL)
- (a->format_free)(a);
-
- iso9660 = calloc(1, sizeof(*iso9660));
- if (iso9660 == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate iso9660 data");
- return (ARCHIVE_FATAL);
- }
- iso9660->birth_time = 0;
- iso9660->temp_fd = -1;
- iso9660->cur_file = NULL;
- iso9660->primary.max_depth = 0;
- iso9660->primary.vdd_type = VDD_PRIMARY;
- iso9660->primary.pathtbl = NULL;
- iso9660->joliet.rootent = NULL;
- iso9660->joliet.max_depth = 0;
- iso9660->joliet.vdd_type = VDD_JOLIET;
- iso9660->joliet.pathtbl = NULL;
- isofile_init_entry_list(iso9660);
- isofile_init_entry_data_file_list(iso9660);
- isofile_init_hardlinks(iso9660);
- iso9660->directories_too_deep = NULL;
- iso9660->dircnt_max = 1;
- iso9660->wbuff_remaining = wb_buffmax();
- iso9660->wbuff_type = WB_TO_TEMP;
- iso9660->wbuff_offset = 0;
- iso9660->wbuff_written = 0;
- iso9660->wbuff_tail = 0;
- archive_string_init(&(iso9660->utf16be));
- archive_string_init(&(iso9660->mbs));
-
- /*
- * Init Identifiers used for PVD and SVD.
- */
- archive_string_init(&(iso9660->volume_identifier));
- archive_strcpy(&(iso9660->volume_identifier), "CDROM");
- archive_string_init(&(iso9660->publisher_identifier));
- archive_string_init(&(iso9660->data_preparer_identifier));
- archive_string_init(&(iso9660->application_identifier));
- archive_strcpy(&(iso9660->application_identifier),
- archive_version_string());
- archive_string_init(&(iso9660->copyright_file_identifier));
- archive_string_init(&(iso9660->abstract_file_identifier));
- archive_string_init(&(iso9660->bibliographic_file_identifier));
-
- /*
- * Init El Torito bootable CD variables.
- */
- archive_string_init(&(iso9660->el_torito.catalog_filename));
- iso9660->el_torito.catalog = NULL;
- /* Set default file name of boot catalog */
- archive_strcpy(&(iso9660->el_torito.catalog_filename),
- "boot.catalog");
- archive_string_init(&(iso9660->el_torito.boot_filename));
- iso9660->el_torito.boot = NULL;
- iso9660->el_torito.platform_id = BOOT_PLATFORM_X86;
- archive_string_init(&(iso9660->el_torito.id));
- iso9660->el_torito.boot_load_seg = 0;
- iso9660->el_torito.boot_load_size = BOOT_LOAD_SIZE;
-
- /*
- * Init zisofs variables.
- */
-#ifdef HAVE_ZLIB_H
- iso9660->zisofs.block_pointers = NULL;
- iso9660->zisofs.block_pointers_allocated = 0;
- iso9660->zisofs.stream_valid = 0;
- iso9660->zisofs.compression_level = 9;
- memset(&(iso9660->zisofs.stream), 0,
- sizeof(iso9660->zisofs.stream));
-#endif
-
- /*
- * Set default value of iso9660 options.
- */
- iso9660->opt.abstract_file = OPT_ABSTRACT_FILE_DEFAULT;
- iso9660->opt.application_id = OPT_APPLICATION_ID_DEFAULT;
- iso9660->opt.allow_vernum = OPT_ALLOW_VERNUM_DEFAULT;
- iso9660->opt.biblio_file = OPT_BIBLIO_FILE_DEFAULT;
- iso9660->opt.boot = OPT_BOOT_DEFAULT;
- iso9660->opt.boot_catalog = OPT_BOOT_CATALOG_DEFAULT;
- iso9660->opt.boot_info_table = OPT_BOOT_INFO_TABLE_DEFAULT;
- iso9660->opt.boot_load_seg = OPT_BOOT_LOAD_SEG_DEFAULT;
- iso9660->opt.boot_load_size = OPT_BOOT_LOAD_SIZE_DEFAULT;
- iso9660->opt.boot_type = OPT_BOOT_TYPE_DEFAULT;
- iso9660->opt.compression_level = OPT_COMPRESSION_LEVEL_DEFAULT;
- iso9660->opt.copyright_file = OPT_COPYRIGHT_FILE_DEFAULT;
- iso9660->opt.iso_level = OPT_ISO_LEVEL_DEFAULT;
- iso9660->opt.joliet = OPT_JOLIET_DEFAULT;
- iso9660->opt.limit_depth = OPT_LIMIT_DEPTH_DEFAULT;
- iso9660->opt.limit_dirs = OPT_LIMIT_DIRS_DEFAULT;
- iso9660->opt.pad = OPT_PAD_DEFAULT;
- iso9660->opt.publisher = OPT_PUBLISHER_DEFAULT;
- iso9660->opt.rr = OPT_RR_DEFAULT;
- iso9660->opt.volume_id = OPT_VOLUME_ID_DEFAULT;
- iso9660->opt.zisofs = OPT_ZISOFS_DEFAULT;
-
- /* Create the root directory. */
- iso9660->primary.rootent =
- isoent_create_virtual_dir(a, iso9660, "");
- if (iso9660->primary.rootent == NULL) {
- free(iso9660);
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- iso9660->primary.rootent->parent = iso9660->primary.rootent;
- iso9660->cur_dirent = iso9660->primary.rootent;
- archive_string_init(&(iso9660->cur_dirstr));
- archive_string_ensure(&(iso9660->cur_dirstr), 1);
- iso9660->cur_dirstr.s[0] = 0;
- iso9660->sconv_to_utf16be = NULL;
- iso9660->sconv_from_utf16be = NULL;
-
- a->format_data = iso9660;
- a->format_name = "iso9660";
- a->format_options = iso9660_options;
- a->format_write_header = iso9660_write_header;
- a->format_write_data = iso9660_write_data;
- a->format_finish_entry = iso9660_finish_entry;
- a->format_close = iso9660_close;
- a->format_free = iso9660_free;
- a->archive.archive_format = ARCHIVE_FORMAT_ISO9660;
- a->archive.archive_format_name = "ISO9660";
-
- return (ARCHIVE_OK);
-}
-
-static int
-get_str_opt(struct archive_write *a, struct archive_string *s,
- size_t maxsize, const char *key, const char *value)
-{
-
- if (strlen(value) > maxsize) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Value is longer than %zu characters "
- "for option ``%s''", maxsize, key);
- return (ARCHIVE_FATAL);
- }
- archive_strcpy(s, value);
- return (ARCHIVE_OK);
-}
-
-static int
-get_num_opt(struct archive_write *a, int *num, int high, int low,
- const char *key, const char *value)
-{
- const char *p = value;
- int data = 0;
- int neg = 0;
-
- if (p == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid value(empty) for option ``%s''", key);
- return (ARCHIVE_FATAL);
- }
- if (*p == '-') {
- neg = 1;
- p++;
- }
- while (*p) {
- if (*p >= '0' && *p <= '9')
- data = data * 10 + *p - '0';
- else {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid value for option ``%s''", key);
- return (ARCHIVE_FATAL);
- }
- if (data > high) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid value(over %d) for "
- "option ``%s''", high, key);
- return (ARCHIVE_FATAL);
- }
- if (data < low) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid value(under %d) for "
- "option ``%s''", low, key);
- return (ARCHIVE_FATAL);
- }
- p++;
- }
- if (neg)
- data *= -1;
- *num = data;
-
- return (ARCHIVE_OK);
-}
-
-static int
-iso9660_options(struct archive_write *a, const char *key, const char *value)
-{
- struct iso9660 *iso9660 = a->format_data;
- const char *p;
- int r;
-
- switch (key[0]) {
- case 'a':
- if (strcmp(key, "abstract-file") == 0) {
- r = get_str_opt(a,
- &(iso9660->abstract_file_identifier),
- ABSTRACT_FILE_SIZE, key, value);
- iso9660->opt.abstract_file = r == ARCHIVE_OK;
- return (r);
- }
- if (strcmp(key, "application-id") == 0) {
- r = get_str_opt(a,
- &(iso9660->application_identifier),
- APPLICATION_IDENTIFIER_SIZE, key, value);
- iso9660->opt.application_id = r == ARCHIVE_OK;
- return (r);
- }
- if (strcmp(key, "allow-vernum") == 0) {
- iso9660->opt.allow_vernum = value != NULL;
- return (ARCHIVE_OK);
- }
- break;
- case 'b':
- if (strcmp(key, "biblio-file") == 0) {
- r = get_str_opt(a,
- &(iso9660->bibliographic_file_identifier),
- BIBLIO_FILE_SIZE, key, value);
- iso9660->opt.biblio_file = r == ARCHIVE_OK;
- return (r);
- }
- if (strcmp(key, "boot") == 0) {
- if (value == NULL)
- iso9660->opt.boot = 0;
- else {
- iso9660->opt.boot = 1;
- archive_strcpy(
- &(iso9660->el_torito.boot_filename),
- value);
- }
- return (ARCHIVE_OK);
- }
- if (strcmp(key, "boot-catalog") == 0) {
- r = get_str_opt(a,
- &(iso9660->el_torito.catalog_filename),
- 1024, key, value);
- iso9660->opt.boot_catalog = r == ARCHIVE_OK;
- return (r);
- }
- if (strcmp(key, "boot-info-table") == 0) {
- iso9660->opt.boot_info_table = value != NULL;
- return (ARCHIVE_OK);
- }
- if (strcmp(key, "boot-load-seg") == 0) {
- uint32_t seg;
-
- iso9660->opt.boot_load_seg = 0;
- if (value == NULL)
- goto invalid_value;
- seg = 0;
- p = value;
- if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X'))
- p += 2;
- while (*p) {
- if (seg)
- seg <<= 4;
- if (*p >= 'A' && *p <= 'F')
- seg += *p - 'A' + 0x0a;
- else if (*p >= 'a' && *p <= 'f')
- seg += *p - 'a' + 0x0a;
- else if (*p >= '0' && *p <= '9')
- seg += *p - '0';
- else
- goto invalid_value;
- if (seg > 0xffff) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Invalid value(over 0xffff) for "
- "option ``%s''", key);
- return (ARCHIVE_FATAL);
- }
- p++;
- }
- iso9660->el_torito.boot_load_seg = (uint16_t)seg;
- iso9660->opt.boot_load_seg = 1;
- return (ARCHIVE_OK);
- }
- if (strcmp(key, "boot-load-size") == 0) {
- int num = 0;
- r = get_num_opt(a, &num, 0xffff, 1, key, value);
- iso9660->opt.boot_load_size = r == ARCHIVE_OK;
- if (r != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- iso9660->el_torito.boot_load_size = (uint16_t)num;
- return (ARCHIVE_OK);
- }
- if (strcmp(key, "boot-type") == 0) {
- if (value == NULL)
- goto invalid_value;
- if (strcmp(value, "no-emulation") == 0)
- iso9660->opt.boot_type = OPT_BOOT_TYPE_NO_EMU;
- else if (strcmp(value, "fd") == 0)
- iso9660->opt.boot_type = OPT_BOOT_TYPE_FD;
- else if (strcmp(value, "hard-disk") == 0)
- iso9660->opt.boot_type = OPT_BOOT_TYPE_HARD_DISK;
- else
- goto invalid_value;
- return (ARCHIVE_OK);
- }
- break;
- case 'c':
- if (strcmp(key, "compression-level") == 0) {
-#ifdef HAVE_ZLIB_H
- if (value == NULL ||
- !(value[0] >= '0' && value[0] <= '9') ||
- value[1] != '\0')
- goto invalid_value;
- iso9660->zisofs.compression_level = value[0] - '0';
- iso9660->opt.compression_level = 1;
- return (ARCHIVE_OK);
-#else
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Option ``%s'' "
- "is not supported on this platform.", key);
- return (ARCHIVE_FATAL);
-#endif
- }
- if (strcmp(key, "copyright-file") == 0) {
- r = get_str_opt(a,
- &(iso9660->copyright_file_identifier),
- COPYRIGHT_FILE_SIZE, key, value);
- iso9660->opt.copyright_file = r == ARCHIVE_OK;
- return (r);
- }
-#ifdef DEBUG
- /* Specifies Volume creation date and time;
- * year(4),month(2),day(2),hour(2),minute(2),second(2).
- * e.g. "20090929033757"
- */
- if (strcmp(key, "creation") == 0) {
- struct tm tm;
- char buf[5];
-
- p = value;
- if (p == NULL || strlen(p) < 14)
- goto invalid_value;
- memset(&tm, 0, sizeof(tm));
- memcpy(buf, p, 4); buf[4] = '\0'; p += 4;
- tm.tm_year = strtol(buf, NULL, 10) - 1900;
- memcpy(buf, p, 2); buf[2] = '\0'; p += 2;
- tm.tm_mon = strtol(buf, NULL, 10) - 1;
- memcpy(buf, p, 2); buf[2] = '\0'; p += 2;
- tm.tm_mday = strtol(buf, NULL, 10);
- memcpy(buf, p, 2); buf[2] = '\0'; p += 2;
- tm.tm_hour = strtol(buf, NULL, 10);
- memcpy(buf, p, 2); buf[2] = '\0'; p += 2;
- tm.tm_min = strtol(buf, NULL, 10);
- memcpy(buf, p, 2); buf[2] = '\0';
- tm.tm_sec = strtol(buf, NULL, 10);
- iso9660->birth_time = mktime(&tm);
- return (ARCHIVE_OK);
- }
-#endif
- break;
- case 'i':
- if (strcmp(key, "iso-level") == 0) {
- if (value != NULL && value[1] == '\0' &&
- (value[0] >= '1' && value[0] <= '4')) {
- iso9660->opt.iso_level = value[0]-'0';
- return (ARCHIVE_OK);
- }
- goto invalid_value;
- }
- break;
- case 'j':
- if (strcmp(key, "joliet") == 0) {
- if (value == NULL)
- iso9660->opt.joliet = OPT_JOLIET_DISABLE;
- else if (strcmp(value, "1") == 0)
- iso9660->opt.joliet = OPT_JOLIET_ENABLE;
- else if (strcmp(value, "long") == 0)
- iso9660->opt.joliet = OPT_JOLIET_LONGNAME;
- else
- goto invalid_value;
- return (ARCHIVE_OK);
- }
- break;
- case 'l':
- if (strcmp(key, "limit-depth") == 0) {
- iso9660->opt.limit_depth = value != NULL;
- return (ARCHIVE_OK);
- }
- if (strcmp(key, "limit-dirs") == 0) {
- iso9660->opt.limit_dirs = value != NULL;
- return (ARCHIVE_OK);
- }
- break;
- case 'p':
- if (strcmp(key, "pad") == 0) {
- iso9660->opt.pad = value != NULL;
- return (ARCHIVE_OK);
- }
- if (strcmp(key, "publisher") == 0) {
- r = get_str_opt(a,
- &(iso9660->publisher_identifier),
- PUBLISHER_IDENTIFIER_SIZE, key, value);
- iso9660->opt.publisher = r == ARCHIVE_OK;
- return (r);
- }
- break;
- case 'r':
- if (strcmp(key, "rockridge") == 0 ||
- strcmp(key, "Rockridge") == 0) {
- if (value == NULL)
- iso9660->opt.rr = OPT_RR_DISABLED;
- else if (strcmp(value, "1") == 0)
- iso9660->opt.rr = OPT_RR_USEFUL;
- else if (strcmp(value, "strict") == 0)
- iso9660->opt.rr = OPT_RR_STRICT;
- else if (strcmp(value, "useful") == 0)
- iso9660->opt.rr = OPT_RR_USEFUL;
- else
- goto invalid_value;
- return (ARCHIVE_OK);
- }
- break;
- case 'v':
- if (strcmp(key, "volume-id") == 0) {
- r = get_str_opt(a, &(iso9660->volume_identifier),
- VOLUME_IDENTIFIER_SIZE, key, value);
- iso9660->opt.volume_id = r == ARCHIVE_OK;
- return (r);
- }
- break;
- case 'z':
- if (strcmp(key, "zisofs") == 0) {
- if (value == NULL)
- iso9660->opt.zisofs = OPT_ZISOFS_DISABLED;
- else {
-#ifdef HAVE_ZLIB_H
- iso9660->opt.zisofs = OPT_ZISOFS_DIRECT;
-#else
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "``zisofs'' "
- "is not supported on this platform.");
- return (ARCHIVE_FATAL);
-#endif
- }
- return (ARCHIVE_OK);
- }
- break;
- }
-
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
-
-invalid_value:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid value for option ``%s''", key);
- return (ARCHIVE_FAILED);
-}
-
-static int
-iso9660_write_header(struct archive_write *a, struct archive_entry *entry)
-{
- struct iso9660 *iso9660;
- struct isofile *file;
- struct isoent *isoent;
- int r, ret = ARCHIVE_OK;
-
- iso9660 = a->format_data;
-
- iso9660->cur_file = NULL;
- iso9660->bytes_remaining = 0;
- iso9660->need_multi_extent = 0;
- if (archive_entry_filetype(entry) == AE_IFLNK
- && iso9660->opt.rr == OPT_RR_DISABLED) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Ignore symlink file.");
- iso9660->cur_file = NULL;
- return (ARCHIVE_WARN);
- }
- if (archive_entry_filetype(entry) == AE_IFREG &&
- archive_entry_size(entry) >= MULTI_EXTENT_SIZE) {
- if (iso9660->opt.iso_level < 3) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Ignore over %lld bytes file. "
- "This file too large.",
- MULTI_EXTENT_SIZE);
- iso9660->cur_file = NULL;
- return (ARCHIVE_WARN);
- }
- iso9660->need_multi_extent = 1;
- }
-
- file = isofile_new(a, entry);
- if (file == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate data");
- return (ARCHIVE_FATAL);
- }
- r = isofile_gen_utility_names(a, file);
- if (r < ARCHIVE_WARN) {
- isofile_free(file);
- return (r);
- }
- else if (r < ret)
- ret = r;
-
- /*
- * Ignore a path which looks like the top of directory name
- * since we have already made the root directory of an ISO image.
- */
- if (archive_strlen(&(file->parentdir)) == 0 &&
- archive_strlen(&(file->basename)) == 0) {
- isofile_free(file);
- return (r);
- }
-
- isofile_add_entry(iso9660, file);
- isoent = isoent_new(file);
- if (isoent == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate data");
- return (ARCHIVE_FATAL);
- }
- if (isoent->file->dircnt > iso9660->dircnt_max)
- iso9660->dircnt_max = isoent->file->dircnt;
-
- /* Add the current file into tree */
- r = isoent_tree(a, &isoent);
- if (r != ARCHIVE_OK)
- return (r);
-
- /* If there is the same file in tree and
- * the current file is older than the file in tree.
- * So we don't need the current file data anymore. */
- if (isoent->file != file)
- return (ARCHIVE_OK);
-
- /* Non regular files contents are unneeded to be saved to
- * temporary files. */
- if (archive_entry_filetype(file->entry) != AE_IFREG)
- return (ret);
-
- /*
- * Set the current file to cur_file to read its contents.
- */
- iso9660->cur_file = file;
-
- if (archive_entry_nlink(file->entry) > 1) {
- r = isofile_register_hardlink(a, file);
- if (r != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
-
- /*
- * Prepare to save the contents of the file.
- */
- if (iso9660->temp_fd < 0) {
- iso9660->temp_fd = __archive_mktemp(NULL);
- if (iso9660->temp_fd < 0) {
- archive_set_error(&a->archive, errno,
- "Couldn't create temporary file");
- return (ARCHIVE_FATAL);
- }
- }
-
- /* Save an offset of current file in temporary file. */
- file->content.offset_of_temp = wb_offset(a);
- file->cur_content = &(file->content);
- r = zisofs_init(a, file);
- if (r < ret)
- ret = r;
- iso9660->bytes_remaining = archive_entry_size(file->entry);
-
- return (ret);
-}
-
-static int
-write_to_temp(struct archive_write *a, const void *buff, size_t s)
-{
- struct iso9660 *iso9660 = a->format_data;
- ssize_t written;
- const unsigned char *b;
-
- b = (const unsigned char *)buff;
- while (s) {
- written = write(iso9660->temp_fd, b, s);
- if (written < 0) {
- archive_set_error(&a->archive, errno,
- "Can't write to temporary file");
- return (ARCHIVE_FATAL);
- }
- s -= written;
- b += written;
- }
- return (ARCHIVE_OK);
-}
-
-static int
-wb_write_to_temp(struct archive_write *a, const void *buff, size_t s)
-{
- const char *xp = buff;
- size_t xs = s;
-
- /*
- * If a written data size is big enough to use system-call
- * and there is no waiting data, this calls write_to_temp() in
- * order to reduce a extra memory copy.
- */
- if (wb_remaining(a) == wb_buffmax() && s > (1024 * 16)) {
- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
- xs = s % LOGICAL_BLOCK_SIZE;
- iso9660->wbuff_offset += s - xs;
- if (write_to_temp(a, buff, s - xs) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- if (xs == 0)
- return (ARCHIVE_OK);
- xp += s - xs;
- }
-
- while (xs) {
- size_t size = xs;
- if (size > wb_remaining(a))
- size = wb_remaining(a);
- memcpy(wb_buffptr(a), xp, size);
- if (wb_consume(a, size) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- xs -= size;
- xp += size;
- }
- return (ARCHIVE_OK);
-}
-
-static int
-wb_write_padding_to_temp(struct archive_write *a, int64_t csize)
-{
- size_t ns;
- int ret;
-
- ns = (size_t)(csize % LOGICAL_BLOCK_SIZE);
- if (ns != 0)
- ret = write_null(a, LOGICAL_BLOCK_SIZE - ns);
- else
- ret = ARCHIVE_OK;
- return (ret);
-}
-
-static ssize_t
-write_iso9660_data(struct archive_write *a, const void *buff, size_t s)
-{
- struct iso9660 *iso9660 = a->format_data;
- size_t ws;
-
- if (iso9660->temp_fd < 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Couldn't create temporary file");
- return (ARCHIVE_FATAL);
- }
-
- ws = s;
- if (iso9660->need_multi_extent &&
- (iso9660->cur_file->cur_content->size + ws) >=
- (MULTI_EXTENT_SIZE - LOGICAL_BLOCK_SIZE)) {
- struct content *con;
- size_t ts;
-
- ts = (size_t)(MULTI_EXTENT_SIZE - LOGICAL_BLOCK_SIZE -
- iso9660->cur_file->cur_content->size);
-
- if (iso9660->zisofs.detect_magic)
- zisofs_detect_magic(a, buff, ts);
-
- if (iso9660->zisofs.making) {
- if (zisofs_write_to_temp(a, buff, ts) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- } else {
- if (wb_write_to_temp(a, buff, ts) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- iso9660->cur_file->cur_content->size += ts;
- }
-
- /* Write padding. */
- if (wb_write_padding_to_temp(a,
- iso9660->cur_file->cur_content->size) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- /* Compute the logical block number. */
- iso9660->cur_file->cur_content->blocks = (int)
- ((iso9660->cur_file->cur_content->size
- + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);
-
- /*
- * Make next extent.
- */
- ws -= ts;
- buff = (const void *)(((const unsigned char *)buff) + ts);
- /* Make a content for next extent. */
- con = calloc(1, sizeof(*con));
- if (con == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate content data");
- return (ARCHIVE_FATAL);
- }
- con->offset_of_temp = wb_offset(a);
- iso9660->cur_file->cur_content->next = con;
- iso9660->cur_file->cur_content = con;
-#ifdef HAVE_ZLIB_H
- iso9660->zisofs.block_offset = 0;
-#endif
- }
-
- if (iso9660->zisofs.detect_magic)
- zisofs_detect_magic(a, buff, ws);
-
- if (iso9660->zisofs.making) {
- if (zisofs_write_to_temp(a, buff, ws) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- } else {
- if (wb_write_to_temp(a, buff, ws) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- iso9660->cur_file->cur_content->size += ws;
- }
-
- return (s);
-}
-
-static ssize_t
-iso9660_write_data(struct archive_write *a, const void *buff, size_t s)
-{
- struct iso9660 *iso9660 = a->format_data;
- ssize_t r;
-
- if (iso9660->cur_file == NULL)
- return (0);
- if (archive_entry_filetype(iso9660->cur_file->entry) != AE_IFREG)
- return (0);
- if (s > iso9660->bytes_remaining)
- s = (size_t)iso9660->bytes_remaining;
- if (s == 0)
- return (0);
-
- r = write_iso9660_data(a, buff, s);
- if (r > 0)
- iso9660->bytes_remaining -= r;
- return (r);
-}
-
-static int
-iso9660_finish_entry(struct archive_write *a)
-{
- struct iso9660 *iso9660 = a->format_data;
-
- if (iso9660->cur_file == NULL)
- return (ARCHIVE_OK);
- if (archive_entry_filetype(iso9660->cur_file->entry) != AE_IFREG)
- return (ARCHIVE_OK);
- if (iso9660->cur_file->content.size == 0)
- return (ARCHIVE_OK);
-
- /* If there are unwritten data, write null data instead. */
- while (iso9660->bytes_remaining > 0) {
- size_t s;
-
- s = (iso9660->bytes_remaining > a->null_length)?
- a->null_length: (size_t)iso9660->bytes_remaining;
- if (write_iso9660_data(a, a->nulls, s) < 0)
- return (ARCHIVE_FATAL);
- iso9660->bytes_remaining -= s;
- }
-
- if (iso9660->zisofs.making && zisofs_finish_entry(a) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- /* Write padding. */
- if (wb_write_padding_to_temp(a, iso9660->cur_file->cur_content->size)
- != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- /* Compute the logical block number. */
- iso9660->cur_file->cur_content->blocks = (int)
- ((iso9660->cur_file->cur_content->size
- + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);
-
- /* Add the current file to data file list. */
- isofile_add_data_file(iso9660, iso9660->cur_file);
-
- return (ARCHIVE_OK);
-}
-
-static int
-iso9660_close(struct archive_write *a)
-{
- struct iso9660 *iso9660;
- int ret, blocks;
-
- iso9660 = a->format_data;
-
- /*
- * Write remaining data out to the temporary file.
- */
- if (wb_remaining(a) > 0) {
- ret = wb_write_out(a);
- if (ret < 0)
- return (ret);
- }
-
- /*
- * Preparations...
- */
-#ifdef DEBUG
- if (iso9660->birth_time == 0)
-#endif
- time(&(iso9660->birth_time));
-
- /*
- * Prepare a bootable ISO image.
- */
- if (iso9660->opt.boot) {
- /* Find out the boot file entry. */
- ret = isoent_find_out_boot_file(a, iso9660->primary.rootent);
- if (ret < 0)
- return (ret);
- /* Reconvert the boot file from zisofs'ed form to
- * plain form. */
- ret = zisofs_rewind_boot_file(a);
- if (ret < 0)
- return (ret);
- /* Write remaining data out to the temporary file. */
- if (wb_remaining(a) > 0) {
- ret = wb_write_out(a);
- if (ret < 0)
- return (ret);
- }
- /* Create the boot catalog. */
- ret = isoent_create_boot_catalog(a, iso9660->primary.rootent);
- if (ret < 0)
- return (ret);
- }
-
- /*
- * Prepare joliet extensions.
- */
- if (iso9660->opt.joliet) {
- /* Make a new tree for joliet. */
- ret = isoent_clone_tree(a, &(iso9660->joliet.rootent),
- iso9660->primary.rootent);
- if (ret < 0)
- return (ret);
- /* Make sure we have UTF-16BE convertors.
- * if there is no file entry, convertors are still
- * uninitilized. */
- if (iso9660->sconv_to_utf16be == NULL) {
- iso9660->sconv_to_utf16be =
- archive_string_conversion_to_charset(
- &(a->archive), "UTF-16BE", 1);
- if (iso9660->sconv_to_utf16be == NULL)
- /* Couldn't allocate memory */
- return (ARCHIVE_FATAL);
- iso9660->sconv_from_utf16be =
- archive_string_conversion_from_charset(
- &(a->archive), "UTF-16BE", 1);
- if (iso9660->sconv_from_utf16be == NULL)
- /* Couldn't allocate memory */
- return (ARCHIVE_FATAL);
- }
- }
-
- /*
- * Make Path Tables.
- */
- ret = isoent_make_path_table(a);
- if (ret < 0)
- return (ret);
-
- /*
- * Calculate a total volume size and setup all locations of
- * contents of an iso9660 image.
- */
- blocks = SYSTEM_AREA_BLOCK
- + PRIMARY_VOLUME_DESCRIPTOR_BLOCK
- + VOLUME_DESCRIPTOR_SET_TERMINATOR_BLOCK
- + NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK;
- if (iso9660->opt.boot)
- blocks += BOOT_RECORD_DESCRIPTOR_BLOCK;
- if (iso9660->opt.joliet)
- blocks += SUPPLEMENTARY_VOLUME_DESCRIPTOR_BLOCK;
- if (iso9660->opt.iso_level == 4)
- blocks += SUPPLEMENTARY_VOLUME_DESCRIPTOR_BLOCK;
-
- /* Setup the locations of Path Table. */
- iso9660->primary.location_type_L_path_table = blocks;
- blocks += iso9660->primary.path_table_block;
- iso9660->primary.location_type_M_path_table = blocks;
- blocks += iso9660->primary.path_table_block;
- if (iso9660->opt.joliet) {
- iso9660->joliet.location_type_L_path_table = blocks;
- blocks += iso9660->joliet.path_table_block;
- iso9660->joliet.location_type_M_path_table = blocks;
- blocks += iso9660->joliet.path_table_block;
- }
-
- /* Setup the locations of directories. */
- isoent_setup_directory_location(iso9660, blocks,
- &(iso9660->primary));
- blocks += iso9660->primary.total_dir_block;
- if (iso9660->opt.joliet) {
- isoent_setup_directory_location(iso9660, blocks,
- &(iso9660->joliet));
- blocks += iso9660->joliet.total_dir_block;
- }
-
- if (iso9660->opt.rr) {
- iso9660->location_rrip_er = blocks;
- blocks += RRIP_ER_BLOCK;
- }
-
- /* Setup the locations of all file contents. */
- isoent_setup_file_location(iso9660, blocks);
- blocks += iso9660->total_file_block;
- if (iso9660->opt.boot && iso9660->opt.boot_info_table) {
- ret = setup_boot_information(a);
- if (ret < 0)
- return (ret);
- }
-
- /* Now we have a total volume size. */
- iso9660->volume_space_size = blocks;
- if (iso9660->opt.pad)
- iso9660->volume_space_size += PADDING_BLOCK;
- iso9660->volume_sequence_number = 1;
-
-
- /*
- * Write an ISO 9660 image.
- */
-
- /* Switc to start using wbuff as file buffer. */
- iso9660->wbuff_remaining = wb_buffmax();
- iso9660->wbuff_type = WB_TO_STREAM;
- iso9660->wbuff_offset = 0;
- iso9660->wbuff_written = 0;
- iso9660->wbuff_tail = 0;
-
- /* Write The System Area */
- ret = write_null(a, SYSTEM_AREA_BLOCK * LOGICAL_BLOCK_SIZE);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- /* Write Primary Volume Descriptor */
- ret = write_VD(a, &(iso9660->primary));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- if (iso9660->opt.boot) {
- /* Write Boot Record Volume Descriptor */
- ret = write_VD_boot_record(a);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
-
- if (iso9660->opt.iso_level == 4) {
- /* Write Enhanced Volume Descriptor */
- iso9660->primary.vdd_type = VDD_ENHANCED;
- ret = write_VD(a, &(iso9660->primary));
- iso9660->primary.vdd_type = VDD_PRIMARY;
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
-
- if (iso9660->opt.joliet) {
- ret = write_VD(a, &(iso9660->joliet));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
-
- /* Write Volume Descriptor Set Terminator */
- ret = write_VD_terminator(a);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- /* Write Non-ISO File System Information */
- ret = write_information_block(a);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- /* Write Type L Path Table */
- ret = write_path_table(a, 0, &(iso9660->primary));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- /* Write Type M Path Table */
- ret = write_path_table(a, 1, &(iso9660->primary));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- if (iso9660->opt.joliet) {
- /* Write Type L Path Table */
- ret = write_path_table(a, 0, &(iso9660->joliet));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- /* Write Type M Path Table */
- ret = write_path_table(a, 1, &(iso9660->joliet));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
-
- /* Write Directory Descriptors */
- ret = write_directory_descriptors(a, &(iso9660->primary));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- if (iso9660->opt.joliet) {
- ret = write_directory_descriptors(a, &(iso9660->joliet));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
-
- if (iso9660->opt.rr) {
- /* Write Rockridge ER(Extensions Reference) */
- ret = write_rr_ER(a);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
-
- /* Write File Descriptors */
- ret = write_file_descriptors(a);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- /* Write Padding */
- if (iso9660->opt.pad) {
- ret = write_null(a, PADDING_BLOCK * LOGICAL_BLOCK_SIZE);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
-
- if (iso9660->directories_too_deep != NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "%s: Directories too deep.",
- archive_entry_pathname(
- iso9660->directories_too_deep->file->entry));
- return (ARCHIVE_WARN);
- }
-
- /* Write remaining data out. */
- ret = wb_write_out(a);
-
- return (ret);
-}
-
-static int
-iso9660_free(struct archive_write *a)
-{
- struct iso9660 *iso9660;
- int i, ret;
-
- iso9660 = a->format_data;
-
- /* Close the temporary file. */
- if (iso9660->temp_fd >= 0)
- close(iso9660->temp_fd);
-
- /* Free some stuff for zisofs operations. */
- ret = zisofs_free(a);
-
- /* Remove directory entries in tree which includes file entries. */
- isoent_free_all(iso9660->primary.rootent);
- for (i = 0; i < iso9660->primary.max_depth; i++)
- free(iso9660->primary.pathtbl[i].sorted);
- free(iso9660->primary.pathtbl);
-
- if (iso9660->opt.joliet) {
- isoent_free_all(iso9660->joliet.rootent);
- for (i = 0; i < iso9660->joliet.max_depth; i++)
- free(iso9660->joliet.pathtbl[i].sorted);
- free(iso9660->joliet.pathtbl);
- }
-
- /* Remove isofile entries. */
- isofile_free_all_entries(iso9660);
- isofile_free_hardlinks(iso9660);
-
- archive_string_free(&(iso9660->cur_dirstr));
- archive_string_free(&(iso9660->volume_identifier));
- archive_string_free(&(iso9660->publisher_identifier));
- archive_string_free(&(iso9660->data_preparer_identifier));
- archive_string_free(&(iso9660->application_identifier));
- archive_string_free(&(iso9660->copyright_file_identifier));
- archive_string_free(&(iso9660->abstract_file_identifier));
- archive_string_free(&(iso9660->bibliographic_file_identifier));
- archive_string_free(&(iso9660->el_torito.catalog_filename));
- archive_string_free(&(iso9660->el_torito.boot_filename));
- archive_string_free(&(iso9660->el_torito.id));
- archive_string_free(&(iso9660->utf16be));
- archive_string_free(&(iso9660->mbs));
-
- free(iso9660);
- a->format_data = NULL;
-
- return (ret);
-}
-
-/*
- * Get the System Identifier
- */
-static void
-get_system_identitier(char *system_id, size_t size)
-{
-#if defined(HAVE_SYS_UTSNAME_H)
- struct utsname u;
-
- uname(&u);
- strncpy(system_id, u.sysname, size-1);
- system_id[size-1] = '\0';
-#elif defined(_WIN32) && !defined(__CYGWIN__)
- strncpy(system_id, "Windows", size-1);
- system_id[size-1] = '\0';
-#else
-#error no way to get the system identifier on your platform.
-#endif
-}
-
-static void
-set_str(unsigned char *p, const char *s, size_t l, char f, const char *map)
-{
- unsigned char c;
-
- if (s == NULL)
- s = "";
- while ((c = *s++) != 0 && l > 0) {
- if (c >= 0x80 || map[c] == 0)
- {
- /* illegal character */
- if (c >= 'a' && c <= 'z') {
- /* convert c from a-z to A-Z */
- c -= 0x20;
- } else
- c = 0x5f;
- }
- *p++ = c;
- l--;
- }
- /* If l isn't zero, fill p buffer by the character
- * which indicated by f. */
- if (l > 0)
- memset(p , f, l);
-}
-
-static inline int
-joliet_allowed_char(unsigned char high, unsigned char low)
-{
- int utf16 = (high << 8) | low;
-
- if (utf16 <= 0x001F)
- return (0);
-
- switch (utf16) {
- case 0x002A: /* '*' */
- case 0x002F: /* '/' */
- case 0x003A: /* ':' */
- case 0x003B: /* ';' */
- case 0x003F: /* '?' */
- case 0x005C: /* '\' */
- return (0);/* Not allowed. */
- }
- return (1);
-}
-
-static int
-set_str_utf16be(struct archive_write *a, unsigned char *p, const char *s,
- size_t l, uint16_t uf, enum vdc vdc)
-{
- size_t size, i;
- int onepad;
-
- if (s == NULL)
- s = "";
- if (l & 0x01) {
- onepad = 1;
- l &= ~1;
- } else
- onepad = 0;
- if (vdc == VDC_UCS2) {
- struct iso9660 *iso9660 = a->format_data;
- if (archive_strncpy_l(&iso9660->utf16be, s, strlen(s),
- iso9660->sconv_to_utf16be) != 0 && errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for UTF-16BE");
- return (ARCHIVE_FATAL);
- }
- size = iso9660->utf16be.length;
- if (size > l)
- size = l;
- memcpy(p, iso9660->utf16be.s, size);
- } else {
- const uint16_t *u16 = (const uint16_t *)s;
-
- size = 0;
- while (*u16++)
- size += 2;
- if (size > l)
- size = l;
- memcpy(p, s, size);
- }
- for (i = 0; i < size; i += 2, p += 2) {
- if (!joliet_allowed_char(p[0], p[1]))
- archive_be16enc(p, 0x005F);/* '_' */
- }
- l -= size;
- while (l > 0) {
- archive_be16enc(p, uf);
- p += 2;
- l -= 2;
- }
- if (onepad)
- *p = 0;
- return (ARCHIVE_OK);
-}
-
-static const char a_characters_map[0x80] = {
-/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */
- 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20-2F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30-3F */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 60-6F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 70-7F */
-};
-
-static const char a1_characters_map[0x80] = {
-/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */
- 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20-2F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30-3F */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60-6F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,/* 70-7F */
-};
-
-static const char d_characters_map[0x80] = {
-/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 20-2F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,/* 30-3F */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 60-6F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 70-7F */
-};
-
-static const char d1_characters_map[0x80] = {
-/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 20-2F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,/* 30-3F */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60-6F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,/* 70-7F */
-};
-
-static int
-set_str_a_characters_bp(struct archive_write *a, unsigned char *bp,
- int from, int to, const char *s, enum vdc vdc)
-{
- int r;
-
- switch (vdc) {
- case VDC_STD:
- set_str(bp+from, s, to - from + 1, 0x20,
- a_characters_map);
- r = ARCHIVE_OK;
- break;
- case VDC_LOWERCASE:
- set_str(bp+from, s, to - from + 1, 0x20,
- a1_characters_map);
- r = ARCHIVE_OK;
- break;
- case VDC_UCS2:
- case VDC_UCS2_DIRECT:
- r = set_str_utf16be(a, bp+from, s, to - from + 1,
- 0x0020, vdc);
- break;
- default:
- r = ARCHIVE_FATAL;
- }
- return (r);
-}
-
-static int
-set_str_d_characters_bp(struct archive_write *a, unsigned char *bp,
- int from, int to, const char *s, enum vdc vdc)
-{
- int r;
-
- switch (vdc) {
- case VDC_STD:
- set_str(bp+from, s, to - from + 1, 0x20,
- d_characters_map);
- r = ARCHIVE_OK;
- break;
- case VDC_LOWERCASE:
- set_str(bp+from, s, to - from + 1, 0x20,
- d1_characters_map);
- r = ARCHIVE_OK;
- break;
- case VDC_UCS2:
- case VDC_UCS2_DIRECT:
- r = set_str_utf16be(a, bp+from, s, to - from + 1,
- 0x0020, vdc);
- break;
- default:
- r = ARCHIVE_FATAL;
- }
- return (r);
-}
-
-static void
-set_VD_bp(unsigned char *bp, enum VD_type type, unsigned char ver)
-{
-
- /* Volume Descriptor Type */
- bp[1] = (unsigned char)type;
- /* Standard Identifier */
- memcpy(bp + 2, "CD001", 5);
- /* Volume Descriptor Version */
- bp[7] = ver;
-}
-
-static inline void
-set_unused_field_bp(unsigned char *bp, int from, int to)
-{
- memset(bp + from, 0, to - from + 1);
-}
-
-/*
- * 8-bit unsigned numerical values.
- * ISO9660 Standard 7.1.1
- */
-static inline void
-set_num_711(unsigned char *p, unsigned char value)
-{
- *p = value;
-}
-
-/*
- * 8-bit signed numerical values.
- * ISO9660 Standard 7.1.2
- */
-static inline void
-set_num_712(unsigned char *p, char value)
-{
- *((char *)p) = value;
-}
-
-/*
- * Least significant byte first.
- * ISO9660 Standard 7.2.1
- */
-static inline void
-set_num_721(unsigned char *p, uint16_t value)
-{
- archive_le16enc(p, value);
-}
-
-/*
- * Most significant byte first.
- * ISO9660 Standard 7.2.2
- */
-static inline void
-set_num_722(unsigned char *p, uint16_t value)
-{
- archive_be16enc(p, value);
-}
-
-/*
- * Both-byte orders.
- * ISO9660 Standard 7.2.3
- */
-static void
-set_num_723(unsigned char *p, uint16_t value)
-{
- archive_le16enc(p, value);
- archive_be16enc(p+2, value);
-}
-
-/*
- * Least significant byte first.
- * ISO9660 Standard 7.3.1
- */
-static inline void
-set_num_731(unsigned char *p, uint32_t value)
-{
- archive_le32enc(p, value);
-}
-
-/*
- * Most significant byte first.
- * ISO9660 Standard 7.3.2
- */
-static inline void
-set_num_732(unsigned char *p, uint32_t value)
-{
- archive_be32enc(p, value);
-}
-
-/*
- * Both-byte orders.
- * ISO9660 Standard 7.3.3
- */
-static inline void
-set_num_733(unsigned char *p, uint32_t value)
-{
- archive_le32enc(p, value);
- archive_be32enc(p+4, value);
-}
-
-static void
-set_digit(unsigned char *p, size_t s, int value)
-{
-
- while (s--) {
- p[s] = '0' + (value % 10);
- value /= 10;
- }
-}
-
-#if defined(HAVE_STRUCT_TM_TM_GMTOFF)
-#define get_gmoffset(tm) ((tm)->tm_gmtoff)
-#elif defined(HAVE_STRUCT_TM___TM_GMTOFF)
-#define get_gmoffset(tm) ((tm)->__tm_gmtoff)
-#else
-static long
-get_gmoffset(struct tm *tm)
-{
- long offset;
-
-#if defined(HAVE__GET_TIMEZONE)
- _get_timezone(&offset);
-#elif defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
- offset = _timezone;
-#else
- offset = timezone;
-#endif
- offset *= -1;
- if (tm->tm_isdst)
- offset += 3600;
- return (offset);
-}
-#endif
-
-static void
-get_tmfromtime(struct tm *tm, time_t *t)
-{
-#if HAVE_LOCALTIME_R
- tzset();
- localtime_r(t, tm);
-#elif HAVE__LOCALTIME64_S
- _localtime64_s(tm, t);
-#else
- memcpy(tm, localtime(t), sizeof(*tm));
-#endif
-}
-
-/*
- * Date and Time Format.
- * ISO9660 Standard 8.4.26.1
- */
-static void
-set_date_time(unsigned char *p, time_t t)
-{
- struct tm tm;
-
- get_tmfromtime(&tm, &t);
- set_digit(p, 4, tm.tm_year + 1900);
- set_digit(p+4, 2, tm.tm_mon + 1);
- set_digit(p+6, 2, tm.tm_mday);
- set_digit(p+8, 2, tm.tm_hour);
- set_digit(p+10, 2, tm.tm_min);
- set_digit(p+12, 2, tm.tm_sec);
- set_digit(p+14, 2, 0);
- set_num_712(p+16, (char)(get_gmoffset(&tm)/(60*15)));
-}
-
-static void
-set_date_time_null(unsigned char *p)
-{
- memset(p, '0', 16);
- p[16] = 0;
-}
-
-static void
-set_time_915(unsigned char *p, time_t t)
-{
- struct tm tm;
-
- get_tmfromtime(&tm, &t);
- set_num_711(p+0, tm.tm_year);
- set_num_711(p+1, tm.tm_mon+1);
- set_num_711(p+2, tm.tm_mday);
- set_num_711(p+3, tm.tm_hour);
- set_num_711(p+4, tm.tm_min);
- set_num_711(p+5, tm.tm_sec);
- set_num_712(p+6, (char)(get_gmoffset(&tm)/(60*15)));
-}
-
-
-/*
- * Write SUSP "CE" System Use Entry.
- */
-static int
-set_SUSP_CE(unsigned char *p, int location, int offset, int size)
-{
- unsigned char *bp = p -1;
- /* Extend the System Use Area
- * "CE" Format:
- * len ver
- * +----+----+----+----+-----------+-----------+
- * | 'C'| 'E'| 1C | 01 | LOCATION1 | LOCATION2 |
- * +----+----+----+----+-----------+-----------+
- * 0 1 2 3 4 12 20
- * +-----------+
- * | LOCATION3 |
- * +-----------+
- * 20 28
- * LOCATION1 : Location of Continuation of System Use Area.
- * LOCATION2 : Offset to Start of Continuation.
- * LOCATION3 : Length of the Continuation.
- */
-
- bp[1] = 'C';
- bp[2] = 'E';
- bp[3] = RR_CE_SIZE; /* length */
- bp[4] = 1; /* version */
- set_num_733(bp+5, location);
- set_num_733(bp+13, offset);
- set_num_733(bp+21, size);
- return (RR_CE_SIZE);
-}
-
-/*
- * The functions, which names are beginning with extra_, are used to
- * control extra records.
- * The maximum size of a Directory Record is 254. When a filename is
- * very long, all of RRIP data of a file won't stored to the Directory
- * Record and so remaining RRIP data store to an extra record instead.
- */
-static unsigned char *
-extra_open_record(unsigned char *bp, int dr_len, struct isoent *isoent,
- struct ctl_extr_rec *ctl)
-{
- ctl->bp = bp;
- if (bp != NULL)
- bp += dr_len;
- ctl->use_extr = 0;
- ctl->isoent = isoent;
- ctl->ce_ptr = NULL;
- ctl->cur_len = ctl->dr_len = dr_len;
- ctl->limit = DR_LIMIT;
-
- return (bp);
-}
-
-static void
-extra_close_record(struct ctl_extr_rec *ctl, int ce_size)
-{
- int padding = 0;
-
- if (ce_size > 0)
- extra_tell_used_size(ctl, ce_size);
- /* Padding. */
- if (ctl->cur_len & 0x01) {
- ctl->cur_len++;
- if (ctl->bp != NULL)
- ctl->bp[ctl->cur_len] = 0;
- padding = 1;
- }
- if (ctl->use_extr) {
- if (ctl->ce_ptr != NULL)
- set_SUSP_CE(ctl->ce_ptr, ctl->extr_loc,
- ctl->extr_off, ctl->cur_len - padding);
- } else
- ctl->dr_len = ctl->cur_len;
-}
-
-#define extra_space(ctl) ((ctl)->limit - (ctl)->cur_len)
-
-static unsigned char *
-extra_next_record(struct ctl_extr_rec *ctl, int length)
-{
- int cur_len = ctl->cur_len;/* save cur_len */
-
- /* Close the current extra record or Directory Record. */
- extra_close_record(ctl, RR_CE_SIZE);
-
- /* Get a next extra record. */
- ctl->use_extr = 1;
- if (ctl->bp != NULL) {
- /* Storing data into an extra record. */
- unsigned char *p;
-
- /* Save the pointer where a CE extension will be
- * stored to. */
- ctl->ce_ptr = &ctl->bp[cur_len+1];
- p = extra_get_record(ctl->isoent,
- &ctl->limit, &ctl->extr_off, &ctl->extr_loc);
- ctl->bp = p - 1;/* the base of bp offset is 1. */
- } else
- /* Calculating the size of an extra record. */
- (void)extra_get_record(ctl->isoent,
- &ctl->limit, NULL, NULL);
- ctl->cur_len = 0;
- /* Check if an extra record is almost full.
- * If so, get a next one. */
- if (extra_space(ctl) < length)
- (void)extra_next_record(ctl, length);
-
- return (ctl->bp);
-}
-
-static inline struct extr_rec *
-extra_last_record(struct isoent *isoent)
-{
- if (isoent->extr_rec_list.first == NULL)
- return (NULL);
- return ((struct extr_rec *)(void *)
- ((char *)(isoent->extr_rec_list.last)
- - offsetof(struct extr_rec, next)));
-}
-
-static unsigned char *
-extra_get_record(struct isoent *isoent, int *space, int *off, int *loc)
-{
- struct extr_rec *rec;
-
- isoent = isoent->parent;
- if (off != NULL) {
- /* Storing data into an extra record. */
- rec = isoent->extr_rec_list.current;
- if (DR_SAFETY > LOGICAL_BLOCK_SIZE - rec->offset)
- rec = rec->next;
- } else {
- /* Calculating the size of an extra record. */
- rec = extra_last_record(isoent);
- if (rec == NULL ||
- DR_SAFETY > LOGICAL_BLOCK_SIZE - rec->offset) {
- rec = malloc(sizeof(*rec));
- if (rec == NULL)
- return (NULL);
- rec->location = 0;
- rec->offset = 0;
- /* Insert `rec` into the tail of isoent->extr_rec_list */
- rec->next = NULL;
- *isoent->extr_rec_list.last = rec;
- isoent->extr_rec_list.last = &(rec->next);
- }
- }
- *space = LOGICAL_BLOCK_SIZE - rec->offset - DR_SAFETY;
- if (*space & 0x01)
- *space -= 1;/* Keep padding space. */
- if (off != NULL)
- *off = rec->offset;
- if (loc != NULL)
- *loc = rec->location;
- isoent->extr_rec_list.current = rec;
-
- return (&rec->buf[rec->offset]);
-}
-
-static void
-extra_tell_used_size(struct ctl_extr_rec *ctl, int size)
-{
- struct isoent *isoent;
- struct extr_rec *rec;
-
- if (ctl->use_extr) {
- isoent = ctl->isoent->parent;
- rec = isoent->extr_rec_list.current;
- if (rec != NULL)
- rec->offset += size;
- }
- ctl->cur_len += size;
-}
-
-static int
-extra_setup_location(struct isoent *isoent, int location)
-{
- struct extr_rec *rec;
- int cnt;
-
- cnt = 0;
- rec = isoent->extr_rec_list.first;
- isoent->extr_rec_list.current = rec;
- while (rec) {
- cnt++;
- rec->location = location++;
- rec->offset = 0;
- rec = rec->next;
- }
- return (cnt);
-}
-
-/*
- * Create the RRIP entries.
- */
-static int
-set_directory_record_rr(unsigned char *bp, int dr_len,
- struct isoent *isoent, struct iso9660 *iso9660, enum dir_rec_type t)
-{
- /* Flags(BP 5) of the Rockridge "RR" System Use Field */
- unsigned char rr_flag;
-#define RR_USE_PX 0x01
-#define RR_USE_PN 0x02
-#define RR_USE_SL 0x04
-#define RR_USE_NM 0x08
-#define RR_USE_CL 0x10
-#define RR_USE_PL 0x20
-#define RR_USE_RE 0x40
-#define RR_USE_TF 0x80
- int length;
- struct ctl_extr_rec ctl;
- struct isoent *rr_parent, *pxent;
- struct isofile *file;
-
- bp = extra_open_record(bp, dr_len, isoent, &ctl);
-
- if (t == DIR_REC_PARENT) {
- rr_parent = isoent->rr_parent;
- pxent = isoent->parent;
- if (rr_parent != NULL)
- isoent = rr_parent;
- else
- isoent = isoent->parent;
- } else {
- rr_parent = NULL;
- pxent = isoent;
- }
- file = isoent->file;
-
- if (t != DIR_REC_NORMAL) {
- rr_flag = RR_USE_PX | RR_USE_TF;
- if (rr_parent != NULL)
- rr_flag |= RR_USE_PL;
- } else {
- rr_flag = RR_USE_PX | RR_USE_NM | RR_USE_TF;
- if (archive_entry_filetype(file->entry) == AE_IFLNK)
- rr_flag |= RR_USE_SL;
- if (isoent->rr_parent != NULL)
- rr_flag |= RR_USE_RE;
- if (isoent->rr_child != NULL)
- rr_flag |= RR_USE_CL;
- if (archive_entry_filetype(file->entry) == AE_IFCHR ||
- archive_entry_filetype(file->entry) == AE_IFBLK)
- rr_flag |= RR_USE_PN;
-#ifdef COMPAT_MKISOFS
- /*
- * mkisofs 2.01.01a63 records "RE" extension to
- * the entry of "rr_moved" directory.
- * I don't understand this behavior.
- */
- if (isoent->virtual &&
- isoent->parent == iso9660->primary.rootent &&
- strcmp(isoent->file->basename.s, "rr_moved") == 0)
- rr_flag |= RR_USE_RE;
-#endif
- }
-
- /* Write "SP" System Use Entry. */
- if (t == DIR_REC_SELF && isoent == isoent->parent) {
- length = 7;
- if (bp != NULL) {
- bp[1] = 'S';
- bp[2] = 'P';
- bp[3] = length;
- bp[4] = 1; /* version */
- bp[5] = 0xBE; /* Check Byte */
- bp[6] = 0xEF; /* Check Byte */
- bp[7] = 0;
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
- }
-
- /* Write "RR" System Use Entry. */
- length = 5;
- if (extra_space(&ctl) < length)
- bp = extra_next_record(&ctl, length);
- if (bp != NULL) {
- bp[1] = 'R';
- bp[2] = 'R';
- bp[3] = length;
- bp[4] = 1; /* version */
- bp[5] = rr_flag;
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
-
- /* Write "NM" System Use Entry. */
- if (rr_flag & RR_USE_NM) {
- /*
- * "NM" Format:
- * e.g. a basename is 'foo'
- * len ver flg
- * +----+----+----+----+----+----+----+----+
- * | 'N'| 'M'| 08 | 01 | 00 | 'f'| 'o'| 'o'|
- * +----+----+----+----+----+----+----+----+
- * <----------------- len ----------------->
- */
- size_t nmlen = file->basename.length;
- const char *nm = file->basename.s;
- size_t nmmax;
-
- if (extra_space(&ctl) < 6)
- bp = extra_next_record(&ctl, 6);
- if (bp != NULL) {
- bp[1] = 'N';
- bp[2] = 'M';
- bp[4] = 1; /* version */
- }
- nmmax = extra_space(&ctl);
- if (nmmax > 0xff)
- nmmax = 0xff;
- while (nmlen + 5 > nmmax) {
- length = (int)nmmax;
- if (bp != NULL) {
- bp[3] = length;
- bp[5] = 0x01;/* Alternate Name continues
- * in next "NM" field */
- memcpy(bp+6, nm, length - 5);
- bp += length;
- }
- nmlen -= length - 5;
- nm += length - 5;
- extra_tell_used_size(&ctl, length);
- if (extra_space(&ctl) < 6) {
- bp = extra_next_record(&ctl, 6);
- nmmax = extra_space(&ctl);
- if (nmmax > 0xff)
- nmmax = 0xff;
- }
- if (bp != NULL) {
- bp[1] = 'N';
- bp[2] = 'M';
- bp[4] = 1; /* version */
- }
- }
- length = 5 + (int)nmlen;
- if (bp != NULL) {
- bp[3] = length;
- bp[5] = 0;
- memcpy(bp+6, nm, nmlen);
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
- }
-
- /* Write "PX" System Use Entry. */
- if (rr_flag & RR_USE_PX) {
- /*
- * "PX" Format:
- * len ver
- * +----+----+----+----+-----------+-----------+
- * | 'P'| 'X'| 2C | 01 | FILE MODE | LINKS |
- * +----+----+----+----+-----------+-----------+
- * 0 1 2 3 4 12 20
- * +-----------+-----------+------------------+
- * | USER ID | GROUP ID |FILE SERIAL NUMBER|
- * +-----------+-----------+------------------+
- * 20 28 36 44
- */
- length = 44;
- if (extra_space(&ctl) < length)
- bp = extra_next_record(&ctl, length);
- if (bp != NULL) {
- mode_t mode;
- int64_t uid;
- int64_t gid;
-
- mode = archive_entry_mode(file->entry);
- uid = archive_entry_uid(file->entry);
- gid = archive_entry_gid(file->entry);
- if (iso9660->opt.rr == OPT_RR_USEFUL) {
- /*
- * This action is simular mkisofs -r option
- * but our rockridge=useful option does not
- * set a zero to uid and gid.
- */
- /* set all read bit ON */
- mode |= 0444;
-#if !defined(_WIN32) && !defined(__CYGWIN__)
- if (mode & 0111)
-#endif
- /* set all exec bit ON */
- mode |= 0111;
- /* clear all write bits. */
- mode &= ~0222;
- /* clear setuid,setgid,sticky bits. */
- mode &= ~07000;
- }
-
- bp[1] = 'P';
- bp[2] = 'X';
- bp[3] = length;
- bp[4] = 1; /* version */
- /* file mode */
- set_num_733(bp+5, mode);
- /* file links (stat.st_nlink) */
- set_num_733(bp+13,
- archive_entry_nlink(file->entry));
- set_num_733(bp+21, (uint32_t)uid);
- set_num_733(bp+29, (uint32_t)gid);
- /* File Serial Number */
- if (pxent->dir)
- set_num_733(bp+37, pxent->dir_location);
- else if (file->hardlink_target != NULL)
- set_num_733(bp+37,
- file->hardlink_target->cur_content->location);
- else
- set_num_733(bp+37,
- file->cur_content->location);
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
- }
-
- /* Write "SL" System Use Entry. */
- if (rr_flag & RR_USE_SL) {
- /*
- * "SL" Format:
- * e.g. a symbolic name is 'foo/bar'
- * len ver flg
- * +----+----+----+----+----+------------+
- * | 'S'| 'L'| 0F | 01 | 00 | components |
- * +----+----+----+----+----+-----+------+
- * 0 1 2 3 4 5 ...|... 15
- * <----------------- len --------+------>
- * components : |
- * cflg clen |
- * +----+----+----+----+----+ |
- * | 00 | 03 | 'f'| 'o'| 'o'| <---+
- * +----+----+----+----+----+ |
- * 5 6 7 8 9 10 |
- * cflg clen |
- * +----+----+----+----+----+ |
- * | 00 | 03 | 'b'| 'a'| 'r'| <---+
- * +----+----+----+----+----+
- * 10 11 12 13 14 15
- *
- * - cflg : flag of componet
- * - clen : length of componet
- */
- const char *sl;
- char sl_last;
-
- if (extra_space(&ctl) < 7)
- bp = extra_next_record(&ctl, 7);
- sl = file->symlink.s;
- sl_last = '\0';
- if (bp != NULL) {
- bp[1] = 'S';
- bp[2] = 'L';
- bp[4] = 1; /* version */
- }
- for (;;) {
- unsigned char *nc, *cf, *cl, cldmy = 0;
- int sllen, slmax;
-
- slmax = extra_space(&ctl);
- if (slmax > 0xff)
- slmax = 0xff;
- if (bp != NULL)
- nc = &bp[6];
- else
- nc = NULL;
- cf = cl = NULL;
- sllen = 0;
- while (*sl && sllen + 11 < slmax) {
- if (sl_last == '\0' && sl[0] == '/') {
- /*
- * flg len
- * +----+----+
- * | 08 | 00 | ROOT component.
- * +----+----+ ("/")
- *
- * Root component has to appear
- * at the first component only.
- */
- if (nc != NULL) {
- cf = nc++;
- *cf = 0x08; /* ROOT */
- *nc++ = 0;
- }
- sllen += 2;
- sl++;
- sl_last = '/';
- cl = NULL;
- continue;
- }
- if (((sl_last == '\0' || sl_last == '/') &&
- sl[0] == '.' && sl[1] == '.' &&
- (sl[2] == '/' || sl[2] == '\0')) ||
- (sl[0] == '/' &&
- sl[1] == '.' && sl[2] == '.' &&
- (sl[3] == '/' || sl[3] == '\0'))) {
- /*
- * flg len
- * +----+----+
- * | 04 | 00 | PARENT component.
- * +----+----+ ("..")
- */
- if (nc != NULL) {
- cf = nc++;
- *cf = 0x04; /* PARENT */
- *nc++ = 0;
- }
- sllen += 2;
- if (sl[0] == '/')
- sl += 3;/* skip "/.." */
- else
- sl += 2;/* skip ".." */
- sl_last = '.';
- cl = NULL;
- continue;
- }
- if (((sl_last == '\0' || sl_last == '/') &&
- sl[0] == '.' &&
- (sl[1] == '/' || sl[1] == '\0')) ||
- (sl[0] == '/' && sl[1] == '.' &&
- (sl[2] == '/' || sl[2] == '\0'))) {
- /*
- * flg len
- * +----+----+
- * | 02 | 00 | CURREENT component.
- * +----+----+ (".")
- */
- if (nc != NULL) {
- cf = nc++;
- *cf = 0x02; /* CURRENT */
- *nc++ = 0;
- }
- sllen += 2;
- if (sl[0] == '/')
- sl += 2;/* skip "/." */
- else
- sl ++; /* skip "." */
- sl_last = '.';
- cl = NULL;
- continue;
- }
- if (sl[0] == '/' || cl == NULL) {
- if (nc != NULL) {
- cf = nc++;
- *cf = 0;
- cl = nc++;
- *cl = 0;
- } else
- cl = &cldmy;
- sllen += 2;
- if (sl[0] == '/') {
- sl_last = *sl++;
- continue;
- }
- }
- sl_last = *sl++;
- if (nc != NULL) {
- *nc++ = sl_last;
- (*cl) ++;
- }
- sllen++;
- }
- if (*sl) {
- length = 5 + sllen;
- if (bp != NULL) {
- /*
- * Mark flg as CONTINUE component.
- */
- *cf |= 0x01;
- /*
- * len ver flg
- * +----+----+----+----+----+-
- * | 'S'| 'L'| XX | 01 | 01 |
- * +----+----+----+----+----+-
- * ^
- * continues in next "SL"
- */
- bp[3] = length;
- bp[5] = 0x01;/* This Symbolic Link
- * continues in next
- * "SL" field */
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
- if (extra_space(&ctl) < 11)
- bp = extra_next_record(&ctl, 11);
- if (bp != NULL) {
- /* Next 'SL' */
- bp[1] = 'S';
- bp[2] = 'L';
- bp[4] = 1; /* version */
- }
- } else {
- length = 5 + sllen;
- if (bp != NULL) {
- bp[3] = length;
- bp[5] = 0;
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
- break;
- }
- }
- }
-
- /* Write "TF" System Use Entry. */
- if (rr_flag & RR_USE_TF) {
- /*
- * "TF" Format:
- * len ver
- * +----+----+----+----+-----+-------------+
- * | 'T'| 'F'| XX | 01 |FLAGS| TIME STAMPS |
- * +----+----+----+----+-----+-------------+
- * 0 1 2 3 4 5 XX
- * TIME STAMPS : ISO 9660 Standard 9.1.5.
- * If TF_LONG_FORM FLAGS is set,
- * use ISO9660 Standard 8.4.26.1.
- */
-#define TF_CREATION 0x01 /* Creation time recorded */
-#define TF_MODIFY 0x02 /* Modification time recorded */
-#define TF_ACCESS 0x04 /* Last Access time recorded */
-#define TF_ATTRIBUTES 0x08 /* Last Attribute Change time recorded */
-#define TF_BACKUP 0x10 /* Last Backup time recorded */
-#define TF_EXPIRATION 0x20 /* Expiration time recorded */
-#define TF_EFFECTIVE 0x40 /* Effective time recorded */
-#define TF_LONG_FORM 0x80 /* ISO 9660 17-byte time format used */
- unsigned char tf_flags;
-
- length = 5;
- tf_flags = 0;
-#ifndef COMPAT_MKISOFS
- if (archive_entry_birthtime_is_set(file->entry) &&
- archive_entry_birthtime(file->entry) <=
- archive_entry_mtime(file->entry)) {
- length += 7;
- tf_flags |= TF_CREATION;
- }
-#endif
- if (archive_entry_mtime_is_set(file->entry)) {
- length += 7;
- tf_flags |= TF_MODIFY;
- }
- if (archive_entry_atime_is_set(file->entry)) {
- length += 7;
- tf_flags |= TF_ACCESS;
- }
- if (archive_entry_ctime_is_set(file->entry)) {
- length += 7;
- tf_flags |= TF_ATTRIBUTES;
- }
- if (extra_space(&ctl) < length)
- bp = extra_next_record(&ctl, length);
- if (bp != NULL) {
- bp[1] = 'T';
- bp[2] = 'F';
- bp[3] = length;
- bp[4] = 1; /* version */
- bp[5] = tf_flags;
- bp += 5;
- /* Creation time */
- if (tf_flags & TF_CREATION) {
- set_time_915(bp+1,
- archive_entry_birthtime(file->entry));
- bp += 7;
- }
- /* Modification time */
- if (tf_flags & TF_MODIFY) {
- set_time_915(bp+1,
- archive_entry_mtime(file->entry));
- bp += 7;
- }
- /* Last Access time */
- if (tf_flags & TF_ACCESS) {
- set_time_915(bp+1,
- archive_entry_atime(file->entry));
- bp += 7;
- }
- /* Last Attribute Change time */
- if (tf_flags & TF_ATTRIBUTES) {
- set_time_915(bp+1,
- archive_entry_ctime(file->entry));
- bp += 7;
- }
- }
- extra_tell_used_size(&ctl, length);
- }
-
- /* Write "RE" System Use Entry. */
- if (rr_flag & RR_USE_RE) {
- /*
- * "RE" Format:
- * len ver
- * +----+----+----+----+
- * | 'R'| 'E'| 04 | 01 |
- * +----+----+----+----+
- * 0 1 2 3 4
- */
- length = 4;
- if (extra_space(&ctl) < length)
- bp = extra_next_record(&ctl, length);
- if (bp != NULL) {
- bp[1] = 'R';
- bp[2] = 'E';
- bp[3] = length;
- bp[4] = 1; /* version */
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
- }
-
- /* Write "PL" System Use Entry. */
- if (rr_flag & RR_USE_PL) {
- /*
- * "PL" Format:
- * len ver
- * +----+----+----+----+------------+
- * | 'P'| 'L'| 0C | 01 | *LOCATION |
- * +----+----+----+----+------------+
- * 0 1 2 3 4 12
- * *LOCATION: location of parent directory
- */
- length = 12;
- if (extra_space(&ctl) < length)
- bp = extra_next_record(&ctl, length);
- if (bp != NULL) {
- bp[1] = 'P';
- bp[2] = 'L';
- bp[3] = length;
- bp[4] = 1; /* version */
- set_num_733(bp + 5,
- rr_parent->dir_location);
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
- }
-
- /* Write "CL" System Use Entry. */
- if (rr_flag & RR_USE_CL) {
- /*
- * "CL" Format:
- * len ver
- * +----+----+----+----+------------+
- * | 'C'| 'L'| 0C | 01 | *LOCATION |
- * +----+----+----+----+------------+
- * 0 1 2 3 4 12
- * *LOCATION: location of child directory
- */
- length = 12;
- if (extra_space(&ctl) < length)
- bp = extra_next_record(&ctl, length);
- if (bp != NULL) {
- bp[1] = 'C';
- bp[2] = 'L';
- bp[3] = length;
- bp[4] = 1; /* version */
- set_num_733(bp + 5,
- isoent->rr_child->dir_location);
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
- }
-
- /* Write "PN" System Use Entry. */
- if (rr_flag & RR_USE_PN) {
- /*
- * "PN" Format:
- * len ver
- * +----+----+----+----+------------+------------+
- * | 'P'| 'N'| 14 | 01 | dev_t high | dev_t low |
- * +----+----+----+----+------------+------------+
- * 0 1 2 3 4 12 20
- */
- length = 20;
- if (extra_space(&ctl) < length)
- bp = extra_next_record(&ctl, length);
- if (bp != NULL) {
- uint64_t dev;
-
- bp[1] = 'P';
- bp[2] = 'N';
- bp[3] = length;
- bp[4] = 1; /* version */
- dev = (uint64_t)archive_entry_rdev(file->entry);
- set_num_733(bp + 5, (uint32_t)(dev >> 32));
- set_num_733(bp + 13, (uint32_t)(dev & 0xFFFFFFFF));
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
- }
-
- /* Write "ZF" System Use Entry. */
- if (file->zisofs.header_size) {
- /*
- * "ZF" Format:
- * len ver
- * +----+----+----+----+----+----+-------------+
- * | 'Z'| 'F'| 10 | 01 | 'p'| 'z'| Header Size |
- * +----+----+----+----+----+----+-------------+
- * 0 1 2 3 4 5 6 7
- * +--------------------+-------------------+
- * | Log2 of block Size | Uncompressed Size |
- * +--------------------+-------------------+
- * 7 8 16
- */
- length = 16;
- if (extra_space(&ctl) < length)
- bp = extra_next_record(&ctl, length);
- if (bp != NULL) {
- bp[1] = 'Z';
- bp[2] = 'F';
- bp[3] = length;
- bp[4] = 1; /* version */
- bp[5] = 'p';
- bp[6] = 'z';
- bp[7] = file->zisofs.header_size;
- bp[8] = file->zisofs.log2_bs;
- set_num_733(bp + 9, file->zisofs.uncompressed_size);
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
- }
-
- /* Write "CE" System Use Entry. */
- if (t == DIR_REC_SELF && isoent == isoent->parent) {
- length = RR_CE_SIZE;
- if (bp != NULL)
- set_SUSP_CE(bp+1, iso9660->location_rrip_er,
- 0, RRIP_ER_SIZE);
- extra_tell_used_size(&ctl, length);
- }
-
- extra_close_record(&ctl, 0);
-
- return (ctl.dr_len);
-}
-
-/*
- * Write data of a Directory Record or calculate writing bytes itself.
- * If parameter `p' is NULL, calculates the size of writing data, which
- * a Directory Record needs to write, then it saved and return
- * the calculated size.
- * Parameter `n' is a remaining size of buffer. when parameter `p' is
- * not NULL, check whether that `n' is not less than the saved size.
- * if that `n' is small, return zero.
- *
- * This format of the Directory Record is according to
- * ISO9660 Standard 9.1
- */
-static int
-set_directory_record(unsigned char *p, size_t n, struct isoent *isoent,
- struct iso9660 *iso9660, enum dir_rec_type t,
- enum vdd_type vdd_type)
-{
- unsigned char *bp;
- size_t dr_len;
- size_t fi_len;
-
- if (p != NULL) {
- /*
- * Check whether a write buffer size is less than the
- * saved size which is needed to write this Directory
- * Record.
- */
- switch (t) {
- case DIR_REC_VD:
- dr_len = isoent->dr_len.vd; break;
- case DIR_REC_SELF:
- dr_len = isoent->dr_len.self; break;
- case DIR_REC_PARENT:
- dr_len = isoent->dr_len.parent; break;
- case DIR_REC_NORMAL:
- default:
- dr_len = isoent->dr_len.normal; break;
- }
- if (dr_len > n)
- return (0);/* Needs more buffer size. */
- }
-
- if (t == DIR_REC_NORMAL && isoent->identifier != NULL)
- fi_len = isoent->id_len;
- else
- fi_len = 1;
-
- if (p != NULL) {
- struct isoent *xisoent;
- struct isofile *file;
- unsigned char flag;
-
- if (t == DIR_REC_PARENT)
- xisoent = isoent->parent;
- else
- xisoent = isoent;
- file = isoent->file;
- if (file->hardlink_target != NULL)
- file = file->hardlink_target;
- /* Make a file flag. */
- if (xisoent->dir)
- flag = FILE_FLAG_DIRECTORY;
- else {
- if (file->cur_content->next != NULL)
- flag = FILE_FLAG_MULTI_EXTENT;
- else
- flag = 0;
- }
-
- bp = p -1;
- /* Extended Attribute Record Length */
- set_num_711(bp+2, 0);
- /* Location of Extent */
- if (xisoent->dir)
- set_num_733(bp+3, xisoent->dir_location);
- else
- set_num_733(bp+3, file->cur_content->location);
- /* Data Length */
- if (xisoent->dir)
- set_num_733(bp+11,
- xisoent->dir_block * LOGICAL_BLOCK_SIZE);
- else
- set_num_733(bp+11, (uint32_t)file->cur_content->size);
- /* Recording Date and Time */
- /* NOTE:
- * If a file type is symbolic link, you are seeing this
- * field value is different from a value mkisofs makes.
- * libarchive uses lstat to get this one, but it
- * seems mkisofs uses stat to get.
- */
- set_time_915(bp+19,
- archive_entry_mtime(xisoent->file->entry));
- /* File Flags */
- bp[26] = flag;
- /* File Unit Size */
- set_num_711(bp+27, 0);
- /* Interleave Gap Size */
- set_num_711(bp+28, 0);
- /* Volume Sequence Number */
- set_num_723(bp+29, iso9660->volume_sequence_number);
- /* Length of File Identifier */
- set_num_711(bp+33, (unsigned char)fi_len);
- /* File Identifier */
- switch (t) {
- case DIR_REC_VD:
- case DIR_REC_SELF:
- set_num_711(bp+34, 0);
- break;
- case DIR_REC_PARENT:
- set_num_711(bp+34, 1);
- break;
- case DIR_REC_NORMAL:
- if (isoent->identifier != NULL)
- memcpy(bp+34, isoent->identifier, fi_len);
- else
- set_num_711(bp+34, 0);
- break;
- }
- } else
- bp = NULL;
- dr_len = 33 + fi_len;
- /* Padding Field */
- if (dr_len & 0x01) {
- dr_len ++;
- if (p != NULL)
- bp[dr_len] = 0;
- }
-
- /* Volume Descriptor does not record extension. */
- if (t == DIR_REC_VD) {
- if (p != NULL)
- /* Length of Directory Record */
- set_num_711(p, (unsigned char)dr_len);
- else
- isoent->dr_len.vd = (int)dr_len;
- return ((int)dr_len);
- }
-
- /* Rockridge */
- if (iso9660->opt.rr && vdd_type != VDD_JOLIET)
- dr_len = set_directory_record_rr(bp, (int)dr_len,
- isoent, iso9660, t);
-
- if (p != NULL)
- /* Length of Directory Record */
- set_num_711(p, (unsigned char)dr_len);
- else {
- /*
- * Save the size which is needed to write this
- * Directory Record.
- */
- switch (t) {
- case DIR_REC_VD:
- /* This case does not come, but compiler
- * complains that DIR_REC_VD not handled
- * in switch .... */
- break;
- case DIR_REC_SELF:
- isoent->dr_len.self = (int)dr_len; break;
- case DIR_REC_PARENT:
- isoent->dr_len.parent = (int)dr_len; break;
- case DIR_REC_NORMAL:
- isoent->dr_len.normal = (int)dr_len; break;
- }
- }
-
- return ((int)dr_len);
-}
-
-/*
- * Calculate the size of a directory record.
- */
-static inline int
-get_dir_rec_size(struct iso9660 *iso9660, struct isoent *isoent,
- enum dir_rec_type t, enum vdd_type vdd_type)
-{
-
- return (set_directory_record(NULL, SIZE_MAX,
- isoent, iso9660, t, vdd_type));
-}
-
-/*
- * Manage to write ISO-image data with wbuff to reduce calling
- * __archive_write_output() for performance.
- */
-
-
-static inline unsigned char *
-wb_buffptr(struct archive_write *a)
-{
- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
-
- return (&(iso9660->wbuff[sizeof(iso9660->wbuff)
- - iso9660->wbuff_remaining]));
-}
-
-static int
-wb_write_out(struct archive_write *a)
-{
- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
- size_t wsize, nw;
- int r;
-
- wsize = sizeof(iso9660->wbuff) - iso9660->wbuff_remaining;
- nw = wsize % LOGICAL_BLOCK_SIZE;
- if (iso9660->wbuff_type == WB_TO_STREAM)
- r = __archive_write_output(a, iso9660->wbuff, wsize - nw);
- else
- r = write_to_temp(a, iso9660->wbuff, wsize - nw);
- /* Increase the offset. */
- iso9660->wbuff_offset += wsize - nw;
- if (iso9660->wbuff_offset > iso9660->wbuff_written)
- iso9660->wbuff_written = iso9660->wbuff_offset;
- iso9660->wbuff_remaining = sizeof(iso9660->wbuff);
- if (nw) {
- iso9660->wbuff_remaining -= nw;
- memmove(iso9660->wbuff, iso9660->wbuff + wsize - nw, nw);
- }
- return (r);
-}
-
-static int
-wb_consume(struct archive_write *a, size_t size)
-{
- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
-
- if (size > iso9660->wbuff_remaining ||
- iso9660->wbuff_remaining == 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal Programing error: iso9660:wb_consume()"
- " size=%jd, wbuff_remaining=%jd",
- (intmax_t)size, (intmax_t)iso9660->wbuff_remaining);
- return (ARCHIVE_FATAL);
- }
- iso9660->wbuff_remaining -= size;
- if (iso9660->wbuff_remaining < LOGICAL_BLOCK_SIZE)
- return (wb_write_out(a));
- return (ARCHIVE_OK);
-}
-
-#ifdef HAVE_ZLIB_H
-
-static int
-wb_set_offset(struct archive_write *a, int64_t off)
-{
- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
- int64_t used, ext_bytes;
-
- if (iso9660->wbuff_type != WB_TO_TEMP) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal Programing error: iso9660:wb_set_offset()");
- return (ARCHIVE_FATAL);
- }
-
- used = sizeof(iso9660->wbuff) - iso9660->wbuff_remaining;
- if (iso9660->wbuff_offset + used > iso9660->wbuff_tail)
- iso9660->wbuff_tail = iso9660->wbuff_offset + used;
- if (iso9660->wbuff_offset < iso9660->wbuff_written) {
- if (used > 0 &&
- write_to_temp(a, iso9660->wbuff, (size_t)used) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- iso9660->wbuff_offset = iso9660->wbuff_written;
- lseek(iso9660->temp_fd, iso9660->wbuff_offset, SEEK_SET);
- iso9660->wbuff_remaining = sizeof(iso9660->wbuff);
- used = 0;
- }
- if (off < iso9660->wbuff_offset) {
- /*
- * Write out waiting data.
- */
- if (used > 0) {
- if (wb_write_out(a) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
- lseek(iso9660->temp_fd, off, SEEK_SET);
- iso9660->wbuff_offset = off;
- iso9660->wbuff_remaining = sizeof(iso9660->wbuff);
- } else if (off <= iso9660->wbuff_tail) {
- iso9660->wbuff_remaining = (size_t)
- (sizeof(iso9660->wbuff) - (off - iso9660->wbuff_offset));
- } else {
- ext_bytes = off - iso9660->wbuff_tail;
- iso9660->wbuff_remaining = (size_t)(sizeof(iso9660->wbuff)
- - (iso9660->wbuff_tail - iso9660->wbuff_offset));
- while (ext_bytes >= (int64_t)iso9660->wbuff_remaining) {
- if (write_null(a, (size_t)iso9660->wbuff_remaining)
- != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- ext_bytes -= iso9660->wbuff_remaining;
- }
- if (ext_bytes > 0) {
- if (write_null(a, (size_t)ext_bytes) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
- }
- return (ARCHIVE_OK);
-}
-
-#endif /* HAVE_ZLIB_H */
-
-static int
-write_null(struct archive_write *a, size_t size)
-{
- size_t remaining;
- unsigned char *p, *old;
- int r;
-
- remaining = wb_remaining(a);
- p = wb_buffptr(a);
- if (size <= remaining) {
- memset(p, 0, size);
- return (wb_consume(a, size));
- }
- memset(p, 0, remaining);
- r = wb_consume(a, remaining);
- if (r != ARCHIVE_OK)
- return (r);
- size -= remaining;
- old = p;
- p = wb_buffptr(a);
- memset(p, 0, old - p);
- remaining = wb_remaining(a);
- while (size) {
- size_t wsize = size;
-
- if (wsize > remaining)
- wsize = remaining;
- r = wb_consume(a, wsize);
- if (r != ARCHIVE_OK)
- return (r);
- size -= wsize;
- }
- return (ARCHIVE_OK);
-}
-
-/*
- * Write Volume Descriptor Set Terminator
- */
-static int
-write_VD_terminator(struct archive_write *a)
-{
- unsigned char *bp;
-
- bp = wb_buffptr(a) -1;
- set_VD_bp(bp, VDT_TERMINATOR, 1);
- set_unused_field_bp(bp, 8, LOGICAL_BLOCK_SIZE);
-
- return (wb_consume(a, LOGICAL_BLOCK_SIZE));
-}
-
-static int
-set_file_identifier(unsigned char *bp, int from, int to, enum vdc vdc,
- struct archive_write *a, struct vdd *vdd, struct archive_string *id,
- const char *label, int leading_under, enum char_type char_type)
-{
- char identifier[256];
- struct isoent *isoent;
- const char *ids;
- size_t len;
- int r;
-
- if (id->length > 0 && leading_under && id->s[0] != '_') {
- if (char_type == A_CHAR)
- r = set_str_a_characters_bp(a, bp, from, to, id->s, vdc);
- else
- r = set_str_d_characters_bp(a, bp, from, to, id->s, vdc);
- } else if (id->length > 0) {
- ids = id->s;
- if (leading_under)
- ids++;
- isoent = isoent_find_entry(vdd->rootent, ids);
- if (isoent == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Not Found %s `%s'.",
- label, ids);
- return (ARCHIVE_FATAL);
- }
- len = isoent->ext_off + isoent->ext_len;
- if (vdd->vdd_type == VDD_JOLIET) {
- if (len > sizeof(identifier)-2)
- len = sizeof(identifier)-2;
- } else {
- if (len > sizeof(identifier)-1)
- len = sizeof(identifier)-1;
- }
- memcpy(identifier, isoent->identifier, len);
- identifier[len] = '\0';
- if (vdd->vdd_type == VDD_JOLIET) {
- identifier[len+1] = 0;
- vdc = VDC_UCS2_DIRECT;
- }
- if (char_type == A_CHAR)
- r = set_str_a_characters_bp(a, bp, from, to,
- identifier, vdc);
- else
- r = set_str_d_characters_bp(a, bp, from, to,
- identifier, vdc);
- } else {
- if (char_type == A_CHAR)
- r = set_str_a_characters_bp(a, bp, from, to, NULL, vdc);
- else
- r = set_str_d_characters_bp(a, bp, from, to, NULL, vdc);
- }
- return (r);
-}
-
-/*
- * Write Primary/Supplementary Volume Descriptor
- */
-static int
-write_VD(struct archive_write *a, struct vdd *vdd)
-{
- struct iso9660 *iso9660;
- unsigned char *bp;
- uint16_t volume_set_size = 1;
- char identifier[256];
- enum VD_type vdt;
- enum vdc vdc;
- unsigned char vd_ver, fst_ver;
- int r;
-
- iso9660 = a->format_data;
- switch (vdd->vdd_type) {
- case VDD_JOLIET:
- vdt = VDT_SUPPLEMENTARY;
- vd_ver = fst_ver = 1;
- vdc = VDC_UCS2;
- break;
- case VDD_ENHANCED:
- vdt = VDT_SUPPLEMENTARY;
- vd_ver = fst_ver = 2;
- vdc = VDC_LOWERCASE;
- break;
- case VDD_PRIMARY:
- default:
- vdt = VDT_PRIMARY;
- vd_ver = fst_ver = 1;
-#ifdef COMPAT_MKISOFS
- vdc = VDC_LOWERCASE;
-#else
- vdc = VDC_STD;
-#endif
- break;
- }
-
- bp = wb_buffptr(a) -1;
- /* Volume Descriptor Type */
- set_VD_bp(bp, vdt, vd_ver);
- /* Unused Field */
- set_unused_field_bp(bp, 8, 8);
- /* System Identifier */
- get_system_identitier(identifier, sizeof(identifier));
- r = set_str_a_characters_bp(a, bp, 9, 40, identifier, vdc);
- if (r != ARCHIVE_OK)
- return (r);
- /* Volume Identifier */
- r = set_str_d_characters_bp(a, bp, 41, 72,
- iso9660->volume_identifier.s, vdc);
- if (r != ARCHIVE_OK)
- return (r);
- /* Unused Field */
- set_unused_field_bp(bp, 73, 80);
- /* Volume Space Size */
- set_num_733(bp+81, iso9660->volume_space_size);
- if (vdd->vdd_type == VDD_JOLIET) {
- /* Escape Sequences */
- bp[89] = 0x25;/* UCS-2 Level 3 */
- bp[90] = 0x2F;
- bp[91] = 0x45;
- memset(bp + 92, 0, 120 - 92 + 1);
- } else {
- /* Unused Field */
- set_unused_field_bp(bp, 89, 120);
- }
- /* Volume Set Size */
- set_num_723(bp+121, volume_set_size);
- /* Volume Sequence Number */
- set_num_723(bp+125, iso9660->volume_sequence_number);
- /* Logical Block Size */
- set_num_723(bp+129, LOGICAL_BLOCK_SIZE);
- /* Path Table Size */
- set_num_733(bp+133, vdd->path_table_size);
- /* Location of Occurrence of Type L Path Table */
- set_num_731(bp+141, vdd->location_type_L_path_table);
- /* Location of Optional Occurrence of Type L Path Table */
- set_num_731(bp+145, 0);
- /* Location of Occurrence of Type M Path Table */
- set_num_732(bp+149, vdd->location_type_M_path_table);
- /* Location of Optional Occurrence of Type M Path Table */
- set_num_732(bp+153, 0);
- /* Directory Record for Root Directory(BP 157 to 190) */
- set_directory_record(bp+157, 190-157+1, vdd->rootent,
- iso9660, DIR_REC_VD, vdd->vdd_type);
- /* Volume Set Identifier */
- r = set_str_d_characters_bp(a, bp, 191, 318, "", vdc);
- if (r != ARCHIVE_OK)
- return (r);
- /* Publisher Identifier */
- r = set_file_identifier(bp, 319, 446, vdc, a, vdd,
- &(iso9660->publisher_identifier),
- "Publisher File", 1, A_CHAR);
- if (r != ARCHIVE_OK)
- return (r);
- /* Data Preparer Identifier */
- r = set_file_identifier(bp, 447, 574, vdc, a, vdd,
- &(iso9660->data_preparer_identifier),
- "Data Preparer File", 1, A_CHAR);
- if (r != ARCHIVE_OK)
- return (r);
- /* Application Identifier */
- r = set_file_identifier(bp, 575, 702, vdc, a, vdd,
- &(iso9660->application_identifier),
- "Application File", 1, A_CHAR);
- if (r != ARCHIVE_OK)
- return (r);
- /* Copyright File Identifier */
- r = set_file_identifier(bp, 703, 739, vdc, a, vdd,
- &(iso9660->copyright_file_identifier),
- "Copyright File", 0, D_CHAR);
- if (r != ARCHIVE_OK)
- return (r);
- /* Abstract File Identifier */
- r = set_file_identifier(bp, 740, 776, vdc, a, vdd,
- &(iso9660->abstract_file_identifier),
- "Abstract File", 0, D_CHAR);
- if (r != ARCHIVE_OK)
- return (r);
- /* Bibliongraphic File Identifier */
- r = set_file_identifier(bp, 777, 813, vdc, a, vdd,
- &(iso9660->bibliographic_file_identifier),
- "Bibliongraphic File", 0, D_CHAR);
- if (r != ARCHIVE_OK)
- return (r);
- /* Volume Creation Date and Time */
- set_date_time(bp+814, iso9660->birth_time);
- /* Volume Modification Date and Time */
- set_date_time(bp+831, iso9660->birth_time);
- /* Volume Expiration Date and Time(obsolete) */
- set_date_time_null(bp+848);
- /* Volume Effective Date and Time */
- set_date_time(bp+865, iso9660->birth_time);
- /* File Structure Version */
- bp[882] = fst_ver;
- /* Reserved */
- bp[883] = 0;
- /* Application Use */
- memset(bp + 884, 0x20, 1395 - 884 + 1);
- /* Reserved */
- set_unused_field_bp(bp, 1396, LOGICAL_BLOCK_SIZE);
-
- return (wb_consume(a, LOGICAL_BLOCK_SIZE));
-}
-
-/*
- * Write Boot Record Volume Descriptor
- */
-static int
-write_VD_boot_record(struct archive_write *a)
-{
- struct iso9660 *iso9660;
- unsigned char *bp;
-
- iso9660 = a->format_data;
- bp = wb_buffptr(a) -1;
- /* Volume Descriptor Type */
- set_VD_bp(bp, VDT_BOOT_RECORD, 1);
- /* Boot System Identifier */
- memcpy(bp+8, "EL TORITO SPECIFICATION", 23);
- set_unused_field_bp(bp, 8+23, 39);
- /* Unused */
- set_unused_field_bp(bp, 40, 71);
- /* Absolute pointer to first sector of Boot Catalog */
- set_num_731(bp+72,
- iso9660->el_torito.catalog->file->content.location);
- /* Unused */
- set_unused_field_bp(bp, 76, LOGICAL_BLOCK_SIZE);
-
- return (wb_consume(a, LOGICAL_BLOCK_SIZE));
-}
-
-enum keytype {
- KEY_FLG,
- KEY_STR,
- KEY_INT,
- KEY_HEX,
-};
-static void
-set_option_info(struct archive_string *info, int *opt, const char *key,
- enum keytype type, ...)
-{
- va_list ap;
- char prefix;
- const char *s;
- int d;
-
- prefix = (*opt==0)? ' ':',';
- va_start(ap, type);
- switch (type) {
- case KEY_FLG:
- d = va_arg(ap, int);
- archive_string_sprintf(info, "%c%s%s",
- prefix, (d == 0)?"!":"", key);
- break;
- case KEY_STR:
- s = va_arg(ap, const char *);
- archive_string_sprintf(info, "%c%s=%s",
- prefix, key, s);
- break;
- case KEY_INT:
- d = va_arg(ap, int);
- archive_string_sprintf(info, "%c%s=%d",
- prefix, key, d);
- break;
- case KEY_HEX:
- d = va_arg(ap, int);
- archive_string_sprintf(info, "%c%s=%x",
- prefix, key, d);
- break;
- }
- va_end(ap);
-
- *opt = 1;
-}
-
-/*
- * Make Non-ISO File System Information
- */
-static int
-write_information_block(struct archive_write *a)
-{
- struct iso9660 *iso9660;
- char buf[128];
- const char *v;
- int opt, r;
- struct archive_string info;
- size_t info_size = LOGICAL_BLOCK_SIZE *
- NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK;
-
- iso9660 = (struct iso9660 *)a->format_data;
- if (info_size > wb_remaining(a)) {
- r = wb_write_out(a);
- if (r != ARCHIVE_OK)
- return (r);
- }
- archive_string_init(&info);
- if (archive_string_ensure(&info, info_size) == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- memset(info.s, 0, info_size);
- opt = 0;
-#if defined(HAVE__CTIME64_S)
- _ctime64_s(buf, sizeof(buf), &(iso9660->birth_time));
-#elif defined(HAVE_CTIME_R)
- ctime_r(&(iso9660->birth_time), buf);
-#else
- strncpy(buf, ctime(&(iso9660->birth_time)), sizeof(buf)-1);
- buf[sizeof(buf)-1] = '\0';
-#endif
- archive_string_sprintf(&info,
- "INFO %s%s", buf, archive_version_string());
- if (iso9660->opt.abstract_file != OPT_ABSTRACT_FILE_DEFAULT)
- set_option_info(&info, &opt, "abstract-file",
- KEY_STR, iso9660->abstract_file_identifier.s);
- if (iso9660->opt.application_id != OPT_APPLICATION_ID_DEFAULT)
- set_option_info(&info, &opt, "application-id",
- KEY_STR, iso9660->application_identifier.s);
- if (iso9660->opt.allow_vernum != OPT_ALLOW_VERNUM_DEFAULT)
- set_option_info(&info, &opt, "allow-vernum",
- KEY_FLG, iso9660->opt.allow_vernum);
- if (iso9660->opt.biblio_file != OPT_BIBLIO_FILE_DEFAULT)
- set_option_info(&info, &opt, "biblio-file",
- KEY_STR, iso9660->bibliographic_file_identifier.s);
- if (iso9660->opt.boot != OPT_BOOT_DEFAULT)
- set_option_info(&info, &opt, "boot",
- KEY_STR, iso9660->el_torito.boot_filename.s);
- if (iso9660->opt.boot_catalog != OPT_BOOT_CATALOG_DEFAULT)
- set_option_info(&info, &opt, "boot-catalog",
- KEY_STR, iso9660->el_torito.catalog_filename.s);
- if (iso9660->opt.boot_info_table != OPT_BOOT_INFO_TABLE_DEFAULT)
- set_option_info(&info, &opt, "boot-info-table",
- KEY_FLG, iso9660->opt.boot_info_table);
- if (iso9660->opt.boot_load_seg != OPT_BOOT_LOAD_SEG_DEFAULT)
- set_option_info(&info, &opt, "boot-load-seg",
- KEY_HEX, iso9660->el_torito.boot_load_seg);
- if (iso9660->opt.boot_load_size != OPT_BOOT_LOAD_SIZE_DEFAULT)
- set_option_info(&info, &opt, "boot-load-size",
- KEY_INT, iso9660->el_torito.boot_load_size);
- if (iso9660->opt.boot_type != OPT_BOOT_TYPE_DEFAULT) {
- v = "no-emulation";
- if (iso9660->opt.boot_type == OPT_BOOT_TYPE_FD)
- v = "fd";
- if (iso9660->opt.boot_type == OPT_BOOT_TYPE_HARD_DISK)
- v = "hard-disk";
- set_option_info(&info, &opt, "boot-type",
- KEY_STR, v);
- }
-#ifdef HAVE_ZLIB_H
- if (iso9660->opt.compression_level != OPT_COMPRESSION_LEVEL_DEFAULT)
- set_option_info(&info, &opt, "compression-level",
- KEY_INT, iso9660->zisofs.compression_level);
-#endif
- if (iso9660->opt.copyright_file != OPT_COPYRIGHT_FILE_DEFAULT)
- set_option_info(&info, &opt, "copyright-file",
- KEY_STR, iso9660->copyright_file_identifier.s);
- if (iso9660->opt.iso_level != OPT_ISO_LEVEL_DEFAULT)
- set_option_info(&info, &opt, "iso-level",
- KEY_INT, iso9660->opt.iso_level);
- if (iso9660->opt.joliet != OPT_JOLIET_DEFAULT) {
- if (iso9660->opt.joliet == OPT_JOLIET_LONGNAME)
- set_option_info(&info, &opt, "joliet",
- KEY_STR, "long");
- else
- set_option_info(&info, &opt, "joliet",
- KEY_FLG, iso9660->opt.joliet);
- }
- if (iso9660->opt.limit_depth != OPT_LIMIT_DEPTH_DEFAULT)
- set_option_info(&info, &opt, "limit-depth",
- KEY_FLG, iso9660->opt.limit_depth);
- if (iso9660->opt.limit_dirs != OPT_LIMIT_DIRS_DEFAULT)
- set_option_info(&info, &opt, "limit-dirs",
- KEY_FLG, iso9660->opt.limit_dirs);
- if (iso9660->opt.pad != OPT_PAD_DEFAULT)
- set_option_info(&info, &opt, "pad",
- KEY_FLG, iso9660->opt.pad);
- if (iso9660->opt.publisher != OPT_PUBLISHER_DEFAULT)
- set_option_info(&info, &opt, "publisher",
- KEY_STR, iso9660->publisher_identifier.s);
- if (iso9660->opt.rr != OPT_RR_DEFAULT) {
- if (iso9660->opt.rr == OPT_RR_DISABLED)
- set_option_info(&info, &opt, "rockridge",
- KEY_FLG, iso9660->opt.rr);
- else if (iso9660->opt.rr == OPT_RR_STRICT)
- set_option_info(&info, &opt, "rockridge",
- KEY_STR, "strict");
- else if (iso9660->opt.rr == OPT_RR_USEFUL)
- set_option_info(&info, &opt, "rockridge",
- KEY_STR, "useful");
- }
- if (iso9660->opt.volume_id != OPT_VOLUME_ID_DEFAULT)
- set_option_info(&info, &opt, "volume-id",
- KEY_STR, iso9660->volume_identifier.s);
- if (iso9660->opt.zisofs != OPT_ZISOFS_DEFAULT)
- set_option_info(&info, &opt, "zisofs",
- KEY_FLG, iso9660->opt.zisofs);
-
- memcpy(wb_buffptr(a), info.s, info_size);
- archive_string_free(&info);
- return (wb_consume(a, info_size));
-}
-
-static int
-write_rr_ER(struct archive_write *a)
-{
- unsigned char *p;
-
- p = wb_buffptr(a);
-
- memset(p, 0, LOGICAL_BLOCK_SIZE);
- p[0] = 'E';
- p[1] = 'R';
- p[3] = 0x01;
- p[2] = RRIP_ER_SIZE;
- p[4] = RRIP_ER_ID_SIZE;
- p[5] = RRIP_ER_DSC_SIZE;
- p[6] = RRIP_ER_SRC_SIZE;
- p[7] = 0x01;
- memcpy(&p[8], rrip_identifier, p[4]);
- memcpy(&p[8+p[4]], rrip_descriptor, p[5]);
- memcpy(&p[8+p[4]+p[5]], rrip_source, p[6]);
-
- return (wb_consume(a, LOGICAL_BLOCK_SIZE));
-}
-
-static void
-calculate_path_table_size(struct vdd *vdd)
-{
- int depth, size;
- struct path_table *pt;
-
- pt = vdd->pathtbl;
- size = 0;
- for (depth = 0; depth < vdd->max_depth; depth++) {
- struct isoent **ptbl;
- int i, cnt;
-
- if ((cnt = pt[depth].cnt) == 0)
- break;
-
- ptbl = pt[depth].sorted;
- for (i = 0; i < cnt; i++) {
- int len;
-
- if (ptbl[i]->identifier == NULL)
- len = 1; /* root directory */
- else
- len = ptbl[i]->id_len;
- if (len & 0x01)
- len++; /* Padding Field */
- size += 8 + len;
- }
- }
- vdd->path_table_size = size;
- vdd->path_table_block =
- ((size + PATH_TABLE_BLOCK_SIZE -1) /
- PATH_TABLE_BLOCK_SIZE) *
- (PATH_TABLE_BLOCK_SIZE / LOGICAL_BLOCK_SIZE);
-}
-
-static int
-_write_path_table(struct archive_write *a, int type_m, int depth,
- struct vdd *vdd)
-{
- unsigned char *bp, *wb;
- struct isoent **ptbl;
- size_t wbremaining;
- int i, r, wsize;
-
- if (vdd->pathtbl[depth].cnt == 0)
- return (0);
-
- wsize = 0;
- wb = wb_buffptr(a);
- wbremaining = wb_remaining(a);
- bp = wb - 1;
- ptbl = vdd->pathtbl[depth].sorted;
- for (i = 0; i < vdd->pathtbl[depth].cnt; i++) {
- struct isoent *np;
- size_t len;
-
- np = ptbl[i];
- if (np->identifier == NULL)
- len = 1; /* root directory */
- else
- len = np->id_len;
- if (wbremaining - ((bp+1) - wb) < (len + 1 + 8)) {
- r = wb_consume(a, (bp+1) - wb);
- if (r < 0)
- return (r);
- wb = wb_buffptr(a);
- wbremaining = wb_remaining(a);
- bp = wb -1;
- }
- /* Length of Directory Identifier */
- set_num_711(bp+1, (unsigned char)len);
- /* Extended Attribute Record Length */
- set_num_711(bp+2, 0);
- /* Location of Extent */
- if (type_m)
- set_num_732(bp+3, np->dir_location);
- else
- set_num_731(bp+3, np->dir_location);
- /* Parent Directory Number */
- if (type_m)
- set_num_722(bp+7, np->parent->dir_number);
- else
- set_num_721(bp+7, np->parent->dir_number);
- /* Directory Identifier */
- if (np->identifier == NULL)
- bp[9] = 0;
- else
- memcpy(&bp[9], np->identifier, len);
- if (len & 0x01) {
- /* Padding Field */
- bp[9+len] = 0;
- len++;
- }
- wsize += 8 + (int)len;
- bp += 8 + len;
- }
- if ((bp + 1) > wb) {
- r = wb_consume(a, (bp+1)-wb);
- if (r < 0)
- return (r);
- }
- return (wsize);
-}
-
-static int
-write_path_table(struct archive_write *a, int type_m, struct vdd *vdd)
-{
- int depth, r;
- size_t path_table_size;
-
- r = ARCHIVE_OK;
- path_table_size = 0;
- for (depth = 0; depth < vdd->max_depth; depth++) {
- r = _write_path_table(a, type_m, depth, vdd);
- if (r < 0)
- return (r);
- path_table_size += r;
- }
-
- /* Write padding data. */
- path_table_size = path_table_size % PATH_TABLE_BLOCK_SIZE;
- if (path_table_size > 0)
- r = write_null(a, PATH_TABLE_BLOCK_SIZE - path_table_size);
- return (r);
-}
-
-static int
-calculate_directory_descriptors(struct iso9660 *iso9660, struct vdd *vdd,
- struct isoent *isoent, int depth)
-{
- struct isoent **enttbl;
- int bs, block, i;
-
- block = 1;
- bs = get_dir_rec_size(iso9660, isoent, DIR_REC_SELF, vdd->vdd_type);
- bs += get_dir_rec_size(iso9660, isoent, DIR_REC_PARENT, vdd->vdd_type);
-
- if (isoent->children.cnt <= 0 || (vdd->vdd_type != VDD_JOLIET &&
- !iso9660->opt.rr && depth + 1 >= vdd->max_depth))
- return (block);
-
- enttbl = isoent->children_sorted;
- for (i = 0; i < isoent->children.cnt; i++) {
- struct isoent *np = enttbl[i];
- struct isofile *file;
-
- file = np->file;
- if (file->hardlink_target != NULL)
- file = file->hardlink_target;
- file->cur_content = &(file->content);
- do {
- int dr_l;
-
- dr_l = get_dir_rec_size(iso9660, np, DIR_REC_NORMAL,
- vdd->vdd_type);
- if ((bs + dr_l) > LOGICAL_BLOCK_SIZE) {
- block ++;
- bs = dr_l;
- } else
- bs += dr_l;
- file->cur_content = file->cur_content->next;
- } while (file->cur_content != NULL);
- }
- return (block);
-}
-
-static int
-_write_directory_descriptors(struct archive_write *a, struct vdd *vdd,
- struct isoent *isoent, int depth)
-{
- struct iso9660 *iso9660 = a->format_data;
- struct isoent **enttbl;
- unsigned char *p, *wb;
- int i, r;
- int dr_l;
-
- p = wb = wb_buffptr(a);
-#define WD_REMAINING (LOGICAL_BLOCK_SIZE - (p - wb))
- p += set_directory_record(p, WD_REMAINING, isoent,
- iso9660, DIR_REC_SELF, vdd->vdd_type);
- p += set_directory_record(p, WD_REMAINING, isoent,
- iso9660, DIR_REC_PARENT, vdd->vdd_type);
-
- if (isoent->children.cnt <= 0 || (vdd->vdd_type != VDD_JOLIET &&
- !iso9660->opt.rr && depth + 1 >= vdd->max_depth)) {
- memset(p, 0, WD_REMAINING);
- return (wb_consume(a, LOGICAL_BLOCK_SIZE));
- }
-
- enttbl = isoent->children_sorted;
- for (i = 0; i < isoent->children.cnt; i++) {
- struct isoent *np = enttbl[i];
- struct isofile *file = np->file;
-
- if (file->hardlink_target != NULL)
- file = file->hardlink_target;
- file->cur_content = &(file->content);
- do {
- dr_l = set_directory_record(p, WD_REMAINING,
- np, iso9660, DIR_REC_NORMAL,
- vdd->vdd_type);
- if (dr_l == 0) {
- memset(p, 0, WD_REMAINING);
- r = wb_consume(a, LOGICAL_BLOCK_SIZE);
- if (r < 0)
- return (r);
- p = wb = wb_buffptr(a);
- dr_l = set_directory_record(p,
- WD_REMAINING, np, iso9660,
- DIR_REC_NORMAL, vdd->vdd_type);
- }
- p += dr_l;
- file->cur_content = file->cur_content->next;
- } while (file->cur_content != NULL);
- }
- memset(p, 0, WD_REMAINING);
- return (wb_consume(a, LOGICAL_BLOCK_SIZE));
-}
-
-static int
-write_directory_descriptors(struct archive_write *a, struct vdd *vdd)
-{
- struct isoent *np;
- int depth, r;
-
- depth = 0;
- np = vdd->rootent;
- do {
- struct extr_rec *extr;
-
- r = _write_directory_descriptors(a, vdd, np, depth);
- if (r < 0)
- return (r);
- if (vdd->vdd_type != VDD_JOLIET) {
- /*
- * This extract record is used by SUSP,RRIP.
- * Not for joliet.
- */
- for (extr = np->extr_rec_list.first;
- extr != NULL;
- extr = extr->next) {
- unsigned char *wb;
-
- wb = wb_buffptr(a);
- memcpy(wb, extr->buf, extr->offset);
- memset(wb + extr->offset, 0,
- LOGICAL_BLOCK_SIZE - extr->offset);
- r = wb_consume(a, LOGICAL_BLOCK_SIZE);
- if (r < 0)
- return (r);
- }
- }
-
- if (np->subdirs.first != NULL && depth + 1 < vdd->max_depth) {
- /* Enter to sub directories. */
- np = np->subdirs.first;
- depth++;
- continue;
- }
- while (np != np->parent) {
- if (np->drnext == NULL) {
- /* Return to the parent directory. */
- np = np->parent;
- depth--;
- } else {
- np = np->drnext;
- break;
- }
- }
- } while (np != np->parent);
-
- return (ARCHIVE_OK);
-}
-
-/*
- * Read file contents from the temporary file, and write it.
- */
-static int
-write_file_contents(struct archive_write *a, int64_t offset, int64_t size)
-{
- struct iso9660 *iso9660 = a->format_data;
- int r;
-
- lseek(iso9660->temp_fd, offset, SEEK_SET);
-
- while (size) {
- size_t rsize;
- ssize_t rs;
- unsigned char *wb;
-
- wb = wb_buffptr(a);
- rsize = wb_remaining(a);
- if (rsize > (size_t)size)
- rsize = (size_t)size;
- rs = read(iso9660->temp_fd, wb, rsize);
- if (rs <= 0) {
- archive_set_error(&a->archive, errno,
- "Can't read temporary file(%jd)", (intmax_t)rs);
- return (ARCHIVE_FATAL);
- }
- size -= rs;
- r = wb_consume(a, rs);
- if (r < 0)
- return (r);
- }
- return (ARCHIVE_OK);
-}
-
-static int
-write_file_descriptors(struct archive_write *a)
-{
- struct iso9660 *iso9660 = a->format_data;
- struct isofile *file;
- int64_t blocks, offset;
- int r;
-
- blocks = 0;
- offset = 0;
-
- /* Make the boot catalog contents, and write it. */
- if (iso9660->el_torito.catalog != NULL) {
- r = make_boot_catalog(a);
- if (r < 0)
- return (r);
- }
-
- /* Write the boot file contents. */
- if (iso9660->el_torito.boot != NULL) {
- file = iso9660->el_torito.boot->file;
- blocks = file->content.blocks;
- offset = file->content.offset_of_temp;
- if (offset != 0) {
- r = write_file_contents(a, offset,
- blocks << LOGICAL_BLOCK_BITS);
- if (r < 0)
- return (r);
- blocks = 0;
- offset = 0;
- }
- }
-
- /* Write out all file contents. */
- for (file = iso9660->data_file_list.first;
- file != NULL; file = file->datanext) {
-
- if (!file->write_content)
- continue;
-
- if ((offset + (blocks << LOGICAL_BLOCK_BITS)) <
- file->content.offset_of_temp) {
- if (blocks > 0) {
- r = write_file_contents(a, offset,
- blocks << LOGICAL_BLOCK_BITS);
- if (r < 0)
- return (r);
- }
- blocks = 0;
- offset = file->content.offset_of_temp;
- }
-
- file->cur_content = &(file->content);
- do {
- blocks += file->cur_content->blocks;
- /* Next fragument */
- file->cur_content = file->cur_content->next;
- } while (file->cur_content != NULL);
- }
-
- /* Flush out remaining blocks. */
- if (blocks > 0) {
- r = write_file_contents(a, offset,
- blocks << LOGICAL_BLOCK_BITS);
- if (r < 0)
- return (r);
- }
-
- return (ARCHIVE_OK);
-}
-
-static void
-isofile_init_entry_list(struct iso9660 *iso9660)
-{
- iso9660->all_file_list.first = NULL;
- iso9660->all_file_list.last = &(iso9660->all_file_list.first);
-}
-
-static void
-isofile_add_entry(struct iso9660 *iso9660, struct isofile *file)
-{
- file->allnext = NULL;
- *iso9660->all_file_list.last = file;
- iso9660->all_file_list.last = &(file->allnext);
-}
-
-static void
-isofile_free_all_entries(struct iso9660 *iso9660)
-{
- struct isofile *file, *file_next;
-
- file = iso9660->all_file_list.first;
- while (file != NULL) {
- file_next = file->allnext;
- isofile_free(file);
- file = file_next;
- }
-}
-
-static void
-isofile_init_entry_data_file_list(struct iso9660 *iso9660)
-{
- iso9660->data_file_list.first = NULL;
- iso9660->data_file_list.last = &(iso9660->data_file_list.first);
-}
-
-static void
-isofile_add_data_file(struct iso9660 *iso9660, struct isofile *file)
-{
- file->datanext = NULL;
- *iso9660->data_file_list.last = file;
- iso9660->data_file_list.last = &(file->datanext);
-}
-
-
-static struct isofile *
-isofile_new(struct archive_write *a, struct archive_entry *entry)
-{
- struct isofile *file;
-
- file = calloc(1, sizeof(*file));
- if (file == NULL)
- return (NULL);
-
- if (entry != NULL)
- file->entry = archive_entry_clone(entry);
- else
- file->entry = archive_entry_new2(&a->archive);
- if (file->entry == NULL) {
- free(file);
- return (NULL);
- }
- archive_string_init(&(file->parentdir));
- archive_string_init(&(file->basename));
- archive_string_init(&(file->basename_utf16));
- archive_string_init(&(file->symlink));
- file->cur_content = &(file->content);
-
- return (file);
-}
-
-static void
-isofile_free(struct isofile *file)
-{
- struct content *con, *tmp;
-
- con = file->content.next;
- while (con != NULL) {
- tmp = con;
- con = con->next;
- free(tmp);
- }
- archive_entry_free(file->entry);
- archive_string_free(&(file->parentdir));
- archive_string_free(&(file->basename));
- archive_string_free(&(file->basename_utf16));
- archive_string_free(&(file->symlink));
- free(file);
-}
-
-#if defined(_WIN32) || defined(__CYGWIN__)
-static int
-cleanup_backslash_1(char *p)
-{
- int mb, dos;
-
- mb = dos = 0;
- while (*p) {
- if (*(unsigned char *)p > 127)
- mb = 1;
- if (*p == '\\') {
- /* If we have not met any multi-byte characters,
- * we can replace '\' with '/'. */
- if (!mb)
- *p = '/';
- dos = 1;
- }
- p++;
- }
- if (!mb || !dos)
- return (0);
- return (-1);
-}
-
-static void
-cleanup_backslash_2(wchar_t *p)
-{
-
- /* Convert a path-separator from '\' to '/' */
- while (*p != L'\0') {
- if (*p == L'\\')
- *p = L'/';
- p++;
- }
-}
-#endif
-
-/*
- * Generate a parent directory name and a base name from a pathname.
- */
-static int
-isofile_gen_utility_names(struct archive_write *a, struct isofile *file)
-{
- struct iso9660 *iso9660;
- const char *pathname;
- char *p, *dirname, *slash;
- size_t len;
- int ret = ARCHIVE_OK;
-
- iso9660 = a->format_data;
-
- archive_string_empty(&(file->parentdir));
- archive_string_empty(&(file->basename));
- archive_string_empty(&(file->basename_utf16));
- archive_string_empty(&(file->symlink));
-
- pathname = archive_entry_pathname(file->entry);
- if (pathname == NULL || pathname[0] == '\0') {/* virtual root */
- file->dircnt = 0;
- return (ret);
- }
-
- /*
- * Make a UTF-16BE basename if Joliet extension enabled.
- */
- if (iso9660->opt.joliet) {
- const char *u16, *ulast;
- size_t u16len, ulen_last;
-
- if (iso9660->sconv_to_utf16be == NULL) {
- iso9660->sconv_to_utf16be =
- archive_string_conversion_to_charset(
- &(a->archive), "UTF-16BE", 1);
- if (iso9660->sconv_to_utf16be == NULL)
- /* Couldn't allocate memory */
- return (ARCHIVE_FATAL);
- iso9660->sconv_from_utf16be =
- archive_string_conversion_from_charset(
- &(a->archive), "UTF-16BE", 1);
- if (iso9660->sconv_from_utf16be == NULL)
- /* Couldn't allocate memory */
- return (ARCHIVE_FATAL);
- }
-
- /*
- * Converte a filename to UTF-16BE.
- */
- if (0 > archive_entry_pathname_l(file->entry, &u16, &u16len,
- iso9660->sconv_to_utf16be)) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for UTF-16BE");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "A filename cannot be converted to UTF-16BE;"
- "You should disable making Joliet extension");
- ret = ARCHIVE_WARN;
- }
-
- /*
- * Make sure a path separator is not in the last;
- * Remove trailing '/'.
- */
- while (u16len >= 2) {
-#if defined(_WIN32) || defined(__CYGWIN__)
- if (u16[u16len-2] == 0 &&
- (u16[u16len-1] == '/' || u16[u16len-1] == '\\'))
-#else
- if (u16[u16len-2] == 0 && u16[u16len-1] == '/')
-#endif
- {
- u16len -= 2;
- } else
- break;
- }
-
- /*
- * Find a basename in UTF-16BE.
- */
- ulast = u16;
- u16len >>= 1;
- ulen_last = u16len;
- while (u16len > 0) {
-#if defined(_WIN32) || defined(__CYGWIN__)
- if (u16[0] == 0 && (u16[1] == '/' || u16[1] == '\\'))
-#else
- if (u16[0] == 0 && u16[1] == '/')
-#endif
- {
- ulast = u16 + 2;
- ulen_last = u16len -1;
- }
- u16 += 2;
- u16len --;
- }
- ulen_last <<= 1;
- if (archive_string_ensure(&(file->basename_utf16),
- ulen_last) == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for UTF-16BE");
- return (ARCHIVE_FATAL);
- }
-
- /*
- * Set UTF-16BE basename.
- */
- memcpy(file->basename_utf16.s, ulast, ulen_last);
- file->basename_utf16.length = ulen_last;
- }
-
- archive_strcpy(&(file->parentdir), pathname);
-#if defined(_WIN32) || defined(__CYGWIN__)
- /*
- * Convert a path-separator from '\' to '/'
- */
- if (cleanup_backslash_1(file->parentdir.s) != 0) {
- const wchar_t *wp = archive_entry_pathname_w(file->entry);
- struct archive_wstring ws;
-
- if (wp != NULL) {
- int r;
- archive_string_init(&ws);
- archive_wstrcpy(&ws, wp);
- cleanup_backslash_2(ws.s);
- archive_string_empty(&(file->parentdir));
- r = archive_string_append_from_wcs(&(file->parentdir),
- ws.s, ws.length);
- archive_wstring_free(&ws);
- if (r < 0 && errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- }
- }
-#endif
-
- len = file->parentdir.length;
- p = dirname = file->parentdir.s;
-
- /*
- * Remove leading '/', '../' and './' elements
- */
- while (*p) {
- if (p[0] == '/') {
- p++;
- len--;
- } else if (p[0] != '.')
- break;
- else if (p[1] == '.' && p[2] == '/') {
- p += 3;
- len -= 3;
- } else if (p[1] == '/' || (p[1] == '.' && p[2] == '\0')) {
- p += 2;
- len -= 2;
- } else if (p[1] == '\0') {
- p++;
- len--;
- } else
- break;
- }
- if (p != dirname) {
- memmove(dirname, p, len+1);
- p = dirname;
- }
- /*
- * Remove "/","/." and "/.." elements from tail.
- */
- while (len > 0) {
- size_t ll = len;
-
- if (len > 0 && p[len-1] == '/') {
- p[len-1] = '\0';
- len--;
- }
- if (len > 1 && p[len-2] == '/' && p[len-1] == '.') {
- p[len-2] = '\0';
- len -= 2;
- }
- if (len > 2 && p[len-3] == '/' && p[len-2] == '.' &&
- p[len-1] == '.') {
- p[len-3] = '\0';
- len -= 3;
- }
- if (ll == len)
- break;
- }
- while (*p) {
- if (p[0] == '/') {
- if (p[1] == '/')
- /* Convert '//' --> '/' */
- strcpy(p, p+1);
- else if (p[1] == '.' && p[2] == '/')
- /* Convert '/./' --> '/' */
- strcpy(p, p+2);
- else if (p[1] == '.' && p[2] == '.' && p[3] == '/') {
- /* Convert 'dir/dir1/../dir2/'
- * --> 'dir/dir2/'
- */
- char *rp = p -1;
- while (rp >= dirname) {
- if (*rp == '/')
- break;
- --rp;
- }
- if (rp > dirname) {
- strcpy(rp, p+3);
- p = rp;
- } else {
- strcpy(dirname, p+4);
- p = dirname;
- }
- } else
- p++;
- } else
- p++;
- }
- p = dirname;
- len = strlen(p);
-
- if (archive_entry_filetype(file->entry) == AE_IFLNK) {
- /* Convert symlink name too. */
- pathname = archive_entry_symlink(file->entry);
- archive_strcpy(&(file->symlink), pathname);
-#if defined(_WIN32) || defined(__CYGWIN__)
- /*
- * Convert a path-separator from '\' to '/'
- */
- if (archive_strlen(&(file->symlink)) > 0 &&
- cleanup_backslash_1(file->symlink.s) != 0) {
- const wchar_t *wp =
- archive_entry_symlink_w(file->entry);
- struct archive_wstring ws;
-
- if (wp != NULL) {
- int r;
- archive_string_init(&ws);
- archive_wstrcpy(&ws, wp);
- cleanup_backslash_2(ws.s);
- archive_string_empty(&(file->symlink));
- r = archive_string_append_from_wcs(
- &(file->symlink),
- ws.s, ws.length);
- archive_wstring_free(&ws);
- if (r < 0 && errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- }
- }
-#endif
- }
- /*
- * - Count up directory elements.
- * - Find out the position which points the last position of
- * path separator('/').
- */
- slash = NULL;
- file->dircnt = 0;
- for (; *p != '\0'; p++)
- if (*p == '/') {
- slash = p;
- file->dircnt++;
- }
- if (slash == NULL) {
- /* The pathname doesn't have a parent directory. */
- file->parentdir.length = len;
- archive_string_copy(&(file->basename), &(file->parentdir));
- archive_string_empty(&(file->parentdir));
- *file->parentdir.s = '\0';
- return (ret);
- }
-
- /* Make a basename from dirname and slash */
- *slash = '\0';
- file->parentdir.length = slash - dirname;
- archive_strcpy(&(file->basename), slash + 1);
- if (archive_entry_filetype(file->entry) == AE_IFDIR)
- file->dircnt ++;
- return (ret);
-}
-
-/*
- * Register a entry to get a hardlink target.
- */
-static int
-isofile_register_hardlink(struct archive_write *a, struct isofile *file)
-{
- struct iso9660 *iso9660 = a->format_data;
- struct hardlink *hl;
- const char *pathname;
-
- archive_entry_set_nlink(file->entry, 1);
- pathname = archive_entry_hardlink(file->entry);
- if (pathname == NULL) {
- /* This `file` is a hardlink target. */
- hl = malloc(sizeof(*hl));
- if (hl == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- hl->nlink = 1;
- /* A hardlink target must be the first position. */
- file->hlnext = NULL;
- hl->file_list.first = file;
- hl->file_list.last = &(file->hlnext);
- __archive_rb_tree_insert_node(&(iso9660->hardlink_rbtree),
- (struct archive_rb_node *)hl);
- } else {
- hl = (struct hardlink *)__archive_rb_tree_find_node(
- &(iso9660->hardlink_rbtree), pathname);
- if (hl != NULL) {
- /* Insert `file` entry into the tail. */
- file->hlnext = NULL;
- *hl->file_list.last = file;
- hl->file_list.last = &(file->hlnext);
- hl->nlink++;
- }
- archive_entry_unset_size(file->entry);
- }
-
- return (ARCHIVE_OK);
-}
-
-/*
- * Hardlinked files have to have the same location of extent.
- * We have to find out hardlink target entries for the entries
- * which have a hardlink target name.
- */
-static void
-isofile_connect_hardlink_files(struct iso9660 *iso9660)
-{
- struct archive_rb_node *n;
- struct hardlink *hl;
- struct isofile *target, *nf;
-
- ARCHIVE_RB_TREE_FOREACH(n, &(iso9660->hardlink_rbtree)) {
- hl = (struct hardlink *)n;
-
- /* The first entry must be a hardlink target. */
- target = hl->file_list.first;
- archive_entry_set_nlink(target->entry, hl->nlink);
- /* Set a hardlink target to reference entries. */
- for (nf = target->hlnext;
- nf != NULL; nf = nf->hlnext) {
- nf->hardlink_target = target;
- archive_entry_set_nlink(nf->entry, hl->nlink);
- }
- }
-}
-
-static int
-isofile_hd_cmp_node(const struct archive_rb_node *n1,
- const struct archive_rb_node *n2)
-{
- const struct hardlink *h1 = (const struct hardlink *)n1;
- const struct hardlink *h2 = (const struct hardlink *)n2;
-
- return (strcmp(archive_entry_pathname(h1->file_list.first->entry),
- archive_entry_pathname(h2->file_list.first->entry)));
-}
-
-static int
-isofile_hd_cmp_key(const struct archive_rb_node *n, const void *key)
-{
- const struct hardlink *h = (const struct hardlink *)n;
-
- return (strcmp(archive_entry_pathname(h->file_list.first->entry),
- (const char *)key));
-}
-
-static void
-isofile_init_hardlinks(struct iso9660 *iso9660)
-{
- static const struct archive_rb_tree_ops rb_ops = {
- isofile_hd_cmp_node, isofile_hd_cmp_key,
- };
-
- __archive_rb_tree_init(&(iso9660->hardlink_rbtree), &rb_ops);
-}
-
-static void
-isofile_free_hardlinks(struct iso9660 *iso9660)
-{
- struct archive_rb_node *n, *next;
-
- for (n = ARCHIVE_RB_TREE_MIN(&(iso9660->hardlink_rbtree)); n;) {
- next = __archive_rb_tree_iterate(&(iso9660->hardlink_rbtree),
- n, ARCHIVE_RB_DIR_RIGHT);
- free(n);
- n = next;
- }
-}
-
-static struct isoent *
-isoent_new(struct isofile *file)
-{
- struct isoent *isoent;
- static const struct archive_rb_tree_ops rb_ops = {
- isoent_cmp_node, isoent_cmp_key,
- };
-
- isoent = calloc(1, sizeof(*isoent));
- if (isoent == NULL)
- return (NULL);
- isoent->file = file;
- isoent->children.first = NULL;
- isoent->children.last = &(isoent->children.first);
- __archive_rb_tree_init(&(isoent->rbtree), &rb_ops);
- isoent->subdirs.first = NULL;
- isoent->subdirs.last = &(isoent->subdirs.first);
- isoent->extr_rec_list.first = NULL;
- isoent->extr_rec_list.last = &(isoent->extr_rec_list.first);
- isoent->extr_rec_list.current = NULL;
- if (archive_entry_filetype(file->entry) == AE_IFDIR)
- isoent->dir = 1;
-
- return (isoent);
-}
-
-static inline struct isoent *
-isoent_clone(struct isoent *src)
-{
- return (isoent_new(src->file));
-}
-
-static void
-_isoent_free(struct isoent *isoent)
-{
- struct extr_rec *er, *er_next;
-
- free(isoent->children_sorted);
- free(isoent->identifier);
- er = isoent->extr_rec_list.first;
- while (er != NULL) {
- er_next = er->next;
- free(er);
- er = er_next;
- }
- free(isoent);
-}
-
-static void
-isoent_free_all(struct isoent *isoent)
-{
- struct isoent *np, *np_temp;
-
- if (isoent == NULL)
- return;
- np = isoent;
- for (;;) {
- if (np->dir) {
- if (np->children.first != NULL) {
- /* Enter to sub directories. */
- np = np->children.first;
- continue;
- }
- }
- for (;;) {
- np_temp = np;
- if (np->chnext == NULL) {
- /* Return to the parent directory. */
- np = np->parent;
- _isoent_free(np_temp);
- if (np == np_temp)
- return;
- } else {
- np = np->chnext;
- _isoent_free(np_temp);
- break;
- }
- }
- }
-}
-
-static struct isoent *
-isoent_create_virtual_dir(struct archive_write *a, struct iso9660 *iso9660, const char *pathname)
-{
- struct isofile *file;
- struct isoent *isoent;
-
- file = isofile_new(a, NULL);
- if (file == NULL)
- return (NULL);
- archive_entry_set_pathname(file->entry, pathname);
- archive_entry_unset_mtime(file->entry);
- archive_entry_unset_atime(file->entry);
- archive_entry_unset_ctime(file->entry);
- archive_entry_set_uid(file->entry, getuid());
- archive_entry_set_gid(file->entry, getgid());
- archive_entry_set_mode(file->entry, 0555 | AE_IFDIR);
- archive_entry_set_nlink(file->entry, 2);
- if (isofile_gen_utility_names(a, file) < ARCHIVE_WARN) {
- isofile_free(file);
- return (NULL);
- }
- isofile_add_entry(iso9660, file);
-
- isoent = isoent_new(file);
- if (isoent == NULL)
- return (NULL);
- isoent->dir = 1;
- isoent->virtual = 1;
-
- return (isoent);
-}
-
-static int
-isoent_cmp_node(const struct archive_rb_node *n1,
- const struct archive_rb_node *n2)
-{
- const struct isoent *e1 = (const struct isoent *)n1;
- const struct isoent *e2 = (const struct isoent *)n2;
-
- return (strcmp(e1->file->basename.s, e2->file->basename.s));
-}
-
-static int
-isoent_cmp_key(const struct archive_rb_node *n, const void *key)
-{
- const struct isoent *e = (const struct isoent *)n;
-
- return (strcmp(e->file->basename.s, (const char *)key));
-}
-
-static int
-isoent_add_child_head(struct isoent *parent, struct isoent *child)
-{
-
- if (!__archive_rb_tree_insert_node(
- &(parent->rbtree), (struct archive_rb_node *)child))
- return (0);
- if ((child->chnext = parent->children.first) == NULL)
- parent->children.last = &(child->chnext);
- parent->children.first = child;
- parent->children.cnt++;
- child->parent = parent;
-
- /* Add a child to a sub-directory chain */
- if (child->dir) {
- if ((child->drnext = parent->subdirs.first) == NULL)
- parent->subdirs.last = &(child->drnext);
- parent->subdirs.first = child;
- parent->subdirs.cnt++;
- child->parent = parent;
- } else
- child->drnext = NULL;
- return (1);
-}
-
-static int
-isoent_add_child_tail(struct isoent *parent, struct isoent *child)
-{
-
- if (!__archive_rb_tree_insert_node(
- &(parent->rbtree), (struct archive_rb_node *)child))
- return (0);
- child->chnext = NULL;
- *parent->children.last = child;
- parent->children.last = &(child->chnext);
- parent->children.cnt++;
- child->parent = parent;
-
- /* Add a child to a sub-directory chain */
- child->drnext = NULL;
- if (child->dir) {
- *parent->subdirs.last = child;
- parent->subdirs.last = &(child->drnext);
- parent->subdirs.cnt++;
- child->parent = parent;
- }
- return (1);
-}
-
-static void
-isoent_remove_child(struct isoent *parent, struct isoent *child)
-{
- struct isoent *ent;
-
- /* Remove a child entry from children chain. */
- ent = parent->children.first;
- while (ent->chnext != child)
- ent = ent->chnext;
- if ((ent->chnext = ent->chnext->chnext) == NULL)
- parent->children.last = &(ent->chnext);
- parent->children.cnt--;
-
- if (child->dir) {
- /* Remove a child entry from sub-directory chain. */
- ent = parent->subdirs.first;
- while (ent->drnext != child)
- ent = ent->drnext;
- if ((ent->drnext = ent->drnext->drnext) == NULL)
- parent->subdirs.last = &(ent->drnext);
- parent->subdirs.cnt--;
- }
-
- __archive_rb_tree_remove_node(&(parent->rbtree),
- (struct archive_rb_node *)child);
-}
-
-static int
-isoent_clone_tree(struct archive_write *a, struct isoent **nroot,
- struct isoent *root)
-{
- struct isoent *np, *xroot, *newent;
-
- np = root;
- xroot = NULL;
- do {
- newent = isoent_clone(np);
- if (newent == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- if (xroot == NULL) {
- *nroot = xroot = newent;
- newent->parent = xroot;
- } else
- isoent_add_child_tail(xroot, newent);
- if (np->dir && np->children.first != NULL) {
- /* Enter to sub directories. */
- np = np->children.first;
- xroot = newent;
- continue;
- }
- while (np != np->parent) {
- if (np->chnext == NULL) {
- /* Return to the parent directory. */
- np = np->parent;
- xroot = xroot->parent;
- } else {
- np = np->chnext;
- break;
- }
- }
- } while (np != np->parent);
-
- return (ARCHIVE_OK);
-}
-
-/*
- * Setup directory locations.
- */
-static void
-isoent_setup_directory_location(struct iso9660 *iso9660, int location,
- struct vdd *vdd)
-{
- struct isoent *np;
- int depth;
-
- vdd->total_dir_block = 0;
- depth = 0;
- np = vdd->rootent;
- do {
- int block;
-
- np->dir_block = calculate_directory_descriptors(
- iso9660, vdd, np, depth);
- vdd->total_dir_block += np->dir_block;
- np->dir_location = location;
- location += np->dir_block;
- block = extra_setup_location(np, location);
- vdd->total_dir_block += block;
- location += block;
-
- if (np->subdirs.first != NULL && depth + 1 < vdd->max_depth) {
- /* Enter to sub directories. */
- np = np->subdirs.first;
- depth++;
- continue;
- }
- while (np != np->parent) {
- if (np->drnext == NULL) {
- /* Return to the parent directory. */
- np = np->parent;
- depth--;
- } else {
- np = np->drnext;
- break;
- }
- }
- } while (np != np->parent);
-}
-
-static void
-_isoent_file_location(struct iso9660 *iso9660, struct isoent *isoent,
- int *symlocation)
-{
- struct isoent **children;
- int n;
-
- if (isoent->children.cnt == 0)
- return;
-
- children = isoent->children_sorted;
- for (n = 0; n < isoent->children.cnt; n++) {
- struct isoent *np;
- struct isofile *file;
-
- np = children[n];
- if (np->dir)
- continue;
- if (np == iso9660->el_torito.boot)
- continue;
- file = np->file;
- if (file->boot || file->hardlink_target != NULL)
- continue;
- if (archive_entry_filetype(file->entry) == AE_IFLNK ||
- file->content.size == 0) {
- /*
- * Do not point a valid location.
- * Make sure entry is not hardlink file.
- */
- file->content.location = (*symlocation)--;
- continue;
- }
-
- file->write_content = 1;
- }
-}
-
-/*
- * Setup file locations.
- */
-static void
-isoent_setup_file_location(struct iso9660 *iso9660, int location)
-{
- struct isoent *isoent;
- struct isoent *np;
- struct isofile *file;
- size_t size;
- int block;
- int depth;
- int joliet;
- int symlocation;
- int total_block;
-
- iso9660->total_file_block = 0;
- if ((isoent = iso9660->el_torito.catalog) != NULL) {
- isoent->file->content.location = location;
- block = (int)((archive_entry_size(isoent->file->entry) +
- LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);
- location += block;
- iso9660->total_file_block += block;
- }
- if ((isoent = iso9660->el_torito.boot) != NULL) {
- isoent->file->content.location = location;
- size = fd_boot_image_size(iso9660->el_torito.media_type);
- if (size == 0)
- size = (size_t)archive_entry_size(isoent->file->entry);
- block = ((int)size + LOGICAL_BLOCK_SIZE -1)
- >> LOGICAL_BLOCK_BITS;
- location += block;
- iso9660->total_file_block += block;
- isoent->file->content.blocks = block;
- }
-
- depth = 0;
- symlocation = -16;
- if (!iso9660->opt.rr && iso9660->opt.joliet) {
- joliet = 1;
- np = iso9660->joliet.rootent;
- } else {
- joliet = 0;
- np = iso9660->primary.rootent;
- }
- do {
- _isoent_file_location(iso9660, np, &symlocation);
-
- if (np->subdirs.first != NULL &&
- (joliet ||
- ((iso9660->opt.rr == OPT_RR_DISABLED &&
- depth + 2 < iso9660->primary.max_depth) ||
- (iso9660->opt.rr &&
- depth + 1 < iso9660->primary.max_depth)))) {
- /* Enter to sub directories. */
- np = np->subdirs.first;
- depth++;
- continue;
- }
- while (np != np->parent) {
- if (np->drnext == NULL) {
- /* Return to the parent directory. */
- np = np->parent;
- depth--;
- } else {
- np = np->drnext;
- break;
- }
- }
- } while (np != np->parent);
-
- total_block = 0;
- for (file = iso9660->data_file_list.first;
- file != NULL; file = file->datanext) {
-
- if (!file->write_content)
- continue;
-
- file->cur_content = &(file->content);
- do {
- file->cur_content->location = location;
- location += file->cur_content->blocks;
- total_block += file->cur_content->blocks;
- /* Next fragument */
- file->cur_content = file->cur_content->next;
- } while (file->cur_content != NULL);
- }
- iso9660->total_file_block += total_block;
-}
-
-static int
-get_path_component(char *name, size_t n, const char *fn)
-{
- char *p;
- size_t l;
-
- p = strchr(fn, '/');
- if (p == NULL) {
- if ((l = strlen(fn)) == 0)
- return (0);
- } else
- l = p - fn;
- if (l > n -1)
- return (-1);
- memcpy(name, fn, l);
- name[l] = '\0';
-
- return ((int)l);
-}
-
-/*
- * Add a new entry into the tree.
- */
-static int
-isoent_tree(struct archive_write *a, struct isoent **isoentpp)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
- char name[_MAX_FNAME];/* Included null terminator size. */
-#elif defined(NAME_MAX) && NAME_MAX >= 255
- char name[NAME_MAX+1];
-#else
- char name[256];
-#endif
- struct iso9660 *iso9660 = a->format_data;
- struct isoent *dent, *isoent, *np;
- struct isofile *f1, *f2;
- const char *fn, *p;
- int l;
-
- isoent = *isoentpp;
- dent = iso9660->primary.rootent;
- if (isoent->file->parentdir.length > 0)
- fn = p = isoent->file->parentdir.s;
- else
- fn = p = "";
-
- /*
- * If the path of the parent directory of `isoent' entry is
- * the same as the path of `cur_dirent', add isoent to
- * `cur_dirent'.
- */
- if (archive_strlen(&(iso9660->cur_dirstr))
- == archive_strlen(&(isoent->file->parentdir)) &&
- strcmp(iso9660->cur_dirstr.s, fn) == 0) {
- if (!isoent_add_child_tail(iso9660->cur_dirent, isoent)) {
- np = (struct isoent *)__archive_rb_tree_find_node(
- &(iso9660->cur_dirent->rbtree),
- isoent->file->basename.s);
- goto same_entry;
- }
- return (ARCHIVE_OK);
- }
-
- for (;;) {
- l = get_path_component(name, sizeof(name), fn);
- if (l == 0) {
- np = NULL;
- break;
- }
- if (l < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "A name buffer is too small");
- _isoent_free(isoent);
- return (ARCHIVE_FATAL);
- }
-
- np = isoent_find_child(dent, name);
- if (np == NULL || fn[0] == '\0')
- break;
-
- /* Find next subdirectory. */
- if (!np->dir) {
- /* NOT Directory! */
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "`%s' is not directory, we cannot insert `%s' ",
- archive_entry_pathname(np->file->entry),
- archive_entry_pathname(isoent->file->entry));
- _isoent_free(isoent);
- *isoentpp = NULL;
- return (ARCHIVE_FAILED);
- }
- fn += l;
- if (fn[0] == '/')
- fn++;
- dent = np;
- }
- if (np == NULL) {
- /*
- * Create virtual parent directories.
- */
- while (fn[0] != '\0') {
- struct isoent *vp;
- struct archive_string as;
-
- archive_string_init(&as);
- archive_strncat(&as, p, fn - p + l);
- if (as.s[as.length-1] == '/') {
- as.s[as.length-1] = '\0';
- as.length--;
- }
- vp = isoent_create_virtual_dir(a, iso9660, as.s);
- if (vp == NULL) {
- archive_string_free(&as);
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- _isoent_free(isoent);
- *isoentpp = NULL;
- return (ARCHIVE_FATAL);
- }
- archive_string_free(&as);
-
- if (vp->file->dircnt > iso9660->dircnt_max)
- iso9660->dircnt_max = vp->file->dircnt;
- isoent_add_child_tail(dent, vp);
- np = vp;
-
- fn += l;
- if (fn[0] == '/')
- fn++;
- l = get_path_component(name, sizeof(name), fn);
- if (l < 0) {
- archive_string_free(&as);
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "A name buffer is too small");
- _isoent_free(isoent);
- *isoentpp = NULL;
- return (ARCHIVE_FATAL);
- }
- dent = np;
- }
-
- /* Found out the parent directory where isoent can be
- * inserted. */
- iso9660->cur_dirent = dent;
- archive_string_empty(&(iso9660->cur_dirstr));
- archive_string_ensure(&(iso9660->cur_dirstr),
- archive_strlen(&(dent->file->parentdir)) +
- archive_strlen(&(dent->file->basename)) + 2);
- if (archive_strlen(&(dent->file->parentdir)) +
- archive_strlen(&(dent->file->basename)) == 0)
- iso9660->cur_dirstr.s[0] = 0;
- else {
- if (archive_strlen(&(dent->file->parentdir)) > 0) {
- archive_string_copy(&(iso9660->cur_dirstr),
- &(dent->file->parentdir));
- archive_strappend_char(&(iso9660->cur_dirstr), '/');
- }
- archive_string_concat(&(iso9660->cur_dirstr),
- &(dent->file->basename));
- }
-
- if (!isoent_add_child_tail(dent, isoent)) {
- np = (struct isoent *)__archive_rb_tree_find_node(
- &(dent->rbtree), isoent->file->basename.s);
- goto same_entry;
- }
- return (ARCHIVE_OK);
- }
-
-same_entry:
- /*
- * We have already has the entry the filename of which is
- * the same.
- */
- f1 = np->file;
- f2 = isoent->file;
-
- /* If the file type of entries is different,
- * we cannot handle it. */
- if (archive_entry_filetype(f1->entry) !=
- archive_entry_filetype(f2->entry)) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Found duplicate entries `%s' and its file type is "
- "different",
- archive_entry_pathname(f1->entry));
- _isoent_free(isoent);
- *isoentpp = NULL;
- return (ARCHIVE_FAILED);
- }
-
- /* Swap file entries. */
- np->file = f2;
- isoent->file = f1;
- np->virtual = 0;
-
- _isoent_free(isoent);
- *isoentpp = np;
- return (ARCHIVE_OK);
-}
-
-/*
- * Find a entry from `isoent'
- */
-static struct isoent *
-isoent_find_child(struct isoent *isoent, const char *child_name)
-{
- struct isoent *np;
-
- np = (struct isoent *)__archive_rb_tree_find_node(
- &(isoent->rbtree), child_name);
- return (np);
-}
-
-/*
- * Find a entry full-path of which is specified by `fn' parameter,
- * in the tree.
- */
-static struct isoent *
-isoent_find_entry(struct isoent *rootent, const char *fn)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
- char name[_MAX_FNAME];/* Included null terminator size. */
-#elif defined(NAME_MAX) && NAME_MAX >= 255
- char name[NAME_MAX+1];
-#else
- char name[256];
-#endif
- struct isoent *isoent, *np;
- int l;
-
- isoent = rootent;
- np = NULL;
- for (;;) {
- l = get_path_component(name, sizeof(name), fn);
- if (l == 0)
- break;
- fn += l;
- if (fn[0] == '/')
- fn++;
-
- np = isoent_find_child(isoent, name);
- if (np == NULL)
- break;
- if (fn[0] == '\0')
- break;/* We found out the entry */
-
- /* Try sub directory. */
- isoent = np;
- np = NULL;
- if (!isoent->dir)
- break;/* Not directory */
- }
-
- return (np);
-}
-
-/*
- * Following idr_* functions are used for resolving duplicated filenames
- * and unreceivable filenames to generate ISO9660/Joliet Identifiers.
- */
-
-static void
-idr_relaxed_filenames(char *map)
-{
- int i;
-
- for (i = 0x21; i <= 0x2F; i++)
- map[i] = 1;
- for (i = 0x3A; i <= 0x41; i++)
- map[i] = 1;
- for (i = 0x5B; i <= 0x5E; i++)
- map[i] = 1;
- map[0x60] = 1;
- for (i = 0x7B; i <= 0x7E; i++)
- map[i] = 1;
-}
-
-static void
-idr_init(struct iso9660 *iso9660, struct vdd *vdd, struct idr *idr)
-{
-
- idr->idrent_pool = NULL;
- idr->pool_size = 0;
- if (vdd->vdd_type != VDD_JOLIET) {
- if (iso9660->opt.iso_level <= 3) {
- memcpy(idr->char_map, d_characters_map,
- sizeof(idr->char_map));
- } else {
- memcpy(idr->char_map, d1_characters_map,
- sizeof(idr->char_map));
- idr_relaxed_filenames(idr->char_map);
- }
- }
-}
-
-static void
-idr_cleanup(struct idr *idr)
-{
- free(idr->idrent_pool);
-}
-
-static int
-idr_ensure_poolsize(struct archive_write *a, struct idr *idr,
- int cnt)
-{
-
- if (idr->pool_size < cnt) {
- void *p;
- const int bk = (1 << 7) - 1;
- int psize;
-
- psize = (cnt + bk) & ~bk;
- p = realloc(idr->idrent_pool, sizeof(struct idrent) * psize);
- if (p == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- idr->idrent_pool = (struct idrent *)p;
- idr->pool_size = psize;
- }
- return (ARCHIVE_OK);
-}
-
-static int
-idr_start(struct archive_write *a, struct idr *idr, int cnt, int ffmax,
- int num_size, int null_size, const struct archive_rb_tree_ops *rbt_ops)
-{
- int r;
-
- (void)ffmax; /* UNUSED */
-
- r = idr_ensure_poolsize(a, idr, cnt);
- if (r != ARCHIVE_OK)
- return (r);
- __archive_rb_tree_init(&(idr->rbtree), rbt_ops);
- idr->wait_list.first = NULL;
- idr->wait_list.last = &(idr->wait_list.first);
- idr->pool_idx = 0;
- idr->num_size = num_size;
- idr->null_size = null_size;
- return (ARCHIVE_OK);
-}
-
-static void
-idr_register(struct idr *idr, struct isoent *isoent, int weight, int noff)
-{
- struct idrent *idrent, *n;
-
- idrent = &(idr->idrent_pool[idr->pool_idx++]);
- idrent->wnext = idrent->avail = NULL;
- idrent->isoent = isoent;
- idrent->weight = weight;
- idrent->noff = noff;
- idrent->rename_num = 0;
-
- if (!__archive_rb_tree_insert_node(&(idr->rbtree), &(idrent->rbnode))) {
- n = (struct idrent *)__archive_rb_tree_find_node(
- &(idr->rbtree), idrent->isoent);
- if (n != NULL) {
- /* this `idrent' needs to rename. */
- idrent->avail = n;
- *idr->wait_list.last = idrent;
- idr->wait_list.last = &(idrent->wnext);
- }
- }
-}
-
-static void
-idr_extend_identifier(struct idrent *wnp, int numsize, int nullsize)
-{
- unsigned char *p;
- int wnp_ext_off;
-
- wnp_ext_off = wnp->isoent->ext_off;
- if (wnp->noff + numsize != wnp_ext_off) {
- p = (unsigned char *)wnp->isoent->identifier;
- /* Extend the filename; foo.c --> foo___.c */
- memmove(p + wnp->noff + numsize, p + wnp_ext_off,
- wnp->isoent->ext_len + nullsize);
- wnp->isoent->ext_off = wnp_ext_off = wnp->noff + numsize;
- wnp->isoent->id_len = wnp_ext_off + wnp->isoent->ext_len;
- }
-}
-
-static void
-idr_resolve(struct idr *idr, void (*fsetnum)(unsigned char *p, int num))
-{
- struct idrent *n;
- unsigned char *p;
-
- for (n = idr->wait_list.first; n != NULL; n = n->wnext) {
- idr_extend_identifier(n, idr->num_size, idr->null_size);
- p = (unsigned char *)n->isoent->identifier + n->noff;
- do {
- fsetnum(p, n->avail->rename_num++);
- } while (!__archive_rb_tree_insert_node(
- &(idr->rbtree), &(n->rbnode)));
- }
-}
-
-static void
-idr_set_num(unsigned char *p, int num)
-{
- static const char xdig[] = {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
- 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
- 'U', 'V', 'W', 'X', 'Y', 'Z'
- };
-
- num %= sizeof(xdig) * sizeof(xdig) * sizeof(xdig);
- p[0] = xdig[(num / (sizeof(xdig) * sizeof(xdig)))];
- num %= sizeof(xdig) * sizeof(xdig);
- p[1] = xdig[ (num / sizeof(xdig))];
- num %= sizeof(xdig);
- p[2] = xdig[num];
-}
-
-static void
-idr_set_num_beutf16(unsigned char *p, int num)
-{
- static const uint16_t xdig[] = {
- 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035,
- 0x0036, 0x0037, 0x0038, 0x0039,
- 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046,
- 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C,
- 0x004D, 0x004E, 0x004F, 0x0050, 0x0051, 0x0052,
- 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
- 0x0059, 0x005A
- };
-#define XDIG_CNT (sizeof(xdig)/sizeof(xdig[0]))
-
- num %= XDIG_CNT * XDIG_CNT * XDIG_CNT;
- archive_be16enc(p, xdig[(num / (XDIG_CNT * XDIG_CNT))]);
- num %= XDIG_CNT * XDIG_CNT;
- archive_be16enc(p+2, xdig[ (num / XDIG_CNT)]);
- num %= XDIG_CNT;
- archive_be16enc(p+4, xdig[num]);
-}
-
-/*
- * Generate ISO9660 Identifier.
- */
-static int
-isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent,
- struct idr *idr)
-{
- struct iso9660 *iso9660;
- struct isoent *np;
- char *p;
- int l, r;
- const char *char_map;
- char allow_ldots, allow_multidot, allow_period, allow_vernum;
- int fnmax, ffmax, dnmax;
- static const struct archive_rb_tree_ops rb_ops = {
- isoent_cmp_node_iso9660, isoent_cmp_key_iso9660
- };
-
- if (isoent->children.cnt == 0)
- return (0);
-
- iso9660 = a->format_data;
- char_map = idr->char_map;
- if (iso9660->opt.iso_level <= 3) {
- allow_ldots = 0;
- allow_multidot = 0;
- allow_period = 1;
- allow_vernum = iso9660->opt.allow_vernum;
- if (iso9660->opt.iso_level == 1) {
- fnmax = 8;
- ffmax = 12;/* fnmax + '.' + 3 */
- dnmax = 8;
- } else {
- fnmax = 30;
- ffmax = 31;
- dnmax = 31;
- }
- } else {
- allow_ldots = allow_multidot = 1;
- allow_period = allow_vernum = 0;
- if (iso9660->opt.rr)
- /*
- * MDR : The maximum size of Directory Record(254).
- * DRL : A Directory Record Length(33).
- * CE : A size of SUSP CE System Use Entry(28).
- * MDR - DRL - CE = 254 - 33 - 28 = 193.
- */
- fnmax = ffmax = dnmax = 193;
- else
- /*
- * XA : CD-ROM XA System Use Extension
- * Information(14).
- * MDR - DRL - XA = 254 - 33 -14 = 207.
- */
- fnmax = ffmax = dnmax = 207;
- }
-
- r = idr_start(a, idr, isoent->children.cnt, ffmax, 3, 1, &rb_ops);
- if (r < 0)
- return (r);
-
- for (np = isoent->children.first; np != NULL; np = np->chnext) {
- char *dot, *xdot;
- int ext_off, noff, weight;
-
- l = (int)np->file->basename.length;
- p = malloc(l+31+2+1);
- if (p == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- memcpy(p, np->file->basename.s, l);
- p[l] = '\0';
- np->identifier = p;
-
- dot = xdot = NULL;
- if (!allow_ldots) {
- /*
- * If there is a '.' character at the first byte,
- * it has to be replaced by '_' character.
- */
- if (*p == '.')
- *p++ = '_';
- }
- for (;*p; p++) {
- if (*p & 0x80) {
- *p = '_';
- continue;
- }
- if (char_map[(unsigned char)*p]) {
- /* if iso-level is '4', a character '.' is
- * allowed by char_map. */
- if (*p == '.') {
- xdot = dot;
- dot = p;
- }
- continue;
- }
- if (*p >= 'a' && *p <= 'z') {
- *p -= 'a' - 'A';
- continue;
- }
- if (*p == '.') {
- xdot = dot;
- dot = p;
- if (allow_multidot)
- continue;
- }
- *p = '_';
- }
- p = np->identifier;
- weight = -1;
- if (dot == NULL) {
- int nammax;
-
- if (np->dir)
- nammax = dnmax;
- else
- nammax = fnmax;
-
- if (l > nammax) {
- p[nammax] = '\0';
- weight = nammax;
- ext_off = nammax;
- } else
- ext_off = l;
- } else {
- *dot = '.';
- ext_off = (int)(dot - p);
-
- if (iso9660->opt.iso_level == 1) {
- if (dot - p <= 8) {
- if (strlen(dot) > 4) {
- /* A length of a file extension
- * must be less than 4 */
- dot[4] = '\0';
- weight = 0;
- }
- } else {
- p[8] = dot[0];
- p[9] = dot[1];
- p[10] = dot[2];
- p[11] = dot[3];
- p[12] = '\0';
- weight = 8;
- ext_off = 8;
- }
- } else if (np->dir) {
- if (l > dnmax) {
- p[dnmax] = '\0';
- weight = dnmax;
- if (ext_off > dnmax)
- ext_off = dnmax;
- }
- } else if (l > ffmax) {
- int extlen = (int)strlen(dot);
- int xdoff;
-
- if (xdot != NULL)
- xdoff = (int)(xdot - p);
- else
- xdoff = 0;
-
- if (extlen > 1 && xdoff < fnmax-1) {
- int off;
-
- if (extlen > ffmax)
- extlen = ffmax;
- off = ffmax - extlen;
- if (off == 0) {
- /* A dot('.') character
- * does't place to the first
- * byte of identifier. */
- off ++;
- extlen --;
- }
- memmove(p+off, dot, extlen);
- p[ffmax] = '\0';
- ext_off = off;
- weight = off;
-#ifdef COMPAT_MKISOFS
- } else if (xdoff >= fnmax-1) {
- /* Simulate a bug(?) of mkisofs. */
- p[fnmax-1] = '\0';
- ext_off = fnmax-1;
- weight = fnmax-1;
-#endif
- } else {
- p[fnmax] = '\0';
- ext_off = fnmax;
- weight = fnmax;
- }
- }
- }
- /* Save an offset of a file name extension to sort files. */
- np->ext_off = ext_off;
- np->ext_len = (int)strlen(&p[ext_off]);
- np->id_len = l = ext_off + np->ext_len;
-
- /* Make an offset of the number which is used to be set
- * hexadecimal number to avoid duplicate identififier. */
- if (iso9660->opt.iso_level == 1) {
- if (ext_off >= 5)
- noff = 5;
- else
- noff = ext_off;
- } else {
- if (l == ffmax)
- noff = ext_off - 3;
- else if (l == ffmax-1)
- noff = ext_off - 2;
- else if (l == ffmax-2)
- noff = ext_off - 1;
- else
- noff = ext_off;
- }
- /* Register entry to the identifier resolver. */
- idr_register(idr, np, weight, noff);
- }
-
- /* Resolve duplicate identifier. */
- idr_resolve(idr, idr_set_num);
-
- /* Add a period and a version number to identifiers. */
- for (np = isoent->children.first; np != NULL; np = np->chnext) {
- if (!np->dir && np->rr_child == NULL) {
- p = np->identifier + np->ext_off + np->ext_len;
- if (np->ext_len == 0 && allow_period) {
- *p++ = '.';
- np->ext_len = 1;
- }
- if (np->ext_len == 1 && !allow_period) {
- *--p = '\0';
- np->ext_len = 0;
- }
- np->id_len = np->ext_off + np->ext_len;
- if (allow_vernum) {
- *p++ = ';';
- *p++ = '1';
- np->id_len += 2;
- }
- *p = '\0';
- } else
- np->id_len = np->ext_off + np->ext_len;
- np->mb_len = np->id_len;
- }
- return (ARCHIVE_OK);
-}
-
-/*
- * Generate Joliet Identifier.
- */
-static int
-isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
- struct idr *idr)
-{
- struct iso9660 *iso9660;
- struct isoent *np;
- unsigned char *p;
- size_t l;
- int r;
- int ffmax, parent_len;
- static const struct archive_rb_tree_ops rb_ops = {
- isoent_cmp_node_joliet, isoent_cmp_key_joliet
- };
-
- if (isoent->children.cnt == 0)
- return (0);
-
- iso9660 = a->format_data;
- if (iso9660->opt.joliet == OPT_JOLIET_LONGNAME)
- ffmax = 206;
- else
- ffmax = 128;
-
- r = idr_start(a, idr, isoent->children.cnt, ffmax, 6, 2, &rb_ops);
- if (r < 0)
- return (r);
-
- parent_len = 1;
- for (np = isoent; np->parent != np; np = np->parent)
- parent_len += np->mb_len + 1;
-
- for (np = isoent->children.first; np != NULL; np = np->chnext) {
- unsigned char *dot;
- int ext_off, noff, weight;
- size_t lt;
-
- if ((int)(l = np->file->basename_utf16.length) > ffmax)
- l = ffmax;
-
- p = malloc((l+1)*2);
- if (p == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- memcpy(p, np->file->basename_utf16.s, l);
- p[l] = 0;
- p[l+1] = 0;
-
- np->identifier = (char *)p;
- lt = l;
- dot = p + l;
- weight = 0;
- while (lt > 0) {
- if (!joliet_allowed_char(p[0], p[1]))
- archive_be16enc(p, 0x005F); /* '_' */
- else if (p[0] == 0 && p[1] == 0x2E) /* '.' */
- dot = p;
- p += 2;
- lt -= 2;
- }
- ext_off = (int)(dot - (unsigned char *)np->identifier);
- np->ext_off = ext_off;
- np->ext_len = (int)l - ext_off;
- np->id_len = (int)l;
-
- /*
- * Get a length of MBS of a full-pathname.
- */
- if ((int)np->file->basename_utf16.length > ffmax) {
- if (archive_strncpy_l(&iso9660->mbs,
- (const char *)np->identifier, l,
- iso9660->sconv_from_utf16be) != 0 &&
- errno == ENOMEM) {
- archive_set_error(&a->archive, errno,
- "No memory");
- return (ARCHIVE_FATAL);
- }
- np->mb_len = (int)iso9660->mbs.length;
- if (np->mb_len != (int)np->file->basename.length)
- weight = np->mb_len;
- } else
- np->mb_len = (int)np->file->basename.length;
-
- /* If a length of full-pathname is longer than 240 bytes,
- * it violates Joliet extensions regulation. */
- if (parent_len + np->mb_len > 240) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "The regulation of Joliet extensions;"
- " A length of a full-pathname of `%s' is "
- "longer than 240 bytes, (p=%d, b=%d)",
- archive_entry_pathname(np->file->entry),
- (int)parent_len, (int)np->mb_len);
- return (ARCHIVE_FATAL);
- }
-
- /* Make an offset of the number which is used to be set
- * hexadecimal number to avoid duplicate identifier. */
- if ((int)l == ffmax)
- noff = ext_off - 6;
- else if ((int)l == ffmax-2)
- noff = ext_off - 4;
- else if ((int)l == ffmax-4)
- noff = ext_off - 2;
- else
- noff = ext_off;
- /* Register entry to the identifier resolver. */
- idr_register(idr, np, weight, noff);
- }
-
- /* Resolve duplicate identifier with Joliet Volume. */
- idr_resolve(idr, idr_set_num_beutf16);
-
- return (ARCHIVE_OK);
-}
-
-/*
- * This comparing rule is according to ISO9660 Standard 9.3
- */
-static int
-isoent_cmp_iso9660_identifier(const struct isoent *p1, const struct isoent *p2)
-{
- const char *s1, *s2;
- int cmp;
- int l;
-
- s1 = p1->identifier;
- s2 = p2->identifier;
-
- /* Compare File Name */
- l = p1->ext_off;
- if (l > p2->ext_off)
- l = p2->ext_off;
- cmp = memcmp(s1, s2, l);
- if (cmp != 0)
- return (cmp);
- if (p1->ext_off < p2->ext_off) {
- s2 += l;
- l = p2->ext_off - p1->ext_off;
- while (l--)
- if (0x20 != *s2++)
- return (0x20
- - *(const unsigned char *)(s2 - 1));
- } else if (p1->ext_off > p2->ext_off) {
- s1 += l;
- l = p1->ext_off - p2->ext_off;
- while (l--)
- if (0x20 != *s1++)
- return (*(const unsigned char *)(s1 - 1)
- - 0x20);
- }
- /* Compare File Name Extension */
- if (p1->ext_len == 0 && p2->ext_len == 0)
- return (0);
- if (p1->ext_len == 1 && p2->ext_len == 1)
- return (0);
- if (p1->ext_len <= 1)
- return (-1);
- if (p2->ext_len <= 1)
- return (1);
- l = p1->ext_len;
- if (l > p2->ext_len)
- l = p2->ext_len;
- s1 = p1->identifier + p1->ext_off;
- s2 = p2->identifier + p2->ext_off;
- if (l > 1) {
- cmp = memcmp(s1, s2, l);
- if (cmp != 0)
- return (cmp);
- }
- if (p1->ext_len < p2->ext_len) {
- s2 += l;
- l = p2->ext_len - p1->ext_len;
- while (l--)
- if (0x20 != *s2++)
- return (0x20
- - *(const unsigned char *)(s2 - 1));
- } else if (p1->ext_len > p2->ext_len) {
- s1 += l;
- l = p1->ext_len - p2->ext_len;
- while (l--)
- if (0x20 != *s1++)
- return (*(const unsigned char *)(s1 - 1)
- - 0x20);
- }
- /* Compare File Version Number */
- /* No operation. The File Version Number is always one. */
-
- return (cmp);
-}
-
-static int
-isoent_cmp_node_iso9660(const struct archive_rb_node *n1,
- const struct archive_rb_node *n2)
-{
- const struct idrent *e1 = (const struct idrent *)n1;
- const struct idrent *e2 = (const struct idrent *)n2;
-
- return (isoent_cmp_iso9660_identifier(e2->isoent, e1->isoent));
-}
-
-static int
-isoent_cmp_key_iso9660(const struct archive_rb_node *node, const void *key)
-{
- const struct isoent *isoent = (const struct isoent *)key;
- const struct idrent *idrent = (const struct idrent *)node;
-
- return (isoent_cmp_iso9660_identifier(isoent, idrent->isoent));
-}
-
-static int
-isoent_cmp_joliet_identifier(const struct isoent *p1, const struct isoent *p2)
-{
- const unsigned char *s1, *s2;
- int cmp;
- int l;
-
- s1 = (const unsigned char *)p1->identifier;
- s2 = (const unsigned char *)p2->identifier;
-
- /* Compare File Name */
- l = p1->ext_off;
- if (l > p2->ext_off)
- l = p2->ext_off;
- cmp = memcmp(s1, s2, l);
- if (cmp != 0)
- return (cmp);
- if (p1->ext_off < p2->ext_off) {
- s2 += l;
- l = p2->ext_off - p1->ext_off;
- while (l--)
- if (0 != *s2++)
- return (- *(const unsigned char *)(s2 - 1));
- } else if (p1->ext_off > p2->ext_off) {
- s1 += l;
- l = p1->ext_off - p2->ext_off;
- while (l--)
- if (0 != *s1++)
- return (*(const unsigned char *)(s1 - 1));
- }
- /* Compare File Name Extension */
- if (p1->ext_len == 0 && p2->ext_len == 0)
- return (0);
- if (p1->ext_len == 2 && p2->ext_len == 2)
- return (0);
- if (p1->ext_len <= 2)
- return (-1);
- if (p2->ext_len <= 2)
- return (1);
- l = p1->ext_len;
- if (l > p2->ext_len)
- l = p2->ext_len;
- s1 = (unsigned char *)(p1->identifier + p1->ext_off);
- s2 = (unsigned char *)(p2->identifier + p2->ext_off);
- if (l > 1) {
- cmp = memcmp(s1, s2, l);
- if (cmp != 0)
- return (cmp);
- }
- if (p1->ext_len < p2->ext_len) {
- s2 += l;
- l = p2->ext_len - p1->ext_len;
- while (l--)
- if (0 != *s2++)
- return (- *(const unsigned char *)(s2 - 1));
- } else if (p1->ext_len > p2->ext_len) {
- s1 += l;
- l = p1->ext_len - p2->ext_len;
- while (l--)
- if (0 != *s1++)
- return (*(const unsigned char *)(s1 - 1));
- }
- /* Compare File Version Number */
- /* No operation. The File Version Number is always one. */
-
- return (cmp);
-}
-
-static int
-isoent_cmp_node_joliet(const struct archive_rb_node *n1,
- const struct archive_rb_node *n2)
-{
- const struct idrent *e1 = (const struct idrent *)n1;
- const struct idrent *e2 = (const struct idrent *)n2;
-
- return (isoent_cmp_joliet_identifier(e2->isoent, e1->isoent));
-}
-
-static int
-isoent_cmp_key_joliet(const struct archive_rb_node *node, const void *key)
-{
- const struct isoent *isoent = (const struct isoent *)key;
- const struct idrent *idrent = (const struct idrent *)node;
-
- return (isoent_cmp_joliet_identifier(isoent, idrent->isoent));
-}
-
-static int
-isoent_make_sorted_files(struct archive_write *a, struct isoent *isoent,
- struct idr *idr)
-{
- struct archive_rb_node *rn;
- struct isoent **children;
-
- children = malloc(isoent->children.cnt * sizeof(struct isoent *));
- if (children == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- isoent->children_sorted = children;
-
- ARCHIVE_RB_TREE_FOREACH(rn, &(idr->rbtree)) {
- struct idrent *idrent = (struct idrent *)rn;
- *children ++ = idrent->isoent;
- }
- return (ARCHIVE_OK);
-}
-
-/*
- * - Generate ISO9660 and Joliet identifiers from basenames.
- * - Sort files by each directory.
- */
-static int
-isoent_traverse_tree(struct archive_write *a, struct vdd* vdd)
-{
- struct iso9660 *iso9660 = a->format_data;
- struct isoent *np;
- struct idr idr;
- int depth;
- int r;
- int (*genid)(struct archive_write *, struct isoent *, struct idr *);
-
- idr_init(iso9660, vdd, &idr);
- np = vdd->rootent;
- depth = 0;
- if (vdd->vdd_type == VDD_JOLIET)
- genid = isoent_gen_joliet_identifier;
- else
- genid = isoent_gen_iso9660_identifier;
- do {
- if (np->virtual &&
- !archive_entry_mtime_is_set(np->file->entry)) {
- /* Set properly times to virtual directory */
- archive_entry_set_mtime(np->file->entry,
- iso9660->birth_time, 0);
- archive_entry_set_atime(np->file->entry,
- iso9660->birth_time, 0);
- archive_entry_set_ctime(np->file->entry,
- iso9660->birth_time, 0);
- }
- if (np->children.first != NULL) {
- if (vdd->vdd_type != VDD_JOLIET &&
- !iso9660->opt.rr && depth + 1 >= vdd->max_depth) {
- if (np->children.cnt > 0)
- iso9660->directories_too_deep = np;
- } else {
- /* Generate Identifier */
- r = genid(a, np, &idr);
- if (r < 0)
- goto exit_traverse_tree;
- r = isoent_make_sorted_files(a, np, &idr);
- if (r < 0)
- goto exit_traverse_tree;
-
- if (np->subdirs.first != NULL &&
- depth + 1 < vdd->max_depth) {
- /* Enter to sub directories. */
- np = np->subdirs.first;
- depth++;
- continue;
- }
- }
- }
- while (np != np->parent) {
- if (np->drnext == NULL) {
- /* Return to the parent directory. */
- np = np->parent;
- depth--;
- } else {
- np = np->drnext;
- break;
- }
- }
- } while (np != np->parent);
-
- r = ARCHIVE_OK;
-exit_traverse_tree:
- idr_cleanup(&idr);
-
- return (r);
-}
-
-/*
- * Collect directory entries into path_table by a directory depth.
- */
-static int
-isoent_collect_dirs(struct vdd *vdd, struct isoent *rootent, int depth)
-{
- struct isoent *np;
-
- if (rootent == NULL)
- rootent = vdd->rootent;
- np = rootent;
- do {
- /* Register current directory to pathtable. */
- path_table_add_entry(&(vdd->pathtbl[depth]), np);
-
- if (np->subdirs.first != NULL && depth + 1 < vdd->max_depth) {
- /* Enter to sub directories. */
- np = np->subdirs.first;
- depth++;
- continue;
- }
- while (np != rootent) {
- if (np->drnext == NULL) {
- /* Return to the parent directory. */
- np = np->parent;
- depth--;
- } else {
- np = np->drnext;
- break;
- }
- }
- } while (np != rootent);
-
- return (ARCHIVE_OK);
-}
-
-/*
- * The entry whose number of levels in a directory hierarchy is
- * large than eight relocate to rr_move directory.
- */
-static int
-isoent_rr_move_dir(struct archive_write *a, struct isoent **rr_moved,
- struct isoent *curent, struct isoent **newent)
-{
- struct iso9660 *iso9660 = a->format_data;
- struct isoent *rrmoved, *mvent, *np;
-
- if ((rrmoved = *rr_moved) == NULL) {
- struct isoent *rootent = iso9660->primary.rootent;
- /* There isn't rr_move entry.
- * Create rr_move entry and insert it into the root entry.
- */
- rrmoved = isoent_create_virtual_dir(a, iso9660, "rr_moved");
- if (rrmoved == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- /* Add "rr_moved" entry to the root entry. */
- isoent_add_child_head(rootent, rrmoved);
- archive_entry_set_nlink(rootent->file->entry,
- archive_entry_nlink(rootent->file->entry) + 1);
- /* Register "rr_moved" entry to second level pathtable. */
- path_table_add_entry(&(iso9660->primary.pathtbl[1]), rrmoved);
- /* Save rr_moved. */
- *rr_moved = rrmoved;
- }
- /*
- * Make a clone of curent which is going to be relocated
- * to rr_moved.
- */
- mvent = isoent_clone(curent);
- if (mvent == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- /* linking.. and use for creating "CL", "PL" and "RE" */
- mvent->rr_parent = curent->parent;
- curent->rr_child = mvent;
- /*
- * Move subdirectories from the curent to mvent
- */
- if (curent->children.first != NULL) {
- *mvent->children.last = curent->children.first;
- mvent->children.last = curent->children.last;
- }
- for (np = mvent->children.first; np != NULL; np = np->chnext)
- np->parent = mvent;
- mvent->children.cnt = curent->children.cnt;
- curent->children.cnt = 0;
- curent->children.first = NULL;
- curent->children.last = &curent->children.first;
-
- if (curent->subdirs.first != NULL) {
- *mvent->subdirs.last = curent->subdirs.first;
- mvent->subdirs.last = curent->subdirs.last;
- }
- mvent->subdirs.cnt = curent->subdirs.cnt;
- curent->subdirs.cnt = 0;
- curent->subdirs.first = NULL;
- curent->subdirs.last = &curent->subdirs.first;
-
- /*
- * The mvent becomes a child of the rr_moved entry.
- */
- isoent_add_child_tail(rrmoved, mvent);
- archive_entry_set_nlink(rrmoved->file->entry,
- archive_entry_nlink(rrmoved->file->entry) + 1);
- /*
- * This entry which relocated to the rr_moved directory
- * has to set the flag as a file.
- * See also RRIP 4.1.5.1 Description of the "CL" System Use Entry.
- */
- curent->dir = 0;
-
- *newent = mvent;
-
- return (ARCHIVE_OK);
-}
-
-static int
-isoent_rr_move(struct archive_write *a)
-{
- struct iso9660 *iso9660 = a->format_data;
- struct path_table *pt;
- struct isoent *rootent, *rr_moved;
- struct isoent *np, *last;
- int r;
-
- pt = &(iso9660->primary.pathtbl[MAX_DEPTH-1]);
- /* Theare aren't level 8 directories reaching a deepr level. */
- if (pt->cnt == 0)
- return (ARCHIVE_OK);
-
- rootent = iso9660->primary.rootent;
- /* If "rr_moved" directory is already existing,
- * we have to use it. */
- rr_moved = isoent_find_child(rootent, "rr_moved");
- if (rr_moved != NULL &&
- rr_moved != rootent->children.first) {
- /*
- * It's necessary that rr_move is the first entry
- * of the root.
- */
- /* Remove "rr_moved" entry from children chain. */
- isoent_remove_child(rootent, rr_moved);
-
- /* Add "rr_moved" entry into the head of children chain. */
- isoent_add_child_head(rootent, rr_moved);
- }
-
- /*
- * Check level 8 path_table.
- * If find out sub directory entries, that entries move to rr_move.
- */
- np = pt->first;
- while (np != NULL) {
- last = path_table_last_entry(pt);
- for (; np != NULL; np = np->ptnext) {
- struct isoent *mvent;
- struct isoent *newent;
-
- if (!np->dir)
- continue;
- for (mvent = np->subdirs.first;
- mvent != NULL; mvent = mvent->drnext) {
- r = isoent_rr_move_dir(a, &rr_moved,
- mvent, &newent);
- if (r < 0)
- return (r);
- isoent_collect_dirs(&(iso9660->primary),
- newent, 2);
- }
- }
- /* If new entries are added to level 8 path_talbe,
- * its sub directory entries move to rr_move too.
- */
- np = last->ptnext;
- }
-
- return (ARCHIVE_OK);
-}
-
-/*
- * This comparing rule is according to ISO9660 Standard 6.9.1
- */
-static int
-_compare_path_table(const void *v1, const void *v2)
-{
- const struct isoent *p1, *p2;
- const char *s1, *s2;
- int cmp, l;
-
- p1 = *((const struct isoent **)(uintptr_t)v1);
- p2 = *((const struct isoent **)(uintptr_t)v2);
-
- /* Compare parent directory number */
- cmp = p1->parent->dir_number - p2->parent->dir_number;
- if (cmp != 0)
- return (cmp);
-
- /* Compare indetifier */
- s1 = p1->identifier;
- s2 = p2->identifier;
- l = p1->ext_off;
- if (l > p2->ext_off)
- l = p2->ext_off;
- cmp = strncmp(s1, s2, l);
- if (cmp != 0)
- return (cmp);
- if (p1->ext_off < p2->ext_off) {
- s2 += l;
- l = p2->ext_off - p1->ext_off;
- while (l--)
- if (0x20 != *s2++)
- return (0x20
- - *(const unsigned char *)(s2 - 1));
- } else if (p1->ext_off > p2->ext_off) {
- s1 += l;
- l = p1->ext_off - p2->ext_off;
- while (l--)
- if (0x20 != *s1++)
- return (*(const unsigned char *)(s1 - 1)
- - 0x20);
- }
- return (0);
-}
-
-static int
-_compare_path_table_joliet(const void *v1, const void *v2)
-{
- const struct isoent *p1, *p2;
- const unsigned char *s1, *s2;
- int cmp, l;
-
- p1 = *((const struct isoent **)(uintptr_t)v1);
- p2 = *((const struct isoent **)(uintptr_t)v2);
-
- /* Compare parent directory number */
- cmp = p1->parent->dir_number - p2->parent->dir_number;
- if (cmp != 0)
- return (cmp);
-
- /* Compare indetifier */
- s1 = (const unsigned char *)p1->identifier;
- s2 = (const unsigned char *)p2->identifier;
- l = p1->ext_off;
- if (l > p2->ext_off)
- l = p2->ext_off;
- cmp = memcmp(s1, s2, l);
- if (cmp != 0)
- return (cmp);
- if (p1->ext_off < p2->ext_off) {
- s2 += l;
- l = p2->ext_off - p1->ext_off;
- while (l--)
- if (0 != *s2++)
- return (- *(const unsigned char *)(s2 - 1));
- } else if (p1->ext_off > p2->ext_off) {
- s1 += l;
- l = p1->ext_off - p2->ext_off;
- while (l--)
- if (0 != *s1++)
- return (*(const unsigned char *)(s1 - 1));
- }
- return (0);
-}
-
-static inline void
-path_table_add_entry(struct path_table *pathtbl, struct isoent *ent)
-{
- ent->ptnext = NULL;
- *pathtbl->last = ent;
- pathtbl->last = &(ent->ptnext);
- pathtbl->cnt ++;
-}
-
-static inline struct isoent *
-path_table_last_entry(struct path_table *pathtbl)
-{
- if (pathtbl->first == NULL)
- return (NULL);
- return (((struct isoent *)(void *)
- ((char *)(pathtbl->last) - offsetof(struct isoent, ptnext))));
-}
-
-/*
- * Sort directory entries in path_table
- * and assign directory number to each entries.
- */
-static int
-isoent_make_path_table_2(struct archive_write *a, struct vdd *vdd,
- int depth, int *dir_number)
-{
- struct isoent *np;
- struct isoent **enttbl;
- struct path_table *pt;
- int i;
-
- pt = &vdd->pathtbl[depth];
- if (pt->cnt == 0) {
- pt->sorted = NULL;
- return (ARCHIVE_OK);
- }
- enttbl = malloc(pt->cnt * sizeof(struct isoent *));
- if (enttbl == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- pt->sorted = enttbl;
- for (np = pt->first; np != NULL; np = np->ptnext)
- *enttbl ++ = np;
- enttbl = pt->sorted;
-
- switch (vdd->vdd_type) {
- case VDD_PRIMARY:
- case VDD_ENHANCED:
-#ifdef __COMPAR_FN_T
- qsort(enttbl, pt->cnt, sizeof(struct isoent *),
- (__compar_fn_t)_compare_path_table);
-#else
- qsort(enttbl, pt->cnt, sizeof(struct isoent *),
- _compare_path_table);
-#endif
- break;
- case VDD_JOLIET:
-#ifdef __COMPAR_FN_T
- qsort(enttbl, pt->cnt, sizeof(struct isoent *),
- (__compar_fn_t)_compare_path_table_joliet);
-#else
- qsort(enttbl, pt->cnt, sizeof(struct isoent *),
- _compare_path_table_joliet);
-#endif
- break;
- }
- for (i = 0; i < pt->cnt; i++)
- enttbl[i]->dir_number = (*dir_number)++;
-
- return (ARCHIVE_OK);
-}
-
-static int
-isoent_alloc_path_table(struct archive_write *a, struct vdd *vdd,
- int max_depth)
-{
- int i;
-
- vdd->max_depth = max_depth;
- vdd->pathtbl = malloc(sizeof(*vdd->pathtbl) * vdd->max_depth);
- if (vdd->pathtbl == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- for (i = 0; i < vdd->max_depth; i++) {
- vdd->pathtbl[i].first = NULL;
- vdd->pathtbl[i].last = &(vdd->pathtbl[i].first);
- vdd->pathtbl[i].sorted = NULL;
- vdd->pathtbl[i].cnt = 0;
- }
- return (ARCHIVE_OK);
-}
-
-/*
- * Make Path Tables
- */
-static int
-isoent_make_path_table(struct archive_write *a)
-{
- struct iso9660 *iso9660 = a->format_data;
- int depth, r;
- int dir_number;
-
- /*
- * Init Path Table.
- */
- if (iso9660->dircnt_max >= MAX_DEPTH &&
- (!iso9660->opt.limit_depth || iso9660->opt.iso_level == 4))
- r = isoent_alloc_path_table(a, &(iso9660->primary),
- iso9660->dircnt_max + 1);
- else
- /* The number of levels in the hierarchy cannot exceed
- * eight. */
- r = isoent_alloc_path_table(a, &(iso9660->primary),
- MAX_DEPTH);
- if (r < 0)
- return (r);
- if (iso9660->opt.joliet) {
- r = isoent_alloc_path_table(a, &(iso9660->joliet),
- iso9660->dircnt_max + 1);
- if (r < 0)
- return (r);
- }
-
- /* Step 0.
- * - Collect directories for primary and joliet.
- */
- isoent_collect_dirs(&(iso9660->primary), NULL, 0);
- if (iso9660->opt.joliet)
- isoent_collect_dirs(&(iso9660->joliet), NULL, 0);
- /*
- * Rockridge; move deeper depth directories to rr_moved.
- */
- if (iso9660->opt.rr) {
- r = isoent_rr_move(a);
- if (r < 0)
- return (r);
- }
-
- /* Update nlink. */
- isofile_connect_hardlink_files(iso9660);
-
- /* Step 1.
- * - Renew a value of the depth of that directories.
- * - Resolve hardlinks.
- * - Convert pathnames to ISO9660 name or UCS2(joliet).
- * - Sort files by each directory.
- */
- r = isoent_traverse_tree(a, &(iso9660->primary));
- if (r < 0)
- return (r);
- if (iso9660->opt.joliet) {
- r = isoent_traverse_tree(a, &(iso9660->joliet));
- if (r < 0)
- return (r);
- }
-
- /* Step 2.
- * - Sort directories.
- * - Assign all directory number.
- */
- dir_number = 1;
- for (depth = 0; depth < iso9660->primary.max_depth; depth++) {
- r = isoent_make_path_table_2(a, &(iso9660->primary),
- depth, &dir_number);
- if (r < 0)
- return (r);
- }
- if (iso9660->opt.joliet) {
- dir_number = 1;
- for (depth = 0; depth < iso9660->joliet.max_depth; depth++) {
- r = isoent_make_path_table_2(a, &(iso9660->joliet),
- depth, &dir_number);
- if (r < 0)
- return (r);
- }
- }
- if (iso9660->opt.limit_dirs && dir_number > 0xffff) {
- /*
- * Maximum number of directories is 65535(0xffff)
- * doe to size(16bit) of Parent Directory Number of
- * the Path Table.
- * See also ISO9660 Standard 9.4.
- */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Too many directories(%d) over 65535.", dir_number);
- return (ARCHIVE_FATAL);
- }
-
- /* Get the size of the Path Table. */
- calculate_path_table_size(&(iso9660->primary));
- if (iso9660->opt.joliet)
- calculate_path_table_size(&(iso9660->joliet));
-
- return (ARCHIVE_OK);
-}
-
-static int
-isoent_find_out_boot_file(struct archive_write *a, struct isoent *rootent)
-{
- struct iso9660 *iso9660 = a->format_data;
-
- /* Find a isoent of the boot file. */
- iso9660->el_torito.boot = isoent_find_entry(rootent,
- iso9660->el_torito.boot_filename.s);
- if (iso9660->el_torito.boot == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Can't find the boot image file ``%s''",
- iso9660->el_torito.boot_filename.s);
- return (ARCHIVE_FATAL);
- }
- iso9660->el_torito.boot->file->boot = BOOT_IMAGE;
- return (ARCHIVE_OK);
-}
-
-static int
-isoent_create_boot_catalog(struct archive_write *a, struct isoent *rootent)
-{
- struct iso9660 *iso9660 = a->format_data;
- struct isofile *file;
- struct isoent *isoent;
- struct archive_entry *entry;
-
- (void)rootent; /* UNUSED */
- /*
- * Create the entry which is the "boot.catalog" file.
- */
- file = isofile_new(a, NULL);
- if (file == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- archive_entry_set_pathname(file->entry,
- iso9660->el_torito.catalog_filename.s);
- archive_entry_set_size(file->entry, LOGICAL_BLOCK_SIZE);
- archive_entry_set_mtime(file->entry, iso9660->birth_time, 0);
- archive_entry_set_atime(file->entry, iso9660->birth_time, 0);
- archive_entry_set_ctime(file->entry, iso9660->birth_time, 0);
- archive_entry_set_uid(file->entry, getuid());
- archive_entry_set_gid(file->entry, getgid());
- archive_entry_set_mode(file->entry, AE_IFREG | 0444);
- archive_entry_set_nlink(file->entry, 1);
-
- if (isofile_gen_utility_names(a, file) < ARCHIVE_WARN) {
- isofile_free(file);
- return (ARCHIVE_FATAL);
- }
- file->boot = BOOT_CATALOG;
- file->content.size = LOGICAL_BLOCK_SIZE;
- isofile_add_entry(iso9660, file);
-
- isoent = isoent_new(file);
- if (isoent == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- isoent->virtual = 1;
-
- /* Add the "boot.catalog" entry into tree */
- if (isoent_tree(a, &isoent) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- iso9660->el_torito.catalog = isoent;
- /*
- * Get a boot medai type.
- */
- switch (iso9660->opt.boot_type) {
- default:
- case OPT_BOOT_TYPE_AUTO:
- /* Try detecting a media type of the boot image. */
- entry = iso9660->el_torito.boot->file->entry;
- if (archive_entry_size(entry) == FD_1_2M_SIZE)
- iso9660->el_torito.media_type =
- BOOT_MEDIA_1_2M_DISKETTE;
- else if (archive_entry_size(entry) == FD_1_44M_SIZE)
- iso9660->el_torito.media_type =
- BOOT_MEDIA_1_44M_DISKETTE;
- else if (archive_entry_size(entry) == FD_2_88M_SIZE)
- iso9660->el_torito.media_type =
- BOOT_MEDIA_2_88M_DISKETTE;
- else
- /* We cannot decide whether the boot image is
- * hard-disk. */
- iso9660->el_torito.media_type =
- BOOT_MEDIA_NO_EMULATION;
- break;
- case OPT_BOOT_TYPE_NO_EMU:
- iso9660->el_torito.media_type = BOOT_MEDIA_NO_EMULATION;
- break;
- case OPT_BOOT_TYPE_HARD_DISK:
- iso9660->el_torito.media_type = BOOT_MEDIA_HARD_DISK;
- break;
- case OPT_BOOT_TYPE_FD:
- entry = iso9660->el_torito.boot->file->entry;
- if (archive_entry_size(entry) <= FD_1_2M_SIZE)
- iso9660->el_torito.media_type =
- BOOT_MEDIA_1_2M_DISKETTE;
- else if (archive_entry_size(entry) <= FD_1_44M_SIZE)
- iso9660->el_torito.media_type =
- BOOT_MEDIA_1_44M_DISKETTE;
- else if (archive_entry_size(entry) <= FD_2_88M_SIZE)
- iso9660->el_torito.media_type =
- BOOT_MEDIA_2_88M_DISKETTE;
- else {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Boot image file(``%s'') size is too big "
- "for fd type.",
- iso9660->el_torito.boot_filename.s);
- return (ARCHIVE_FATAL);
- }
- break;
- }
-
- /*
- * Get a system type.
- * TODO: `El Torito' specification says "A copy of byte 5 from the
- * Partition Table found in the boot image".
- */
- iso9660->el_torito.system_type = 0;
-
- /*
- * Get an ID.
- */
- if (iso9660->opt.publisher)
- archive_string_copy(&(iso9660->el_torito.id),
- &(iso9660->publisher_identifier));
-
-
- return (ARCHIVE_OK);
-}
-
-/*
- * If a media type is floppy, return its image size.
- * otherwise return 0.
- */
-static size_t
-fd_boot_image_size(int media_type)
-{
- switch (media_type) {
- case BOOT_MEDIA_1_2M_DISKETTE:
- return (FD_1_2M_SIZE);
- case BOOT_MEDIA_1_44M_DISKETTE:
- return (FD_1_44M_SIZE);
- case BOOT_MEDIA_2_88M_DISKETTE:
- return (FD_2_88M_SIZE);
- default:
- return (0);
- }
-}
-
-/*
- * Make a boot catalog image data.
- */
-static int
-make_boot_catalog(struct archive_write *a)
-{
- struct iso9660 *iso9660 = a->format_data;
- unsigned char *block;
- unsigned char *p;
- uint16_t sum, *wp;
-
- block = wb_buffptr(a);
- memset(block, 0, LOGICAL_BLOCK_SIZE);
- p = block;
- /*
- * Validation Entry
- */
- /* Header ID */
- p[0] = 1;
- /* Platform ID */
- p[1] = iso9660->el_torito.platform_id;
- /* Reserved */
- p[2] = p[3] = 0;
- /* ID */
- if (archive_strlen(&(iso9660->el_torito.id)) > 0)
- strncpy((char *)p+4, iso9660->el_torito.id.s, 23);
- p[27] = 0;
- /* Checksum */
- p[28] = p[29] = 0;
- /* Key */
- p[30] = 0x55;
- p[31] = 0xAA;
-
- sum = 0;
- wp = (uint16_t *)block;
- while (wp < (uint16_t *)&block[32])
- sum += archive_le16dec(wp++);
- set_num_721(&block[28], (~sum) + 1);
-
- /*
- * Initial/Default Entry
- */
- p = &block[32];
- /* Boot Indicator */
- p[0] = 0x88;
- /* Boot media type */
- p[1] = iso9660->el_torito.media_type;
- /* Load Segment */
- if (iso9660->el_torito.media_type == BOOT_MEDIA_NO_EMULATION)
- set_num_721(&p[2], iso9660->el_torito.boot_load_seg);
- else
- set_num_721(&p[2], 0);
- /* System Type */
- p[4] = iso9660->el_torito.system_type;
- /* Unused */
- p[5] = 0;
- /* Sector Count */
- if (iso9660->el_torito.media_type == BOOT_MEDIA_NO_EMULATION)
- set_num_721(&p[6], iso9660->el_torito.boot_load_size);
- else
- set_num_721(&p[6], 1);
- /* Load RBA */
- set_num_731(&p[8],
- iso9660->el_torito.boot->file->content.location);
- /* Unused */
- memset(&p[12], 0, 20);
-
- return (wb_consume(a, LOGICAL_BLOCK_SIZE));
-}
-
-static int
-setup_boot_information(struct archive_write *a)
-{
- struct iso9660 *iso9660 = a->format_data;
- struct isoent *np;
- int64_t size;
- uint32_t sum;
- unsigned char buff[4096];
-
- np = iso9660->el_torito.boot;
- lseek(iso9660->temp_fd,
- np->file->content.offset_of_temp + 64, SEEK_SET);
- size = archive_entry_size(np->file->entry) - 64;
- if (size <= 0) {
- archive_set_error(&a->archive, errno,
- "Boot file(%jd) is too small", (intmax_t)size + 64);
- return (ARCHIVE_FATAL);
- }
- sum = 0;
- while (size > 0) {
- size_t rsize;
- ssize_t i, rs;
-
- if (size > (int64_t)sizeof(buff))
- rsize = sizeof(buff);
- else
- rsize = (size_t)size;
-
- rs = read(iso9660->temp_fd, buff, rsize);
- if (rs <= 0) {
- archive_set_error(&a->archive, errno,
- "Can't read temporary file(%jd)",
- (intmax_t)rs);
- return (ARCHIVE_FATAL);
- }
- for (i = 0; i < rs; i += 4)
- sum += archive_le32dec(buff + i);
- size -= rs;
- }
- /* Set the location of Primary Volume Descriptor. */
- set_num_731(buff, SYSTEM_AREA_BLOCK);
- /* Set the location of the boot file. */
- set_num_731(buff+4, np->file->content.location);
- /* Set the size of the boot file. */
- size = fd_boot_image_size(iso9660->el_torito.media_type);
- if (size == 0)
- size = archive_entry_size(np->file->entry);
- set_num_731(buff+8, (uint32_t)size);
- /* Set the sum of the boot file. */
- set_num_731(buff+12, sum);
- /* Clear reserved bytes. */
- memset(buff+16, 0, 40);
-
- /* Overwrite the boot file. */
- lseek(iso9660->temp_fd,
- np->file->content.offset_of_temp + 8, SEEK_SET);
- return (write_to_temp(a, buff, 56));
-}
-
-#ifdef HAVE_ZLIB_H
-
-static int
-zisofs_init_zstream(struct archive_write *a)
-{
- struct iso9660 *iso9660 = a->format_data;
- int r;
-
- iso9660->zisofs.stream.next_in = NULL;
- iso9660->zisofs.stream.avail_in = 0;
- iso9660->zisofs.stream.total_in = 0;
- iso9660->zisofs.stream.total_out = 0;
- if (iso9660->zisofs.stream_valid)
- r = deflateReset(&(iso9660->zisofs.stream));
- else {
- r = deflateInit(&(iso9660->zisofs.stream),
- iso9660->zisofs.compression_level);
- iso9660->zisofs.stream_valid = 1;
- }
- switch (r) {
- case Z_OK:
- break;
- default:
- case Z_STREAM_ERROR:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal error initializing "
- "compression library: invalid setup parameter");
- return (ARCHIVE_FATAL);
- case Z_MEM_ERROR:
- archive_set_error(&a->archive, ENOMEM,
- "Internal error initializing "
- "compression library");
- return (ARCHIVE_FATAL);
- case Z_VERSION_ERROR:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal error initializing "
- "compression library: invalid library version");
- return (ARCHIVE_FATAL);
- }
- return (ARCHIVE_OK);
-}
-
-#endif /* HAVE_ZLIB_H */
-
-static int
-zisofs_init(struct archive_write *a, struct isofile *file)
-{
- struct iso9660 *iso9660 = a->format_data;
-#ifdef HAVE_ZLIB_H
- uint64_t tsize;
- size_t _ceil, bpsize;
- int r;
-#endif
-
- iso9660->zisofs.detect_magic = 0;
- iso9660->zisofs.making = 0;
-
- if (!iso9660->opt.rr || !iso9660->opt.zisofs)
- return (ARCHIVE_OK);
-
- if (archive_entry_size(file->entry) >= 24 &&
- archive_entry_size(file->entry) < MULTI_EXTENT_SIZE) {
- /* Acceptable file size for zisofs. */
- iso9660->zisofs.detect_magic = 1;
- iso9660->zisofs.magic_cnt = 0;
- }
- if (!iso9660->zisofs.detect_magic)
- return (ARCHIVE_OK);
-
-#ifdef HAVE_ZLIB_H
- /* The number of Logical Blocks which uncompressed data
- * will use in iso-image file is the same as the number of
- * Logical Blocks which zisofs(compressed) data will use
- * in ISO-image file. It won't reduce iso-image file size. */
- if (archive_entry_size(file->entry) <= LOGICAL_BLOCK_SIZE)
- return (ARCHIVE_OK);
-
- /* Initialize compression library */
- r = zisofs_init_zstream(a);
- if (r != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- /* Mark file->zisofs to create RRIP 'ZF' Use Entry. */
- file->zisofs.header_size = ZF_HEADER_SIZE >> 2;
- file->zisofs.log2_bs = ZF_LOG2_BS;
- file->zisofs.uncompressed_size =
- (uint32_t)archive_entry_size(file->entry);
-
- /* Calculate a size of Block Pointers of zisofs. */
- _ceil = (file->zisofs.uncompressed_size + ZF_BLOCK_SIZE -1)
- >> file->zisofs.log2_bs;
- iso9660->zisofs.block_pointers_cnt = (int)_ceil + 1;
- iso9660->zisofs.block_pointers_idx = 0;
-
- /* Ensure a buffer size used for Block Pointers */
- bpsize = iso9660->zisofs.block_pointers_cnt *
- sizeof(iso9660->zisofs.block_pointers[0]);
- if (iso9660->zisofs.block_pointers_allocated < bpsize) {
- free(iso9660->zisofs.block_pointers);
- iso9660->zisofs.block_pointers = malloc(bpsize);
- if (iso9660->zisofs.block_pointers == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate data");
- return (ARCHIVE_FATAL);
- }
- iso9660->zisofs.block_pointers_allocated = bpsize;
- }
-
- /*
- * Skip zisofs header and Block Pointers, which we will write
- * after all compressed data of a file written to the temporary
- * file.
- */
- tsize = ZF_HEADER_SIZE + bpsize;
- if (write_null(a, (size_t)tsize) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- /*
- * Initialize some variables to make zisofs.
- */
- archive_le32enc(&(iso9660->zisofs.block_pointers[0]),
- (uint32_t)tsize);
- iso9660->zisofs.remaining = file->zisofs.uncompressed_size;
- iso9660->zisofs.making = 1;
- iso9660->zisofs.allzero = 1;
- iso9660->zisofs.block_offset = tsize;
- iso9660->zisofs.total_size = tsize;
- iso9660->cur_file->cur_content->size = tsize;
-#endif
-
- return (ARCHIVE_OK);
-}
-
-static void
-zisofs_detect_magic(struct archive_write *a, const void *buff, size_t s)
-{
- struct iso9660 *iso9660 = a->format_data;
- struct isofile *file = iso9660->cur_file;
- const unsigned char *p, *endp;
- const unsigned char *magic_buff;
- uint32_t uncompressed_size;
- unsigned char header_size;
- unsigned char log2_bs;
- size_t _ceil, doff;
- uint32_t bst, bed;
- int magic_max;
- int64_t entry_size;
-
- entry_size = archive_entry_size(file->entry);
- if ((int64_t)sizeof(iso9660->zisofs.magic_buffer) > entry_size)
- magic_max = (int)entry_size;
- else
- magic_max = sizeof(iso9660->zisofs.magic_buffer);
-
- if (iso9660->zisofs.magic_cnt == 0 && s >= (size_t)magic_max)
- /* It's unnecessary we copy buffer. */
- magic_buff = buff;
- else {
- if (iso9660->zisofs.magic_cnt < magic_max) {
- size_t l;
-
- l = sizeof(iso9660->zisofs.magic_buffer)
- - iso9660->zisofs.magic_cnt;
- if (l > s)
- l = s;
- memcpy(iso9660->zisofs.magic_buffer
- + iso9660->zisofs.magic_cnt, buff, l);
- iso9660->zisofs.magic_cnt += (int)l;
- if (iso9660->zisofs.magic_cnt < magic_max)
- return;
- }
- magic_buff = iso9660->zisofs.magic_buffer;
- }
- iso9660->zisofs.detect_magic = 0;
- p = magic_buff;
-
- /* Check the magic code of zisofs. */
- if (memcmp(p, zisofs_magic, sizeof(zisofs_magic)) != 0)
- /* This is not zisofs file which made by mkzftree. */
- return;
- p += sizeof(zisofs_magic);
-
- /* Read a zisofs header. */
- uncompressed_size = archive_le32dec(p);
- header_size = p[4];
- log2_bs = p[5];
- if (uncompressed_size < 24 || header_size != 4 ||
- log2_bs > 30 || log2_bs < 7)
- return;/* Invalid or not supported header. */
-
- /* Calculate a size of Block Pointers of zisofs. */
- _ceil = (uncompressed_size +
- (ARCHIVE_LITERAL_LL(1) << log2_bs) -1) >> log2_bs;
- doff = (_ceil + 1) * 4 + 16;
- if (entry_size < (int64_t)doff)
- return;/* Invalid data. */
-
- /* Check every Block Pointer has valid value. */
- p = magic_buff + 16;
- endp = magic_buff + magic_max;
- while (_ceil && p + 8 <= endp) {
- bst = archive_le32dec(p);
- if (bst != doff)
- return;/* Invalid data. */
- p += 4;
- bed = archive_le32dec(p);
- if (bed < bst || bed > entry_size)
- return;/* Invalid data. */
- doff += bed - bst;
- _ceil--;
- }
-
- file->zisofs.uncompressed_size = uncompressed_size;
- file->zisofs.header_size = header_size;
- file->zisofs.log2_bs = log2_bs;
-
- /* Disable making a zisofs image. */
- iso9660->zisofs.making = 0;
-}
-
-#ifdef HAVE_ZLIB_H
-
-/*
- * Compress data and write it to a temporary file.
- */
-static int
-zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s)
-{
- struct iso9660 *iso9660 = a->format_data;
- struct isofile *file = iso9660->cur_file;
- const unsigned char *b;
- z_stream *zstrm;
- size_t avail, csize;
- int flush, r;
-
- zstrm = &(iso9660->zisofs.stream);
- zstrm->next_out = wb_buffptr(a);
- zstrm->avail_out = (uInt)wb_remaining(a);
- b = (const unsigned char *)buff;
- do {
- avail = ZF_BLOCK_SIZE - zstrm->total_in;
- if (s < avail) {
- avail = s;
- flush = Z_NO_FLUSH;
- } else
- flush = Z_FINISH;
- iso9660->zisofs.remaining -= avail;
- if (iso9660->zisofs.remaining <= 0)
- flush = Z_FINISH;
-
- zstrm->next_in = (Bytef *)(uintptr_t)(const void *)b;
- zstrm->avail_in = (uInt)avail;
-
- /*
- * Check if current data block are all zero.
- */
- if (iso9660->zisofs.allzero) {
- const unsigned char *nonzero = b;
- const unsigned char *nonzeroend = b + avail;
-
- while (nonzero < nonzeroend)
- if (*nonzero++) {
- iso9660->zisofs.allzero = 0;
- break;
- }
- }
- b += avail;
- s -= avail;
-
- /*
- * If current data block are all zero, we do not use
- * compressed data.
- */
- if (flush == Z_FINISH && iso9660->zisofs.allzero &&
- avail + zstrm->total_in == ZF_BLOCK_SIZE) {
- if (iso9660->zisofs.block_offset !=
- file->cur_content->size) {
- int64_t diff;
-
- r = wb_set_offset(a,
- file->cur_content->offset_of_temp +
- iso9660->zisofs.block_offset);
- if (r != ARCHIVE_OK)
- return (r);
- diff = file->cur_content->size -
- iso9660->zisofs.block_offset;
- file->cur_content->size -= diff;
- iso9660->zisofs.total_size -= diff;
- }
- zstrm->avail_in = 0;
- }
-
- /*
- * Compress file data.
- */
- while (zstrm->avail_in > 0) {
- csize = zstrm->total_out;
- r = deflate(zstrm, flush);
- switch (r) {
- case Z_OK:
- case Z_STREAM_END:
- csize = zstrm->total_out - csize;
- if (wb_consume(a, csize) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- iso9660->zisofs.total_size += csize;
- iso9660->cur_file->cur_content->size += csize;
- zstrm->next_out = wb_buffptr(a);
- zstrm->avail_out = (uInt)wb_remaining(a);
- break;
- default:
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Compression failed:"
- " deflate() call returned status %d",
- r);
- return (ARCHIVE_FATAL);
- }
- }
-
- if (flush == Z_FINISH) {
- /*
- * Save the information of one zisofs block.
- */
- iso9660->zisofs.block_pointers_idx ++;
- archive_le32enc(&(iso9660->zisofs.block_pointers[
- iso9660->zisofs.block_pointers_idx]),
- (uint32_t)iso9660->zisofs.total_size);
- r = zisofs_init_zstream(a);
- if (r != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- iso9660->zisofs.allzero = 1;
- iso9660->zisofs.block_offset = file->cur_content->size;
- }
- } while (s);
-
- return (ARCHIVE_OK);
-}
-
-static int
-zisofs_finish_entry(struct archive_write *a)
-{
- struct iso9660 *iso9660 = a->format_data;
- struct isofile *file = iso9660->cur_file;
- unsigned char buff[16];
- size_t s;
- int64_t tail;
-
- /* Direct temp file stream to zisofs temp file stream. */
- archive_entry_set_size(file->entry, iso9660->zisofs.total_size);
-
- /*
- * Save a file pointer which points the end of current zisofs data.
- */
- tail = wb_offset(a);
-
- /*
- * Make a header.
- *
- * +-----------------+----------------+-----------------+
- * | Header 16 bytes | Block Pointers | Compressed data |
- * +-----------------+----------------+-----------------+
- * 0 16 +X
- * Block Pointers :
- * 4 * (((Uncompressed file size + block_size -1) / block_size) + 1)
- *
- * Write zisofs header.
- * Magic number
- * +----+----+----+----+----+----+----+----+
- * | 37 | E4 | 53 | 96 | C9 | DB | D6 | 07 |
- * +----+----+----+----+----+----+----+----+
- * 0 1 2 3 4 5 6 7 8
- *
- * +------------------------+------------------+
- * | Uncompressed file size | header_size >> 2 |
- * +------------------------+------------------+
- * 8 12 13
- *
- * +-----------------+----------------+
- * | log2 block_size | Reserved(0000) |
- * +-----------------+----------------+
- * 13 14 16
- */
- memcpy(buff, zisofs_magic, 8);
- set_num_731(buff+8, file->zisofs.uncompressed_size);
- buff[12] = file->zisofs.header_size;
- buff[13] = file->zisofs.log2_bs;
- buff[14] = buff[15] = 0;/* Reserved */
-
- /* Move to the right position to write the header. */
- wb_set_offset(a, file->content.offset_of_temp);
-
- /* Write the header. */
- if (wb_write_to_temp(a, buff, 16) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- /*
- * Write zisofs Block Pointers.
- */
- s = iso9660->zisofs.block_pointers_cnt *
- sizeof(iso9660->zisofs.block_pointers[0]);
- if (wb_write_to_temp(a, iso9660->zisofs.block_pointers, s)
- != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- /* Set a file pointer back to the end of the temporary file. */
- wb_set_offset(a, tail);
-
- return (ARCHIVE_OK);
-}
-
-static int
-zisofs_free(struct archive_write *a)
-{
- struct iso9660 *iso9660 = a->format_data;
- int ret = ARCHIVE_OK;
-
- free(iso9660->zisofs.block_pointers);
- if (iso9660->zisofs.stream_valid &&
- deflateEnd(&(iso9660->zisofs.stream)) != Z_OK) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Failed to clean up compressor");
- ret = ARCHIVE_FATAL;
- }
- iso9660->zisofs.block_pointers = NULL;
- iso9660->zisofs.stream_valid = 0;
- return (ret);
-}
-
-struct zisofs_extract {
- int pz_log2_bs; /* Log2 of block size */
- uint64_t pz_uncompressed_size;
- size_t uncompressed_buffer_size;
-
- int initialized:1;
- int header_passed:1;
-
- uint32_t pz_offset;
- unsigned char *block_pointers;
- size_t block_pointers_size;
- size_t block_pointers_avail;
- size_t block_off;
- uint32_t block_avail;
-
- z_stream stream;
- int stream_valid;
-};
-
-static ssize_t
-zisofs_extract_init(struct archive_write *a, struct zisofs_extract *zisofs,
- const unsigned char *p, size_t bytes)
-{
- size_t avail = bytes;
- size_t _ceil, xsize;
-
- /* Allocate block pointers buffer. */
- _ceil = (size_t)((zisofs->pz_uncompressed_size +
- (((int64_t)1) << zisofs->pz_log2_bs) - 1)
- >> zisofs->pz_log2_bs);
- xsize = (_ceil + 1) * 4;
- if (zisofs->block_pointers == NULL) {
- size_t alloc = ((xsize >> 10) + 1) << 10;
- zisofs->block_pointers = malloc(alloc);
- if (zisofs->block_pointers == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "No memory for zisofs decompression");
- return (ARCHIVE_FATAL);
- }
- }
- zisofs->block_pointers_size = xsize;
-
- /* Allocate uncompressed data buffer. */
- zisofs->uncompressed_buffer_size = (size_t)1UL << zisofs->pz_log2_bs;
-
- /*
- * Read the file header, and check the magic code of zisofs.
- */
- if (!zisofs->header_passed) {
- int err = 0;
- if (avail < 16) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Illegal zisofs file body");
- return (ARCHIVE_FATAL);
- }
-
- if (memcmp(p, zisofs_magic, sizeof(zisofs_magic)) != 0)
- err = 1;
- else if (archive_le32dec(p + 8) != zisofs->pz_uncompressed_size)
- err = 1;
- else if (p[12] != 4 || p[13] != zisofs->pz_log2_bs)
- err = 1;
- if (err) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Illegal zisofs file body");
- return (ARCHIVE_FATAL);
- }
- avail -= 16;
- p += 16;
- zisofs->header_passed = 1;
- }
-
- /*
- * Read block pointers.
- */
- if (zisofs->header_passed &&
- zisofs->block_pointers_avail < zisofs->block_pointers_size) {
- xsize = zisofs->block_pointers_size
- - zisofs->block_pointers_avail;
- if (avail < xsize)
- xsize = avail;
- memcpy(zisofs->block_pointers
- + zisofs->block_pointers_avail, p, xsize);
- zisofs->block_pointers_avail += xsize;
- avail -= xsize;
- if (zisofs->block_pointers_avail
- == zisofs->block_pointers_size) {
- /* We've got all block pointers and initialize
- * related variables. */
- zisofs->block_off = 0;
- zisofs->block_avail = 0;
- /* Complete a initialization */
- zisofs->initialized = 1;
- }
- }
- return ((ssize_t)avail);
-}
-
-static ssize_t
-zisofs_extract(struct archive_write *a, struct zisofs_extract *zisofs,
- const unsigned char *p, size_t bytes)
-{
- size_t avail;
- int r;
-
- if (!zisofs->initialized) {
- ssize_t rs = zisofs_extract_init(a, zisofs, p, bytes);
- if (rs < 0)
- return (rs);
- if (!zisofs->initialized) {
- /* We need more data. */
- zisofs->pz_offset += (uint32_t)bytes;
- return (bytes);
- }
- avail = rs;
- p += bytes - avail;
- } else
- avail = bytes;
-
- /*
- * Get block offsets from block pointers.
- */
- if (zisofs->block_avail == 0) {
- uint32_t bst, bed;
-
- if (zisofs->block_off + 4 >= zisofs->block_pointers_size) {
- /* There isn't a pair of offsets. */
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Illegal zisofs block pointers");
- return (ARCHIVE_FATAL);
- }
- bst = archive_le32dec(
- zisofs->block_pointers + zisofs->block_off);
- if (bst != zisofs->pz_offset + (bytes - avail)) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Illegal zisofs block pointers(cannot seek)");
- return (ARCHIVE_FATAL);
- }
- bed = archive_le32dec(
- zisofs->block_pointers + zisofs->block_off + 4);
- if (bed < bst) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Illegal zisofs block pointers");
- return (ARCHIVE_FATAL);
- }
- zisofs->block_avail = bed - bst;
- zisofs->block_off += 4;
-
- /* Initialize compression library for new block. */
- if (zisofs->stream_valid)
- r = inflateReset(&zisofs->stream);
- else
- r = inflateInit(&zisofs->stream);
- if (r != Z_OK) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Can't initialize zisofs decompression.");
- return (ARCHIVE_FATAL);
- }
- zisofs->stream_valid = 1;
- zisofs->stream.total_in = 0;
- zisofs->stream.total_out = 0;
- }
-
- /*
- * Make uncompressed data.
- */
- if (zisofs->block_avail == 0) {
- /*
- * It's basically 32K bytes NUL data.
- */
- unsigned char *wb;
- size_t size, wsize;
-
- size = zisofs->uncompressed_buffer_size;
- while (size) {
- wb = wb_buffptr(a);
- if (size > wb_remaining(a))
- wsize = wb_remaining(a);
- else
- wsize = size;
- memset(wb, 0, wsize);
- r = wb_consume(a, wsize);
- if (r < 0)
- return (r);
- size -= wsize;
- }
- } else {
- zisofs->stream.next_in = (Bytef *)(uintptr_t)(const void *)p;
- if (avail > zisofs->block_avail)
- zisofs->stream.avail_in = zisofs->block_avail;
- else
- zisofs->stream.avail_in = (uInt)avail;
- zisofs->stream.next_out = wb_buffptr(a);
- zisofs->stream.avail_out = (uInt)wb_remaining(a);
-
- r = inflate(&zisofs->stream, 0);
- switch (r) {
- case Z_OK: /* Decompressor made some progress.*/
- case Z_STREAM_END: /* Found end of stream. */
- break;
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "zisofs decompression failed (%d)", r);
- return (ARCHIVE_FATAL);
- }
- avail -= zisofs->stream.next_in - p;
- zisofs->block_avail -= (uint32_t)(zisofs->stream.next_in - p);
- r = wb_consume(a, wb_remaining(a) - zisofs->stream.avail_out);
- if (r < 0)
- return (r);
- }
- zisofs->pz_offset += (uint32_t)bytes;
- return (bytes - avail);
-}
-
-static int
-zisofs_rewind_boot_file(struct archive_write *a)
-{
- struct iso9660 *iso9660 = a->format_data;
- struct isofile *file;
- unsigned char *rbuff;
- ssize_t r;
- size_t remaining, rbuff_size;
- struct zisofs_extract zext;
- int64_t read_offset, write_offset, new_offset;
- int fd, ret = ARCHIVE_OK;
-
- file = iso9660->el_torito.boot->file;
- /*
- * There is nothing to do if this boot file does not have
- * zisofs header.
- */
- if (file->zisofs.header_size == 0)
- return (ARCHIVE_OK);
-
- /*
- * Uncompress the zisofs'ed file contents.
- */
- memset(&zext, 0, sizeof(zext));
- zext.pz_uncompressed_size = file->zisofs.uncompressed_size;
- zext.pz_log2_bs = file->zisofs.log2_bs;
-
- fd = iso9660->temp_fd;
- new_offset = wb_offset(a);
- read_offset = file->content.offset_of_temp;
- remaining = (size_t)file->content.size;
- if (remaining > 1024 * 32)
- rbuff_size = 1024 * 32;
- else
- rbuff_size = remaining;
-
- rbuff = malloc(rbuff_size);
- if (rbuff == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- while (remaining) {
- size_t rsize;
- ssize_t rs;
-
- /* Get the current file pointer. */
- write_offset = lseek(fd, 0, SEEK_CUR);
-
- /* Change the file pointer to read. */
- lseek(fd, read_offset, SEEK_SET);
-
- rsize = rbuff_size;
- if (rsize > remaining)
- rsize = remaining;
- rs = read(iso9660->temp_fd, rbuff, rsize);
- if (rs <= 0) {
- archive_set_error(&a->archive, errno,
- "Can't read temporary file(%jd)", (intmax_t)rs);
- ret = ARCHIVE_FATAL;
- break;
- }
- remaining -= rs;
- read_offset += rs;
-
- /* Put the file pointer back to write. */
- lseek(fd, write_offset, SEEK_SET);
-
- r = zisofs_extract(a, &zext, rbuff, rs);
- if (r < 0) {
- ret = (int)r;
- break;
- }
- }
-
- if (ret == ARCHIVE_OK) {
- /*
- * Change the boot file content from zisofs'ed data
- * to plain data.
- */
- file->content.offset_of_temp = new_offset;
- file->content.size = file->zisofs.uncompressed_size;
- archive_entry_set_size(file->entry, file->content.size);
- /* Set to be no zisofs. */
- file->zisofs.header_size = 0;
- file->zisofs.log2_bs = 0;
- file->zisofs.uncompressed_size = 0;
- r = wb_write_padding_to_temp(a, file->content.size);
- if (r < 0)
- ret = ARCHIVE_FATAL;
- }
-
- /*
- * Free the resource we used in this function only.
- */
- free(rbuff);
- free(zext.block_pointers);
- if (zext.stream_valid && inflateEnd(&(zext.stream)) != Z_OK) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Failed to clean up compressor");
- ret = ARCHIVE_FATAL;
- }
-
- return (ret);
-}
-
-#else
-
-static int
-zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s)
-{
- (void)buff; /* UNUSED */
- (void)s; /* UNUSED */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Programing error");
- return (ARCHIVE_FATAL);
-}
-
-static int
-zisofs_rewind_boot_file(struct archive_write *a)
-{
- struct iso9660 *iso9660 = a->format_data;
-
- if (iso9660->el_torito.boot->file->zisofs.header_size != 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "We cannot extract the zisofs imaged boot file;"
- " this may not boot in being zisofs imaged");
- return (ARCHIVE_FAILED);
- }
- return (ARCHIVE_OK);
-}
-
-static int
-zisofs_finish_entry(struct archive_write *a)
-{
- (void)a; /* UNUSED */
- return (ARCHIVE_OK);
-}
-
-static int
-zisofs_free(struct archive_write *a)
-{
- (void)a; /* UNUSED */
- return (ARCHIVE_OK);
-}
-
-#endif /* HAVE_ZLIB_H */
-
diff --git a/3rdparty/libarchive/libarchive/archive_write_set_format_mtree.c b/3rdparty/libarchive/libarchive/archive_write_set_format_mtree.c
deleted file mode 100644
index 9c0613c9..00000000
--- a/3rdparty/libarchive/libarchive/archive_write_set_format_mtree.c
+++ /dev/null
@@ -1,2203 +0,0 @@
-/*-
- * Copyright (c) 2008 Joerg Sonnenberger
- * Copyright (c) 2009-2012 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"
-__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_mtree.c 201171 2009-12-29 06:39:07Z kientzle $");
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "archive.h"
-#include "archive_crypto_private.h"
-#include "archive_entry.h"
-#include "archive_private.h"
-#include "archive_rb.h"
-#include "archive_string.h"
-#include "archive_write_private.h"
-
-#define INDENTNAMELEN 15
-#define MAXLINELEN 80
-#define SET_KEYS \
- (F_FLAGS | F_GID | F_GNAME | F_MODE | F_TYPE | F_UID | F_UNAME)
-
-struct attr_counter {
- struct attr_counter *prev;
- struct attr_counter *next;
- struct mtree_entry *m_entry;
- int count;
-};
-
-struct att_counter_set {
- struct attr_counter *uid_list;
- struct attr_counter *gid_list;
- struct attr_counter *mode_list;
- struct attr_counter *flags_list;
-};
-
-struct mtree_chain {
- struct mtree_entry *first;
- struct mtree_entry **last;
-};
-
-/*
- * The Data only for a directory file.
- */
-struct dir_info {
- struct archive_rb_tree rbtree;
- struct mtree_chain children;
- struct mtree_entry *chnext;
- int virtual;
-};
-
-/*
- * The Data only for a regular file.
- */
-struct reg_info {
- int compute_sum;
- uint32_t crc;
-#ifdef ARCHIVE_HAS_MD5
- unsigned char buf_md5[16];
-#endif
-#ifdef ARCHIVE_HAS_RMD160
- unsigned char buf_rmd160[20];
-#endif
-#ifdef ARCHIVE_HAS_SHA1
- unsigned char buf_sha1[20];
-#endif
-#ifdef ARCHIVE_HAS_SHA256
- unsigned char buf_sha256[32];
-#endif
-#ifdef ARCHIVE_HAS_SHA384
- unsigned char buf_sha384[48];
-#endif
-#ifdef ARCHIVE_HAS_SHA512
- unsigned char buf_sha512[64];
-#endif
-};
-
-struct mtree_entry {
- struct archive_rb_node rbnode;
- struct mtree_entry *next;
- struct mtree_entry *parent;
- struct dir_info *dir_info;
- struct reg_info *reg_info;
-
- struct archive_string parentdir;
- struct archive_string basename;
- struct archive_string pathname;
- struct archive_string symlink;
- struct archive_string uname;
- struct archive_string gname;
- struct archive_string fflags_text;
- unsigned int nlink;
- mode_t filetype;
- mode_t mode;
- int64_t size;
- int64_t uid;
- int64_t gid;
- time_t mtime;
- long mtime_nsec;
- unsigned long fflags_set;
- unsigned long fflags_clear;
- dev_t rdevmajor;
- dev_t rdevminor;
-};
-
-struct mtree_writer {
- struct mtree_entry *mtree_entry;
- struct mtree_entry *root;
- struct mtree_entry *cur_dirent;
- struct archive_string cur_dirstr;
- struct mtree_chain file_list;
-
- struct archive_string ebuf;
- struct archive_string buf;
- int first;
- uint64_t entry_bytes_remaining;
-
- /*
- * Set global value.
- */
- struct {
- int processing;
- mode_t type;
- int keys;
- int64_t uid;
- int64_t gid;
- mode_t mode;
- unsigned long fflags_set;
- unsigned long fflags_clear;
- } set;
- struct att_counter_set acs;
- int classic;
- int depth;
-
- /* check sum */
- int compute_sum;
- uint32_t crc;
- uint64_t crc_len;
-#ifdef ARCHIVE_HAS_MD5
- archive_md5_ctx md5ctx;
-#endif
-#ifdef ARCHIVE_HAS_RMD160
- archive_rmd160_ctx rmd160ctx;
-#endif
-#ifdef ARCHIVE_HAS_SHA1
- archive_sha1_ctx sha1ctx;
-#endif
-#ifdef ARCHIVE_HAS_SHA256
- archive_sha256_ctx sha256ctx;
-#endif
-#ifdef ARCHIVE_HAS_SHA384
- archive_sha384_ctx sha384ctx;
-#endif
-#ifdef ARCHIVE_HAS_SHA512
- archive_sha512_ctx sha512ctx;
-#endif
- /* Keyword options */
- int keys;
-#define F_CKSUM 0x00000001 /* check sum */
-#define F_DEV 0x00000002 /* device type */
-#define F_DONE 0x00000004 /* directory done */
-#define F_FLAGS 0x00000008 /* file flags */
-#define F_GID 0x00000010 /* gid */
-#define F_GNAME 0x00000020 /* group name */
-#define F_IGN 0x00000040 /* ignore */
-#define F_MAGIC 0x00000080 /* name has magic chars */
-#define F_MD5 0x00000100 /* MD5 digest */
-#define F_MODE 0x00000200 /* mode */
-#define F_NLINK 0x00000400 /* number of links */
-#define F_NOCHANGE 0x00000800 /* If owner/mode "wrong", do
- * not change */
-#define F_OPT 0x00001000 /* existence optional */
-#define F_RMD160 0x00002000 /* RIPEMD160 digest */
-#define F_SHA1 0x00004000 /* SHA-1 digest */
-#define F_SIZE 0x00008000 /* size */
-#define F_SLINK 0x00010000 /* symbolic link */
-#define F_TAGS 0x00020000 /* tags */
-#define F_TIME 0x00040000 /* modification time */
-#define F_TYPE 0x00080000 /* file type */
-#define F_UID 0x00100000 /* uid */
-#define F_UNAME 0x00200000 /* user name */
-#define F_VISIT 0x00400000 /* file visited */
-#define F_SHA256 0x00800000 /* SHA-256 digest */
-#define F_SHA384 0x01000000 /* SHA-384 digest */
-#define F_SHA512 0x02000000 /* SHA-512 digest */
-
- /* Options */
- int dironly; /* If it is set, ignore all files except
- * directory files, like mtree(8) -d option. */
- int indent; /* If it is set, indent output data. */
- int output_global_set; /* If it is set, use /set keyword to set
- * global values. When generating mtree
- * classic format, it is set by default. */
-};
-
-#define DEFAULT_KEYS (F_DEV | F_FLAGS | F_GID | F_GNAME | F_SLINK | F_MODE\
- | F_NLINK | F_SIZE | F_TIME | F_TYPE | F_UID\
- | F_UNAME)
-#define attr_counter_set_reset attr_counter_set_free
-
-static void attr_counter_free(struct attr_counter **);
-static int attr_counter_inc(struct attr_counter **, struct attr_counter *,
- struct attr_counter *, struct mtree_entry *);
-static struct attr_counter * attr_counter_new(struct mtree_entry *,
- struct attr_counter *);
-static int attr_counter_set_collect(struct mtree_writer *,
- struct mtree_entry *);
-static void attr_counter_set_free(struct mtree_writer *);
-static int get_global_set_keys(struct mtree_writer *, struct mtree_entry *);
-static int mtree_entry_add_child_tail(struct mtree_entry *,
- struct mtree_entry *);
-static int mtree_entry_create_virtual_dir(struct archive_write *, const char *,
- struct mtree_entry **);
-static int mtree_entry_cmp_node(const struct archive_rb_node *,
- const struct archive_rb_node *);
-static int mtree_entry_cmp_key(const struct archive_rb_node *, const void *);
-static int mtree_entry_exchange_same_entry(struct archive_write *,
- struct mtree_entry *, struct mtree_entry *);
-static void mtree_entry_free(struct mtree_entry *);
-static int mtree_entry_new(struct archive_write *, struct archive_entry *,
- struct mtree_entry **);
-static void mtree_entry_register_free(struct mtree_writer *);
-static void mtree_entry_register_init(struct mtree_writer *);
-static int mtree_entry_setup_filenames(struct archive_write *,
- struct mtree_entry *, struct archive_entry *);
-static int mtree_entry_tree_add(struct archive_write *, struct mtree_entry **);
-static void sum_init(struct mtree_writer *);
-static void sum_update(struct mtree_writer *, const void *, size_t);
-static void sum_final(struct mtree_writer *, struct reg_info *);
-static void sum_write(struct archive_string *, struct reg_info *);
-static int write_mtree_entry(struct archive_write *, struct mtree_entry *);
-static int write_dot_dot_entry(struct archive_write *, struct mtree_entry *);
-
-#define COMPUTE_CRC(var, ch) (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)]
-static const uint32_t crctab[] = {
- 0x0,
- 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
- 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
- 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
- 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
- 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
- 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
- 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
- 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
- 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
- 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
- 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
- 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
- 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
- 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
- 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
- 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
- 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
- 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
- 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
- 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
- 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
- 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
- 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
- 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
- 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
- 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
- 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
- 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
- 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
- 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
- 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
- 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
- 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
- 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
- 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
- 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
- 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
- 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
- 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
- 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
- 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
- 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
- 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
- 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
- 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
- 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
- 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
- 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
- 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
- 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
- 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
-};
-
-static const unsigned char safe_char[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
- /* !"$%&'()*+,-./ EXCLUSION:0x20( ) 0x23(#) */
- 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
- /* 0123456789:;<>? EXCLUSION:0x3d(=) */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, /* 30 - 3F */
- /* @ABCDEFGHIJKLMNO */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
- /* PQRSTUVWXYZ[]^_ EXCLUSION:0x5c(\) */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, /* 50 - 5F */
- /* `abcdefghijklmno */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
- /* pqrstuvwxyz{|}~ */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
-};
-
-static void
-mtree_quote(struct archive_string *s, const char *str)
-{
- const char *start;
- char buf[4];
- unsigned char c;
-
- for (start = str; *str != '\0'; ++str) {
- if (safe_char[*(const unsigned char *)str])
- continue;
- if (start != str)
- archive_strncat(s, start, str - start);
- c = (unsigned char)*str;
- buf[0] = '\\';
- buf[1] = (c / 64) + '0';
- buf[2] = (c / 8 % 8) + '0';
- buf[3] = (c % 8) + '0';
- archive_strncat(s, buf, 4);
- start = str + 1;
- }
-
- if (start != str)
- archive_strncat(s, start, str - start);
-}
-
-/*
- * Indent a line as mtree utility to be readable for people.
- */
-static void
-mtree_indent(struct mtree_writer *mtree)
-{
- int i, fn, nd, pd;
- const char *r, *s, *x;
-
- if (mtree->classic) {
- if (mtree->indent) {
- nd = 0;
- pd = mtree->depth * 4;
- } else {
- nd = mtree->depth?4:0;
- pd = 0;
- }
- } else
- nd = pd = 0;
- fn = 1;
- s = r = mtree->ebuf.s;
- x = NULL;
- while (*r == ' ')
- r++;
- while ((r = strchr(r, ' ')) != NULL) {
- if (fn) {
- fn = 0;
- for (i = 0; i < nd + pd; i++)
- archive_strappend_char(&mtree->buf, ' ');
- archive_strncat(&mtree->buf, s, r - s);
- if (nd + (r -s) > INDENTNAMELEN) {
- archive_strncat(&mtree->buf, " \\\n", 3);
- for (i = 0; i < (INDENTNAMELEN + 1 + pd); i++)
- archive_strappend_char(&mtree->buf, ' ');
- } else {
- for (i = (int)(r -s + nd);
- i < (INDENTNAMELEN + 1); i++)
- archive_strappend_char(&mtree->buf, ' ');
- }
- s = ++r;
- x = NULL;
- continue;
- }
- if (pd + (r - s) <= MAXLINELEN - 3 - INDENTNAMELEN)
- x = r++;
- else {
- if (x == NULL)
- x = r;
- archive_strncat(&mtree->buf, s, x - s);
- archive_strncat(&mtree->buf, " \\\n", 3);
- for (i = 0; i < (INDENTNAMELEN + 1 + pd); i++)
- archive_strappend_char(&mtree->buf, ' ');
- s = r = ++x;
- x = NULL;
- }
- }
- if (fn) {
- for (i = 0; i < nd + pd; i++)
- archive_strappend_char(&mtree->buf, ' ');
- archive_strcat(&mtree->buf, s);
- s += strlen(s);
- }
- if (x != NULL && pd + strlen(s) > MAXLINELEN - 3 - INDENTNAMELEN) {
- /* Last keyword is longer. */
- archive_strncat(&mtree->buf, s, x - s);
- archive_strncat(&mtree->buf, " \\\n", 3);
- for (i = 0; i < (INDENTNAMELEN + 1 + pd); i++)
- archive_strappend_char(&mtree->buf, ' ');
- s = ++x;
- }
- archive_strcat(&mtree->buf, s);
- archive_string_empty(&mtree->ebuf);
-}
-
-/*
- * Write /set keyword.
- * Set most used value of uid,gid,mode and fflags, which are
- * collected by attr_counter_set_collect() function.
- */
-static void
-write_global(struct mtree_writer *mtree)
-{
- struct archive_string setstr;
- struct archive_string unsetstr;
- struct att_counter_set *acs;
- int keys, oldkeys, effkeys;
-
- archive_string_init(&setstr);
- archive_string_init(&unsetstr);
- keys = mtree->keys & SET_KEYS;
- oldkeys = mtree->set.keys;
- effkeys = keys;
- acs = &mtree->acs;
- if (mtree->set.processing) {
- /*
- * Check if the global data needs updating.
- */
- effkeys &= ~F_TYPE;
- if (acs->uid_list == NULL)
- effkeys &= ~(F_UNAME | F_UID);
- else if (oldkeys & (F_UNAME | F_UID)) {
- if (acs->uid_list->count < 2 ||
- mtree->set.uid == acs->uid_list->m_entry->uid)
- effkeys &= ~(F_UNAME | F_UID);
- }
- if (acs->gid_list == NULL)
- effkeys &= ~(F_GNAME | F_GID);
- else if (oldkeys & (F_GNAME | F_GID)) {
- if (acs->gid_list->count < 2 ||
- mtree->set.gid == acs->gid_list->m_entry->gid)
- effkeys &= ~(F_GNAME | F_GID);
- }
- if (acs->mode_list == NULL)
- effkeys &= ~F_MODE;
- else if (oldkeys & F_MODE) {
- if (acs->mode_list->count < 2 ||
- mtree->set.mode == acs->mode_list->m_entry->mode)
- effkeys &= ~F_MODE;
- }
- if (acs->flags_list == NULL)
- effkeys &= ~F_FLAGS;
- else if ((oldkeys & F_FLAGS) != 0) {
- if (acs->flags_list->count < 2 ||
- (acs->flags_list->m_entry->fflags_set ==
- mtree->set.fflags_set &&
- acs->flags_list->m_entry->fflags_clear ==
- mtree->set.fflags_clear))
- effkeys &= ~F_FLAGS;
- }
- } else {
- if (acs->uid_list == NULL)
- keys &= ~(F_UNAME | F_UID);
- if (acs->gid_list == NULL)
- keys &= ~(F_GNAME | F_GID);
- if (acs->mode_list == NULL)
- keys &= ~F_MODE;
- if (acs->flags_list == NULL)
- keys &= ~F_FLAGS;
- }
- if ((keys & effkeys & F_TYPE) != 0) {
- if (mtree->dironly) {
- archive_strcat(&setstr, " type=dir");
- mtree->set.type = AE_IFDIR;
- } else {
- archive_strcat(&setstr, " type=file");
- mtree->set.type = AE_IFREG;
- }
- }
- if ((keys & effkeys & F_UNAME) != 0) {
- if (archive_strlen(&(acs->uid_list->m_entry->uname)) > 0) {
- archive_strcat(&setstr, " uname=");
- mtree_quote(&setstr, acs->uid_list->m_entry->uname.s);
- } else {
- keys &= ~F_UNAME;
- if ((oldkeys & F_UNAME) != 0)
- archive_strcat(&unsetstr, " uname");
- }
- }
- if ((keys & effkeys & F_UID) != 0) {
- mtree->set.uid = acs->uid_list->m_entry->uid;
- archive_string_sprintf(&setstr, " uid=%jd",
- (intmax_t)mtree->set.uid);
- }
- if ((keys & effkeys & F_GNAME) != 0) {
- if (archive_strlen(&(acs->gid_list->m_entry->gname)) > 0) {
- archive_strcat(&setstr, " gname=");
- mtree_quote(&setstr, acs->gid_list->m_entry->gname.s);
- } else {
- keys &= ~F_GNAME;
- if ((oldkeys & F_GNAME) != 0)
- archive_strcat(&unsetstr, " gname");
- }
- }
- if ((keys & effkeys & F_GID) != 0) {
- mtree->set.gid = acs->gid_list->m_entry->gid;
- archive_string_sprintf(&setstr, " gid=%jd",
- (intmax_t)mtree->set.gid);
- }
- if ((keys & effkeys & F_MODE) != 0) {
- mtree->set.mode = acs->mode_list->m_entry->mode;
- archive_string_sprintf(&setstr, " mode=%o",
- (unsigned int)mtree->set.mode);
- }
- if ((keys & effkeys & F_FLAGS) != 0) {
- if (archive_strlen(
- &(acs->flags_list->m_entry->fflags_text)) > 0) {
- archive_strcat(&setstr, " flags=");
- mtree_quote(&setstr,
- acs->flags_list->m_entry->fflags_text.s);
- mtree->set.fflags_set =
- acs->flags_list->m_entry->fflags_set;
- mtree->set.fflags_clear =
- acs->flags_list->m_entry->fflags_clear;
- } else {
- keys &= ~F_FLAGS;
- if ((oldkeys & F_FLAGS) != 0)
- archive_strcat(&unsetstr, " flags");
- }
- }
- if (unsetstr.length > 0)
- archive_string_sprintf(&mtree->buf, "/unset%s\n", unsetstr.s);
- archive_string_free(&unsetstr);
- if (setstr.length > 0)
- archive_string_sprintf(&mtree->buf, "/set%s\n", setstr.s);
- archive_string_free(&setstr);
- mtree->set.keys = keys;
- mtree->set.processing = 1;
-}
-
-static struct attr_counter *
-attr_counter_new(struct mtree_entry *me, struct attr_counter *prev)
-{
- struct attr_counter *ac;
-
- ac = malloc(sizeof(*ac));
- if (ac != NULL) {
- ac->prev = prev;
- ac->next = NULL;
- ac->count = 1;
- ac->m_entry = me;
- }
- return (ac);
-}
-
-static void
-attr_counter_free(struct attr_counter **top)
-{
- struct attr_counter *ac, *tac;
-
- if (*top == NULL)
- return;
- ac = *top;
- while (ac != NULL) {
- tac = ac->next;
- free(ac);
- ac = tac;
- }
- *top = NULL;
-}
-
-static int
-attr_counter_inc(struct attr_counter **top, struct attr_counter *ac,
- struct attr_counter *last, struct mtree_entry *me)
-{
- struct attr_counter *pac;
-
- if (ac != NULL) {
- ac->count++;
- if (*top == ac || ac->prev->count >= ac->count)
- return (0);
- for (pac = ac->prev; pac; pac = pac->prev) {
- if (pac->count >= ac->count)
- break;
- }
- ac->prev->next = ac->next;
- if (ac->next != NULL)
- ac->next->prev = ac->prev;
- if (pac != NULL) {
- ac->prev = pac;
- ac->next = pac->next;
- pac->next = ac;
- if (ac->next != NULL)
- ac->next->prev = ac;
- } else {
- ac->prev = NULL;
- ac->next = *top;
- *top = ac;
- ac->next->prev = ac;
- }
- } else {
- ac = attr_counter_new(me, last);
- if (ac == NULL)
- return (-1);
- last->next = ac;
- }
- return (0);
-}
-
-/*
- * Tabulate uid,gid,mode and fflags of a entry in order to be used for /set.
- */
-static int
-attr_counter_set_collect(struct mtree_writer *mtree, struct mtree_entry *me)
-{
- struct attr_counter *ac, *last;
- struct att_counter_set *acs = &mtree->acs;
- int keys = mtree->keys;
-
- if (keys & (F_UNAME | F_UID)) {
- if (acs->uid_list == NULL) {
- acs->uid_list = attr_counter_new(me, NULL);
- if (acs->uid_list == NULL)
- return (-1);
- } else {
- last = NULL;
- for (ac = acs->uid_list; ac; ac = ac->next) {
- if (ac->m_entry->uid == me->uid)
- break;
- last = ac;
- }
- if (attr_counter_inc(&acs->uid_list, ac, last, me) < 0)
- return (-1);
- }
- }
- if (keys & (F_GNAME | F_GID)) {
- if (acs->gid_list == NULL) {
- acs->gid_list = attr_counter_new(me, NULL);
- if (acs->gid_list == NULL)
- return (-1);
- } else {
- last = NULL;
- for (ac = acs->gid_list; ac; ac = ac->next) {
- if (ac->m_entry->gid == me->gid)
- break;
- last = ac;
- }
- if (attr_counter_inc(&acs->gid_list, ac, last, me) < 0)
- return (-1);
- }
- }
- if (keys & F_MODE) {
- if (acs->mode_list == NULL) {
- acs->mode_list = attr_counter_new(me, NULL);
- if (acs->mode_list == NULL)
- return (-1);
- } else {
- last = NULL;
- for (ac = acs->mode_list; ac; ac = ac->next) {
- if (ac->m_entry->mode == me->mode)
- break;
- last = ac;
- }
- if (attr_counter_inc(&acs->mode_list, ac, last, me) < 0)
- return (-1);
- }
- }
- if (keys & F_FLAGS) {
- if (acs->flags_list == NULL) {
- acs->flags_list = attr_counter_new(me, NULL);
- if (acs->flags_list == NULL)
- return (-1);
- } else {
- last = NULL;
- for (ac = acs->flags_list; ac; ac = ac->next) {
- if (ac->m_entry->fflags_set == me->fflags_set &&
- ac->m_entry->fflags_clear ==
- me->fflags_clear)
- break;
- last = ac;
- }
- if (attr_counter_inc(&acs->flags_list, ac, last, me) < 0)
- return (-1);
- }
- }
-
- return (0);
-}
-
-static void
-attr_counter_set_free(struct mtree_writer *mtree)
-{
- struct att_counter_set *acs = &mtree->acs;
-
- attr_counter_free(&acs->uid_list);
- attr_counter_free(&acs->gid_list);
- attr_counter_free(&acs->mode_list);
- attr_counter_free(&acs->flags_list);
-}
-
-static int
-get_global_set_keys(struct mtree_writer *mtree, struct mtree_entry *me)
-{
- int keys;
-
- keys = mtree->keys;
-
- /*
- * If a keyword has been set by /set, we do not need to
- * output it.
- */
- if (mtree->set.keys == 0)
- return (keys);/* /set is not used. */
-
- if ((mtree->set.keys & (F_GNAME | F_GID)) != 0 &&
- mtree->set.gid == me->gid)
- keys &= ~(F_GNAME | F_GID);
- if ((mtree->set.keys & (F_UNAME | F_UID)) != 0 &&
- mtree->set.uid == me->uid)
- keys &= ~(F_UNAME | F_UID);
- if (mtree->set.keys & F_FLAGS) {
- if (mtree->set.fflags_set == me->fflags_set &&
- mtree->set.fflags_clear == me->fflags_clear)
- keys &= ~F_FLAGS;
- }
- if ((mtree->set.keys & F_MODE) != 0 && mtree->set.mode == me->mode)
- keys &= ~F_MODE;
-
- switch (me->filetype) {
- case AE_IFLNK: case AE_IFSOCK: case AE_IFCHR:
- case AE_IFBLK: case AE_IFIFO:
- break;
- case AE_IFDIR:
- if ((mtree->set.keys & F_TYPE) != 0 &&
- mtree->set.type == AE_IFDIR)
- keys &= ~F_TYPE;
- break;
- case AE_IFREG:
- default: /* Handle unknown file types as regular files. */
- if ((mtree->set.keys & F_TYPE) != 0 &&
- mtree->set.type == AE_IFREG)
- keys &= ~F_TYPE;
- break;
- }
-
- return (keys);
-}
-
-static int
-mtree_entry_new(struct archive_write *a, struct archive_entry *entry,
- struct mtree_entry **m_entry)
-{
- struct mtree_entry *me;
- const char *s;
- int r;
- static const struct archive_rb_tree_ops rb_ops = {
- mtree_entry_cmp_node, mtree_entry_cmp_key
- };
-
- me = calloc(1, sizeof(*me));
- if (me == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for a mtree entry");
- *m_entry = NULL;
- return (ARCHIVE_FATAL);
- }
-
- r = mtree_entry_setup_filenames(a, me, entry);
- if (r < ARCHIVE_WARN) {
- mtree_entry_free(me);
- *m_entry = NULL;
- return (r);
- }
-
- if ((s = archive_entry_symlink(entry)) != NULL)
- archive_strcpy(&me->symlink, s);
- me->nlink = archive_entry_nlink(entry);
- me->filetype = archive_entry_filetype(entry);
- me->mode = archive_entry_mode(entry) & 07777;
- me->uid = archive_entry_uid(entry);
- me->gid = archive_entry_gid(entry);
- if ((s = archive_entry_uname(entry)) != NULL)
- archive_strcpy(&me->uname, s);
- if ((s = archive_entry_gname(entry)) != NULL)
- archive_strcpy(&me->gname, s);
- if ((s = archive_entry_fflags_text(entry)) != NULL)
- archive_strcpy(&me->fflags_text, s);
- archive_entry_fflags(entry, &me->fflags_set, &me->fflags_clear);
- me->mtime = archive_entry_mtime(entry);
- me->mtime_nsec = archive_entry_mtime_nsec(entry);
- me->rdevmajor = archive_entry_rdevmajor(entry);
- me->rdevminor = archive_entry_rdevminor(entry);
- me->size = archive_entry_size(entry);
- if (me->filetype == AE_IFDIR) {
- me->dir_info = calloc(1, sizeof(*me->dir_info));
- if (me->dir_info == NULL) {
- mtree_entry_free(me);
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for a mtree entry");
- *m_entry = NULL;
- return (ARCHIVE_FATAL);
- }
- __archive_rb_tree_init(&me->dir_info->rbtree, &rb_ops);
- me->dir_info->children.first = NULL;
- me->dir_info->children.last = &(me->dir_info->children.first);
- me->dir_info->chnext = NULL;
- } else if (me->filetype == AE_IFREG) {
- me->reg_info = calloc(1, sizeof(*me->reg_info));
- if (me->reg_info == NULL) {
- mtree_entry_free(me);
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for a mtree entry");
- *m_entry = NULL;
- return (ARCHIVE_FATAL);
- }
- me->reg_info->compute_sum = 0;
- }
-
- *m_entry = me;
- return (ARCHIVE_OK);
-}
-
-static void
-mtree_entry_free(struct mtree_entry *me)
-{
- archive_string_free(&me->parentdir);
- archive_string_free(&me->basename);
- archive_string_free(&me->pathname);
- archive_string_free(&me->symlink);
- archive_string_free(&me->uname);
- archive_string_free(&me->gname);
- archive_string_free(&me->fflags_text);
- free(me->dir_info);
- free(me->reg_info);
- free(me);
-}
-
-static int
-archive_write_mtree_header(struct archive_write *a,
- struct archive_entry *entry)
-{
- struct mtree_writer *mtree= a->format_data;
- struct mtree_entry *mtree_entry;
- int r, r2;
-
- if (mtree->first) {
- mtree->first = 0;
- archive_strcat(&mtree->buf, "#mtree\n");
- if ((mtree->keys & SET_KEYS) == 0)
- mtree->output_global_set = 0;/* Disalbed. */
- }
-
- mtree->entry_bytes_remaining = archive_entry_size(entry);
-
- /* While directory only mode, we do not handle non directory files. */
- if (mtree->dironly && archive_entry_filetype(entry) != AE_IFDIR)
- return (ARCHIVE_OK);
-
- r2 = mtree_entry_new(a, entry, &mtree_entry);
- if (r2 < ARCHIVE_WARN)
- return (r2);
- r = mtree_entry_tree_add(a, &mtree_entry);
- if (r < ARCHIVE_WARN) {
- mtree_entry_free(mtree_entry);
- return (r);
- }
- mtree->mtree_entry = mtree_entry;
-
- /* If the current file is a regular file, we have to
- * compute the sum of its content.
- * Initialize a bunch of sum check context. */
- if (mtree_entry->reg_info)
- sum_init(mtree);
-
- return (r2);
-}
-
-static int
-write_mtree_entry(struct archive_write *a, struct mtree_entry *me)
-{
- struct mtree_writer *mtree = a->format_data;
- struct archive_string *str;
- int keys, ret;
-
- if (me->dir_info) {
- if (mtree->classic) {
- /*
- * Output a comment line to describe the full
- * pathname of the entry as mtree utility does
- * while generating classic format.
- */
- if (!mtree->dironly)
- archive_strappend_char(&mtree->buf, '\n');
- if (me->parentdir.s)
- archive_string_sprintf(&mtree->buf,
- "# %s/%s\n",
- me->parentdir.s, me->basename.s);
- else
- archive_string_sprintf(&mtree->buf,
- "# %s\n",
- me->basename.s);
- }
- if (mtree->output_global_set)
- write_global(mtree);
- }
- archive_string_empty(&mtree->ebuf);
- str = (mtree->indent || mtree->classic)? &mtree->ebuf : &mtree->buf;
-
- if (!mtree->classic && me->parentdir.s) {
- /*
- * If generating format is not classic one(v1), output
- * a full pathname.
- */
- mtree_quote(str, me->parentdir.s);
- archive_strappend_char(str, '/');
- }
- mtree_quote(str, me->basename.s);
-
- keys = get_global_set_keys(mtree, me);
- if ((keys & F_NLINK) != 0 &&
- me->nlink != 1 && me->filetype != AE_IFDIR)
- archive_string_sprintf(str, " nlink=%u", me->nlink);
-
- if ((keys & F_GNAME) != 0 && archive_strlen(&me->gname) > 0) {
- archive_strcat(str, " gname=");
- mtree_quote(str, me->gname.s);
- }
- if ((keys & F_UNAME) != 0 && archive_strlen(&me->uname) > 0) {
- archive_strcat(str, " uname=");
- mtree_quote(str, me->uname.s);
- }
- if ((keys & F_FLAGS) != 0) {
- if (archive_strlen(&me->fflags_text) > 0) {
- archive_strcat(str, " flags=");
- mtree_quote(str, me->fflags_text.s);
- } else if (mtree->set.processing &&
- (mtree->set.keys & F_FLAGS) != 0)
- /* Overwrite the global parameter. */
- archive_strcat(str, " flags=none");
- }
- if ((keys & F_TIME) != 0)
- archive_string_sprintf(str, " time=%jd.%jd",
- (intmax_t)me->mtime, (intmax_t)me->mtime_nsec);
- if ((keys & F_MODE) != 0)
- archive_string_sprintf(str, " mode=%o", (unsigned int)me->mode);
- if ((keys & F_GID) != 0)
- archive_string_sprintf(str, " gid=%jd", (intmax_t)me->gid);
- if ((keys & F_UID) != 0)
- archive_string_sprintf(str, " uid=%jd", (intmax_t)me->uid);
-
- switch (me->filetype) {
- case AE_IFLNK:
- if ((keys & F_TYPE) != 0)
- archive_strcat(str, " type=link");
- if ((keys & F_SLINK) != 0) {
- archive_strcat(str, " link=");
- mtree_quote(str, me->symlink.s);
- }
- break;
- case AE_IFSOCK:
- if ((keys & F_TYPE) != 0)
- archive_strcat(str, " type=socket");
- break;
- case AE_IFCHR:
- if ((keys & F_TYPE) != 0)
- archive_strcat(str, " type=char");
- if ((keys & F_DEV) != 0) {
- archive_string_sprintf(str,
- " device=native,%ju,%ju",
- (uintmax_t)me->rdevmajor,
- (uintmax_t)me->rdevminor);
- }
- break;
- case AE_IFBLK:
- if ((keys & F_TYPE) != 0)
- archive_strcat(str, " type=block");
- if ((keys & F_DEV) != 0) {
- archive_string_sprintf(str,
- " device=native,%ju,%ju",
- (uintmax_t)me->rdevmajor,
- (uintmax_t)me->rdevminor);
- }
- break;
- case AE_IFDIR:
- if ((keys & F_TYPE) != 0)
- archive_strcat(str, " type=dir");
- break;
- case AE_IFIFO:
- if ((keys & F_TYPE) != 0)
- archive_strcat(str, " type=fifo");
- break;
- case AE_IFREG:
- default: /* Handle unknown file types as regular files. */
- if ((keys & F_TYPE) != 0)
- archive_strcat(str, " type=file");
- if ((keys & F_SIZE) != 0)
- archive_string_sprintf(str, " size=%jd",
- (intmax_t)me->size);
- break;
- }
-
- /* Write a bunch of sum. */
- if (me->reg_info)
- sum_write(str, me->reg_info);
-
- archive_strappend_char(str, '\n');
- if (mtree->indent || mtree->classic)
- mtree_indent(mtree);
-
- if (mtree->buf.length > 32768) {
- ret = __archive_write_output(
- a, mtree->buf.s, mtree->buf.length);
- archive_string_empty(&mtree->buf);
- } else
- ret = ARCHIVE_OK;
- return (ret);
-}
-
-static int
-write_dot_dot_entry(struct archive_write *a, struct mtree_entry *n)
-{
- struct mtree_writer *mtree = a->format_data;
- int ret;
-
- if (n->parentdir.s) {
- if (mtree->indent) {
- int i, pd = mtree->depth * 4;
- for (i = 0; i < pd; i++)
- archive_strappend_char(&mtree->buf, ' ');
- }
- archive_string_sprintf(&mtree->buf, "# %s/%s\n",
- n->parentdir.s, n->basename.s);
- }
-
- if (mtree->indent) {
- archive_string_empty(&mtree->ebuf);
- archive_strncat(&mtree->ebuf, "..\n\n", (mtree->dironly)?3:4);
- mtree_indent(mtree);
- } else
- archive_strncat(&mtree->buf, "..\n\n", (mtree->dironly)?3:4);
-
- if (mtree->buf.length > 32768) {
- ret = __archive_write_output(
- a, mtree->buf.s, mtree->buf.length);
- archive_string_empty(&mtree->buf);
- } else
- ret = ARCHIVE_OK;
- return (ret);
-}
-
-/*
- * Write mtree entries saved at attr_counter_set_collect() function.
- */
-static int
-write_mtree_entry_tree(struct archive_write *a)
-{
- struct mtree_writer *mtree = a->format_data;
- struct mtree_entry *np = mtree->root;
- struct archive_rb_node *n;
- int ret;
-
- do {
- if (mtree->output_global_set) {
- /*
- * Collect attribute infomation to know which value
- * is frequently used among the children.
- */
- attr_counter_set_reset(mtree);
- ARCHIVE_RB_TREE_FOREACH(n, &(np->dir_info->rbtree)) {
- struct mtree_entry *e = (struct mtree_entry *)n;
- if (attr_counter_set_collect(mtree, e) < 0) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- }
- }
- if (!np->dir_info->virtual || mtree->classic) {
- ret = write_mtree_entry(a, np);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- } else {
- /* Whenever output_global_set is enabled
- * output global value(/set keywords)
- * even if the directory entry is not allowd
- * to be written because the global values
- * can be used for the children. */
- if (mtree->output_global_set)
- write_global(mtree);
- }
- /*
- * Output the attribute of all files except directory files.
- */
- mtree->depth++;
- ARCHIVE_RB_TREE_FOREACH(n, &(np->dir_info->rbtree)) {
- struct mtree_entry *e = (struct mtree_entry *)n;
-
- if (e->dir_info)
- mtree_entry_add_child_tail(np, e);
- else {
- ret = write_mtree_entry(a, e);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
- }
- mtree->depth--;
-
- if (np->dir_info->children.first != NULL) {
- /*
- * Descend the tree.
- */
- np = np->dir_info->children.first;
- if (mtree->indent)
- mtree->depth++;
- continue;
- } else if (mtree->classic) {
- /*
- * While printing mtree classic, if there are not
- * any directory files(except "." and "..") in the
- * directory, output two dots ".." as returning
- * the parent directory.
- */
- ret = write_dot_dot_entry(a, np);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
-
- while (np != np->parent) {
- if (np->dir_info->chnext == NULL) {
- /*
- * Ascend the tree; go back to the parent.
- */
- if (mtree->indent)
- mtree->depth--;
- if (mtree->classic) {
- ret = write_dot_dot_entry(a,
- np->parent);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
- np = np->parent;
- } else {
- /*
- * Switch to next mtree entry in the directory.
- */
- np = np->dir_info->chnext;
- break;
- }
- }
- } while (np != np->parent);
-
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_mtree_finish_entry(struct archive_write *a)
-{
- struct mtree_writer *mtree = a->format_data;
- struct mtree_entry *me;
-
- if ((me = mtree->mtree_entry) == NULL)
- return (ARCHIVE_OK);
- mtree->mtree_entry = NULL;
-
- if (me->reg_info)
- sum_final(mtree, me->reg_info);
-
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_mtree_close(struct archive_write *a)
-{
- struct mtree_writer *mtree= a->format_data;
- int ret;
-
- if (mtree->root != NULL) {
- ret = write_mtree_entry_tree(a);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
-
- archive_write_set_bytes_in_last_block(&a->archive, 1);
-
- return __archive_write_output(a, mtree->buf.s, mtree->buf.length);
-}
-
-static ssize_t
-archive_write_mtree_data(struct archive_write *a, const void *buff, size_t n)
-{
- struct mtree_writer *mtree= a->format_data;
-
- if (n > mtree->entry_bytes_remaining)
- n = (size_t)mtree->entry_bytes_remaining;
- mtree->entry_bytes_remaining -= n;
-
- /* We don't need to compute a regular file sum */
- if (mtree->mtree_entry == NULL)
- return (n);
-
- if (mtree->mtree_entry->filetype == AE_IFREG)
- sum_update(mtree, buff, n);
-
- return (n);
-}
-
-static int
-archive_write_mtree_free(struct archive_write *a)
-{
- struct mtree_writer *mtree= a->format_data;
-
- if (mtree == NULL)
- return (ARCHIVE_OK);
-
- /* Make sure we dot not leave any entries. */
- mtree_entry_register_free(mtree);
- archive_string_free(&mtree->cur_dirstr);
- archive_string_free(&mtree->ebuf);
- archive_string_free(&mtree->buf);
- attr_counter_set_free(mtree);
- free(mtree);
- a->format_data = NULL;
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_mtree_options(struct archive_write *a, const char *key,
- const char *value)
-{
- struct mtree_writer *mtree= a->format_data;
- int keybit = 0;
-
- switch (key[0]) {
- case 'a':
- if (strcmp(key, "all") == 0)
- keybit = ~0;
- break;
- case 'c':
- if (strcmp(key, "cksum") == 0)
- keybit = F_CKSUM;
- break;
- case 'd':
- if (strcmp(key, "device") == 0)
- keybit = F_DEV;
- else if (strcmp(key, "dironly") == 0) {
- mtree->dironly = (value != NULL)? 1: 0;
- return (ARCHIVE_OK);
- }
- break;
- case 'f':
- if (strcmp(key, "flags") == 0)
- keybit = F_FLAGS;
- break;
- case 'g':
- if (strcmp(key, "gid") == 0)
- keybit = F_GID;
- else if (strcmp(key, "gname") == 0)
- keybit = F_GNAME;
- break;
- case 'i':
- if (strcmp(key, "indent") == 0) {
- mtree->indent = (value != NULL)? 1: 0;
- return (ARCHIVE_OK);
- }
- break;
- case 'l':
- if (strcmp(key, "link") == 0)
- keybit = F_SLINK;
- break;
- case 'm':
- if (strcmp(key, "md5") == 0 ||
- strcmp(key, "md5digest") == 0)
- keybit = F_MD5;
- if (strcmp(key, "mode") == 0)
- keybit = F_MODE;
- break;
- case 'n':
- if (strcmp(key, "nlink") == 0)
- keybit = F_NLINK;
- break;
- case 'r':
- if (strcmp(key, "ripemd160digest") == 0 ||
- strcmp(key, "rmd160") == 0 ||
- strcmp(key, "rmd160digest") == 0)
- keybit = F_RMD160;
- break;
- case 's':
- if (strcmp(key, "sha1") == 0 ||
- strcmp(key, "sha1digest") == 0)
- keybit = F_SHA1;
- if (strcmp(key, "sha256") == 0 ||
- strcmp(key, "sha256digest") == 0)
- keybit = F_SHA256;
- if (strcmp(key, "sha384") == 0 ||
- strcmp(key, "sha384digest") == 0)
- keybit = F_SHA384;
- if (strcmp(key, "sha512") == 0 ||
- strcmp(key, "sha512digest") == 0)
- keybit = F_SHA512;
- if (strcmp(key, "size") == 0)
- keybit = F_SIZE;
- break;
- case 't':
- if (strcmp(key, "time") == 0)
- keybit = F_TIME;
- else if (strcmp(key, "type") == 0)
- keybit = F_TYPE;
- break;
- case 'u':
- if (strcmp(key, "uid") == 0)
- keybit = F_UID;
- else if (strcmp(key, "uname") == 0)
- keybit = F_UNAME;
- else if (strcmp(key, "use-set") == 0) {
- mtree->output_global_set = (value != NULL)? 1: 0;
- return (ARCHIVE_OK);
- }
- break;
- }
- if (keybit != 0) {
- if (value != NULL)
- mtree->keys |= keybit;
- else
- mtree->keys &= ~keybit;
- return (ARCHIVE_OK);
- }
-
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
-}
-
-static int
-archive_write_set_format_mtree_default(struct archive *_a, const char *fn)
-{
- struct archive_write *a = (struct archive_write *)_a;
- struct mtree_writer *mtree;
-
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, fn);
-
- if (a->format_free != NULL)
- (a->format_free)(a);
-
- if ((mtree = calloc(1, sizeof(*mtree))) == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate mtree data");
- return (ARCHIVE_FATAL);
- }
-
- mtree->mtree_entry = NULL;
- mtree->first = 1;
- memset(&(mtree->set), 0, sizeof(mtree->set));
- mtree->keys = DEFAULT_KEYS;
- mtree->dironly = 0;
- mtree->indent = 0;
- archive_string_init(&mtree->ebuf);
- archive_string_init(&mtree->buf);
- mtree_entry_register_init(mtree);
- a->format_data = mtree;
- a->format_free = archive_write_mtree_free;
- a->format_name = "mtree";
- a->format_options = archive_write_mtree_options;
- a->format_write_header = archive_write_mtree_header;
- a->format_close = archive_write_mtree_close;
- a->format_write_data = archive_write_mtree_data;
- a->format_finish_entry = archive_write_mtree_finish_entry;
- a->archive.archive_format = ARCHIVE_FORMAT_MTREE;
- a->archive.archive_format_name = "mtree";
-
- return (ARCHIVE_OK);
-}
-
-int
-archive_write_set_format_mtree(struct archive *_a)
-{
- return archive_write_set_format_mtree_default(_a,
- "archive_write_set_format_mtree");
-}
-
-int
-archive_write_set_format_mtree_classic(struct archive *_a)
-{
- int r;
-
- r = archive_write_set_format_mtree_default(_a,
- "archive_write_set_format_mtree_classic");
- if (r == ARCHIVE_OK) {
- struct archive_write *a = (struct archive_write *)_a;
- struct mtree_writer *mtree;
-
- mtree = (struct mtree_writer *)a->format_data;
-
- /* Set to output a mtree archive in classic format. */
- mtree->classic = 1;
- /* Basically, mtree classic format uses '/set' global
- * value. */
- mtree->output_global_set = 1;
- }
- return (r);
-}
-
-static void
-sum_init(struct mtree_writer *mtree)
-{
-
- mtree->compute_sum = 0;
-
- if (mtree->keys & F_CKSUM) {
- mtree->compute_sum |= F_CKSUM;
- mtree->crc = 0;
- mtree->crc_len = 0;
- }
-#ifdef ARCHIVE_HAS_MD5
- if (mtree->keys & F_MD5) {
- if (archive_md5_init(&mtree->md5ctx) == ARCHIVE_OK)
- mtree->compute_sum |= F_MD5;
- else
- mtree->keys &= ~F_MD5;/* Not supported. */
- }
-#endif
-#ifdef ARCHIVE_HAS_RMD160
- if (mtree->keys & F_RMD160) {
- if (archive_rmd160_init(&mtree->rmd160ctx) == ARCHIVE_OK)
- mtree->compute_sum |= F_RMD160;
- else
- mtree->keys &= ~F_RMD160;/* Not supported. */
- }
-#endif
-#ifdef ARCHIVE_HAS_SHA1
- if (mtree->keys & F_SHA1) {
- if (archive_sha1_init(&mtree->sha1ctx) == ARCHIVE_OK)
- mtree->compute_sum |= F_SHA1;
- else
- mtree->keys &= ~F_SHA1;/* Not supported. */
- }
-#endif
-#ifdef ARCHIVE_HAS_SHA256
- if (mtree->keys & F_SHA256) {
- if (archive_sha256_init(&mtree->sha256ctx) == ARCHIVE_OK)
- mtree->compute_sum |= F_SHA256;
- else
- mtree->keys &= ~F_SHA256;/* Not supported. */
- }
-#endif
-#ifdef ARCHIVE_HAS_SHA384
- if (mtree->keys & F_SHA384) {
- if (archive_sha384_init(&mtree->sha384ctx) == ARCHIVE_OK)
- mtree->compute_sum |= F_SHA384;
- else
- mtree->keys &= ~F_SHA384;/* Not supported. */
- }
-#endif
-#ifdef ARCHIVE_HAS_SHA512
- if (mtree->keys & F_SHA512) {
- if (archive_sha512_init(&mtree->sha512ctx) == ARCHIVE_OK)
- mtree->compute_sum |= F_SHA512;
- else
- mtree->keys &= ~F_SHA512;/* Not supported. */
- }
-#endif
-}
-
-static void
-sum_update(struct mtree_writer *mtree, const void *buff, size_t n)
-{
- if (mtree->compute_sum & F_CKSUM) {
- /*
- * Compute a POSIX 1003.2 checksum
- */
- const unsigned char *p;
- size_t nn;
-
- for (nn = n, p = buff; nn--; ++p)
- COMPUTE_CRC(mtree->crc, *p);
- mtree->crc_len += n;
- }
-#ifdef ARCHIVE_HAS_MD5
- if (mtree->compute_sum & F_MD5)
- archive_md5_update(&mtree->md5ctx, buff, n);
-#endif
-#ifdef ARCHIVE_HAS_RMD160
- if (mtree->compute_sum & F_RMD160)
- archive_rmd160_update(&mtree->rmd160ctx, buff, n);
-#endif
-#ifdef ARCHIVE_HAS_SHA1
- if (mtree->compute_sum & F_SHA1)
- archive_sha1_update(&mtree->sha1ctx, buff, n);
-#endif
-#ifdef ARCHIVE_HAS_SHA256
- if (mtree->compute_sum & F_SHA256)
- archive_sha256_update(&mtree->sha256ctx, buff, n);
-#endif
-#ifdef ARCHIVE_HAS_SHA384
- if (mtree->compute_sum & F_SHA384)
- archive_sha384_update(&mtree->sha384ctx, buff, n);
-#endif
-#ifdef ARCHIVE_HAS_SHA512
- if (mtree->compute_sum & F_SHA512)
- archive_sha512_update(&mtree->sha512ctx, buff, n);
-#endif
-}
-
-static void
-sum_final(struct mtree_writer *mtree, struct reg_info *reg)
-{
-
- if (mtree->compute_sum & F_CKSUM) {
- uint64_t len;
- /* Include the length of the file. */
- for (len = mtree->crc_len; len != 0; len >>= 8)
- COMPUTE_CRC(mtree->crc, len & 0xff);
- reg->crc = ~mtree->crc;
- }
-#ifdef ARCHIVE_HAS_MD5
- if (mtree->compute_sum & F_MD5)
- archive_md5_final(&mtree->md5ctx, reg->buf_md5);
-#endif
-#ifdef ARCHIVE_HAS_RMD160
- if (mtree->compute_sum & F_RMD160)
- archive_rmd160_final(&mtree->rmd160ctx, reg->buf_rmd160);
-#endif
-#ifdef ARCHIVE_HAS_SHA1
- if (mtree->compute_sum & F_SHA1)
- archive_sha1_final(&mtree->sha1ctx, reg->buf_sha1);
-#endif
-#ifdef ARCHIVE_HAS_SHA256
- if (mtree->compute_sum & F_SHA256)
- archive_sha256_final(&mtree->sha256ctx, reg->buf_sha256);
-#endif
-#ifdef ARCHIVE_HAS_SHA384
- if (mtree->compute_sum & F_SHA384)
- archive_sha384_final(&mtree->sha384ctx, reg->buf_sha384);
-#endif
-#ifdef ARCHIVE_HAS_SHA512
- if (mtree->compute_sum & F_SHA512)
- archive_sha512_final(&mtree->sha512ctx, reg->buf_sha512);
-#endif
- /* Save what types of sum are computed. */
- reg->compute_sum = mtree->compute_sum;
-}
-
-#if defined(ARCHIVE_HAS_MD5) || defined(ARCHIVE_HAS_RMD160) || \
- defined(ARCHIVE_HAS_SHA1) || defined(ARCHIVE_HAS_SHA256) || \
- defined(ARCHIVE_HAS_SHA384) || defined(ARCHIVE_HAS_SHA512)
-static void
-strappend_bin(struct archive_string *s, const unsigned char *bin, int n)
-{
- static const char hex[] = "0123456789abcdef";
- int i;
-
- for (i = 0; i < n; i++) {
- archive_strappend_char(s, hex[bin[i] >> 4]);
- archive_strappend_char(s, hex[bin[i] & 0x0f]);
- }
-}
-#endif
-
-static void
-sum_write(struct archive_string *str, struct reg_info *reg)
-{
-
- if (reg->compute_sum & F_CKSUM) {
- archive_string_sprintf(str, " cksum=%ju",
- (uintmax_t)reg->crc);
- }
-#ifdef ARCHIVE_HAS_MD5
- if (reg->compute_sum & F_MD5) {
- archive_strcat(str, " md5digest=");
- strappend_bin(str, reg->buf_md5, sizeof(reg->buf_md5));
- }
-#endif
-#ifdef ARCHIVE_HAS_RMD160
- if (reg->compute_sum & F_RMD160) {
- archive_strcat(str, " rmd160digest=");
- strappend_bin(str, reg->buf_rmd160, sizeof(reg->buf_rmd160));
- }
-#endif
-#ifdef ARCHIVE_HAS_SHA1
- if (reg->compute_sum & F_SHA1) {
- archive_strcat(str, " sha1digest=");
- strappend_bin(str, reg->buf_sha1, sizeof(reg->buf_sha1));
- }
-#endif
-#ifdef ARCHIVE_HAS_SHA256
- if (reg->compute_sum & F_SHA256) {
- archive_strcat(str, " sha256digest=");
- strappend_bin(str, reg->buf_sha256, sizeof(reg->buf_sha256));
- }
-#endif
-#ifdef ARCHIVE_HAS_SHA384
- if (reg->compute_sum & F_SHA384) {
- archive_strcat(str, " sha384digest=");
- strappend_bin(str, reg->buf_sha384, sizeof(reg->buf_sha384));
- }
-#endif
-#ifdef ARCHIVE_HAS_SHA512
- if (reg->compute_sum & F_SHA512) {
- archive_strcat(str, " sha512digest=");
- strappend_bin(str, reg->buf_sha512, sizeof(reg->buf_sha512));
- }
-#endif
-}
-
-static int
-mtree_entry_cmp_node(const struct archive_rb_node *n1,
- const struct archive_rb_node *n2)
-{
- const struct mtree_entry *e1 = (const struct mtree_entry *)n1;
- const struct mtree_entry *e2 = (const struct mtree_entry *)n2;
-
- return (strcmp(e2->basename.s, e1->basename.s));
-}
-
-static int
-mtree_entry_cmp_key(const struct archive_rb_node *n, const void *key)
-{
- const struct mtree_entry *e = (const struct mtree_entry *)n;
-
- return (strcmp((const char *)key, e->basename.s));
-}
-
-#if defined(_WIN32) || defined(__CYGWIN__)
-static int
-cleanup_backslash_1(char *p)
-{
- int mb, dos;
-
- mb = dos = 0;
- while (*p) {
- if (*(unsigned char *)p > 127)
- mb = 1;
- if (*p == '\\') {
- /* If we have not met any multi-byte characters,
- * we can replace '\' with '/'. */
- if (!mb)
- *p = '/';
- dos = 1;
- }
- p++;
- }
- if (!mb || !dos)
- return (0);
- return (-1);
-}
-
-static void
-cleanup_backslash_2(wchar_t *p)
-{
-
- /* Convert a path-separator from '\' to '/' */
- while (*p != L'\0') {
- if (*p == L'\\')
- *p = L'/';
- p++;
- }
-}
-#endif
-
-/*
- * Generate a parent directory name and a base name from a pathname.
- */
-static int
-mtree_entry_setup_filenames(struct archive_write *a, struct mtree_entry *file,
- struct archive_entry *entry)
-{
- const char *pathname;
- char *p, *dirname, *slash;
- size_t len;
- int ret = ARCHIVE_OK;
-
- archive_strcpy(&file->pathname, archive_entry_pathname(entry));
-#if defined(_WIN32) || defined(__CYGWIN__)
- /*
- * Convert a path-separator from '\' to '/'
- */
- if (cleanup_backslash_1(file->pathname.s) != 0) {
- const wchar_t *wp = archive_entry_pathname_w(entry);
- struct archive_wstring ws;
-
- if (wp != NULL) {
- int r;
- archive_string_init(&ws);
- archive_wstrcpy(&ws, wp);
- cleanup_backslash_2(ws.s);
- archive_string_empty(&(file->pathname));
- r = archive_string_append_from_wcs(&(file->pathname),
- ws.s, ws.length);
- archive_wstring_free(&ws);
- if (r < 0 && errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- }
- }
-#else
- (void)a; /* UNUSED */
-#endif
- pathname = file->pathname.s;
- if (strcmp(pathname, ".") == 0) {
- archive_strcpy(&file->basename, ".");
- return (ARCHIVE_OK);
- }
-
- archive_strcpy(&(file->parentdir), pathname);
-
- len = file->parentdir.length;
- p = dirname = file->parentdir.s;
-
- /*
- * Remove leading '/' and '../' elements
- */
- while (*p) {
- if (p[0] == '/') {
- p++;
- len--;
- } else if (p[0] != '.')
- break;
- else if (p[1] == '.' && p[2] == '/') {
- p += 3;
- len -= 3;
- } else
- break;
- }
- if (p != dirname) {
- memmove(dirname, p, len+1);
- p = dirname;
- }
- /*
- * Remove "/","/." and "/.." elements from tail.
- */
- while (len > 0) {
- size_t ll = len;
-
- if (len > 0 && p[len-1] == '/') {
- p[len-1] = '\0';
- len--;
- }
- if (len > 1 && p[len-2] == '/' && p[len-1] == '.') {
- p[len-2] = '\0';
- len -= 2;
- }
- if (len > 2 && p[len-3] == '/' && p[len-2] == '.' &&
- p[len-1] == '.') {
- p[len-3] = '\0';
- len -= 3;
- }
- if (ll == len)
- break;
- }
- while (*p) {
- if (p[0] == '/') {
- if (p[1] == '/')
- /* Convert '//' --> '/' */
- strcpy(p, p+1);
- else if (p[1] == '.' && p[2] == '/')
- /* Convert '/./' --> '/' */
- strcpy(p, p+2);
- else if (p[1] == '.' && p[2] == '.' && p[3] == '/') {
- /* Convert 'dir/dir1/../dir2/'
- * --> 'dir/dir2/'
- */
- char *rp = p -1;
- while (rp >= dirname) {
- if (*rp == '/')
- break;
- --rp;
- }
- if (rp > dirname) {
- strcpy(rp, p+3);
- p = rp;
- } else {
- strcpy(dirname, p+4);
- p = dirname;
- }
- } else
- p++;
- } else
- p++;
- }
- p = dirname;
- len = strlen(p);
-
- /*
- * Add "./" prefiex.
- * NOTE: If the pathname does not have a path separator, we have
- * to add "./" to the head of the pathename because mtree reader
- * will suppose that it is v1(a.k.a classic) mtree format and
- * change the directory unexpectedly and so it will make a wrong
- * path.
- */
- if (strcmp(p, ".") != 0 && strncmp(p, "./", 2) != 0) {
- struct archive_string as;
- archive_string_init(&as);
- archive_strcpy(&as, "./");
- archive_strncat(&as, p, len);
- archive_string_empty(&file->parentdir);
- archive_string_concat(&file->parentdir, &as);
- archive_string_free(&as);
- p = file->parentdir.s;
- len = archive_strlen(&file->parentdir);
- }
-
- /*
- * Find out the position which points the last position of
- * path separator('/').
- */
- slash = NULL;
- for (; *p != '\0'; p++) {
- if (*p == '/')
- slash = p;
- }
- if (slash == NULL) {
- /* The pathname doesn't have a parent directory. */
- file->parentdir.length = len;
- archive_string_copy(&(file->basename), &(file->parentdir));
- archive_string_empty(&(file->parentdir));
- *file->parentdir.s = '\0';
- return (ret);
- }
-
- /* Make a basename from dirname and slash */
- *slash = '\0';
- file->parentdir.length = slash - dirname;
- archive_strcpy(&(file->basename), slash + 1);
- return (ret);
-}
-
-static int
-mtree_entry_create_virtual_dir(struct archive_write *a, const char *pathname,
- struct mtree_entry **m_entry)
-{
- struct archive_entry *entry;
- struct mtree_entry *file;
- int r;
-
- entry = archive_entry_new();
- if (entry == NULL) {
- *m_entry = NULL;
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- archive_entry_copy_pathname(entry, pathname);
- archive_entry_set_mode(entry, AE_IFDIR | 0755);
- archive_entry_set_mtime(entry, time(NULL), 0);
-
- r = mtree_entry_new(a, entry, &file);
- archive_entry_free(entry);
- if (r < ARCHIVE_WARN) {
- *m_entry = NULL;
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
-
- file->dir_info->virtual = 1;
-
- *m_entry = file;
- return (ARCHIVE_OK);
-}
-
-static void
-mtree_entry_register_add(struct mtree_writer *mtree, struct mtree_entry *file)
-{
- file->next = NULL;
- *mtree->file_list.last = file;
- mtree->file_list.last = &(file->next);
-}
-
-static void
-mtree_entry_register_init(struct mtree_writer *mtree)
-{
- mtree->file_list.first = NULL;
- mtree->file_list.last = &(mtree->file_list.first);
-}
-
-static void
-mtree_entry_register_free(struct mtree_writer *mtree)
-{
- struct mtree_entry *file, *file_next;
-
- file = mtree->file_list.first;
- while (file != NULL) {
- file_next = file->next;
- mtree_entry_free(file);
- file = file_next;
- }
-}
-
-static int
-mtree_entry_add_child_tail(struct mtree_entry *parent,
- struct mtree_entry *child)
-{
- child->dir_info->chnext = NULL;
- *parent->dir_info->children.last = child;
- parent->dir_info->children.last = &(child->dir_info->chnext);
- return (1);
-}
-
-/*
- * Find a entry from a parent entry with the name.
- */
-static struct mtree_entry *
-mtree_entry_find_child(struct mtree_entry *parent, const char *child_name)
-{
- struct mtree_entry *np;
-
- if (parent == NULL)
- return (NULL);
- np = (struct mtree_entry *)__archive_rb_tree_find_node(
- &(parent->dir_info->rbtree), child_name);
- return (np);
-}
-
-static int
-get_path_component(char *name, size_t n, const char *fn)
-{
- char *p;
- size_t l;
-
- p = strchr(fn, '/');
- if (p == NULL) {
- if ((l = strlen(fn)) == 0)
- return (0);
- } else
- l = p - fn;
- if (l > n -1)
- return (-1);
- memcpy(name, fn, l);
- name[l] = '\0';
-
- return ((int)l);
-}
-
-/*
- * Add a new entry into the tree.
- */
-static int
-mtree_entry_tree_add(struct archive_write *a, struct mtree_entry **filep)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
- char name[_MAX_FNAME];/* Included null terminator size. */
-#elif defined(NAME_MAX) && NAME_MAX >= 255
- char name[NAME_MAX+1];
-#else
- char name[256];
-#endif
- struct mtree_writer *mtree = (struct mtree_writer *)a->format_data;
- struct mtree_entry *dent, *file, *np;
- const char *fn, *p;
- int l, r;
-
- file = *filep;
- if (file->parentdir.length == 0 && file->basename.length == 1 &&
- file->basename.s[0] == '.') {
- file->parent = file;
- if (mtree->root != NULL) {
- np = mtree->root;
- goto same_entry;
- }
- mtree->root = file;
- mtree_entry_register_add(mtree, file);
- return (ARCHIVE_OK);
- }
-
- if (file->parentdir.length == 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal programing error "
- "in generating canonical name for %s",
- file->pathname.s);
- return (ARCHIVE_FAILED);
- }
-
- fn = p = file->parentdir.s;
-
- /*
- * If the path of the parent directory of `file' entry is
- * the same as the path of `cur_dirent', add `file' entry to
- * `cur_dirent'.
- */
- if (archive_strlen(&(mtree->cur_dirstr))
- == archive_strlen(&(file->parentdir)) &&
- strcmp(mtree->cur_dirstr.s, fn) == 0) {
- if (!__archive_rb_tree_insert_node(
- &(mtree->cur_dirent->dir_info->rbtree),
- (struct archive_rb_node *)file)) {
- /* There is the same name in the tree. */
- np = (struct mtree_entry *)__archive_rb_tree_find_node(
- &(mtree->cur_dirent->dir_info->rbtree),
- file->basename.s);
- goto same_entry;
- }
- file->parent = mtree->cur_dirent;
- mtree_entry_register_add(mtree, file);
- return (ARCHIVE_OK);
- }
-
- dent = mtree->root;
- for (;;) {
- l = get_path_component(name, sizeof(name), fn);
- if (l == 0) {
- np = NULL;
- break;
- }
- if (l < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "A name buffer is too small");
- return (ARCHIVE_FATAL);
- }
- if (l == 1 && name[0] == '.' && dent != NULL &&
- dent == mtree->root) {
- fn += l;
- if (fn[0] == '/')
- fn++;
- continue;
- }
-
- np = mtree_entry_find_child(dent, name);
- if (np == NULL || fn[0] == '\0')
- break;
-
- /* Find next sub directory. */
- if (!np->dir_info) {
- /* NOT Directory! */
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "`%s' is not directory, we cannot insert `%s' ",
- np->pathname.s, file->pathname.s);
- return (ARCHIVE_FAILED);
- }
- fn += l;
- if (fn[0] == '/')
- fn++;
- dent = np;
- }
- if (np == NULL) {
- /*
- * Create virtual parent directories.
- */
- while (fn[0] != '\0') {
- struct mtree_entry *vp;
- struct archive_string as;
-
- archive_string_init(&as);
- archive_strncat(&as, p, fn - p + l);
- if (as.s[as.length-1] == '/') {
- as.s[as.length-1] = '\0';
- as.length--;
- }
- r = mtree_entry_create_virtual_dir(a, as.s, &vp);
- archive_string_free(&as);
- if (r < ARCHIVE_WARN)
- return (r);
-
- if (strcmp(vp->pathname.s, ".") == 0) {
- vp->parent = vp;
- mtree->root = vp;
- } else {
- __archive_rb_tree_insert_node(
- &(dent->dir_info->rbtree),
- (struct archive_rb_node *)vp);
- vp->parent = dent;
- }
- mtree_entry_register_add(mtree, vp);
- np = vp;
-
- fn += l;
- if (fn[0] == '/')
- fn++;
- l = get_path_component(name, sizeof(name), fn);
- if (l < 0) {
- archive_string_free(&as);
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "A name buffer is too small");
- return (ARCHIVE_FATAL);
- }
- dent = np;
- }
-
- /* Found out the parent directory where `file' can be
- * inserted. */
- mtree->cur_dirent = dent;
- archive_string_empty(&(mtree->cur_dirstr));
- archive_string_ensure(&(mtree->cur_dirstr),
- archive_strlen(&(dent->parentdir)) +
- archive_strlen(&(dent->basename)) + 2);
- if (archive_strlen(&(dent->parentdir)) +
- archive_strlen(&(dent->basename)) == 0)
- mtree->cur_dirstr.s[0] = 0;
- else {
- if (archive_strlen(&(dent->parentdir)) > 0) {
- archive_string_copy(&(mtree->cur_dirstr),
- &(dent->parentdir));
- archive_strappend_char(
- &(mtree->cur_dirstr), '/');
- }
- archive_string_concat(&(mtree->cur_dirstr),
- &(dent->basename));
- }
-
- if (!__archive_rb_tree_insert_node(
- &(dent->dir_info->rbtree),
- (struct archive_rb_node *)file)) {
- np = (struct mtree_entry *)__archive_rb_tree_find_node(
- &(dent->dir_info->rbtree), file->basename.s);
- goto same_entry;
- }
- file->parent = dent;
- mtree_entry_register_add(mtree, file);
- return (ARCHIVE_OK);
- }
-
-same_entry:
- /*
- * We have already has the entry the filename of which is
- * the same.
- */
- r = mtree_entry_exchange_same_entry(a, np, file);
- if (r < ARCHIVE_WARN)
- return (r);
- if (np->dir_info)
- np->dir_info->virtual = 0;
- *filep = np;
- mtree_entry_free(file);
- return (ARCHIVE_WARN);
-}
-
-static int
-mtree_entry_exchange_same_entry(struct archive_write *a, struct mtree_entry *np,
- struct mtree_entry *file)
-{
-
- if ((np->mode & AE_IFMT) != (file->mode & AE_IFMT)) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Found duplicate entries `%s' and its file type is "
- "different",
- np->pathname.s);
- return (ARCHIVE_FAILED);
- }
-
- /* Update the existent mtree entry's attributes by the new one's. */
- archive_string_empty(&np->symlink);
- archive_string_concat(&np->symlink, &file->symlink);
- archive_string_empty(&np->uname);
- archive_string_concat(&np->uname, &file->uname);
- archive_string_empty(&np->gname);
- archive_string_concat(&np->gname, &file->gname);
- archive_string_empty(&np->fflags_text);
- archive_string_concat(&np->fflags_text, &file->fflags_text);
- np->nlink = file->nlink;
- np->filetype = file->filetype;
- np->mode = file->mode;
- np->size = file->size;
- np->uid = file->uid;
- np->gid = file->gid;
- np->fflags_set = file->fflags_set;
- np->fflags_clear = file->fflags_clear;
- np->mtime = file->mtime;
- np->mtime_nsec = file->mtime_nsec;
- np->rdevmajor = file->rdevmajor;
- np->rdevminor = file->rdevminor;
-
- return (ARCHIVE_WARN);
-}
diff --git a/3rdparty/libarchive/libarchive/archive_write_set_format_pax.c b/3rdparty/libarchive/libarchive/archive_write_set_format_pax.c
deleted file mode 100644
index 687f8e48..00000000
--- a/3rdparty/libarchive/libarchive/archive_write_set_format_pax.c
+++ /dev/null
@@ -1,1900 +0,0 @@
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * Copyright (c) 2010-2012 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"
-__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_pax.c 201162 2009-12-29 05:47:46Z kientzle $");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#include "archive.h"
-#include "archive_entry.h"
-#include "archive_entry_locale.h"
-#include "archive_private.h"
-#include "archive_write_private.h"
-
-struct sparse_block {
- struct sparse_block *next;
- int is_hole;
- uint64_t offset;
- uint64_t remaining;
-};
-
-struct pax {
- uint64_t entry_bytes_remaining;
- uint64_t entry_padding;
- struct archive_string l_url_encoded_name;
- struct archive_string pax_header;
- struct archive_string sparse_map;
- size_t sparse_map_padding;
- struct sparse_block *sparse_list;
- struct sparse_block *sparse_tail;
- struct archive_string_conv *sconv_utf8;
- int opt_binary;
-};
-
-static void add_pax_attr(struct archive_string *, const char *key,
- const char *value);
-static void add_pax_attr_int(struct archive_string *,
- const char *key, int64_t value);
-static void add_pax_attr_time(struct archive_string *,
- const char *key, int64_t sec,
- unsigned long nanos);
-static ssize_t archive_write_pax_data(struct archive_write *,
- const void *, size_t);
-static int archive_write_pax_close(struct archive_write *);
-static int archive_write_pax_free(struct archive_write *);
-static int archive_write_pax_finish_entry(struct archive_write *);
-static int archive_write_pax_header(struct archive_write *,
- struct archive_entry *);
-static int archive_write_pax_options(struct archive_write *,
- const char *, const char *);
-static char *base64_encode(const char *src, size_t len);
-static char *build_gnu_sparse_name(char *dest, const char *src);
-static char *build_pax_attribute_name(char *dest, const char *src);
-static char *build_ustar_entry_name(char *dest, const char *src,
- size_t src_length, const char *insert);
-static char *format_int(char *dest, int64_t);
-static int has_non_ASCII(const char *);
-static void sparse_list_clear(struct pax *);
-static int sparse_list_add(struct pax *, int64_t, int64_t);
-static char *url_encode(const char *in);
-
-/*
- * Set output format to 'restricted pax' format.
- *
- * This is the same as normal 'pax', but tries to suppress
- * the pax header whenever possible. This is the default for
- * bsdtar, for instance.
- */
-int
-archive_write_set_format_pax_restricted(struct archive *_a)
-{
- struct archive_write *a = (struct archive_write *)_a;
- int r;
-
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_set_format_pax_restricted");
-
- r = archive_write_set_format_pax(&a->archive);
- a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED;
- a->archive.archive_format_name = "restricted POSIX pax interchange";
- return (r);
-}
-
-/*
- * Set output format to 'pax' format.
- */
-int
-archive_write_set_format_pax(struct archive *_a)
-{
- struct archive_write *a = (struct archive_write *)_a;
- struct pax *pax;
-
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_set_format_pax");
-
- if (a->format_free != NULL)
- (a->format_free)(a);
-
- pax = (struct pax *)malloc(sizeof(*pax));
- if (pax == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate pax data");
- return (ARCHIVE_FATAL);
- }
- memset(pax, 0, sizeof(*pax));
- a->format_data = pax;
- a->format_name = "pax";
- a->format_options = archive_write_pax_options;
- a->format_write_header = archive_write_pax_header;
- a->format_write_data = archive_write_pax_data;
- a->format_close = archive_write_pax_close;
- a->format_free = archive_write_pax_free;
- a->format_finish_entry = archive_write_pax_finish_entry;
- a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
- a->archive.archive_format_name = "POSIX pax interchange";
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_pax_options(struct archive_write *a, const char *key,
- const char *val)
-{
- struct pax *pax = (struct pax *)a->format_data;
- int ret = ARCHIVE_FAILED;
-
- if (strcmp(key, "hdrcharset") == 0) {
- /*
- * The character-set we can use are defined in
- * IEEE Std 1003.1-2001
- */
- if (val == NULL || val[0] == 0)
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "pax: hdrcharset option needs a character-set name");
- else if (strcmp(val, "BINARY") == 0 ||
- strcmp(val, "binary") == 0) {
- /*
- * Specify binary mode. We will not convert
- * filenames, uname and gname to any charsets.
- */
- pax->opt_binary = 1;
- ret = ARCHIVE_OK;
- } else if (strcmp(val, "UTF-8") == 0) {
- /*
- * Specify UTF-8 character-set to be used for
- * filenames. This is almost the test that
- * running platform supports the string conversion.
- * Especially libarchive_test needs this trick for
- * its test.
- */
- pax->sconv_utf8 = archive_string_conversion_to_charset(
- &(a->archive), "UTF-8", 0);
- if (pax->sconv_utf8 == NULL)
- ret = ARCHIVE_FATAL;
- else
- ret = ARCHIVE_OK;
- } else
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "pax: invalid charset name");
- return (ret);
- }
-
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
-}
-
-/*
- * Note: This code assumes that 'nanos' has the same sign as 'sec',
- * which implies that sec=-1, nanos=200000000 represents -1.2 seconds
- * and not -0.8 seconds. This is a pretty pedantic point, as we're
- * unlikely to encounter many real files created before Jan 1, 1970,
- * much less ones with timestamps recorded to sub-second resolution.
- */
-static void
-add_pax_attr_time(struct archive_string *as, const char *key,
- int64_t sec, unsigned long nanos)
-{
- int digit, i;
- char *t;
- /*
- * Note that each byte contributes fewer than 3 base-10
- * digits, so this will always be big enough.
- */
- char tmp[1 + 3*sizeof(sec) + 1 + 3*sizeof(nanos)];
-
- tmp[sizeof(tmp) - 1] = 0;
- t = tmp + sizeof(tmp) - 1;
-
- /* Skip trailing zeros in the fractional part. */
- for (digit = 0, i = 10; i > 0 && digit == 0; i--) {
- digit = nanos % 10;
- nanos /= 10;
- }
-
- /* Only format the fraction if it's non-zero. */
- if (i > 0) {
- while (i > 0) {
- *--t = "0123456789"[digit];
- digit = nanos % 10;
- nanos /= 10;
- i--;
- }
- *--t = '.';
- }
- t = format_int(t, sec);
-
- add_pax_attr(as, key, t);
-}
-
-static char *
-format_int(char *t, int64_t i)
-{
- uint64_t ui;
-
- if (i < 0)
- ui = (i == INT64_MIN) ? (uint64_t)(INT64_MAX) + 1 : (uint64_t)(-i);
- else
- ui = i;
-
- do {
- *--t = "0123456789"[ui % 10];
- } while (ui /= 10);
- if (i < 0)
- *--t = '-';
- return (t);
-}
-
-static void
-add_pax_attr_int(struct archive_string *as, const char *key, int64_t value)
-{
- char tmp[1 + 3 * sizeof(value)];
-
- tmp[sizeof(tmp) - 1] = 0;
- add_pax_attr(as, key, format_int(tmp + sizeof(tmp) - 1, value));
-}
-
-/*
- * Add a key/value attribute to the pax header. This function handles
- * the length field and various other syntactic requirements.
- */
-static void
-add_pax_attr(struct archive_string *as, const char *key, const char *value)
-{
- int digits, i, len, next_ten;
- char tmp[1 + 3 * sizeof(int)]; /* < 3 base-10 digits per byte */
-
- /*-
- * PAX attributes have the following layout:
- * <len> <space> <key> <=> <value> <nl>
- */
- len = 1 + (int)strlen(key) + 1 + (int)strlen(value) + 1;
-
- /*
- * The <len> field includes the length of the <len> field, so
- * computing the correct length is tricky. I start by
- * counting the number of base-10 digits in 'len' and
- * computing the next higher power of 10.
- */
- next_ten = 1;
- digits = 0;
- i = len;
- while (i > 0) {
- i = i / 10;
- digits++;
- next_ten = next_ten * 10;
- }
- /*
- * For example, if string without the length field is 99
- * chars, then adding the 2 digit length "99" will force the
- * total length past 100, requiring an extra digit. The next
- * statement adjusts for this effect.
- */
- if (len + digits >= next_ten)
- digits++;
-
- /* Now, we have the right length so we can build the line. */
- tmp[sizeof(tmp) - 1] = 0; /* Null-terminate the work area. */
- archive_strcat(as, format_int(tmp + sizeof(tmp) - 1, len + digits));
- archive_strappend_char(as, ' ');
- archive_strcat(as, key);
- archive_strappend_char(as, '=');
- archive_strcat(as, value);
- archive_strappend_char(as, '\n');
-}
-
-static int
-archive_write_pax_header_xattrs(struct archive_write *a,
- struct pax *pax, struct archive_entry *entry)
-{
- struct archive_string s;
- int i = archive_entry_xattr_reset(entry);
-
- while (i--) {
- const char *name;
- const void *value;
- char *encoded_value;
- char *url_encoded_name = NULL, *encoded_name = NULL;
- size_t size;
- int r;
-
- archive_entry_xattr_next(entry, &name, &value, &size);
- url_encoded_name = url_encode(name);
- if (url_encoded_name != NULL) {
- /* Convert narrow-character to UTF-8. */
- r = archive_strcpy_l(&(pax->l_url_encoded_name),
- url_encoded_name, pax->sconv_utf8);
- free(url_encoded_name); /* Done with this. */
- if (r == 0)
- encoded_name = pax->l_url_encoded_name.s;
- else if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Linkname");
- return (ARCHIVE_FATAL);
- }
- }
-
- encoded_value = base64_encode((const char *)value, size);
-
- if (encoded_name != NULL && encoded_value != NULL) {
- archive_string_init(&s);
- archive_strcpy(&s, "LIBARCHIVE.xattr.");
- archive_strcat(&s, encoded_name);
- add_pax_attr(&(pax->pax_header), s.s, encoded_value);
- archive_string_free(&s);
- }
- free(encoded_value);
- }
- return (ARCHIVE_OK);
-}
-
-static int
-get_entry_hardlink(struct archive_write *a, struct archive_entry *entry,
- const char **name, size_t *length, struct archive_string_conv *sc)
-{
- int r;
-
- r = archive_entry_hardlink_l(entry, name, length, sc);
- if (r != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Linkname");
- return (ARCHIVE_FATAL);
- }
- return (ARCHIVE_WARN);
- }
- return (ARCHIVE_OK);
-}
-
-static int
-get_entry_pathname(struct archive_write *a, struct archive_entry *entry,
- const char **name, size_t *length, struct archive_string_conv *sc)
-{
- int r;
-
- r = archive_entry_pathname_l(entry, name, length, sc);
- if (r != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Pathname");
- return (ARCHIVE_FATAL);
- }
- return (ARCHIVE_WARN);
- }
- return (ARCHIVE_OK);
-}
-
-static int
-get_entry_uname(struct archive_write *a, struct archive_entry *entry,
- const char **name, size_t *length, struct archive_string_conv *sc)
-{
- int r;
-
- r = archive_entry_uname_l(entry, name, length, sc);
- if (r != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Uname");
- return (ARCHIVE_FATAL);
- }
- return (ARCHIVE_WARN);
- }
- return (ARCHIVE_OK);
-}
-
-static int
-get_entry_gname(struct archive_write *a, struct archive_entry *entry,
- const char **name, size_t *length, struct archive_string_conv *sc)
-{
- int r;
-
- r = archive_entry_gname_l(entry, name, length, sc);
- if (r != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Gname");
- return (ARCHIVE_FATAL);
- }
- return (ARCHIVE_WARN);
- }
- return (ARCHIVE_OK);
-}
-
-static int
-get_entry_symlink(struct archive_write *a, struct archive_entry *entry,
- const char **name, size_t *length, struct archive_string_conv *sc)
-{
- int r;
-
- r = archive_entry_symlink_l(entry, name, length, sc);
- if (r != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Linkname");
- return (ARCHIVE_FATAL);
- }
- return (ARCHIVE_WARN);
- }
- return (ARCHIVE_OK);
-}
-
-/*
- * TODO: Consider adding 'comment' and 'charset' fields to
- * archive_entry so that clients can specify them. Also, consider
- * adding generic key/value tags so clients can add arbitrary
- * key/value data.
- *
- * TODO: Break up this 700-line function!!!! Yowza!
- */
-static int
-archive_write_pax_header(struct archive_write *a,
- struct archive_entry *entry_original)
-{
- struct archive_entry *entry_main;
- const char *p;
- const char *suffix;
- int need_extension, r, ret;
- int sparse_count;
- uint64_t sparse_total, real_size;
- struct pax *pax;
- const char *hardlink;
- const char *path = NULL, *linkpath = NULL;
- const char *uname = NULL, *gname = NULL;
- const void *mac_metadata;
- size_t mac_metadata_size;
- struct archive_string_conv *sconv;
- size_t hardlink_length, path_length, linkpath_length;
- size_t uname_length, gname_length;
-
- char paxbuff[512];
- char ustarbuff[512];
- char ustar_entry_name[256];
- char pax_entry_name[256];
- char gnu_sparse_name[256];
- struct archive_string entry_name;
-
- ret = ARCHIVE_OK;
- need_extension = 0;
- pax = (struct pax *)a->format_data;
-
- /* Sanity check. */
- if (archive_entry_pathname(entry_original) == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Can't record entry in tar file without pathname");
- return (ARCHIVE_FAILED);
- }
-
- /*
- * Choose a header encoding.
- */
- if (pax->opt_binary)
- sconv = NULL;/* Binary mode. */
- else {
- /* Header encoding is UTF-8. */
- if (pax->sconv_utf8 == NULL) {
- /* Initialize the string conversion object
- * we must need */
- pax->sconv_utf8 = archive_string_conversion_to_charset(
- &(a->archive), "UTF-8", 1);
- if (pax->sconv_utf8 == NULL)
- /* Couldn't allocate memory */
- return (ARCHIVE_FAILED);
- }
- sconv = pax->sconv_utf8;
- }
-
- r = get_entry_hardlink(a, entry_original, &hardlink,
- &hardlink_length, sconv);
- if (r == ARCHIVE_FATAL)
- return (r);
- else if (r != ARCHIVE_OK) {
- r = get_entry_hardlink(a, entry_original, &hardlink,
- &hardlink_length, NULL);
- if (r == ARCHIVE_FATAL)
- return (r);
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate linkname '%s' to %s", hardlink,
- archive_string_conversion_charset_name(sconv));
- ret = ARCHIVE_WARN;
- sconv = NULL;/* The header charset switches to binary mode. */
- }
-
- /* Make sure this is a type of entry that we can handle here */
- if (hardlink == NULL) {
- switch (archive_entry_filetype(entry_original)) {
- case AE_IFBLK:
- case AE_IFCHR:
- case AE_IFIFO:
- case AE_IFLNK:
- case AE_IFREG:
- break;
- case AE_IFDIR:
- {
- /*
- * Ensure a trailing '/'. Modify the original
- * entry so the client sees the change.
- */
-#if defined(_WIN32) && !defined(__CYGWIN__)
- const wchar_t *wp;
-
- wp = archive_entry_pathname_w(entry_original);
- if (wp != NULL && wp[wcslen(wp) -1] != L'/') {
- struct archive_wstring ws;
-
- archive_string_init(&ws);
- path_length = wcslen(wp);
- if (archive_wstring_ensure(&ws,
- path_length + 2) == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate pax data");
- archive_wstring_free(&ws);
- return(ARCHIVE_FATAL);
- }
- /* Should we keep '\' ? */
- if (wp[path_length -1] == L'\\')
- path_length--;
- archive_wstrncpy(&ws, wp, path_length);
- archive_wstrappend_wchar(&ws, L'/');
- archive_entry_copy_pathname_w(
- entry_original, ws.s);
- archive_wstring_free(&ws);
- p = NULL;
- } else
-#endif
- p = archive_entry_pathname(entry_original);
- /*
- * On Windows, this is a backup operation just in
- * case getting WCS failed. On POSIX, this is a
- * normal operation.
- */
- if (p != NULL && p[strlen(p) - 1] != '/') {
- struct archive_string as;
-
- archive_string_init(&as);
- path_length = strlen(p);
- if (archive_string_ensure(&as,
- path_length + 2) == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate pax data");
- archive_string_free(&as);
- return(ARCHIVE_FATAL);
- }
-#if defined(_WIN32) && !defined(__CYGWIN__)
- /* NOTE: This might break the pathname
- * if the current code page is CP932 and
- * the pathname includes a character '\'
- * as a part of its multibyte pathname. */
- if (p[strlen(p) -1] == '\\')
- path_length--;
- else
-#endif
- archive_strncpy(&as, p, path_length);
- archive_strappend_char(&as, '/');
- archive_entry_copy_pathname(
- entry_original, as.s);
- archive_string_free(&as);
- }
- break;
- }
- case AE_IFSOCK:
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "tar format cannot archive socket");
- return (ARCHIVE_FAILED);
- default:
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "tar format cannot archive this (type=0%lo)",
- (unsigned long)
- archive_entry_filetype(entry_original));
- return (ARCHIVE_FAILED);
- }
- }
-
- /*
- * If Mac OS metadata blob is here, recurse to write that
- * as a separate entry. This is really a pretty poor design:
- * In particular, it doubles the overhead for long filenames.
- * TODO: Help Apple folks design something better and figure
- * out how to transition from this legacy format.
- *
- * Note that this code is present on every platform; clients
- * on non-Mac are unlikely to ever provide this data, but
- * applications that copy entries from one archive to another
- * should not lose data just because the local filesystem
- * can't store it.
- */
- mac_metadata =
- archive_entry_mac_metadata(entry_original, &mac_metadata_size);
- if (mac_metadata != NULL) {
- const char *oname;
- char *name, *bname;
- size_t name_length;
- struct archive_entry *extra = archive_entry_new2(&a->archive);
-
- oname = archive_entry_pathname(entry_original);
- name_length = strlen(oname);
- name = malloc(name_length + 3);
- if (name == NULL || extra == NULL) {
- /* XXX error message */
- archive_entry_free(extra);
- free(name);
- return (ARCHIVE_FAILED);
- }
- strcpy(name, oname);
- /* Find last '/'; strip trailing '/' characters */
- bname = strrchr(name, '/');
- while (bname != NULL && bname[1] == '\0') {
- *bname = '\0';
- bname = strrchr(name, '/');
- }
- if (bname == NULL) {
- memmove(name + 2, name, name_length + 1);
- memmove(name, "._", 2);
- } else {
- bname += 1;
- memmove(bname + 2, bname, strlen(bname) + 1);
- memmove(bname, "._", 2);
- }
- archive_entry_copy_pathname(extra, name);
- free(name);
-
- archive_entry_set_size(extra, mac_metadata_size);
- archive_entry_set_filetype(extra, AE_IFREG);
- archive_entry_set_perm(extra,
- archive_entry_perm(entry_original));
- archive_entry_set_mtime(extra,
- archive_entry_mtime(entry_original),
- archive_entry_mtime_nsec(entry_original));
- archive_entry_set_gid(extra,
- archive_entry_gid(entry_original));
- archive_entry_set_gname(extra,
- archive_entry_gname(entry_original));
- archive_entry_set_uid(extra,
- archive_entry_uid(entry_original));
- archive_entry_set_uname(extra,
- archive_entry_uname(entry_original));
-
- /* Recurse to write the special copyfile entry. */
- r = archive_write_pax_header(a, extra);
- archive_entry_free(extra);
- if (r < ARCHIVE_WARN)
- return (r);
- if (r < ret)
- ret = r;
- r = (int)archive_write_pax_data(a, mac_metadata,
- mac_metadata_size);
- if (r < ARCHIVE_WARN)
- return (r);
- if (r < ret)
- ret = r;
- r = archive_write_pax_finish_entry(a);
- if (r < ARCHIVE_WARN)
- return (r);
- if (r < ret)
- ret = r;
- }
-
- /* Copy entry so we can modify it as needed. */
-#if defined(_WIN32) && !defined(__CYGWIN__)
- /* Make sure the path separators in pahtname, hardlink and symlink
- * are all slash '/', not the Windows path separator '\'. */
- entry_main = __la_win_entry_in_posix_pathseparator(entry_original);
- if (entry_main == entry_original)
- entry_main = archive_entry_clone(entry_original);
-#else
- entry_main = archive_entry_clone(entry_original);
-#endif
- if (entry_main == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate pax data");
- return(ARCHIVE_FATAL);
- }
- archive_string_empty(&(pax->pax_header)); /* Blank our work area. */
- archive_string_empty(&(pax->sparse_map));
- sparse_total = 0;
- sparse_list_clear(pax);
-
- if (hardlink == NULL &&
- archive_entry_filetype(entry_main) == AE_IFREG)
- sparse_count = archive_entry_sparse_reset(entry_main);
- else
- sparse_count = 0;
- if (sparse_count) {
- int64_t offset, length, last_offset = 0;
- /* Get the last entry of sparse block. */
- while (archive_entry_sparse_next(
- entry_main, &offset, &length) == ARCHIVE_OK)
- last_offset = offset + length;
-
- /* If the last sparse block does not reach the end of file,
- * We have to add a empty sparse block as the last entry to
- * manage storing file data. */
- if (last_offset < archive_entry_size(entry_main))
- archive_entry_sparse_add_entry(entry_main,
- archive_entry_size(entry_main), 0);
- sparse_count = archive_entry_sparse_reset(entry_main);
- }
-
- /*
- * First, check the name fields and see if any of them
- * require binary coding. If any of them does, then all of
- * them do.
- */
- r = get_entry_pathname(a, entry_main, &path, &path_length, sconv);
- if (r == ARCHIVE_FATAL)
- return (r);
- else if (r != ARCHIVE_OK) {
- r = get_entry_pathname(a, entry_main, &path,
- &path_length, NULL);
- if (r == ARCHIVE_FATAL)
- return (r);
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate pathname '%s' to %s", path,
- archive_string_conversion_charset_name(sconv));
- ret = ARCHIVE_WARN;
- sconv = NULL;/* The header charset switches to binary mode. */
- }
- r = get_entry_uname(a, entry_main, &uname, &uname_length, sconv);
- if (r == ARCHIVE_FATAL)
- return (r);
- else if (r != ARCHIVE_OK) {
- r = get_entry_uname(a, entry_main, &uname, &uname_length, NULL);
- if (r == ARCHIVE_FATAL)
- return (r);
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate uname '%s' to %s", uname,
- archive_string_conversion_charset_name(sconv));
- ret = ARCHIVE_WARN;
- sconv = NULL;/* The header charset switches to binary mode. */
- }
- r = get_entry_gname(a, entry_main, &gname, &gname_length, sconv);
- if (r == ARCHIVE_FATAL)
- return (r);
- else if (r != ARCHIVE_OK) {
- r = get_entry_gname(a, entry_main, &gname, &gname_length, NULL);
- if (r == ARCHIVE_FATAL)
- return (r);
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate gname '%s' to %s", gname,
- archive_string_conversion_charset_name(sconv));
- ret = ARCHIVE_WARN;
- sconv = NULL;/* The header charset switches to binary mode. */
- }
- linkpath = hardlink;
- linkpath_length = hardlink_length;
- if (linkpath == NULL) {
- r = get_entry_symlink(a, entry_main, &linkpath,
- &linkpath_length, sconv);
- if (r == ARCHIVE_FATAL)
- return (r);
- else if (r != ARCHIVE_OK) {
- r = get_entry_symlink(a, entry_main, &linkpath,
- &linkpath_length, NULL);
- if (r == ARCHIVE_FATAL)
- return (r);
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate linkname '%s' to %s", linkpath,
- archive_string_conversion_charset_name(sconv));
- ret = ARCHIVE_WARN;
- sconv = NULL;
- }
- }
-
- /* If any string conversions failed, get all attributes
- * in binary-mode. */
- if (sconv == NULL && !pax->opt_binary) {
- if (hardlink != NULL) {
- r = get_entry_hardlink(a, entry_main, &hardlink,
- &hardlink_length, NULL);
- if (r == ARCHIVE_FATAL)
- return (r);
- linkpath = hardlink;
- linkpath_length = hardlink_length;
- }
- r = get_entry_pathname(a, entry_main, &path,
- &path_length, NULL);
- if (r == ARCHIVE_FATAL)
- return (r);
- r = get_entry_uname(a, entry_main, &uname, &uname_length, NULL);
- if (r == ARCHIVE_FATAL)
- return (r);
- r = get_entry_gname(a, entry_main, &gname, &gname_length, NULL);
- if (r == ARCHIVE_FATAL)
- return (r);
- }
-
- /* Store the header encoding first, to be nice to readers. */
- if (sconv == NULL)
- add_pax_attr(&(pax->pax_header), "hdrcharset", "BINARY");
-
-
- /*
- * If name is too long, or has non-ASCII characters, add
- * 'path' to pax extended attrs. (Note that an unconvertible
- * name must have non-ASCII characters.)
- */
- if (has_non_ASCII(path)) {
- /* We have non-ASCII characters. */
- add_pax_attr(&(pax->pax_header), "path", path);
- archive_entry_set_pathname(entry_main,
- build_ustar_entry_name(ustar_entry_name,
- path, path_length, NULL));
- need_extension = 1;
- } else {
- /* We have an all-ASCII path; we'd like to just store
- * it in the ustar header if it will fit. Yes, this
- * duplicates some of the logic in
- * archive_write_set_format_ustar.c
- */
- if (path_length <= 100) {
- /* Fits in the old 100-char tar name field. */
- } else {
- /* Find largest suffix that will fit. */
- /* Note: strlen() > 100, so strlen() - 100 - 1 >= 0 */
- suffix = strchr(path + path_length - 100 - 1, '/');
- /* Don't attempt an empty prefix. */
- if (suffix == path)
- suffix = strchr(suffix + 1, '/');
- /* We can put it in the ustar header if it's
- * all ASCII and it's either <= 100 characters
- * or can be split at a '/' into a prefix <=
- * 155 chars and a suffix <= 100 chars. (Note
- * the strchr() above will return NULL exactly
- * when the path can't be split.)
- */
- if (suffix == NULL /* Suffix > 100 chars. */
- || suffix[1] == '\0' /* empty suffix */
- || suffix - path > 155) /* Prefix > 155 chars */
- {
- add_pax_attr(&(pax->pax_header), "path", path);
- archive_entry_set_pathname(entry_main,
- build_ustar_entry_name(ustar_entry_name,
- path, path_length, NULL));
- need_extension = 1;
- }
- }
- }
-
- if (linkpath != NULL) {
- /* If link name is too long or has non-ASCII characters, add
- * 'linkpath' to pax extended attrs. */
- if (linkpath_length > 100 || has_non_ASCII(linkpath)) {
- add_pax_attr(&(pax->pax_header), "linkpath", linkpath);
- if (linkpath_length > 100) {
- if (hardlink != NULL)
- archive_entry_set_hardlink(entry_main,
- "././@LongHardLink");
- else
- archive_entry_set_symlink(entry_main,
- "././@LongSymLink");
- }
- need_extension = 1;
- }
- }
- /* Save a pathname since it will be renamed if `entry_main` has
- * sparse blocks. */
- archive_string_init(&entry_name);
- archive_strcpy(&entry_name, archive_entry_pathname(entry_main));
-
- /* If file size is too large, add 'size' to pax extended attrs. */
- if (archive_entry_size(entry_main) >= (((int64_t)1) << 33)) {
- add_pax_attr_int(&(pax->pax_header), "size",
- archive_entry_size(entry_main));
- need_extension = 1;
- }
-
- /* If numeric GID is too large, add 'gid' to pax extended attrs. */
- if ((unsigned int)archive_entry_gid(entry_main) >= (1 << 18)) {
- add_pax_attr_int(&(pax->pax_header), "gid",
- archive_entry_gid(entry_main));
- need_extension = 1;
- }
-
- /* If group name is too large or has non-ASCII characters, add
- * 'gname' to pax extended attrs. */
- if (gname != NULL) {
- if (gname_length > 31 || has_non_ASCII(gname)) {
- add_pax_attr(&(pax->pax_header), "gname", gname);
- need_extension = 1;
- }
- }
-
- /* If numeric UID is too large, add 'uid' to pax extended attrs. */
- if ((unsigned int)archive_entry_uid(entry_main) >= (1 << 18)) {
- add_pax_attr_int(&(pax->pax_header), "uid",
- archive_entry_uid(entry_main));
- need_extension = 1;
- }
-
- /* Add 'uname' to pax extended attrs if necessary. */
- if (uname != NULL) {
- if (uname_length > 31 || has_non_ASCII(uname)) {
- add_pax_attr(&(pax->pax_header), "uname", uname);
- need_extension = 1;
- }
- }
-
- /*
- * POSIX/SUSv3 doesn't provide a standard key for large device
- * numbers. I use the same keys here that Joerg Schilling
- * used for 'star.' (Which, somewhat confusingly, are called
- * "devXXX" even though they code "rdev" values.) No doubt,
- * other implementations use other keys. Note that there's no
- * reason we can't write the same information into a number of
- * different keys.
- *
- * Of course, this is only needed for block or char device entries.
- */
- if (archive_entry_filetype(entry_main) == AE_IFBLK
- || archive_entry_filetype(entry_main) == AE_IFCHR) {
- /*
- * If rdevmajor is too large, add 'SCHILY.devmajor' to
- * extended attributes.
- */
- int rdevmajor, rdevminor;
- rdevmajor = archive_entry_rdevmajor(entry_main);
- rdevminor = archive_entry_rdevminor(entry_main);
- if (rdevmajor >= (1 << 18)) {
- add_pax_attr_int(&(pax->pax_header), "SCHILY.devmajor",
- rdevmajor);
- /*
- * Non-strict formatting below means we don't
- * have to truncate here. Not truncating improves
- * the chance that some more modern tar archivers
- * (such as GNU tar 1.13) can restore the full
- * value even if they don't understand the pax
- * extended attributes. See my rant below about
- * file size fields for additional details.
- */
- /* archive_entry_set_rdevmajor(entry_main,
- rdevmajor & ((1 << 18) - 1)); */
- need_extension = 1;
- }
-
- /*
- * If devminor is too large, add 'SCHILY.devminor' to
- * extended attributes.
- */
- if (rdevminor >= (1 << 18)) {
- add_pax_attr_int(&(pax->pax_header), "SCHILY.devminor",
- rdevminor);
- /* Truncation is not necessary here, either. */
- /* archive_entry_set_rdevminor(entry_main,
- rdevminor & ((1 << 18) - 1)); */
- need_extension = 1;
- }
- }
-
- /*
- * Technically, the mtime field in the ustar header can
- * support 33 bits, but many platforms use signed 32-bit time
- * values. The cutoff of 0x7fffffff here is a compromise.
- * Yes, this check is duplicated just below; this helps to
- * avoid writing an mtime attribute just to handle a
- * high-resolution timestamp in "restricted pax" mode.
- */
- if (!need_extension &&
- ((archive_entry_mtime(entry_main) < 0)
- || (archive_entry_mtime(entry_main) >= 0x7fffffff)))
- need_extension = 1;
-
- /* I use a star-compatible file flag attribute. */
- p = archive_entry_fflags_text(entry_main);
- if (!need_extension && p != NULL && *p != '\0')
- need_extension = 1;
-
- /* If there are non-trivial ACL entries, we need an extension. */
- if (!need_extension && archive_entry_acl_count(entry_original,
- ARCHIVE_ENTRY_ACL_TYPE_ACCESS) > 0)
- need_extension = 1;
-
- /* If there are non-trivial ACL entries, we need an extension. */
- if (!need_extension && archive_entry_acl_count(entry_original,
- ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) > 0)
- need_extension = 1;
-
- /* If there are extended attributes, we need an extension */
- if (!need_extension && archive_entry_xattr_count(entry_original) > 0)
- need_extension = 1;
-
- /* If there are sparse info, we need an extension */
- if (!need_extension && sparse_count > 0)
- need_extension = 1;
-
- /*
- * The following items are handled differently in "pax
- * restricted" format. In particular, in "pax restricted"
- * format they won't be added unless need_extension is
- * already set (we're already generating an extended header, so
- * may as well include these).
- */
- if (a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_RESTRICTED ||
- need_extension) {
-
- if (archive_entry_mtime(entry_main) < 0 ||
- archive_entry_mtime(entry_main) >= 0x7fffffff ||
- archive_entry_mtime_nsec(entry_main) != 0)
- add_pax_attr_time(&(pax->pax_header), "mtime",
- archive_entry_mtime(entry_main),
- archive_entry_mtime_nsec(entry_main));
-
- if (archive_entry_ctime(entry_main) != 0 ||
- archive_entry_ctime_nsec(entry_main) != 0)
- add_pax_attr_time(&(pax->pax_header), "ctime",
- archive_entry_ctime(entry_main),
- archive_entry_ctime_nsec(entry_main));
-
- if (archive_entry_atime(entry_main) != 0 ||
- archive_entry_atime_nsec(entry_main) != 0)
- add_pax_attr_time(&(pax->pax_header), "atime",
- archive_entry_atime(entry_main),
- archive_entry_atime_nsec(entry_main));
-
- /* Store birth/creationtime only if it's earlier than mtime */
- if (archive_entry_birthtime_is_set(entry_main) &&
- archive_entry_birthtime(entry_main)
- < archive_entry_mtime(entry_main))
- add_pax_attr_time(&(pax->pax_header),
- "LIBARCHIVE.creationtime",
- archive_entry_birthtime(entry_main),
- archive_entry_birthtime_nsec(entry_main));
-
- /* I use a star-compatible file flag attribute. */
- p = archive_entry_fflags_text(entry_main);
- if (p != NULL && *p != '\0')
- add_pax_attr(&(pax->pax_header), "SCHILY.fflags", p);
-
- /* I use star-compatible ACL attributes. */
- r = archive_entry_acl_text_l(entry_original,
- ARCHIVE_ENTRY_ACL_TYPE_ACCESS |
- ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID,
- &p, NULL, pax->sconv_utf8);
- if (r != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for "
- "ACL.access");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate ACL.access to UTF-8");
- ret = ARCHIVE_WARN;
- } else if (p != NULL && *p != '\0') {
- add_pax_attr(&(pax->pax_header),
- "SCHILY.acl.access", p);
- }
- r = archive_entry_acl_text_l(entry_original,
- ARCHIVE_ENTRY_ACL_TYPE_DEFAULT |
- ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID,
- &p, NULL, pax->sconv_utf8);
- if (r != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for "
- "ACL.default");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate ACL.default to UTF-8");
- ret = ARCHIVE_WARN;
- } else if (p != NULL && *p != '\0') {
- add_pax_attr(&(pax->pax_header),
- "SCHILY.acl.default", p);
- }
-
- /* We use GNU-tar-compatible sparse attributes. */
- if (sparse_count > 0) {
- int64_t soffset, slength;
-
- add_pax_attr_int(&(pax->pax_header),
- "GNU.sparse.major", 1);
- add_pax_attr_int(&(pax->pax_header),
- "GNU.sparse.minor", 0);
- add_pax_attr(&(pax->pax_header),
- "GNU.sparse.name", entry_name.s);
- add_pax_attr_int(&(pax->pax_header),
- "GNU.sparse.realsize",
- archive_entry_size(entry_main));
-
- /* Rename the file name which will be used for
- * ustar header to a special name, which GNU
- * PAX Format 1.0 requires */
- archive_entry_set_pathname(entry_main,
- build_gnu_sparse_name(gnu_sparse_name,
- entry_name.s));
-
- /*
- * - Make a sparse map, which will precede a file data.
- * - Get the total size of available data of sparse.
- */
- archive_string_sprintf(&(pax->sparse_map), "%d\n",
- sparse_count);
- while (archive_entry_sparse_next(entry_main,
- &soffset, &slength) == ARCHIVE_OK) {
- archive_string_sprintf(&(pax->sparse_map),
- "%jd\n%jd\n",
- (intmax_t)soffset,
- (intmax_t)slength);
- sparse_total += slength;
- if (sparse_list_add(pax, soffset, slength)
- != ARCHIVE_OK) {
- archive_set_error(&a->archive,
- ENOMEM,
- "Can't allocate memory");
- archive_entry_free(entry_main);
- archive_string_free(&entry_name);
- return (ARCHIVE_FATAL);
- }
- }
- }
-
- /* Store extended attributes */
- if (archive_write_pax_header_xattrs(a, pax, entry_original)
- == ARCHIVE_FATAL) {
- archive_entry_free(entry_main);
- archive_string_free(&entry_name);
- return (ARCHIVE_FATAL);
- }
- }
-
- /* Only regular files have data. */
- if (archive_entry_filetype(entry_main) != AE_IFREG)
- archive_entry_set_size(entry_main, 0);
-
- /*
- * Pax-restricted does not store data for hardlinks, in order
- * to improve compatibility with ustar.
- */
- if (a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE &&
- hardlink != NULL)
- archive_entry_set_size(entry_main, 0);
-
- /*
- * XXX Full pax interchange format does permit a hardlink
- * entry to have data associated with it. I'm not supporting
- * that here because the client expects me to tell them whether
- * or not this format expects data for hardlinks. If I
- * don't check here, then every pax archive will end up with
- * duplicated data for hardlinks. Someday, there may be
- * need to select this behavior, in which case the following
- * will need to be revisited. XXX
- */
- if (hardlink != NULL)
- archive_entry_set_size(entry_main, 0);
-
- /* Save a real file size. */
- real_size = archive_entry_size(entry_main);
- /*
- * Overwrite a file size by the total size of sparse blocks and
- * the size of sparse map info. That file size is the length of
- * the data, which we will exactly store into an archive file.
- */
- if (archive_strlen(&(pax->sparse_map))) {
- size_t mapsize = archive_strlen(&(pax->sparse_map));
- pax->sparse_map_padding = 0x1ff & (-(ssize_t)mapsize);
- archive_entry_set_size(entry_main,
- mapsize + pax->sparse_map_padding + sparse_total);
- }
-
- /* Format 'ustar' header for main entry.
- *
- * The trouble with file size: If the reader can't understand
- * the file size, they may not be able to locate the next
- * entry and the rest of the archive is toast. Pax-compliant
- * readers are supposed to ignore the file size in the main
- * header, so the question becomes how to maximize portability
- * for readers that don't support pax attribute extensions.
- * For maximum compatibility, I permit numeric extensions in
- * the main header so that the file size stored will always be
- * correct, even if it's in a format that only some
- * implementations understand. The technique used here is:
- *
- * a) If possible, follow the standard exactly. This handles
- * files up to 8 gigabytes minus 1.
- *
- * b) If that fails, try octal but omit the field terminator.
- * That handles files up to 64 gigabytes minus 1.
- *
- * c) Otherwise, use base-256 extensions. That handles files
- * up to 2^63 in this implementation, with the potential to
- * go up to 2^94. That should hold us for a while. ;-)
- *
- * The non-strict formatter uses similar logic for other
- * numeric fields, though they're less critical.
- */
- if (__archive_write_format_header_ustar(a, ustarbuff, entry_main, -1, 0,
- NULL) == ARCHIVE_FATAL)
- return (ARCHIVE_FATAL);
-
- /* If we built any extended attributes, write that entry first. */
- if (archive_strlen(&(pax->pax_header)) > 0) {
- struct archive_entry *pax_attr_entry;
- time_t s;
- int64_t uid, gid;
- int mode;
-
- pax_attr_entry = archive_entry_new2(&a->archive);
- p = entry_name.s;
- archive_entry_set_pathname(pax_attr_entry,
- build_pax_attribute_name(pax_entry_name, p));
- archive_entry_set_size(pax_attr_entry,
- archive_strlen(&(pax->pax_header)));
- /* Copy uid/gid (but clip to ustar limits). */
- uid = archive_entry_uid(entry_main);
- if (uid >= 1 << 18)
- uid = (1 << 18) - 1;
- archive_entry_set_uid(pax_attr_entry, uid);
- gid = archive_entry_gid(entry_main);
- if (gid >= 1 << 18)
- gid = (1 << 18) - 1;
- archive_entry_set_gid(pax_attr_entry, gid);
- /* Copy mode over (but not setuid/setgid bits) */
- mode = archive_entry_mode(entry_main);
-#ifdef S_ISUID
- mode &= ~S_ISUID;
-#endif
-#ifdef S_ISGID
- mode &= ~S_ISGID;
-#endif
-#ifdef S_ISVTX
- mode &= ~S_ISVTX;
-#endif
- archive_entry_set_mode(pax_attr_entry, mode);
-
- /* Copy uname/gname. */
- archive_entry_set_uname(pax_attr_entry,
- archive_entry_uname(entry_main));
- archive_entry_set_gname(pax_attr_entry,
- archive_entry_gname(entry_main));
-
- /* Copy mtime, but clip to ustar limits. */
- s = archive_entry_mtime(entry_main);
- if (s < 0) { s = 0; }
- if (s >= 0x7fffffff) { s = 0x7fffffff; }
- archive_entry_set_mtime(pax_attr_entry, s, 0);
-
- /* Standard ustar doesn't support atime. */
- archive_entry_set_atime(pax_attr_entry, 0, 0);
-
- /* Standard ustar doesn't support ctime. */
- archive_entry_set_ctime(pax_attr_entry, 0, 0);
-
- r = __archive_write_format_header_ustar(a, paxbuff,
- pax_attr_entry, 'x', 1, NULL);
-
- archive_entry_free(pax_attr_entry);
-
- /* Note that the 'x' header shouldn't ever fail to format */
- if (r < ARCHIVE_WARN) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "archive_write_pax_header: "
- "'x' header failed?! This can't happen.\n");
- return (ARCHIVE_FATAL);
- } else if (r < ret)
- ret = r;
- r = __archive_write_output(a, paxbuff, 512);
- if (r != ARCHIVE_OK) {
- sparse_list_clear(pax);
- pax->entry_bytes_remaining = 0;
- pax->entry_padding = 0;
- return (ARCHIVE_FATAL);
- }
-
- pax->entry_bytes_remaining = archive_strlen(&(pax->pax_header));
- pax->entry_padding =
- 0x1ff & (-(int64_t)pax->entry_bytes_remaining);
-
- r = __archive_write_output(a, pax->pax_header.s,
- archive_strlen(&(pax->pax_header)));
- if (r != ARCHIVE_OK) {
- /* If a write fails, we're pretty much toast. */
- return (ARCHIVE_FATAL);
- }
- /* Pad out the end of the entry. */
- r = __archive_write_nulls(a, (size_t)pax->entry_padding);
- if (r != ARCHIVE_OK) {
- /* If a write fails, we're pretty much toast. */
- return (ARCHIVE_FATAL);
- }
- pax->entry_bytes_remaining = pax->entry_padding = 0;
- }
-
- /* Write the header for main entry. */
- r = __archive_write_output(a, ustarbuff, 512);
- if (r != ARCHIVE_OK)
- return (r);
-
- /*
- * Inform the client of the on-disk size we're using, so
- * they can avoid unnecessarily writing a body for something
- * that we're just going to ignore.
- */
- archive_entry_set_size(entry_original, real_size);
- if (pax->sparse_list == NULL && real_size > 0) {
- /* This is not a sparse file but we handle its data as
- * a sparse block. */
- sparse_list_add(pax, 0, real_size);
- sparse_total = real_size;
- }
- pax->entry_padding = 0x1ff & (-(int64_t)sparse_total);
- archive_entry_free(entry_main);
- archive_string_free(&entry_name);
-
- return (ret);
-}
-
-/*
- * We need a valid name for the regular 'ustar' entry. This routine
- * tries to hack something more-or-less reasonable.
- *
- * The approach here tries to preserve leading dir names. We do so by
- * working with four sections:
- * 1) "prefix" directory names,
- * 2) "suffix" directory names,
- * 3) inserted dir name (optional),
- * 4) filename.
- *
- * These sections must satisfy the following requirements:
- * * Parts 1 & 2 together form an initial portion of the dir name.
- * * Part 3 is specified by the caller. (It should not contain a leading
- * or trailing '/'.)
- * * Part 4 forms an initial portion of the base filename.
- * * The filename must be <= 99 chars to fit the ustar 'name' field.
- * * Parts 2, 3, 4 together must be <= 99 chars to fit the ustar 'name' fld.
- * * Part 1 must be <= 155 chars to fit the ustar 'prefix' field.
- * * If the original name ends in a '/', the new name must also end in a '/'
- * * Trailing '/.' sequences may be stripped.
- *
- * Note: Recall that the ustar format does not store the '/' separating
- * parts 1 & 2, but does store the '/' separating parts 2 & 3.
- */
-static char *
-build_ustar_entry_name(char *dest, const char *src, size_t src_length,
- const char *insert)
-{
- const char *prefix, *prefix_end;
- const char *suffix, *suffix_end;
- const char *filename, *filename_end;
- char *p;
- int need_slash = 0; /* Was there a trailing slash? */
- size_t suffix_length = 99;
- size_t insert_length;
-
- /* Length of additional dir element to be added. */
- if (insert == NULL)
- insert_length = 0;
- else
- /* +2 here allows for '/' before and after the insert. */
- insert_length = strlen(insert) + 2;
-
- /* Step 0: Quick bailout in a common case. */
- if (src_length < 100 && insert == NULL) {
- strncpy(dest, src, src_length);
- dest[src_length] = '\0';
- return (dest);
- }
-
- /* Step 1: Locate filename and enforce the length restriction. */
- filename_end = src + src_length;
- /* Remove trailing '/' chars and '/.' pairs. */
- for (;;) {
- if (filename_end > src && filename_end[-1] == '/') {
- filename_end --;
- need_slash = 1; /* Remember to restore trailing '/'. */
- continue;
- }
- if (filename_end > src + 1 && filename_end[-1] == '.'
- && filename_end[-2] == '/') {
- filename_end -= 2;
- need_slash = 1; /* "foo/." will become "foo/" */
- continue;
- }
- break;
- }
- if (need_slash)
- suffix_length--;
- /* Find start of filename. */
- filename = filename_end - 1;
- while ((filename > src) && (*filename != '/'))
- filename --;
- if ((*filename == '/') && (filename < filename_end - 1))
- filename ++;
- /* Adjust filename_end so that filename + insert fits in 99 chars. */
- suffix_length -= insert_length;
- if (filename_end > filename + suffix_length)
- filename_end = filename + suffix_length;
- /* Calculate max size for "suffix" section (#3 above). */
- suffix_length -= filename_end - filename;
-
- /* Step 2: Locate the "prefix" section of the dirname, including
- * trailing '/'. */
- prefix = src;
- prefix_end = prefix + 155;
- if (prefix_end > filename)
- prefix_end = filename;
- while (prefix_end > prefix && *prefix_end != '/')
- prefix_end--;
- if ((prefix_end < filename) && (*prefix_end == '/'))
- prefix_end++;
-
- /* Step 3: Locate the "suffix" section of the dirname,
- * including trailing '/'. */
- suffix = prefix_end;
- suffix_end = suffix + suffix_length; /* Enforce limit. */
- if (suffix_end > filename)
- suffix_end = filename;
- if (suffix_end < suffix)
- suffix_end = suffix;
- while (suffix_end > suffix && *suffix_end != '/')
- suffix_end--;
- if ((suffix_end < filename) && (*suffix_end == '/'))
- suffix_end++;
-
- /* Step 4: Build the new name. */
- /* The OpenBSD strlcpy function is safer, but less portable. */
- /* Rather than maintain two versions, just use the strncpy version. */
- p = dest;
- if (prefix_end > prefix) {
- strncpy(p, prefix, prefix_end - prefix);
- p += prefix_end - prefix;
- }
- if (suffix_end > suffix) {
- strncpy(p, suffix, suffix_end - suffix);
- p += suffix_end - suffix;
- }
- if (insert != NULL) {
- /* Note: assume insert does not have leading or trailing '/' */
- strcpy(p, insert);
- p += strlen(insert);
- *p++ = '/';
- }
- strncpy(p, filename, filename_end - filename);
- p += filename_end - filename;
- if (need_slash)
- *p++ = '/';
- *p = '\0';
-
- return (dest);
-}
-
-/*
- * The ustar header for the pax extended attributes must have a
- * reasonable name: SUSv3 requires 'dirname'/PaxHeader.'pid'/'filename'
- * where 'pid' is the PID of the archiving process. Unfortunately,
- * that makes testing a pain since the output varies for each run,
- * so I'm sticking with the simpler 'dirname'/PaxHeader/'filename'
- * for now. (Someday, I'll make this settable. Then I can use the
- * SUS recommendation as default and test harnesses can override it
- * to get predictable results.)
- *
- * Joerg Schilling has argued that this is unnecessary because, in
- * practice, if the pax extended attributes get extracted as regular
- * files, no one is going to bother reading those attributes to
- * manually restore them. Based on this, 'star' uses
- * /tmp/PaxHeader/'basename' as the ustar header name. This is a
- * tempting argument, in part because it's simpler than the SUSv3
- * recommendation, but I'm not entirely convinced. I'm also
- * uncomfortable with the fact that "/tmp" is a Unix-ism.
- *
- * The following routine leverages build_ustar_entry_name() above and
- * so is simpler than you might think. It just needs to provide the
- * additional path element and handle a few pathological cases).
- */
-static char *
-build_pax_attribute_name(char *dest, const char *src)
-{
- char buff[64];
- const char *p;
-
- /* Handle the null filename case. */
- if (src == NULL || *src == '\0') {
- strcpy(dest, "PaxHeader/blank");
- return (dest);
- }
-
- /* Prune final '/' and other unwanted final elements. */
- p = src + strlen(src);
- for (;;) {
- /* Ends in "/", remove the '/' */
- if (p > src && p[-1] == '/') {
- --p;
- continue;
- }
- /* Ends in "/.", remove the '.' */
- if (p > src + 1 && p[-1] == '.'
- && p[-2] == '/') {
- --p;
- continue;
- }
- break;
- }
-
- /* Pathological case: After above, there was nothing left.
- * This includes "/." "/./." "/.//./." etc. */
- if (p == src) {
- strcpy(dest, "/PaxHeader/rootdir");
- return (dest);
- }
-
- /* Convert unadorned "." into a suitable filename. */
- if (*src == '.' && p == src + 1) {
- strcpy(dest, "PaxHeader/currentdir");
- return (dest);
- }
-
- /*
- * TODO: Push this string into the 'pax' structure to avoid
- * recomputing it every time. That will also open the door
- * to having clients override it.
- */
-#if HAVE_GETPID && 0 /* Disable this for now; see above comment. */
- sprintf(buff, "PaxHeader.%d", getpid());
-#else
- /* If the platform can't fetch the pid, don't include it. */
- strcpy(buff, "PaxHeader");
-#endif
- /* General case: build a ustar-compatible name adding
- * "/PaxHeader/". */
- build_ustar_entry_name(dest, src, p - src, buff);
-
- return (dest);
-}
-
-/*
- * GNU PAX Format 1.0 requires the special name, which pattern is:
- * <dir>/GNUSparseFile.<pid>/<original file name>
- *
- * This function is used for only Sparse file, a file type of which
- * is regular file.
- */
-static char *
-build_gnu_sparse_name(char *dest, const char *src)
-{
- char buff[64];
- const char *p;
-
- /* Handle the null filename case. */
- if (src == NULL || *src == '\0') {
- strcpy(dest, "GNUSparseFile/blank");
- return (dest);
- }
-
- /* Prune final '/' and other unwanted final elements. */
- p = src + strlen(src);
- for (;;) {
- /* Ends in "/", remove the '/' */
- if (p > src && p[-1] == '/') {
- --p;
- continue;
- }
- /* Ends in "/.", remove the '.' */
- if (p > src + 1 && p[-1] == '.'
- && p[-2] == '/') {
- --p;
- continue;
- }
- break;
- }
-
-#if HAVE_GETPID && 0 /* Disable this as pax attribute name. */
- sprintf(buff, "GNUSparseFile.%d", getpid());
-#else
- /* If the platform can't fetch the pid, don't include it. */
- strcpy(buff, "GNUSparseFile");
-#endif
- /* General case: build a ustar-compatible name adding
- * "/GNUSparseFile/". */
- build_ustar_entry_name(dest, src, p - src, buff);
-
- return (dest);
-}
-
-/* Write two null blocks for the end of archive */
-static int
-archive_write_pax_close(struct archive_write *a)
-{
- return (__archive_write_nulls(a, 512 * 2));
-}
-
-static int
-archive_write_pax_free(struct archive_write *a)
-{
- struct pax *pax;
-
- pax = (struct pax *)a->format_data;
- if (pax == NULL)
- return (ARCHIVE_OK);
-
- archive_string_free(&pax->pax_header);
- archive_string_free(&pax->sparse_map);
- archive_string_free(&pax->l_url_encoded_name);
- sparse_list_clear(pax);
- free(pax);
- a->format_data = NULL;
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_pax_finish_entry(struct archive_write *a)
-{
- struct pax *pax;
- uint64_t remaining;
- int ret;
-
- pax = (struct pax *)a->format_data;
- remaining = pax->entry_bytes_remaining;
- if (remaining == 0) {
- while (pax->sparse_list) {
- struct sparse_block *sb;
- if (!pax->sparse_list->is_hole)
- remaining += pax->sparse_list->remaining;
- sb = pax->sparse_list->next;
- free(pax->sparse_list);
- pax->sparse_list = sb;
- }
- }
- ret = __archive_write_nulls(a, (size_t)(remaining + pax->entry_padding));
- pax->entry_bytes_remaining = pax->entry_padding = 0;
- return (ret);
-}
-
-static ssize_t
-archive_write_pax_data(struct archive_write *a, const void *buff, size_t s)
-{
- struct pax *pax;
- size_t ws;
- size_t total;
- int ret;
-
- pax = (struct pax *)a->format_data;
-
- /*
- * According to GNU PAX format 1.0, write a sparse map
- * before the body.
- */
- if (archive_strlen(&(pax->sparse_map))) {
- ret = __archive_write_output(a, pax->sparse_map.s,
- archive_strlen(&(pax->sparse_map)));
- if (ret != ARCHIVE_OK)
- return (ret);
- ret = __archive_write_nulls(a, pax->sparse_map_padding);
- if (ret != ARCHIVE_OK)
- return (ret);
- archive_string_empty(&(pax->sparse_map));
- }
-
- total = 0;
- while (total < s) {
- const unsigned char *p;
-
- while (pax->sparse_list != NULL &&
- pax->sparse_list->remaining == 0) {
- struct sparse_block *sb = pax->sparse_list->next;
- free(pax->sparse_list);
- pax->sparse_list = sb;
- }
-
- if (pax->sparse_list == NULL)
- return (total);
-
- p = ((const unsigned char *)buff) + total;
- ws = s - total;
- if (ws > pax->sparse_list->remaining)
- ws = (size_t)pax->sparse_list->remaining;
-
- if (pax->sparse_list->is_hole) {
- /* Current block is hole thus we do not write
- * the body. */
- pax->sparse_list->remaining -= ws;
- total += ws;
- continue;
- }
-
- ret = __archive_write_output(a, p, ws);
- pax->sparse_list->remaining -= ws;
- total += ws;
- if (ret != ARCHIVE_OK)
- return (ret);
- }
- return (total);
-}
-
-static int
-has_non_ASCII(const char *_p)
-{
- const unsigned char *p = (const unsigned char *)_p;
-
- if (p == NULL)
- return (1);
- while (*p != '\0' && *p < 128)
- p++;
- return (*p != '\0');
-}
-
-/*
- * Used by extended attribute support; encodes the name
- * so that there will be no '=' characters in the result.
- */
-static char *
-url_encode(const char *in)
-{
- const char *s;
- char *d;
- int out_len = 0;
- char *out;
-
- for (s = in; *s != '\0'; s++) {
- if (*s < 33 || *s > 126 || *s == '%' || *s == '=')
- out_len += 3;
- else
- out_len++;
- }
-
- out = (char *)malloc(out_len + 1);
- if (out == NULL)
- return (NULL);
-
- for (s = in, d = out; *s != '\0'; s++) {
- /* encode any non-printable ASCII character or '%' or '=' */
- if (*s < 33 || *s > 126 || *s == '%' || *s == '=') {
- /* URL encoding is '%' followed by two hex digits */
- *d++ = '%';
- *d++ = "0123456789ABCDEF"[0x0f & (*s >> 4)];
- *d++ = "0123456789ABCDEF"[0x0f & *s];
- } else {
- *d++ = *s;
- }
- }
- *d = '\0';
- return (out);
-}
-
-/*
- * Encode a sequence of bytes into a C string using base-64 encoding.
- *
- * Returns a null-terminated C string allocated with malloc(); caller
- * is responsible for freeing the result.
- */
-static char *
-base64_encode(const char *s, size_t len)
-{
- static const char digits[64] =
- { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
- 'P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d',
- 'e','f','g','h','i','j','k','l','m','n','o','p','q','r','s',
- 't','u','v','w','x','y','z','0','1','2','3','4','5','6','7',
- '8','9','+','/' };
- int v;
- char *d, *out;
-
- /* 3 bytes becomes 4 chars, but round up and allow for trailing NUL */
- out = (char *)malloc((len * 4 + 2) / 3 + 1);
- if (out == NULL)
- return (NULL);
- d = out;
-
- /* Convert each group of 3 bytes into 4 characters. */
- while (len >= 3) {
- v = (((int)s[0] << 16) & 0xff0000)
- | (((int)s[1] << 8) & 0xff00)
- | (((int)s[2]) & 0x00ff);
- s += 3;
- len -= 3;
- *d++ = digits[(v >> 18) & 0x3f];
- *d++ = digits[(v >> 12) & 0x3f];
- *d++ = digits[(v >> 6) & 0x3f];
- *d++ = digits[(v) & 0x3f];
- }
- /* Handle final group of 1 byte (2 chars) or 2 bytes (3 chars). */
- switch (len) {
- case 0: break;
- case 1:
- v = (((int)s[0] << 16) & 0xff0000);
- *d++ = digits[(v >> 18) & 0x3f];
- *d++ = digits[(v >> 12) & 0x3f];
- break;
- case 2:
- v = (((int)s[0] << 16) & 0xff0000)
- | (((int)s[1] << 8) & 0xff00);
- *d++ = digits[(v >> 18) & 0x3f];
- *d++ = digits[(v >> 12) & 0x3f];
- *d++ = digits[(v >> 6) & 0x3f];
- break;
- }
- /* Add trailing NUL character so output is a valid C string. */
- *d = '\0';
- return (out);
-}
-
-static void
-sparse_list_clear(struct pax *pax)
-{
- while (pax->sparse_list != NULL) {
- struct sparse_block *sb = pax->sparse_list;
- pax->sparse_list = sb->next;
- free(sb);
- }
- pax->sparse_tail = NULL;
-}
-
-static int
-_sparse_list_add_block(struct pax *pax, int64_t offset, int64_t length,
- int is_hole)
-{
- struct sparse_block *sb;
-
- sb = (struct sparse_block *)malloc(sizeof(*sb));
- if (sb == NULL)
- return (ARCHIVE_FATAL);
- sb->next = NULL;
- sb->is_hole = is_hole;
- sb->offset = offset;
- sb->remaining = length;
- if (pax->sparse_list == NULL || pax->sparse_tail == NULL)
- pax->sparse_list = pax->sparse_tail = sb;
- else {
- pax->sparse_tail->next = sb;
- pax->sparse_tail = sb;
- }
- return (ARCHIVE_OK);
-}
-
-static int
-sparse_list_add(struct pax *pax, int64_t offset, int64_t length)
-{
- int64_t last_offset;
- int r;
-
- if (pax->sparse_tail == NULL)
- last_offset = 0;
- else {
- last_offset = pax->sparse_tail->offset +
- pax->sparse_tail->remaining;
- }
- if (last_offset < offset) {
- /* Add a hole block. */
- r = _sparse_list_add_block(pax, last_offset,
- offset - last_offset, 1);
- if (r != ARCHIVE_OK)
- return (r);
- }
- /* Add data block. */
- return (_sparse_list_add_block(pax, offset, length, 0));
-}
-
diff --git a/3rdparty/libarchive/libarchive/archive_write_set_format_shar.c b/3rdparty/libarchive/libarchive/archive_write_set_format_shar.c
deleted file mode 100644
index 9ec15f91..00000000
--- a/3rdparty/libarchive/libarchive/archive_write_set_format_shar.c
+++ /dev/null
@@ -1,642 +0,0 @@
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * Copyright (c) 2008 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(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: head/lib/libarchive/archive_write_set_format_shar.c 189438 2009-03-06 05:58:56Z kientzle $");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#include <stdio.h>
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#include "archive.h"
-#include "archive_entry.h"
-#include "archive_private.h"
-#include "archive_write_private.h"
-
-struct shar {
- int dump;
- int end_of_line;
- struct archive_entry *entry;
- int has_data;
- char *last_dir;
-
- /* Line buffer for uuencoded dump format */
- char outbuff[45];
- size_t outpos;
-
- int wrote_header;
- struct archive_string work;
- struct archive_string quoted_name;
-};
-
-static int archive_write_shar_close(struct archive_write *);
-static int archive_write_shar_free(struct archive_write *);
-static int archive_write_shar_header(struct archive_write *,
- struct archive_entry *);
-static ssize_t archive_write_shar_data_sed(struct archive_write *,
- const void * buff, size_t);
-static ssize_t archive_write_shar_data_uuencode(struct archive_write *,
- const void * buff, size_t);
-static int archive_write_shar_finish_entry(struct archive_write *);
-
-/*
- * Copy the given string to the buffer, quoting all shell meta characters
- * found.
- */
-static void
-shar_quote(struct archive_string *buf, const char *str, int in_shell)
-{
- static const char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~";
- size_t len;
-
- while (*str != '\0') {
- if ((len = strcspn(str, meta)) != 0) {
- archive_strncat(buf, str, len);
- str += len;
- } else if (*str == '\n') {
- if (in_shell)
- archive_strcat(buf, "\"\n\"");
- else
- archive_strcat(buf, "\\n");
- ++str;
- } else {
- archive_strappend_char(buf, '\\');
- archive_strappend_char(buf, *str);
- ++str;
- }
- }
-}
-
-/*
- * Set output format to 'shar' format.
- */
-int
-archive_write_set_format_shar(struct archive *_a)
-{
- struct archive_write *a = (struct archive_write *)_a;
- struct shar *shar;
-
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_set_format_shar");
-
- /* If someone else was already registered, unregister them. */
- if (a->format_free != NULL)
- (a->format_free)(a);
-
- shar = (struct shar *)malloc(sizeof(*shar));
- if (shar == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Can't allocate shar data");
- return (ARCHIVE_FATAL);
- }
- memset(shar, 0, sizeof(*shar));
- archive_string_init(&shar->work);
- archive_string_init(&shar->quoted_name);
- a->format_data = shar;
- a->format_name = "shar";
- a->format_write_header = archive_write_shar_header;
- a->format_close = archive_write_shar_close;
- a->format_free = archive_write_shar_free;
- a->format_write_data = archive_write_shar_data_sed;
- a->format_finish_entry = archive_write_shar_finish_entry;
- a->archive.archive_format = ARCHIVE_FORMAT_SHAR_BASE;
- a->archive.archive_format_name = "shar";
- return (ARCHIVE_OK);
-}
-
-/*
- * An alternate 'shar' that uses uudecode instead of 'sed' to encode
- * file contents and can therefore be used to archive binary files.
- * In addition, this variant also attempts to restore ownership, file modes,
- * and other extended file information.
- */
-int
-archive_write_set_format_shar_dump(struct archive *_a)
-{
- struct archive_write *a = (struct archive_write *)_a;
- struct shar *shar;
-
- archive_write_set_format_shar(&a->archive);
- shar = (struct shar *)a->format_data;
- shar->dump = 1;
- a->format_write_data = archive_write_shar_data_uuencode;
- a->archive.archive_format = ARCHIVE_FORMAT_SHAR_DUMP;
- a->archive.archive_format_name = "shar dump";
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_shar_header(struct archive_write *a, struct archive_entry *entry)
-{
- const char *linkname;
- const char *name;
- char *p, *pp;
- struct shar *shar;
-
- shar = (struct shar *)a->format_data;
- if (!shar->wrote_header) {
- archive_strcat(&shar->work, "#!/bin/sh\n");
- archive_strcat(&shar->work, "# This is a shell archive\n");
- shar->wrote_header = 1;
- }
-
- /* Save the entry for the closing. */
- if (shar->entry)
- archive_entry_free(shar->entry);
- shar->entry = archive_entry_clone(entry);
- name = archive_entry_pathname(entry);
-
- /* Handle some preparatory issues. */
- switch(archive_entry_filetype(entry)) {
- case AE_IFREG:
- /* Only regular files have non-zero size. */
- break;
- case AE_IFDIR:
- archive_entry_set_size(entry, 0);
- /* Don't bother trying to recreate '.' */
- if (strcmp(name, ".") == 0 || strcmp(name, "./") == 0)
- return (ARCHIVE_OK);
- break;
- case AE_IFIFO:
- case AE_IFCHR:
- case AE_IFBLK:
- /* All other file types have zero size in the archive. */
- archive_entry_set_size(entry, 0);
- break;
- default:
- archive_entry_set_size(entry, 0);
- if (archive_entry_hardlink(entry) == NULL &&
- archive_entry_symlink(entry) == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "shar format cannot archive this");
- return (ARCHIVE_WARN);
- }
- }
-
- archive_string_empty(&shar->quoted_name);
- shar_quote(&shar->quoted_name, name, 1);
-
- /* Stock preparation for all file types. */
- archive_string_sprintf(&shar->work, "echo x %s\n", shar->quoted_name.s);
-
- if (archive_entry_filetype(entry) != AE_IFDIR) {
- /* Try to create the dir. */
- p = strdup(name);
- pp = strrchr(p, '/');
- /* If there is a / character, try to create the dir. */
- if (pp != NULL) {
- *pp = '\0';
-
- /* Try to avoid a lot of redundant mkdir commands. */
- if (strcmp(p, ".") == 0) {
- /* Don't try to "mkdir ." */
- free(p);
- } else if (shar->last_dir == NULL) {
- archive_strcat(&shar->work, "mkdir -p ");
- shar_quote(&shar->work, p, 1);
- archive_strcat(&shar->work,
- " > /dev/null 2>&1\n");
- shar->last_dir = p;
- } else if (strcmp(p, shar->last_dir) == 0) {
- /* We've already created this exact dir. */
- free(p);
- } else if (strlen(p) < strlen(shar->last_dir) &&
- strncmp(p, shar->last_dir, strlen(p)) == 0) {
- /* We've already created a subdir. */
- free(p);
- } else {
- archive_strcat(&shar->work, "mkdir -p ");
- shar_quote(&shar->work, p, 1);
- archive_strcat(&shar->work,
- " > /dev/null 2>&1\n");
- shar->last_dir = p;
- }
- } else {
- free(p);
- }
- }
-
- /* Handle file-type specific issues. */
- shar->has_data = 0;
- if ((linkname = archive_entry_hardlink(entry)) != NULL) {
- archive_strcat(&shar->work, "ln -f ");
- shar_quote(&shar->work, linkname, 1);
- archive_string_sprintf(&shar->work, " %s\n",
- shar->quoted_name.s);
- } else if ((linkname = archive_entry_symlink(entry)) != NULL) {
- archive_strcat(&shar->work, "ln -fs ");
- shar_quote(&shar->work, linkname, 1);
- archive_string_sprintf(&shar->work, " %s\n",
- shar->quoted_name.s);
- } else {
- switch(archive_entry_filetype(entry)) {
- case AE_IFREG:
- if (archive_entry_size(entry) == 0) {
- /* More portable than "touch." */
- archive_string_sprintf(&shar->work,
- "test -e \"%s\" || :> \"%s\"\n",
- shar->quoted_name.s, shar->quoted_name.s);
- } else {
- if (shar->dump) {
- unsigned int mode = archive_entry_mode(entry) & 0777;
- archive_string_sprintf(&shar->work,
- "uudecode -p > %s << 'SHAR_END'\n",
- shar->quoted_name.s);
- archive_string_sprintf(&shar->work,
- "begin %o ", mode);
- shar_quote(&shar->work, name, 0);
- archive_strcat(&shar->work, "\n");
- } else {
- archive_string_sprintf(&shar->work,
- "sed 's/^X//' > %s << 'SHAR_END'\n",
- shar->quoted_name.s);
- }
- shar->has_data = 1;
- shar->end_of_line = 1;
- shar->outpos = 0;
- }
- break;
- case AE_IFDIR:
- archive_string_sprintf(&shar->work,
- "mkdir -p %s > /dev/null 2>&1\n",
- shar->quoted_name.s);
- /* Record that we just created this directory. */
- if (shar->last_dir != NULL)
- free(shar->last_dir);
-
- shar->last_dir = strdup(name);
- /* Trim a trailing '/'. */
- pp = strrchr(shar->last_dir, '/');
- if (pp != NULL && pp[1] == '\0')
- *pp = '\0';
- /*
- * TODO: Put dir name/mode on a list to be fixed
- * up at end of archive.
- */
- break;
- case AE_IFIFO:
- archive_string_sprintf(&shar->work,
- "mkfifo %s\n", shar->quoted_name.s);
- break;
- case AE_IFCHR:
- archive_string_sprintf(&shar->work,
- "mknod %s c %ju %ju\n", shar->quoted_name.s,
- (uintmax_t)archive_entry_rdevmajor(entry),
- (uintmax_t)archive_entry_rdevminor(entry));
- break;
- case AE_IFBLK:
- archive_string_sprintf(&shar->work,
- "mknod %s b %ju %ju\n", shar->quoted_name.s,
- (uintmax_t)archive_entry_rdevmajor(entry),
- (uintmax_t)archive_entry_rdevminor(entry));
- break;
- default:
- return (ARCHIVE_WARN);
- }
- }
-
- return (ARCHIVE_OK);
-}
-
-static ssize_t
-archive_write_shar_data_sed(struct archive_write *a, const void *buff, size_t n)
-{
- static const size_t ensured = 65533;
- struct shar *shar;
- const char *src;
- char *buf, *buf_end;
- int ret;
- size_t written = n;
-
- shar = (struct shar *)a->format_data;
- if (!shar->has_data || n == 0)
- return (0);
-
- src = (const char *)buff;
-
- /*
- * ensure is the number of bytes in buffer before expanding the
- * current character. Each operation writes the current character
- * and optionally the start-of-new-line marker. This can happen
- * twice before entering the loop, so make sure three additional
- * bytes can be written.
- */
- if (archive_string_ensure(&shar->work, ensured + 3) == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
-
- if (shar->work.length > ensured) {
- ret = __archive_write_output(a, shar->work.s,
- shar->work.length);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- archive_string_empty(&shar->work);
- }
- buf = shar->work.s + shar->work.length;
- buf_end = shar->work.s + ensured;
-
- if (shar->end_of_line) {
- *buf++ = 'X';
- shar->end_of_line = 0;
- }
-
- while (n-- != 0) {
- if ((*buf++ = *src++) == '\n') {
- if (n == 0)
- shar->end_of_line = 1;
- else
- *buf++ = 'X';
- }
-
- if (buf >= buf_end) {
- shar->work.length = buf - shar->work.s;
- ret = __archive_write_output(a, shar->work.s,
- shar->work.length);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- archive_string_empty(&shar->work);
- buf = shar->work.s;
- }
- }
-
- shar->work.length = buf - shar->work.s;
-
- return (written);
-}
-
-#define UUENC(c) (((c)!=0) ? ((c) & 077) + ' ': '`')
-
-static void
-uuencode_group(const char _in[3], char out[4])
-{
- const unsigned char *in = (const unsigned char *)_in;
- int t;
-
- t = (in[0] << 16) | (in[1] << 8) | in[2];
- out[0] = UUENC( 0x3f & (t >> 18) );
- out[1] = UUENC( 0x3f & (t >> 12) );
- out[2] = UUENC( 0x3f & (t >> 6) );
- out[3] = UUENC( 0x3f & t );
-}
-
-static int
-_uuencode_line(struct archive_write *a, struct shar *shar, const char *inbuf, size_t len)
-{
- char *buf;
- size_t alloc_len;
-
- /* len <= 45 -> expanded to 60 + len byte + new line */
- alloc_len = shar->work.length + 62;
- if (archive_string_ensure(&shar->work, alloc_len) == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
-
- buf = shar->work.s + shar->work.length;
- *buf++ = UUENC(len);
- while (len >= 3) {
- uuencode_group(inbuf, buf);
- len -= 3;
- inbuf += 3;
- buf += 4;
- }
- if (len != 0) {
- char tmp_buf[3];
- tmp_buf[0] = inbuf[0];
- if (len == 1)
- tmp_buf[1] = '\0';
- else
- tmp_buf[1] = inbuf[1];
- tmp_buf[2] = '\0';
- uuencode_group(tmp_buf, buf);
- buf += 4;
- }
- *buf++ = '\n';
- if ((buf - shar->work.s) > (ptrdiff_t)(shar->work.length + 62)) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC, "Buffer overflow");
- return (ARCHIVE_FATAL);
- }
- shar->work.length = buf - shar->work.s;
- return (ARCHIVE_OK);
-}
-
-#define uuencode_line(__a, __shar, __inbuf, __len) \
- do { \
- int r = _uuencode_line(__a, __shar, __inbuf, __len); \
- if (r != ARCHIVE_OK) \
- return (ARCHIVE_FATAL); \
- } while (0)
-
-static ssize_t
-archive_write_shar_data_uuencode(struct archive_write *a, const void *buff,
- size_t length)
-{
- struct shar *shar;
- const char *src;
- size_t n;
- int ret;
-
- shar = (struct shar *)a->format_data;
- if (!shar->has_data)
- return (ARCHIVE_OK);
- src = (const char *)buff;
-
- if (shar->outpos != 0) {
- n = 45 - shar->outpos;
- if (n > length)
- n = length;
- memcpy(shar->outbuff + shar->outpos, src, n);
- if (shar->outpos + n < 45) {
- shar->outpos += n;
- return length;
- }
- uuencode_line(a, shar, shar->outbuff, 45);
- src += n;
- n = length - n;
- } else {
- n = length;
- }
-
- while (n >= 45) {
- uuencode_line(a, shar, src, 45);
- src += 45;
- n -= 45;
-
- if (shar->work.length < 65536)
- continue;
- ret = __archive_write_output(a, shar->work.s,
- shar->work.length);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- archive_string_empty(&shar->work);
- }
- if (n != 0) {
- memcpy(shar->outbuff, src, n);
- shar->outpos = n;
- }
- return (length);
-}
-
-static int
-archive_write_shar_finish_entry(struct archive_write *a)
-{
- const char *g, *p, *u;
- struct shar *shar;
- int ret;
-
- shar = (struct shar *)a->format_data;
- if (shar->entry == NULL)
- return (0);
-
- if (shar->dump) {
- /* Finish uuencoded data. */
- if (shar->has_data) {
- if (shar->outpos > 0)
- uuencode_line(a, shar, shar->outbuff,
- shar->outpos);
- archive_strcat(&shar->work, "`\nend\n");
- archive_strcat(&shar->work, "SHAR_END\n");
- }
- /* Restore file mode, owner, flags. */
- /*
- * TODO: Don't immediately restore mode for
- * directories; defer that to end of script.
- */
- archive_string_sprintf(&shar->work, "chmod %o ",
- (unsigned int)(archive_entry_mode(shar->entry) & 07777));
- shar_quote(&shar->work, archive_entry_pathname(shar->entry), 1);
- archive_strcat(&shar->work, "\n");
-
- u = archive_entry_uname(shar->entry);
- g = archive_entry_gname(shar->entry);
- if (u != NULL || g != NULL) {
- archive_strcat(&shar->work, "chown ");
- if (u != NULL)
- shar_quote(&shar->work, u, 1);
- if (g != NULL) {
- archive_strcat(&shar->work, ":");
- shar_quote(&shar->work, g, 1);
- }
- shar_quote(&shar->work,
- archive_entry_pathname(shar->entry), 1);
- archive_strcat(&shar->work, "\n");
- }
-
- if ((p = archive_entry_fflags_text(shar->entry)) != NULL) {
- archive_string_sprintf(&shar->work, "chflags %s ", p);
- shar_quote(&shar->work,
- archive_entry_pathname(shar->entry), 1);
- archive_strcat(&shar->work, "\n");
- }
-
- /* TODO: restore ACLs */
-
- } else {
- if (shar->has_data) {
- /* Finish sed-encoded data: ensure last line ends. */
- if (!shar->end_of_line)
- archive_strappend_char(&shar->work, '\n');
- archive_strcat(&shar->work, "SHAR_END\n");
- }
- }
-
- archive_entry_free(shar->entry);
- shar->entry = NULL;
-
- if (shar->work.length < 65536)
- return (ARCHIVE_OK);
-
- ret = __archive_write_output(a, shar->work.s, shar->work.length);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- archive_string_empty(&shar->work);
-
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_shar_close(struct archive_write *a)
-{
- struct shar *shar;
- int ret;
-
- /*
- * TODO: Accumulate list of directory names/modes and
- * fix them all up at end-of-archive.
- */
-
- shar = (struct shar *)a->format_data;
-
- /*
- * Only write the end-of-archive markers if the archive was
- * actually started. This avoids problems if someone sets
- * shar format, then sets another format (which would invoke
- * shar_finish to free the format-specific data).
- */
- if (shar->wrote_header == 0)
- return (ARCHIVE_OK);
-
- archive_strcat(&shar->work, "exit\n");
-
- ret = __archive_write_output(a, shar->work.s, shar->work.length);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
-
- /* Shar output is never padded. */
- archive_write_set_bytes_in_last_block(&a->archive, 1);
- /*
- * TODO: shar should also suppress padding of
- * uncompressed data within gzip/bzip2 streams.
- */
-
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_shar_free(struct archive_write *a)
-{
- struct shar *shar;
-
- shar = (struct shar *)a->format_data;
- if (shar == NULL)
- return (ARCHIVE_OK);
-
- archive_entry_free(shar->entry);
- free(shar->last_dir);
- archive_string_free(&(shar->work));
- archive_string_free(&(shar->quoted_name));
- free(shar);
- a->format_data = NULL;
- return (ARCHIVE_OK);
-}
diff --git a/3rdparty/libarchive/libarchive/archive_write_set_format_ustar.c b/3rdparty/libarchive/libarchive/archive_write_set_format_ustar.c
index 484ab34b..c54aeabd 100644
--- a/3rdparty/libarchive/libarchive/archive_write_set_format_ustar.c
+++ b/3rdparty/libarchive/libarchive/archive_write_set_format_ustar.c
@@ -114,9 +114,9 @@ static const char template_header[] = {
'0','0','0','0','0','0', ' ','\0',
/* gid, space-null termination: 8 bytes */
'0','0','0','0','0','0', ' ','\0',
- /* size, space termation: 12 bytes */
+ /* size, space termination: 12 bytes */
'0','0','0','0','0','0','0','0','0','0','0', ' ',
- /* mtime, space termation: 12 bytes */
+ /* mtime, space termination: 12 bytes */
'0','0','0','0','0','0','0','0','0','0','0', ' ',
/* Initial checksum value: 8 spaces */
' ',' ',' ',' ',' ',' ',' ',' ',
@@ -184,13 +184,12 @@ archive_write_set_format_ustar(struct archive *_a)
return (ARCHIVE_FATAL);
}
- ustar = (struct ustar *)malloc(sizeof(*ustar));
+ ustar = (struct ustar *)calloc(1, sizeof(*ustar));
if (ustar == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate ustar data");
return (ARCHIVE_FATAL);
}
- memset(ustar, 0, sizeof(*ustar));
a->format_data = ustar;
a->format_name = "ustar";
a->format_options = archive_write_ustar_options;
@@ -307,7 +306,7 @@ archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
* case getting WCS failed. On POSIX, this is a
* normal operation.
*/
- if (p != NULL && p[strlen(p) - 1] != '/') {
+ if (p != NULL && p[0] != '\0' && p[strlen(p) - 1] != '/') {
struct archive_string as;
archive_string_init(&as);
@@ -336,7 +335,7 @@ archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
}
#if defined(_WIN32) && !defined(__CYGWIN__)
- /* Make sure the path separators in pahtname, hardlink and symlink
+ /* Make sure the path separators in pathname, hardlink and symlink
* are all slash '/', not the Windows path separator '\'. */
entry_main = __la_win_entry_in_posix_pathseparator(entry);
if (entry_main == NULL) {
diff --git a/3rdparty/libarchive/libarchive/archive_write_set_format_v7tar.c b/3rdparty/libarchive/libarchive/archive_write_set_format_v7tar.c
deleted file mode 100644
index 17efbaf7..00000000
--- a/3rdparty/libarchive/libarchive/archive_write_set_format_v7tar.c
+++ /dev/null
@@ -1,661 +0,0 @@
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * Copyright (c) 2011-2012 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"
-__FBSDID("$FreeBSD$");
-
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#include <stdio.h>
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#include "archive.h"
-#include "archive_entry.h"
-#include "archive_entry_locale.h"
-#include "archive_private.h"
-#include "archive_write_private.h"
-
-struct v7tar {
- uint64_t entry_bytes_remaining;
- uint64_t entry_padding;
-
- struct archive_string_conv *opt_sconv;
- struct archive_string_conv *sconv_default;
- int init_default_conversion;
-};
-
-/*
- * Define structure of POSIX 'v7tar' tar header.
- */
-#define V7TAR_name_offset 0
-#define V7TAR_name_size 100
-#define V7TAR_mode_offset 100
-#define V7TAR_mode_size 6
-#define V7TAR_mode_max_size 8
-#define V7TAR_uid_offset 108
-#define V7TAR_uid_size 6
-#define V7TAR_uid_max_size 8
-#define V7TAR_gid_offset 116
-#define V7TAR_gid_size 6
-#define V7TAR_gid_max_size 8
-#define V7TAR_size_offset 124
-#define V7TAR_size_size 11
-#define V7TAR_size_max_size 12
-#define V7TAR_mtime_offset 136
-#define V7TAR_mtime_size 11
-#define V7TAR_mtime_max_size 12
-#define V7TAR_checksum_offset 148
-#define V7TAR_checksum_size 8
-#define V7TAR_typeflag_offset 156
-#define V7TAR_typeflag_size 1
-#define V7TAR_linkname_offset 157
-#define V7TAR_linkname_size 100
-#define V7TAR_padding_offset 257
-#define V7TAR_padding_size 255
-
-/*
- * A filled-in copy of the header for initialization.
- */
-static const char template_header[] = {
- /* name: 100 bytes */
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
- 0,0,0,0,
- /* Mode, space-null termination: 8 bytes */
- '0','0','0','0','0','0', ' ','\0',
- /* uid, space-null termination: 8 bytes */
- '0','0','0','0','0','0', ' ','\0',
- /* gid, space-null termination: 8 bytes */
- '0','0','0','0','0','0', ' ','\0',
- /* size, space termation: 12 bytes */
- '0','0','0','0','0','0','0','0','0','0','0', ' ',
- /* mtime, space termation: 12 bytes */
- '0','0','0','0','0','0','0','0','0','0','0', ' ',
- /* Initial checksum value: 8 spaces */
- ' ',' ',' ',' ',' ',' ',' ',' ',
- /* Typeflag: 1 byte */
- 0,
- /* Linkname: 100 bytes */
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
- 0,0,0,0,
- /* Padding: 255 bytes */
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0
-};
-
-static ssize_t archive_write_v7tar_data(struct archive_write *a, const void *buff,
- size_t s);
-static int archive_write_v7tar_free(struct archive_write *);
-static int archive_write_v7tar_close(struct archive_write *);
-static int archive_write_v7tar_finish_entry(struct archive_write *);
-static int archive_write_v7tar_header(struct archive_write *,
- struct archive_entry *entry);
-static int archive_write_v7tar_options(struct archive_write *,
- const char *, const char *);
-static int format_256(int64_t, char *, int);
-static int format_number(int64_t, char *, int size, int max, int strict);
-static int format_octal(int64_t, char *, int);
-static int format_header_v7tar(struct archive_write *, char h[512],
- struct archive_entry *, int, struct archive_string_conv *);
-
-/*
- * Set output format to 'v7tar' format.
- */
-int
-archive_write_set_format_v7tar(struct archive *_a)
-{
- struct archive_write *a = (struct archive_write *)_a;
- struct v7tar *v7tar;
-
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_set_format_v7tar");
-
- /* If someone else was already registered, unregister them. */
- if (a->format_free != NULL)
- (a->format_free)(a);
-
- /* Basic internal sanity test. */
- if (sizeof(template_header) != 512) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal: template_header wrong size: %zu should be 512",
- sizeof(template_header));
- return (ARCHIVE_FATAL);
- }
-
- v7tar = (struct v7tar *)malloc(sizeof(*v7tar));
- if (v7tar == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate v7tar data");
- return (ARCHIVE_FATAL);
- }
- memset(v7tar, 0, sizeof(*v7tar));
- a->format_data = v7tar;
- a->format_name = "tar (non-POSIX)";
- a->format_options = archive_write_v7tar_options;
- a->format_write_header = archive_write_v7tar_header;
- a->format_write_data = archive_write_v7tar_data;
- a->format_close = archive_write_v7tar_close;
- a->format_free = archive_write_v7tar_free;
- a->format_finish_entry = archive_write_v7tar_finish_entry;
- a->archive.archive_format = ARCHIVE_FORMAT_TAR;
- a->archive.archive_format_name = "tar (non-POSIX)";
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_v7tar_options(struct archive_write *a, const char *key,
- const char *val)
-{
- struct v7tar *v7tar = (struct v7tar *)a->format_data;
- int ret = ARCHIVE_FAILED;
-
- if (strcmp(key, "hdrcharset") == 0) {
- if (val == NULL || val[0] == 0)
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "%s: hdrcharset option needs a character-set name",
- a->format_name);
- else {
- v7tar->opt_sconv = archive_string_conversion_to_charset(
- &a->archive, val, 0);
- if (v7tar->opt_sconv != NULL)
- ret = ARCHIVE_OK;
- else
- ret = ARCHIVE_FATAL;
- }
- return (ret);
- }
-
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
-}
-
-static int
-archive_write_v7tar_header(struct archive_write *a, struct archive_entry *entry)
-{
- char buff[512];
- int ret, ret2;
- struct v7tar *v7tar;
- struct archive_entry *entry_main;
- struct archive_string_conv *sconv;
-
- v7tar = (struct v7tar *)a->format_data;
-
- /* Setup default string conversion. */
- if (v7tar->opt_sconv == NULL) {
- if (!v7tar->init_default_conversion) {
- v7tar->sconv_default =
- archive_string_default_conversion_for_write(
- &(a->archive));
- v7tar->init_default_conversion = 1;
- }
- sconv = v7tar->sconv_default;
- } else
- sconv = v7tar->opt_sconv;
-
- /* Sanity check. */
- if (archive_entry_pathname(entry) == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Can't record entry in tar file without pathname");
- return (ARCHIVE_FAILED);
- }
-
- /* Only regular files (not hardlinks) have data. */
- if (archive_entry_hardlink(entry) != NULL ||
- archive_entry_symlink(entry) != NULL ||
- !(archive_entry_filetype(entry) == AE_IFREG))
- archive_entry_set_size(entry, 0);
-
- if (AE_IFDIR == archive_entry_filetype(entry)) {
- const char *p;
- size_t path_length;
- /*
- * Ensure a trailing '/'. Modify the entry so
- * the client sees the change.
- */
-#if defined(_WIN32) && !defined(__CYGWIN__)
- const wchar_t *wp;
-
- wp = archive_entry_pathname_w(entry);
- if (wp != NULL && wp[wcslen(wp) -1] != L'/') {
- struct archive_wstring ws;
-
- archive_string_init(&ws);
- path_length = wcslen(wp);
- if (archive_wstring_ensure(&ws,
- path_length + 2) == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate v7tar data");
- archive_wstring_free(&ws);
- return(ARCHIVE_FATAL);
- }
- /* Should we keep '\' ? */
- if (wp[path_length -1] == L'\\')
- path_length--;
- archive_wstrncpy(&ws, wp, path_length);
- archive_wstrappend_wchar(&ws, L'/');
- archive_entry_copy_pathname_w(entry, ws.s);
- archive_wstring_free(&ws);
- p = NULL;
- } else
-#endif
- p = archive_entry_pathname(entry);
- /*
- * On Windows, this is a backup operation just in
- * case getting WCS failed. On POSIX, this is a
- * normal operation.
- */
- if (p != NULL && p[strlen(p) - 1] != '/') {
- struct archive_string as;
-
- archive_string_init(&as);
- path_length = strlen(p);
- if (archive_string_ensure(&as,
- path_length + 2) == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate v7tar data");
- archive_string_free(&as);
- return(ARCHIVE_FATAL);
- }
-#if defined(_WIN32) && !defined(__CYGWIN__)
- /* NOTE: This might break the pathname
- * if the current code page is CP932 and
- * the pathname includes a character '\'
- * as a part of its multibyte pathname. */
- if (p[strlen(p) -1] == '\\')
- path_length--;
- else
-#endif
- archive_strncpy(&as, p, path_length);
- archive_strappend_char(&as, '/');
- archive_entry_copy_pathname(entry, as.s);
- archive_string_free(&as);
- }
- }
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
- /* Make sure the path separators in pahtname, hardlink and symlink
- * are all slash '/', not the Windows path separator '\'. */
- entry_main = __la_win_entry_in_posix_pathseparator(entry);
- if (entry_main == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate v7tar data");
- return(ARCHIVE_FATAL);
- }
- if (entry != entry_main)
- entry = entry_main;
- else
- entry_main = NULL;
-#else
- entry_main = NULL;
-#endif
- ret = format_header_v7tar(a, buff, entry, 1, sconv);
- if (ret < ARCHIVE_WARN) {
- if (entry_main)
- archive_entry_free(entry_main);
- return (ret);
- }
- ret2 = __archive_write_output(a, buff, 512);
- if (ret2 < ARCHIVE_WARN) {
- if (entry_main)
- archive_entry_free(entry_main);
- return (ret2);
- }
- if (ret2 < ret)
- ret = ret2;
-
- v7tar->entry_bytes_remaining = archive_entry_size(entry);
- v7tar->entry_padding = 0x1ff & (-(int64_t)v7tar->entry_bytes_remaining);
- if (entry_main)
- archive_entry_free(entry_main);
- return (ret);
-}
-
-/*
- * Format a basic 512-byte "v7tar" header.
- *
- * Returns -1 if format failed (due to field overflow).
- * Note that this always formats as much of the header as possible.
- * If "strict" is set to zero, it will extend numeric fields as
- * necessary (overwriting terminators or using base-256 extensions).
- *
- */
-static int
-format_header_v7tar(struct archive_write *a, char h[512],
- struct archive_entry *entry, int strict,
- struct archive_string_conv *sconv)
-{
- unsigned int checksum;
- int i, r, ret;
- size_t copy_length;
- const char *p, *pp;
- int mytartype;
-
- ret = 0;
- mytartype = -1;
- /*
- * The "template header" already includes the "v7tar"
- * signature, various end-of-field markers and other required
- * elements.
- */
- memcpy(h, &template_header, 512);
-
- /*
- * Because the block is already null-filled, and strings
- * are allowed to exactly fill their destination (without null),
- * I use memcpy(dest, src, strlen()) here a lot to copy strings.
- */
- r = archive_entry_pathname_l(entry, &pp, &copy_length, sconv);
- if (r != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Pathname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate pathname '%s' to %s",
- pp, archive_string_conversion_charset_name(sconv));
- ret = ARCHIVE_WARN;
- }
- if (strict && copy_length < V7TAR_name_size)
- memcpy(h + V7TAR_name_offset, pp, copy_length);
- else if (!strict && copy_length <= V7TAR_name_size)
- memcpy(h + V7TAR_name_offset, pp, copy_length);
- else {
- /* Prefix is too long. */
- archive_set_error(&a->archive, ENAMETOOLONG,
- "Pathname too long");
- ret = ARCHIVE_FAILED;
- }
-
- r = archive_entry_hardlink_l(entry, &p, &copy_length, sconv);
- if (r != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Linkname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate linkname '%s' to %s",
- p, archive_string_conversion_charset_name(sconv));
- ret = ARCHIVE_WARN;
- }
- if (copy_length > 0)
- mytartype = '1';
- else {
- r = archive_entry_symlink_l(entry, &p, &copy_length, sconv);
- if (r != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Linkname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate linkname '%s' to %s",
- p, archive_string_conversion_charset_name(sconv));
- ret = ARCHIVE_WARN;
- }
- }
- if (copy_length > 0) {
- if (copy_length >= V7TAR_linkname_size) {
- archive_set_error(&a->archive, ENAMETOOLONG,
- "Link contents too long");
- ret = ARCHIVE_FAILED;
- copy_length = V7TAR_linkname_size;
- }
- memcpy(h + V7TAR_linkname_offset, p, copy_length);
- }
-
- if (format_number(archive_entry_mode(entry) & 07777,
- h + V7TAR_mode_offset, V7TAR_mode_size,
- V7TAR_mode_max_size, strict)) {
- archive_set_error(&a->archive, ERANGE,
- "Numeric mode too large");
- ret = ARCHIVE_FAILED;
- }
-
- if (format_number(archive_entry_uid(entry),
- h + V7TAR_uid_offset, V7TAR_uid_size, V7TAR_uid_max_size, strict)) {
- archive_set_error(&a->archive, ERANGE,
- "Numeric user ID too large");
- ret = ARCHIVE_FAILED;
- }
-
- if (format_number(archive_entry_gid(entry),
- h + V7TAR_gid_offset, V7TAR_gid_size, V7TAR_gid_max_size, strict)) {
- archive_set_error(&a->archive, ERANGE,
- "Numeric group ID too large");
- ret = ARCHIVE_FAILED;
- }
-
- if (format_number(archive_entry_size(entry),
- h + V7TAR_size_offset, V7TAR_size_size,
- V7TAR_size_max_size, strict)) {
- archive_set_error(&a->archive, ERANGE,
- "File size out of range");
- ret = ARCHIVE_FAILED;
- }
-
- if (format_number(archive_entry_mtime(entry),
- h + V7TAR_mtime_offset, V7TAR_mtime_size,
- V7TAR_mtime_max_size, strict)) {
- archive_set_error(&a->archive, ERANGE,
- "File modification time too large");
- ret = ARCHIVE_FAILED;
- }
-
- if (mytartype >= 0) {
- h[V7TAR_typeflag_offset] = mytartype;
- } else {
- switch (archive_entry_filetype(entry)) {
- case AE_IFREG: case AE_IFDIR:
- break;
- case AE_IFLNK:
- h[V7TAR_typeflag_offset] = '2';
- break;
- case AE_IFCHR:
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "tar format cannot archive character device");
- return (ARCHIVE_FAILED);
- case AE_IFBLK:
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "tar format cannot archive block device");
- return (ARCHIVE_FAILED);
- case AE_IFIFO:
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "tar format cannot archive fifo");
- return (ARCHIVE_FAILED);
- case AE_IFSOCK:
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "tar format cannot archive socket");
- return (ARCHIVE_FAILED);
- default:
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "tar format cannot archive this (mode=0%lo)",
- (unsigned long)archive_entry_mode(entry));
- ret = ARCHIVE_FAILED;
- }
- }
-
- checksum = 0;
- for (i = 0; i < 512; i++)
- checksum += 255 & (unsigned int)h[i];
- format_octal(checksum, h + V7TAR_checksum_offset, 6);
- /* Can't be pre-set in the template. */
- h[V7TAR_checksum_offset + 6] = '\0';
- return (ret);
-}
-
-/*
- * Format a number into a field, with some intelligence.
- */
-static int
-format_number(int64_t v, char *p, int s, int maxsize, int strict)
-{
- int64_t limit;
-
- limit = ((int64_t)1 << (s*3));
-
- /* "Strict" only permits octal values with proper termination. */
- if (strict)
- return (format_octal(v, p, s));
-
- /*
- * In non-strict mode, we allow the number to overwrite one or
- * more bytes of the field termination. Even old tar
- * implementations should be able to handle this with no
- * problem.
- */
- if (v >= 0) {
- while (s <= maxsize) {
- if (v < limit)
- return (format_octal(v, p, s));
- s++;
- limit <<= 3;
- }
- }
-
- /* Base-256 can handle any number, positive or negative. */
- return (format_256(v, p, maxsize));
-}
-
-/*
- * Format a number into the specified field using base-256.
- */
-static int
-format_256(int64_t v, char *p, int s)
-{
- p += s;
- while (s-- > 0) {
- *--p = (char)(v & 0xff);
- v >>= 8;
- }
- *p |= 0x80; /* Set the base-256 marker bit. */
- return (0);
-}
-
-/*
- * Format a number into the specified field.
- */
-static int
-format_octal(int64_t v, char *p, int s)
-{
- int len;
-
- len = s;
-
- /* Octal values can't be negative, so use 0. */
- if (v < 0) {
- while (len-- > 0)
- *p++ = '0';
- return (-1);
- }
-
- p += s; /* Start at the end and work backwards. */
- while (s-- > 0) {
- *--p = (char)('0' + (v & 7));
- v >>= 3;
- }
-
- if (v == 0)
- return (0);
-
- /* If it overflowed, fill field with max value. */
- while (len-- > 0)
- *p++ = '7';
-
- return (-1);
-}
-
-static int
-archive_write_v7tar_close(struct archive_write *a)
-{
- return (__archive_write_nulls(a, 512*2));
-}
-
-static int
-archive_write_v7tar_free(struct archive_write *a)
-{
- struct v7tar *v7tar;
-
- v7tar = (struct v7tar *)a->format_data;
- free(v7tar);
- a->format_data = NULL;
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_v7tar_finish_entry(struct archive_write *a)
-{
- struct v7tar *v7tar;
- int ret;
-
- v7tar = (struct v7tar *)a->format_data;
- ret = __archive_write_nulls(a,
- (size_t)(v7tar->entry_bytes_remaining + v7tar->entry_padding));
- v7tar->entry_bytes_remaining = v7tar->entry_padding = 0;
- return (ret);
-}
-
-static ssize_t
-archive_write_v7tar_data(struct archive_write *a, const void *buff, size_t s)
-{
- struct v7tar *v7tar;
- int ret;
-
- v7tar = (struct v7tar *)a->format_data;
- if (s > v7tar->entry_bytes_remaining)
- s = (size_t)v7tar->entry_bytes_remaining;
- ret = __archive_write_output(a, buff, s);
- v7tar->entry_bytes_remaining -= s;
- if (ret != ARCHIVE_OK)
- return (ret);
- return (s);
-}
diff --git a/3rdparty/libarchive/libarchive/archive_write_set_format_xar.c b/3rdparty/libarchive/libarchive/archive_write_set_format_xar.c
deleted file mode 100644
index 79667e56..00000000
--- a/3rdparty/libarchive/libarchive/archive_write_set_format_xar.c
+++ /dev/null
@@ -1,3181 +0,0 @@
-/*-
- * Copyright (c) 2010-2012 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"
-__FBSDID("$FreeBSD$");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#endif
-#include <stdlib.h>
-#if HAVE_LIBXML_XMLWRITER_H
-#include <libxml/xmlwriter.h>
-#endif
-#ifdef HAVE_BZLIB_H
-#include <bzlib.h>
-#endif
-#if HAVE_LZMA_H
-#include <lzma.h>
-#endif
-#ifdef HAVE_ZLIB_H
-#include <zlib.h>
-#endif
-
-#include "archive.h"
-#include "archive_crypto_private.h"
-#include "archive_endian.h"
-#include "archive_entry.h"
-#include "archive_entry_locale.h"
-#include "archive_private.h"
-#include "archive_rb.h"
-#include "archive_string.h"
-#include "archive_write_private.h"
-
-/*
- * Differences to xar utility.
- * - Subdocument is not supported yet.
- * - ACL is not supported yet.
- * - When writing an XML element <link type="<file-type>">, <file-type>
- * which is a file type a symbolic link is referencing is always marked
- * as "broken". Xar utility uses stat(2) to get the file type, but, in
- * libarcive format writer, we should not use it; if it is needed, we
- * should get about it at archive_read_disk.c.
- * - It is possible to appear both <flags> and <ext2> elements.
- * Xar utility generates <flags> on BSD platform and <ext2> on Linux
- * platform.
- *
- */
-
-#if !(defined(HAVE_LIBXML_XMLWRITER_H) && defined(LIBXML_VERSION) &&\
- LIBXML_VERSION >= 20703) ||\
- !defined(HAVE_ZLIB_H) || \
- !defined(ARCHIVE_HAS_MD5) || !defined(ARCHIVE_HAS_SHA1)
-/*
- * xar needs several external libraries.
- * o libxml2
- * o openssl or MD5/SHA1 hash function
- * o zlib
- * o bzlib2 (option)
- * o liblzma (option)
- */
-int
-archive_write_set_format_xar(struct archive *_a)
-{
- struct archive_write *a = (struct archive_write *)_a;
-
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Xar not supported on this platform");
- return (ARCHIVE_WARN);
-}
-
-#else /* Support xar format */
-
-/*#define DEBUG_PRINT_TOC 1 */
-
-#define BAD_CAST_CONST (const xmlChar *)
-
-#define HEADER_MAGIC 0x78617221
-#define HEADER_SIZE 28
-#define HEADER_VERSION 1
-
-enum sumalg {
- CKSUM_NONE = 0,
- CKSUM_SHA1 = 1,
- CKSUM_MD5 = 2
-};
-
-#define MD5_SIZE 16
-#define SHA1_SIZE 20
-#define MAX_SUM_SIZE 20
-#define MD5_NAME "md5"
-#define SHA1_NAME "sha1"
-
-enum enctype {
- NONE,
- GZIP,
- BZIP2,
- LZMA,
- XZ,
-};
-
-struct chksumwork {
- enum sumalg alg;
-#ifdef ARCHIVE_HAS_MD5
- archive_md5_ctx md5ctx;
-#endif
-#ifdef ARCHIVE_HAS_SHA1
- archive_sha1_ctx sha1ctx;
-#endif
-};
-
-enum la_zaction {
- ARCHIVE_Z_FINISH,
- ARCHIVE_Z_RUN
-};
-
-/*
- * Universal zstream.
- */
-struct la_zstream {
- const unsigned char *next_in;
- size_t avail_in;
- uint64_t total_in;
-
- unsigned char *next_out;
- size_t avail_out;
- uint64_t total_out;
-
- int valid;
- void *real_stream;
- int (*code) (struct archive *a,
- struct la_zstream *lastrm,
- enum la_zaction action);
- int (*end)(struct archive *a,
- struct la_zstream *lastrm);
-};
-
-struct chksumval {
- enum sumalg alg;
- size_t len;
- unsigned char val[MAX_SUM_SIZE];
-};
-
-struct heap_data {
- int id;
- struct heap_data *next;
- uint64_t temp_offset;
- uint64_t length; /* archived size. */
- uint64_t size; /* extracted size. */
- enum enctype compression;
- struct chksumval a_sum; /* archived checksum. */
- struct chksumval e_sum; /* extracted checksum. */
-};
-
-struct file {
- struct archive_rb_node rbnode;
-
- int id;
- struct archive_entry *entry;
-
- struct archive_rb_tree rbtree;
- struct file *next;
- struct file *chnext;
- struct file *hlnext;
- /* For hardlinked files.
- * Use only when archive_entry_nlink() > 1 */
- struct file *hardlink_target;
- struct file *parent; /* parent directory entry */
- /*
- * To manage sub directory files.
- * We use 'chnext' a menber of struct file to chain.
- */
- struct {
- struct file *first;
- struct file **last;
- } children;
-
- /* For making a directory tree. */
- struct archive_string parentdir;
- struct archive_string basename;
- struct archive_string symlink;
-
- int ea_idx;
- struct {
- struct heap_data *first;
- struct heap_data **last;
- } xattr;
- struct heap_data data;
- struct archive_string script;
-
- int virtual:1;
- int dir:1;
-};
-
-struct hardlink {
- struct archive_rb_node rbnode;
- int nlink;
- struct {
- struct file *first;
- struct file **last;
- } file_list;
-};
-
-struct xar {
- int temp_fd;
- uint64_t temp_offset;
-
- int file_idx;
- struct file *root;
- struct file *cur_dirent;
- struct archive_string cur_dirstr;
- struct file *cur_file;
- uint64_t bytes_remaining;
- struct archive_string tstr;
- struct archive_string vstr;
-
- enum sumalg opt_toc_sumalg;
- enum sumalg opt_sumalg;
- enum enctype opt_compression;
- int opt_compression_level;
-
- struct chksumwork a_sumwrk; /* archived checksum. */
- struct chksumwork e_sumwrk; /* extracted checksum. */
- struct la_zstream stream;
- struct archive_string_conv *sconv;
- /*
- * Compressed data buffer.
- */
- unsigned char wbuff[1024 * 64];
- size_t wbuff_remaining;
-
- struct heap_data toc;
- /*
- * The list of all file entries is used to manage struct file
- * objects.
- * We use 'next' a menber of struct file to chain.
- */
- struct {
- struct file *first;
- struct file **last;
- } file_list;
- /*
- * The list of hard-linked file entries.
- * We use 'hlnext' a menber of struct file to chain.
- */
- struct archive_rb_tree hardlink_rbtree;
-};
-
-static int xar_options(struct archive_write *,
- const char *, const char *);
-static int xar_write_header(struct archive_write *,
- struct archive_entry *);
-static ssize_t xar_write_data(struct archive_write *,
- const void *, size_t);
-static int xar_finish_entry(struct archive_write *);
-static int xar_close(struct archive_write *);
-static int xar_free(struct archive_write *);
-
-static struct file *file_new(struct archive_write *a, struct archive_entry *);
-static void file_free(struct file *);
-static struct file *file_create_virtual_dir(struct archive_write *a, struct xar *,
- const char *);
-static int file_add_child_tail(struct file *, struct file *);
-static struct file *file_find_child(struct file *, const char *);
-static int file_gen_utility_names(struct archive_write *,
- struct file *);
-static int get_path_component(char *, int, const char *);
-static int file_tree(struct archive_write *, struct file **);
-static void file_register(struct xar *, struct file *);
-static void file_init_register(struct xar *);
-static void file_free_register(struct xar *);
-static int file_register_hardlink(struct archive_write *,
- struct file *);
-static void file_connect_hardlink_files(struct xar *);
-static void file_init_hardlinks(struct xar *);
-static void file_free_hardlinks(struct xar *);
-
-static void checksum_init(struct chksumwork *, enum sumalg);
-static void checksum_update(struct chksumwork *, const void *, size_t);
-static void checksum_final(struct chksumwork *, struct chksumval *);
-static int compression_init_encoder_gzip(struct archive *,
- struct la_zstream *, int, int);
-static int compression_code_gzip(struct archive *,
- struct la_zstream *, enum la_zaction);
-static int compression_end_gzip(struct archive *, struct la_zstream *);
-static int compression_init_encoder_bzip2(struct archive *,
- struct la_zstream *, int);
-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
-static int compression_code_bzip2(struct archive *,
- struct la_zstream *, enum la_zaction);
-static int compression_end_bzip2(struct archive *, struct la_zstream *);
-#endif
-static int compression_init_encoder_lzma(struct archive *,
- struct la_zstream *, int);
-static int compression_init_encoder_xz(struct archive *,
- struct la_zstream *, int);
-#if defined(HAVE_LZMA_H)
-static int compression_code_lzma(struct archive *,
- struct la_zstream *, enum la_zaction);
-static int compression_end_lzma(struct archive *, struct la_zstream *);
-#endif
-static int xar_compression_init_encoder(struct archive_write *);
-static int compression_code(struct archive *,
- struct la_zstream *, enum la_zaction);
-static int compression_end(struct archive *,
- struct la_zstream *);
-static int save_xattrs(struct archive_write *, struct file *);
-static int getalgsize(enum sumalg);
-static const char *getalgname(enum sumalg);
-
-int
-archive_write_set_format_xar(struct archive *_a)
-{
- struct archive_write *a = (struct archive_write *)_a;
- struct xar *xar;
-
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_set_format_xar");
-
- /* If another format was already registered, unregister it. */
- if (a->format_free != NULL)
- (a->format_free)(a);
-
- xar = calloc(1, sizeof(*xar));
- if (xar == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate xar data");
- return (ARCHIVE_FATAL);
- }
- xar->temp_fd = -1;
- file_init_register(xar);
- file_init_hardlinks(xar);
- archive_string_init(&(xar->tstr));
- archive_string_init(&(xar->vstr));
-
- /*
- * Create the root directory.
- */
- xar->root = file_create_virtual_dir(a, xar, "");
- if (xar->root == NULL) {
- free(xar);
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate xar data");
- return (ARCHIVE_FATAL);
- }
- xar->root->parent = xar->root;
- file_register(xar, xar->root);
- xar->cur_dirent = xar->root;
- archive_string_init(&(xar->cur_dirstr));
- archive_string_ensure(&(xar->cur_dirstr), 1);
- xar->cur_dirstr.s[0] = 0;
-
- /*
- * Initialize option.
- */
- /* Set default checksum type. */
- xar->opt_toc_sumalg = CKSUM_SHA1;
- xar->opt_sumalg = CKSUM_SHA1;
- /* Set default compression type and level. */
- xar->opt_compression = GZIP;
- xar->opt_compression_level = 6;
-
- a->format_data = xar;
-
- a->format_name = "xar";
- a->format_options = xar_options;
- a->format_write_header = xar_write_header;
- a->format_write_data = xar_write_data;
- a->format_finish_entry = xar_finish_entry;
- a->format_close = xar_close;
- a->format_free = xar_free;
- a->archive.archive_format = ARCHIVE_FORMAT_XAR;
- a->archive.archive_format_name = "xar";
-
- return (ARCHIVE_OK);
-}
-
-static int
-xar_options(struct archive_write *a, const char *key, const char *value)
-{
- struct xar *xar;
-
- xar = (struct xar *)a->format_data;
-
- if (strcmp(key, "checksum") == 0) {
- if (value == NULL)
- xar->opt_sumalg = CKSUM_NONE;
- else if (strcmp(value, "sha1") == 0)
- xar->opt_sumalg = CKSUM_SHA1;
- else if (strcmp(value, "md5") == 0)
- xar->opt_sumalg = CKSUM_MD5;
- else {
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "Unknown checksum name: `%s'",
- value);
- return (ARCHIVE_FAILED);
- }
- return (ARCHIVE_OK);
- }
- if (strcmp(key, "compression") == 0) {
- const char *name = NULL;
-
- if (value == NULL)
- xar->opt_compression = NONE;
- else if (strcmp(value, "gzip") == 0)
- xar->opt_compression = GZIP;
- else if (strcmp(value, "bzip2") == 0)
-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
- xar->opt_compression = BZIP2;
-#else
- name = "bzip2";
-#endif
- else if (strcmp(value, "lzma") == 0)
-#if HAVE_LZMA_H
- xar->opt_compression = LZMA;
-#else
- name = "lzma";
-#endif
- else if (strcmp(value, "xz") == 0)
-#if HAVE_LZMA_H
- xar->opt_compression = XZ;
-#else
- name = "xz";
-#endif
- else {
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "Unknown compression name: `%s'",
- value);
- return (ARCHIVE_FAILED);
- }
- if (name != NULL) {
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "`%s' compression not supported "
- "on this platform",
- name);
- return (ARCHIVE_FAILED);
- }
- return (ARCHIVE_OK);
- }
- if (strcmp(key, "compression-level") == 0) {
- if (value == NULL ||
- !(value[0] >= '0' && value[0] <= '9') ||
- value[1] != '\0') {
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "Illegal value `%s'",
- value);
- return (ARCHIVE_FAILED);
- }
- xar->opt_compression_level = value[0] - '0';
- return (ARCHIVE_OK);
- }
- if (strcmp(key, "toc-checksum") == 0) {
- if (value == NULL)
- xar->opt_toc_sumalg = CKSUM_NONE;
- else if (strcmp(value, "sha1") == 0)
- xar->opt_toc_sumalg = CKSUM_SHA1;
- else if (strcmp(value, "md5") == 0)
- xar->opt_toc_sumalg = CKSUM_MD5;
- else {
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "Unknown checksum name: `%s'",
- value);
- return (ARCHIVE_FAILED);
- }
- return (ARCHIVE_OK);
- }
-
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
-}
-
-static int
-xar_write_header(struct archive_write *a, struct archive_entry *entry)
-{
- struct xar *xar;
- struct file *file;
- struct archive_entry *file_entry;
- int r, r2;
-
- xar = (struct xar *)a->format_data;
- xar->cur_file = NULL;
- xar->bytes_remaining = 0;
-
- if (xar->sconv == NULL) {
- xar->sconv = archive_string_conversion_to_charset(
- &a->archive, "UTF-8", 1);
- if (xar->sconv == NULL)
- return (ARCHIVE_FATAL);
- }
-
- file = file_new(a, entry);
- if (file == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate data");
- return (ARCHIVE_FATAL);
- }
- r2 = file_gen_utility_names(a, file);
- if (r2 < ARCHIVE_WARN)
- return (r2);
-
- /*
- * Ignore a path which looks like the top of directory name
- * since we have already made the root directory of an Xar archive.
- */
- if (archive_strlen(&(file->parentdir)) == 0 &&
- archive_strlen(&(file->basename)) == 0) {
- file_free(file);
- return (r2);
- }
-
- /* Add entry into tree */
- file_entry = file->entry;
- r = file_tree(a, &file);
- if (r != ARCHIVE_OK)
- return (r);
- /* There is the same file in tree and
- * the current file is older than the file in tree.
- * So we don't need the current file data anymore. */
- if (file->entry != file_entry)
- return (r2);
- if (file->id == 0)
- file_register(xar, file);
-
- /* A virtual file, which is a directory, does not have
- * any contents and we won't store it into a archive
- * file other than its name. */
- if (file->virtual)
- return (r2);
-
- /*
- * Prepare to save the contents of the file.
- */
- if (xar->temp_fd == -1) {
- int algsize;
- xar->temp_offset = 0;
- xar->temp_fd = __archive_mktemp(NULL);
- if (xar->temp_fd < 0) {
- archive_set_error(&a->archive, errno,
- "Couldn't create temporary file");
- return (ARCHIVE_FATAL);
- }
- algsize = getalgsize(xar->opt_toc_sumalg);
- if (algsize > 0) {
- if (lseek(xar->temp_fd, algsize, SEEK_SET) < 0) {
- archive_set_error(&(a->archive), errno,
- "lseek failed");
- return (ARCHIVE_FATAL);
- }
- xar->temp_offset = algsize;
- }
- }
-
- if (archive_entry_hardlink(file->entry) == NULL) {
- r = save_xattrs(a, file);
- if (r != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
-
- /* Non regular files contents are unneeded to be saved to
- * a temporary file. */
- if (archive_entry_filetype(file->entry) != AE_IFREG)
- return (r2);
-
- /*
- * Set the current file to cur_file to read its contents.
- */
- xar->cur_file = file;
-
- if (archive_entry_nlink(file->entry) > 1) {
- r = file_register_hardlink(a, file);
- if (r != ARCHIVE_OK)
- return (r);
- if (archive_entry_hardlink(file->entry) != NULL) {
- archive_entry_unset_size(file->entry);
- return (r2);
- }
- }
-
- /* Save a offset of current file in temporary file. */
- file->data.temp_offset = xar->temp_offset;
- file->data.size = archive_entry_size(file->entry);
- file->data.compression = xar->opt_compression;
- xar->bytes_remaining = archive_entry_size(file->entry);
- checksum_init(&(xar->a_sumwrk), xar->opt_sumalg);
- checksum_init(&(xar->e_sumwrk), xar->opt_sumalg);
- r = xar_compression_init_encoder(a);
-
- if (r != ARCHIVE_OK)
- return (r);
- else
- return (r2);
-}
-
-static int
-write_to_temp(struct archive_write *a, const void *buff, size_t s)
-{
- struct xar *xar;
- const unsigned char *p;
- ssize_t ws;
-
- xar = (struct xar *)a->format_data;
- p = (const unsigned char *)buff;
- while (s) {
- ws = write(xar->temp_fd, p, s);
- if (ws < 0) {
- archive_set_error(&(a->archive), errno,
- "fwrite function failed");
- return (ARCHIVE_FATAL);
- }
- s -= ws;
- p += ws;
- xar->temp_offset += ws;
- }
- return (ARCHIVE_OK);
-}
-
-static ssize_t
-xar_write_data(struct archive_write *a, const void *buff, size_t s)
-{
- struct xar *xar;
- enum la_zaction run;
- size_t size, rsize;
- int r;
-
- xar = (struct xar *)a->format_data;
-
- if (s > xar->bytes_remaining)
- s = (size_t)xar->bytes_remaining;
- if (s == 0 || xar->cur_file == NULL)
- return (0);
- if (xar->cur_file->data.compression == NONE) {
- checksum_update(&(xar->e_sumwrk), buff, s);
- checksum_update(&(xar->a_sumwrk), buff, s);
- size = rsize = s;
- } else {
- xar->stream.next_in = (const unsigned char *)buff;
- xar->stream.avail_in = s;
- if (xar->bytes_remaining > s)
- run = ARCHIVE_Z_RUN;
- else
- run = ARCHIVE_Z_FINISH;
- /* Compress file data. */
- r = compression_code(&(a->archive), &(xar->stream), run);
- if (r != ARCHIVE_OK && r != ARCHIVE_EOF)
- return (ARCHIVE_FATAL);
- rsize = s - xar->stream.avail_in;
- checksum_update(&(xar->e_sumwrk), buff, rsize);
- size = sizeof(xar->wbuff) - xar->stream.avail_out;
- checksum_update(&(xar->a_sumwrk), xar->wbuff, size);
- }
-#if !defined(_WIN32) || defined(__CYGWIN__)
- if (xar->bytes_remaining ==
- (uint64_t)archive_entry_size(xar->cur_file->entry)) {
- /*
- * Get the path of a shell script if so.
- */
- const unsigned char *b = (const unsigned char *)buff;
-
- archive_string_empty(&(xar->cur_file->script));
- if (rsize > 2 && b[0] == '#' && b[1] == '!') {
- size_t i, end, off;
-
- off = 2;
- if (b[off] == ' ')
- off++;
-#ifdef PATH_MAX
- if ((rsize - off) > PATH_MAX)
- end = off + PATH_MAX;
- else
-#endif
- end = rsize;
- /* Find the end of a script path. */
- for (i = off; i < end && b[i] != '\0' &&
- b[i] != '\n' && b[i] != '\r' &&
- b[i] != ' ' && b[i] != '\t'; i++)
- ;
- archive_strncpy(&(xar->cur_file->script), b + off,
- i - off);
- }
- }
-#endif
-
- if (xar->cur_file->data.compression == NONE) {
- if (write_to_temp(a, buff, size) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- } else {
- if (write_to_temp(a, xar->wbuff, size) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
- xar->bytes_remaining -= rsize;
- xar->cur_file->data.length += size;
-
- return (rsize);
-}
-
-static int
-xar_finish_entry(struct archive_write *a)
-{
- struct xar *xar;
- struct file *file;
- size_t s;
- ssize_t w;
-
- xar = (struct xar *)a->format_data;
- if (xar->cur_file == NULL)
- return (ARCHIVE_OK);
-
- while (xar->bytes_remaining > 0) {
- s = (size_t)xar->bytes_remaining;
- if (s > a->null_length)
- s = a->null_length;
- w = xar_write_data(a, a->nulls, s);
- if (w > 0)
- xar->bytes_remaining -= w;
- else
- return (w);
- }
- file = xar->cur_file;
- checksum_final(&(xar->e_sumwrk), &(file->data.e_sum));
- checksum_final(&(xar->a_sumwrk), &(file->data.a_sum));
- xar->cur_file = NULL;
-
- return (ARCHIVE_OK);
-}
-
-static int
-xmlwrite_string_attr(struct archive_write *a, xmlTextWriterPtr writer,
- const char *key, const char *value,
- const char *attrkey, const char *attrvalue)
-{
- int r;
-
- r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(key));
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
- if (attrkey != NULL && attrvalue != NULL) {
- r = xmlTextWriterWriteAttribute(writer,
- BAD_CAST_CONST(attrkey), BAD_CAST_CONST(attrvalue));
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterWriteAttribute() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
- }
- if (value != NULL) {
- r = xmlTextWriterWriteString(writer, BAD_CAST_CONST(value));
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterWriteString() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
- }
- r = xmlTextWriterEndElement(writer);
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndElement() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
- return (ARCHIVE_OK);
-}
-
-static int
-xmlwrite_string(struct archive_write *a, xmlTextWriterPtr writer,
- const char *key, const char *value)
-{
- int r;
-
- if (value == NULL)
- return (ARCHIVE_OK);
-
- r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(key));
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
- if (value != NULL) {
- r = xmlTextWriterWriteString(writer, BAD_CAST_CONST(value));
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterWriteString() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
- }
- r = xmlTextWriterEndElement(writer);
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndElement() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
- return (ARCHIVE_OK);
-}
-
-static int
-xmlwrite_fstring(struct archive_write *a, xmlTextWriterPtr writer,
- const char *key, const char *fmt, ...)
-{
- struct xar *xar;
- va_list ap;
-
- xar = (struct xar *)a->format_data;
- va_start(ap, fmt);
- archive_string_empty(&xar->vstr);
- archive_string_vsprintf(&xar->vstr, fmt, ap);
- va_end(ap);
- return (xmlwrite_string(a, writer, key, xar->vstr.s));
-}
-
-static int
-xmlwrite_time(struct archive_write *a, xmlTextWriterPtr writer,
- const char *key, time_t t, int z)
-{
- char timestr[100];
- struct tm tm;
-
-#if defined(HAVE_GMTIME_R)
- gmtime_r(&t, &tm);
-#elif defined(HAVE__GMTIME64_S)
- _gmtime64_s(&tm, &t);
-#else
- memcpy(&tm, gmtime(&t), sizeof(tm));
-#endif
- memset(&timestr, 0, sizeof(timestr));
- /* Do not use %F and %T for portability. */
- strftime(timestr, sizeof(timestr), "%Y-%m-%dT%H:%M:%S", &tm);
- if (z)
- strcat(timestr, "Z");
- return (xmlwrite_string(a, writer, key, timestr));
-}
-
-static int
-xmlwrite_mode(struct archive_write *a, xmlTextWriterPtr writer,
- const char *key, mode_t mode)
-{
- char ms[5];
-
- ms[0] = '0';
- ms[1] = '0' + ((mode >> 6) & 07);
- ms[2] = '0' + ((mode >> 3) & 07);
- ms[3] = '0' + (mode & 07);
- ms[4] = '\0';
-
- return (xmlwrite_string(a, writer, key, ms));
-}
-
-static int
-xmlwrite_sum(struct archive_write *a, xmlTextWriterPtr writer,
- const char *key, struct chksumval *sum)
-{
- const char *algname;
- int algsize;
- char buff[MAX_SUM_SIZE*2 + 1];
- char *p;
- unsigned char *s;
- int i, r;
-
- if (sum->len > 0) {
- algname = getalgname(sum->alg);
- algsize = getalgsize(sum->alg);
- if (algname != NULL) {
- const char *hex = "0123456789abcdef";
- p = buff;
- s = sum->val;
- for (i = 0; i < algsize; i++) {
- *p++ = hex[(*s >> 4)];
- *p++ = hex[(*s & 0x0f)];
- s++;
- }
- *p = '\0';
- r = xmlwrite_string_attr(a, writer,
- key, buff,
- "style", algname);
- if (r < 0)
- return (ARCHIVE_FATAL);
- }
- }
- return (ARCHIVE_OK);
-}
-
-static int
-xmlwrite_heap(struct archive_write *a, xmlTextWriterPtr writer,
- struct heap_data *heap)
-{
- const char *encname;
- int r;
-
- r = xmlwrite_fstring(a, writer, "length", "%ju", heap->length);
- if (r < 0)
- return (ARCHIVE_FATAL);
- r = xmlwrite_fstring(a, writer, "offset", "%ju", heap->temp_offset);
- if (r < 0)
- return (ARCHIVE_FATAL);
- r = xmlwrite_fstring(a, writer, "size", "%ju", heap->size);
- if (r < 0)
- return (ARCHIVE_FATAL);
- switch (heap->compression) {
- case GZIP:
- encname = "application/x-gzip"; break;
- case BZIP2:
- encname = "application/x-bzip2"; break;
- case LZMA:
- encname = "application/x-lzma"; break;
- case XZ:
- encname = "application/x-xz"; break;
- default:
- encname = "application/octet-stream"; break;
- }
- r = xmlwrite_string_attr(a, writer, "encoding", NULL,
- "style", encname);
- if (r < 0)
- return (ARCHIVE_FATAL);
- r = xmlwrite_sum(a, writer, "archived-checksum", &(heap->a_sum));
- if (r < 0)
- return (ARCHIVE_FATAL);
- r = xmlwrite_sum(a, writer, "extracted-checksum", &(heap->e_sum));
- if (r < 0)
- return (ARCHIVE_FATAL);
- return (ARCHIVE_OK);
-}
-
-/*
- * xar utility records fflags as following xml elements:
- * <flags>
- * <UserNoDump/>
- * .....
- * </flags>
- * or
- * <ext2>
- * <NoDump/>
- * .....
- * </ext2>
- * If xar is running on BSD platform, records <flags>..</flags>;
- * if xar is running on linux platform, records <ext2>..</ext2>;
- * otherwise does not record.
- *
- * Our implements records both <flags> and <ext2> if it's necessary.
- */
-static int
-make_fflags_entry(struct archive_write *a, xmlTextWriterPtr writer,
- const char *element, const char *fflags_text)
-{
- static const struct flagentry {
- const char *name;
- const char *xarname;
- }
- flagbsd[] = {
- { "sappnd", "SystemAppend"},
- { "sappend", "SystemAppend"},
- { "arch", "SystemArchived"},
- { "archived", "SystemArchived"},
- { "schg", "SystemImmutable"},
- { "schange", "SystemImmutable"},
- { "simmutable", "SystemImmutable"},
- { "nosunlnk", "SystemNoUnlink"},
- { "nosunlink", "SystemNoUnlink"},
- { "snapshot", "SystemSnapshot"},
- { "uappnd", "UserAppend"},
- { "uappend", "UserAppend"},
- { "uchg", "UserImmutable"},
- { "uchange", "UserImmutable"},
- { "uimmutable", "UserImmutable"},
- { "nodump", "UserNoDump"},
- { "noopaque", "UserOpaque"},
- { "nouunlnk", "UserNoUnlink"},
- { "nouunlink", "UserNoUnlink"},
- { NULL, NULL}
- },
- flagext2[] = {
- { "sappnd", "AppendOnly"},
- { "sappend", "AppendOnly"},
- { "schg", "Immutable"},
- { "schange", "Immutable"},
- { "simmutable", "Immutable"},
- { "nodump", "NoDump"},
- { "nouunlnk", "Undelete"},
- { "nouunlink", "Undelete"},
- { "btree", "BTree"},
- { "comperr", "CompError"},
- { "compress", "Compress"},
- { "noatime", "NoAtime"},
- { "compdirty", "CompDirty"},
- { "comprblk", "CompBlock"},
- { "dirsync", "DirSync"},
- { "hashidx", "HashIndexed"},
- { "imagic", "iMagic"},
- { "journal", "Journaled"},
- { "securedeletion", "SecureDeletion"},
- { "sync", "Synchronous"},
- { "notail", "NoTail"},
- { "topdir", "TopDir"},
- { "reserved", "Reserved"},
- { NULL, NULL}
- };
- const struct flagentry *fe, *flagentry;
-#define FLAGENTRY_MAXSIZE ((sizeof(flagbsd)+sizeof(flagext2))/sizeof(flagbsd))
- const struct flagentry *avail[FLAGENTRY_MAXSIZE];
- const char *p;
- int i, n, r;
-
- if (strcmp(element, "ext2") == 0)
- flagentry = flagext2;
- else
- flagentry = flagbsd;
- n = 0;
- p = fflags_text;
- do {
- const char *cp;
-
- cp = strchr(p, ',');
- if (cp == NULL)
- cp = p + strlen(p);
-
- for (fe = flagentry; fe->name != NULL; fe++) {
- if (fe->name[cp - p] != '\0'
- || p[0] != fe->name[0])
- continue;
- if (strncmp(p, fe->name, cp - p) == 0) {
- avail[n++] = fe;
- break;
- }
- }
- if (*cp == ',')
- p = cp + 1;
- else
- p = NULL;
- } while (p != NULL);
-
- if (n > 0) {
- r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(element));
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
- for (i = 0; i < n; i++) {
- r = xmlwrite_string(a, writer,
- avail[i]->xarname, NULL);
- if (r != ARCHIVE_OK)
- return (r);
- }
-
- r = xmlTextWriterEndElement(writer);
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndElement() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
- }
- return (ARCHIVE_OK);
-}
-
-static int
-make_file_entry(struct archive_write *a, xmlTextWriterPtr writer,
- struct file *file)
-{
- struct xar *xar;
- const char *filetype, *filelink, *fflags;
- struct archive_string linkto;
- struct heap_data *heap;
- unsigned char *tmp;
- const char *p;
- size_t len;
- int r, r2, l, ll;
-
- xar = (struct xar *)a->format_data;
- r2 = ARCHIVE_OK;
-
- /*
- * Make a file name entry, "<name>".
- */
- l = ll = archive_strlen(&(file->basename));
- tmp = malloc(l);
- if (tmp == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- r = UTF8Toisolat1(tmp, &l, BAD_CAST(file->basename.s), &ll);
- free(tmp);
- if (r < 0) {
- r = xmlTextWriterStartElement(writer, BAD_CAST("name"));
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
- r = xmlTextWriterWriteAttribute(writer,
- BAD_CAST("enctype"), BAD_CAST("base64"));
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterWriteAttribute() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
- r = xmlTextWriterWriteBase64(writer, file->basename.s,
- 0, archive_strlen(&(file->basename)));
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterWriteBase64() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
- r = xmlTextWriterEndElement(writer);
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndElement() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
- } else {
- r = xmlwrite_string(a, writer, "name", file->basename.s);
- if (r < 0)
- return (ARCHIVE_FATAL);
- }
-
- /*
- * Make a file type entry, "<type>".
- */
- filelink = NULL;
- archive_string_init(&linkto);
- switch (archive_entry_filetype(file->entry)) {
- case AE_IFDIR:
- filetype = "directory"; break;
- case AE_IFLNK:
- filetype = "symlink"; break;
- case AE_IFCHR:
- filetype = "character special"; break;
- case AE_IFBLK:
- filetype = "block special"; break;
- case AE_IFSOCK:
- filetype = "socket"; break;
- case AE_IFIFO:
- filetype = "fifo"; break;
- case AE_IFREG:
- default:
- if (file->hardlink_target != NULL) {
- filetype = "hardlink";
- filelink = "link";
- if (file->hardlink_target == file)
- archive_strcpy(&linkto, "original");
- else
- archive_string_sprintf(&linkto, "%d",
- file->hardlink_target->id);
- } else
- filetype = "file";
- break;
- }
- r = xmlwrite_string_attr(a, writer, "type", filetype,
- filelink, linkto.s);
- archive_string_free(&linkto);
- if (r < 0)
- return (ARCHIVE_FATAL);
-
- /*
- * On a virtual directory, we record "name" and "type" only.
- */
- if (file->virtual)
- return (ARCHIVE_OK);
-
- switch (archive_entry_filetype(file->entry)) {
- case AE_IFLNK:
- /*
- * xar utility has checked a file type, which
- * a symblic-link file has referenced.
- * For example:
- * <link type="directory">../ref/</link>
- * The symlink target file is "../ref/" and its
- * file type is a directory.
- *
- * <link type="file">../f</link>
- * The symlink target file is "../f" and its
- * file type is a regular file.
- *
- * But our implemention cannot do it, and then we
- * always record that a attribute "type" is "borken",
- * for example:
- * <link type="broken">foo/bar</link>
- * It means "foo/bar" is not reachable.
- */
- r = xmlwrite_string_attr(a, writer, "link",
- file->symlink.s,
- "type", "broken");
- if (r < 0)
- return (ARCHIVE_FATAL);
- break;
- case AE_IFCHR:
- case AE_IFBLK:
- r = xmlTextWriterStartElement(writer, BAD_CAST("device"));
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
- r = xmlwrite_fstring(a, writer, "major",
- "%d", archive_entry_rdevmajor(file->entry));
- if (r < 0)
- return (ARCHIVE_FATAL);
- r = xmlwrite_fstring(a, writer, "minor",
- "%d", archive_entry_rdevminor(file->entry));
- if (r < 0)
- return (ARCHIVE_FATAL);
- r = xmlTextWriterEndElement(writer);
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndElement() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
- break;
- default:
- break;
- }
-
- /*
- * Make a inode entry, "<inode>".
- */
- r = xmlwrite_fstring(a, writer, "inode",
- "%jd", archive_entry_ino64(file->entry));
- if (r < 0)
- return (ARCHIVE_FATAL);
- if (archive_entry_dev(file->entry) != 0) {
- r = xmlwrite_fstring(a, writer, "deviceno",
- "%d", archive_entry_dev(file->entry));
- if (r < 0)
- return (ARCHIVE_FATAL);
- }
-
- /*
- * Make a file mode entry, "<mode>".
- */
- r = xmlwrite_mode(a, writer, "mode",
- archive_entry_mode(file->entry));
- if (r < 0)
- return (ARCHIVE_FATAL);
-
- /*
- * Make a user entry, "<uid>" and "<user>.
- */
- r = xmlwrite_fstring(a, writer, "uid",
- "%d", archive_entry_uid(file->entry));
- if (r < 0)
- return (ARCHIVE_FATAL);
- r = archive_entry_uname_l(file->entry, &p, &len, xar->sconv);
- if (r != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Uname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate uname '%s' to UTF-8",
- archive_entry_uname(file->entry));
- r2 = ARCHIVE_WARN;
- }
- if (len > 0) {
- r = xmlwrite_string(a, writer, "user", p);
- if (r < 0)
- return (ARCHIVE_FATAL);
- }
-
- /*
- * Make a group entry, "<gid>" and "<group>.
- */
- r = xmlwrite_fstring(a, writer, "gid",
- "%d", archive_entry_gid(file->entry));
- if (r < 0)
- return (ARCHIVE_FATAL);
- r = archive_entry_gname_l(file->entry, &p, &len, xar->sconv);
- if (r != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Gname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate gname '%s' to UTF-8",
- archive_entry_gname(file->entry));
- r2 = ARCHIVE_WARN;
- }
- if (len > 0) {
- r = xmlwrite_string(a, writer, "group", p);
- if (r < 0)
- return (ARCHIVE_FATAL);
- }
-
- /*
- * Make a ctime entry, "<ctime>".
- */
- if (archive_entry_ctime_is_set(file->entry)) {
- r = xmlwrite_time(a, writer, "ctime",
- archive_entry_ctime(file->entry), 1);
- if (r < 0)
- return (ARCHIVE_FATAL);
- }
-
- /*
- * Make a mtime entry, "<mtime>".
- */
- if (archive_entry_mtime_is_set(file->entry)) {
- r = xmlwrite_time(a, writer, "mtime",
- archive_entry_mtime(file->entry), 1);
- if (r < 0)
- return (ARCHIVE_FATAL);
- }
-
- /*
- * Make a atime entry, "<atime>".
- */
- if (archive_entry_atime_is_set(file->entry)) {
- r = xmlwrite_time(a, writer, "atime",
- archive_entry_atime(file->entry), 1);
- if (r < 0)
- return (ARCHIVE_FATAL);
- }
-
- /*
- * Make fflags entries, "<flags>" and "<ext2>".
- */
- fflags = archive_entry_fflags_text(file->entry);
- if (fflags != NULL) {
- r = make_fflags_entry(a, writer, "flags", fflags);
- if (r < 0)
- return (r);
- r = make_fflags_entry(a, writer, "ext2", fflags);
- if (r < 0)
- return (r);
- }
-
- /*
- * Make extended attribute entries, "<ea>".
- */
- archive_entry_xattr_reset(file->entry);
- for (heap = file->xattr.first; heap != NULL; heap = heap->next) {
- const char *name;
- const void *value;
- size_t size;
-
- archive_entry_xattr_next(file->entry,
- &name, &value, &size);
- r = xmlTextWriterStartElement(writer, BAD_CAST("ea"));
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
- r = xmlTextWriterWriteFormatAttribute(writer,
- BAD_CAST("id"), "%d", heap->id);
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterWriteAttribute() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
- r = xmlwrite_heap(a, writer, heap);
- if (r < 0)
- return (ARCHIVE_FATAL);
- r = xmlwrite_string(a, writer, "name", name);
- if (r < 0)
- return (ARCHIVE_FATAL);
-
- r = xmlTextWriterEndElement(writer);
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndElement() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
- }
-
- /*
- * Make a file data entry, "<data>".
- */
- if (file->data.length > 0) {
- r = xmlTextWriterStartElement(writer, BAD_CAST("data"));
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
-
- r = xmlwrite_heap(a, writer, &(file->data));
- if (r < 0)
- return (ARCHIVE_FATAL);
-
- r = xmlTextWriterEndElement(writer);
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndElement() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
- }
-
- if (archive_strlen(&file->script) > 0) {
- r = xmlTextWriterStartElement(writer, BAD_CAST("content"));
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
-
- r = xmlwrite_string(a, writer,
- "interpreter", file->script.s);
- if (r < 0)
- return (ARCHIVE_FATAL);
-
- r = xmlwrite_string(a, writer, "type", "script");
- if (r < 0)
- return (ARCHIVE_FATAL);
-
- r = xmlTextWriterEndElement(writer);
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndElement() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
- }
-
- return (r2);
-}
-
-/*
- * Make the TOC
- */
-static int
-make_toc(struct archive_write *a)
-{
- struct xar *xar;
- struct file *np;
- xmlBufferPtr bp;
- xmlTextWriterPtr writer;
- int algsize;
- int r, ret;
-
- xar = (struct xar *)a->format_data;
-
- ret = ARCHIVE_FATAL;
-
- /*
- * Initialize xml writer.
- */
- writer = NULL;
- bp = xmlBufferCreate();
- if (bp == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "xmlBufferCreate() "
- "couldn't create xml buffer");
- goto exit_toc;
- }
- writer = xmlNewTextWriterMemory(bp, 0);
- if (writer == NULL) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlNewTextWriterMemory() "
- "couldn't create xml writer");
- goto exit_toc;
- }
- r = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL);
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartDocument() failed: %d", r);
- goto exit_toc;
- }
- r = xmlTextWriterSetIndent(writer, 4);
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterSetIndent() failed: %d", r);
- goto exit_toc;
- }
-
- /*
- * Start recoding TOC
- */
- r = xmlTextWriterStartElement(writer, BAD_CAST("xar"));
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() failed: %d", r);
- goto exit_toc;
- }
- r = xmlTextWriterStartElement(writer, BAD_CAST("toc"));
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartDocument() failed: %d", r);
- goto exit_toc;
- }
-
- /*
- * Record the creation time of the archive file.
- */
- r = xmlwrite_time(a, writer, "creation-time", time(NULL), 0);
- if (r < 0)
- goto exit_toc;
-
- /*
- * Record the checksum value of TOC
- */
- algsize = getalgsize(xar->opt_toc_sumalg);
- if (algsize) {
- /*
- * Record TOC checksum
- */
- r = xmlTextWriterStartElement(writer, BAD_CAST("checksum"));
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() failed: %d", r);
- goto exit_toc;
- }
- r = xmlTextWriterWriteAttribute(writer, BAD_CAST("style"),
- BAD_CAST_CONST(getalgname(xar->opt_toc_sumalg)));
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterWriteAttribute() failed: %d", r);
- goto exit_toc;
- }
-
- /*
- * Record the offset of the value of checksum of TOC
- */
- r = xmlwrite_string(a, writer, "offset", "0");
- if (r < 0)
- goto exit_toc;
-
- /*
- * Record the size of the value of checksum of TOC
- */
- r = xmlwrite_fstring(a, writer, "size", "%d", algsize);
- if (r < 0)
- goto exit_toc;
-
- r = xmlTextWriterEndElement(writer);
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndElement() failed: %d", r);
- goto exit_toc;
- }
- }
-
- np = xar->root;
- do {
- if (np != np->parent) {
- r = make_file_entry(a, writer, np);
- if (r != ARCHIVE_OK)
- goto exit_toc;
- }
-
- if (np->dir && np->children.first != NULL) {
- /* Enter to sub directories. */
- np = np->children.first;
- r = xmlTextWriterStartElement(writer,
- BAD_CAST("file"));
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() "
- "failed: %d", r);
- goto exit_toc;
- }
- r = xmlTextWriterWriteFormatAttribute(
- writer, BAD_CAST("id"), "%d", np->id);
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterWriteAttribute() "
- "failed: %d", r);
- goto exit_toc;
- }
- continue;
- }
- while (np != np->parent) {
- r = xmlTextWriterEndElement(writer);
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndElement() "
- "failed: %d", r);
- goto exit_toc;
- }
- if (np->chnext == NULL) {
- /* Return to the parent directory. */
- np = np->parent;
- } else {
- np = np->chnext;
- r = xmlTextWriterStartElement(writer,
- BAD_CAST("file"));
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() "
- "failed: %d", r);
- goto exit_toc;
- }
- r = xmlTextWriterWriteFormatAttribute(
- writer, BAD_CAST("id"), "%d", np->id);
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterWriteAttribute() "
- "failed: %d", r);
- goto exit_toc;
- }
- break;
- }
- }
- } while (np != np->parent);
-
- r = xmlTextWriterEndDocument(writer);
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndDocument() failed: %d", r);
- goto exit_toc;
- }
-#if DEBUG_PRINT_TOC
- fprintf(stderr, "\n---TOC-- %d bytes --\n%s\n",
- strlen((const char *)bp->content), bp->content);
-#endif
-
- /*
- * Compress the TOC and calculate the sum of the TOC.
- */
- xar->toc.temp_offset = xar->temp_offset;
- xar->toc.size = bp->use;
- checksum_init(&(xar->a_sumwrk), xar->opt_toc_sumalg);
-
- r = compression_init_encoder_gzip(&(a->archive),
- &(xar->stream), 6, 1);
- if (r != ARCHIVE_OK)
- goto exit_toc;
- xar->stream.next_in = bp->content;
- xar->stream.avail_in = bp->use;
- xar->stream.total_in = 0;
- xar->stream.next_out = xar->wbuff;
- xar->stream.avail_out = sizeof(xar->wbuff);
- xar->stream.total_out = 0;
- for (;;) {
- size_t size;
-
- r = compression_code(&(a->archive),
- &(xar->stream), ARCHIVE_Z_FINISH);
- if (r != ARCHIVE_OK && r != ARCHIVE_EOF)
- goto exit_toc;
- size = sizeof(xar->wbuff) - xar->stream.avail_out;
- checksum_update(&(xar->a_sumwrk), xar->wbuff, size);
- if (write_to_temp(a, xar->wbuff, size) != ARCHIVE_OK)
- goto exit_toc;
- if (r == ARCHIVE_EOF)
- break;
- xar->stream.next_out = xar->wbuff;
- xar->stream.avail_out = sizeof(xar->wbuff);
- }
- r = compression_end(&(a->archive), &(xar->stream));
- if (r != ARCHIVE_OK)
- goto exit_toc;
- xar->toc.length = xar->stream.total_out;
- xar->toc.compression = GZIP;
- checksum_final(&(xar->a_sumwrk), &(xar->toc.a_sum));
-
- ret = ARCHIVE_OK;
-exit_toc:
- if (writer)
- xmlFreeTextWriter(writer);
- if (bp)
- xmlBufferFree(bp);
-
- return (ret);
-}
-
-static int
-flush_wbuff(struct archive_write *a)
-{
- struct xar *xar;
- int r;
- size_t s;
-
- xar = (struct xar *)a->format_data;
- s = sizeof(xar->wbuff) - xar->wbuff_remaining;
- r = __archive_write_output(a, xar->wbuff, s);
- if (r != ARCHIVE_OK)
- return (r);
- xar->wbuff_remaining = sizeof(xar->wbuff);
- return (r);
-}
-
-static int
-copy_out(struct archive_write *a, uint64_t offset, uint64_t length)
-{
- struct xar *xar;
- int r;
-
- xar = (struct xar *)a->format_data;
- if (lseek(xar->temp_fd, offset, SEEK_SET) < 0) {
- archive_set_error(&(a->archive), errno, "lseek failed");
- return (ARCHIVE_FATAL);
- }
- while (length) {
- size_t rsize;
- ssize_t rs;
- unsigned char *wb;
-
- if (length > xar->wbuff_remaining)
- rsize = xar->wbuff_remaining;
- else
- rsize = (size_t)length;
- wb = xar->wbuff + (sizeof(xar->wbuff) - xar->wbuff_remaining);
- rs = read(xar->temp_fd, wb, rsize);
- if (rs < 0) {
- archive_set_error(&(a->archive), errno,
- "Can't read temporary file(%jd)",
- (intmax_t)rs);
- return (ARCHIVE_FATAL);
- }
- if (rs == 0) {
- archive_set_error(&(a->archive), 0,
- "Truncated xar archive");
- return (ARCHIVE_FATAL);
- }
- xar->wbuff_remaining -= rs;
- length -= rs;
- if (xar->wbuff_remaining == 0) {
- r = flush_wbuff(a);
- if (r != ARCHIVE_OK)
- return (r);
- }
- }
- return (ARCHIVE_OK);
-}
-
-static int
-xar_close(struct archive_write *a)
-{
- struct xar *xar;
- unsigned char *wb;
- uint64_t length;
- int r;
-
- xar = (struct xar *)a->format_data;
-
- /* Empty! */
- if (xar->root->children.first == NULL)
- return (ARCHIVE_OK);
-
- /* Save the length of all file extended attributes and contents. */
- length = xar->temp_offset;
-
- /* Connect hardlinked files */
- file_connect_hardlink_files(xar);
-
- /* Make the TOC */
- r = make_toc(a);
- if (r != ARCHIVE_OK)
- return (r);
- /*
- * Make the xar header on wbuff(write buffer).
- */
- wb = xar->wbuff;
- xar->wbuff_remaining = sizeof(xar->wbuff);
- archive_be32enc(&wb[0], HEADER_MAGIC);
- archive_be16enc(&wb[4], HEADER_SIZE);
- archive_be16enc(&wb[6], HEADER_VERSION);
- archive_be64enc(&wb[8], xar->toc.length);
- archive_be64enc(&wb[16], xar->toc.size);
- archive_be32enc(&wb[24], xar->toc.a_sum.alg);
- xar->wbuff_remaining -= HEADER_SIZE;
-
- /*
- * Write the TOC
- */
- r = copy_out(a, xar->toc.temp_offset, xar->toc.length);
- if (r != ARCHIVE_OK)
- return (r);
-
- /* Write the checksum value of the TOC. */
- if (xar->toc.a_sum.len) {
- if (xar->wbuff_remaining < xar->toc.a_sum.len) {
- r = flush_wbuff(a);
- if (r != ARCHIVE_OK)
- return (r);
- }
- wb = xar->wbuff + (sizeof(xar->wbuff) - xar->wbuff_remaining);
- memcpy(wb, xar->toc.a_sum.val, xar->toc.a_sum.len);
- xar->wbuff_remaining -= xar->toc.a_sum.len;
- }
-
- /*
- * Write all file extended attributes and contents.
- */
- r = copy_out(a, xar->toc.a_sum.len, length);
- if (r != ARCHIVE_OK)
- return (r);
- r = flush_wbuff(a);
- return (r);
-}
-
-static int
-xar_free(struct archive_write *a)
-{
- struct xar *xar;
-
- xar = (struct xar *)a->format_data;
- archive_string_free(&(xar->cur_dirstr));
- archive_string_free(&(xar->tstr));
- archive_string_free(&(xar->vstr));
- file_free_hardlinks(xar);
- file_free_register(xar);
- compression_end(&(a->archive), &(xar->stream));
- free(xar);
-
- return (ARCHIVE_OK);
-}
-
-static int
-file_cmp_node(const struct archive_rb_node *n1,
- const struct archive_rb_node *n2)
-{
- const struct file *f1 = (const struct file *)n1;
- const struct file *f2 = (const struct file *)n2;
-
- return (strcmp(f1->basename.s, f2->basename.s));
-}
-
-static int
-file_cmp_key(const struct archive_rb_node *n, const void *key)
-{
- const struct file *f = (const struct file *)n;
-
- return (strcmp(f->basename.s, (const char *)key));
-}
-
-static struct file *
-file_new(struct archive_write *a, struct archive_entry *entry)
-{
- struct file *file;
- static const struct archive_rb_tree_ops rb_ops = {
- file_cmp_node, file_cmp_key
- };
-
- file = calloc(1, sizeof(*file));
- if (file == NULL)
- return (NULL);
-
- if (entry != NULL)
- file->entry = archive_entry_clone(entry);
- else
- file->entry = archive_entry_new2(&a->archive);
- if (file->entry == NULL) {
- free(file);
- return (NULL);
- }
- __archive_rb_tree_init(&(file->rbtree), &rb_ops);
- file->children.first = NULL;
- file->children.last = &(file->children.first);
- file->xattr.first = NULL;
- file->xattr.last = &(file->xattr.first);
- archive_string_init(&(file->parentdir));
- archive_string_init(&(file->basename));
- archive_string_init(&(file->symlink));
- archive_string_init(&(file->script));
- if (entry != NULL && archive_entry_filetype(entry) == AE_IFDIR)
- file->dir = 1;
-
- return (file);
-}
-
-static void
-file_free(struct file *file)
-{
- struct heap_data *heap, *next_heap;
-
- heap = file->xattr.first;
- while (heap != NULL) {
- next_heap = heap->next;
- free(heap);
- heap = next_heap;
- }
- archive_string_free(&(file->parentdir));
- archive_string_free(&(file->basename));
- archive_string_free(&(file->symlink));
- archive_string_free(&(file->script));
- free(file);
-}
-
-static struct file *
-file_create_virtual_dir(struct archive_write *a, struct xar *xar,
- const char *pathname)
-{
- struct file *file;
-
- (void)xar; /* UNUSED */
-
- file = file_new(a, NULL);
- if (file == NULL)
- return (NULL);
- archive_entry_set_pathname(file->entry, pathname);
- archive_entry_set_mode(file->entry, 0555 | AE_IFDIR);
-
- file->dir = 1;
- file->virtual = 1;
-
- return (file);
-}
-
-static int
-file_add_child_tail(struct file *parent, struct file *child)
-{
- if (!__archive_rb_tree_insert_node(
- &(parent->rbtree), (struct archive_rb_node *)child))
- return (0);
- child->chnext = NULL;
- *parent->children.last = child;
- parent->children.last = &(child->chnext);
- child->parent = parent;
- return (1);
-}
-
-/*
- * Find a entry from `parent'
- */
-static struct file *
-file_find_child(struct file *parent, const char *child_name)
-{
- struct file *np;
-
- np = (struct file *)__archive_rb_tree_find_node(
- &(parent->rbtree), child_name);
- return (np);
-}
-
-#if defined(_WIN32) || defined(__CYGWIN__)
-static void
-cleanup_backslash(char *utf8, size_t len)
-{
-
- /* Convert a path-separator from '\' to '/' */
- while (*utf8 != '\0' && len) {
- if (*utf8 == '\\')
- *utf8 = '/';
- ++utf8;
- --len;
- }
-}
-#else
-#define cleanup_backslash(p, len) /* nop */
-#endif
-
-/*
- * Generate a parent directory name and a base name from a pathname.
- */
-static int
-file_gen_utility_names(struct archive_write *a, struct file *file)
-{
- struct xar *xar;
- const char *pp;
- char *p, *dirname, *slash;
- size_t len;
- int r = ARCHIVE_OK;
-
- xar = (struct xar *)a->format_data;
- archive_string_empty(&(file->parentdir));
- archive_string_empty(&(file->basename));
- archive_string_empty(&(file->symlink));
-
- if (file->parent == file)/* virtual root */
- return (ARCHIVE_OK);
-
- if (archive_entry_pathname_l(file->entry, &pp, &len, xar->sconv)
- != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Pathname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate pathname '%s' to UTF-8",
- archive_entry_pathname(file->entry));
- r = ARCHIVE_WARN;
- }
- archive_strncpy(&(file->parentdir), pp, len);
- len = file->parentdir.length;
- p = dirname = file->parentdir.s;
- /*
- * Convert a path-separator from '\' to '/'
- */
- cleanup_backslash(p, len);
-
- /*
- * Remove leading '/', '../' and './' elements
- */
- while (*p) {
- if (p[0] == '/') {
- p++;
- len--;
- } else if (p[0] != '.')
- break;
- else if (p[1] == '.' && p[2] == '/') {
- p += 3;
- len -= 3;
- } else if (p[1] == '/' || (p[1] == '.' && p[2] == '\0')) {
- p += 2;
- len -= 2;
- } else if (p[1] == '\0') {
- p++;
- len--;
- } else
- break;
- }
- if (p != dirname) {
- memmove(dirname, p, len+1);
- p = dirname;
- }
- /*
- * Remove "/","/." and "/.." elements from tail.
- */
- while (len > 0) {
- size_t ll = len;
-
- if (len > 0 && p[len-1] == '/') {
- p[len-1] = '\0';
- len--;
- }
- if (len > 1 && p[len-2] == '/' && p[len-1] == '.') {
- p[len-2] = '\0';
- len -= 2;
- }
- if (len > 2 && p[len-3] == '/' && p[len-2] == '.' &&
- p[len-1] == '.') {
- p[len-3] = '\0';
- len -= 3;
- }
- if (ll == len)
- break;
- }
- while (*p) {
- if (p[0] == '/') {
- if (p[1] == '/')
- /* Convert '//' --> '/' */
- strcpy(p, p+1);
- else if (p[1] == '.' && p[2] == '/')
- /* Convert '/./' --> '/' */
- strcpy(p, p+2);
- else if (p[1] == '.' && p[2] == '.' && p[3] == '/') {
- /* Convert 'dir/dir1/../dir2/'
- * --> 'dir/dir2/'
- */
- char *rp = p -1;
- while (rp >= dirname) {
- if (*rp == '/')
- break;
- --rp;
- }
- if (rp > dirname) {
- strcpy(rp, p+3);
- p = rp;
- } else {
- strcpy(dirname, p+4);
- p = dirname;
- }
- } else
- p++;
- } else
- p++;
- }
- p = dirname;
- len = strlen(p);
-
- if (archive_entry_filetype(file->entry) == AE_IFLNK) {
- size_t len2;
- /* Convert symlink name too. */
- if (archive_entry_symlink_l(file->entry, &pp, &len2,
- xar->sconv) != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Linkname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate symlink '%s' to UTF-8",
- archive_entry_symlink(file->entry));
- r = ARCHIVE_WARN;
- }
- archive_strncpy(&(file->symlink), pp, len2);
- cleanup_backslash(file->symlink.s, file->symlink.length);
- }
- /*
- * - Count up directory elements.
- * - Find out the position which points the last position of
- * path separator('/').
- */
- slash = NULL;
- for (; *p != '\0'; p++)
- if (*p == '/')
- slash = p;
- if (slash == NULL) {
- /* The pathname doesn't have a parent directory. */
- file->parentdir.length = len;
- archive_string_copy(&(file->basename), &(file->parentdir));
- archive_string_empty(&(file->parentdir));
- file->parentdir.s = '\0';
- return (r);
- }
-
- /* Make a basename from dirname and slash */
- *slash = '\0';
- file->parentdir.length = slash - dirname;
- archive_strcpy(&(file->basename), slash + 1);
- return (r);
-}
-
-static int
-get_path_component(char *name, int n, const char *fn)
-{
- char *p;
- int l;
-
- p = strchr(fn, '/');
- if (p == NULL) {
- if ((l = strlen(fn)) == 0)
- return (0);
- } else
- l = p - fn;
- if (l > n -1)
- return (-1);
- memcpy(name, fn, l);
- name[l] = '\0';
-
- return (l);
-}
-
-/*
- * Add a new entry into the tree.
- */
-static int
-file_tree(struct archive_write *a, struct file **filepp)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
- char name[_MAX_FNAME];/* Included null terminator size. */
-#elif defined(NAME_MAX) && NAME_MAX >= 255
- char name[NAME_MAX+1];
-#else
- char name[256];
-#endif
- struct xar *xar = (struct xar *)a->format_data;
- struct file *dent, *file, *np;
- struct archive_entry *ent;
- const char *fn, *p;
- int l;
-
- file = *filepp;
- dent = xar->root;
- if (file->parentdir.length > 0)
- fn = p = file->parentdir.s;
- else
- fn = p = "";
-
- /*
- * If the path of the parent directory of `file' entry is
- * the same as the path of `cur_dirent', add isoent to
- * `cur_dirent'.
- */
- if (archive_strlen(&(xar->cur_dirstr))
- == archive_strlen(&(file->parentdir)) &&
- strcmp(xar->cur_dirstr.s, fn) == 0) {
- if (!file_add_child_tail(xar->cur_dirent, file)) {
- np = (struct file *)__archive_rb_tree_find_node(
- &(xar->cur_dirent->rbtree),
- file->basename.s);
- goto same_entry;
- }
- return (ARCHIVE_OK);
- }
-
- for (;;) {
- l = get_path_component(name, sizeof(name), fn);
- if (l == 0) {
- np = NULL;
- break;
- }
- if (l < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "A name buffer is too small");
- file_free(file);
- *filepp = NULL;
- return (ARCHIVE_FATAL);
- }
-
- np = file_find_child(dent, name);
- if (np == NULL || fn[0] == '\0')
- break;
-
- /* Find next subdirectory. */
- if (!np->dir) {
- /* NOT Directory! */
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "`%s' is not directory, we cannot insert `%s' ",
- archive_entry_pathname(np->entry),
- archive_entry_pathname(file->entry));
- file_free(file);
- *filepp = NULL;
- return (ARCHIVE_FAILED);
- }
- fn += l;
- if (fn[0] == '/')
- fn++;
- dent = np;
- }
- if (np == NULL) {
- /*
- * Create virtual parent directories.
- */
- while (fn[0] != '\0') {
- struct file *vp;
- struct archive_string as;
-
- archive_string_init(&as);
- archive_strncat(&as, p, fn - p + l);
- if (as.s[as.length-1] == '/') {
- as.s[as.length-1] = '\0';
- as.length--;
- }
- vp = file_create_virtual_dir(a, xar, as.s);
- if (vp == NULL) {
- archive_string_free(&as);
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- file_free(file);
- *filepp = NULL;
- return (ARCHIVE_FATAL);
- }
- archive_string_free(&as);
- if (file_gen_utility_names(a, vp) <= ARCHIVE_FAILED)
- return (ARCHIVE_FATAL);
- file_add_child_tail(dent, vp);
- file_register(xar, vp);
- np = vp;
-
- fn += l;
- if (fn[0] == '/')
- fn++;
- l = get_path_component(name, sizeof(name), fn);
- if (l < 0) {
- archive_string_free(&as);
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "A name buffer is too small");
- file_free(file);
- *filepp = NULL;
- return (ARCHIVE_FATAL);
- }
- dent = np;
- }
-
- /* Found out the parent directory where isoent can be
- * inserted. */
- xar->cur_dirent = dent;
- archive_string_empty(&(xar->cur_dirstr));
- archive_string_ensure(&(xar->cur_dirstr),
- archive_strlen(&(dent->parentdir)) +
- archive_strlen(&(dent->basename)) + 2);
- if (archive_strlen(&(dent->parentdir)) +
- archive_strlen(&(dent->basename)) == 0)
- xar->cur_dirstr.s[0] = 0;
- else {
- if (archive_strlen(&(dent->parentdir)) > 0) {
- archive_string_copy(&(xar->cur_dirstr),
- &(dent->parentdir));
- archive_strappend_char(&(xar->cur_dirstr), '/');
- }
- archive_string_concat(&(xar->cur_dirstr),
- &(dent->basename));
- }
-
- if (!file_add_child_tail(dent, file)) {
- np = (struct file *)__archive_rb_tree_find_node(
- &(dent->rbtree), file->basename.s);
- goto same_entry;
- }
- return (ARCHIVE_OK);
- }
-
-same_entry:
- /*
- * We have already has the entry the filename of which is
- * the same.
- */
- if (archive_entry_filetype(np->entry) !=
- archive_entry_filetype(file->entry)) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Found duplicate entries `%s' and its file type is "
- "different",
- archive_entry_pathname(np->entry));
- file_free(file);
- *filepp = NULL;
- return (ARCHIVE_FAILED);
- }
-
- /* Swap files. */
- ent = np->entry;
- np->entry = file->entry;
- file->entry = ent;
- np->virtual = 0;
-
- file_free(file);
- *filepp = np;
- return (ARCHIVE_OK);
-}
-
-static void
-file_register(struct xar *xar, struct file *file)
-{
- file->id = xar->file_idx++;
- file->next = NULL;
- *xar->file_list.last = file;
- xar->file_list.last = &(file->next);
-}
-
-static void
-file_init_register(struct xar *xar)
-{
- xar->file_list.first = NULL;
- xar->file_list.last = &(xar->file_list.first);
-}
-
-static void
-file_free_register(struct xar *xar)
-{
- struct file *file, *file_next;
-
- file = xar->file_list.first;
- while (file != NULL) {
- file_next = file->next;
- file_free(file);
- file = file_next;
- }
-}
-
-/*
- * Register entry to get a hardlink target.
- */
-static int
-file_register_hardlink(struct archive_write *a, struct file *file)
-{
- struct xar *xar = (struct xar *)a->format_data;
- struct hardlink *hl;
- const char *pathname;
-
- archive_entry_set_nlink(file->entry, 1);
- pathname = archive_entry_hardlink(file->entry);
- if (pathname == NULL) {
- /* This `file` is a hardlink target. */
- hl = malloc(sizeof(*hl));
- if (hl == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- hl->nlink = 1;
- /* A hardlink target must be the first position. */
- file->hlnext = NULL;
- hl->file_list.first = file;
- hl->file_list.last = &(file->hlnext);
- __archive_rb_tree_insert_node(&(xar->hardlink_rbtree),
- (struct archive_rb_node *)hl);
- } else {
- hl = (struct hardlink *)__archive_rb_tree_find_node(
- &(xar->hardlink_rbtree), pathname);
- if (hl != NULL) {
- /* Insert `file` entry into the tail. */
- file->hlnext = NULL;
- *hl->file_list.last = file;
- hl->file_list.last = &(file->hlnext);
- hl->nlink++;
- }
- archive_entry_unset_size(file->entry);
- }
-
- return (ARCHIVE_OK);
-}
-
-/*
- * Hardlinked files have to have the same location of extent.
- * We have to find out hardlink target entries for entries which
- * have a hardlink target name.
- */
-static void
-file_connect_hardlink_files(struct xar *xar)
-{
- struct archive_rb_node *n;
- struct hardlink *hl;
- struct file *target, *nf;
-
- ARCHIVE_RB_TREE_FOREACH(n, &(xar->hardlink_rbtree)) {
- hl = (struct hardlink *)n;
-
- /* The first entry must be a hardlink target. */
- target = hl->file_list.first;
- archive_entry_set_nlink(target->entry, hl->nlink);
- if (hl->nlink > 1)
- /* It means this file is a hardlink
- * targe itself. */
- target->hardlink_target = target;
- for (nf = target->hlnext;
- nf != NULL; nf = nf->hlnext) {
- nf->hardlink_target = target;
- archive_entry_set_nlink(nf->entry, hl->nlink);
- }
- }
-}
-
-static int
-file_hd_cmp_node(const struct archive_rb_node *n1,
- const struct archive_rb_node *n2)
-{
- const struct hardlink *h1 = (const struct hardlink *)n1;
- const struct hardlink *h2 = (const struct hardlink *)n2;
-
- return (strcmp(archive_entry_pathname(h1->file_list.first->entry),
- archive_entry_pathname(h2->file_list.first->entry)));
-}
-
-static int
-file_hd_cmp_key(const struct archive_rb_node *n, const void *key)
-{
- const struct hardlink *h = (const struct hardlink *)n;
-
- return (strcmp(archive_entry_pathname(h->file_list.first->entry),
- (const char *)key));
-}
-
-
-static void
-file_init_hardlinks(struct xar *xar)
-{
- static const struct archive_rb_tree_ops rb_ops = {
- file_hd_cmp_node, file_hd_cmp_key,
- };
-
- __archive_rb_tree_init(&(xar->hardlink_rbtree), &rb_ops);
-}
-
-static void
-file_free_hardlinks(struct xar *xar)
-{
- struct archive_rb_node *n, *next;
-
- for (n = ARCHIVE_RB_TREE_MIN(&(xar->hardlink_rbtree)); n;) {
- next = __archive_rb_tree_iterate(&(xar->hardlink_rbtree),
- n, ARCHIVE_RB_DIR_RIGHT);
- free(n);
- n = next;
- }
-}
-
-static void
-checksum_init(struct chksumwork *sumwrk, enum sumalg sum_alg)
-{
- sumwrk->alg = sum_alg;
- switch (sum_alg) {
- case CKSUM_NONE:
- break;
- case CKSUM_SHA1:
- archive_sha1_init(&(sumwrk->sha1ctx));
- break;
- case CKSUM_MD5:
- archive_md5_init(&(sumwrk->md5ctx));
- break;
- }
-}
-
-static void
-checksum_update(struct chksumwork *sumwrk, const void *buff, size_t size)
-{
-
- switch (sumwrk->alg) {
- case CKSUM_NONE:
- break;
- case CKSUM_SHA1:
- archive_sha1_update(&(sumwrk->sha1ctx), buff, size);
- break;
- case CKSUM_MD5:
- archive_md5_update(&(sumwrk->md5ctx), buff, size);
- break;
- }
-}
-
-static void
-checksum_final(struct chksumwork *sumwrk, struct chksumval *sumval)
-{
-
- switch (sumwrk->alg) {
- case CKSUM_NONE:
- sumval->len = 0;
- break;
- case CKSUM_SHA1:
- archive_sha1_final(&(sumwrk->sha1ctx), sumval->val);
- sumval->len = SHA1_SIZE;
- break;
- case CKSUM_MD5:
- archive_md5_final(&(sumwrk->md5ctx), sumval->val);
- sumval->len = MD5_SIZE;
- break;
- }
- sumval->alg = sumwrk->alg;
-}
-
-#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR) || !defined(HAVE_LZMA_H)
-static int
-compression_unsupported_encoder(struct archive *a,
- struct la_zstream *lastrm, const char *name)
-{
-
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "%s compression not supported on this platform", name);
- lastrm->valid = 0;
- lastrm->real_stream = NULL;
- return (ARCHIVE_FAILED);
-}
-#endif
-
-static int
-compression_init_encoder_gzip(struct archive *a,
- struct la_zstream *lastrm, int level, int withheader)
-{
- z_stream *strm;
-
- if (lastrm->valid)
- compression_end(a, lastrm);
- strm = calloc(1, sizeof(*strm));
- if (strm == NULL) {
- archive_set_error(a, ENOMEM,
- "Can't allocate memory for gzip stream");
- return (ARCHIVE_FATAL);
- }
- /* zlib.h is not const-correct, so we need this one bit
- * of ugly hackery to convert a const * pointer to
- * a non-const pointer. */
- strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
- strm->avail_in = lastrm->avail_in;
- strm->total_in = (uLong)lastrm->total_in;
- strm->next_out = lastrm->next_out;
- strm->avail_out = lastrm->avail_out;
- strm->total_out = (uLong)lastrm->total_out;
- if (deflateInit2(strm, level, Z_DEFLATED,
- (withheader)?15:-15,
- 8, Z_DEFAULT_STRATEGY) != Z_OK) {
- free(strm);
- lastrm->real_stream = NULL;
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library");
- return (ARCHIVE_FATAL);
- }
- lastrm->real_stream = strm;
- lastrm->valid = 1;
- lastrm->code = compression_code_gzip;
- lastrm->end = compression_end_gzip;
- return (ARCHIVE_OK);
-}
-
-static int
-compression_code_gzip(struct archive *a,
- struct la_zstream *lastrm, enum la_zaction action)
-{
- z_stream *strm;
- int r;
-
- strm = (z_stream *)lastrm->real_stream;
- /* zlib.h is not const-correct, so we need this one bit
- * of ugly hackery to convert a const * pointer to
- * a non-const pointer. */
- strm->next_in = (Bytef *)(uintptr_t)(const void *)lastrm->next_in;
- strm->avail_in = lastrm->avail_in;
- strm->total_in = (uLong)lastrm->total_in;
- strm->next_out = lastrm->next_out;
- strm->avail_out = lastrm->avail_out;
- strm->total_out = (uLong)lastrm->total_out;
- r = deflate(strm,
- (action == ARCHIVE_Z_FINISH)? Z_FINISH: Z_NO_FLUSH);
- lastrm->next_in = strm->next_in;
- lastrm->avail_in = strm->avail_in;
- lastrm->total_in = strm->total_in;
- lastrm->next_out = strm->next_out;
- lastrm->avail_out = strm->avail_out;
- lastrm->total_out = strm->total_out;
- switch (r) {
- case Z_OK:
- return (ARCHIVE_OK);
- case Z_STREAM_END:
- return (ARCHIVE_EOF);
- default:
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "GZip compression failed:"
- " deflate() call returned status %d", r);
- return (ARCHIVE_FATAL);
- }
-}
-
-static int
-compression_end_gzip(struct archive *a, struct la_zstream *lastrm)
-{
- z_stream *strm;
- int r;
-
- strm = (z_stream *)lastrm->real_stream;
- r = deflateEnd(strm);
- free(strm);
- lastrm->real_stream = NULL;
- lastrm->valid = 0;
- if (r != Z_OK) {
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "Failed to clean up compressor");
- return (ARCHIVE_FATAL);
- }
- return (ARCHIVE_OK);
-}
-
-#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
-static int
-compression_init_encoder_bzip2(struct archive *a,
- struct la_zstream *lastrm, int level)
-{
- bz_stream *strm;
-
- if (lastrm->valid)
- compression_end(a, lastrm);
- strm = calloc(1, sizeof(*strm));
- if (strm == NULL) {
- archive_set_error(a, ENOMEM,
- "Can't allocate memory for bzip2 stream");
- return (ARCHIVE_FATAL);
- }
- /* bzlib.h is not const-correct, so we need this one bit
- * of ugly hackery to convert a const * pointer to
- * a non-const pointer. */
- strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
- strm->avail_in = lastrm->avail_in;
- strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
- strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
- strm->next_out = (char *)lastrm->next_out;
- strm->avail_out = lastrm->avail_out;
- strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
- strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
- if (BZ2_bzCompressInit(strm, level, 0, 30) != BZ_OK) {
- free(strm);
- lastrm->real_stream = NULL;
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library");
- return (ARCHIVE_FATAL);
- }
- lastrm->real_stream = strm;
- lastrm->valid = 1;
- lastrm->code = compression_code_bzip2;
- lastrm->end = compression_end_bzip2;
- return (ARCHIVE_OK);
-}
-
-static int
-compression_code_bzip2(struct archive *a,
- struct la_zstream *lastrm, enum la_zaction action)
-{
- bz_stream *strm;
- int r;
-
- strm = (bz_stream *)lastrm->real_stream;
- /* bzlib.h is not const-correct, so we need this one bit
- * of ugly hackery to convert a const * pointer to
- * a non-const pointer. */
- strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
- strm->avail_in = lastrm->avail_in;
- strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
- strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
- strm->next_out = (char *)lastrm->next_out;
- strm->avail_out = lastrm->avail_out;
- strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
- strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
- r = BZ2_bzCompress(strm,
- (action == ARCHIVE_Z_FINISH)? BZ_FINISH: BZ_RUN);
- lastrm->next_in = (const unsigned char *)strm->next_in;
- lastrm->avail_in = strm->avail_in;
- lastrm->total_in =
- (((uint64_t)(uint32_t)strm->total_in_hi32) << 32)
- + (uint64_t)(uint32_t)strm->total_in_lo32;
- lastrm->next_out = (unsigned char *)strm->next_out;
- lastrm->avail_out = strm->avail_out;
- lastrm->total_out =
- (((uint64_t)(uint32_t)strm->total_out_hi32) << 32)
- + (uint64_t)(uint32_t)strm->total_out_lo32;
- switch (r) {
- case BZ_RUN_OK: /* Non-finishing */
- case BZ_FINISH_OK: /* Finishing: There's more work to do */
- return (ARCHIVE_OK);
- case BZ_STREAM_END: /* Finishing: all done */
- /* Only occurs in finishing case */
- return (ARCHIVE_EOF);
- default:
- /* Any other return value indicates an error */
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "Bzip2 compression failed:"
- " BZ2_bzCompress() call returned status %d", r);
- return (ARCHIVE_FATAL);
- }
-}
-
-static int
-compression_end_bzip2(struct archive *a, struct la_zstream *lastrm)
-{
- bz_stream *strm;
- int r;
-
- strm = (bz_stream *)lastrm->real_stream;
- r = BZ2_bzCompressEnd(strm);
- free(strm);
- lastrm->real_stream = NULL;
- lastrm->valid = 0;
- if (r != BZ_OK) {
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "Failed to clean up compressor");
- return (ARCHIVE_FATAL);
- }
- return (ARCHIVE_OK);
-}
-
-#else
-static int
-compression_init_encoder_bzip2(struct archive *a,
- struct la_zstream *lastrm, int level)
-{
-
- (void) level; /* UNUSED */
- if (lastrm->valid)
- compression_end(a, lastrm);
- return (compression_unsupported_encoder(a, lastrm, "bzip2"));
-}
-#endif
-
-#if defined(HAVE_LZMA_H)
-static int
-compression_init_encoder_lzma(struct archive *a,
- struct la_zstream *lastrm, int level)
-{
- static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;
- lzma_stream *strm;
- lzma_options_lzma lzma_opt;
- int r;
-
- if (lastrm->valid)
- compression_end(a, lastrm);
- if (lzma_lzma_preset(&lzma_opt, level)) {
- lastrm->real_stream = NULL;
- archive_set_error(a, ENOMEM,
- "Internal error initializing compression library");
- return (ARCHIVE_FATAL);
- }
- strm = calloc(1, sizeof(*strm));
- if (strm == NULL) {
- archive_set_error(a, ENOMEM,
- "Can't allocate memory for lzma stream");
- return (ARCHIVE_FATAL);
- }
- *strm = lzma_init_data;
- r = lzma_alone_encoder(strm, &lzma_opt);
- switch (r) {
- case LZMA_OK:
- lastrm->real_stream = strm;
- lastrm->valid = 1;
- lastrm->code = compression_code_lzma;
- lastrm->end = compression_end_lzma;
- r = ARCHIVE_OK;
- break;
- case LZMA_MEM_ERROR:
- free(strm);
- lastrm->real_stream = NULL;
- archive_set_error(a, ENOMEM,
- "Internal error initializing compression library: "
- "Cannot allocate memory");
- r = ARCHIVE_FATAL;
- break;
- default:
- free(strm);
- lastrm->real_stream = NULL;
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library: "
- "It's a bug in liblzma");
- r = ARCHIVE_FATAL;
- break;
- }
- return (r);
-}
-
-static int
-compression_init_encoder_xz(struct archive *a,
- struct la_zstream *lastrm, int level)
-{
- static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;
- lzma_stream *strm;
- lzma_filter *lzmafilters;
- lzma_options_lzma lzma_opt;
- int r;
-
- if (lastrm->valid)
- compression_end(a, lastrm);
- strm = calloc(1, sizeof(*strm) + sizeof(*lzmafilters) * 2);
- if (strm == NULL) {
- archive_set_error(a, ENOMEM,
- "Can't allocate memory for xz stream");
- return (ARCHIVE_FATAL);
- }
- lzmafilters = (lzma_filter *)(strm+1);
- if (level > 6)
- level = 6;
- if (lzma_lzma_preset(&lzma_opt, level)) {
- free(strm);
- lastrm->real_stream = NULL;
- archive_set_error(a, ENOMEM,
- "Internal error initializing compression library");
- return (ARCHIVE_FATAL);
- }
- lzmafilters[0].id = LZMA_FILTER_LZMA2;
- lzmafilters[0].options = &lzma_opt;
- lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
-
- *strm = lzma_init_data;
- r = lzma_stream_encoder(strm, lzmafilters, LZMA_CHECK_CRC64);
- switch (r) {
- case LZMA_OK:
- lastrm->real_stream = strm;
- lastrm->valid = 1;
- lastrm->code = compression_code_lzma;
- lastrm->end = compression_end_lzma;
- r = ARCHIVE_OK;
- break;
- case LZMA_MEM_ERROR:
- free(strm);
- lastrm->real_stream = NULL;
- archive_set_error(a, ENOMEM,
- "Internal error initializing compression library: "
- "Cannot allocate memory");
- r = ARCHIVE_FATAL;
- break;
- default:
- free(strm);
- lastrm->real_stream = NULL;
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library: "
- "It's a bug in liblzma");
- r = ARCHIVE_FATAL;
- break;
- }
- return (r);
-}
-
-static int
-compression_code_lzma(struct archive *a,
- struct la_zstream *lastrm, enum la_zaction action)
-{
- lzma_stream *strm;
- int r;
-
- strm = (lzma_stream *)lastrm->real_stream;
- strm->next_in = lastrm->next_in;
- strm->avail_in = lastrm->avail_in;
- strm->total_in = lastrm->total_in;
- strm->next_out = lastrm->next_out;
- strm->avail_out = lastrm->avail_out;
- strm->total_out = lastrm->total_out;
- r = lzma_code(strm,
- (action == ARCHIVE_Z_FINISH)? LZMA_FINISH: LZMA_RUN);
- lastrm->next_in = strm->next_in;
- lastrm->avail_in = strm->avail_in;
- lastrm->total_in = strm->total_in;
- lastrm->next_out = strm->next_out;
- lastrm->avail_out = strm->avail_out;
- lastrm->total_out = strm->total_out;
- switch (r) {
- case LZMA_OK:
- /* Non-finishing case */
- return (ARCHIVE_OK);
- case LZMA_STREAM_END:
- /* This return can only occur in finishing case. */
- return (ARCHIVE_EOF);
- case LZMA_MEMLIMIT_ERROR:
- archive_set_error(a, ENOMEM,
- "lzma compression error:"
- " %ju MiB would have been needed",
- (uintmax_t)((lzma_memusage(strm) + 1024 * 1024 -1)
- / (1024 * 1024)));
- return (ARCHIVE_FATAL);
- default:
- /* Any other return value indicates an error */
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "lzma compression failed:"
- " lzma_code() call returned status %d", r);
- return (ARCHIVE_FATAL);
- }
-}
-
-static int
-compression_end_lzma(struct archive *a, struct la_zstream *lastrm)
-{
- lzma_stream *strm;
-
- (void)a; /* UNUSED */
- strm = (lzma_stream *)lastrm->real_stream;
- lzma_end(strm);
- free(strm);
- lastrm->valid = 0;
- lastrm->real_stream = NULL;
- return (ARCHIVE_OK);
-}
-#else
-static int
-compression_init_encoder_lzma(struct archive *a,
- struct la_zstream *lastrm, int level)
-{
-
- (void) level; /* UNUSED */
- if (lastrm->valid)
- compression_end(a, lastrm);
- return (compression_unsupported_encoder(a, lastrm, "lzma"));
-}
-static int
-compression_init_encoder_xz(struct archive *a,
- struct la_zstream *lastrm, int level)
-{
-
- (void) level; /* UNUSED */
- if (lastrm->valid)
- compression_end(a, lastrm);
- return (compression_unsupported_encoder(a, lastrm, "xz"));
-}
-#endif
-
-static int
-xar_compression_init_encoder(struct archive_write *a)
-{
- struct xar *xar;
- int r;
-
- xar = (struct xar *)a->format_data;
- switch (xar->opt_compression) {
- case GZIP:
- r = compression_init_encoder_gzip(
- &(a->archive), &(xar->stream),
- xar->opt_compression_level, 1);
- break;
- case BZIP2:
- r = compression_init_encoder_bzip2(
- &(a->archive), &(xar->stream),
- xar->opt_compression_level);
- break;
- case LZMA:
- r = compression_init_encoder_lzma(
- &(a->archive), &(xar->stream),
- xar->opt_compression_level);
- break;
- case XZ:
- r = compression_init_encoder_xz(
- &(a->archive), &(xar->stream),
- xar->opt_compression_level);
- break;
- default:
- r = ARCHIVE_OK;
- break;
- }
- if (r == ARCHIVE_OK) {
- xar->stream.total_in = 0;
- xar->stream.next_out = xar->wbuff;
- xar->stream.avail_out = sizeof(xar->wbuff);
- xar->stream.total_out = 0;
- }
-
- return (r);
-}
-
-static int
-compression_code(struct archive *a, struct la_zstream *lastrm,
- enum la_zaction action)
-{
- if (lastrm->valid)
- return (lastrm->code(a, lastrm, action));
- return (ARCHIVE_OK);
-}
-
-static int
-compression_end(struct archive *a, struct la_zstream *lastrm)
-{
- if (lastrm->valid)
- return (lastrm->end(a, lastrm));
- return (ARCHIVE_OK);
-}
-
-
-static int
-save_xattrs(struct archive_write *a, struct file *file)
-{
- struct xar *xar;
- const char *name;
- const void *value;
- struct heap_data *heap;
- size_t size;
- int count, r;
-
- xar = (struct xar *)a->format_data;
- count = archive_entry_xattr_reset(file->entry);
- if (count == 0)
- return (ARCHIVE_OK);
- while (count--) {
- archive_entry_xattr_next(file->entry,
- &name, &value, &size);
- checksum_init(&(xar->a_sumwrk), xar->opt_sumalg);
- checksum_init(&(xar->e_sumwrk), xar->opt_sumalg);
-
- heap = calloc(1, sizeof(*heap));
- if (heap == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for xattr");
- return (ARCHIVE_FATAL);
- }
- heap->id = file->ea_idx++;
- heap->temp_offset = xar->temp_offset;
- heap->size = size;/* save a extracted size */
- heap->compression = xar->opt_compression;
- /* Get a extracted sumcheck value. */
- checksum_update(&(xar->e_sumwrk), value, size);
- checksum_final(&(xar->e_sumwrk), &(heap->e_sum));
-
- /*
- * Not compression to xattr is simple way.
- */
- if (heap->compression == NONE) {
- checksum_update(&(xar->a_sumwrk), value, size);
- checksum_final(&(xar->a_sumwrk), &(heap->a_sum));
- if (write_to_temp(a, value, size)
- != ARCHIVE_OK) {
- free(heap);
- return (ARCHIVE_FATAL);
- }
- heap->length = size;
- /* Add heap to the tail of file->xattr. */
- heap->next = NULL;
- *file->xattr.last = heap;
- file->xattr.last = &(heap->next);
- /* Next xattr */
- continue;
- }
-
- /*
- * Init compression library.
- */
- r = xar_compression_init_encoder(a);
- if (r != ARCHIVE_OK) {
- free(heap);
- return (ARCHIVE_FATAL);
- }
-
- xar->stream.next_in = (const unsigned char *)value;
- xar->stream.avail_in = size;
- for (;;) {
- r = compression_code(&(a->archive),
- &(xar->stream), ARCHIVE_Z_FINISH);
- if (r != ARCHIVE_OK && r != ARCHIVE_EOF) {
- free(heap);
- return (ARCHIVE_FATAL);
- }
- size = sizeof(xar->wbuff) - xar->stream.avail_out;
- checksum_update(&(xar->a_sumwrk),
- xar->wbuff, size);
- if (write_to_temp(a, xar->wbuff, size)
- != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- if (r == ARCHIVE_OK) {
- xar->stream.next_out = xar->wbuff;
- xar->stream.avail_out = sizeof(xar->wbuff);
- } else {
- checksum_final(&(xar->a_sumwrk),
- &(heap->a_sum));
- heap->length = xar->stream.total_out;
- /* Add heap to the tail of file->xattr. */
- heap->next = NULL;
- *file->xattr.last = heap;
- file->xattr.last = &(heap->next);
- break;
- }
- }
- /* Clean up compression library. */
- r = compression_end(&(a->archive), &(xar->stream));
- if (r != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
- return (ARCHIVE_OK);
-}
-
-static int
-getalgsize(enum sumalg sumalg)
-{
- switch (sumalg) {
- default:
- case CKSUM_NONE:
- return (0);
- case CKSUM_SHA1:
- return (SHA1_SIZE);
- case CKSUM_MD5:
- return (MD5_SIZE);
- }
-}
-
-static const char *
-getalgname(enum sumalg sumalg)
-{
- switch (sumalg) {
- default:
- case CKSUM_NONE:
- return (NULL);
- case CKSUM_SHA1:
- return (SHA1_NAME);
- case CKSUM_MD5:
- return (MD5_NAME);
- }
-}
-
-#endif /* Support xar format */
-
diff --git a/3rdparty/libarchive/libarchive/archive_write_set_format_zip.c b/3rdparty/libarchive/libarchive/archive_write_set_format_zip.c
deleted file mode 100644
index 3d8b3b5f..00000000
--- a/3rdparty/libarchive/libarchive/archive_write_set_format_zip.c
+++ /dev/null
@@ -1,930 +0,0 @@
-/*-
- * Copyright (c) 2008 Anselm Strauss
- * Copyright (c) 2009 Joerg Sonnenberger
- * Copyright (c) 2011-2012 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.
- */
-
-/*
- * Development supported by Google Summer of Code 2008.
- */
-
-/*
- * The current implementation is very limited:
- *
- * - No encryption support.
- * - No ZIP64 support.
- * - No support for splitting and spanning.
- * - Only supports regular file and folder entries.
- *
- * Note that generally data in ZIP files is little-endian encoded,
- * with some exceptions.
- *
- * TODO: Since Libarchive is generally 64bit oriented, but this implementation
- * does not yet support sizes exceeding 32bit, it is highly fragile for
- * big archives. This should change when ZIP64 is finally implemented, otherwise
- * some serious checking has to be done.
- *
- */
-
-#include "archive_platform.h"
-__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_zip.c 201168 2009-12-29 06:15:32Z kientzle $");
-
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_LANGINFO_H
-#include <langinfo.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_ZLIB_H
-#include <zlib.h>
-#endif
-
-#include "archive.h"
-#include "archive_endian.h"
-#include "archive_entry.h"
-#include "archive_entry_locale.h"
-#include "archive_private.h"
-#include "archive_write_private.h"
-
-#ifndef HAVE_ZLIB_H
-#include "archive_crc32.h"
-#endif
-
-#define ZIP_SIGNATURE_LOCAL_FILE_HEADER 0x04034b50
-#define ZIP_SIGNATURE_DATA_DESCRIPTOR 0x08074b50
-#define ZIP_SIGNATURE_FILE_HEADER 0x02014b50
-#define ZIP_SIGNATURE_CENTRAL_DIRECTORY_END 0x06054b50
-#define ZIP_SIGNATURE_EXTRA_TIMESTAMP 0x5455
-#define ZIP_SIGNATURE_EXTRA_NEW_UNIX 0x7875
-#define ZIP_VERSION_EXTRACT 0x0014 /* ZIP version 2.0 is needed. */
-#define ZIP_VERSION_BY 0x0314 /* Made by UNIX, using ZIP version 2.0. */
-#define ZIP_FLAGS 0x08 /* Flagging bit 3 (count from 0) for using data descriptor. */
-#define ZIP_FLAGS_UTF8_NAME (1 << 11)
-
-enum compression {
- COMPRESSION_STORE = 0
-#ifdef HAVE_ZLIB_H
- ,
- COMPRESSION_DEFLATE = 8
-#endif
-};
-
-static ssize_t archive_write_zip_data(struct archive_write *,
- const void *buff, size_t s);
-static int archive_write_zip_close(struct archive_write *);
-static int archive_write_zip_free(struct archive_write *);
-static int archive_write_zip_finish_entry(struct archive_write *);
-static int archive_write_zip_header(struct archive_write *,
- struct archive_entry *);
-static int archive_write_zip_options(struct archive_write *,
- const char *, const char *);
-static unsigned int dos_time(const time_t);
-static size_t path_length(struct archive_entry *);
-static int write_path(struct archive_entry *, struct archive_write *);
-
-#define LOCAL_FILE_HEADER_SIGNATURE 0
-#define LOCAL_FILE_HEADER_VERSION 4
-#define LOCAL_FILE_HEADER_FLAGS 6
-#define LOCAL_FILE_HEADER_COMPRESSION 8
-#define LOCAL_FILE_HEADER_TIMEDATE 10
-#define LOCAL_FILE_HEADER_CRC32 14
-#define LOCAL_FILE_HEADER_COMPRESSED_SIZE 18
-#define LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE 22
-#define LOCAL_FILE_HEADER_FILENAME_LENGTH 26
-#define LOCAL_FILE_HEADER_EXTRA_LENGTH 28
-#define SIZE_LOCAL_FILE_HEADER 30
-
-#define FILE_HEADER_SIGNATURE 0
-#define FILE_HEADER_VERSION_BY 4
-#define FILE_HEADER_VERSION_EXTRACT 6
-#define FILE_HEADER_FLAGS 8
-#define FILE_HEADER_COMPRESSION 10
-#define FILE_HEADER_TIMEDATE 12
-#define FILE_HEADER_CRC32 16
-#define FILE_HEADER_COMPRESSED_SIZE 20
-#define FILE_HEADER_UNCOMPRESSED_SIZE 24
-#define FILE_HEADER_FILENAME_LENGTH 28
-#define FILE_HEADER_EXTRA_LENGTH 30
-#define FILE_HEADER_COMMENT_LENGTH 32
-#define FILE_HEADER_DISK_NUMBER 34
-#define FILE_HEADER_ATTRIBUTES_INTERNAL 36
-#define FILE_HEADER_ATTRIBUTES_EXTERNAL 38
-#define FILE_HEADER_OFFSET 42
-#define SIZE_FILE_HEADER 46
-
- /* Not mandatory, but recommended by specification. */
-#define DATA_DESCRIPTOR_SIGNATURE 0
-#define DATA_DESCRIPTOR_CRC32 4
-#define DATA_DESCRIPTOR_COMPRESSED_SIZE 8
-#define DATA_DESCRIPTOR_UNCOMPRESSED_SIZE 12
-#define SIZE_DATA_DESCRIPTOR 16
-
-#define EXTRA_DATA_LOCAL_TIME_ID 0
-#define EXTRA_DATA_LOCAL_TIME_SIZE 2
-#define EXTRA_DATA_LOCAL_TIME_FLAG 4
-#define EXTRA_DATA_LOCAL_MTIME 5
-#define EXTRA_DATA_LOCAL_ATIME 9
-#define EXTRA_DATA_LOCAL_CTIME 13
-#define EXTRA_DATA_LOCAL_UNIX_ID 17
-#define EXTRA_DATA_LOCAL_UNIX_SIZE 19
-#define EXTRA_DATA_LOCAL_UNIX_VERSION 21
-#define EXTRA_DATA_LOCAL_UNIX_UID_SIZE 22
-#define EXTRA_DATA_LOCAL_UNIX_UID 23
-#define EXTRA_DATA_LOCAL_UNIX_GID_SIZE 27
-#define EXTRA_DATA_LOCAL_UNIX_GID 28
-#define SIZE_EXTRA_DATA_LOCAL 32
-
-#define EXTRA_DATA_CENTRAL_TIME_ID 0
-#define EXTRA_DATA_CENTRAL_TIME_SIZE 2
-#define EXTRA_DATA_CENTRAL_TIME_FLAG 4
-#define EXTRA_DATA_CENTRAL_MTIME 5
-#define EXTRA_DATA_CENTRAL_UNIX_ID 9
-#define EXTRA_DATA_CENTRAL_UNIX_SIZE 11
-#define SIZE_EXTRA_DATA_CENTRAL 13
-
-#define CENTRAL_DIRECTORY_END_SIGNATURE 0
-#define CENTRAL_DIRECTORY_END_DISK 4
-#define CENTRAL_DIRECTORY_END_START_DISK 6
-#define CENTRAL_DIRECTORY_END_ENTRIES_DISK 8
-#define CENTRAL_DIRECTORY_END_ENTRIES 10
-#define CENTRAL_DIRECTORY_END_SIZE 12
-#define CENTRAL_DIRECTORY_END_OFFSET 16
-#define CENTRAL_DIRECTORY_END_COMMENT_LENGTH 20
-#define SIZE_CENTRAL_DIRECTORY_END 22
-
-struct zip_file_header_link {
- struct zip_file_header_link *next;
- struct archive_entry *entry;
- int64_t offset;
- unsigned long crc32;
- int64_t compressed_size;
- enum compression compression;
- int flags;
-};
-
-struct zip {
- uint8_t data_descriptor[SIZE_DATA_DESCRIPTOR];
- struct zip_file_header_link *central_directory;
- struct zip_file_header_link *central_directory_end;
- int64_t offset;
- int64_t written_bytes;
- int64_t remaining_data_bytes;
- enum compression compression;
- int flags;
- struct archive_string_conv *opt_sconv;
- struct archive_string_conv *sconv_default;
- int init_default_conversion;
-
-#ifdef HAVE_ZLIB_H
- z_stream stream;
- size_t len_buf;
- unsigned char *buf;
-#endif
-};
-
-static int
-archive_write_zip_options(struct archive_write *a, const char *key,
- const char *val)
-{
- struct zip *zip = a->format_data;
- int ret = ARCHIVE_FAILED;
-
- if (strcmp(key, "compression") == 0) {
- if (val == NULL || val[0] == 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "%s: compression option needs a compression name",
- a->format_name);
- } else if (strcmp(val, "deflate") == 0) {
-#ifdef HAVE_ZLIB_H
- zip->compression = COMPRESSION_DEFLATE;
- ret = ARCHIVE_OK;
-#else
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "deflate compression not supported");
-#endif
- } else if (strcmp(val, "store") == 0) {
- zip->compression = COMPRESSION_STORE;
- ret = ARCHIVE_OK;
- }
- return (ret);
- } else if (strcmp(key, "hdrcharset") == 0) {
- if (val == NULL || val[0] == 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "%s: hdrcharset option needs a character-set name",
- a->format_name);
- } else {
- zip->opt_sconv = archive_string_conversion_to_charset(
- &a->archive, val, 0);
- if (zip->opt_sconv != NULL)
- ret = ARCHIVE_OK;
- else
- ret = ARCHIVE_FATAL;
- }
- return (ret);
- }
-
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
-}
-
-int
-archive_write_zip_set_compression_deflate(struct archive *_a)
-{
- struct archive_write *a = (struct archive_write *)_a;
- int ret = ARCHIVE_FAILED;
-
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER,
- "archive_write_zip_set_compression_deflate");
- if (a->archive.archive_format != ARCHIVE_FORMAT_ZIP) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Can only use archive_write_zip_set_compression_deflate"
- " with zip format");
- ret = ARCHIVE_FATAL;
- } else {
-#ifdef HAVE_ZLIB_H
- struct zip *zip = a->format_data;
- zip->compression = COMPRESSION_DEFLATE;
- ret = ARCHIVE_OK;
-#else
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "deflate compression not supported");
-#endif
- }
- return (ret);
-}
-
-int
-archive_write_zip_set_compression_store(struct archive *_a)
-{
- struct archive_write *a = (struct archive_write *)_a;
- struct zip *zip = a->format_data;
- int ret = ARCHIVE_FAILED;
-
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER,
- "archive_write_zip_set_compression_deflate");
- if (a->archive.archive_format != ARCHIVE_FORMAT_ZIP) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Can only use archive_write_zip_set_compression_store"
- " with zip format");
- ret = ARCHIVE_FATAL;
- } else {
- zip->compression = COMPRESSION_STORE;
- ret = ARCHIVE_OK;
- }
- return (ret);
-}
-
-int
-archive_write_set_format_zip(struct archive *_a)
-{
- struct archive_write *a = (struct archive_write *)_a;
- struct zip *zip;
-
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_set_format_zip");
-
- /* If another format was already registered, unregister it. */
- if (a->format_free != NULL)
- (a->format_free)(a);
-
- zip = (struct zip *) calloc(1, sizeof(*zip));
- if (zip == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate zip data");
- return (ARCHIVE_FATAL);
- }
- zip->central_directory = NULL;
- zip->central_directory_end = NULL;
- zip->offset = 0;
- zip->written_bytes = 0;
- zip->remaining_data_bytes = 0;
-
-#ifdef HAVE_ZLIB_H
- zip->compression = COMPRESSION_DEFLATE;
- zip->len_buf = 65536;
- zip->buf = malloc(zip->len_buf);
- if (zip->buf == NULL) {
- free(zip);
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate compression buffer");
- return (ARCHIVE_FATAL);
- }
-#else
- zip->compression = COMPRESSION_STORE;
-#endif
-
- a->format_data = zip;
- a->format_name = "zip";
- a->format_options = archive_write_zip_options;
- a->format_write_header = archive_write_zip_header;
- a->format_write_data = archive_write_zip_data;
- a->format_finish_entry = archive_write_zip_finish_entry;
- a->format_close = archive_write_zip_close;
- a->format_free = archive_write_zip_free;
- a->archive.archive_format = ARCHIVE_FORMAT_ZIP;
- a->archive.archive_format_name = "ZIP";
-
- archive_le32enc(&zip->data_descriptor[DATA_DESCRIPTOR_SIGNATURE],
- ZIP_SIGNATURE_DATA_DESCRIPTOR);
-
- return (ARCHIVE_OK);
-}
-
-static int
-is_all_ascii(const char *p)
-{
- const unsigned char *pp = (const unsigned char *)p;
-
- while (*pp) {
- if (*pp++ > 127)
- return (0);
- }
- return (1);
-}
-
-static int
-archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
-{
- struct zip *zip;
- uint8_t h[SIZE_LOCAL_FILE_HEADER];
- uint8_t e[SIZE_EXTRA_DATA_LOCAL];
- uint8_t *d;
- struct zip_file_header_link *l;
- struct archive_string_conv *sconv;
- int ret, ret2 = ARCHIVE_OK;
- int64_t size;
- mode_t type;
-
- /* Entries other than a regular file or a folder are skipped. */
- type = archive_entry_filetype(entry);
- if (type != AE_IFREG && type != AE_IFDIR && type != AE_IFLNK) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Filetype not supported");
- return ARCHIVE_FAILED;
- };
-
- /* Directory entries should have a size of 0. */
- if (type == AE_IFDIR)
- archive_entry_set_size(entry, 0);
-
- zip = a->format_data;
- /* Setup default conversion. */
- if (zip->opt_sconv == NULL && !zip->init_default_conversion) {
- zip->sconv_default =
- archive_string_default_conversion_for_write(&(a->archive));
- zip->init_default_conversion = 1;
- }
-
- if (zip->flags == 0) {
- /* Initialize the general purpose flags. */
- zip->flags = ZIP_FLAGS;
- if (zip->opt_sconv != NULL) {
- if (strcmp(archive_string_conversion_charset_name(
- zip->opt_sconv), "UTF-8") == 0)
- zip->flags |= ZIP_FLAGS_UTF8_NAME;
-#if HAVE_NL_LANGINFO
- } else if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0) {
- zip->flags |= ZIP_FLAGS_UTF8_NAME;
-#endif
- }
- }
- d = zip->data_descriptor;
- size = archive_entry_size(entry);
- zip->remaining_data_bytes = size;
-
- /* Append archive entry to the central directory data. */
- l = (struct zip_file_header_link *) malloc(sizeof(*l));
- if (l == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate zip header data");
- return (ARCHIVE_FATAL);
- }
-#if defined(_WIN32) && !defined(__CYGWIN__)
- /* Make sure the path separators in pahtname, hardlink and symlink
- * are all slash '/', not the Windows path separator '\'. */
- l->entry = __la_win_entry_in_posix_pathseparator(entry);
- if (l->entry == entry)
- l->entry = archive_entry_clone(entry);
-#else
- l->entry = archive_entry_clone(entry);
-#endif
- if (l->entry == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate zip header data");
- free(l);
- return (ARCHIVE_FATAL);
- }
- l->flags = zip->flags;
- if (zip->opt_sconv != NULL)
- sconv = zip->opt_sconv;
- else
- sconv = zip->sconv_default;
- if (sconv != NULL) {
- const char *p;
- size_t len;
-
- if (archive_entry_pathname_l(entry, &p, &len, sconv) != 0) {
- if (errno == ENOMEM) {
- archive_entry_free(l->entry);
- free(l);
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Pathname");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate Pathname '%s' to %s",
- archive_entry_pathname(entry),
- archive_string_conversion_charset_name(sconv));
- ret2 = ARCHIVE_WARN;
- }
- if (len > 0)
- archive_entry_set_pathname(l->entry, p);
-
- /*
- * Although there is no character-set regulation for Symlink,
- * it is suitable to convert a character-set of Symlinke to
- * what those of the Pathname has been converted to.
- */
- if (type == AE_IFLNK) {
- if (archive_entry_symlink_l(entry, &p, &len, sconv)) {
- if (errno == ENOMEM) {
- archive_entry_free(l->entry);
- free(l);
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory "
- " for Symlink");
- return (ARCHIVE_FATAL);
- }
- /*
- * Even if the strng conversion failed,
- * we should not report the error since
- * thre is no regulation for.
- */
- } else if (len > 0)
- archive_entry_set_symlink(l->entry, p);
- }
- }
- /* If all characters in a filename are ASCII, Reset UTF-8 Name flag. */
- if ((l->flags & ZIP_FLAGS_UTF8_NAME) != 0 &&
- is_all_ascii(archive_entry_pathname(l->entry)))
- l->flags &= ~ZIP_FLAGS_UTF8_NAME;
-
- /* Initialize the CRC variable and potentially the local crc32(). */
- l->crc32 = crc32(0, NULL, 0);
- if (type == AE_IFLNK) {
- const char *p = archive_entry_symlink(l->entry);
- if (p != NULL)
- size = strlen(p);
- else
- size = 0;
- zip->remaining_data_bytes = 0;
- archive_entry_set_size(l->entry, size);
- l->compression = COMPRESSION_STORE;
- l->compressed_size = size;
- } else {
- l->compression = zip->compression;
- l->compressed_size = 0;
- }
- l->next = NULL;
- if (zip->central_directory == NULL) {
- zip->central_directory = l;
- } else {
- zip->central_directory_end->next = l;
- }
- zip->central_directory_end = l;
-
- /* Store the offset of this header for later use in central
- * directory. */
- l->offset = zip->written_bytes;
-
- memset(h, 0, sizeof(h));
- archive_le32enc(&h[LOCAL_FILE_HEADER_SIGNATURE],
- ZIP_SIGNATURE_LOCAL_FILE_HEADER);
- archive_le16enc(&h[LOCAL_FILE_HEADER_VERSION], ZIP_VERSION_EXTRACT);
- archive_le16enc(&h[LOCAL_FILE_HEADER_FLAGS], l->flags);
- archive_le16enc(&h[LOCAL_FILE_HEADER_COMPRESSION], l->compression);
- archive_le32enc(&h[LOCAL_FILE_HEADER_TIMEDATE],
- dos_time(archive_entry_mtime(entry)));
- archive_le16enc(&h[LOCAL_FILE_HEADER_FILENAME_LENGTH],
- (uint16_t)path_length(l->entry));
-
- switch (l->compression) {
- case COMPRESSION_STORE:
- /* Setting compressed and uncompressed sizes even when
- * specification says to set to zero when using data
- * descriptors. Otherwise the end of the data for an
- * entry is rather difficult to find. */
- archive_le32enc(&h[LOCAL_FILE_HEADER_COMPRESSED_SIZE],
- (uint32_t)size);
- archive_le32enc(&h[LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE],
- (uint32_t)size);
- break;
-#ifdef HAVE_ZLIB_H
- case COMPRESSION_DEFLATE:
- archive_le32enc(&h[LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE],
- (uint32_t)size);
-
- zip->stream.zalloc = Z_NULL;
- zip->stream.zfree = Z_NULL;
- zip->stream.opaque = Z_NULL;
- zip->stream.next_out = zip->buf;
- zip->stream.avail_out = (uInt)zip->len_buf;
- if (deflateInit2(&zip->stream, Z_DEFAULT_COMPRESSION,
- Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't init deflate compressor");
- return (ARCHIVE_FATAL);
- }
- break;
-#endif
- }
-
- /* Formatting extra data. */
- archive_le16enc(&h[LOCAL_FILE_HEADER_EXTRA_LENGTH], sizeof(e));
- archive_le16enc(&e[EXTRA_DATA_LOCAL_TIME_ID],
- ZIP_SIGNATURE_EXTRA_TIMESTAMP);
- archive_le16enc(&e[EXTRA_DATA_LOCAL_TIME_SIZE], 1 + 4 * 3);
- e[EXTRA_DATA_LOCAL_TIME_FLAG] = 0x07;
- archive_le32enc(&e[EXTRA_DATA_LOCAL_MTIME],
- (uint32_t)archive_entry_mtime(entry));
- archive_le32enc(&e[EXTRA_DATA_LOCAL_ATIME],
- (uint32_t)archive_entry_atime(entry));
- archive_le32enc(&e[EXTRA_DATA_LOCAL_CTIME],
- (uint32_t)archive_entry_ctime(entry));
-
- archive_le16enc(&e[EXTRA_DATA_LOCAL_UNIX_ID],
- ZIP_SIGNATURE_EXTRA_NEW_UNIX);
- archive_le16enc(&e[EXTRA_DATA_LOCAL_UNIX_SIZE], 1 + (1 + 4) * 2);
- e[EXTRA_DATA_LOCAL_UNIX_VERSION] = 1;
- e[EXTRA_DATA_LOCAL_UNIX_UID_SIZE] = 4;
- archive_le32enc(&e[EXTRA_DATA_LOCAL_UNIX_UID],
- (uint32_t)archive_entry_uid(entry));
- e[EXTRA_DATA_LOCAL_UNIX_GID_SIZE] = 4;
- archive_le32enc(&e[EXTRA_DATA_LOCAL_UNIX_GID],
- (uint32_t)archive_entry_gid(entry));
-
- archive_le32enc(&d[DATA_DESCRIPTOR_UNCOMPRESSED_SIZE],
- (uint32_t)size);
-
- ret = __archive_write_output(a, h, sizeof(h));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- zip->written_bytes += sizeof(h);
-
- ret = write_path(l->entry, a);
- if (ret <= ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- zip->written_bytes += ret;
-
- ret = __archive_write_output(a, e, sizeof(e));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- zip->written_bytes += sizeof(e);
-
- if (type == AE_IFLNK) {
- const unsigned char *p;
-
- p = (const unsigned char *)archive_entry_symlink(l->entry);
- ret = __archive_write_output(a, p, (size_t)size);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- zip->written_bytes += size;
- l->crc32 = crc32(l->crc32, p, (unsigned)size);
- }
-
- if (ret2 != ARCHIVE_OK)
- return (ret2);
- return (ARCHIVE_OK);
-}
-
-static ssize_t
-archive_write_zip_data(struct archive_write *a, const void *buff, size_t s)
-{
- int ret;
- struct zip *zip = a->format_data;
- struct zip_file_header_link *l = zip->central_directory_end;
-
- if ((int64_t)s > zip->remaining_data_bytes)
- s = (size_t)zip->remaining_data_bytes;
-
- if (s == 0) return 0;
-
- switch (l->compression) {
- case COMPRESSION_STORE:
- ret = __archive_write_output(a, buff, s);
- if (ret != ARCHIVE_OK) return (ret);
- zip->written_bytes += s;
- zip->remaining_data_bytes -= s;
- l->compressed_size += s;
- l->crc32 = crc32(l->crc32, buff, (unsigned)s);
- return (s);
-#if HAVE_ZLIB_H
- case COMPRESSION_DEFLATE:
- zip->stream.next_in = (unsigned char*)(uintptr_t)buff;
- zip->stream.avail_in = (uInt)s;
- do {
- ret = deflate(&zip->stream, Z_NO_FLUSH);
- if (ret == Z_STREAM_ERROR)
- return (ARCHIVE_FATAL);
- if (zip->stream.avail_out == 0) {
- ret = __archive_write_output(a, zip->buf,
- zip->len_buf);
- if (ret != ARCHIVE_OK)
- return (ret);
- l->compressed_size += zip->len_buf;
- zip->written_bytes += zip->len_buf;
- zip->stream.next_out = zip->buf;
- zip->stream.avail_out = (uInt)zip->len_buf;
- }
- } while (zip->stream.avail_in != 0);
- zip->remaining_data_bytes -= s;
- /* If we have it, use zlib's fast crc32() */
- l->crc32 = crc32(l->crc32, buff, (uInt)s);
- return (s);
-#endif
-
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid ZIP compression type");
- return ARCHIVE_FATAL;
- }
-}
-
-static int
-archive_write_zip_finish_entry(struct archive_write *a)
-{
- /* Write the data descripter after file data has been written. */
- int ret;
- struct zip *zip = a->format_data;
- uint8_t *d = zip->data_descriptor;
- struct zip_file_header_link *l = zip->central_directory_end;
-#if HAVE_ZLIB_H
- size_t reminder;
-#endif
-
- switch(l->compression) {
- case COMPRESSION_STORE:
- break;
-#if HAVE_ZLIB_H
- case COMPRESSION_DEFLATE:
- for (;;) {
- ret = deflate(&zip->stream, Z_FINISH);
- if (ret == Z_STREAM_ERROR)
- return (ARCHIVE_FATAL);
- reminder = zip->len_buf - zip->stream.avail_out;
- ret = __archive_write_output(a, zip->buf, reminder);
- if (ret != ARCHIVE_OK)
- return (ret);
- l->compressed_size += reminder;
- zip->written_bytes += reminder;
- zip->stream.next_out = zip->buf;
- if (zip->stream.avail_out != 0)
- break;
- zip->stream.avail_out = (uInt)zip->len_buf;
- }
- deflateEnd(&zip->stream);
- break;
-#endif
- }
-
- archive_le32enc(&d[DATA_DESCRIPTOR_CRC32], l->crc32);
- archive_le32enc(&d[DATA_DESCRIPTOR_COMPRESSED_SIZE],
- (uint32_t)l->compressed_size);
- ret = __archive_write_output(a, d, SIZE_DATA_DESCRIPTOR);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- zip->written_bytes += SIZE_DATA_DESCRIPTOR;
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_zip_close(struct archive_write *a)
-{
- struct zip *zip;
- struct zip_file_header_link *l;
- uint8_t h[SIZE_FILE_HEADER];
- uint8_t end[SIZE_CENTRAL_DIRECTORY_END];
- uint8_t e[SIZE_EXTRA_DATA_CENTRAL];
- int64_t offset_start, offset_end;
- int entries;
- int ret;
-
- zip = a->format_data;
- l = zip->central_directory;
-
- /*
- * Formatting central directory file header fields that are
- * fixed for all entries.
- * Fields not used (and therefor 0) are:
- *
- * - comment_length
- * - disk_number
- * - attributes_internal
- */
- memset(h, 0, sizeof(h));
- archive_le32enc(&h[FILE_HEADER_SIGNATURE], ZIP_SIGNATURE_FILE_HEADER);
- archive_le16enc(&h[FILE_HEADER_VERSION_BY], ZIP_VERSION_BY);
- archive_le16enc(&h[FILE_HEADER_VERSION_EXTRACT], ZIP_VERSION_EXTRACT);
-
- entries = 0;
- offset_start = zip->written_bytes;
-
- /* Formatting individual header fields per entry and
- * writing each entry. */
- while (l != NULL) {
- archive_le16enc(&h[FILE_HEADER_FLAGS], l->flags);
- archive_le16enc(&h[FILE_HEADER_COMPRESSION], l->compression);
- archive_le32enc(&h[FILE_HEADER_TIMEDATE],
- dos_time(archive_entry_mtime(l->entry)));
- archive_le32enc(&h[FILE_HEADER_CRC32], l->crc32);
- archive_le32enc(&h[FILE_HEADER_COMPRESSED_SIZE],
- (uint32_t)l->compressed_size);
- archive_le32enc(&h[FILE_HEADER_UNCOMPRESSED_SIZE],
- (uint32_t)archive_entry_size(l->entry));
- archive_le16enc(&h[FILE_HEADER_FILENAME_LENGTH],
- (uint16_t)path_length(l->entry));
- archive_le16enc(&h[FILE_HEADER_EXTRA_LENGTH], sizeof(e));
- archive_le16enc(&h[FILE_HEADER_ATTRIBUTES_EXTERNAL+2],
- archive_entry_mode(l->entry));
- archive_le32enc(&h[FILE_HEADER_OFFSET], (uint32_t)l->offset);
-
- /* Formatting extra data. */
- archive_le16enc(&e[EXTRA_DATA_CENTRAL_TIME_ID],
- ZIP_SIGNATURE_EXTRA_TIMESTAMP);
- archive_le16enc(&e[EXTRA_DATA_CENTRAL_TIME_SIZE], 1 + 4);
- e[EXTRA_DATA_CENTRAL_TIME_FLAG] = 0x07;
- archive_le32enc(&e[EXTRA_DATA_CENTRAL_MTIME],
- (uint32_t)archive_entry_mtime(l->entry));
- archive_le16enc(&e[EXTRA_DATA_CENTRAL_UNIX_ID],
- ZIP_SIGNATURE_EXTRA_NEW_UNIX);
- archive_le16enc(&e[EXTRA_DATA_CENTRAL_UNIX_SIZE], 0x0000);
-
- ret = __archive_write_output(a, h, sizeof(h));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- zip->written_bytes += sizeof(h);
-
- ret = write_path(l->entry, a);
- if (ret <= ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- zip->written_bytes += ret;
-
- ret = __archive_write_output(a, e, sizeof(e));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- zip->written_bytes += sizeof(e);
-
- l = l->next;
- entries++;
- }
- offset_end = zip->written_bytes;
-
- /* Formatting end of central directory. */
- memset(end, 0, sizeof(end));
- archive_le32enc(&end[CENTRAL_DIRECTORY_END_SIGNATURE],
- ZIP_SIGNATURE_CENTRAL_DIRECTORY_END);
- archive_le16enc(&end[CENTRAL_DIRECTORY_END_ENTRIES_DISK], entries);
- archive_le16enc(&end[CENTRAL_DIRECTORY_END_ENTRIES], entries);
- archive_le32enc(&end[CENTRAL_DIRECTORY_END_SIZE],
- (uint32_t)(offset_end - offset_start));
- archive_le32enc(&end[CENTRAL_DIRECTORY_END_OFFSET],
- (uint32_t)offset_start);
-
- /* Writing end of central directory. */
- ret = __archive_write_output(a, end, sizeof(end));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- zip->written_bytes += sizeof(end);
- return (ARCHIVE_OK);
-}
-
-static int
-archive_write_zip_free(struct archive_write *a)
-{
- struct zip *zip;
- struct zip_file_header_link *l;
-
- zip = a->format_data;
- while (zip->central_directory != NULL) {
- l = zip->central_directory;
- zip->central_directory = l->next;
- archive_entry_free(l->entry);
- free(l);
- }
-#ifdef HAVE_ZLIB_H
- free(zip->buf);
-#endif
- free(zip);
- a->format_data = NULL;
- return (ARCHIVE_OK);
-}
-
-/* Convert into MSDOS-style date/time. */
-static unsigned int
-dos_time(const time_t unix_time)
-{
- struct tm *t;
- unsigned int dt;
-
- /* This will not preserve time when creating/extracting the archive
- * on two systems with different time zones. */
- t = localtime(&unix_time);
-
- /* MSDOS-style date/time is only between 1980-01-01 and 2107-12-31 */
- if (t->tm_year < 1980 - 1900)
- /* Set minimum date/time '1980-01-01 00:00:00'. */
- dt = 0x00210000U;
- else if (t->tm_year > 2107 - 1900)
- /* Set maximum date/time '2107-12-31 23:59:58'. */
- dt = 0xff9fbf7dU;
- else {
- dt = 0;
- dt += ((t->tm_year - 80) & 0x7f) << 9;
- dt += ((t->tm_mon + 1) & 0x0f) << 5;
- dt += (t->tm_mday & 0x1f);
- dt <<= 16;
- dt += (t->tm_hour & 0x1f) << 11;
- dt += (t->tm_min & 0x3f) << 5;
- dt += (t->tm_sec & 0x3e) >> 1; /* Only counting every 2 seconds. */
- }
- return dt;
-}
-
-static size_t
-path_length(struct archive_entry *entry)
-{
- mode_t type;
- const char *path;
-
- type = archive_entry_filetype(entry);
- path = archive_entry_pathname(entry);
-
- if (path == NULL)
- return (0);
- if (type == AE_IFDIR &&
- (path[0] == '\0' || path[strlen(path) - 1] != '/')) {
- return strlen(path) + 1;
- } else {
- return strlen(path);
- }
-}
-
-static int
-write_path(struct archive_entry *entry, struct archive_write *archive)
-{
- int ret;
- const char *path;
- mode_t type;
- size_t written_bytes;
-
- path = archive_entry_pathname(entry);
- type = archive_entry_filetype(entry);
- written_bytes = 0;
-
- ret = __archive_write_output(archive, path, strlen(path));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- written_bytes += strlen(path);
-
- /* Folders are recognized by a traling slash. */
- if ((type == AE_IFDIR) & (path[strlen(path) - 1] != '/')) {
- ret = __archive_write_output(archive, "/", 1);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- written_bytes += 1;
- }
-
- return ((int)written_bytes);
-}
diff --git a/3rdparty/libarchive/libarchive/config_freebsd.h b/3rdparty/libarchive/libarchive/config_freebsd.h
index 20734316..be25258f 100644
--- a/3rdparty/libarchive/libarchive/config_freebsd.h
+++ b/3rdparty/libarchive/libarchive/config_freebsd.h
@@ -22,139 +22,238 @@
* (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: head/lib/libarchive/config_freebsd.h 201079 2009-12-28 02:01:42Z kientzle $
+ * $FreeBSD$
*/
-/* FreeBSD 5.0 and later have ACL and extattr support. */
+#include <osreldate.h>
+
+/* FreeBSD 5.0 and later has ACL and extattr support. */
#if __FreeBSD__ > 4
-#define HAVE_ACL_CREATE_ENTRY 1
-#define HAVE_ACL_GET_LINK_NP 1
-#define HAVE_ACL_GET_PERM_NP 1
-#define HAVE_ACL_INIT 1
-#define HAVE_ACL_SET_FD 1
-#define HAVE_ACL_SET_FD_NP 1
-#define HAVE_ACL_SET_FILE 1
-#define HAVE_ACL_USER 1
-#define HAVE_EXTATTR_GET_FILE 1
-#define HAVE_EXTATTR_LIST_FILE 1
-#define HAVE_EXTATTR_SET_FD 1
-#define HAVE_EXTATTR_SET_FILE 1
-#define HAVE_SYS_ACL_H 1
-#define HAVE_SYS_EXTATTR_H 1
-#endif
+#define ARCHIVE_ACL_FREEBSD 1
+#define HAVE_ACL_GET_PERM_NP 1
+#define HAVE_ARC4RANDOM_BUF 1
+#define HAVE_EXTATTR_GET_FILE 1
+#define HAVE_EXTATTR_LIST_FILE 1
+#define HAVE_EXTATTR_SET_FD 1
+#define HAVE_EXTATTR_SET_FILE 1
+#define HAVE_STRUCT_XVFSCONF 1
+#define HAVE_SYS_ACL_H 1
+#define HAVE_SYS_EXTATTR_H 1
+#if __FreeBSD__ > 7
+/* FreeBSD 8.0 and later has NFSv4 ACL support */
+#define ARCHIVE_ACL_FREEBSD_NFS4 1
+#define HAVE_ACL_GET_LINK_NP 1
+#define HAVE_ACL_IS_TRIVIAL_NP 1
+#define HAVE_ACL_SET_LINK_NP 1
+#endif /* __FreeBSD__ > 7 */
+#endif /* __FreeBSD__ > 4 */
#ifdef WITH_OPENSSL
-#define HAVE_OPENSSL_MD5_H 1
-#define HAVE_OPENSSL_RIPEMD_H 1
-#define HAVE_OPENSSL_SHA_H 1
-#define HAVE_SHA384 1
-#define HAVE_SHA512 1
+#define HAVE_LIBCRYPTO 1
+#define HAVE_OPENSSL_EVP_H 1
+#define HAVE_OPENSSL_MD5_H 1
+#define HAVE_OPENSSL_RIPEMD_H 1
+#define HAVE_OPENSSL_SHA_H 1
+#define HAVE_OPENSSL_SHA256_INIT 1
+#define HAVE_OPENSSL_SHA384_INIT 1
+#define HAVE_OPENSSL_SHA512_INIT 1
+#define HAVE_PKCS5_PBKDF2_HMAC_SHA1 1
+#define HAVE_SHA256 1
+#define HAVE_SHA384 1
+#define HAVE_SHA512 1
+#else
+#define HAVE_LIBMD 1
+#define HAVE_MD5_H 1
+#define HAVE_MD5INIT 1
+#define HAVE_RIPEMD_H 1
+#define HAVE_SHA_H 1
+#define HAVE_SHA1 1
+#define HAVE_SHA1_INIT 1
+#define HAVE_SHA256 1
+#define HAVE_SHA256_H 1
+#define HAVE_SHA256_INIT 1
+#define HAVE_SHA512 1
+#define HAVE_SHA512_H 1
+#define HAVE_SHA512_INIT 1
#endif
-#define HAVE_BSDXML_H 1
-#define HAVE_BZLIB_H 1
-#define HAVE_CHFLAGS 1
-#define HAVE_CHOWN 1
-#define HAVE_DECL_INT64_MAX 1
-#define HAVE_DECL_INT64_MIN 1
-#define HAVE_DECL_SIZE_MAX 1
-#define HAVE_DECL_SSIZE_MAX 1
-#define HAVE_DECL_STRERROR_R 1
-#define HAVE_DECL_UINT32_MAX 1
-#define HAVE_DECL_UINT64_MAX 1
-#define HAVE_DIRENT_H 1
-#define HAVE_EFTYPE 1
-#define HAVE_EILSEQ 1
-#define HAVE_ERRNO_H 1
-#define HAVE_FCHDIR 1
-#define HAVE_FCHFLAGS 1
-#define HAVE_FCHMOD 1
-#define HAVE_FCHOWN 1
-#define HAVE_FCNTL 1
-#define HAVE_FCNTL_H 1
-#define HAVE_FSEEKO 1
-#define HAVE_FSTAT 1
-#define HAVE_FTRUNCATE 1
-#define HAVE_FUTIMES 1
-#define HAVE_GETEUID 1
-#define HAVE_GETGRGID_R 1
-#define HAVE_GETPID 1
-#define HAVE_GETPWUID_R 1
-#define HAVE_GRP_H 1
-#define HAVE_INTTYPES_H 1
-#define HAVE_LCHFLAGS 1
-#define HAVE_LCHMOD 1
-#define HAVE_LCHOWN 1
-#define HAVE_LIMITS_H 1
-#define HAVE_LINK 1
-#define HAVE_LSTAT 1
-#define HAVE_LUTIMES 1
-#define HAVE_MALLOC 1
-#define HAVE_MD5 1
-#define HAVE_MD5_H 1
-#define HAVE_MEMMOVE 1
-#define HAVE_MKDIR 1
-#define HAVE_MKFIFO 1
-#define HAVE_MKNOD 1
-#define HAVE_PIPE 1
-#define HAVE_POLL 1
-#define HAVE_POLL_H 1
-#define HAVE_PWD_H 1
-#define HAVE_READLINK 1
-#define HAVE_RMD160 1
-#define HAVE_SELECT 1
-#define HAVE_SETENV 1
-#define HAVE_SHA_H 1
-#define HAVE_SHA1 1
-#define HAVE_SHA256 1
-#define HAVE_SHA256_H 1
-#define HAVE_SIGNAL_H 1
-#define HAVE_STDINT_H 1
-#define HAVE_STDLIB_H 1
-#define HAVE_STRCHR 1
-#define HAVE_STRDUP 1
-#define HAVE_STRERROR 1
-#define HAVE_STRERROR_R 1
-#define HAVE_STRINGS_H 1
-#define HAVE_STRING_H 1
-#define HAVE_STRRCHR 1
-#define HAVE_STRUCT_STAT_ST_BLKSIZE 1
-#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1
-#define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 1
-#define HAVE_STRUCT_STAT_ST_FLAGS 1
-#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1
-#define HAVE_STRUCT_TM_TM_GMTOFF 1
-#define HAVE_SYMLINK 1
-#define HAVE_SYS_CDEFS_H 1
-#define HAVE_SYS_IOCTL_H 1
-#define HAVE_SYS_MOUNT_H 1
-#define HAVE_SYS_PARAM_H 1
-#define HAVE_SYS_SELECT_H 1
-#define HAVE_SYS_STAT_H 1
-#define HAVE_SYS_TIME_H 1
-#define HAVE_SYS_TYPES_H 1
-#undef HAVE_SYS_UTIME_H
-#define HAVE_SYS_UTSNAME_H 1
-#define HAVE_SYS_WAIT_H 1
-#define HAVE_TIMEGM 1
-#define HAVE_TZSET 1
-#define HAVE_UNISTD_H 1
-#define HAVE_UNSETENV 1
-#define HAVE_UTIME 1
-#define HAVE_UTIMES 1
-#define HAVE_UTIME_H 1
-#define HAVE_VFORK 1
-#define HAVE_WCHAR_H 1
-#define HAVE_WCSCPY 1
-#define HAVE_WCSLEN 1
-#define HAVE_WCTOMB 1
-#define HAVE_WMEMCMP 1
-#define HAVE_WMEMCPY 1
-#define HAVE_ZLIB_H 1
-#define TIME_WITH_SYS_TIME 1
+#define HAVE_BSDXML_H 1
+#define HAVE_BZLIB_H 1
+#define HAVE_CHFLAGS 1
+#define HAVE_CHOWN 1
+#define HAVE_CHROOT 1
+#define HAVE_CTIME_R 1
+#define HAVE_CTYPE_H 1
+#define HAVE_DECL_EXTATTR_NAMESPACE_USER 1
+#define HAVE_DECL_INT32_MAX 1
+#define HAVE_DECL_INT32_MIN 1
+#define HAVE_DECL_INT64_MAX 1
+#define HAVE_DECL_INT64_MIN 1
+#define HAVE_DECL_INTMAX_MAX 1
+#define HAVE_DECL_INTMAX_MIN 1
+#define HAVE_DECL_SIZE_MAX 1
+#define HAVE_DECL_SSIZE_MAX 1
+#define HAVE_DECL_STRERROR_R 1
+#define HAVE_DECL_UINT32_MAX 1
+#define HAVE_DECL_UINT64_MAX 1
+#define HAVE_DECL_UINTMAX_MAX 1
+#define HAVE_DIRENT_H 1
+#define HAVE_DLFCN_H 1
+#define HAVE_D_MD_ORDER 1
+#define HAVE_EFTYPE 1
+#define HAVE_EILSEQ 1
+#define HAVE_ERRNO_H 1
+#define HAVE_FCHDIR 1
+#define HAVE_FCHFLAGS 1
+#define HAVE_FCHMOD 1
+#define HAVE_FCHOWN 1
+#define HAVE_FCNTL 1
+#define HAVE_FCNTL_H 1
+#define HAVE_FDOPENDIR 1
+#define HAVE_FORK 1
+#define HAVE_FSEEKO 1
+#define HAVE_FSTAT 1
+#define HAVE_FSTATAT 1
+#define HAVE_FSTATFS 1
+#define HAVE_FSTATVFS 1
+#define HAVE_FTRUNCATE 1
+#define HAVE_FUTIMES 1
+#define HAVE_FUTIMESAT 1
+#define HAVE_GETEUID 1
+#define HAVE_GETGRGID_R 1
+#define HAVE_GETGRNAM_R 1
+#define HAVE_GETPID 1
+#define HAVE_GETPWNAM_R 1
+#define HAVE_GETPWUID_R 1
+#define HAVE_GETVFSBYNAME 1
+#define HAVE_GMTIME_R 1
+#define HAVE_GRP_H 1
+#define HAVE_INTMAX_T 1
+#define HAVE_INTTYPES_H 1
+#define HAVE_LANGINFO_H 1
+#define HAVE_LCHFLAGS 1
+#define HAVE_LCHMOD 1
+#define HAVE_LCHOWN 1
+#define HAVE_LIBZ 1
+#define HAVE_LIMITS_H 1
+#define HAVE_LINK 1
+#define HAVE_LOCALE_H 1
+#define HAVE_LOCALTIME_R 1
+#define HAVE_LONG_LONG_INT 1
+#define HAVE_LSTAT 1
+#define HAVE_LUTIMES 1
+#define HAVE_MBRTOWC 1
+#define HAVE_MEMMOVE 1
+#define HAVE_MEMORY_H 1
+#define HAVE_MEMSET 1
+#define HAVE_MKDIR 1
+#define HAVE_MKFIFO 1
+#define HAVE_MKNOD 1
+#define HAVE_MKSTEMP 1
+#define HAVE_NL_LANGINFO 1
+#define HAVE_OPENAT 1
+#define HAVE_PATHS_H 1
+#define HAVE_PIPE 1
+#define HAVE_POLL 1
+#define HAVE_POLL_H 1
+#define HAVE_POSIX_SPAWNP 1
+#define HAVE_PTHREAD_H 1
+#define HAVE_PWD_H 1
+#define HAVE_READDIR_R 1
+#define HAVE_READLINK 1
+#define HAVE_READLINKAT 1
+#define HAVE_READPASSPHRASE 1
+#define HAVE_READPASSPHRASE_H 1
+#define HAVE_REGEX_H 1
+#define HAVE_SELECT 1
+#define HAVE_SETENV 1
+#define HAVE_SETLOCALE 1
+#define HAVE_SIGACTION 1
+#define HAVE_SIGNAL_H 1
+#define HAVE_SPAWN_H 1
+#define HAVE_STATFS 1
+#define HAVE_STATVFS 1
+#define HAVE_STDARG_H 1
+#define HAVE_STDINT_H 1
+#define HAVE_STDLIB_H 1
+#define HAVE_STRCHR 1
+#define HAVE_STRDUP 1
+#define HAVE_STRERROR 1
+#define HAVE_STRERROR_R 1
+#define HAVE_STRFTIME 1
+#define HAVE_STRINGS_H 1
+#define HAVE_STRING_H 1
+#define HAVE_STRRCHR 1
+#define HAVE_STRUCT_STATFS_F_NAMEMAX 1
+#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1
+#define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 1
+#define HAVE_STRUCT_STAT_ST_BLKSIZE 1
+#define HAVE_STRUCT_STAT_ST_FLAGS 1
+#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1
+#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1
+#define HAVE_STRUCT_TM_TM_GMTOFF 1
+#define HAVE_SYMLINK 1
+#define HAVE_SYS_CDEFS_H 1
+#define HAVE_SYS_IOCTL_H 1
+#define HAVE_SYS_MOUNT_H 1
+#define HAVE_SYS_PARAM_H 1
+#define HAVE_SYS_POLL_H 1
+#define HAVE_SYS_SELECT_H 1
+#define HAVE_SYS_STATVFS_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TIME_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_SYS_UTSNAME_H 1
+#define HAVE_SYS_WAIT_H 1
+#define HAVE_TIMEGM 1
+#define HAVE_TIME_H 1
+#define HAVE_TZSET 1
+#define HAVE_UINTMAX_T 1
+#define HAVE_UNISTD_H 1
+#define HAVE_UNSETENV 1
+#define HAVE_UNSIGNED_LONG_LONG 1
+#define HAVE_UNSIGNED_LONG_LONG_INT 1
+#define HAVE_UTIME 1
+#define HAVE_UTIMES 1
+#define HAVE_UTIME_H 1
+#define HAVE_VFORK 1
+#define HAVE_VPRINTF 1
+#define HAVE_WCHAR_H 1
+#define HAVE_WCHAR_T 1
+#define HAVE_WCRTOMB 1
+#define HAVE_WCSCMP 1
+#define HAVE_WCSCPY 1
+#define HAVE_WCSLEN 1
+#define HAVE_WCTOMB 1
+#define HAVE_WCTYPE_H 1
+#define HAVE_WMEMCMP 1
+#define HAVE_WMEMCPY 1
+#define HAVE_WMEMMOVE 1
+#define HAVE_ZLIB_H 1
+#define TIME_WITH_SYS_TIME 1
+
+#if __FreeBSD_version >= 1100056
+#define HAVE_FUTIMENS 1
+#define HAVE_UTIMENSAT 1
+#endif
/* FreeBSD 4 and earlier lack intmax_t/uintmax_t */
#if __FreeBSD__ < 5
-#define intmax_t int64_t
-#define uintmax_t uint64_t
+#define intmax_t int64_t
+#define uintmax_t uint64_t
+#endif
+
+/* FreeBSD defines for archive_hash.h */
+#ifdef WITH_OPENSSL
+#define ARCHIVE_CRYPTO_MD5_OPENSSL 1
+#define ARCHIVE_CRYPTO_RMD160_OPENSSL 1
+#define ARCHIVE_CRYPTO_SHA1_OPENSSL
+#define ARCHIVE_CRYPTO_SHA256_OPENSSL 1
+#define ARCHIVE_CRYPTO_SHA384_OPENSSL 1
+#define ARCHIVE_CRYPTO_SHA512_OPENSSL 1
+#else
+#define ARCHIVE_CRYPTO_MD5_LIBMD 1
+#define ARCHIVE_CRYPTO_SHA1_LIBMD 1
+#define ARCHIVE_CRYPTO_SHA256_LIBMD 1
+#define ARCHIVE_CRYPTO_SHA512_LIBMD 1
#endif
diff --git a/3rdparty/libarchive/libarchive/filter_fork_windows.c b/3rdparty/libarchive/libarchive/filter_fork_windows.c
index fa59cc9e..ad271fe6 100644
--- a/3rdparty/libarchive/libarchive/filter_fork_windows.c
+++ b/3rdparty/libarchive/libarchive/filter_fork_windows.c
@@ -36,7 +36,7 @@ __archive_create_child(const char *cmd, int *child_stdin, int *child_stdout)
{
HANDLE childStdout[2], childStdin[2],childStderr;
SECURITY_ATTRIBUTES secAtts;
- STARTUPINFO staInfo;
+ STARTUPINFOA staInfo;
PROCESS_INFORMATION childInfo;
struct archive_string cmdline;
struct archive_string fullpath;
diff --git a/3rdparty/libarchive/qt_attribution.json b/3rdparty/libarchive/qt_attribution.json
index e0d04dd8..3abf2fcb 100644
--- a/3rdparty/libarchive/qt_attribution.json
+++ b/3rdparty/libarchive/qt_attribution.json
@@ -6,10 +6,10 @@
"Description": "Multi-format archive and compression library.",
"Homepage": "http://www.libarchive.org/",
- "Version": "3.1.2",
+ "Version": "3.3.2",
"License": "BSD 2-clause \"Simplified\" License",
"LicenseId": "BSD-2-Clause",
"LicenseFile": "COPYING",
- "Copyright": "(c) 2003-2016 Tim Kientzle et al. - see COPYING and the individual file headers"
+ "Copyright": "(c) 2003-2017 Tim Kientzle et al. - see COPYING and the individual file headers"
}
diff --git a/3rdparty/libyaml/README b/3rdparty/libyaml/README
index d35ebcc9..373727e0 100644
--- a/3rdparty/libyaml/README
+++ b/3rdparty/libyaml/README
@@ -5,7 +5,7 @@ $ ./configure
$ make
# make install
-If you checked the source code from the Subversion repository, run
+If you checked the source code from the Mercurial repository, run
$ ./bootstrap
$ ./configure
$ make
@@ -18,7 +18,7 @@ Post your questions and opinions to the YAML-Core mailing list:
'http://lists.sourceforge.net/lists/listinfo/yaml-core'.
Submit bug reports and feature requests to the LibYAML bug tracker:
-'http://pyyaml.org/newticket?component=libyaml'.
+'https://bitbucket.org/xi/libyaml/issues/new'.
LibYAML is written by Kirill Simonov <xi@resolvent.net>. It is released
under the MIT license. See the file LICENSE for more details.
diff --git a/3rdparty/libyaml/qt_attribution.json b/3rdparty/libyaml/qt_attribution.json
index 02465ec6..756df164 100644
--- a/3rdparty/libyaml/qt_attribution.json
+++ b/3rdparty/libyaml/qt_attribution.json
@@ -6,10 +6,10 @@
"Description": "LibYAML is a YAML 1.1 parser and emitter written in C.",
"Homepage": "http://pyyaml.org/wiki/LibYAML/",
- "Version": "0.1.6",
+ "Version": "0.1.7",
"License": "MIT License",
"LicenseId": "MIT",
"LicenseFile": "LICENSE",
- "Copyright": "Copyright (c) 2006-2016 Kirill Simonov"
+ "Copyright": "Copyright (c) 2006 Kirill Simonov"
}
diff --git a/3rdparty/libyaml/src/api.c b/3rdparty/libyaml/src/api.c
index daa94835..b1a8da0b 100644
--- a/3rdparty/libyaml/src/api.c
+++ b/3rdparty/libyaml/src/api.c
@@ -63,11 +63,7 @@ yaml_strdup(const yaml_char_t *str)
if (!str)
return NULL;
-#if defined(_WIN32) || defined(_WIN64)
- return (yaml_char_t *) _strdup((char *)str);
-#else
- return (yaml_char_t *) strdup((char *)str);
-#endif
+ return (yaml_char_t *)strdup((char *)str);
}
/*
@@ -419,7 +415,7 @@ yaml_string_write_handler(void *data, unsigned char *buffer, size_t size)
{
yaml_emitter_t *emitter = data;
- if (emitter->output.string.size + *emitter->output.string.size_written
+ if (emitter->output.string.size - *emitter->output.string.size_written
< size) {
memcpy(emitter->output.string.buffer
+ *emitter->output.string.size_written,
diff --git a/3rdparty/libyaml/win32/config.h b/3rdparty/libyaml/win32/config.h
index 2459f492..9ca2669a 100644
--- a/3rdparty/libyaml/win32/config.h
+++ b/3rdparty/libyaml/win32/config.h
@@ -1,4 +1,4 @@
#define YAML_VERSION_MAJOR 0
#define YAML_VERSION_MINOR 1
-#define YAML_VERSION_PATCH 6
-#define YAML_VERSION_STRING "0.1.6"
+#define YAML_VERSION_PATCH 7
+#define YAML_VERSION_STRING "0.1.7"