Index: vendor/libarchive/dist/Makefile.am =================================================================== --- vendor/libarchive/dist/Makefile.am (revision 302036) +++ vendor/libarchive/dist/Makefile.am (revision 302037) @@ -1,1246 +1,1248 @@ ## Process this file with automake to produce Makefile.in AUTOMAKE_OPTIONS= foreign subdir-objects ACLOCAL_AMFLAGS = -I build/autoconf # # What to build and install # lib_LTLIBRARIES= libarchive.la noinst_LTLIBRARIES= libarchive_fe.la bin_PROGRAMS= $(bsdtar_programs) $(bsdcpio_programs) $(bsdcat_programs) man_MANS= $(libarchive_man_MANS) $(bsdtar_man_MANS) $(bsdcpio_man_MANS) $(bsdcat_man_MANS) BUILT_SOURCES= libarchive/test/list.h tar/test/list.h cpio/test/list.h cat/test/list.h # # What to test: We always test libarchive, test bsdtar and bsdcpio only # if we built them. # check_PROGRAMS= libarchive_test $(bsdtar_test_programs) $(bsdcpio_test_programs) $(bsdcat_test_programs) TESTS= libarchive_test $(bsdtar_test_programs) $(bsdcpio_test_programs) $(bsdcat_test_programs) TESTS_ENVIRONMENT= $(libarchive_TESTS_ENVIRONMENT) $(bsdtar_TESTS_ENVIRONMENT) $(bsdcpio_TESTS_ENVIRONMENT) $(bsdcat_TESTS_ENVIRONMENT) # Always build and test both bsdtar and bsdcpio as part of 'distcheck' DISTCHECK_CONFIGURE_FLAGS = --enable-bsdtar --enable-bsdcpio # The next line is commented out by default in shipping libarchive releases. # It is uncommented by default in trunk. DEV_CFLAGS=-Werror -Wextra -Wunused -Wshadow -Wmissing-prototypes -Wcast-qual -g AM_CFLAGS=$(DEV_CFLAGS) PLATFORMCPPFLAGS = @PLATFORMCPPFLAGS@ AM_CPPFLAGS=$(PLATFORMCPPFLAGS) # # What to include in the distribution # EXTRA_DIST= \ CMakeLists.txt \ build/autogen.sh \ build/bump-version.sh \ build/clean.sh \ build/cmake \ build/version \ contrib \ doc \ examples \ $(libarchive_EXTRA_DIST) \ $(libarchive_test_EXTRA_DIST) \ $(bsdtar_EXTRA_DIST) \ $(bsdtar_test_EXTRA_DIST) \ $(bsdcpio_EXTRA_DIST) \ $(bsdcpio_test_EXTRA_DIST) \ $(bsdcat_EXTRA_DIST) \ $(bsdcat_test_EXTRA_DIST) # a) Clean out some unneeded files and directories # b) Collect all documentation and format it for distribution. dist-hook: rm -rf `find $(distdir) -name CVS -type d` rm -rf `find $(distdir) -name .svn -type d` rm -f `find $(distdir) -name '*~'` rm -f `find $(distdir) -name '*.out'` rm -f `find $(distdir) -name '*.core'` -rm -f $(distdir)/*/Makefile $(distdir)/*/*/Makefile cd $(distdir)/doc && /bin/sh update.sh # # Extra rules for cleanup # DISTCLEANFILES= \ libarchive/test/list.h \ tar/test/list.h \ cpio/test/list.h \ cat/test/list.h distclean-local: -rm -rf .ref -rm -rf autom4te.cache/ -rm -f *~ -[ -f libarchive/Makefile ] && cd libarchive && make clean -[ -f libarchive/test/Makefile ] && cd libarchive/test && make clean -[ -f tar/Makefile ] && cd tar && make clean -[ -f tar/test/Makefile ] && cd tar/test && make clean -[ -f cpio/Makefile ] && cd cpio && make clean -[ -f cpio/test/Makefile ] && cd cpio/test && make clean -[ -f cat/Makefile ] && cd cat && make clean -[ -f cpio/test/Makefile ] && cd cat/test && make clean # # Libarchive headers, source, etc. # # include_HEADERS= libarchive/archive.h libarchive/archive_entry.h libarchive_la_SOURCES= \ libarchive/archive_acl.c \ libarchive/archive_acl_private.h \ libarchive/archive_check_magic.c \ libarchive/archive_cmdline.c \ libarchive/archive_cmdline_private.h \ libarchive/archive_crc32.h \ libarchive/archive_cryptor.c \ libarchive/archive_cryptor_private.h \ libarchive/archive_digest.c \ libarchive/archive_digest_private.h \ libarchive/archive_endian.h \ libarchive/archive_entry.c \ libarchive/archive_entry.h \ libarchive/archive_entry_copy_stat.c \ libarchive/archive_entry_link_resolver.c \ libarchive/archive_entry_locale.h \ libarchive/archive_entry_private.h \ libarchive/archive_entry_sparse.c \ libarchive/archive_entry_stat.c \ libarchive/archive_entry_strmode.c \ libarchive/archive_entry_xattr.c \ libarchive/archive_getdate.c \ libarchive/archive_getdate.h \ libarchive/archive_hmac.c \ libarchive/archive_hmac_private.h \ libarchive/archive_match.c \ libarchive/archive_options.c \ libarchive/archive_options_private.h \ libarchive/archive_pack_dev.h \ libarchive/archive_pack_dev.c \ libarchive/archive_pathmatch.c \ libarchive/archive_pathmatch.h \ libarchive/archive_platform.h \ libarchive/archive_ppmd_private.h \ libarchive/archive_ppmd7.c \ libarchive/archive_ppmd7_private.h \ libarchive/archive_private.h \ libarchive/archive_random.c \ libarchive/archive_random_private.h \ libarchive/archive_rb.c \ libarchive/archive_rb.h \ libarchive/archive_read.c \ libarchive/archive_read_add_passphrase.c \ libarchive/archive_read_append_filter.c \ libarchive/archive_read_data_into_fd.c \ libarchive/archive_read_disk_entry_from_file.c \ libarchive/archive_read_disk_posix.c \ libarchive/archive_read_disk_private.h \ libarchive/archive_read_disk_set_standard_lookup.c \ libarchive/archive_read_extract.c \ libarchive/archive_read_extract2.c \ libarchive/archive_read_open_fd.c \ libarchive/archive_read_open_file.c \ libarchive/archive_read_open_filename.c \ libarchive/archive_read_open_memory.c \ libarchive/archive_read_private.h \ 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_lz4.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_warc.c \ libarchive/archive_read_support_format_xar.c \ libarchive/archive_read_support_format_zip.c \ libarchive/archive_string.c \ libarchive/archive_string.h \ libarchive/archive_string_composition.h \ libarchive/archive_string_sprintf.c \ libarchive/archive_util.c \ libarchive/archive_virtual.c \ libarchive/archive_write.c \ libarchive/archive_write_disk_acl.c \ libarchive/archive_write_disk_posix.c \ libarchive/archive_write_disk_private.h \ 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_private.h \ libarchive/archive_write_add_filter.c \ libarchive/archive_write_add_filter_b64encode.c \ libarchive/archive_write_add_filter_by_name.c \ libarchive/archive_write_add_filter_bzip2.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_lz4.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_set_format.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_cpio.c \ libarchive/archive_write_set_format_cpio_newc.c \ libarchive/archive_write_set_format_filter_by_ext.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_raw.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_gnutar.c \ libarchive/archive_write_set_format_warc.c \ libarchive/archive_write_set_format_xar.c \ libarchive/archive_write_set_format_zip.c \ libarchive/archive_write_set_options.c \ libarchive/archive_write_set_passphrase.c \ libarchive/archive_xxhash.h \ libarchive/config_freebsd.h \ libarchive/filter_fork_posix.c \ libarchive/filter_fork.h \ libarchive/xxhash.c if INC_WINDOWS_FILES libarchive_la_SOURCES+= \ libarchive/archive_entry_copy_bhfi.c \ libarchive/archive_read_disk_windows.c \ libarchive/archive_windows.h \ libarchive/archive_windows.c \ libarchive/archive_write_disk_windows.c \ libarchive/filter_fork_windows.c endif # -no-undefined marks that libarchive doesn't rely on symbols # defined in the application. This is mandatory for cygwin. libarchive_la_LDFLAGS= -no-undefined -version-info $(ARCHIVE_LIBTOOL_VERSION) libarchive_la_LIBADD= $(LTLIBICONV) # Manpages to install libarchive_man_MANS= \ libarchive/archive_entry.3 \ libarchive/archive_entry_acl.3 \ libarchive/archive_entry_linkify.3 \ libarchive/archive_entry_paths.3 \ libarchive/archive_entry_perms.3 \ libarchive/archive_entry_stat.3 \ libarchive/archive_entry_time.3 \ libarchive/archive_read.3 \ libarchive/archive_read_add_passphrase.3 \ libarchive/archive_read_data.3 \ libarchive/archive_read_disk.3 \ libarchive/archive_read_extract.3 \ libarchive/archive_read_filter.3 \ libarchive/archive_read_format.3 \ libarchive/archive_read_free.3 \ libarchive/archive_read_header.3 \ libarchive/archive_read_new.3 \ libarchive/archive_read_open.3 \ libarchive/archive_read_set_options.3 \ libarchive/archive_util.3 \ libarchive/archive_write.3 \ libarchive/archive_write_blocksize.3 \ libarchive/archive_write_data.3 \ libarchive/archive_write_disk.3 \ libarchive/archive_write_filter.3 \ libarchive/archive_write_finish_entry.3 \ libarchive/archive_write_format.3 \ libarchive/archive_write_free.3 \ libarchive/archive_write_header.3 \ libarchive/archive_write_new.3 \ libarchive/archive_write_open.3 \ libarchive/archive_write_set_options.3 \ libarchive/archive_write_set_passphrase.3 \ libarchive/cpio.5 \ libarchive/libarchive.3 \ libarchive/libarchive_changes.3 \ libarchive/libarchive_internals.3 \ libarchive/libarchive-formats.5 \ libarchive/mtree.5 \ libarchive/tar.5 # Additional libarchive files to include in the distribution libarchive_EXTRA_DIST= \ libarchive/archive_windows.c \ libarchive/archive_windows.h \ libarchive/filter_fork_windows.c \ libarchive/CMakeLists.txt \ $(libarchive_man_MANS) # pkgconfig pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = build/pkgconfig/libarchive.pc # Sources needed by all test programs test_utils_SOURCES= \ test_utils/test_utils.c \ test_utils/test_utils.h # # # libarchive_test program # # libarchive_test_SOURCES= \ $(libarchive_la_SOURCES) \ $(test_utils_SOURCES) \ libarchive/test/main.c \ libarchive/test/read_open_memory.c \ libarchive/test/test.h \ libarchive/test/test_acl_freebsd_posix1e.c \ libarchive/test/test_acl_freebsd_nfs4.c \ libarchive/test/test_acl_nfs4.c \ libarchive/test/test_acl_pax.c \ libarchive/test/test_acl_posix1e.c \ libarchive/test/test_archive_api_feature.c \ libarchive/test/test_archive_clear_error.c \ libarchive/test/test_archive_cmdline.c \ libarchive/test/test_archive_digest.c \ libarchive/test/test_archive_getdate.c \ libarchive/test/test_archive_match_owner.c \ libarchive/test/test_archive_match_path.c \ libarchive/test/test_archive_match_time.c \ libarchive/test/test_archive_pathmatch.c \ libarchive/test/test_archive_read_add_passphrase.c \ libarchive/test/test_archive_read_close_twice.c \ libarchive/test/test_archive_read_close_twice_open_fd.c \ libarchive/test/test_archive_read_close_twice_open_filename.c \ libarchive/test/test_archive_read_multiple_data_objects.c \ libarchive/test/test_archive_read_next_header_empty.c \ libarchive/test/test_archive_read_next_header_raw.c \ libarchive/test/test_archive_read_open2.c \ libarchive/test/test_archive_read_set_filter_option.c \ libarchive/test/test_archive_read_set_format_option.c \ libarchive/test/test_archive_read_set_option.c \ libarchive/test/test_archive_read_set_options.c \ libarchive/test/test_archive_read_support.c \ libarchive/test/test_archive_set_error.c \ libarchive/test/test_archive_string.c \ libarchive/test/test_archive_string_conversion.c \ libarchive/test/test_archive_write_add_filter_by_name.c \ libarchive/test/test_archive_write_set_filter_option.c \ libarchive/test/test_archive_write_set_format_by_name.c \ libarchive/test/test_archive_write_set_format_filter_by_ext.c \ libarchive/test/test_archive_write_set_format_option.c \ libarchive/test/test_archive_write_set_option.c \ libarchive/test/test_archive_write_set_options.c \ libarchive/test/test_archive_write_set_passphrase.c \ libarchive/test/test_bad_fd.c \ libarchive/test/test_compat_bzip2.c \ libarchive/test/test_compat_cpio.c \ libarchive/test/test_compat_gtar.c \ libarchive/test/test_compat_gzip.c \ libarchive/test/test_compat_lz4.c \ libarchive/test/test_compat_lzip.c \ libarchive/test/test_compat_lzma.c \ libarchive/test/test_compat_lzop.c \ libarchive/test/test_compat_mac.c \ libarchive/test/test_compat_pax_libarchive_2x.c \ libarchive/test/test_compat_solaris_tar_acl.c \ libarchive/test/test_compat_solaris_pax_sparse.c \ libarchive/test/test_compat_tar_hardlink.c \ libarchive/test/test_compat_uudecode.c \ libarchive/test/test_compat_uudecode_large.c \ libarchive/test/test_compat_xz.c \ libarchive/test/test_compat_zip.c \ libarchive/test/test_empty_write.c \ libarchive/test/test_entry.c \ libarchive/test/test_entry_strmode.c \ libarchive/test/test_extattr_freebsd.c \ libarchive/test/test_filter_count.c \ libarchive/test/test_fuzz.c \ libarchive/test/test_gnutar_filename_encoding.c \ libarchive/test/test_link_resolver.c \ libarchive/test/test_open_failure.c \ libarchive/test/test_open_fd.c \ libarchive/test/test_open_file.c \ libarchive/test/test_open_filename.c \ libarchive/test/test_pax_filename_encoding.c \ libarchive/test/test_read_data_large.c \ libarchive/test/test_read_disk.c \ libarchive/test/test_read_disk_directory_traversals.c \ libarchive/test/test_read_disk_entry_from_file.c \ libarchive/test/test_read_extract.c \ libarchive/test/test_read_file_nonexistent.c \ libarchive/test/test_read_filter_compress.c \ libarchive/test/test_read_filter_grzip.c \ libarchive/test/test_read_filter_lrzip.c \ libarchive/test/test_read_filter_lzop.c \ libarchive/test/test_read_filter_lzop_multiple_parts.c \ libarchive/test/test_read_filter_program.c \ libarchive/test/test_read_filter_program_signature.c \ libarchive/test/test_read_filter_uudecode.c \ libarchive/test/test_read_format_7zip.c \ libarchive/test/test_read_format_7zip_encryption_data.c \ libarchive/test/test_read_format_7zip_encryption_partially.c \ libarchive/test/test_read_format_7zip_encryption_header.c \ libarchive/test/test_read_format_7zip_malformed.c \ libarchive/test/test_read_format_ar.c \ libarchive/test/test_read_format_cab.c \ libarchive/test/test_read_format_cab_filename.c \ libarchive/test/test_read_format_cpio_afio.c \ libarchive/test/test_read_format_cpio_bin.c \ libarchive/test/test_read_format_cpio_bin_Z.c \ libarchive/test/test_read_format_cpio_bin_be.c \ libarchive/test/test_read_format_cpio_bin_bz2.c \ libarchive/test/test_read_format_cpio_bin_gz.c \ libarchive/test/test_read_format_cpio_bin_le.c \ libarchive/test/test_read_format_cpio_bin_lzip.c \ libarchive/test/test_read_format_cpio_bin_lzma.c \ libarchive/test/test_read_format_cpio_bin_xz.c \ libarchive/test/test_read_format_cpio_filename.c \ libarchive/test/test_read_format_cpio_odc.c \ libarchive/test/test_read_format_cpio_svr4_bzip2_rpm.c \ libarchive/test/test_read_format_cpio_svr4_gzip.c \ libarchive/test/test_read_format_cpio_svr4_gzip_rpm.c \ libarchive/test/test_read_format_cpio_svr4c_Z.c \ libarchive/test/test_read_format_empty.c \ libarchive/test/test_read_format_gtar_filename.c \ libarchive/test/test_read_format_gtar_gz.c \ libarchive/test/test_read_format_gtar_lzma.c \ libarchive/test/test_read_format_gtar_sparse.c \ libarchive/test/test_read_format_gtar_sparse_skip_entry.c \ libarchive/test/test_read_format_iso_Z.c \ libarchive/test/test_read_format_iso_multi_extent.c \ libarchive/test/test_read_format_iso_xorriso.c \ libarchive/test/test_read_format_isojoliet_bz2.c \ libarchive/test/test_read_format_isojoliet_long.c \ libarchive/test/test_read_format_isojoliet_rr.c \ libarchive/test/test_read_format_isojoliet_versioned.c \ libarchive/test/test_read_format_isorr_bz2.c \ libarchive/test/test_read_format_isorr_ce.c \ libarchive/test/test_read_format_isorr_new_bz2.c \ libarchive/test/test_read_format_isorr_rr_moved.c \ libarchive/test/test_read_format_isozisofs_bz2.c \ libarchive/test/test_read_format_lha.c \ libarchive/test/test_read_format_lha_bugfix_0.c \ libarchive/test/test_read_format_lha_filename.c \ libarchive/test/test_read_format_mtree.c \ libarchive/test/test_read_format_pax_bz2.c \ libarchive/test/test_read_format_rar.c \ libarchive/test/test_read_format_rar_encryption_data.c \ libarchive/test/test_read_format_rar_encryption_partially.c \ libarchive/test/test_read_format_rar_encryption_header.c \ + libarchive/test/test_read_format_rar_invalid1.c \ libarchive/test/test_read_format_raw.c \ libarchive/test/test_read_format_tar.c \ libarchive/test/test_read_format_tar_concatenated.c \ libarchive/test/test_read_format_tar_empty_pax.c \ libarchive/test/test_read_format_tar_empty_filename.c \ libarchive/test/test_read_format_tar_filename.c \ libarchive/test/test_read_format_tbz.c \ libarchive/test/test_read_format_tgz.c \ libarchive/test/test_read_format_tlz.c \ libarchive/test/test_read_format_txz.c \ libarchive/test/test_read_format_tz.c \ libarchive/test/test_read_format_ustar_filename.c \ libarchive/test/test_read_format_warc.c \ libarchive/test/test_read_format_xar.c \ libarchive/test/test_read_format_zip.c \ libarchive/test/test_read_format_zip_comment_stored.c \ libarchive/test/test_read_format_zip_encryption_data.c \ libarchive/test/test_read_format_zip_encryption_partially.c \ libarchive/test/test_read_format_zip_encryption_header.c \ libarchive/test/test_read_format_zip_filename.c \ libarchive/test/test_read_format_zip_mac_metadata.c \ libarchive/test/test_read_format_zip_malformed.c \ libarchive/test/test_read_format_zip_msdos.c \ libarchive/test/test_read_format_zip_nested.c \ libarchive/test/test_read_format_zip_nofiletype.c \ libarchive/test/test_read_format_zip_padded.c \ libarchive/test/test_read_format_zip_sfx.c \ libarchive/test/test_read_format_zip_traditional_encryption_data.c \ libarchive/test/test_read_format_zip_winzip_aes.c \ libarchive/test/test_read_format_zip_winzip_aes_large.c \ libarchive/test/test_read_format_zip_zip64.c \ libarchive/test/test_read_large.c \ libarchive/test/test_read_pax_truncated.c \ libarchive/test/test_read_position.c \ libarchive/test/test_read_set_format.c \ libarchive/test/test_read_too_many_filters.c \ libarchive/test/test_read_truncated.c \ libarchive/test/test_read_truncated_filter.c \ libarchive/test/test_sparse_basic.c \ libarchive/test/test_tar_filenames.c \ libarchive/test/test_tar_large.c \ libarchive/test/test_ustar_filenames.c \ libarchive/test/test_ustar_filename_encoding.c \ libarchive/test/test_warn_missing_hardlink_target.c \ libarchive/test/test_write_disk.c \ libarchive/test/test_write_disk_appledouble.c \ libarchive/test/test_write_disk_failures.c \ libarchive/test/test_write_disk_hardlink.c \ libarchive/test/test_write_disk_hfs_compression.c \ libarchive/test/test_write_disk_lookup.c \ libarchive/test/test_write_disk_mac_metadata.c \ libarchive/test/test_write_disk_no_hfs_compression.c \ libarchive/test/test_write_disk_perms.c \ libarchive/test/test_write_disk_secure.c \ libarchive/test/test_write_disk_sparse.c \ libarchive/test/test_write_disk_symlink.c \ libarchive/test/test_write_disk_times.c \ libarchive/test/test_write_filter_b64encode.c \ libarchive/test/test_write_filter_bzip2.c \ libarchive/test/test_write_filter_compress.c \ libarchive/test/test_write_filter_gzip.c \ libarchive/test/test_write_filter_gzip_timestamp.c \ libarchive/test/test_write_filter_lrzip.c \ libarchive/test/test_write_filter_lz4.c \ libarchive/test/test_write_filter_lzip.c \ libarchive/test/test_write_filter_lzma.c \ libarchive/test/test_write_filter_lzop.c \ libarchive/test/test_write_filter_program.c \ libarchive/test/test_write_filter_uuencode.c \ libarchive/test/test_write_filter_xz.c \ libarchive/test/test_write_format_7zip.c \ libarchive/test/test_write_format_7zip_empty.c \ libarchive/test/test_write_format_7zip_large.c \ libarchive/test/test_write_format_ar.c \ libarchive/test/test_write_format_cpio.c \ libarchive/test/test_write_format_cpio_empty.c \ libarchive/test/test_write_format_cpio_newc.c \ libarchive/test/test_write_format_cpio_odc.c \ libarchive/test/test_write_format_gnutar.c \ libarchive/test/test_write_format_gnutar_filenames.c \ libarchive/test/test_write_format_iso9660.c \ libarchive/test/test_write_format_iso9660_boot.c \ libarchive/test/test_write_format_iso9660_empty.c \ libarchive/test/test_write_format_iso9660_filename.c \ libarchive/test/test_write_format_iso9660_zisofs.c \ libarchive/test/test_write_format_mtree.c \ libarchive/test/test_write_format_mtree_absolute_path.c \ libarchive/test/test_write_format_mtree_classic.c \ libarchive/test/test_write_format_mtree_classic_indent.c\ libarchive/test/test_write_format_mtree_fflags.c \ libarchive/test/test_write_format_mtree_no_separator.c \ libarchive/test/test_write_format_mtree_quoted_filename.c\ libarchive/test/test_write_format_pax.c \ libarchive/test/test_write_format_raw.c \ libarchive/test/test_write_format_raw_b64.c \ libarchive/test/test_write_format_shar_empty.c \ libarchive/test/test_write_format_tar.c \ libarchive/test/test_write_format_tar_empty.c \ libarchive/test/test_write_format_tar_sparse.c \ libarchive/test/test_write_format_tar_ustar.c \ libarchive/test/test_write_format_tar_v7tar.c \ libarchive/test/test_write_format_warc.c \ libarchive/test/test_write_format_warc_empty.c \ libarchive/test/test_write_format_xar.c \ libarchive/test/test_write_format_xar_empty.c \ libarchive/test/test_write_format_zip.c \ libarchive/test/test_write_format_zip_compression_store.c \ libarchive/test/test_write_format_zip_empty.c \ libarchive/test/test_write_format_zip_empty_zip64.c \ libarchive/test/test_write_format_zip_file.c \ libarchive/test/test_write_format_zip_file_zip64.c \ libarchive/test/test_write_format_zip_large.c \ libarchive/test/test_write_format_zip_zip64.c \ libarchive/test/test_write_open_memory.c \ libarchive/test/test_write_read_format_zip.c \ libarchive/test/test_zip_filename_encoding.c libarchive_test_CPPFLAGS= -I$(top_srcdir)/libarchive -I$(top_srcdir)/test_utils -I$(top_builddir)/libarchive/test -DLIBARCHIVE_STATIC $(PLATFORMCPPFLAGS) libarchive_test_LDADD= $(LTLIBICONV) # The "list.h" file just lists all of the tests defined in all of the sources. # Building it automatically provides a sanity-check on libarchive_test_SOURCES # above. libarchive/test/list.h: Makefile $(MKDIR_P) libarchive/test cat $(top_srcdir)/libarchive/test/test_*.c | grep '^DEFINE_TEST' > libarchive/test/list.h libarchive_TESTS_ENVIRONMENT= LIBARCHIVE_TEST_FILES=`cd $(top_srcdir);/bin/pwd`/libarchive/test LRZIP=NOCONFIG libarchive_test_EXTRA_DIST=\ libarchive/test/list.h \ libarchive/test/test_acl_pax.tar.uu \ libarchive/test/test_archive_string_conversion.txt.Z.uu \ libarchive/test/test_compat_bzip2_1.tbz.uu \ libarchive/test/test_compat_bzip2_2.tbz.uu \ libarchive/test/test_compat_cpio_1.cpio.uu \ libarchive/test/test_compat_gtar_1.tar.uu \ libarchive/test/test_compat_gzip_1.tgz.uu \ libarchive/test/test_compat_gzip_2.tgz.uu \ libarchive/test/test_compat_lz4_1.tar.lz4.uu \ libarchive/test/test_compat_lz4_2.tar.lz4.uu \ libarchive/test/test_compat_lz4_3.tar.lz4.uu \ libarchive/test/test_compat_lz4_B4.tar.lz4.uu \ libarchive/test/test_compat_lz4_B4BD.tar.lz4.uu \ libarchive/test/test_compat_lz4_B4BDBX.tar.lz4.uu \ libarchive/test/test_compat_lz4_B5.tar.lz4.uu \ libarchive/test/test_compat_lz4_B5BD.tar.lz4.uu \ libarchive/test/test_compat_lz4_B6.tar.lz4.uu \ libarchive/test/test_compat_lz4_B6BD.tar.lz4.uu \ libarchive/test/test_compat_lz4_B7.tar.lz4.uu \ libarchive/test/test_compat_lz4_B7BD.tar.lz4.uu \ libarchive/test/test_compat_lzip_1.tlz.uu \ libarchive/test/test_compat_lzip_2.tlz.uu \ libarchive/test/test_compat_lzma_1.tlz.uu \ libarchive/test/test_compat_lzma_2.tlz.uu \ libarchive/test/test_compat_lzma_3.tlz.uu \ libarchive/test/test_compat_lzop_1.tar.lzo.uu \ libarchive/test/test_compat_lzop_2.tar.lzo.uu \ libarchive/test/test_compat_lzop_3.tar.lzo.uu \ libarchive/test/test_compat_mac-1.tar.Z.uu \ libarchive/test/test_compat_mac-2.tar.Z.uu \ libarchive/test/test_compat_pax_libarchive_2x.tar.Z.uu \ libarchive/test/test_compat_solaris_pax_sparse_1.pax.Z.uu \ libarchive/test/test_compat_solaris_pax_sparse_2.pax.Z.uu \ libarchive/test/test_compat_solaris_tar_acl.tar.uu \ libarchive/test/test_compat_tar_hardlink_1.tar.uu \ libarchive/test/test_compat_uudecode_large.tar.Z.uu \ libarchive/test/test_compat_xz_1.txz.uu \ libarchive/test/test_compat_zip_1.zip.uu \ libarchive/test/test_compat_zip_2.zip.uu \ libarchive/test/test_compat_zip_3.zip.uu \ libarchive/test/test_compat_zip_4.zip.uu \ libarchive/test/test_compat_zip_5.zip.uu \ libarchive/test/test_compat_zip_6.zip.uu \ libarchive/test/test_compat_zip_7.xps.uu \ libarchive/test/test_fuzz.cab.uu \ libarchive/test/test_fuzz.lzh.uu \ libarchive/test/test_fuzz_1.iso.Z.uu \ libarchive/test/test_pax_filename_encoding.tar.uu \ libarchive/test/test_rar_multivolume_multiple_files.part1.rar.uu \ libarchive/test/test_rar_multivolume_multiple_files.part2.rar.uu \ libarchive/test/test_rar_multivolume_multiple_files.part3.rar.uu \ libarchive/test/test_rar_multivolume_multiple_files.part4.rar.uu \ libarchive/test/test_rar_multivolume_multiple_files.part5.rar.uu \ libarchive/test/test_rar_multivolume_multiple_files.part6.rar.uu \ libarchive/test/test_rar_multivolume_single_file.part1.rar.uu \ libarchive/test/test_rar_multivolume_single_file.part2.rar.uu \ libarchive/test/test_rar_multivolume_single_file.part3.rar.uu \ libarchive/test/test_rar_multivolume_uncompressed_files.part01.rar.uu \ libarchive/test/test_rar_multivolume_uncompressed_files.part02.rar.uu \ libarchive/test/test_rar_multivolume_uncompressed_files.part03.rar.uu \ libarchive/test/test_rar_multivolume_uncompressed_files.part04.rar.uu \ libarchive/test/test_rar_multivolume_uncompressed_files.part05.rar.uu \ libarchive/test/test_rar_multivolume_uncompressed_files.part06.rar.uu \ libarchive/test/test_rar_multivolume_uncompressed_files.part07.rar.uu \ libarchive/test/test_rar_multivolume_uncompressed_files.part08.rar.uu \ libarchive/test/test_rar_multivolume_uncompressed_files.part09.rar.uu \ libarchive/test/test_rar_multivolume_uncompressed_files.part10.rar.uu \ libarchive/test/test_read_filter_grzip.tar.grz.uu \ libarchive/test/test_read_filter_lrzip.tar.lrz.uu \ libarchive/test/test_read_filter_lzop.tar.lzo.uu \ libarchive/test/test_read_filter_lzop_multiple_parts.tar.lzo.uu \ libarchive/test/test_read_format_7zip_bcj2_bzip2.7z.uu \ libarchive/test/test_read_format_7zip_bcj2_copy_1.7z.uu \ libarchive/test/test_read_format_7zip_bcj2_copy_2.7z.uu \ libarchive/test/test_read_format_7zip_bcj2_copy_lzma.7z.uu \ libarchive/test/test_read_format_7zip_bcj2_deflate.7z.uu \ libarchive/test/test_read_format_7zip_bcj2_lzma1_1.7z.uu \ libarchive/test/test_read_format_7zip_bcj2_lzma1_2.7z.uu \ libarchive/test/test_read_format_7zip_bcj2_lzma2_1.7z.uu \ libarchive/test/test_read_format_7zip_bcj2_lzma2_2.7z.uu \ libarchive/test/test_read_format_7zip_bcj_bzip2.7z.uu \ libarchive/test/test_read_format_7zip_bcj_copy.7z.uu \ libarchive/test/test_read_format_7zip_bcj_deflate.7z.uu \ libarchive/test/test_read_format_7zip_bcj_lzma1.7z.uu \ libarchive/test/test_read_format_7zip_bcj_lzma2.7z.uu \ libarchive/test/test_read_format_7zip_bzip2.7z.uu \ libarchive/test/test_read_format_7zip_copy.7z.uu \ libarchive/test/test_read_format_7zip_copy_2.7z.uu \ libarchive/test/test_read_format_7zip_deflate.7z.uu \ libarchive/test/test_read_format_7zip_delta_lzma1.7z.uu \ libarchive/test/test_read_format_7zip_delta_lzma2.7z.uu \ libarchive/test/test_read_format_7zip_empty_archive.7z.uu \ libarchive/test/test_read_format_7zip_empty_file.7z.uu \ libarchive/test/test_read_format_7zip_encryption.7z.uu \ libarchive/test/test_read_format_7zip_encryption_header.7z.uu \ libarchive/test/test_read_format_7zip_encryption_partially.7z.uu \ libarchive/test/test_read_format_7zip_lzma1.7z.uu \ libarchive/test/test_read_format_7zip_lzma1_2.7z.uu \ libarchive/test/test_read_format_7zip_lzma1_lzma2.7z.uu \ libarchive/test/test_read_format_7zip_lzma2.7z.uu \ libarchive/test/test_read_format_7zip_malformed.7z.uu \ libarchive/test/test_read_format_7zip_malformed2.7z.uu \ libarchive/test/test_read_format_7zip_ppmd.7z.uu \ libarchive/test/test_read_format_7zip_symbolic_name.7z.uu \ libarchive/test/test_read_format_ar.ar.uu \ libarchive/test/test_read_format_cab_1.cab.uu \ libarchive/test/test_read_format_cab_2.cab.uu \ libarchive/test/test_read_format_cab_3.cab.uu \ libarchive/test/test_read_format_cab_filename_cp932.cab.uu \ libarchive/test/test_read_format_cpio_bin_be.cpio.uu \ libarchive/test/test_read_format_cpio_bin_le.cpio.uu \ libarchive/test/test_read_format_cpio_filename_cp866.cpio.uu \ libarchive/test/test_read_format_cpio_filename_eucjp.cpio.uu \ libarchive/test/test_read_format_cpio_filename_koi8r.cpio.uu \ libarchive/test/test_read_format_cpio_filename_utf8_jp.cpio.uu \ libarchive/test/test_read_format_cpio_filename_utf8_ru.cpio.uu \ libarchive/test/test_read_format_cpio_svr4_bzip2_rpm.rpm.uu \ libarchive/test/test_read_format_cpio_svr4_gzip_rpm.rpm.uu \ libarchive/test/test_read_format_gtar_filename_cp866.tar.Z.uu \ libarchive/test/test_read_format_gtar_filename_eucjp.tar.Z.uu \ libarchive/test/test_read_format_gtar_filename_koi8r.tar.Z.uu \ libarchive/test/test_read_format_gtar_sparse_1_13.tar.uu \ libarchive/test/test_read_format_gtar_sparse_1_17.tar.uu \ libarchive/test/test_read_format_gtar_sparse_1_17_posix00.tar.uu \ libarchive/test/test_read_format_gtar_sparse_1_17_posix01.tar.uu \ libarchive/test/test_read_format_gtar_sparse_1_17_posix10.tar.uu \ libarchive/test/test_read_format_gtar_sparse_1_17_posix10_modified.tar.uu \ libarchive/test/test_read_format_gtar_sparse_skip_entry.tar.Z.uu \ libarchive/test/test_read_format_iso.iso.Z.uu \ libarchive/test/test_read_format_iso_2.iso.Z.uu \ libarchive/test/test_read_format_iso_joliet.iso.Z.uu \ libarchive/test/test_read_format_iso_joliet_by_nero.iso.Z.uu \ libarchive/test/test_read_format_iso_joliet_long.iso.Z.uu \ libarchive/test/test_read_format_iso_joliet_rockridge.iso.Z.uu \ libarchive/test/test_read_format_iso_multi_extent.iso.Z.uu \ libarchive/test/test_read_format_iso_rockridge.iso.Z.uu \ libarchive/test/test_read_format_iso_rockridge_ce.iso.Z.uu \ libarchive/test/test_read_format_iso_rockridge_new.iso.Z.uu \ libarchive/test/test_read_format_iso_rockridge_rr_moved.iso.Z.uu \ libarchive/test/test_read_format_iso_xorriso.iso.Z.uu \ libarchive/test/test_read_format_iso_zisofs.iso.Z.uu \ libarchive/test/test_read_format_lha_bugfix_0.lzh.uu \ libarchive/test/test_read_format_lha_filename_cp932.lzh.uu \ libarchive/test/test_read_format_lha_header0.lzh.uu \ libarchive/test/test_read_format_lha_header1.lzh.uu \ libarchive/test/test_read_format_lha_header2.lzh.uu \ libarchive/test/test_read_format_lha_header3.lzh.uu \ libarchive/test/test_read_format_lha_lh0.lzh.uu \ libarchive/test/test_read_format_lha_lh6.lzh.uu \ libarchive/test/test_read_format_lha_lh7.lzh.uu \ libarchive/test/test_read_format_lha_withjunk.lzh.uu \ libarchive/test/test_read_format_mtree.mtree.uu \ libarchive/test/test_read_format_mtree_nomagic.mtree.uu \ libarchive/test/test_read_format_mtree_nomagic2.mtree.uu \ libarchive/test/test_read_format_mtree_nomagic3.mtree.uu \ libarchive/test/test_read_format_rar.rar.uu \ libarchive/test/test_read_format_rar_binary_data.rar.uu \ libarchive/test/test_read_format_rar_compress_best.rar.uu \ libarchive/test/test_read_format_rar_compress_normal.rar.uu \ libarchive/test/test_read_format_rar_encryption_data.rar.uu \ libarchive/test/test_read_format_rar_encryption_header.rar.uu \ libarchive/test/test_read_format_rar_encryption_partially.rar.uu \ + libarchive/test/test_read_format_rar_invalid1.rar.uu \ libarchive/test/test_read_format_rar_multi_lzss_blocks.rar.uu \ libarchive/test/test_read_format_rar_multivolume.part0001.rar.uu \ libarchive/test/test_read_format_rar_multivolume.part0002.rar.uu \ libarchive/test/test_read_format_rar_multivolume.part0003.rar.uu \ libarchive/test/test_read_format_rar_multivolume.part0004.rar.uu \ libarchive/test/test_read_format_rar_noeof.rar.uu \ libarchive/test/test_read_format_rar_ppmd_lzss_conversion.rar.uu \ libarchive/test/test_read_format_rar_sfx.exe.uu \ libarchive/test/test_read_format_rar_subblock.rar.uu \ libarchive/test/test_read_format_rar_unicode.rar.uu \ libarchive/test/test_read_format_rar_windows.rar.uu \ libarchive/test/test_read_format_raw.data.Z.uu \ libarchive/test/test_read_format_raw.data.uu \ libarchive/test/test_read_format_tar_concatenated.tar.uu \ libarchive/test/test_read_format_tar_empty_filename.tar.uu \ libarchive/test/test_read_format_tar_empty_pax.tar.Z.uu \ libarchive/test/test_read_format_tar_filename_koi8r.tar.Z.uu \ libarchive/test/test_read_format_ustar_filename_cp866.tar.Z.uu \ libarchive/test/test_read_format_ustar_filename_eucjp.tar.Z.uu \ libarchive/test/test_read_format_ustar_filename_koi8r.tar.Z.uu \ libarchive/test/test_read_format_warc.warc.uu \ libarchive/test/test_read_format_zip.zip.uu \ libarchive/test/test_read_format_zip_comment_stored_1.zip.uu \ libarchive/test/test_read_format_zip_comment_stored_2.zip.uu \ libarchive/test/test_read_format_zip_encryption_data.zip.uu \ libarchive/test/test_read_format_zip_encryption_header.zip.uu \ libarchive/test/test_read_format_zip_encryption_partially.zip.uu \ libarchive/test/test_read_format_zip_filename_cp866.zip.uu \ libarchive/test/test_read_format_zip_filename_cp932.zip.uu \ libarchive/test/test_read_format_zip_filename_koi8r.zip.uu \ libarchive/test/test_read_format_zip_filename_utf8_jp.zip.uu \ libarchive/test/test_read_format_zip_filename_utf8_ru.zip.uu \ libarchive/test/test_read_format_zip_filename_utf8_ru2.zip.uu \ libarchive/test/test_read_format_zip_length_at_end.zip.uu \ libarchive/test/test_read_format_zip_mac_metadata.zip.uu \ libarchive/test/test_read_format_zip_malformed1.zip.uu \ libarchive/test/test_read_format_zip_msdos.zip.uu \ libarchive/test/test_read_format_zip_nested.zip.uu \ libarchive/test/test_read_format_zip_nofiletype.zip.uu \ libarchive/test/test_read_format_zip_padded1.zip.uu \ libarchive/test/test_read_format_zip_padded2.zip.uu \ libarchive/test/test_read_format_zip_padded3.zip.uu \ libarchive/test/test_read_format_zip_sfx.uu \ libarchive/test/test_read_format_zip_symlink.zip.uu \ libarchive/test/test_read_format_zip_traditional_encryption_data.zip.uu \ libarchive/test/test_read_format_zip_ux.zip.uu \ libarchive/test/test_read_format_zip_winzip_aes128.zip.uu \ libarchive/test/test_read_format_zip_winzip_aes256.zip.uu \ libarchive/test/test_read_format_zip_winzip_aes256_large.zip.uu \ libarchive/test/test_read_format_zip_winzip_aes256_stored.zip.uu \ libarchive/test/test_read_format_zip_zip64a.zip.uu \ libarchive/test/test_read_format_zip_zip64b.zip.uu \ libarchive/test/test_read_large_splitted_rar_aa.uu \ libarchive/test/test_read_large_splitted_rar_ab.uu \ libarchive/test/test_read_large_splitted_rar_ac.uu \ libarchive/test/test_read_large_splitted_rar_ad.uu \ libarchive/test/test_read_large_splitted_rar_ae.uu \ libarchive/test/test_read_splitted_rar_aa.uu \ libarchive/test/test_read_splitted_rar_ab.uu \ libarchive/test/test_read_splitted_rar_ac.uu \ libarchive/test/test_read_splitted_rar_ad.uu \ libarchive/test/test_read_too_many_filters.gz.uu \ libarchive/test/test_splitted_rar_seek_support_aa.uu \ libarchive/test/test_splitted_rar_seek_support_ab.uu \ libarchive/test/test_splitted_rar_seek_support_ac.uu \ libarchive/test/test_write_disk_appledouble.cpio.gz.uu \ libarchive/test/test_write_disk_hfs_compression.tgz.uu \ libarchive/test/test_write_disk_mac_metadata.tar.gz.uu \ libarchive/test/test_write_disk_no_hfs_compression.tgz.uu \ libarchive/test/CMakeLists.txt \ libarchive/test/README # # Common code for libarchive frontends (cpio, tar) # libarchive_fe_la_SOURCES= \ libarchive_fe/err.c \ libarchive_fe/err.h \ libarchive_fe/lafe_platform.h \ libarchive_fe/line_reader.c \ libarchive_fe/line_reader.h \ libarchive_fe/passphrase.c \ libarchive_fe/passphrase.h libarchive_fe_la_CPPFLAGS= -I$(top_srcdir)/libarchive # # # bsdtar source, docs, etc. # # bsdtar_SOURCES= \ tar/bsdtar.c \ tar/bsdtar.h \ tar/bsdtar_platform.h \ tar/cmdline.c \ tar/creation_set.c \ tar/read.c \ tar/subst.c \ tar/util.c \ tar/write.c if INC_WINDOWS_FILES bsdtar_SOURCES+= \ tar/bsdtar_windows.h \ tar/bsdtar_windows.c endif bsdtar_DEPENDENCIES= libarchive.la libarchive_fe.la if STATIC_BSDTAR bsdtar_ldstatic= -static bsdtar_ccstatic= -DLIBARCHIVE_STATIC else bsdtar_ldstatic= bsdtar_ccstatic= endif bsdtar_LDADD= libarchive.la libarchive_fe.la $(LTLIBICONV) bsdtar_CPPFLAGS= -I$(top_srcdir)/libarchive -I$(top_srcdir)/libarchive_fe $(bsdtar_ccstatic) $(PLATFORMCPPFLAGS) bsdtar_LDFLAGS= $(bsdtar_ldstatic) bsdtar_EXTRA_DIST= \ tar/bsdtar.1 \ tar/bsdtar_windows.h \ tar/bsdtar_windows.c \ tar/CMakeLists.txt \ tar/config_freebsd.h if BUILD_BSDTAR bsdtar_man_MANS= tar/bsdtar.1 bsdtar_programs= bsdtar else bsdtar_man_MANS= bsdtar_programs= endif # # bsdtar_test # bsdtar_test_SOURCES= \ $(test_utils_SOURCES) \ tar/test/main.c \ tar/test/test.h \ tar/test/test_0.c \ tar/test/test_basic.c \ tar/test/test_copy.c \ tar/test/test_empty_mtree.c \ tar/test/test_extract_tar_Z.c \ tar/test/test_extract_tar_bz2.c \ tar/test/test_extract_tar_grz.c \ tar/test/test_extract_tar_gz.c \ tar/test/test_extract_tar_lrz.c \ tar/test/test_extract_tar_lz.c \ tar/test/test_extract_tar_lz4.c \ tar/test/test_extract_tar_lzma.c \ tar/test/test_extract_tar_lzo.c \ tar/test/test_extract_tar_xz.c \ tar/test/test_format_newc.c \ tar/test/test_help.c \ tar/test/test_leading_slash.c \ tar/test/test_missing_file.c \ tar/test/test_option_C_upper.c \ tar/test/test_option_H_upper.c \ tar/test/test_option_L_upper.c \ tar/test/test_option_O_upper.c \ tar/test/test_option_T_upper.c \ tar/test/test_option_U_upper.c \ tar/test/test_option_X_upper.c \ tar/test/test_option_a.c \ tar/test/test_option_b.c \ tar/test/test_option_b64encode.c \ tar/test/test_option_exclude.c \ tar/test/test_option_gid_gname.c \ tar/test/test_option_grzip.c \ tar/test/test_option_j.c \ tar/test/test_option_k.c \ tar/test/test_option_keep_newer_files.c \ tar/test/test_option_lrzip.c \ tar/test/test_option_lz4.c \ tar/test/test_option_lzma.c \ tar/test/test_option_lzop.c \ tar/test/test_option_n.c \ tar/test/test_option_newer_than.c \ tar/test/test_option_nodump.c \ tar/test/test_option_older_than.c \ tar/test/test_option_passphrase.c \ tar/test/test_option_q.c \ tar/test/test_option_r.c \ tar/test/test_option_s.c \ tar/test/test_option_uid_uname.c \ tar/test/test_option_uuencode.c \ tar/test/test_option_xz.c \ tar/test/test_option_z.c \ tar/test/test_patterns.c \ tar/test/test_print_longpath.c \ tar/test/test_stdio.c \ tar/test/test_strip_components.c \ tar/test/test_symlink_dir.c \ tar/test/test_version.c \ tar/test/test_windows.c bsdtar_test_CPPFLAGS=\ -I$(top_srcdir)/libarchive -I$(top_srcdir)/libarchive_fe \ -I$(top_srcdir)/test_utils \ -I$(top_srcdir)/tar -I$(top_builddir)/tar/test \ $(PLATFORMCPPFLAGS) tar/test/list.h: Makefile $(MKDIR_P) tar/test cat $(top_srcdir)/tar/test/test_*.c | grep '^DEFINE_TEST' > tar/test/list.h if BUILD_BSDTAR bsdtar_test_programs= bsdtar_test bsdtar_TESTS_ENVIRONMENT= BSDTAR=`cd $(top_builddir);/bin/pwd`/bsdtar$(EXEEXT) BSDTAR_TEST_FILES=`cd $(top_srcdir);/bin/pwd`/tar/test else bsdtar_test_programs= bsdtar_TESTS_ENVIRONMENT= endif bsdtar_test_EXTRA_DIST= \ tar/test/list.h \ tar/test/test_extract.tar.Z.uu \ tar/test/test_extract.tar.bz2.uu \ tar/test/test_extract.tar.grz.uu \ tar/test/test_extract.tar.gz.uu \ tar/test/test_extract.tar.lrz.uu \ tar/test/test_extract.tar.lz.uu \ tar/test/test_extract.tar.lz4.uu \ tar/test/test_extract.tar.lzma.uu \ tar/test/test_extract.tar.lzo.uu \ tar/test/test_extract.tar.xz.uu \ tar/test/test_leading_slash.tar.uu \ tar/test/test_option_keep_newer_files.tar.Z.uu \ tar/test/test_option_passphrase.zip.uu \ tar/test/test_option_s.tar.Z.uu \ tar/test/test_patterns_2.tar.uu \ tar/test/test_patterns_3.tar.uu \ tar/test/test_patterns_4.tar.uu \ tar/test/test_print_longpath.tar.Z.uu \ tar/test/CMakeLists.txt # # # bsdcpio source, docs, etc. # # bsdcpio_SOURCES= \ cpio/cmdline.c \ cpio/cpio.c \ cpio/cpio.h \ cpio/cpio_platform.h if INC_WINDOWS_FILES bsdcpio_SOURCES+= \ cpio/cpio_windows.h \ cpio/cpio_windows.c endif bsdcpio_DEPENDENCIES = libarchive.la libarchive_fe.la if STATIC_BSDCPIO bsdcpio_ldstatic= -static bsdcpio_ccstatic= -DLIBARCHIVE_STATIC else bsdcpio_ldstatic= bsdcpio_ccstatic= endif bsdcpio_LDADD= libarchive_fe.la libarchive.la $(LTLIBICONV) bsdcpio_CPPFLAGS= -I$(top_srcdir)/libarchive -I$(top_srcdir)/libarchive_fe $(bsdcpio_ccstatic) $(PLATFORMCPPFLAGS) bsdcpio_LDFLAGS= $(bsdcpio_ldstatic) bsdcpio_EXTRA_DIST= \ cpio/bsdcpio.1 \ cpio/cpio_windows.h \ cpio/cpio_windows.c \ cpio/CMakeLists.txt \ cpio/config_freebsd.h if BUILD_BSDCPIO # Manpages to install bsdcpio_man_MANS= cpio/bsdcpio.1 bsdcpio_programs= bsdcpio else bsdcpio_man_MANS= bsdcpio_programs= endif # # bsdcpio_test # bsdcpio_test_SOURCES= \ $(test_utils_SOURCES) \ cpio/cmdline.c \ cpio/test/main.c \ cpio/test/test.h \ cpio/test/test_0.c \ cpio/test/test_basic.c \ cpio/test/test_cmdline.c \ cpio/test/test_extract_cpio_Z.c \ cpio/test/test_extract_cpio_bz2.c \ cpio/test/test_extract_cpio_grz.c \ cpio/test/test_extract_cpio_gz.c \ cpio/test/test_extract_cpio_lrz.c \ cpio/test/test_extract_cpio_lz.c \ cpio/test/test_extract_cpio_lz4.c \ cpio/test/test_extract_cpio_lzma.c \ cpio/test/test_extract_cpio_lzo.c \ cpio/test/test_extract_cpio_xz.c \ cpio/test/test_format_newc.c \ cpio/test/test_gcpio_compat.c \ cpio/test/test_missing_file.c \ cpio/test/test_option_0.c \ cpio/test/test_option_B_upper.c \ cpio/test/test_option_C_upper.c \ cpio/test/test_option_J_upper.c \ cpio/test/test_option_L_upper.c \ cpio/test/test_option_Z_upper.c \ cpio/test/test_option_a.c \ cpio/test/test_option_b64encode.c \ cpio/test/test_option_c.c \ cpio/test/test_option_d.c \ cpio/test/test_option_f.c \ cpio/test/test_option_grzip.c \ cpio/test/test_option_help.c \ cpio/test/test_option_l.c \ cpio/test/test_option_lrzip.c \ cpio/test/test_option_lz4.c \ cpio/test/test_option_lzma.c \ cpio/test/test_option_lzop.c \ cpio/test/test_option_m.c \ cpio/test/test_option_passphrase.c \ cpio/test/test_option_t.c \ cpio/test/test_option_u.c \ cpio/test/test_option_uuencode.c \ cpio/test/test_option_version.c \ cpio/test/test_option_xz.c \ cpio/test/test_option_y.c \ cpio/test/test_option_z.c \ cpio/test/test_owner_parse.c \ cpio/test/test_passthrough_dotdot.c \ cpio/test/test_passthrough_reverse.c bsdcpio_test_CPPFLAGS= \ -I$(top_srcdir)/libarchive -I$(top_srcdir)/libarchive_fe \ -I$(top_srcdir)/test_utils \ -I$(top_srcdir)/cpio -I$(top_builddir)/cpio/test \ $(PLATFORMCPPFLAGS) bsdcpio_test_LDADD=libarchive_fe.la cpio/test/list.h: Makefile $(MKDIR_P) cpio/test cat $(top_srcdir)/cpio/test/test_*.c | grep '^DEFINE_TEST' > cpio/test/list.h if BUILD_BSDCPIO bsdcpio_test_programs= bsdcpio_test bsdcpio_TESTS_ENVIRONMENT= BSDCPIO=`cd $(top_builddir);/bin/pwd`/bsdcpio$(EXEEXT) BSDCPIO_TEST_FILES=`cd $(top_srcdir);/bin/pwd`/cpio/test else bsdcpio_test_programs= bsdcpio_TESTS_ENVIRONMENT= endif bsdcpio_test_EXTRA_DIST= \ cpio/test/list.h \ cpio/test/test_extract.cpio.Z.uu \ cpio/test/test_extract.cpio.bz2.uu \ cpio/test/test_extract.cpio.grz.uu \ cpio/test/test_extract.cpio.gz.uu \ cpio/test/test_extract.cpio.lrz.uu \ cpio/test/test_extract.cpio.lz.uu \ cpio/test/test_extract.cpio.lz4.uu \ cpio/test/test_extract.cpio.lzma.uu \ cpio/test/test_extract.cpio.lzo.uu \ cpio/test/test_extract.cpio.xz.uu \ cpio/test/test_gcpio_compat_ref.bin.uu \ cpio/test/test_gcpio_compat_ref.crc.uu \ cpio/test/test_gcpio_compat_ref.newc.uu \ cpio/test/test_gcpio_compat_ref.ustar.uu \ cpio/test/test_gcpio_compat_ref_nosym.bin.uu \ cpio/test/test_gcpio_compat_ref_nosym.crc.uu \ cpio/test/test_gcpio_compat_ref_nosym.newc.uu \ cpio/test/test_gcpio_compat_ref_nosym.ustar.uu \ cpio/test/test_option_f.cpio.uu \ cpio/test/test_option_m.cpio.uu \ cpio/test/test_option_passphrase.zip.uu \ cpio/test/test_option_t.cpio.uu \ cpio/test/test_option_t.stdout.uu \ cpio/test/test_option_tv.stdout.uu \ cpio/test/CMakeLists.txt # # # bsdcat source, docs, etc. # # bsdcat_SOURCES= \ cat/bsdcat.c \ cat/bsdcat.h \ cat/bsdcat_platform.h \ cat/cmdline.c if INC_WINDOWS_FILES bsdcat_SOURCES+= endif bsdcat_DEPENDENCIES = libarchive.la libarchive_fe.la if STATIC_BSDCAT bsdcat_ldstatic= -static bsdcat_ccstatic= -DLIBARCHIVE_STATIC else bsdcat_ldstatic= bsdcat_ccstatic= endif bsdcat_LDADD= libarchive_fe.la libarchive.la $(LTLIBICONV) bsdcat_CPPFLAGS= -I$(top_srcdir)/libarchive -I$(top_srcdir)/libarchive_fe $(bsdcat_ccstatic) $(PLATFORMCPPFLAGS) bsdcat_LDFLAGS= $(bsdcat_ldstatic) bsdcat_EXTRA_DIST= \ cat/bsdcat.1 \ cat/CMakeLists.txt if BUILD_BSDCAT # Manpages to install bsdcat_man_MANS= cat/bsdcat.1 bsdcat_programs= bsdcat else bsdcat_man_MANS= bsdcat_programs= endif # # bsdcat_test # bsdcat_test_SOURCES= \ $(test_utils_SOURCES) \ cat/test/main.c \ cat/test/test.h \ cat/test/test_0.c \ cat/test/test_empty_gz.c \ cat/test/test_empty_lz4.c \ cat/test/test_empty_xz.c \ cat/test/test_error.c \ cat/test/test_error_mixed.c \ cat/test/test_expand_Z.c \ cat/test/test_expand_bz2.c \ cat/test/test_expand_gz.c \ cat/test/test_expand_lz4.c \ cat/test/test_expand_mixed.c \ cat/test/test_expand_plain.c \ cat/test/test_expand_xz.c \ cat/test/test_help.c \ cat/test/test_version.c bsdcat_test_CPPFLAGS= \ -I$(top_srcdir)/libarchive -I$(top_srcdir)/libarchive_fe \ -I$(top_srcdir)/test_utils \ -I$(top_srcdir)/cat -I$(top_builddir)/cat/test \ $(PLATFORMCPPFLAGS) bsdcat_test_LDADD=libarchive_fe.la cat/test/list.h: Makefile cat $(top_srcdir)/cat/test/test_*.c | grep '^DEFINE_TEST' > cat/test/list.h if BUILD_BSDCAT bsdcat_test_programs= bsdcat_test bsdcat_TESTS_ENVIRONMENT= BSDCAT=`cd $(top_builddir);/bin/pwd`/bsdcat$(EXEEXT) BSDCAT_TEST_FILES=`cd $(top_srcdir);/bin/pwd`/cat/test else bsdcat_test_programs= bsdcat_TESTS_ENVIRONMENT= endif bsdcat_test_EXTRA_DIST= \ cat/test/list.h \ cat/test/test_empty.gz.uu \ cat/test/test_empty.lz4.uu \ cat/test/test_empty.xz.uu \ cat/test/test_expand.Z.uu \ cat/test/test_expand.bz2.uu \ cat/test/test_expand.gz.uu \ cat/test/test_expand.lz4.uu \ cat/test/test_expand.plain.uu \ cat/test/test_expand.xz.uu \ cat/test/CMakeLists.txt Index: vendor/libarchive/dist/NEWS =================================================================== --- vendor/libarchive/dist/NEWS (revision 302036) +++ vendor/libarchive/dist/NEWS (revision 302037) @@ -1,658 +1,663 @@ +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. Jan 13, 2013: libarchive 3.1.1 released Jan 13, 2013: libarchive 3.1.0 released Dec 07, 2012: Implement functions to manually set the format and filters used. Nov 11, 2012: Add support for __MACOSX directory in Zip archives, which resource forks are stored in. Oct 20, 2012: Add support for writing v7 tar format. Oct 09, 2012: Add support for grzip compression. Oct 07, 2012: Introduce b64encode filter. Oct 07, 2012: Introduce uuencode filter. Oct 06, 2012: Add support for lzop. Sep 27, 2012: Implement function used to seek within data blocks. (Currently only supported for uncompressed RAR archives). Apr 22, 2012: Add basic archive read and write filter support for lrzip. Mar 27, 2012: libarchive 3.0.4 released Feb 05, 2012: libarchive development now hosted at GitHub. http://libarchive.github.com/ Feb 05, 2012: libarchive's issue tracker remains at Google Code. http://code.google.com/p/libarchive/issues/list Feb 05, 2012: libarchive's mailing lists remain at Google Groups. Dec 24, 2011: libarchive 3.0.2 released Dec 23, 2011: Various fixes merged from FreeBSD Dec 23, 2011: Symlink support in Zip reader and writer Dec 23, 2011: Robustness fixes to 7Zip reader Nov 27, 2011: libarchive 3.0.1b released Nov 26, 2011: 7Zip reader Nov 26, 2011: Small fixes to ISO and Zip to improve robustness with corrupted input Nov 24, 2011: Improve streaming Zip reader's support for uncompressed entries Nov 20, 2011: New seeking Zip reader supports SFX Zip archives Nov 20, 2011: Build fixes on Windows Nov 13, 2011: libarchive 3.0.0a released Nov 06, 2011: Update shared-library version calculations for libarchive 3.x Sep 04, 2011: Fix tar -s; follow GNU tar for controlling hardlink/symlink substitutions Aug 18, 2011: Fix reading ISO images built by NetBSD's mkisofs Aug 15, 2011: Old archive_read_support_compression_XXX functions are deprecated and will disappear in libarchive 4.0. Jun 26, 2011: RAR reader Jun 16, 2011: Add tar:compat-2x option to emulate broken libarchive 2.x handling of pax UTF-8 headers Apr 25, 2011: Refactor read_open() into a collection of single-item setters; support the old interfaces as wrappers Apr 12, 2011: Split disk writer into separate POSIX and Windows implementations Apr 10, 2011: Improvements to character translations on Windows. Mar 30, 2011: More work to return errors instead of calling abort() Mar 23, 2011: Add charset option to many writers to control MBCS filenames Mar 17, 2011: Overhauled support for per-format extension options Mar 17, 2011: Track character set used for mbcs strings, support translating to/from user-specified locale Mar 09, 2011: Recognize mtree files without requiring a signature Mar 06, 2011: Use iconv to convert to/from Unicode instead of making bad assumptions about the C90 character set translation functions Feb 17, 2011: Fixes for AIX, TRU64, and other platforms Dec 22, 2010: CAB reader Dec 20, 2010: LHA/LZH reader Jul 03, 2010: minitar example demonstrates archive_read_disk directory traversal Jun 29, 2010: Many improvements to ISO reader compatibility Jun 26, 2010: Use larger buffers when copy files into an archive Jun 18, 2010: Reimplement Mac OS extensions in libarchive Jun 09, 2010: archive_read_disk now supports traversals May 28, 2010: XAR writer May 16, 2010: Fix ^T handling; don't exit on interrupted reads and writes May 09, 2010: Improved detection of platform-specific crypto support May 04, 2010: lzip read and write filters May 01, 2010: New options: tar --gid --gname --uid --uname Apr 28, 2010: Use Red-black tree for ISO reader/writer to improve performance Apr 17, 2010: Minimal writer for legacy GNU tar format Mar 12, 2010: Don't dereference symlinks on Linux when reading ACLs. Mar 06, 2010: Fix build when an older libarchive is already installed Feb 28, 2010: Relax handling of state failures; misuse by clients now generally results in a sticky ARCHIVE_FATAL rather than a visit to abort() Feb 25, 2010: ISO writer Feb 21, 2010: Split many man pages into smaller chunks. Feb 21, 2010: Performance: Cheat on block sizes when reading archives from disk. Feb 21, 2010: Use int64_t instead of off_t, dev_t, ino_t, uid_t, and gid_t Feb 20, 2010: Document new ACL functions. Feb 19, 2010: Support multiple write filters Feb 07, 2010: Remove some legacy libarchive 1.x APIs Feb 04, 2010: Read afio headers Feb 02, 2010: Archive sparse files compatibly with GNU tar Feb 01, 2010: Integrate Apple extensions for Mac OS extended attributes into bsdtar Jan 31, 2010: Support cpio -V Feb 04, 2010: libarchive 2.8.0 released Jan 17, 2010: Fix error handling for 'echo nonexistent | cpio -o' Jan 17, 2010: Don't use futimes() on Cygwin Jan 02, 2010: libarchive 2.7.902a released (test release for 2.8) Jan 02, 2010: Fix tar/test/test_windows on MinGW Jan 02, 2010: Fix memory leaks in libarchive tests Jan 01, 2010: Fix memory leak when filter startup fails Dec 27, 2009: libarchive 2.7.901a released (test release for 2.8) Aug 04, 2009: libarchive 2.7.1 released Jul 20, 2009: Suppress bogus warning about unxz Jul 19, 2009: Support Cygwin 1.7 Jun 11, 2009: Support lzma/xz files compressed with larger buffer sizes. May 24, 2009: Handle gzip files signed with OpenBSD "gzsig" program. May 07, 2009: Avoid false failures when reading from pipe. Apr 16, 2009: libarchive 2.7.0 released Apr 10, 2009: libarchive 2.6.992a released Apr 09, 2009: Fix SIGPIPE issue building with MSVC. Apr 09, 2009: Fix several minor memory leaks in libarchive and libarchive_test Apr 08, 2009: libarchive 2.6.991a released Apr 07, 2009: Additional tests added to bsdcpio_test Apr 01, 2009: libarchive 2.6.990a released Apr 01, 2009: Use command-line gunzip, bunzip2, unxz, unlzma for decompression if the library is built without suitable libraries. The setup functions return ARCHIVE_WARN in this case so clients can adapt if necessary. Apr 01, 2009: Use getpw*_r and getgr*_r functions for thread-safety. Mar 24, 2009: Add archive_read_next_header2(), which is up to 25% more efficient for some clients; from Brian Harring. Mar 22, 2009: PDF versions of manpages are now included in the distribution. Mar, 2009: Major work to improve Cygwin build by Charles Wilson. Feb/Mar, 2009: Major work on cmake build support, mostly by Michihiro NAKAJIMA. Feb/Mar, 2009: Major work on Visual Studio support by Michihiro NAKAJIMA. All tests now pass. Feb 25, 2009: Fix Debian Bug #516577 Feb 21, 2009: Yacc is no longer needed to build; date parser rewritten in C. Jan/Feb, 2009: Mtree work by Michihiro. Feb, 2009: Joliet support by Andreas Henriksson. Jan/Feb, 2009: New options framework by Michihiro. Feb, 2009: High-res timestamps on Tru64, AIX, and GNU Hurd, by Björn Jacke. Jan 18, 2009: Extended attributes work on FreeBSD and Linux now with pax format. Jan 07, 2009: New archive_read_disk_entry_from_file() knows about ACLs, extended attributes, etc so that bsdtar and bsdcpio don't require such system-specific knowledge. Jan 03, 2009: Read filter system extensively refactored. In particular, read filter pipelines are now built out automatically and individual filters should be much easier to implement. Documentation on the Googlecode Wiki explains how to implement new filters. Dec 28, 2008: Many Windows/Visual Studio fixes from Michihiro NAKAJIMA. Dec 28, 2008: Main libarchive development moved from FreeBSD Perforce server to Google Code. This should make it easier for more people to participate in libarchive development. Dec 28, 2008: libarchive 2.6.0 released Dec 25, 2008: libarchive 2.5.905a released Dec 10, 2008: libarchive 2.5.904a released Dec 04, 2008: libarchive 2.5.903a released Nov 09, 2008: libarchive 2.5.902a released Nov 08, 2008: libarchive 2.5.901a released Nov 08, 2008: Start of pre-release testing for libarchive 2.6 Nov 07, 2008: Read filter refactor: The decompression routines just consume and produce arbitrarily-sized blocks. The reblocking from read_support_compression_none() has been pulled into the read core. Also, the decompression bid now makes multiple passes and stacks read filters. Oct 21, 2008: bsdcpio: New command-line parser. Oct 19, 2008: Internal read_ahead change: short reads are now an error Oct 06, 2008: bsdtar: option parser no longer uses getopt_long(), gives consistent option parsing on all platforms. Sep 19, 2008: Jaakko Heinonen: shar utility built on libarchive Sep 17, 2008: Pedro Giffuni: birthtime support Sep 17, 2008: Miklos Vajna: lzma reader and test. Note: I still have some concerns about the auto-detection (LZMA file format doesn't support auto-detection well), so this is not yet enabled under archive_read_support_compression_all(). For now, you must call archive_read_support_compression_lzma() if you want LZMA read support. Sep 11, 2008: Ivailo Petrov: Many fixes to Windows build, new solution files Jul 26, 2008: archive_entry now tracks which values have not been set. This helps zip extraction (file size is often "unknown") and time restores (tar usually doesn't know atime). Jul 26, 2008: Joerg Sonnenberger: Performance improvements to shar writer Jul 25, 2008: Joerg Sonnenberger: mtree write support Jul 02, 2008: libarchive 2.5.5 released Jul 02, 2008: libarchive 2.5.5b released Jul 01, 2008: bsdcpio is being used by enough people, we can call it 1.0.0 now Jun 20, 2008: bsdcpio: If a -l link fails with EXDEV, copy the file instead Jun 19, 2008: bsdcpio: additional long options for better GNU cpio compat Jun 15, 2008: Many small portability and bugfixes since 2.5.4b. May 25, 2008: libarchive 2.5.4b released May 21, 2008: Joerg Sonnenberger: fix bsdtar hardlink handling for newc format May 21, 2008: More progress on Windows building. Thanks to "Scott" for the Windows makefiles, thanks to Kees Zeelenberg for code contributions. May 21, 2008: Fix a number of non-exploitable integer and buffer overflows, thanks to David Remahl at Apple for pointing these out. May 21, 2008: Colin Percival: SIGINFO or SIGUSR1 to bsdtar prints progress info May 16, 2008: bsdtar's test harness no longer depends on file ordering. This was causing spurious test failures on a lot of systems. Thanks to Bernhard R. Link for the diagnosis. May 14, 2008: Joerg Sonnenberger: -s substitution support for bsdtar May 13, 2008: Joerg Sonnenberger: Many mtree improvements May 11, 2008: Joerg Sonnenberger: fix hardlink extraction when hardlinks have different permissions from original file April 30, 2008: Primary libarchive work has been moved into the FreeBSD project's Perforce repository: http://perforce.freebsd.org/ The libarchive project can be browsed at //depot/user/kientzle/libarchive-portable Direct link: http://preview.tinyurl.com/46mdgr May 04, 2008: libarchive 2.5.3b released * libarchive: Several fixes to link resolver to address bsdcpio crashes * bsdcpio: -p hardlink handling fixes * tar/pax: Ensure ustar dirnames end in '/'; be more careful about measuring filenames when deciding what pathname fields to use * 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: 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 * iso9660: Don't bother trying to find the body of an empty file; this works around strange behavior from some ISO9660 writers * tar: allow -r -T to be used together * tar: allow --format with -r or -u * libarchive: Don't build archive.h May 04, 2008: Simplified building: archive.h is no longer constructed This may require additional #if conditionals on some platforms. Mar 30, 2008: libarchive 2.5.1b released Mar 15, 2008: libarchive 2.5.0b released Mar 15, 2008: bsdcpio now seems to correctly write hardlinks into newc, ustar, and old cpio archives. Just a little more testing before bsdcpio 1.0 becomes a reality. Mar 15, 2008: I think the new linkify() interface is finally handling all known hardlink strategies. Mar 15, 2008: Mtree read fixes from Joerg Sonnenberger. Mar 15, 2008: Many new bsdtar and bsdcpio options from Joerg Sonnenberger. Mar 15, 2008: test harnesses no longer require uudecode; they now have built-in decoding logic that decodes the reference files as they are needed. Mar 14, 2008: libarchive 2.4.14 released; identical to 2.4.13 except for a point fix for gname/uname mixup in pax format that was introduced with the UTF-8 fixes. Feb 26, 2008: libarchive 2.4.13 released Feb 25, 2008: Handle path, linkname, gname, or uname that can't be converted to/from UTF-8. Implement "hdrcharset" attribute from SUS-2008. Feb 25, 2008: Fix name clash on NetBSD. Feb 18, 2008: Fix writing empty 'ar' archives, per Kai Wang Feb 18, 2008: [bsdtar] Permit appending on block devices. Feb 09, 2008: New "linkify" resolver to help with newc hardlink writing; bsdcpio still needs to be converted to use this. Feb 02, 2008: Windows compatibility fixes from Ivailo Petrov, Kees Zeelenberg Jan 30, 2008: Ignore hardlink size for non-POSIX tar archives. Jan 22, 2008: libarchive 2.4.12 released Jan 22, 2008: Fix bad padding when writing symlinks to newc cpio archives. Jan 22, 2008: Verify bsdcpio_test by getting it to work against GNU cpio 2.9. bsdcpio_test complains about missing options (-y and -z), format of informational messages (--version, --help), and a minor formatting issue in odc format output. After this update, bsdcpio_test uncovered several more cosmetic issues in bsdcpio, all now fixed. Jan 22, 2008: Experimental support for self-extracting Zip archives. Jan 22, 2008: Extend hardlink restore strategy to work correctly with hardlinks extracted from newc cpio files. (Which store the body only with the last occurrence of a link.) Dec 30, 2007: libarchive 2.4.11 released Dec 30, 2007: Fixed a compile error in bsdcpio on some systems. Dec 29, 2007: libarchive 2.4.10 released Dec 29, 2007: bsdcpio 0.9.0 is ready for wider use. Dec 29, 2007: Completed initial test harness for bsdcpio. Dec 22, 2007: libarchive 2.4.9 released Dec 22, 2007: Implement the remaining options for bsdcpio: -a, -q, -L, -f, pattern selection for -i and -it. Dec 13, 2007: libarchive 2.4.8 released Dec 13, 2007: gzip and bzip2 compression now handle zero-byte writes correctly, Thanks to Damien Golding for bringing this to my attention. Dec 12, 2007: libarchive 2.4.7 released Dec 10, 2007: libarchive 2.4.6 released Dec 09, 2007: tar/test/test_copy.c verifies "tar -c | tar -x" copy pipeline Dec 07, 2007: Fix a couple of minor memory leaks. Dec 04, 2007: libarchive 2.4.5 released Dec 04, 2007: Fix cpio/test/test_write_odc by setting the umask first. Dec 03, 2007: libarchive 2.4.4 released Dec 03, 2007: New configure options --disable-xattr and --disable-acl, thanks to Samuli Suominen. Dec 03, 2007: libarchive 2.4.3 released Dec 03, 2007: Thanks to Lapo Luchini for sending me a ZIP file that libarchive couldn't handle. Fixed a bug in handling of "length at end" flags in ZIP files. Dec 03, 2007: Fixed bsdcpio -help, bsdtar -help tests. Dec 02, 2007: First cut at real bsdtar test harness. Dec 02, 2007: libarchive 2.4.2 released Dec 02, 2007: libarchive 2.4.1 released Dec 02, 2007: Minor fixes, rough cut of mdoc-to-man conversion for man pages. Oct 30, 2007: libarchive 2.4.0 released Oct 30, 2007: Minor compile fix thanks to Joerg Schilling. Oct 30, 2007: Only run the format auction once at the beginning of the archive. This is simpler and supports better error recovery. Oct 29, 2007: Test support for very large entries in tar archives: libarchive_test now exercises entries from 2GB up to 1TB. Oct 27, 2007: libarchive 2.3.5 released Oct 27, 2007: Correct some unnecessary internal data copying in the "compression none" reader and writer; this reduces user time by up to 2/3 in some tests. (Thanks to Jan Psota for publishing his performance test results to GNU tar's bug-tar mailing list; those results pointed me towards this problem.) Oct 27, 2007: Fix for skipping archive entries that are exactly a multiple of 4G on 32-bit platforms. Oct 25, 2007: Fix for reading very large (>8G) tar archives; this was broken when I put in support for new GNU tar sparse formats. Oct 20, 2007: Initial work on new pattern-matching code for cpio; I hope this eventually replaces the code currently in bsdtar. Oct 08, 2007: libarchive 2.3.4 released Oct 05, 2007: Continuing work on bsdcpio test suite. Oct 05, 2007: New cpio.5 manpage, updates to "History" of bsdcpio.1 and bsdtar.1 manpages. Oct 05, 2007: Fix zip reader to immediately return EOF if you try to read body of non-regular file. In particular, this fixes bsdtar extraction of zip archives. Sep 30, 2007: libarchive 2.3.3 released Sep 26, 2007: Rework Makefile.am so that the enable/disable options actually do the right things. Sep 26, 2007: cpio-odc and cpio-newc archives no longer write bodies for non-regular files. Sep 26, 2007: Test harness for bsdcpio is in place, needs more tests written. This is much nicer than the ragtag collection of test scripts that bsdtar has. Sep 20, 2007: libarchive 2.3.2 released Sep 20, 2007: libarchive 2.3.1 broke bsdtar because the archive_write_data() fix was implemented incorrectly. Sep 16, 2007: libarchive 2.3.1 released Sep 16, 2007: Many fixes to bsdcpio 0.3: handle hardlinks with -p, recognize block size on writing, fix a couple of segfaults. Sep 16, 2007: Fixed return value from archive_write_data() when used with archive_write_disk() to match the documentation and other instances of this same function. Sep 15, 2007: Add archive_entry_link_resolver, archive_entry_strmode Sep 11, 2007: libarchive 2.2.8 released Sep 09, 2007: bsdcpio 0.2 supports most (not yet all) of the old POSIX spec. Sep 01, 2007: libarchive 2.2.7 released Aug 31, 2007: Support for reading mtree files, including an mtree.5 manpage (A little experimental still.) Aug 18, 2007: Read gtar 1.17 --posix --sparse entries. Aug 13, 2007: Refined suid/sgid restore handling; it is no longer an error if suid/sgid bits are dropped when you request perm restore but don't request owner restore. Aug 06, 2007: Use --enable-bsdcpio if you want to try bsdcpio Aug 05, 2007: libarchive 2.2.6 released Aug 05, 2007: New configure option --disable-bsdtar, thanks to Joerg Sonnenberger. Aug 05, 2007: Several bug fixes from FreeBSD CVS repo. Jul 13, 2007: libarchive 2.2.5 released Jul 12, 2007: libarchive 2.2.4 released Jul 12, 2007: Thanks to Colin Percival's help in diagnosing and fixing several critical security bugs. Details available at http://security.freebsd.org/advisories/FreeBSD-SA-07:05.libarchive.asc May 26, 2007: libarchive 2.2.3 released May 26, 2007: Fix memory leaks in ZIP reader and shar writer, add some missing system headers to archive_entry.h, dead code cleanup from Colin Percival, more tests for gzip/bzip2, fix an EOF anomaly in bzip2 decompression. May 12, 2007: libarchive 2.2.2 released May 12, 2007: Fix archive_write_disk permission restore by cloning entry passed into write_header so that permission info is still available at finish_entry time. (archive_read_extract() worked okay because it held onto the passed-in entry, but direct consumers of archive_write_disk would break). This required fixing archive_entry_clone(), which now works and has a reasonably complete test case. May 10, 2007: Skeletal cpio implementation. May 06, 2007: libarchive 2.2.1 released May 06, 2007: Flesh out a lot more of test_entry.c so as to catch problems such as the device node breakage before releasing . May 05, 2007: Fix a bad bug introduced in 2.1.9 that broke device node entries in tar archives. May 03, 2007: Move 'struct stat' out of archive_entry core as well. This removes some portability headaches and fixes a bunch of corner cases that arise when manipulating archives on dissimilar systems. Apr 30, 2007: libarchive 2.1.10 released Apr 31, 2007: Minor code cleanup. Apr 24, 2007: libarchive 2.1.9 released Apr 24, 2007: Fix some recently-introduced problems with libraries (Just let automake handle it and it all works much better.) Finish isolating major()/minor()/makedev() in archive_entry.c. Apr 23, 2007: libarchive 2.1.8 released Apr 23, 2007: Minor fixes found from building on MacOS X Apr 22, 2007: libarchive 2.1.7 released Apr 22, 2007: Eliminated all uses of 'struct stat' from the format readers/writers. This should improve portability; 'struct stat' is now only used in archive_entry and in code that actually touches the disk. Apr 17, 2007: libarchive 2.1.6 released Libarchive now compiles and passes all tests on Interix. Apr 16, 2007: libarchive 2.1.5 released Apr 15, 2007: libarchive 2.1b2 released Apr 15, 2007: New libarchive_internals.3 documentation of internal APIs. Not complete, but should prove helpful. Apr 15, 2007: Experimental "read_compress_program" and "write_compress_program" for using libarchive with external compression. Not yet well tested, and likely has portability issues. Feedback appreciated. Apr 14, 2007: libarchive 2.0.31 released Apr 14, 2007: More fixes for Interix, more 'ar' work Apr 14, 2007: libarchive 2.0.30 released Apr 13, 2007: libarchive now enforces trailing '/' on dirs written to tar archives Apr 11, 2007: libarchive 2.0.29 released Apr 11, 2007: Make it easier to statically configure for different platforms. Apr 11, 2007: Updated config.guess, config.sub, libtool Apr 06, 2007: libarchive 2.0.28 released Apr 06, 2007: 'ar' format read/write support thanks to Kai Wang. Apr 01, 2007: libarchive 2.0.27 released Mar 31, 2007: Several minor fixes from Colin Percival and Joerg Sonnenberger. Mar 12, 2007: libarchive 2.0.25 released Mar 12, 2007: Fix broken --unlink flag. Mar 11, 2007: libarchive 2.0.24 released Mar 10, 2007: Correct an ACL blunder that causes any ACL with an entry that refers to a non-existent user or group to not be restored correctly. The fix both makes the parser more tolerant (so that archives created with the buggy ACLs can be read now) and corrects the ACL formatter. Mar 10, 2007: More work on test portability to Linux. Mar 10, 2007: libarchive 2.0.22 released Mar 10, 2007: Header cleanups; added linux/fs.h, removed some unnecessary headers, added #include guards in bsdtar. If you see any obvious compile failures from this, let me know. Mar 10, 2007: Work on bsdtar test scripts: not yet robust enough to enable as part of "make check", but getting better. Mar 10, 2007: libarchive now returns ARCHIVE_FAILED when a header write fails in a way that only affects this item. Less bad than ARCHIVE_FATAL, but worse than ARCHIVE_WARN. Mar 07, 2007: libarchive 2.0.21 released Mar 07, 2007: Add some ACL tests (only for the system-independent portion of the ACL support for now). Mar 07, 2007: tar's ability to read ACLs off disk got turned off for FreeBSD; re-enable it. (ACL restores and libarchive support for storing/reading ACLs from pax archives was unaffected.) Mar 02, 2007: libarchive 2.0.20 released Mar 2, 2007: It's not perfect, but it's pretty good. Libarchive 2.0 is officially out of beta. Feb 28, 2007: libarchive 2.0b17 released Feb 27, 2007: Make the GID restore checks more robust by checking whether the current user has too few or too many privileges. Feb 26, 2007: libarchive 2.0b15 released Feb 26, 2007: Don't lose symlinks when extracting from ISOs. Thanks to Diego "Flameeyes" Pettenò for telling me about the broken testcase on Gentoo that (finally!) led me to the cause of this long-standing bug. Feb 26, 2007: libarchive 2.0b14 released Feb 26, 2007: Fix a broken test on platforms that lack lchmod(). Feb 25, 2007: libarchive 2.0b13 released Feb 25, 2007: Empty archives were being written as empty files, without a proper end-of-archive marker. Fixed. Feb 23, 2007: libarchive 2.0b12 released Feb 22, 2007: Basic security checks added: _EXTRACT_SECURE_NODOTDOT and _EXTRACT_SECURE_SYMLINK. These checks used to be in bsdtar, but they belong down in libarchive where they can be used by other tools and where they can be better optimized. Feb 11, 2007: libarchive 2.0b11 released Feb 10, 2007: Fixed a bunch of errors in libarchive's handling of EXTRACT_PERM and EXTRACT_OWNER, especially relating to SUID and SGID bits. Jan 31, 2007: libarchive 2.0b9 released Jan 31, 2007: Added read support for "empty" archives as a distinct archive format. Bsdtar uses this to handle, e.g., "touch foo.tar; tar -rf foo.tar" Jan 22, 2007: libarchive 2.0b6 released Jan 22, 2007: archive_write_disk API is now in place. It provides a finer-grained interface than archive_read_extract. In particular, you can use it to create objects on disk without having an archive around (just feed it archive_entry objects describing what you want to create), you can override the uname/gname-to-uid/gid lookups (minitar uses this to avoid getpwXXX() and getgrXXX() bloat). Jan 09, 2007: libarchive 2.0a3 released Jan 9, 2007: archive_extract is now much better; it handles the most common cases with a minimal number of system calls. Some features still need a lot of testing, especially corner cases involving objects that already exist on disk. I expect the next round of API overhaul will simplify building test cases. Jan 9, 2007: a number of fixes thanks to Colin Percival, especially corrections to the skip() framework and handling of large files. Jan 9, 2007: Fixes for large ISOs. The code should correctly handle very large ISOs with entries up to 4G. Thanks to Robert Sciuk for pointing out these issues. Sep 05, 2006: libarchive 1.3.1 released Sep 5, 2006: Bump version to 1.3 for new I/O wrappers. Sep 4, 2006: New memory and FILE read/write wrappers. Sep 4, 2006: libarchive test harness is now minimally functional; it's located a few minor bugs in error-handling logic Aug 17, 2006: libarchive 1.2.54 released Aug 17, 2006: Outline ABI changes for libarchive 2.0; these are protected behind #ifdef's until I think I've found everything that needs to change. Aug 17, 2006: Fix error-handling in archive_read/write_close() They weren't returning any errors before. Aug 17, 2006: Fix recursive-add logic to not trigger if it's not set Fixes a bug adding files when writing archive to pipe or when using archive_write_open() directly. Jul 2006: New "skip" handling improves performance extracting single files from large uncompressed archives. Mar 21, 2006: 1.2.52 released Mar 21, 2006: Fix -p on platforms that don't have platform-specific extended attribute code. Mar 20, 2006: Add NEWS file; fill in some older history from other files. I'll try to keep this file up-to-date from now on. OLDER NEWS SUMMARIES Mar 19, 2006: libarchive 1.2.51 released Mar 18, 2006: Many fixes to extended attribute support, including a redesign of the storage format to simplify debugging. Mar 12, 2006: Remove 'tp' support; it was a fun idea, but not worth spending much time on. Mar 11, 2006: Incorporated Jaakko Heinonen's still-experimental support for extended attributes (Currently Linux-only.). Mar 11, 2006: Reorganized distribution package: There is now one tar.gz file that builds both libarchive and bsdtar. Feb 13, 2006: Minor bug fixes: correctly read cpio device entries, write Pax attribute entry names. Nov 7, 2005: Experimental 'tp' format support in libarchive. Feedback appreciated; this is not enabled by archive_read_support_format_all() yet as I'm not quite content with the format detection heuristics. Nov 7, 2005: Some more portability improvements thanks to Darin Broady, minor bugfixes. Oct 12, 2005: Use GNU libtool to build shared libraries on many systems. Aug 9, 2005: Correctly detect that MacOS X does not have POSIX ACLs. Apr 17, 2005: Kees Zeelenberg has ported libarchive and bsdtar to Windows: http://gnuwin32.sourceforge.net/ Apr 11, 2005: Extended Zip/Zip64 support thanks to Dan Nelson. -L/-h fix from Jaakko Heinonen. Mar 12, 2005: archive_read_extract can now handle very long pathnames (I've tested with pathnames up to 1MB). Mar 12, 2005: Marcus Geiger has written an article about libarchive http://xsnil.antbear.org/2005/02/05/archive-mit-libarchive-verarbeiten/ including examples of using it from Objective-C. His MoinX http://moinx.antbear.org/ desktop Wiki uses libarchive for archiving and restoring Wiki pages. Jan 22, 2005: Preliminary ZIP extraction support, new directory-walking code for bsdtar. Jan 16, 2005: ISO9660 extraction code added; manpage corrections. May 22, 2004: Many gtar-compatible long options have been added; almost all FreeBSD ports extract correctly with bsdtar. May 18, 2004: bsdtar can read Solaris, HP-UX, Unixware, star, gtar, and pdtar archives. Index: vendor/libarchive/dist/build/version =================================================================== --- vendor/libarchive/dist/build/version (revision 302036) +++ vendor/libarchive/dist/build/version (revision 302037) @@ -1 +1 @@ -3002000 +3002001 Index: vendor/libarchive/dist/configure.ac =================================================================== --- vendor/libarchive/dist/configure.ac (revision 302036) +++ vendor/libarchive/dist/configure.ac (revision 302037) @@ -1,878 +1,878 @@ dnl Process this file with autoconf to produce a configure script. dnl First, define all of the version numbers up front. dnl In particular, this allows the version macro to be used in AC_INIT dnl These first two version numbers are updated automatically on each release. -m4_define([LIBARCHIVE_VERSION_S],[3.2.0]) -m4_define([LIBARCHIVE_VERSION_N],[3002000]) +m4_define([LIBARCHIVE_VERSION_S],[3.2.1]) +m4_define([LIBARCHIVE_VERSION_N],[3002001]) dnl bsdtar and bsdcpio versioning tracks libarchive m4_define([BSDTAR_VERSION_S],LIBARCHIVE_VERSION_S()) m4_define([BSDCPIO_VERSION_S],LIBARCHIVE_VERSION_S()) m4_define([BSDCAT_VERSION_S],LIBARCHIVE_VERSION_S()) AC_PREREQ([2.69]) # # Now starts the "real" configure script. # AC_INIT([libarchive],[LIBARCHIVE_VERSION_S()],[libarchive-discuss@googlegroups.com]) # Make sure the srcdir contains "libarchive" directory AC_CONFIG_SRCDIR([libarchive]) # Use auxiliary subscripts from this subdirectory (cleans up root) AC_CONFIG_AUX_DIR([build/autoconf]) # M4 scripts AC_CONFIG_MACRO_DIR([build/autoconf]) # Must follow AC_CONFIG macros above... AM_INIT_AUTOMAKE() m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) # Libtool's "interface version" can be computed from the libarchive version. # Libtool interface version bumps on any API change, so increments # whenever libarchive minor version does. ARCHIVE_MINOR=$(( (LIBARCHIVE_VERSION_N() / 1000) % 1000 )) # Libarchive 2.7 == libtool interface 9 = 2 + 7 # Libarchive 2.8 == libtool interface 10 = 2 + 8 # Libarchive 2.9 == libtool interface 11 = 2 + 8 # Libarchive 3.0 == libtool interface 12 # Libarchive 3.1 == libtool interface 13 ARCHIVE_INTERFACE=`echo $((13 + ${ARCHIVE_MINOR}))` # Libarchive revision is bumped on any source change === libtool revision ARCHIVE_REVISION=$(( LIBARCHIVE_VERSION_N() % 1000 )) # Libarchive minor is bumped on any interface addition === libtool age ARCHIVE_LIBTOOL_VERSION=$ARCHIVE_INTERFACE:$ARCHIVE_REVISION:$ARCHIVE_MINOR # Stick the version numbers into config.h AC_DEFINE([LIBARCHIVE_VERSION_STRING],"LIBARCHIVE_VERSION_S()", [Version number of libarchive]) AC_DEFINE_UNQUOTED([LIBARCHIVE_VERSION_NUMBER],"LIBARCHIVE_VERSION_N()", [Version number of libarchive as a single integer]) AC_DEFINE([BSDCPIO_VERSION_STRING],"BSDCPIO_VERSION_S()", [Version number of bsdcpio]) AC_DEFINE([BSDTAR_VERSION_STRING],"BSDTAR_VERSION_S()", [Version number of bsdtar]) AC_DEFINE([BSDCAT_VERSION_STRING],"BSDTAR_VERSION_S()", [Version number of bsdcat]) # The shell variables here must be the same as the AC_SUBST() variables # below, but the shell variable names apparently cannot be the same as # the m4 macro names above. Why? Ask autoconf. BSDCPIO_VERSION_STRING=BSDCPIO_VERSION_S() BSDTAR_VERSION_STRING=BSDTAR_VERSION_S() BSDCAT_VERSION_STRING=BSDCAT_VERSION_S() LIBARCHIVE_VERSION_STRING=LIBARCHIVE_VERSION_S() LIBARCHIVE_VERSION_NUMBER=LIBARCHIVE_VERSION_N() # Substitute the above version numbers into the various files below. # Yes, I believe this is the fourth time we define what are essentially # the same symbols. Why? Ask autoconf. AC_SUBST(ARCHIVE_LIBTOOL_VERSION) AC_SUBST(BSDCPIO_VERSION_STRING) AC_SUBST(BSDTAR_VERSION_STRING) AC_SUBST(BSDCAT_VERSION_STRING) AC_SUBST(LIBARCHIVE_VERSION_STRING) AC_SUBST(LIBARCHIVE_VERSION_NUMBER) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([Makefile]) AC_CONFIG_FILES([build/pkgconfig/libarchive.pc]) # Check for host type AC_CANONICAL_HOST dnl Compilation on mingw and Cygwin needs special Makefile rules inc_windows_files=no inc_cygwin_files=no case "$host_os" in *mingw* ) inc_windows_files=yes ;; *cygwin*) inc_cygwin_files=yes ;; esac AM_CONDITIONAL([INC_WINDOWS_FILES], [test $inc_windows_files = yes]) AM_CONDITIONAL([INC_CYGWIN_FILES], [test $inc_cygwin_files = yes]) dnl Defines that are required for specific platforms (e.g. -D_POSIX_SOURCE, etc) PLATFORMCPPFLAGS= case "$host_os" in *mingw* ) PLATFORMCPPFLAGS=-D__USE_MINGW_ANSI_STDIO ;; esac AC_SUBST(PLATFORMCPPFLAGS) # Checks for programs. AC_PROG_CC AM_PROG_CC_C_O AC_USE_SYSTEM_EXTENSIONS AC_LIBTOOL_WIN32_DLL AC_PROG_LIBTOOL AC_CHECK_TOOL([STRIP],[strip]) AC_PROG_MKDIR_P # # Options for building bsdtar. # # Default is to build bsdtar, but allow people to override that. # AC_ARG_ENABLE([bsdtar], [AS_HELP_STRING([--enable-bsdtar], [enable build of bsdtar (default)]) AS_HELP_STRING([--enable-bsdtar=static], [force static build of bsdtar]) AS_HELP_STRING([--enable-bsdtar=shared], [force dynamic build of bsdtar]) AS_HELP_STRING([--disable-bsdtar], [disable build of bsdtar])], [], [enable_bsdtar=yes]) case "$enable_bsdtar" in yes) if test "$enable_static" = "no"; then static_bsdtar=no else static_bsdtar=yes fi build_bsdtar=yes ;; dynamic|shared) if test "$enable_shared" = "no"; then AC_MSG_FAILURE([Shared linking of bsdtar requires shared libarchive]) fi build_bsdtar=yes static_bsdtar=no ;; static) build_bsdtar=yes static_bsdtar=yes ;; no) build_bsdtar=no static_bsdtar=no ;; *) AC_MSG_FAILURE([Unsupported value for --enable-bsdtar]) ;; esac AM_CONDITIONAL([BUILD_BSDTAR], [ test "$build_bsdtar" = yes ]) AM_CONDITIONAL([STATIC_BSDTAR], [ test "$static_bsdtar" = yes ]) # # Options for building bsdcat. # # Default is to build bsdcat, but allow people to override that. # AC_ARG_ENABLE([bsdcat], [AS_HELP_STRING([--enable-bsdcat], [enable build of bsdcat (default)]) AS_HELP_STRING([--enable-bsdcat=static], [force static build of bsdcat]) AS_HELP_STRING([--enable-bsdcat=shared], [force dynamic build of bsdcat]) AS_HELP_STRING([--disable-bsdcat], [disable build of bsdcat])], [], [enable_bsdcat=yes]) case "$enable_bsdcat" in yes) if test "$enable_static" = "no"; then static_bsdcat=no else static_bsdcat=yes fi build_bsdcat=yes ;; dynamic|shared) if test "$enable_shared" = "no"; then AC_MSG_FAILURE([Shared linking of bsdcat requires shared libarchive]) fi build_bsdcat=yes static_bsdcat=no ;; static) build_bsdcat=yes static_bsdcat=yes ;; no) build_bsdcat=no static_bsdcat=no ;; *) AC_MSG_FAILURE([Unsupported value for --enable-bsdcat]) ;; esac AM_CONDITIONAL([BUILD_BSDCAT], [ test "$build_bsdcat" = yes ]) AM_CONDITIONAL([STATIC_BSDCAT], [ test "$static_bsdcat" = yes ]) # # Options for building bsdcpio. # # Default is not to build bsdcpio, but that can be overridden. # AC_ARG_ENABLE([bsdcpio], [AS_HELP_STRING([--enable-bsdcpio], [enable build of bsdcpio (default)]) AS_HELP_STRING([--enable-bsdcpio=static], [static build of bsdcpio]) AS_HELP_STRING([--enable-bsdcpio=shared], [dynamic build of bsdcpio]) AS_HELP_STRING([--disable-bsdcpio], [disable build of bsdcpio])], [], [enable_bsdcpio=yes]) case "$enable_bsdcpio" in yes) if test "$enable_static" = "no"; then static_bsdcpio=no else static_bsdcpio=yes fi build_bsdcpio=yes ;; dynamic|shared) if test "$enabled_shared" = "no"; then AC_MSG_FAILURE([Shared linking of bsdcpio requires shared libarchive]) fi build_bsdcpio=yes ;; static) build_bsdcpio=yes static_bsdcpio=yes ;; no) build_bsdcpio=no static_bsdcpio=no ;; *) AC_MSG_FAILURE([Unsupported value for --enable-bsdcpio]) ;; esac AM_CONDITIONAL([BUILD_BSDCPIO], [ test "$build_bsdcpio" = yes ]) AM_CONDITIONAL([STATIC_BSDCPIO], [ test "$static_bsdcpio" = yes ]) # Set up defines needed before including any headers case $host in *mingw* | *cygwin* ) AC_DEFINE([_WIN32_WINNT], 0x0502, [Define to '0x0502' for Windows Server 2003 APIs.]) AC_DEFINE([WINVER], 0x0502, [Define to '0x0502' for Windows Server 2003 APIs.]) AC_DEFINE([NTDDI_VERSION], 0x05020000, [Define to '0x05020000' for Windows Server 2003 APIs.]) ;; esac # Checks for header files. AC_HEADER_DIRENT AC_HEADER_SYS_WAIT AC_CHECK_HEADERS([copyfile.h ctype.h]) AC_CHECK_HEADERS([errno.h ext2fs/ext2_fs.h fcntl.h grp.h]) AC_CACHE_CHECK([whether EXT2_IOC_GETFLAGS is usable], [ac_cv_have_decl_EXT2_IOC_GETFLAGS], [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([@%:@include @%:@include ], [int x = EXT2_IOC_GETFLAGS])], [AS_VAR_SET([ac_cv_have_decl_EXT2_IOC_GETFLAGS], [yes])], [AS_VAR_SET([ac_cv_have_decl_EXT2_IOC_GETFLAGS], [no])])]) AS_VAR_IF([ac_cv_have_decl_EXT2_IOC_GETFLAGS], [yes], [AC_DEFINE_UNQUOTED([HAVE_WORKING_EXT2_IOC_GETFLAGS], [1], [Define to 1 if you have a working EXT2_IOC_GETFLAGS])]) AC_CHECK_HEADERS([inttypes.h io.h langinfo.h limits.h]) AC_CHECK_HEADERS([linux/fiemap.h linux/fs.h linux/magic.h linux/types.h]) AC_CHECK_HEADERS([locale.h paths.h poll.h pthread.h pwd.h]) AC_CHECK_HEADERS([readpassphrase.h signal.h spawn.h]) AC_CHECK_HEADERS([stdarg.h stdint.h stdlib.h string.h]) AC_CHECK_HEADERS([sys/cdefs.h sys/extattr.h]) AC_CHECK_HEADERS([sys/ioctl.h sys/mkdev.h sys/mount.h]) AC_CHECK_HEADERS([sys/param.h sys/poll.h sys/select.h sys/statfs.h sys/statvfs.h]) AC_CHECK_HEADERS([sys/time.h sys/utime.h sys/utsname.h sys/vfs.h]) AC_CHECK_HEADERS([time.h unistd.h utime.h wchar.h wctype.h]) AC_CHECK_HEADERS([windows.h]) AC_CHECK_HEADERS([Bcrypt.h]) # check windows.h first; the other headers require it. AC_CHECK_HEADERS([wincrypt.h winioctl.h],[],[], [[#ifdef HAVE_WINDOWS_H # include #endif ]]) # Checks for libraries. AC_ARG_WITH([zlib], AS_HELP_STRING([--without-zlib], [Don't build support for gzip through zlib])) if test "x$with_zlib" != "xno"; then AC_CHECK_HEADERS([zlib.h]) AC_CHECK_LIB(z,inflate) fi AC_ARG_WITH([bz2lib], AS_HELP_STRING([--without-bz2lib], [Don't build support for bzip2 through bz2lib])) if test "x$with_bz2lib" != "xno"; then AC_CHECK_HEADERS([bzlib.h]) case "$host_os" in *mingw* | *cygwin*) dnl AC_CHECK_LIB cannot be used on the Windows port of libbz2, therefore dnl use AC_LINK_IFELSE. AC_MSG_CHECKING([for BZ2_bzDecompressInit in -lbz2]) old_LIBS="$LIBS" LIBS="-lbz2 $LIBS" AC_LINK_IFELSE( [AC_LANG_SOURCE(#include int main() { return BZ2_bzDecompressInit(NULL, 0, 0); })], [ac_cv_lib_bz2_BZ2_bzDecompressInit=yes], [ac_cv_lib_bz2_BZ2_bzDecompressInit=no]) LIBS="$old_LIBS" AC_MSG_RESULT($ac_cv_lib_bz2_BZ2_bzDecompressInit) if test "x$ac_cv_lib_bz2_BZ2_bzDecompressInit" = xyes; then AC_DEFINE([HAVE_LIBBZ2], [1], [Define to 1 if you have the `bz2' library (-lbz2).]) LIBS="-lbz2 $LIBS" fi ;; *) AC_CHECK_LIB(bz2,BZ2_bzDecompressInit) ;; esac fi AC_ARG_WITH([lzmadec], AS_HELP_STRING([--without-lzmadec], [Don't build support for lzma through lzmadec])) if test "x$with_lzmadec" != "xno"; then AC_CHECK_HEADERS([lzmadec.h]) AC_CHECK_LIB(lzmadec,lzmadec_decode) fi AC_ARG_WITH([iconv], AS_HELP_STRING([--without-iconv], [Don't try to link against iconv])) if test "x$with_iconv" != "xno"; then AM_ICONV AC_CHECK_HEADERS([iconv.h],[],[],[#include ]) if test "x$am_cv_func_iconv" = "xyes"; then AC_CHECK_HEADERS([localcharset.h]) am_save_LIBS="$LIBS" LIBS="${LIBS} ${LIBICONV}" AC_CHECK_FUNCS([locale_charset]) LIBS="${am_save_LIBS}" if test "x$ac_cv_func_locale_charset" != "xyes"; then # If locale_charset() is not in libiconv, we have to find libcharset. AC_CHECK_LIB(charset,locale_charset) fi fi fi AC_ARG_WITH([lz4], AS_HELP_STRING([--without-lz4], [Don't build support for lz4 through liblz4])) if test "x$with_lz4" != "xno"; then AC_CHECK_HEADERS([lz4.h lz4hc.h]) AC_CHECK_LIB(lz4,LZ4_decompress_safe) fi AC_ARG_WITH([lzma], AS_HELP_STRING([--without-lzma], [Don't build support for xz through lzma])) if test "x$with_lzma" != "xno"; then AC_CHECK_HEADERS([lzma.h]) AC_CHECK_LIB(lzma,lzma_stream_decoder) # Some pre-release (but widely distributed) versions of liblzma # included a disabled version of lzma_stream_encoder_mt that # fools a naive AC_CHECK_LIB or AC_CHECK_FUNC, so we need # to do something more complex here: AC_CACHE_CHECK( [whether we have multithread support in lzma], ac_cv_lzma_has_mt, [AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[#include ]], [[lzma_stream_encoder_mt(0, 0);]])], [ac_cv_lzma_has_mt=yes], [ac_cv_lzma_has_mt=no])]) if test "x$ac_cv_lzma_has_mt" != xno; then AC_DEFINE([HAVE_LZMA_STREAM_ENCODER_MT], [1], [Define to 1 if you have the `lzma_stream_encoder_mt' function.]) fi fi AC_ARG_WITH([lzo2], AS_HELP_STRING([--without-lzo2], [Don't build support for lzop through liblzo2])) if test "x$with_lzo2" != "xno"; then AC_CHECK_HEADERS([lzo/lzoconf.h lzo/lzo1x.h]) AC_CHECK_LIB(lzo2,lzo1x_decompress_safe) fi AC_ARG_WITH([nettle], AS_HELP_STRING([--without-nettle], [Don't build with crypto support from Nettle])) AC_ARG_WITH([openssl], AS_HELP_STRING([--without-openssl], [Don't build support for mtree and xar hashes through openssl])) case "$host_os" in *darwin* ) with_openssl=no ;; esac AC_ARG_WITH([xml2], AS_HELP_STRING([--without-xml2], [Don't build support for xar through libxml2])) AC_ARG_WITH([expat], AS_HELP_STRING([--without-expat], [Don't build support for xar through expat])) if test "x$with_xml2" != "xno"; then PKG_PROG_PKG_CONFIG PKG_CHECK_MODULES(LIBXML2_PC, [libxml-2.0], [ CPPFLAGS="${CPPFLAGS} ${LIBXML2_PC_CFLAGS}" LIBS="${LIBS} ${LIBXML2_PC_LIBS}" AC_CHECK_LIB(xml2,xmlInitParser,[true],AC_MSG_FAILURE(Missing xml2 library)) ], [ AC_CHECK_LIB(xml2,xmlInitParser) ]) AC_CHECK_HEADERS([libxml/xmlreader.h libxml/xmlwriter.h]) fi if test "x$ac_cv_header_libxml_xmlreader_h" != "xyes"; then if test "x$with_expat" != "xno"; then AC_CHECK_HEADERS([expat.h]) AC_CHECK_LIB(expat,XML_ParserCreate) fi fi AC_ARG_ENABLE([posix-regex-lib], [AS_HELP_STRING([--enable-posix-regex-lib], [choose what library to use for POSIX regular expression support (default: auto)]) AS_HELP_STRING([--enable-posix-regex-lib=libc], [use libc POSIX regular expression support]) AS_HELP_STRING([--enable-posix-regex-lib=libregex], [use libregex POSIX regular expression support]) AS_HELP_STRING([--enable-posix-regex-lib=libpcreposix], [use libpcreposix POSIX regular expression support]) AS_HELP_STRING([--disable-posix-regex-lib], [don't enable POSIX regular expression support])], [], [enable_posix_regex_lib=auto]) posix_regex_lib_found= if test "$enable_posix_regex_lib" = "auto" || test "$enable_posix_regex_lib" = "libc" || test "$enable_posix_regex_lib" = "libregex"; then AC_CHECK_HEADERS([regex.h]) if test "x$ac_cv_header_regex_h" != "xno"; then AC_CHECK_FUNC(regcomp) if test "x$ac_cv_func_regcomp" = xyes; then posix_regex_lib_found=1 else AC_CHECK_LIB(regex,regcomp) if test "x$ac_cv_lib_regex_regcomp" = xyes; then posix_regex_lib_found=1 fi fi fi fi if test -z $posix_regex_lib_found && (test "$enable_posix_regex_lib" = "auto" || test "$enable_posix_regex_lib" = "libpcreposix"); then AC_CHECK_HEADERS([pcreposix.h]) AC_CHECK_LIB(pcreposix,regcomp) if test "x$ac_cv_lib_pcreposix_regcomp" != xyes; then AC_MSG_NOTICE(trying libpcreposix check again with libpcre) unset ac_cv_lib_pcreposix_regcomp AC_CHECK_LIB(pcre,pcre_exec) AC_CHECK_LIB(pcreposix,regcomp) if test "x$ac_cv_lib_pcre_pcre_exec" = xyes && test "x$ac_cv_lib_pcreposix_regcomp" = xyes; then AC_MSG_CHECKING(if PCRE_STATIC needs to be defined) AC_LINK_IFELSE( [AC_LANG_SOURCE(#include int main() { return regcomp(NULL, NULL, 0); })], [without_pcre_static=yes], [without_pcre_static=no]) AC_LINK_IFELSE( [AC_LANG_SOURCE(#define PCRE_STATIC #include int main() { return regcomp(NULL, NULL, 0); })], [with_pcre_static=yes], [with_pcre_static=no]) if test "x$without_pcre_static" != xyes && test "x$with_pcre_static" = xyes; then AC_MSG_RESULT(yes) AC_DEFINE([PCRE_STATIC], [1], [Define to 1 if PCRE_STATIC needs to be defined.]) elif test "x$without_pcre_static" = xyes || test "x$with_pcre_static" = xyes; then AC_MSG_RESULT(no) fi posix_regex_lib_found=1 fi else posix_regex_lib_found=1 fi fi # TODO: Give the user the option of using a pre-existing system # libarchive. This will define HAVE_LIBARCHIVE which will cause # bsdtar_platform.h to use #include <...> for the libarchive headers. # Need to include Makefile.am magic to link against system # -larchive in that case. #AC_CHECK_LIB(archive,archive_version) # Checks for supported compiler flags AX_APPEND_COMPILE_FLAGS([-Wall -Wformat -Wformat-security]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST # la_TYPE_UID_T defaults to "int", which is incorrect for MinGW # and MSVC. Use a customized version. la_TYPE_UID_T AC_TYPE_MODE_T # AC_TYPE_OFF_T defaults to "long", which limits us to 4GB files on # most systems... default to "long long" instead. AC_CHECK_TYPE(off_t, [long long]) AC_TYPE_SIZE_T AC_CHECK_TYPE(id_t, [unsigned long]) AC_CHECK_TYPE(uintptr_t, [unsigned int]) # Check for tm_gmtoff in struct tm AC_CHECK_MEMBERS([struct tm.tm_gmtoff, struct tm.__tm_gmtoff],,, [ #include ]) # Check for f_namemax in struct statfs AC_CHECK_MEMBERS([struct statfs.f_namemax],,, [ #include #include ]) # Check for f_iosize in struct statvfs AC_CHECK_MEMBERS([struct statvfs.f_iosize],,, [ #include ]) # Check for birthtime in struct stat AC_CHECK_MEMBERS([struct stat.st_birthtime]) # Check for high-resolution timestamps in struct stat AC_CHECK_MEMBERS([struct stat.st_birthtimespec.tv_nsec]) AC_CHECK_MEMBERS([struct stat.st_mtimespec.tv_nsec]) AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec]) AC_CHECK_MEMBERS([struct stat.st_mtime_n]) # AIX AC_CHECK_MEMBERS([struct stat.st_umtime]) # Tru64 AC_CHECK_MEMBERS([struct stat.st_mtime_usec]) # Hurd # Check for block size support in struct stat AC_CHECK_MEMBERS([struct stat.st_blksize]) # Check for st_flags in struct stat (BSD fflags) AC_CHECK_MEMBERS([struct stat.st_flags]) # If you have uintmax_t, we assume printf supports %ju # If you have unsigned long long, we assume printf supports %llu # TODO: Check for %ju and %llu support directly. AC_CHECK_TYPES([uintmax_t, unsigned long long]) # We use C99-style integer types # Declare them if the local platform doesn't already do so. AC_TYPE_INTMAX_T AC_TYPE_UINTMAX_T AC_TYPE_INT64_T AC_TYPE_UINT64_T AC_TYPE_INT32_T AC_TYPE_UINT32_T AC_TYPE_INT16_T AC_TYPE_UINT16_T AC_TYPE_UINT8_T AC_CHECK_DECLS([SIZE_MAX, INT32_MAX, INT32_MIN]) AC_CHECK_DECLS([INT64_MAX, INT64_MIN, UINT64_MAX, UINT32_MAX]) AC_CHECK_DECLS([INTMAX_MAX, INTMAX_MIN, UINTMAX_MAX]) AC_CHECK_DECL([SSIZE_MAX], [AC_DEFINE(HAVE_DECL_SSIZE_MAX, 1, [Define to 1 if you have the declaration of `SSIZE_MAX', and to 0 if you don't.])], [], [#include ]) AC_CHECK_DECL([EFTYPE], [AC_DEFINE(HAVE_EFTYPE, 1, [A possible errno value for invalid file format errors])], [], [#include ]) AC_CHECK_DECL([EILSEQ], [AC_DEFINE(HAVE_EILSEQ, 1, [A possible errno value for invalid file format errors])], [], [#include ]) AC_CHECK_TYPE([wchar_t], [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_[]wchar_t), 1, [Define to 1 if the system has the type `wchar_t'.])dnl AC_CHECK_SIZEOF([wchar_t])], []) AC_HEADER_TIME # Checks for library functions. AC_PROG_GCC_TRADITIONAL AC_HEADER_MAJOR AC_FUNC_FSEEKO AC_FUNC_MEMCMP AC_FUNC_LSTAT AC_FUNC_STAT AC_FUNC_STRERROR_R AC_FUNC_STRFTIME AC_FUNC_VPRINTF # check for: # CreateHardLinkA(LPCSTR, LPCSTR, LPSECURITY_ATTRIBUTES) # To avoid necessity for including windows.h or special forward declaration # workarounds, we use 'void *' for 'struct SECURITY_ATTRIBUTES *' AC_CHECK_STDCALL_FUNC([CreateHardLinkA],[const char *, const char *, void *]) AC_CHECK_FUNCS([arc4random_buf chflags chown chroot ctime_r dirfd]) AC_CHECK_FUNCS([fchdir fchflags fchmod fchown fcntl fdopendir fork]) AC_CHECK_FUNCS([fstat fstatat fstatfs fstatvfs ftruncate]) AC_CHECK_FUNCS([futimens futimes futimesat]) AC_CHECK_FUNCS([geteuid getpid getgrgid_r getgrnam_r]) AC_CHECK_FUNCS([getpwnam_r getpwuid_r getvfsbyname gmtime_r]) AC_CHECK_FUNCS([lchflags lchmod lchown link localtime_r lstat lutimes]) AC_CHECK_FUNCS([mbrtowc memmove memset]) AC_CHECK_FUNCS([mkdir mkfifo mknod mkstemp]) AC_CHECK_FUNCS([nl_langinfo openat pipe poll posix_spawnp readlink readlinkat]) AC_CHECK_FUNCS([readpassphrase]) AC_CHECK_FUNCS([select setenv setlocale sigaction statfs statvfs]) AC_CHECK_FUNCS([strchr strdup strerror strncpy_s strrchr symlink timegm]) AC_CHECK_FUNCS([tzset unsetenv utime utimensat utimes vfork]) AC_CHECK_FUNCS([wcrtomb wcscmp wcscpy wcslen wctomb wmemcmp wmemcpy wmemmove]) AC_CHECK_FUNCS([_ctime64_s _fseeki64]) AC_CHECK_FUNCS([_get_timezone _localtime64_s _mkgmtime64]) # detects cygwin-1.7, as opposed to older versions AC_CHECK_FUNCS([cygwin_conv_path]) # There are several variants of readdir_r around; we only # accept the POSIX-compliant version. AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#include ]], [[DIR *dir; struct dirent e, *r; return(readdir_r(dir, &e, &r));]])], [AC_DEFINE(HAVE_READDIR_R,1,[Define to 1 if you have a POSIX compatible readdir_r])] ) # FreeBSD's nl_langinfo supports an option to specify whether the # current locale uses month/day or day/month ordering. It makes the # output a little prettier... AC_CHECK_DECL([D_MD_ORDER], [AC_DEFINE(HAVE_D_MD_ORDER, 1, [Define to 1 if nl_langinfo supports D_MD_ORDER])], [], [#if HAVE_LANGINFO_H #include #endif ]) # Check for dirent.d_namlen field explicitly # (This is a bit more straightforward than, if not quite as portable as, # the recipe given by the autoconf maintainers.) AC_CHECK_MEMBER(struct dirent.d_namlen,,, [#if HAVE_DIRENT_H #include #endif ]) # Check for Extended Attributes support AC_ARG_ENABLE([xattr], AS_HELP_STRING([--disable-xattr], [Disable Extended Attributes support (default: check)])) if test "x$enable_xattr" != "xno"; then AC_CHECK_HEADERS([attr/xattr.h]) AC_CHECK_HEADERS([sys/xattr.h sys/ea.h]) AC_SEARCH_LIBS([setxattr], [attr]) AC_CHECK_FUNCS([extattr_get_file extattr_list_file]) AC_CHECK_FUNCS([extattr_set_fd extattr_set_file]) AC_CHECK_FUNCS([fgetxattr flistxattr fsetxattr getxattr]) AC_CHECK_FUNCS([lgetxattr listxattr llistxattr lsetxattr]) AC_CHECK_FUNCS([fgetea flistea fsetea getea]) AC_CHECK_FUNCS([lgetea listea llistea lsetea]) AC_CHECK_DECLS([EXTATTR_NAMESPACE_USER], [], [], [#include #include ]) fi # Check for ACL support # # The ACL support in libarchive is written against the POSIX1e draft, # which was never officially approved and varies quite a bit across # platforms. Worse, some systems have completely non-POSIX acl functions, # which makes the following checks rather more complex than I would like. # AC_ARG_ENABLE([acl], AS_HELP_STRING([--disable-acl], [Disable ACL support (default: check)])) if test "x$enable_acl" != "xno"; then AC_CHECK_HEADERS([acl/libacl.h]) AC_CHECK_HEADERS([sys/acl.h]) AC_CHECK_LIB([acl],[acl_get_file]) AC_CHECK_FUNCS([acl_create_entry acl_init acl_set_fd acl_set_fd_np acl_set_file]) AC_CHECK_TYPES(acl_permset_t,,, [#if HAVE_SYS_TYPES_H #include #endif #if HAVE_SYS_ACL_H #include #endif ]) # The "acl_get_perm()" function was omitted from the POSIX draft. # (It's a pretty obvious oversight; otherwise, there's no way to # test for specific permissions in a permset.) Linux uses the obvious # name, FreeBSD adds _np to mark it as "non-Posix extension." # Test for both as a double-check that we really have POSIX-style ACL support. AC_CHECK_FUNCS(acl_get_perm_np acl_get_perm acl_get_link acl_get_link_np,,, [#if HAVE_SYS_TYPES_H #include #endif #if HAVE_SYS_ACL_H #include #endif ]) # MacOS has an acl.h that isn't POSIX. It can be detected by # checking for ACL_USER AC_CHECK_DECL([ACL_USER], [AC_DEFINE(HAVE_ACL_USER, 1, [True for systems with POSIX ACL support])], [], [#include ]) fi # Additional requirements AC_SYS_LARGEFILE dnl NOTE: Crypto checks must run last. AC_DEFUN([CRYPTO_CHECK], [ if test "$found_$1" != yes; then saved_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS -I. -I$srcdir -I$srcdir/libarchive" touch "check_crypto_md.h" AC_MSG_CHECKING([support for ARCHIVE_CRYPTO_$1_$2]) AC_LINK_IFELSE([AC_LANG_SOURCE([ #define ARCHIVE_$1_COMPILE_TEST #define ARCHIVE_CRYPTO_$1_$2 #define PLATFORM_CONFIG_H "check_crypto_md.h" $(cat "$srcdir/libarchive/archive_digest.c") int main(int argc, char **argv) { archive_$3_ctx ctx; archive_$3_init(&ctx); archive_$3_update(&ctx, *argv, argc); archive_$3_final(&ctx, NULL); return 0; } ])], [ AC_MSG_RESULT([yes]) found_$1=yes found_$2=yes AC_DEFINE(ARCHIVE_CRYPTO_$1_$2, 1, [ $1 via ARCHIVE_CRYPTO_$1_$2 supported.]) ], [ AC_MSG_RESULT([no])]) CPPFLAGS="$saved_CPPFLAGS" rm "check_crypto_md.h" fi ]) AC_DEFUN([CRYPTO_CHECK_WIN], [ if test "$found_$1" != yes; then AC_MSG_CHECKING([support for ARCHIVE_CRYPTO_$1_WIN]) AC_LINK_IFELSE([AC_LANG_SOURCE([ #define ARCHIVE_$1_COMPILE_TEST #include #include int main(int argc, char **argv) { (void)argc; (void)argv; return ($2); } ])], [ AC_MSG_RESULT([yes]) found_$1=yes found_WIN=yes AC_DEFINE(ARCHIVE_CRYPTO_$1_WIN, 1, [ $1 via ARCHIVE_CRYPTO_$1_WIN supported.]) ], [ AC_MSG_RESULT([no])]) fi ]) case "$host_os" in *mingw* | *cygwin*) ;; *) CRYPTO_CHECK(MD5, LIBC, md5) CRYPTO_CHECK(MD5, LIBSYSTEM, md5) CRYPTO_CHECK(RMD160, LIBC, rmd160) CRYPTO_CHECK(SHA1, LIBC, sha1) CRYPTO_CHECK(SHA1, LIBSYSTEM, sha1) CRYPTO_CHECK(SHA256, LIBC, sha256) CRYPTO_CHECK(SHA256, LIBC2, sha256) CRYPTO_CHECK(SHA256, LIBC3, sha256) CRYPTO_CHECK(SHA256, LIBSYSTEM, sha256) CRYPTO_CHECK(SHA384, LIBC, sha384) CRYPTO_CHECK(SHA384, LIBC2, sha384) CRYPTO_CHECK(SHA384, LIBC3, sha384) CRYPTO_CHECK(SHA384, LIBSYSTEM, sha384) CRYPTO_CHECK(SHA512, LIBC, sha512) CRYPTO_CHECK(SHA512, LIBC2, sha512) CRYPTO_CHECK(SHA512, LIBC3, sha512) CRYPTO_CHECK(SHA512, LIBSYSTEM, sha512) ;; esac if test "x$with_nettle" != "xno"; then AC_CHECK_HEADERS([nettle/md5.h nettle/ripemd160.h nettle/sha.h]) AC_CHECK_HEADERS([nettle/pbkdf2.h nettle/aes.h nettle/hmac.h]) saved_LIBS=$LIBS AC_CHECK_LIB(nettle,nettle_sha1_init) CRYPTO_CHECK(MD5, NETTLE, md5) CRYPTO_CHECK(RMD160, NETTLE, rmd160) CRYPTO_CHECK(SHA1, NETTLE, sha1) CRYPTO_CHECK(SHA256, NETTLE, sha256) CRYPTO_CHECK(SHA384, NETTLE, sha384) CRYPTO_CHECK(SHA512, NETTLE, sha512) if test "x$found_NETTLE" != "xyes"; then LIBS=$saved_LIBS fi fi if test "x$with_openssl" != "xno"; then AC_CHECK_HEADERS([openssl/evp.h]) saved_LIBS=$LIBS case "$host_os" in *mingw* | *cygwin*) case "$host_cpu" in x86_64) AC_CHECK_LIB(eay64,OPENSSL_config) if test "x$ac_cv_lib_eay64_main" != "xyes"; then AC_CHECK_LIB(eay32,OPENSSL_config) fi ;; *) AC_CHECK_LIB(eay32,OPENSSL_config) ;; esac ;; *) AC_CHECK_LIB(crypto,OPENSSL_config) ;; esac CRYPTO_CHECK(MD5, OPENSSL, md5) CRYPTO_CHECK(RMD160, OPENSSL, rmd160) CRYPTO_CHECK(SHA1, OPENSSL, sha1) CRYPTO_CHECK(SHA256, OPENSSL, sha256) CRYPTO_CHECK(SHA384, OPENSSL, sha384) CRYPTO_CHECK(SHA512, OPENSSL, sha512) if test "x$found_OPENSSL" != "xyes"; then LIBS=$saved_LIBS else AC_CHECK_FUNCS([PKCS5_PBKDF2_HMAC_SHA1]) fi fi # Probe libmd AFTER OpenSSL/libcrypto. # The two are incompatible and OpenSSL is more complete. AC_CHECK_HEADERS([md5.h ripemd.h sha.h sha256.h sha512.h]) saved_LIBS=$LIBS AC_CHECK_LIB(md,MD5Init) CRYPTO_CHECK(MD5, LIBMD, md5) CRYPTO_CHECK(RMD160, LIBMD, rmd160) CRYPTO_CHECK(SHA1, LIBMD, sha1) CRYPTO_CHECK(SHA256, LIBMD, sha256) CRYPTO_CHECK(SHA512, LIBMD, sha512) if test "x$found_LIBMD" != "xyes"; then LIBS=$saved_LIBS fi case "$host_os" in *mingw* | *cygwin*) CRYPTO_CHECK_WIN(MD5, CALG_MD5) CRYPTO_CHECK_WIN(SHA1, CALG_SHA1) CRYPTO_CHECK_WIN(SHA256, CALG_SHA_256) CRYPTO_CHECK_WIN(SHA384, CALG_SHA_384) CRYPTO_CHECK_WIN(SHA512, CALG_SHA_512) ;; esac # Ensure test directories are present if building out-of-tree AC_CONFIG_COMMANDS([mkdirs], [mkdir -p libarchive/test tar/test cat/test cpio/test]) AC_OUTPUT Index: vendor/libarchive/dist/libarchive/archive.h =================================================================== --- vendor/libarchive/dist/libarchive/archive.h (revision 302036) +++ vendor/libarchive/dist/libarchive/archive.h (revision 302037) @@ -1,1183 +1,1183 @@ /*- * Copyright (c) 2003-2010 Tim Kientzle * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/lib/libarchive/archive.h.in,v 1.50 2008/05/26 17:00:22 kientzle Exp $ */ #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 3002000 +#define ARCHIVE_VERSION_NUMBER 3002001 #include #include /* for wchar_t */ #include /* For FILE * */ #include /* For time_t */ /* * Note: archive.h is for use outside of libarchive; the configuration * headers (config.h, archive_platform.h, etc.) are purely internal. * Do NOT use HAVE_XXX configuration macros to control the behavior of * this header! If you must conditionalize, use predefined compiler and/or * platform macros. */ #if defined(__BORLANDC__) && __BORLANDC__ >= 0x560 # include #elif !defined(__WATCOMC__) && !defined(_MSC_VER) && !defined(__INTERIX) && !defined(__BORLANDC__) && !defined(_SCO_DS) && !defined(__osf__) # include #endif /* 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 #define __LA_INT64_T_DEFINED # if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__) typedef __int64 la_int64_t; # else # include /* ssize_t */ # 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 # include /* ssize_t */ typedef ssize_t la_ssize_t; # endif #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 * libarchive source should ever define __LIBARCHIVE_BUILD. */ #if ((defined __WIN32__) || (defined _WIN32) || defined(__CYGWIN__)) && (!defined LIBARCHIVE_STATIC) # ifdef __LIBARCHIVE_BUILD # ifdef __GNUC__ # define __LA_DECL __attribute__((dllexport)) extern # else # define __LA_DECL __declspec(dllexport) # endif # else # ifdef __GNUC__ # define __LA_DECL # else # define __LA_DECL __declspec(dllimport) # endif # endif #else /* Static libraries or non-Windows needs no special declaration. */ # define __LA_DECL #endif #if defined(__GNUC__) && __GNUC__ >= 3 && !defined(__MINGW32__) #define __LA_PRINTF(fmtarg, firstvararg) \ __attribute__((__format__ (__printf__, fmtarg, firstvararg))) #else #define __LA_PRINTF(fmtarg, firstvararg) /* nothing */ #endif #if defined(__GNUC__) && __GNUC__ >= 3 && __GNUC_MINOR__ >= 1 # define __LA_DEPRECATED __attribute__((deprecated)) #else # define __LA_DEPRECATED #endif #ifdef __cplusplus extern "C" { #endif /* * The version number is provided as both a macro and a function. * The macro identifies the installed header; the function identifies * the library version (which may not be the same if you're using a * dynamically-linked version of the library). Of course, if the * header and library are very different, you should expect some * strangeness. Don't do that. */ __LA_DECL int archive_version_number(void); /* * Textual name/version of the library, useful for version displays. */ -#define ARCHIVE_VERSION_ONLY_STRING "3.2.0" +#define ARCHIVE_VERSION_ONLY_STRING "3.2.1" #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; /* * Error codes: Use archive_errno() and archive_error_string() * to retrieve details. Unless specified otherwise, all functions * that return 'int' use these codes. */ #define ARCHIVE_EOF 1 /* Found end of archive. */ #define ARCHIVE_OK 0 /* Operation was successful. */ #define ARCHIVE_RETRY (-10) /* Retry might succeed. */ #define ARCHIVE_WARN (-20) /* Partial success. */ /* For example, if write_header "fails", then you can't push data. */ #define ARCHIVE_FAILED (-25) /* Current operation cannot complete. */ /* But if write_header is "fatal," then this archive is dead and useless. */ #define ARCHIVE_FATAL (-30) /* No more operations are possible. */ /* * As far as possible, archive_errno returns standard platform errno codes. * Of course, the details vary by platform, so the actual definitions * here are stored in "archive_platform.h". The symbols are listed here * for reference; as a rule, clients should not need to know the exact * platform-dependent error code. */ /* Unrecognized or invalid file format. */ /* #define ARCHIVE_ERRNO_FILE_FORMAT */ /* Illegal usage of the library. */ /* #define ARCHIVE_ERRNO_PROGRAMMER_ERROR */ /* Unknown or unclassified error. */ /* #define ARCHIVE_ERRNO_MISC */ /* * Callbacks are invoked to automatically read/skip/write/open/close the * archive. You can provide your own for complex tasks (like breaking * archives across multiple tapes) or use standard ones built into the * library. */ /* Returns pointer and size of next block of data from 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. * This may skip fewer bytes than requested; it may even skip zero bytes. * If you do skip fewer bytes than requested, libarchive will invoke your * read callback and discard data as necessary to make up the full skip. */ typedef la_int64_t archive_skip_callback(struct archive *, void *_client_data, la_int64_t request); /* Seeks to specified location in the file and returns the position. * Whence values are SEEK_SET, SEEK_CUR, SEEK_END from stdio.h. * Return ARCHIVE_FATAL if the seek fails for any reason. */ typedef la_int64_t archive_seek_callback(struct archive *, void *_client_data, la_int64_t offset, int whence); /* Returns size actually written, zero on EOF, -1 on error. */ typedef la_ssize_t archive_write_callback(struct archive *, void *_client_data, const void *_buffer, size_t _length); typedef int archive_open_callback(struct archive *, void *_client_data); typedef int archive_close_callback(struct archive *, void *_client_data); /* Switches from one client data object to the next/prev client data object. * This is useful for reading from different data blocks such as a set of files * that make up one large file. */ 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 #define ARCHIVE_FILTER_GZIP 1 #define ARCHIVE_FILTER_BZIP2 2 #define ARCHIVE_FILTER_COMPRESS 3 #define ARCHIVE_FILTER_PROGRAM 4 #define ARCHIVE_FILTER_LZMA 5 #define ARCHIVE_FILTER_XZ 6 #define ARCHIVE_FILTER_UU 7 #define ARCHIVE_FILTER_RPM 8 #define ARCHIVE_FILTER_LZIP 9 #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 #define ARCHIVE_COMPRESSION_GZIP ARCHIVE_FILTER_GZIP #define ARCHIVE_COMPRESSION_BZIP2 ARCHIVE_FILTER_BZIP2 #define ARCHIVE_COMPRESSION_COMPRESS ARCHIVE_FILTER_COMPRESS #define ARCHIVE_COMPRESSION_PROGRAM ARCHIVE_FILTER_PROGRAM #define ARCHIVE_COMPRESSION_LZMA ARCHIVE_FILTER_LZMA #define ARCHIVE_COMPRESSION_XZ ARCHIVE_FILTER_XZ #define ARCHIVE_COMPRESSION_UU ARCHIVE_FILTER_UU #define ARCHIVE_COMPRESSION_RPM ARCHIVE_FILTER_RPM #define ARCHIVE_COMPRESSION_LZIP ARCHIVE_FILTER_LZIP #define ARCHIVE_COMPRESSION_LRZIP ARCHIVE_FILTER_LRZIP #endif /* * Codes returned by archive_format. * * Top 16 bits identifies the format family (e.g., "tar"); lower * 16 bits indicate the variant. This is updated by read_next_header. * Note that the lower 16 bits will often vary from entry to entry. * In some cases, this variation occurs as libarchive learns more about * the archive (for example, later entries might utilize extensions that * weren't necessary earlier in the archive; in this case, libarchive * will change the format code to indicate the extended format that * was used). In other cases, it's because different tools have * modified the archive and so different parts of the archive * actually have slightly different formats. (Both tar and cpio store * format codes in each entry, so it is quite possible for each * entry to be in a different format.) */ #define ARCHIVE_FORMAT_BASE_MASK 0xff0000 #define ARCHIVE_FORMAT_CPIO 0x10000 #define ARCHIVE_FORMAT_CPIO_POSIX (ARCHIVE_FORMAT_CPIO | 1) #define ARCHIVE_FORMAT_CPIO_BIN_LE (ARCHIVE_FORMAT_CPIO | 2) #define ARCHIVE_FORMAT_CPIO_BIN_BE (ARCHIVE_FORMAT_CPIO | 3) #define ARCHIVE_FORMAT_CPIO_SVR4_NOCRC (ARCHIVE_FORMAT_CPIO | 4) #define ARCHIVE_FORMAT_CPIO_SVR4_CRC (ARCHIVE_FORMAT_CPIO | 5) #define ARCHIVE_FORMAT_CPIO_AFIO_LARGE (ARCHIVE_FORMAT_CPIO | 6) #define ARCHIVE_FORMAT_SHAR 0x20000 #define ARCHIVE_FORMAT_SHAR_BASE (ARCHIVE_FORMAT_SHAR | 1) #define ARCHIVE_FORMAT_SHAR_DUMP (ARCHIVE_FORMAT_SHAR | 2) #define ARCHIVE_FORMAT_TAR 0x30000 #define ARCHIVE_FORMAT_TAR_USTAR (ARCHIVE_FORMAT_TAR | 1) #define ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE (ARCHIVE_FORMAT_TAR | 2) #define ARCHIVE_FORMAT_TAR_PAX_RESTRICTED (ARCHIVE_FORMAT_TAR | 3) #define ARCHIVE_FORMAT_TAR_GNUTAR (ARCHIVE_FORMAT_TAR | 4) #define ARCHIVE_FORMAT_ISO9660 0x40000 #define ARCHIVE_FORMAT_ISO9660_ROCKRIDGE (ARCHIVE_FORMAT_ISO9660 | 1) #define ARCHIVE_FORMAT_ZIP 0x50000 #define ARCHIVE_FORMAT_EMPTY 0x60000 #define ARCHIVE_FORMAT_AR 0x70000 #define ARCHIVE_FORMAT_AR_GNU (ARCHIVE_FORMAT_AR | 1) #define ARCHIVE_FORMAT_AR_BSD (ARCHIVE_FORMAT_AR | 2) #define ARCHIVE_FORMAT_MTREE 0x80000 #define ARCHIVE_FORMAT_RAW 0x90000 #define ARCHIVE_FORMAT_XAR 0xA0000 #define ARCHIVE_FORMAT_LHA 0xB0000 #define ARCHIVE_FORMAT_CAB 0xC0000 #define ARCHIVE_FORMAT_RAR 0xD0000 #define ARCHIVE_FORMAT_7ZIP 0xE0000 #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: * 1) Ask archive_read_new for an archive reader object. * 2) Update any global properties as appropriate. * In particular, you'll certainly want to call appropriate * archive_read_support_XXX functions. * 3) Call archive_read_open_XXX to open the archive * 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. */ __LA_DECL struct archive *archive_read_new(void); /* * The archive_read_support_XXX calls enable auto-detect for this * archive handle. They also link in the necessary support code. * For example, if you don't want bzlib linked in, don't invoke * support_compression_bzip2(). The "all" functions provide the * obvious shorthand. */ #if ARCHIVE_VERSION_NUMBER < 4000000 __LA_DECL int archive_read_support_compression_all(struct archive *) __LA_DEPRECATED; __LA_DECL int archive_read_support_compression_bzip2(struct archive *) __LA_DEPRECATED; __LA_DECL int archive_read_support_compression_compress(struct archive *) __LA_DEPRECATED; __LA_DECL int archive_read_support_compression_gzip(struct archive *) __LA_DEPRECATED; __LA_DECL int archive_read_support_compression_lzip(struct archive *) __LA_DEPRECATED; __LA_DECL int archive_read_support_compression_lzma(struct archive *) __LA_DEPRECATED; __LA_DECL int archive_read_support_compression_none(struct archive *) __LA_DEPRECATED; __LA_DECL int archive_read_support_compression_program(struct archive *, const char *command) __LA_DEPRECATED; __LA_DECL int archive_read_support_compression_program_signature (struct archive *, const char *, const void * /* match */, size_t) __LA_DEPRECATED; __LA_DECL int archive_read_support_compression_rpm(struct archive *) __LA_DEPRECATED; __LA_DECL int archive_read_support_compression_uu(struct archive *) __LA_DEPRECATED; __LA_DECL int archive_read_support_compression_xz(struct archive *) __LA_DEPRECATED; #endif __LA_DECL int archive_read_support_filter_all(struct archive *); __LA_DECL int archive_read_support_filter_bzip2(struct archive *); __LA_DECL int archive_read_support_filter_compress(struct archive *); __LA_DECL int archive_read_support_filter_gzip(struct archive *); __LA_DECL int archive_read_support_filter_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 *); __LA_DECL int archive_read_support_filter_none(struct archive *); __LA_DECL int archive_read_support_filter_program(struct archive *, const char *command); __LA_DECL int archive_read_support_filter_program_signature (struct archive *, const char * /* cmd */, const void * /* match */, size_t); __LA_DECL int archive_read_support_filter_rpm(struct archive *); __LA_DECL int archive_read_support_filter_uu(struct archive *); __LA_DECL int archive_read_support_filter_xz(struct archive *); __LA_DECL int archive_read_support_format_7zip(struct archive *); __LA_DECL int archive_read_support_format_all(struct archive *); __LA_DECL int archive_read_support_format_ar(struct archive *); __LA_DECL int archive_read_support_format_by_code(struct archive *, int); __LA_DECL int archive_read_support_format_cab(struct archive *); __LA_DECL int archive_read_support_format_cpio(struct archive *); __LA_DECL int archive_read_support_format_empty(struct archive *); __LA_DECL int archive_read_support_format_gnutar(struct archive *); __LA_DECL int archive_read_support_format_iso9660(struct archive *); __LA_DECL int archive_read_support_format_lha(struct archive *); __LA_DECL int archive_read_support_format_mtree(struct archive *); __LA_DECL int archive_read_support_format_rar(struct archive *); __LA_DECL int archive_read_support_format_raw(struct archive *); __LA_DECL int archive_read_support_format_tar(struct archive *); __LA_DECL int archive_read_support_format_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 * is known in advance. */ __LA_DECL int archive_read_set_format(struct archive *, int); __LA_DECL int archive_read_append_filter(struct archive *, int); __LA_DECL int archive_read_append_filter_program(struct archive *, const char *); __LA_DECL int archive_read_append_filter_program_signature (struct archive *, const char *, const void * /* match */, size_t); /* Set various callbacks. */ __LA_DECL int archive_read_set_open_callback(struct archive *, archive_open_callback *); __LA_DECL int archive_read_set_read_callback(struct archive *, archive_read_callback *); __LA_DECL int archive_read_set_seek_callback(struct archive *, archive_seek_callback *); __LA_DECL int archive_read_set_skip_callback(struct archive *, archive_skip_callback *); __LA_DECL int archive_read_set_close_callback(struct archive *, archive_close_callback *); /* Callback used to switch between one data object to the next */ __LA_DECL int archive_read_set_switch_callback(struct archive *, archive_switch_callback *); /* This sets the first data object. */ __LA_DECL int archive_read_set_callback_data(struct archive *, void *); /* This sets data object at specified index */ __LA_DECL int archive_read_set_callback_data2(struct archive *, void *, unsigned int); /* This adds a data object at the specified index. */ __LA_DECL int archive_read_add_callback_data(struct archive *, void *, unsigned int); /* This appends a data object to the end of list */ __LA_DECL int archive_read_append_callback_data(struct archive *, void *); /* This prepends a data object to the beginning of list */ __LA_DECL int archive_read_prepend_callback_data(struct archive *, void *); /* Opening freezes the callbacks. */ __LA_DECL int archive_read_open1(struct archive *); /* Convenience wrappers around the above. */ __LA_DECL int archive_read_open(struct archive *, void *_client_data, archive_open_callback *, archive_read_callback *, archive_close_callback *); __LA_DECL int archive_read_open2(struct archive *, void *_client_data, archive_open_callback *, archive_read_callback *, archive_skip_callback *, archive_close_callback *); /* * A variety of shortcuts that invoke archive_read_open() with * canned callbacks suitable for common situations. The ones that * accept a block size handle tape blocking correctly. */ /* Use this if you know the filename. Note: NULL indicates stdin. */ __LA_DECL int archive_read_open_filename(struct archive *, const char *_filename, size_t _block_size); /* Use this for reading multivolume files by filenames. * NOTE: Must be NULL terminated. Sorting is NOT done. */ __LA_DECL int archive_read_open_filenames(struct archive *, const char **_filenames, size_t _block_size); __LA_DECL int archive_read_open_filename_w(struct archive *, const wchar_t *_filename, size_t _block_size); /* archive_read_open_file() is a deprecated synonym for ..._open_filename(). */ __LA_DECL int archive_read_open_file(struct archive *, 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 *, 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, 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, size_t _block_size); /* Read an archive that's already open, using a FILE *. */ /* Note: DO NOT use this with tape drives. */ __LA_DECL int archive_read_open_FILE(struct archive *, FILE *_file); /* Parses and returns next entry header. */ __LA_DECL int archive_read_next_header(struct archive *, struct archive_entry **); /* Parses and returns next entry header using the archive_entry passed in */ __LA_DECL int archive_read_next_header2(struct archive *, struct archive_entry *); /* * Retrieve the byte offset in UNCOMPRESSED data where last-read * header started. */ __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 uncapable 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 *, 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); /* * A zero-copy version of archive_read_data that also exposes the file offset * of each returned block. Note that the client has no way to specify * the desired size of the block. The API does guarantee that offsets will * 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); /*- * Some convenience functions that are built on archive_read_data: * 'skip': skips entire entry * 'into_buffer': writes data into memory buffer that you provide * 'into_fd': writes data to specified filedes */ __LA_DECL int archive_read_data_skip(struct archive *); __LA_DECL int archive_read_data_into_fd(struct archive *, int fd); /* * Set read options. */ /* Apply option to the format only. */ __LA_DECL int archive_read_set_format_option(struct archive *_a, const char *m, const char *o, const char *v); /* Apply option to the filter only. */ __LA_DECL int archive_read_set_filter_option(struct archive *_a, const char *m, const char *o, const char *v); /* Apply option to both the format and the filter. */ __LA_DECL int archive_read_set_option(struct archive *_a, const char *m, const char *o, const char *v); /* Apply option string to both the format and the filter. */ __LA_DECL int archive_read_set_options(struct archive *_a, const char *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. * * This does quite a bit more than just copy data to disk. It also: * - Creates intermediate directories as required. * - Manages directory permissions: non-writable directories will * be initially created with write permission enabled; when the * archive is closed, dir permissions are edited to the values specified * in the archive. * - Checks hardlinks: hardlinks will not be extracted unless the * linked-to file was also extracted within the same session. (TODO) */ /* The "flags" argument selects optional behavior, 'OR' the flags you want. */ /* Default: Do not try to set owner/group. */ #define ARCHIVE_EXTRACT_OWNER (0x0001) /* Default: Do obey umask, do not restore SUID/SGID/SVTX bits. */ #define ARCHIVE_EXTRACT_PERM (0x0002) /* Default: Do not restore mtime/atime. */ #define ARCHIVE_EXTRACT_TIME (0x0004) /* Default: Replace existing files. */ #define ARCHIVE_EXTRACT_NO_OVERWRITE (0x0008) /* Default: Try create first, unlink only if create fails with EEXIST. */ #define ARCHIVE_EXTRACT_UNLINK (0x0010) /* Default: Do not restore ACLs. */ #define ARCHIVE_EXTRACT_ACL (0x0020) /* Default: Do not restore fflags. */ #define ARCHIVE_EXTRACT_FFLAGS (0x0040) /* Default: Do not restore xattrs. */ #define ARCHIVE_EXTRACT_XATTR (0x0080) /* Default: Do not try to guard against extracts redirected by symlinks. */ /* Note: With ARCHIVE_EXTRACT_UNLINK, will remove any intermediate symlink. */ #define ARCHIVE_EXTRACT_SECURE_SYMLINKS (0x0100) /* Default: Do not reject entries with '..' as path elements. */ #define ARCHIVE_EXTRACT_SECURE_NODOTDOT (0x0200) /* Default: Create parent directories as needed. */ #define ARCHIVE_EXTRACT_NO_AUTODIR (0x0400) /* Default: Overwrite files, even if one on disk is newer. */ #define ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER (0x0800) /* Detect blocks of 0 and write holes instead. */ #define ARCHIVE_EXTRACT_SPARSE (0x1000) /* Default: Do not restore Mac extended metadata. */ /* This has no effect except on Mac OS. */ #define ARCHIVE_EXTRACT_MAC_METADATA (0x2000) /* Default: Use HFS+ compression if it was compressed. */ /* This has no effect except on Mac OS v10.6 or later. */ #define ARCHIVE_EXTRACT_NO_HFS_COMPRESSION (0x4000) /* 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); __LA_DECL int archive_read_extract2(struct archive *, struct archive_entry *, struct archive * /* dest */); __LA_DECL void archive_read_extract_set_progress_callback(struct archive *, void (*_progress_func)(void *), void *_user_data); /* 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); /* Close the file and release most resources. */ __LA_DECL int archive_read_close(struct archive *); /* Release all resources and destroy the object. */ /* Note that archive_read_free will call archive_read_close for you. */ __LA_DECL int archive_read_free(struct archive *); #if ARCHIVE_VERSION_NUMBER < 4000000 /* Synonym for archive_read_free() for backwards compatibility. */ __LA_DECL int archive_read_finish(struct archive *) __LA_DEPRECATED; #endif /*- * To create an archive: * 1) Ask archive_write_new for an archive writer object. * 2) Set any global properties. In particular, you should set * the compression and format to use. * 3) Call archive_write_open to open the file (most people * will use archive_write_open_file or archive_write_open_fd, * which provide convenient canned I/O callbacks for you). * 4) For each entry: * - construct an appropriate struct archive_entry structure * - archive_write_header to write the header * - archive_write_data to write the entry data * 5) archive_write_close to close the output * 6) archive_write_free to cleanup the writer and release resources */ __LA_DECL struct archive *archive_write_new(void); __LA_DECL int archive_write_set_bytes_per_block(struct archive *, int bytes_per_block); __LA_DECL int archive_write_get_bytes_per_block(struct archive *); /* XXX This is badly misnamed; suggestions appreciated. XXX */ __LA_DECL int archive_write_set_bytes_in_last_block(struct archive *, int bytes_in_last_block); __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); #if ARCHIVE_VERSION_NUMBER < 4000000 __LA_DECL int archive_write_set_compression_bzip2(struct archive *) __LA_DEPRECATED; __LA_DECL int archive_write_set_compression_compress(struct archive *) __LA_DEPRECATED; __LA_DECL int archive_write_set_compression_gzip(struct archive *) __LA_DEPRECATED; __LA_DECL int archive_write_set_compression_lzip(struct archive *) __LA_DEPRECATED; __LA_DECL int archive_write_set_compression_lzma(struct archive *) __LA_DEPRECATED; __LA_DECL int archive_write_set_compression_none(struct archive *) __LA_DEPRECATED; __LA_DECL int archive_write_set_compression_program(struct archive *, const char *cmd) __LA_DEPRECATED; __LA_DECL int archive_write_set_compression_xz(struct archive *) __LA_DEPRECATED; #endif /* A convenience function to set the filter based on the code. */ __LA_DECL int archive_write_add_filter(struct archive *, int filter_code); __LA_DECL int archive_write_add_filter_by_name(struct archive *, const char *name); __LA_DECL int archive_write_add_filter_b64encode(struct archive *); __LA_DECL int archive_write_add_filter_bzip2(struct archive *); __LA_DECL int archive_write_add_filter_compress(struct archive *); __LA_DECL int archive_write_add_filter_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 *); __LA_DECL int archive_write_add_filter_none(struct archive *); __LA_DECL int archive_write_add_filter_program(struct archive *, const char *cmd); __LA_DECL int archive_write_add_filter_uuencode(struct archive *); __LA_DECL int archive_write_add_filter_xz(struct archive *); /* A convenience function to set the format based on the code or name. */ __LA_DECL int archive_write_set_format(struct archive *, int format_code); __LA_DECL int archive_write_set_format_by_name(struct archive *, const char *name); /* To minimize link pollution, use one or more of the following. */ __LA_DECL int archive_write_set_format_7zip(struct archive *); __LA_DECL int archive_write_set_format_ar_bsd(struct archive *); __LA_DECL int archive_write_set_format_ar_svr4(struct archive *); __LA_DECL int archive_write_set_format_cpio(struct archive *); __LA_DECL int archive_write_set_format_cpio_newc(struct archive *); __LA_DECL int archive_write_set_format_gnutar(struct archive *); __LA_DECL int archive_write_set_format_iso9660(struct archive *); __LA_DECL int archive_write_set_format_mtree(struct archive *); __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 *, archive_open_callback *, archive_write_callback *, archive_close_callback *); __LA_DECL int archive_write_open_fd(struct archive *, int _fd); __LA_DECL int archive_write_open_filename(struct archive *, const char *_file); __LA_DECL int archive_write_open_filename_w(struct archive *, const wchar_t *_file); /* A deprecated synonym for archive_write_open_filename() */ __LA_DECL int archive_write_open_file(struct archive *, const char *_file) __LA_DEPRECATED; __LA_DECL int archive_write_open_FILE(struct archive *, FILE *); /* _buffSize is the size of the buffer, _used refers to a variable that * will be updated after each write into the buffer. */ __LA_DECL int archive_write_open_memory(struct archive *, void *_buffer, size_t _buffSize, size_t *_used); /* * Note that the library will truncate writes beyond the size provided * to archive_write_header or pad if the provided data is short. */ __LA_DECL int archive_write_header(struct archive *, struct archive_entry *); __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 int archive_write_finish_entry(struct archive *); __LA_DECL int archive_write_close(struct archive *); /* Marks the archive as FATAL so that a subsequent free() operation * won't try to close() cleanly. Provides a fast abort capability * when the client discovers that things have gone wrong. */ __LA_DECL int archive_write_fail(struct archive *); /* This can fail if the archive wasn't already closed, in which case * archive_write_free() will implicitly call archive_write_close(). */ __LA_DECL int archive_write_free(struct archive *); #if ARCHIVE_VERSION_NUMBER < 4000000 /* Synonym for archive_write_free() for backwards compatibility. */ __LA_DECL int archive_write_finish(struct archive *) __LA_DEPRECATED; #endif /* * Set write options. */ /* Apply option to the format only. */ __LA_DECL int archive_write_set_format_option(struct archive *_a, const char *m, const char *o, const char *v); /* Apply option to the filter only. */ __LA_DECL int archive_write_set_filter_option(struct archive *_a, const char *m, const char *o, const char *v); /* Apply option to both the format and the filter. */ __LA_DECL int archive_write_set_option(struct archive *_a, const char *m, const char *o, const char *v); /* Apply option string to both the format and the filter. */ __LA_DECL int archive_write_set_options(struct archive *_a, const char *opts); /* * 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 * * To create objects on disk: * 1) Ask archive_write_disk_new for a new archive_write_disk object. * 2) Set any global properties. In particular, you probably * want to set the options. * 3) For each entry: * - construct an appropriate struct archive_entry structure * - archive_write_header to create the file/dir/etc on disk * - archive_write_data to write the entry data * 4) archive_write_free to cleanup the writer and release resources * * In particular, you can use this in conjunction with archive_read() * to pull entries out of an archive and create them on disk. */ __LA_DECL struct archive *archive_write_disk_new(void); /* This file will not be overwritten. */ __LA_DECL int archive_write_disk_set_skip_file(struct archive *, 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 *, int flags); /* * The lookup functions are given uname/uid (or gname/gid) pairs and * return a uid (gid) suitable for this system. These are used for * restoring ownership and for setting ACLs. The default functions * are naive, they just return the uid/gid. These are small, so reasonable * for applications that don't need to preserve ownership; they * are probably also appropriate for applications that are doing * same-system backup and restore. */ /* * The "standard" lookup functions use common system calls to lookup * the uname/gname, falling back to the uid/gid if the names can't be * found. They cache lookups and are reasonably fast, but can be very * large, so they are not used unless you ask for them. In * particular, these match the specifications of POSIX "pax" and old * POSIX "tar". */ __LA_DECL int archive_write_disk_set_standard_lookup(struct archive *); /* * If neither the default (naive) nor the standard (big) functions suit * your needs, you can write your own and register them. Be sure to * include a cleanup function if you have allocated private data. */ __LA_DECL int archive_write_disk_set_group_lookup(struct archive *, void * /* private_data */, la_int64_t (*)(void *, const char *, la_int64_t), void (* /* cleanup */)(void *)); __LA_DECL int archive_write_disk_set_user_lookup(struct archive *, void * /* private_data */, la_int64_t (*)(void *, const char *, la_int64_t), void (* /* cleanup */)(void *)); __LA_DECL la_int64_t archive_write_disk_gid(struct archive *, const char *, la_int64_t); __LA_DECL la_int64_t archive_write_disk_uid(struct archive *, const char *, la_int64_t); /* * ARCHIVE_READ_DISK API * * This is still evolving and somewhat experimental. */ __LA_DECL struct archive *archive_read_disk_new(void); /* The names for symlink modes here correspond to an old BSD * command-line argument convention: -L, -P, -H */ /* Follow all symlinks. */ __LA_DECL int archive_read_disk_set_symlink_logical(struct archive *); /* Follow no symlinks. */ __LA_DECL int archive_read_disk_set_symlink_physical(struct archive *); /* Follow symlink initially, then not. */ __LA_DECL int archive_read_disk_set_symlink_hybrid(struct archive *); /* TODO: Handle Linux stat32/stat64 ugliness. */ __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); /* "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), 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), void (* /* cleanup_fn */)(void *)); /* Start traversal. */ __LA_DECL int archive_read_disk_open(struct archive *, const char *); __LA_DECL int archive_read_disk_open_w(struct archive *, const wchar_t *); /* * Request that current entry be visited. If you invoke it on every * directory, you'll get a physical traversal. This is ignored if the * current entry isn't a directory or a link to a directory. So, if * you invoke this on every returned path, you'll get a full logical * traversal. */ __LA_DECL int archive_read_disk_descend(struct archive *); __LA_DECL int archive_read_disk_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. */ __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. * 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. */ #define ARCHIVE_READDISK_HONOR_NODUMP (0x0002) /* Default: Skip a mac resource fork file whose prefix is "._" because of * using copyfile. */ #define ARCHIVE_READDISK_MAC_COPYFILE (0x0004) /* Default: Traverse mount points. */ #define ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS (0x0008) /* Default: Xattrs are read from disk. */ #define ARCHIVE_READDISK_NO_XATTR (0x0010) __LA_DECL int archive_read_disk_set_behavior(struct archive *, int flags); /* * Set archive_match object that will be used in archive_read_disk to * know whether an entry should be skipped. The callback function * _excluded_func will be invoked when an entry is skipped by the result * of archive_match. */ __LA_DECL int archive_read_disk_set_matching(struct archive *, struct archive *_matching, void (*_excluded_func) (struct archive *, void *, struct archive_entry *), void *_client_data); __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: */ /* Number of filters in the current filter pipeline. */ /* Filter #0 is the one closest to the format, -1 is a synonym for the * last filter, which is always the pseudo-filter that wraps the * client callbacks. */ __LA_DECL int archive_filter_count(struct archive *); __LA_DECL la_int64_t archive_filter_bytes(struct archive *, int); __LA_DECL int archive_filter_code(struct archive *, int); __LA_DECL const char * archive_filter_name(struct archive *, int); #if ARCHIVE_VERSION_NUMBER < 4000000 /* These don't properly handle multiple filters, so are deprecated and * will eventually be removed. */ /* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, -1); */ __LA_DECL la_int64_t archive_position_compressed(struct archive *) __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_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 *) __LA_DEPRECATED; /* As of libarchive 3.0, this is an alias for archive_filter_code(a, 0); */ __LA_DECL int archive_compression(struct archive *) __LA_DEPRECATED; #endif __LA_DECL int archive_errno(struct archive *); __LA_DECL const char *archive_error_string(struct archive *); __LA_DECL const char *archive_format_name(struct archive *); __LA_DECL int archive_format(struct archive *); __LA_DECL void archive_clear_error(struct archive *); __LA_DECL void archive_set_error(struct archive *, int _err, const char *fmt, ...) __LA_PRINTF(3, 4); __LA_DECL void archive_copy_error(struct archive *dest, struct archive *src); __LA_DECL int archive_file_count(struct archive *); /* * ARCHIVE_MATCH API */ __LA_DECL struct archive *archive_match_new(void); __LA_DECL int archive_match_free(struct archive *); /* * Test if archive_entry is excluded. * This is a convenience function. This is the same as calling all * archive_match_path_excluded, archive_match_time_excluded * and archive_match_owner_excluded. */ __LA_DECL int archive_match_excluded(struct archive *, struct archive_entry *); /* * Test if pathname is excluded. The conditions are set by following functions. */ __LA_DECL int archive_match_path_excluded(struct archive *, struct archive_entry *); /* Add exclusion pathname pattern. */ __LA_DECL int archive_match_exclude_pattern(struct archive *, const char *); __LA_DECL int archive_match_exclude_pattern_w(struct archive *, const wchar_t *); /* Add exclusion pathname pattern from file. */ __LA_DECL int archive_match_exclude_pattern_from_file(struct archive *, const char *, int _nullSeparator); __LA_DECL int archive_match_exclude_pattern_from_file_w(struct archive *, const wchar_t *, int _nullSeparator); /* Add inclusion pathname pattern. */ __LA_DECL int archive_match_include_pattern(struct archive *, const char *); __LA_DECL int archive_match_include_pattern_w(struct archive *, const wchar_t *); /* Add inclusion pathname pattern from file. */ __LA_DECL int archive_match_include_pattern_from_file(struct archive *, const char *, int _nullSeparator); __LA_DECL int archive_match_include_pattern_from_file_w(struct archive *, const wchar_t *, int _nullSeparator); /* * How to get statistic information for inclusion patterns. */ /* Return the amount number of unmatched inclusion patterns. */ __LA_DECL int archive_match_path_unmatched_inclusions(struct archive *); /* Return the pattern of unmatched inclusion with ARCHIVE_OK. * Return ARCHIVE_EOF if there is no inclusion pattern. */ __LA_DECL int archive_match_path_unmatched_inclusions_next( struct archive *, const char **); __LA_DECL int archive_match_path_unmatched_inclusions_next_w( struct archive *, const wchar_t **); /* * Test if a file is excluded by its time stamp. * The conditions are set by following functions. */ __LA_DECL int archive_match_time_excluded(struct archive *, struct archive_entry *); /* * Flags to tell a matching type of time stamps. These are used for * following functinos. */ /* Time flag: mtime to be tested. */ #define ARCHIVE_MATCH_MTIME (0x0100) /* Time flag: ctime to be tested. */ #define ARCHIVE_MATCH_CTIME (0x0200) /* Comparison flag: Match the time if it is newer than. */ #define ARCHIVE_MATCH_NEWER (0x0001) /* Comparison flag: Match the time if it is older than. */ #define ARCHIVE_MATCH_OLDER (0x0002) /* Comparison flag: Match the time if it is equal to. */ #define ARCHIVE_MATCH_EQUAL (0x0010) /* Set inclusion time. */ __LA_DECL int archive_match_include_time(struct archive *, int _flag, time_t _sec, long _nsec); /* Set inclusion time by a date string. */ __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. */ __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 *, int _flag, const wchar_t *_pathname); /* Add exclusion entry. */ __LA_DECL int archive_match_exclude_entry(struct archive *, int _flag, struct archive_entry *); /* * Test if a file is excluded by its uid ,gid, uname or gname. * The conditions are set by following functions. */ __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_uname(struct archive *, const char *); __LA_DECL int archive_match_include_uname_w(struct archive *, const wchar_t *); __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 /* These are meaningless outside of this header. */ #undef __LA_DECL #endif /* !ARCHIVE_H_INCLUDED */ Index: vendor/libarchive/dist/libarchive/archive_entry.h =================================================================== --- vendor/libarchive/dist/libarchive/archive_entry.h (revision 302036) +++ vendor/libarchive/dist/libarchive/archive_entry.h (revision 302037) @@ -1,642 +1,642 @@ /*- * Copyright (c) 2003-2008 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: head/lib/libarchive/archive_entry.h 201096 2009-12-28 02:41:27Z kientzle $ */ #ifndef ARCHIVE_ENTRY_H_INCLUDED #define ARCHIVE_ENTRY_H_INCLUDED /* Note: Compiler will complain if this does not match archive.h! */ -#define ARCHIVE_VERSION_NUMBER 3002000 +#define ARCHIVE_VERSION_NUMBER 3002001 /* * Note: archive_entry.h is for use outside of libarchive; the * configuration headers (config.h, archive_platform.h, etc.) are * purely internal. Do NOT use HAVE_XXX configuration macros to * control the behavior of this header! If you must conditionalize, * use predefined compiler and/or platform macros. */ #include #include /* for wchar_t */ #include #if defined(_WIN32) && !defined(__CYGWIN__) #include #endif /* Get a suitable 64-bit integer type. */ #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 # if defined(_SCO_DS) || defined(__osf__) typedef long long la_int64_t; # else typedef int64_t la_int64_t; # endif # endif #endif /* Get a suitable definition for mode_t */ #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__) && !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 * libarchive source should ever define __LIBARCHIVE_BUILD. */ #if ((defined __WIN32__) || (defined _WIN32) || defined(__CYGWIN__)) && (!defined LIBARCHIVE_STATIC) # ifdef __LIBARCHIVE_BUILD # ifdef __GNUC__ # define __LA_DECL __attribute__((dllexport)) extern # else # define __LA_DECL __declspec(dllexport) # endif # else # ifdef __GNUC__ # define __LA_DECL # else # define __LA_DECL __declspec(dllimport) # endif # endif #else /* Static libraries on all platforms and shared libraries on non-Windows. */ # define __LA_DECL #endif #ifdef __cplusplus extern "C" { #endif /* * Description of an archive entry. * * You can think of this as "struct stat" with some text fields added in. * * TODO: Add "comment", "charset", and possibly other entries that are * supported by "pax interchange" format. However, GNU, ustar, cpio, * and other variants don't support these features, so they're not an * excruciatingly high priority right now. * * TODO: "pax interchange" format allows essentially arbitrary * key/value attributes to be attached to any entry. Supporting * such extensions may make this library useful for special * applications (e.g., a package manager could attach special * package-management attributes to each entry). */ struct archive; struct archive_entry; /* * File-type constants. These are returned from archive_entry_filetype() * and passed to archive_entry_set_filetype(). * * These values match S_XXX defines on every platform I've checked, * including Windows, AIX, Linux, Solaris, and BSD. They're * (re)defined here because platforms generally don't define the ones * they don't support. For example, Windows doesn't define S_IFLNK or * S_IFBLK. Instead of having a mass of conditional logic and system * checks to define any S_XXX values that aren't supported locally, * I've just defined a new set of such constants so that * libarchive-based applications can manipulate and identify archive * entries properly even if the hosting platform can't store them on * disk. * * These values are also used directly within some portable formats, * such as cpio. If you find a platform that varies from these, the * correct solution is to leave these alone and translate from these * portable values to platform-native values when entries are read from * or written to disk. */ /* * In libarchive 4.0, we can drop the casts here. * They're needed to work around Borland C's broken mode_t. */ #define AE_IFMT ((__LA_MODE_T)0170000) #define AE_IFREG ((__LA_MODE_T)0100000) #define AE_IFLNK ((__LA_MODE_T)0120000) #define AE_IFSOCK ((__LA_MODE_T)0140000) #define AE_IFCHR ((__LA_MODE_T)0020000) #define AE_IFBLK ((__LA_MODE_T)0060000) #define AE_IFDIR ((__LA_MODE_T)0040000) #define AE_IFIFO ((__LA_MODE_T)0010000) /* * Basic object manipulation */ __LA_DECL struct archive_entry *archive_entry_clear(struct archive_entry *); /* The 'clone' function does a deep copy; all of the strings are copied too. */ __LA_DECL struct archive_entry *archive_entry_clone(struct archive_entry *); __LA_DECL void archive_entry_free(struct archive_entry *); __LA_DECL struct archive_entry *archive_entry_new(void); /* * This form of archive_entry_new2() will pull character-set * conversion information from the specified archive handle. The * older archive_entry_new(void) form is equivalent to calling * archive_entry_new2(NULL) and will result in the use of an internal * default character-set conversion. */ __LA_DECL struct archive_entry *archive_entry_new2(struct archive *); /* * Retrieve fields from an archive_entry. * * There are a number of implicit conversions among these fields. For * example, if a regular string field is set and you read the _w wide * character field, the entry will implicitly convert narrow-to-wide * using the current locale. Similarly, dev values are automatically * updated when you write devmajor or devminor and vice versa. * * In addition, fields can be "set" or "unset." Unset string fields * return NULL, non-string fields have _is_set() functions to test * whether they've been set. You can "unset" a string field by * assigning NULL; non-string fields have _unset() functions to * unset them. * * Note: There is one ambiguity in the above; string fields will * also return NULL when implicit character set conversions fail. * This is usually what you want. */ __LA_DECL time_t archive_entry_atime(struct archive_entry *); __LA_DECL long archive_entry_atime_nsec(struct archive_entry *); __LA_DECL int archive_entry_atime_is_set(struct archive_entry *); __LA_DECL time_t archive_entry_birthtime(struct archive_entry *); __LA_DECL long archive_entry_birthtime_nsec(struct archive_entry *); __LA_DECL int archive_entry_birthtime_is_set(struct archive_entry *); __LA_DECL time_t archive_entry_ctime(struct archive_entry *); __LA_DECL long archive_entry_ctime_nsec(struct archive_entry *); __LA_DECL int archive_entry_ctime_is_set(struct archive_entry *); __LA_DECL dev_t archive_entry_dev(struct archive_entry *); __LA_DECL int archive_entry_dev_is_set(struct archive_entry *); __LA_DECL dev_t archive_entry_devmajor(struct archive_entry *); __LA_DECL dev_t archive_entry_devminor(struct archive_entry *); __LA_DECL __LA_MODE_T archive_entry_filetype(struct archive_entry *); __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 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 int archive_entry_ino_is_set(struct archive_entry *); __LA_DECL __LA_MODE_T archive_entry_mode(struct archive_entry *); __LA_DECL time_t archive_entry_mtime(struct archive_entry *); __LA_DECL long archive_entry_mtime_nsec(struct archive_entry *); __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 *); __LA_DECL dev_t archive_entry_rdevmajor(struct archive_entry *); __LA_DECL dev_t archive_entry_rdevminor(struct archive_entry *); __LA_DECL const char *archive_entry_sourcepath(struct archive_entry *); __LA_DECL const wchar_t *archive_entry_sourcepath_w(struct archive_entry *); __LA_DECL la_int64_t archive_entry_size(struct archive_entry *); __LA_DECL int archive_entry_size_is_set(struct archive_entry *); __LA_DECL const char *archive_entry_strmode(struct archive_entry *); __LA_DECL const char *archive_entry_symlink(struct archive_entry *); __LA_DECL const 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 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. * * Note: Before libarchive 2.4, there were 'set' and 'copy' versions * of the string setters. 'copy' copied the actual string, 'set' just * stored the pointer. In libarchive 2.4 and later, strings are * always copied. */ __LA_DECL void archive_entry_set_atime(struct archive_entry *, time_t, long); __LA_DECL void archive_entry_unset_atime(struct archive_entry *); #if defined(_WIN32) && !defined(__CYGWIN__) __LA_DECL void archive_entry_copy_bhfi(struct archive_entry *, BY_HANDLE_FILE_INFORMATION *); #endif __LA_DECL void archive_entry_set_birthtime(struct archive_entry *, time_t, long); __LA_DECL void archive_entry_unset_birthtime(struct archive_entry *); __LA_DECL void archive_entry_set_ctime(struct archive_entry *, time_t, long); __LA_DECL void archive_entry_unset_ctime(struct archive_entry *); __LA_DECL void archive_entry_set_dev(struct archive_entry *, dev_t); __LA_DECL void archive_entry_set_devmajor(struct archive_entry *, dev_t); __LA_DECL void archive_entry_set_devminor(struct archive_entry *, dev_t); __LA_DECL void archive_entry_set_filetype(struct archive_entry *, unsigned int); __LA_DECL void archive_entry_set_fflags(struct archive_entry *, unsigned long /* set */, unsigned long /* clear */); /* Returns pointer to start of first invalid token, or NULL if none. */ /* Note that all recognized tokens are processed, regardless. */ __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_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_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 *); __LA_DECL void archive_entry_set_mode(struct archive_entry *, __LA_MODE_T); __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 *); __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_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_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 * archive_entry object, but this created issues when trying to * manipulate archives on systems different than the ones they were * created on. * * TODO: On Linux and other LFS systems, provide both stat32 and * stat64 versions of these functions and all of the macro glue so * that archive_entry_stat is magically defined to * archive_entry_stat32 or archive_entry_stat64 as appropriate. */ __LA_DECL const struct stat *archive_entry_stat(struct archive_entry *); __LA_DECL void archive_entry_copy_stat(struct archive_entry *, const struct stat *); /* * Storage for Mac OS-specific AppleDouble metadata information. * Apple-format tar files store a separate binary blob containing * encoded metadata with ACL, extended attributes, etc. * This provides a place to store that blob. */ __LA_DECL const void * archive_entry_mac_metadata(struct archive_entry *, size_t *); __LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const void *, size_t); /* * ACL routines. This used to simply store and return text-format ACL * strings, but that proved insufficient for a number of reasons: * = clients need control over uname/uid and gname/gid mappings * = there are many different ACL text formats * = would like to be able to read/convert archives containing ACLs * on platforms that lack ACL libraries * * This last point, in particular, forces me to implement a reasonably * complete set of ACL support routines. */ /* * Permission bits. */ #define ARCHIVE_ENTRY_ACL_EXECUTE 0x00000001 #define ARCHIVE_ENTRY_ACL_WRITE 0x00000002 #define ARCHIVE_ENTRY_ACL_READ 0x00000004 #define ARCHIVE_ENTRY_ACL_READ_DATA 0x00000008 #define ARCHIVE_ENTRY_ACL_LIST_DIRECTORY 0x00000008 #define ARCHIVE_ENTRY_ACL_WRITE_DATA 0x00000010 #define ARCHIVE_ENTRY_ACL_ADD_FILE 0x00000010 #define ARCHIVE_ENTRY_ACL_APPEND_DATA 0x00000020 #define ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY 0x00000020 #define ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS 0x00000040 #define ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS 0x00000080 #define ARCHIVE_ENTRY_ACL_DELETE_CHILD 0x00000100 #define ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES 0x00000200 #define ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES 0x00000400 #define ARCHIVE_ENTRY_ACL_DELETE 0x00000800 #define ARCHIVE_ENTRY_ACL_READ_ACL 0x00001000 #define ARCHIVE_ENTRY_ACL_WRITE_ACL 0x00002000 #define ARCHIVE_ENTRY_ACL_WRITE_OWNER 0x00004000 #define ARCHIVE_ENTRY_ACL_SYNCHRONIZE 0x00008000 #define ARCHIVE_ENTRY_ACL_PERMS_POSIX1E \ (ARCHIVE_ENTRY_ACL_EXECUTE \ | ARCHIVE_ENTRY_ACL_WRITE \ | ARCHIVE_ENTRY_ACL_READ) #define ARCHIVE_ENTRY_ACL_PERMS_NFS4 \ (ARCHIVE_ENTRY_ACL_EXECUTE \ | ARCHIVE_ENTRY_ACL_READ_DATA \ | ARCHIVE_ENTRY_ACL_LIST_DIRECTORY \ | ARCHIVE_ENTRY_ACL_WRITE_DATA \ | ARCHIVE_ENTRY_ACL_ADD_FILE \ | ARCHIVE_ENTRY_ACL_APPEND_DATA \ | ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY \ | ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS \ | ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS \ | ARCHIVE_ENTRY_ACL_DELETE_CHILD \ | ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES \ | ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES \ | ARCHIVE_ENTRY_ACL_DELETE \ | ARCHIVE_ENTRY_ACL_READ_ACL \ | ARCHIVE_ENTRY_ACL_WRITE_ACL \ | ARCHIVE_ENTRY_ACL_WRITE_OWNER \ | ARCHIVE_ENTRY_ACL_SYNCHRONIZE) /* * Inheritance values (NFS4 ACLs only); included in permset. */ #define ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT 0x02000000 #define ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT 0x04000000 #define ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT 0x08000000 #define ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY 0x10000000 #define ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS 0x20000000 #define ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS 0x40000000 #define ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4 \ (ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT \ | ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT \ | ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT \ | ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY \ | ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS \ | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS) /* We need to be able to specify combinations of these. */ #define ARCHIVE_ENTRY_ACL_TYPE_ACCESS 256 /* POSIX.1e only */ #define ARCHIVE_ENTRY_ACL_TYPE_DEFAULT 512 /* POSIX.1e only */ #define ARCHIVE_ENTRY_ACL_TYPE_ALLOW 1024 /* NFS4 only */ #define ARCHIVE_ENTRY_ACL_TYPE_DENY 2048 /* NFS4 only */ #define ARCHIVE_ENTRY_ACL_TYPE_AUDIT 4096 /* NFS4 only */ #define ARCHIVE_ENTRY_ACL_TYPE_ALARM 8192 /* NFS4 only */ #define ARCHIVE_ENTRY_ACL_TYPE_POSIX1E (ARCHIVE_ENTRY_ACL_TYPE_ACCESS \ | ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) #define ARCHIVE_ENTRY_ACL_TYPE_NFS4 (ARCHIVE_ENTRY_ACL_TYPE_ALLOW \ | ARCHIVE_ENTRY_ACL_TYPE_DENY \ | ARCHIVE_ENTRY_ACL_TYPE_AUDIT \ | ARCHIVE_ENTRY_ACL_TYPE_ALARM) /* Tag values mimic POSIX.1e */ #define ARCHIVE_ENTRY_ACL_USER 10001 /* Specified user. */ #define ARCHIVE_ENTRY_ACL_USER_OBJ 10002 /* User who owns the file. */ #define ARCHIVE_ENTRY_ACL_GROUP 10003 /* Specified group. */ #define ARCHIVE_ENTRY_ACL_GROUP_OBJ 10004 /* Group who owns the file. */ #define ARCHIVE_ENTRY_ACL_MASK 10005 /* Modify group access (POSIX.1e only) */ #define ARCHIVE_ENTRY_ACL_OTHER 10006 /* Public (POSIX.1e only) */ #define ARCHIVE_ENTRY_ACL_EVERYONE 10107 /* Everyone (NFS4 only) */ /* * Set the ACL by clearing it and adding entries one at a time. * Unlike the POSIX.1e ACL routines, you must specify the type * (access/default) for each entry. Internally, the ACL data is just * a soup of entries. API calls here allow you to retrieve just the * entries of interest. This design (which goes against the spirit of * POSIX.1e) is useful for handling archive formats that combine * default and access information in a single ACL list. */ __LA_DECL void archive_entry_acl_clear(struct archive_entry *); __LA_DECL int archive_entry_acl_add_entry(struct archive_entry *, int /* type */, int /* permset */, int /* tag */, int /* qual */, const char * /* name */); __LA_DECL int archive_entry_acl_add_entry_w(struct archive_entry *, int /* type */, int /* permset */, int /* tag */, int /* qual */, const wchar_t * /* name */); /* * To retrieve the ACL, first "reset", then repeatedly ask for the * "next" entry. The want_type parameter allows you to request only * certain types of entries. */ __LA_DECL int archive_entry_acl_reset(struct archive_entry *, int /* want_type */); __LA_DECL int archive_entry_acl_next(struct archive_entry *, int /* want_type */, int * /* type */, int * /* permset */, int * /* tag */, int * /* qual */, const char ** /* name */); __LA_DECL int archive_entry_acl_next_w(struct archive_entry *, int /* want_type */, int * /* type */, int * /* permset */, int * /* tag */, int * /* qual */, const wchar_t ** /* name */); /* * Construct a text-format ACL. The flags argument is a bitmask that * can include any of the following: * * 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. */ #define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024 #define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048 __LA_DECL const wchar_t *archive_entry_acl_text_w(struct archive_entry *, int /* flags */); __LA_DECL const char *archive_entry_acl_text(struct archive_entry *, int /* flags */); /* Return a count of entries matching 'want_type' */ __LA_DECL int archive_entry_acl_count(struct archive_entry *, int /* want_type */); /* Return an opaque ACL object. */ /* There's not yet anything clients can actually do with this... */ struct archive_acl; __LA_DECL struct archive_acl *archive_entry_acl(struct archive_entry *); /* * extended attributes */ __LA_DECL void archive_entry_xattr_clear(struct archive_entry *); __LA_DECL void archive_entry_xattr_add_entry(struct archive_entry *, const char * /* name */, const void * /* value */, size_t /* size */); /* * To retrieve the xattr list, first "reset", then repeatedly ask for the * "next" entry. */ __LA_DECL int archive_entry_xattr_count(struct archive_entry *); __LA_DECL int archive_entry_xattr_reset(struct archive_entry *); __LA_DECL int archive_entry_xattr_next(struct archive_entry *, const char ** /* name */, const void ** /* value */, size_t *); /* * sparse */ __LA_DECL void archive_entry_sparse_clear(struct archive_entry *); __LA_DECL void archive_entry_sparse_add_entry(struct archive_entry *, la_int64_t /* offset */, la_int64_t /* length */); /* * To retrieve the xattr list, first "reset", then repeatedly ask for the * "next" entry. */ __LA_DECL int archive_entry_sparse_count(struct archive_entry *); __LA_DECL int archive_entry_sparse_reset(struct archive_entry *); __LA_DECL int archive_entry_sparse_next(struct archive_entry *, la_int64_t * /* offset */, la_int64_t * /* length */); /* * Utility to match up hardlinks. * * The 'struct archive_entry_linkresolver' is a cache of archive entries * for files with multiple links. Here's how to use it: * 1. Create a lookup object with archive_entry_linkresolver_new() * 2. Tell it the archive format you're using. * 3. Hand each archive_entry to archive_entry_linkify(). * That function will return 0, 1, or 2 entries that should * be written. * 4. Call archive_entry_linkify(resolver, NULL) until * no more entries are returned. * 5. Call archive_entry_linkresolver_free(resolver) to free resources. * * The entries returned have their hardlink and size fields updated * appropriately. If an entry is passed in that does not refer to * a file with multiple links, it is returned unchanged. The intention * is that you should be able to simply filter all entries through * this machine. * * To make things more efficient, be sure that each entry has a valid * nlinks value. The hardlink cache uses this to track when all links * have been found. If the nlinks value is zero, it will keep every * name in the cache indefinitely, which can use a lot of memory. * * Note that archive_entry_size() is reset to zero if the file * body should not be written to the archive. Pay attention! */ struct archive_entry_linkresolver; /* * There are three different strategies for marking hardlinks. * The descriptions below name them after the best-known * formats that rely on each strategy: * * "Old cpio" is the simplest, it always returns any entry unmodified. * As far as I know, only cpio formats use this. Old cpio archives * store every link with the full body; the onus is on the dearchiver * to detect and properly link the files as they are restored. * "tar" is also pretty simple; it caches a copy the first time it sees * any link. Subsequent appearances are modified to be hardlink * references to the first one without any body. Used by all tar * formats, although the newest tar formats permit the "old cpio" strategy * as well. This strategy is very simple for the dearchiver, * and reasonably straightforward for the archiver. * "new cpio" is trickier. It stores the body only with the last * occurrence. The complication is that we might not * see every link to a particular file in a single session, so * there's no easy way to know when we've seen the last occurrence. * The solution here is to queue one link until we see the next. * At the end of the session, you can enumerate any remaining * entries by calling archive_entry_linkify(NULL) and store those * bodies. If you have a file with three links l1, l2, and l3, * you'll get the following behavior if you see all three links: * linkify(l1) => NULL (the resolver stores l1 internally) * linkify(l2) => l1 (resolver stores l2, you write l1) * linkify(l3) => l2, l3 (all links seen, you can write both). * If you only see l1 and l2, you'll get this behavior: * linkify(l1) => NULL * linkify(l2) => l1 * linkify(NULL) => l2 (at end, you retrieve remaining links) * As the name suggests, this strategy is used by newer cpio variants. * It's noticeably more complex for the archiver, slightly more complex * for the dearchiver than the tar strategy, but makes it straightforward * to restore a file using any link by simply continuing to scan until * you see a link that is stored with a body. In contrast, the tar * strategy requires you to rescan the archive from the beginning to * correctly extract an arbitrary link. */ __LA_DECL struct archive_entry_linkresolver *archive_entry_linkresolver_new(void); __LA_DECL void archive_entry_linkresolver_set_strategy( struct archive_entry_linkresolver *, int /* format_code */); __LA_DECL void archive_entry_linkresolver_free(struct archive_entry_linkresolver *); __LA_DECL void archive_entry_linkify(struct archive_entry_linkresolver *, struct archive_entry **, struct archive_entry **); __LA_DECL struct archive_entry *archive_entry_partial_links( struct archive_entry_linkresolver *res, unsigned int *links); #ifdef __cplusplus } #endif /* This is meaningless outside of this header. */ #undef __LA_DECL #endif /* !ARCHIVE_ENTRY_H_INCLUDED */ Index: vendor/libarchive/dist/libarchive/archive_ppmd7.c =================================================================== --- vendor/libarchive/dist/libarchive/archive_ppmd7.c (revision 302036) +++ vendor/libarchive/dist/libarchive/archive_ppmd7.c (revision 302037) @@ -1,1163 +1,1168 @@ /* Ppmd7.c -- PPMdH codec 2010-03-12 : Igor Pavlov : Public domain This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ #include "archive_platform.h" #include #include "archive_ppmd7_private.h" #ifdef PPMD_32BIT #define Ppmd7_GetPtr(p, ptr) (ptr) #define Ppmd7_GetContext(p, ptr) (ptr) #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats) #else #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs))) #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs))) #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats))) #endif #define Ppmd7_GetBinSumm(p) \ &p->BinSumm[Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \ p->NS2BSIndx[Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \ (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \ 2 * p->HB2Flag[Ppmd7Context_OneState(p->MinContext)->Symbol] + \ ((p->RunLength >> 26) & 0x20)] #define kTopValue (1 << 24) #define MAX_FREQ 124 #define UNIT_SIZE 12 #define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) #define U2I(nu) (p->Units2Indx[(nu) - 1]) #define I2U(indx) (p->Indx2Units[indx]) #ifdef PPMD_32BIT #define REF(ptr) (ptr) #else #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) #endif #define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) #define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) #define STATS(ctx) Ppmd7_GetStats(p, ctx) #define ONE_STATE(ctx) Ppmd7Context_OneState(ctx) #define SUFFIX(ctx) CTX((ctx)->Suffix) static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; static const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; typedef CPpmd7_Context * CTX_PTR; struct CPpmd7_Node_; typedef #ifdef PPMD_32BIT struct CPpmd7_Node_ * #else UInt32 #endif CPpmd7_Node_Ref; typedef struct CPpmd7_Node_ { UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */ UInt16 NU; CPpmd7_Node_Ref Next; /* must be at offset >= 4 */ CPpmd7_Node_Ref Prev; } CPpmd7_Node; #ifdef PPMD_32BIT #define NODE(ptr) (ptr) #else #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs))) #endif static void Ppmd7_Update1(CPpmd7 *p); static void Ppmd7_Update1_0(CPpmd7 *p); static void Ppmd7_Update2(CPpmd7 *p); static void Ppmd7_UpdateBin(CPpmd7 *p); static CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale); /* ----------- Base ----------- */ static void Ppmd7_Construct(CPpmd7 *p) { unsigned i, k, m; p->Base = 0; for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) { unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); do { p->Units2Indx[k++] = (Byte)i; } while(--step); p->Indx2Units[i] = (Byte)k; } p->NS2BSIndx[0] = (0 << 1); p->NS2BSIndx[1] = (1 << 1); memset(p->NS2BSIndx + 2, (2 << 1), 9); memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); for (i = 0; i < 3; i++) p->NS2Indx[i] = (Byte)i; for (m = i, k = 1; i < 256; i++) { p->NS2Indx[i] = (Byte)m; if (--k == 0) k = (++m) - 2; } memset(p->HB2Flag, 0, 0x40); memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40); } static void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc) { alloc->Free(alloc, p->Base); p->Size = 0; p->Base = 0; } 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 (4 - size) & 3; #else 4 - (size & 3); #endif if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size #ifndef PPMD_32BIT + UNIT_SIZE #endif )) == 0) return False; p->Size = size; } return True; } static void InsertNode(CPpmd7 *p, void *node, unsigned indx) { *((CPpmd_Void_Ref *)node) = p->FreeList[indx]; p->FreeList[indx] = REF(node); } static void *RemoveNode(CPpmd7 *p, unsigned indx) { CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]); p->FreeList[indx] = *node; return node; } static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx) { unsigned i, nu = I2U(oldIndx) - I2U(newIndx); ptr = (Byte *)ptr + U2B(I2U(newIndx)); if (I2U(i = U2I(nu)) != nu) { unsigned k = I2U(--i); InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); } InsertNode(p, ptr, i); } static void GlueFreeBlocks(CPpmd7 *p) { #ifdef PPMD_32BIT CPpmd7_Node headItem; CPpmd7_Node_Ref head = &headItem; #else CPpmd7_Node_Ref head = p->AlignOffset + p->Size; #endif CPpmd7_Node_Ref n = head; unsigned i; p->GlueCount = 255; /* create doubly-linked list of free blocks */ for (i = 0; i < PPMD_NUM_INDEXES; i++) { UInt16 nu = I2U(i); CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i]; p->FreeList[i] = 0; while (next != 0) { CPpmd7_Node *node = NODE(next); node->Next = n; n = NODE(n)->Prev = next; next = *(const CPpmd7_Node_Ref *)node; node->Stamp = 0; node->NU = (UInt16)nu; } } NODE(head)->Stamp = 1; NODE(head)->Next = n; NODE(n)->Prev = head; if (p->LoUnit != p->HiUnit) ((CPpmd7_Node *)p->LoUnit)->Stamp = 1; /* Glue free blocks */ while (n != head) { CPpmd7_Node *node = NODE(n); UInt32 nu = (UInt32)node->NU; for (;;) { CPpmd7_Node *node2 = NODE(n) + nu; nu += node2->NU; if (node2->Stamp != 0 || nu >= 0x10000) break; NODE(node2->Prev)->Next = node2->Next; NODE(node2->Next)->Prev = node2->Prev; node->NU = (UInt16)nu; } n = node->Next; } /* Fill lists of free blocks */ for (n = NODE(head)->Next; n != head;) { CPpmd7_Node *node = NODE(n); unsigned nu; CPpmd7_Node_Ref next = node->Next; for (nu = node->NU; nu > 128; nu -= 128, node += 128) InsertNode(p, node, PPMD_NUM_INDEXES - 1); if (I2U(i = U2I(nu)) != nu) { unsigned k = I2U(--i); InsertNode(p, node + k, nu - k - 1); } InsertNode(p, node, i); n = next; } } static void *AllocUnitsRare(CPpmd7 *p, unsigned indx) { unsigned i; void *retVal; if (p->GlueCount == 0) { GlueFreeBlocks(p); if (p->FreeList[indx] != 0) return RemoveNode(p, indx); } i = indx; do { if (++i == PPMD_NUM_INDEXES) { UInt32 numBytes = U2B(I2U(indx)); p->GlueCount--; return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); } } while (p->FreeList[i] == 0); retVal = RemoveNode(p, i); SplitBlock(p, retVal, i, indx); return retVal; } static void *AllocUnits(CPpmd7 *p, unsigned indx) { UInt32 numBytes; if (p->FreeList[indx] != 0) return RemoveNode(p, indx); numBytes = U2B(I2U(indx)); if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) { void *retVal = p->LoUnit; p->LoUnit += numBytes; return retVal; } return AllocUnitsRare(p, indx); } #define MyMem12Cpy(dest, src, num) \ { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \ do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while(--n); } static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU) { unsigned i0 = U2I(oldNU); unsigned i1 = U2I(newNU); if (i0 == i1) return oldPtr; if (p->FreeList[i1] != 0) { void *ptr = RemoveNode(p, i1); MyMem12Cpy(ptr, oldPtr, newNU); InsertNode(p, oldPtr, i0); return ptr; } SplitBlock(p, oldPtr, i0, i1); return oldPtr; } #define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) { (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); } static void RestartModel(CPpmd7 *p) { unsigned i, k, m; memset(p->FreeList, 0, sizeof(p->FreeList)); p->Text = p->Base + p->AlignOffset; p->HiUnit = p->Text + p->Size; p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; p->GlueCount = 0; p->OrderFall = p->MaxOrder; p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; p->PrevSuccess = 0; p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ p->MinContext->Suffix = 0; p->MinContext->NumStats = 256; p->MinContext->SummFreq = 256 + 1; p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ p->LoUnit += U2B(256 / 2); p->MinContext->Stats = REF(p->FoundState); for (i = 0; i < 256; i++) { CPpmd_State *s = &p->FoundState[i]; s->Symbol = (Byte)i; s->Freq = 1; SetSuccessor(s, 0); } for (i = 0; i < 128; i++) for (k = 0; k < 8; k++) { UInt16 *dest = p->BinSumm[i] + k; UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2)); for (m = 0; m < 64; m += 8) dest[m] = val; } for (i = 0; i < 25; i++) for (k = 0; k < 16; k++) { CPpmd_See *s = &p->See[i][k]; s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4)); s->Count = 4; } } static void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder) { p->MaxOrder = maxOrder; RestartModel(p); p->DummySee.Shift = PPMD_PERIOD_BITS; p->DummySee.Summ = 0; /* unused */ p->DummySee.Count = 64; /* unused */ } static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip) { CPpmd_State upState; CTX_PTR c = p->MinContext; CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); CPpmd_State *ps[PPMD7_MAX_ORDER]; unsigned numPs = 0; if (!skip) ps[numPs++] = p->FoundState; while (c->Suffix) { CPpmd_Void_Ref successor; CPpmd_State *s; c = SUFFIX(c); if (c->NumStats != 1) { for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); } else s = ONE_STATE(c); successor = SUCCESSOR(s); if (successor != upBranch) { c = CTX(successor); if (numPs == 0) return c; break; } ps[numPs++] = s; } upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch); SetSuccessor(&upState, upBranch + 1); if (c->NumStats == 1) upState.Freq = ONE_STATE(c)->Freq; else { UInt32 cf, s0; CPpmd_State *s; for (s = STATS(c); s->Symbol != upState.Symbol; s++); cf = s->Freq - 1; s0 = c->SummFreq - c->NumStats - cf; upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0)))); } while (numPs != 0) { /* Create Child */ CTX_PTR c1; /* = AllocContext(p); */ if (p->HiUnit != p->LoUnit) c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); else if (p->FreeList[0] != 0) c1 = (CTX_PTR)RemoveNode(p, 0); else { c1 = (CTX_PTR)AllocUnitsRare(p, 0); if (!c1) return NULL; } c1->NumStats = 1; *ONE_STATE(c1) = upState; c1->Suffix = REF(c); SetSuccessor(ps[--numPs], REF(c1)); c = c1; } return c; } static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) { CPpmd_State tmp = *t1; *t1 = *t2; *t2 = tmp; } static void UpdateModel(CPpmd7 *p) { CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); CTX_PTR c; unsigned s0, ns; if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) { c = SUFFIX(p->MinContext); if (c->NumStats == 1) { CPpmd_State *s = ONE_STATE(c); if (s->Freq < 32) s->Freq++; } else { CPpmd_State *s = STATS(c); if (s->Symbol != p->FoundState->Symbol) { do { s++; } while (s->Symbol != p->FoundState->Symbol); if (s[0].Freq >= s[-1].Freq) { SwapStates(&s[0], &s[-1]); s--; } } if (s->Freq < MAX_FREQ - 9) { s->Freq += 2; c->SummFreq += 2; } } } if (p->OrderFall == 0) { p->MinContext = p->MaxContext = CreateSuccessors(p, True); if (p->MinContext == 0) { RestartModel(p); return; } SetSuccessor(p->FoundState, REF(p->MinContext)); return; } *p->Text++ = p->FoundState->Symbol; successor = REF(p->Text); if (p->Text >= p->UnitsStart) { RestartModel(p); return; } if (fSuccessor) { if (fSuccessor <= successor) { CTX_PTR cs = CreateSuccessors(p, False); if (cs == NULL) { RestartModel(p); return; } fSuccessor = REF(cs); } if (--p->OrderFall == 0) { successor = fSuccessor; p->Text -= (p->MaxContext != p->MinContext); } } else { SetSuccessor(p->FoundState, successor); fSuccessor = REF(p->MinContext); } s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1); for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c)) { unsigned ns1; UInt32 cf, sf; if ((ns1 = c->NumStats) != 1) { if ((ns1 & 1) == 0) { /* Expand for one UNIT */ unsigned oldNU = ns1 >> 1; unsigned i = U2I(oldNU); if (i != U2I(oldNU + 1)) { void *ptr = AllocUnits(p, i + 1); void *oldPtr; if (!ptr) { RestartModel(p); return; } oldPtr = STATS(c); MyMem12Cpy(ptr, oldPtr, oldNU); InsertNode(p, oldPtr, i); c->Stats = STATS_REF(ptr); } } c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1))); } else { CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0); if (!s) { RestartModel(p); return; } *s = *ONE_STATE(c); c->Stats = REF(s); if (s->Freq < MAX_FREQ / 4 - 1) s->Freq <<= 1; else s->Freq = MAX_FREQ - 4; c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3)); } cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6); sf = (UInt32)s0 + c->SummFreq; if (cf < 6 * sf) { cf = 1 + (cf > sf) + (cf >= 4 * sf); c->SummFreq += 3; } else { cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf); c->SummFreq = (UInt16)(c->SummFreq + cf); } { CPpmd_State *s = STATS(c) + ns1; SetSuccessor(s, successor); s->Symbol = p->FoundState->Symbol; s->Freq = (Byte)cf; c->NumStats = (UInt16)(ns1 + 1); } } p->MaxContext = p->MinContext = CTX(fSuccessor); } static void Rescale(CPpmd7 *p) { unsigned i, adder, sumFreq, escFreq; CPpmd_State *stats = STATS(p->MinContext); CPpmd_State *s = p->FoundState; { CPpmd_State tmp = *s; for (; s != stats; s--) s[0] = s[-1]; *s = tmp; } escFreq = p->MinContext->SummFreq - s->Freq; s->Freq += 4; adder = (p->OrderFall != 0); s->Freq = (Byte)((s->Freq + adder) >> 1); sumFreq = s->Freq; i = p->MinContext->NumStats - 1; do { escFreq -= (++s)->Freq; s->Freq = (Byte)((s->Freq + adder) >> 1); sumFreq += s->Freq; if (s[0].Freq > s[-1].Freq) { CPpmd_State *s1 = s; CPpmd_State tmp = *s1; do s1[0] = s1[-1]; while (--s1 != stats && tmp.Freq > s1[-1].Freq); *s1 = tmp; } } while (--i); if (s->Freq == 0) { unsigned numStats = p->MinContext->NumStats; unsigned n0, n1; do { i++; } while ((--s)->Freq == 0); escFreq += i; p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i); if (p->MinContext->NumStats == 1) { CPpmd_State tmp = *stats; do { tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1)); escFreq >>= 1; } while (escFreq > 1); InsertNode(p, stats, U2I(((numStats + 1) >> 1))); *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; return; } n0 = (numStats + 1) >> 1; n1 = (p->MinContext->NumStats + 1) >> 1; if (n0 != n1) p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); } p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); p->FoundState = STATS(p->MinContext); } static CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq) { CPpmd_See *see; unsigned nonMasked = p->MinContext->NumStats - numMasked; if (p->MinContext->NumStats != 256) { see = p->See[p->NS2Indx[nonMasked - 1]] + (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) + 2 * (p->MinContext->SummFreq < 11 * p->MinContext->NumStats) + 4 * (numMasked > nonMasked) + p->HiBitsFlag; { unsigned r = (see->Summ >> see->Shift); see->Summ = (UInt16)(see->Summ - r); *escFreq = r + (r == 0); } } else { see = &p->DummySee; *escFreq = 1; } return see; } static void NextContext(CPpmd7 *p) { CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); if (p->OrderFall == 0 && (Byte *)c > p->Text) p->MinContext = p->MaxContext = c; else UpdateModel(p); } static void Ppmd7_Update1(CPpmd7 *p) { CPpmd_State *s = p->FoundState; s->Freq += 4; p->MinContext->SummFreq += 4; if (s[0].Freq > s[-1].Freq) { SwapStates(&s[0], &s[-1]); p->FoundState = --s; if (s->Freq > MAX_FREQ) Rescale(p); } NextContext(p); } static void Ppmd7_Update1_0(CPpmd7 *p) { p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq); p->RunLength += p->PrevSuccess; p->MinContext->SummFreq += 4; if ((p->FoundState->Freq += 4) > MAX_FREQ) Rescale(p); NextContext(p); } static void Ppmd7_UpdateBin(CPpmd7 *p) { p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0)); p->PrevSuccess = 1; p->RunLength++; NextContext(p); } static void Ppmd7_Update2(CPpmd7 *p) { p->MinContext->SummFreq += 4; if ((p->FoundState->Freq += 4) > MAX_FREQ) Rescale(p); p->RunLength = p->InitRL; UpdateModel(p); } /* ---------- Decode ---------- */ static Bool Ppmd_RangeDec_Init(CPpmd7z_RangeDec *p) { unsigned i; p->Low = p->Bottom = 0; p->Range = 0xFFFFFFFF; for (i = 0; i < 4; i++) p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); return (p->Code < 0xFFFFFFFF); } static Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p) { if (p->Stream->Read((void *)p->Stream) != 0) return False; return Ppmd_RangeDec_Init(p); } static Bool PpmdRAR_RangeDec_Init(CPpmd7z_RangeDec *p) { if (!Ppmd_RangeDec_Init(p)) return False; p->Bottom = 0x8000; return True; } static UInt32 Range_GetThreshold(void *pp, UInt32 total) { CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; return (p->Code - p->Low) / (p->Range /= total); } static void Range_Normalize(CPpmd7z_RangeDec *p) { while (1) { if((p->Low ^ (p->Low + p->Range)) >= kTopValue) { if(p->Range >= p->Bottom) break; else p->Range = ((uint32_t)(-(int32_t)p->Low)) & (p->Bottom - 1); } p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); p->Range <<= 8; p->Low <<= 8; } } static void Range_Decode_7z(void *pp, UInt32 start, UInt32 size) { CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; p->Code -= start * p->Range; p->Range *= size; Range_Normalize(p); } static void Range_Decode_RAR(void *pp, UInt32 start, UInt32 size) { CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; p->Low += start * p->Range; p->Range *= size; Range_Normalize(p); } static UInt32 Range_DecodeBit_7z(void *pp, UInt32 size0) { CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; UInt32 newBound = (p->Range >> 14) * size0; UInt32 symbol; if (p->Code < newBound) { symbol = 0; p->Range = newBound; } else { symbol = 1; p->Code -= newBound; p->Range -= newBound; } Range_Normalize(p); return symbol; } static UInt32 Range_DecodeBit_RAR(void *pp, UInt32 size0) { CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; UInt32 bit, value = p->p.GetThreshold(p, PPMD_BIN_SCALE); if(value < size0) { bit = 0; p->p.Decode(p, 0, size0); } else { bit = 1; p->p.Decode(p, size0, PPMD_BIN_SCALE - size0); } return bit; } static void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p) { p->p.GetThreshold = Range_GetThreshold; p->p.Decode = Range_Decode_7z; p->p.DecodeBit = Range_DecodeBit_7z; } static void PpmdRAR_RangeDec_CreateVTable(CPpmd7z_RangeDec *p) { p->p.GetThreshold = Range_GetThreshold; p->p.Decode = Range_Decode_RAR; p->p.DecodeBit = Range_DecodeBit_RAR; } #define MASK(sym) ((signed char *)charMask)[sym] static int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc) { size_t charMask[256 / sizeof(size_t)]; if (p->MinContext->NumStats != 1) { CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); unsigned i; UInt32 count, hiCnt; if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) { Byte symbol; rc->Decode(rc, 0, s->Freq); p->FoundState = s; symbol = s->Symbol; Ppmd7_Update1_0(p); return symbol; } p->PrevSuccess = 0; i = p->MinContext->NumStats - 1; do { if ((hiCnt += (++s)->Freq) > count) { Byte symbol; rc->Decode(rc, hiCnt - s->Freq, s->Freq); p->FoundState = s; symbol = s->Symbol; Ppmd7_Update1(p); return symbol; } } while (--i); if (count >= p->MinContext->SummFreq) return -2; p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]; rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt); PPMD_SetAllBitsIn256Bytes(charMask); MASK(s->Symbol) = 0; i = p->MinContext->NumStats - 1; do { MASK((--s)->Symbol) = 0; } while (--i); } else { UInt16 *prob = Ppmd7_GetBinSumm(p); if (rc->DecodeBit(rc, *prob) == 0) { Byte symbol; *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol; Ppmd7_UpdateBin(p); return symbol; } *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); p->InitEsc = PPMD7_kExpEscape[*prob >> 10]; PPMD_SetAllBitsIn256Bytes(charMask); MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0; p->PrevSuccess = 0; } for (;;) { CPpmd_State *ps[256], *s; UInt32 freqSum, count, hiCnt; CPpmd_See *see; unsigned i, num, numMasked = p->MinContext->NumStats; do { p->OrderFall++; if (!p->MinContext->Suffix) return -1; p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix); } while (p->MinContext->NumStats == numMasked); hiCnt = 0; s = Ppmd7_GetStats(p, p->MinContext); i = 0; num = p->MinContext->NumStats - numMasked; do { int k = (int)(MASK(s->Symbol)); hiCnt += (s->Freq & k); ps[i] = s++; i -= k; } while (i != num); see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum); freqSum += hiCnt; count = rc->GetThreshold(rc, freqSum); if (count < hiCnt) { Byte symbol; CPpmd_State **pps = ps; for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); s = *pps; rc->Decode(rc, hiCnt - s->Freq, s->Freq); Ppmd_See_Update(see); p->FoundState = s; symbol = s->Symbol; Ppmd7_Update2(p); return symbol; } if (count >= freqSum) return -2; rc->Decode(rc, hiCnt, freqSum - hiCnt); see->Summ = (UInt16)(see->Summ + freqSum); do { MASK(ps[--i]->Symbol) = 0; } while (i != 0); } } /* ---------- Encode ---------- Ppmd7Enc.c */ #define kTopValue (1 << 24) static void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p) { p->Low = 0; p->Range = 0xFFFFFFFF; p->Cache = 0; p->CacheSize = 1; } static void RangeEnc_ShiftLow(CPpmd7z_RangeEnc *p) { if ((UInt32)p->Low < (UInt32)0xFF000000 || (unsigned)(p->Low >> 32) != 0) { Byte temp = p->Cache; do { p->Stream->Write(p->Stream, (Byte)(temp + (Byte)(p->Low >> 32))); temp = 0xFF; } while(--p->CacheSize != 0); p->Cache = (Byte)((UInt32)p->Low >> 24); } p->CacheSize++; p->Low = ((UInt32)p->Low << 8) & 0xFFFFFFFF; } static void RangeEnc_Encode(CPpmd7z_RangeEnc *p, UInt32 start, UInt32 size, UInt32 total) { p->Low += start * (p->Range /= total); p->Range *= size; while (p->Range < kTopValue) { p->Range <<= 8; RangeEnc_ShiftLow(p); } } static void RangeEnc_EncodeBit_0(CPpmd7z_RangeEnc *p, UInt32 size0) { p->Range = (p->Range >> 14) * size0; while (p->Range < kTopValue) { p->Range <<= 8; RangeEnc_ShiftLow(p); } } static void RangeEnc_EncodeBit_1(CPpmd7z_RangeEnc *p, UInt32 size0) { UInt32 newBound = (p->Range >> 14) * size0; p->Low += newBound; p->Range -= newBound; while (p->Range < kTopValue) { p->Range <<= 8; RangeEnc_ShiftLow(p); } } static void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p) { unsigned i; for (i = 0; i < 5; i++) RangeEnc_ShiftLow(p); } #define MASK(sym) ((signed char *)charMask)[sym] static void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol) { size_t charMask[256 / sizeof(size_t)]; if (p->MinContext->NumStats != 1) { CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); UInt32 sum; unsigned i; if (s->Symbol == symbol) { RangeEnc_Encode(rc, 0, s->Freq, p->MinContext->SummFreq); p->FoundState = s; Ppmd7_Update1_0(p); return; } p->PrevSuccess = 0; sum = s->Freq; i = p->MinContext->NumStats - 1; do { if ((++s)->Symbol == symbol) { RangeEnc_Encode(rc, sum, s->Freq, p->MinContext->SummFreq); p->FoundState = s; Ppmd7_Update1(p); return; } sum += s->Freq; } while (--i); p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]; PPMD_SetAllBitsIn256Bytes(charMask); MASK(s->Symbol) = 0; i = p->MinContext->NumStats - 1; do { MASK((--s)->Symbol) = 0; } while (--i); RangeEnc_Encode(rc, sum, p->MinContext->SummFreq - sum, p->MinContext->SummFreq); } else { UInt16 *prob = Ppmd7_GetBinSumm(p); CPpmd_State *s = Ppmd7Context_OneState(p->MinContext); if (s->Symbol == symbol) { RangeEnc_EncodeBit_0(rc, *prob); *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); p->FoundState = s; Ppmd7_UpdateBin(p); return; } else { RangeEnc_EncodeBit_1(rc, *prob); *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); p->InitEsc = PPMD7_kExpEscape[*prob >> 10]; PPMD_SetAllBitsIn256Bytes(charMask); MASK(s->Symbol) = 0; p->PrevSuccess = 0; } } for (;;) { UInt32 escFreq; CPpmd_See *see; CPpmd_State *s; UInt32 sum; unsigned i, numMasked = p->MinContext->NumStats; do { p->OrderFall++; if (!p->MinContext->Suffix) return; /* EndMarker (symbol = -1) */ p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix); } while (p->MinContext->NumStats == numMasked); see = Ppmd7_MakeEscFreq(p, numMasked, &escFreq); s = Ppmd7_GetStats(p, p->MinContext); sum = 0; i = p->MinContext->NumStats; do { int cur = s->Symbol; if (cur == symbol) { UInt32 low = sum; CPpmd_State *s1 = s; do { sum += (s->Freq & (int)(MASK(s->Symbol))); s++; } while (--i); RangeEnc_Encode(rc, low, s1->Freq, sum + escFreq); Ppmd_See_Update(see); p->FoundState = s1; Ppmd7_Update2(p); return; } sum += (s->Freq & (int)(MASK(cur))); MASK(cur) = 0; s++; } while (--i); RangeEnc_Encode(rc, sum, escFreq, sum + escFreq); see->Summ = (UInt16)(see->Summ + sum + escFreq); } } const IPpmd7 __archive_ppmd7_functions = { &Ppmd7_Construct, &Ppmd7_Alloc, &Ppmd7_Free, &Ppmd7_Init, &Ppmd7z_RangeDec_CreateVTable, &PpmdRAR_RangeDec_CreateVTable, &Ppmd7z_RangeDec_Init, &PpmdRAR_RangeDec_Init, &Ppmd7_DecodeSymbol, &Ppmd7z_RangeEnc_Init, &Ppmd7z_RangeEnc_FlushData, &Ppmd7_EncodeSymbol }; Index: vendor/libarchive/dist/libarchive/archive_read_support_format_7zip.c =================================================================== --- vendor/libarchive/dist/libarchive/archive_read_support_format_7zip.c (revision 302036) +++ vendor/libarchive/dist/libarchive/archive_read_support_format_7zip.c (revision 302037) @@ -1,3880 +1,3883 @@ /*- * 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 #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_BZLIB_H #include #endif #ifdef HAVE_LZMA_H #include #endif #ifdef HAVE_ZLIB_H #include #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_MAIN_ZIP 0x06F10101 /* Main Zip crypto algo */ #define _7Z_CRYPTO_RAR_29 0x06F10303 /* Rar29 AES-128 + (modified SHA-1) */ #define _7Z_CRYPTO_AES_256_SHA_256 0x06F10701 /* AES-256 + SHA-256 */ #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 #define kDummy 0x19 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]; /* Custom value that is non-zero if this archive contains encrypted entries. */ int has_encrypted_entries; }; /* Maximum entry size. This limitation prevents reading intentional * corrupted 7-zip files on assuming there are not so many entries in * the files. */ #define UMAX_ENTRY ARCHIVE_LITERAL_ULL(100000000) static int archive_read_format_7zip_has_encrypted_entries(struct archive_read *); static int archive_read_support_format_7zip_capabilities(struct archive_read *a); 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); } /* * Until enough data has been read, we cannot tell about * any encrypted entries yet. */ zip->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW; 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, archive_read_support_format_7zip_capabilities, archive_read_format_7zip_has_encrypted_entries); if (r != ARCHIVE_OK) free(zip); return (ARCHIVE_OK); } static int archive_read_support_format_7zip_capabilities(struct archive_read * a) { (void)a; /* UNUSED */ return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA | ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA); } static int archive_read_format_7zip_has_encrypted_entries(struct archive_read *_a) { if (_a && _a->format) { struct _7zip * zip = (struct _7zip *)_a->format->data; if (zip) { return zip->has_encrypted_entries; } } return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW; } 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; struct _7z_folder *folder = 0; uint64_t fidx = 0; /* * It should be sufficient to call archive_read_next_header() for * a reader to determine if an entry is encrypted or not. If the * encryption of an entry is only detectable when calling * archive_read_data(), so be it. We'll do the same check there * as well. */ if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) { zip->has_encrypted_entries = 0; } 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 || zip_entry == NULL) 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); } /* Figure out if the entry is encrypted by looking at the folder that is associated to the current 7zip entry. If the folder has a coder with a _7Z_CRYPTO codec then the folder is encrypted. Hence the entry must also be encrypted. */ if (zip_entry && zip_entry->folderIndex < zip->si.ci.numFolders) { folder = &(zip->si.ci.folders[zip_entry->folderIndex]); for (fidx=0; folder && fidxnumCoders; fidx++) { switch(folder->coders[fidx].codec) { case _7Z_CRYPTO_MAIN_ZIP: case _7Z_CRYPTO_RAR_29: case _7Z_CRYPTO_AES_256_SHA_256: { archive_entry_set_is_data_encrypted(entry, 1); zip->has_encrypted_entries = 1; break; } } } } /* Now that we've checked for encryption, if there were still no * encrypted entries found we can say for sure that there are none. */ if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) { zip->has_encrypted_entries = 0; } 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->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) { zip->has_encrypted_entries = 0; } 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 < 50010000 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 < 50010000 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 < 50010000 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); case _7Z_CRYPTO_MAIN_ZIP: case _7Z_CRYPTO_RAR_29: case _7Z_CRYPTO_AES_256_SHA_256: if (a->entry) { archive_entry_set_is_metadata_encrypted(a->entry, 1); archive_entry_set_is_data_encrypted(a->entry, 1); zip->has_encrypted_entries = 1; } archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Crypto codec not supported yet (ID: 0x%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 += ((uint64_t)(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 (UMAX_ENTRY < 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 (UMAX_ENTRY < f->coders[i].numInStreams) return (-1); if (parse_7zip_uint64( a, &(f->coders[i].numOutStreams)) < 0) return (-1); if (UMAX_ENTRY < 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 (UMAX_ENTRY < f->bindPairs[i].inIndex) return (-1); if (parse_7zip_uint64(a, &(f->bindPairs[i].outIndex)) < 0) return (-1); if (UMAX_ENTRY < 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 (UMAX_ENTRY < 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 (UMAX_ENTRY < 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 (UMAX_ENTRY < ci->dataStreamIndex) return (-1); if (ci->numFolders > 0) { archive_set_error(&a->archive, -1, "Malformed 7-Zip archive"); goto failed; } break; default: archive_set_error(&a->archive, -1, "Malformed 7-Zip archive"); goto failed; } 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 (UMAX_ENTRY < f[i].numUnpackStreams) return (-1); + if (unpack_streams > SIZE_MAX - UMAX_ENTRY) { + 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 (UMAX_ENTRY < 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; } case kDummy: if (ll == 0) 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 (UMAX_ENTRY < 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; zip->has_encrypted_entries = 0; 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++) { switch(folder->coders[i].codec) { case _7Z_CRYPTO_MAIN_ZIP: case _7Z_CRYPTO_RAR_29: case _7Z_CRYPTO_AES_256_SHA_256: { /* For entry that is associated with this folder, mark it as encrypted (data+metadata). */ zip->has_encrypted_entries = 1; if (a->entry) { archive_entry_set_is_data_encrypted(a->entry, 1); archive_entry_set_is_metadata_encrypted(a->entry, 1); } archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC, "The %s is encrypted, " "but currently not supported", cname); return (ARCHIVE_FATAL); } case _7Z_X86_BCJ2: { found_bcj2++; break; } } } /* Now that we've checked for encryption, if there were still no * encrypted entries found we can say for sure that there are none. */ if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) { zip->has_encrypted_entries = 0; } 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); } Index: vendor/libarchive/dist/libarchive/archive_read_support_format_iso9660.c =================================================================== --- vendor/libarchive/dist/libarchive/archive_read_support_format_iso9660.c (revision 302036) +++ vendor/libarchive/dist/libarchive/archive_read_support_format_iso9660.c (revision 302037) @@ -1,3263 +1,3263 @@ /*- * Copyright (c) 2003-2007 Tim Kientzle * Copyright (c) 2009 Andreas Henriksson * 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 #endif /* #include */ /* See archive_platform.h */ #include #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #include #ifdef HAVE_ZLIB_H #include #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 *, int); 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, NULL, NULL); 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 = LOGICAL_BLOCK_SIZE * (int64_t)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 = LOGICAL_BLOCK_SIZE * (int64_t)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"); return (ARCHIVE_FATAL); } 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 { const char *path = build_pathname(&iso9660->pathname, file, 0); if (path == NULL) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Pathname is too long"); return (ARCHIVE_FATAL); } else { archive_string_empty(&iso9660->pathname); archive_entry_set_pathname(entry, path); } } 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, *filep; size_t name_len; const unsigned char *rr_start, *rr_end; const unsigned char *p; size_t dr_len; uint64_t fsize, offset; 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); } /* Sanity check that this entry does not create a cycle. */ offset = iso9660->logical_block_size * (uint64_t)location; for (filep = parent; filep != NULL; filep = filep->parent) { if (filep->offset == offset) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Directory structure contains loop"); 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 = offset; 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. * * 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, int depth) { // Plain ISO9660 only allows 8 dir levels; if we get // to 1000, then something is very, very wrong. if (depth > 1000) { return NULL; } if (file->parent != NULL && archive_strlen(&file->parent->name) > 0) { if (build_pathname(as, file->parent, depth + 1) == NULL) { return NULL; } 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 Index: vendor/libarchive/dist/libarchive/archive_read_support_format_rar.c =================================================================== --- vendor/libarchive/dist/libarchive/archive_read_support_format_rar.c (revision 302036) +++ vendor/libarchive/dist/libarchive/archive_read_support_format_rar.c (revision 302037) @@ -1,2944 +1,2954 @@ /*- * 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 #endif #include #include #ifdef HAVE_ZLIB_H #include /* 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 numallocatedentries; 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_save_size; 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; /* * Custom field to denote that this archive contains encrypted entries */ int has_encrypted_entries; }; static int archive_read_support_format_rar_capabilities(struct archive_read *); static int archive_read_format_rar_has_encrypted_entries(struct archive_read *); 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)); /* * Until enough data has been read, we cannot tell about * any encrypted entries yet. */ rar->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW; 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, archive_read_support_format_rar_capabilities, archive_read_format_rar_has_encrypted_entries); if (r != ARCHIVE_OK) free(rar); return (r); } static int archive_read_support_format_rar_capabilities(struct archive_read * a) { (void)a; /* UNUSED */ return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA | ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA); } static int archive_read_format_rar_has_encrypted_entries(struct archive_read *_a) { if (_a && _a->format) { struct rar * rar = (struct rar *)_a->format->data; if (rar) { return rar->has_encrypted_entries; } } return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW; } 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; unsigned long crc32_expected; 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); /* * It should be sufficient to call archive_read_next_header() for * a reader to determine if an entry is encrypted or not. If the * encryption of an entry is only detectable when calling * archive_read_data(), so be it. We'll do the same check there * as well. */ if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) { rar->has_encrypted_entries = 0; } /* 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)); } /* Main header is password encrytped, so we cannot read any file names or any other info about files from the header. */ if (rar->main_flags & MHD_PASSWORD) { archive_entry_set_is_metadata_encrypted(entry, 1); archive_entry_set_is_data_encrypted(entry, 1); rar->has_encrypted_entries = 1; 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 too small"); return (ARCHIVE_FATAL); } if (flags & HD_ADD_SIZE_PRESENT) { if (skip < 7 + 4) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Invalid header size too small"); return (ARCHIVE_FATAL); } if ((h = __archive_read_ahead(a, skip, NULL)) == NULL) return (ARCHIVE_FATAL); p = h; skip += archive_le32dec(p + 7); } /* Skip over the 2-byte CRC at the beginning of the header. */ crc32_expected = archive_le16dec(p); __archive_read_consume(a, 2); skip -= 2; /* Skim the entire header and compute the CRC. */ crc32_val = 0; while (skip > 0) { size_t to_read = skip; ssize_t did_read; if (to_read > 32 * 1024) { to_read = 32 * 1024; } if ((h = __archive_read_ahead(a, to_read, &did_read)) == NULL) { return (ARCHIVE_FATAL); } p = h; crc32_val = crc32(crc32_val, (const unsigned char *)p, (unsigned)did_read); __archive_read_consume(a, did_read); skip -= did_read; } if ((crc32_val & 0xffff) != crc32_expected) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Header CRC error"); return (ARCHIVE_FATAL); } 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->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) { rar->has_encrypted_entries = 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; } *buff = NULL; if (rar->entry_eof || rar->offset_seek >= rar->unp_size) { *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 */ __archive_reset_read_data(&a->archive); 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_entry_set_is_data_encrypted(entry, 1); rar->has_encrypted_entries = 1; archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "RAR encryption support unavailable."); /* Since it is only the data part itself that is encrypted we can at least extract information about the currently processed entry and don't need to return ARCHIVE_FATAL here. */ /*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 && filename_size == rar->filename_save_size && !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); rar->filename_save_size = filename_size; /* 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 (rar->dictionary_size == 0) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Invalid zero dictionary size"); + return (ARCHIVE_FATAL); + } + 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; code->numentries = 0; code->numallocatedentries = 0; 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; if (code->numallocatedentries == code->numentries) { int new_num_entries = 256; if (code->numentries > 0) { new_num_entries = code->numentries * 2; } new_tree = realloc(code->tree, new_num_entries * sizeof(*code->tree)); if (new_tree == NULL) return (-1); code->tree = (struct huffman_tree_node *)new_tree; code->numallocatedentries = new_num_entries; } 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)) + if(windowoffs + length <= lzss_size(&rar->lzss)) { memcpy(&rar->unp_buffer[rar->unp_offset], &rar->lzss.window[windowoffs], length); - else - { + } else if (length <= lzss_size(&rar->lzss)) { 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 + } else { memcpy(&rar->unp_buffer[rar->unp_offset], &rar->lzss.window[windowoffs], length); + } + } else { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Bad RAR file data"); + return (ARCHIVE_FATAL); } 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->archive.read_data_is_posix_read && *avail > (ssize_t)a->archive.read_data_requested) *avail = a->archive.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; } Index: vendor/libarchive/dist/libarchive/test/CMakeLists.txt =================================================================== --- vendor/libarchive/dist/libarchive/test/CMakeLists.txt (revision 302036) +++ vendor/libarchive/dist/libarchive/test/CMakeLists.txt (revision 302037) @@ -1,300 +1,301 @@ ############################################ # # How to build libarchive_test # ############################################ IF(ENABLE_TEST) SET(libarchive_test_SOURCES ../../test_utils/test_utils.c main.c read_open_memory.c test.h test_acl_freebsd_nfs4.c test_acl_freebsd_posix1e.c test_acl_nfs4.c test_acl_pax.c test_acl_posix1e.c test_archive_api_feature.c test_archive_clear_error.c test_archive_cmdline.c test_archive_digest.c test_archive_getdate.c test_archive_match_owner.c test_archive_match_path.c test_archive_match_time.c test_archive_pathmatch.c test_archive_read_add_passphrase.c test_archive_read_close_twice.c test_archive_read_close_twice_open_fd.c test_archive_read_close_twice_open_filename.c test_archive_read_multiple_data_objects.c test_archive_read_next_header_empty.c test_archive_read_next_header_raw.c test_archive_read_open2.c test_archive_read_set_filter_option.c test_archive_read_set_format_option.c test_archive_read_set_option.c test_archive_read_set_options.c test_archive_read_support.c test_archive_set_error.c test_archive_string.c test_archive_string_conversion.c test_archive_write_add_filter_by_name.c test_archive_write_set_filter_option.c test_archive_write_set_format_by_name.c test_archive_write_set_format_filter_by_ext.c test_archive_write_set_format_option.c test_archive_write_set_option.c test_archive_write_set_options.c test_archive_write_set_passphrase.c test_bad_fd.c test_compat_bzip2.c test_compat_cpio.c test_compat_gtar.c test_compat_gzip.c test_compat_lz4.c test_compat_lzip.c test_compat_lzma.c test_compat_lzop.c test_compat_mac.c test_compat_pax_libarchive_2x.c test_compat_solaris_pax_sparse.c test_compat_solaris_tar_acl.c test_compat_tar_hardlink.c test_compat_uudecode.c test_compat_uudecode_large.c test_compat_xz.c test_compat_zip.c test_empty_write.c test_entry.c test_entry_strmode.c test_extattr_freebsd.c test_filter_count.c test_fuzz.c test_gnutar_filename_encoding.c test_link_resolver.c test_open_failure.c test_open_fd.c test_open_file.c test_open_filename.c test_pax_filename_encoding.c test_read_data_large.c test_read_disk.c test_read_disk_directory_traversals.c test_read_disk_entry_from_file.c test_read_extract.c test_read_file_nonexistent.c test_read_filter_compress.c test_read_filter_grzip.c test_read_filter_lrzip.c test_read_filter_lzop.c test_read_filter_lzop_multiple_parts.c test_read_filter_program.c test_read_filter_program_signature.c test_read_filter_uudecode.c test_read_format_7zip.c test_read_format_7zip_encryption_data.c test_read_format_7zip_encryption_header.c test_read_format_7zip_encryption_partially.c test_read_format_7zip_malformed.c test_read_format_ar.c test_read_format_cab.c test_read_format_cab_filename.c test_read_format_cpio_afio.c test_read_format_cpio_bin.c test_read_format_cpio_bin_Z.c test_read_format_cpio_bin_be.c test_read_format_cpio_bin_bz2.c test_read_format_cpio_bin_gz.c test_read_format_cpio_bin_le.c test_read_format_cpio_bin_lzip.c test_read_format_cpio_bin_lzma.c test_read_format_cpio_bin_xz.c test_read_format_cpio_filename.c test_read_format_cpio_odc.c test_read_format_cpio_svr4_bzip2_rpm.c test_read_format_cpio_svr4_gzip.c test_read_format_cpio_svr4_gzip_rpm.c test_read_format_cpio_svr4c_Z.c test_read_format_empty.c test_read_format_gtar_filename.c test_read_format_gtar_gz.c test_read_format_gtar_lzma.c test_read_format_gtar_sparse.c test_read_format_gtar_sparse_skip_entry.c test_read_format_iso_Z.c test_read_format_iso_multi_extent.c test_read_format_iso_xorriso.c test_read_format_isojoliet_bz2.c test_read_format_isojoliet_long.c test_read_format_isojoliet_rr.c test_read_format_isojoliet_versioned.c test_read_format_isorr_bz2.c test_read_format_isorr_ce.c test_read_format_isorr_new_bz2.c test_read_format_isorr_rr_moved.c test_read_format_isozisofs_bz2.c test_read_format_lha.c test_read_format_lha_bugfix_0.c test_read_format_lha_filename.c test_read_format_mtree.c test_read_format_pax_bz2.c test_read_format_rar.c test_read_format_rar_encryption_data.c test_read_format_rar_encryption_header.c test_read_format_rar_encryption_partially.c + test_read_format_rar_invalid1.c test_read_format_raw.c test_read_format_tar.c test_read_format_tar_concatenated.c test_read_format_tar_empty_filename.c test_read_format_tar_empty_pax.c test_read_format_tar_filename.c test_read_format_tbz.c test_read_format_tgz.c test_read_format_tlz.c test_read_format_txz.c test_read_format_tz.c test_read_format_ustar_filename.c test_read_format_warc.c test_read_format_xar.c test_read_format_zip.c test_read_format_zip_comment_stored.c test_read_format_zip_encryption_data.c test_read_format_zip_encryption_header.c test_read_format_zip_encryption_partially.c test_read_format_zip_filename.c test_read_format_zip_mac_metadata.c test_read_format_zip_malformed.c test_read_format_zip_msdos.c test_read_format_zip_nested.c test_read_format_zip_nofiletype.c test_read_format_zip_padded.c test_read_format_zip_sfx.c test_read_format_zip_traditional_encryption_data.c test_read_format_zip_winzip_aes.c test_read_format_zip_winzip_aes_large.c test_read_format_zip_zip64.c test_read_large.c test_read_pax_truncated.c test_read_position.c test_read_set_format.c test_read_too_many_filters.c test_read_truncated.c test_read_truncated_filter.c test_sparse_basic.c test_tar_filenames.c test_tar_large.c test_ustar_filename_encoding.c test_ustar_filenames.c test_warn_missing_hardlink_target.c test_write_disk.c test_write_disk_appledouble.c test_write_disk_failures.c test_write_disk_hardlink.c test_write_disk_hfs_compression.c test_write_disk_lookup.c test_write_disk_mac_metadata.c test_write_disk_no_hfs_compression.c test_write_disk_perms.c test_write_disk_secure.c test_write_disk_sparse.c test_write_disk_symlink.c test_write_disk_times.c test_write_filter_b64encode.c test_write_filter_bzip2.c test_write_filter_compress.c test_write_filter_gzip.c test_write_filter_gzip_timestamp.c test_write_filter_lrzip.c test_write_filter_lz4.c test_write_filter_lzip.c test_write_filter_lzma.c test_write_filter_lzop.c test_write_filter_program.c test_write_filter_uuencode.c test_write_filter_xz.c test_write_format_7zip.c test_write_format_7zip_empty.c test_write_format_7zip_large.c test_write_format_ar.c test_write_format_cpio.c test_write_format_cpio_empty.c test_write_format_cpio_newc.c test_write_format_cpio_odc.c test_write_format_gnutar.c test_write_format_gnutar_filenames.c test_write_format_iso9660.c test_write_format_iso9660_boot.c test_write_format_iso9660_empty.c test_write_format_iso9660_filename.c test_write_format_iso9660_zisofs.c test_write_format_mtree.c test_write_format_mtree_absolute_path.c test_write_format_mtree_classic.c test_write_format_mtree_classic_indent.c test_write_format_mtree_fflags.c test_write_format_mtree_no_separator.c test_write_format_mtree_quoted_filename.c test_write_format_pax.c test_write_format_raw.c test_write_format_raw_b64.c test_write_format_shar_empty.c test_write_format_tar.c test_write_format_tar_empty.c test_write_format_tar_sparse.c test_write_format_tar_ustar.c test_write_format_tar_v7tar.c test_write_format_warc.c test_write_format_warc_empty.c test_write_format_xar.c test_write_format_xar_empty.c test_write_format_zip.c test_write_format_zip_compression_store.c test_write_format_zip_empty.c test_write_format_zip_empty_zip64.c test_write_format_zip_file.c test_write_format_zip_file_zip64.c test_write_format_zip_large.c test_write_format_zip_zip64.c test_write_open_memory.c test_write_read_format_zip.c test_zip_filename_encoding.c ) # # Register target # ADD_EXECUTABLE(libarchive_test ${libarchive_test_SOURCES}) TARGET_LINK_LIBRARIES(libarchive_test archive_static ${ADDITIONAL_LIBS}) SET_PROPERTY(TARGET libarchive_test PROPERTY COMPILE_DEFINITIONS LIBARCHIVE_STATIC LIST_H) # # Generate list.h by grepping DEFINE_TEST() lines out of the C sources. # GENERATE_LIST_H(${CMAKE_CURRENT_BINARY_DIR}/list.h ${CMAKE_CURRENT_LIST_FILE} ${libarchive_test_SOURCES}) SET_PROPERTY(DIRECTORY APPEND PROPERTY INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}) # list.h has a line DEFINE_TEST(testname) for every # test. We can use that to define the tests for cmake by # defining a DEFINE_TEST macro and reading list.h in. MACRO (DEFINE_TEST _testname) ADD_TEST( NAME libarchive_${_testname} COMMAND libarchive_test -vv -r ${CMAKE_CURRENT_SOURCE_DIR} ${_testname}) ENDMACRO (DEFINE_TEST _testname) INCLUDE(${CMAKE_CURRENT_BINARY_DIR}/list.h) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/test_utils) # Experimental new test handling ADD_CUSTOM_TARGET(run_libarchive_test COMMAND libarchive_test -r ${CMAKE_CURRENT_SOURCE_DIR}) ADD_DEPENDENCIES(run_all_tests run_libarchive_test) ENDIF(ENABLE_TEST) Index: vendor/libarchive/dist/libarchive/test/test_write_format_gnutar_filenames.c =================================================================== --- vendor/libarchive/dist/libarchive/test/test_write_format_gnutar_filenames.c (revision 302036) +++ vendor/libarchive/dist/libarchive/test/test_write_format_gnutar_filenames.c (revision 302037) @@ -1,145 +1,145 @@ /*- * Copyright (c) 2016 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 "test.h" __FBSDID("$FreeBSD$"); /* * Inspired by Github issue #682, which reported that gnutar filenames * of exactly 512 bytes weren't getting written correctly. * * This writes a filename of every length from 1 to 2000 bytes and * reads back to verify it. */ -static char filename[1024]; +static char filename[2048]; DEFINE_TEST(test_write_format_gnutar_filenames) { size_t buffsize = 1000000; char *buff; struct archive_entry *ae, *template; struct archive *a; size_t used; buff = malloc(buffsize); /* million bytes of work area */ assert(buff != NULL); /* Create a template entry. */ assert((template = archive_entry_new()) != NULL); archive_entry_set_atime(template, 2, 20); archive_entry_set_birthtime(template, 3, 30); archive_entry_set_ctime(template, 4, 40); archive_entry_set_mtime(template, 5, 50); archive_entry_set_mode(template, S_IFREG | 0755); archive_entry_set_size(template, 8); for (int i = 0; i < 2000; ++i) { filename[i] = 'a'; filename[i + 1] = '\0'; archive_entry_copy_pathname(template, filename); /* Write a one-item gnutar format archive. */ assert((a = archive_write_new()) != NULL); assertA(0 == archive_write_set_format_gnutar(a)); assertA(0 == archive_write_add_filter_none(a)); assertA(0 == archive_write_open_memory(a, buff, buffsize, &used)); assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, template)); assertEqualIntA(a, 8, archive_write_data(a, "12345678", 9)); assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a)); /* Read back and verify the filename. */ assert((a = archive_read_new()) != NULL); assertEqualIntA(a, 0, archive_read_support_format_all(a)); assertEqualIntA(a, 0, archive_read_support_filter_all(a)); assertEqualIntA(a, 0, archive_read_open_memory(a, buff, used)); assertEqualIntA(a, 0, archive_read_next_header(a, &ae)); assertEqualString(filename, archive_entry_pathname(ae)); assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a)); } archive_entry_free(template); free(buff); } DEFINE_TEST(test_write_format_gnutar_linknames) { size_t buffsize = 1000000; char *buff; struct archive_entry *ae, *template; struct archive *a; size_t used; buff = malloc(buffsize); /* million bytes of work area */ assert(buff != NULL); /* Create a template entry. */ assert((template = archive_entry_new()) != NULL); archive_entry_set_atime(template, 2, 20); archive_entry_set_birthtime(template, 3, 30); archive_entry_set_ctime(template, 4, 40); archive_entry_set_mtime(template, 5, 50); archive_entry_set_mode(template, S_IFLNK | 0755); archive_entry_copy_pathname(template, "link"); for (int i = 0; i < 2000; ++i) { filename[i] = 'a'; filename[i + 1] = '\0'; archive_entry_copy_symlink(template, filename); /* Write a one-item gnutar format archive. */ assert((a = archive_write_new()) != NULL); assertA(0 == archive_write_set_format_gnutar(a)); assertA(0 == archive_write_add_filter_none(a)); assertA(0 == archive_write_open_memory(a, buff, buffsize, &used)); assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, template)); assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a)); /* Read back and verify the filename. */ assert((a = archive_read_new()) != NULL); assertEqualIntA(a, 0, archive_read_support_format_all(a)); assertEqualIntA(a, 0, archive_read_support_filter_all(a)); assertEqualIntA(a, 0, archive_read_open_memory(a, buff, used)); assertEqualIntA(a, 0, archive_read_next_header(a, &ae)); assertEqualString("link", archive_entry_pathname(ae)); assertEqualString(filename, archive_entry_symlink(ae)); assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a)); } archive_entry_free(template); free(buff); }