diff options
author | Robert Griebl <robert.griebl@pelagicore.com> | 2018-02-06 17:47:49 +0100 |
---|---|---|
committer | Dominik Holland <dominik.holland@pelagicore.com> | 2018-02-07 13:26:46 +0000 |
commit | 8df633d8195f16221ca348d527ab8671142f7426 (patch) | |
tree | 8abe6b75d476b4c63cba0371041b92a5e530fb24 | |
parent | b5b9138b77feb3b39e81eb95ebac347ccd1e7e06 (diff) | |
download | qtapplicationmanager-8df633d8195f16221ca348d527ab8671142f7426.tar.gz |
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>
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, ©_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, ©_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, ©_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(×tr, 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" |