aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Matuska <mm@FreeBSD.org>2026-07-30 08:13:34 +0000
committerMartin Matuska <mm@FreeBSD.org>2026-07-30 10:11:06 +0000
commit185becb1e1bd2657c156f78aeb52edac05ba5fb5 (patch)
tree90c54e5f3d1689efa9f267a4c10ec8a03577544d
parent5f02c8439786728392f250ff6fa772ce1787b74c (diff)
parent6d46c752afc81c22e51b47e020e2a898e9384afd (diff)
libarchive: merge from vendor branch
libarchive 3.8.9 ChangeLog: https://github.com/libarchive/libarchive/compare/v3.8.7...v3.8.9 Obtained from: libarchive Vendor commit: 27cbc7827172698143e440801fc0ba39ccb4f1f5 MFC after: 2 weeks
-rw-r--r--contrib/libarchive/FREEBSD-Xlist6
-rw-r--r--contrib/libarchive/NEWS4
-rw-r--r--contrib/libarchive/SECURITY.md19
-rwxr-xr-xcontrib/libarchive/build/ci/github_actions/install-macos-dependencies.sh22
-rw-r--r--contrib/libarchive/cpio/cpio.c10
-rw-r--r--contrib/libarchive/cpio/test/test_extract_cpio_absolute_paths.c1
-rw-r--r--contrib/libarchive/cpio/test/test_format_newc.c2
-rw-r--r--contrib/libarchive/libarchive/archive.h9
-rw-r--r--contrib/libarchive/libarchive/archive_acl.c457
-rw-r--r--contrib/libarchive/libarchive/archive_acl_private.h2
-rw-r--r--contrib/libarchive/libarchive/archive_check_magic.c1
-rw-r--r--contrib/libarchive/libarchive/archive_cmdline.c28
-rw-r--r--contrib/libarchive/libarchive/archive_crc32.h71
-rw-r--r--contrib/libarchive/libarchive/archive_cryptor.c4
-rw-r--r--contrib/libarchive/libarchive/archive_cryptor_private.h12
-rw-r--r--contrib/libarchive/libarchive/archive_digest.c69
-rw-r--r--contrib/libarchive/libarchive/archive_digest_private.h12
-rw-r--r--contrib/libarchive/libarchive/archive_endian.h41
-rw-r--r--contrib/libarchive/libarchive/archive_entry.c30
-rw-r--r--contrib/libarchive/libarchive/archive_entry.h4
-rw-r--r--contrib/libarchive/libarchive/archive_entry_link_resolver.c19
-rw-r--r--contrib/libarchive/libarchive/archive_entry_sparse.c5
-rw-r--r--contrib/libarchive/libarchive/archive_entry_strmode.c45
-rw-r--r--contrib/libarchive/libarchive/archive_entry_xattr.c10
-rw-r--r--contrib/libarchive/libarchive/archive_hmac.c2
-rw-r--r--contrib/libarchive/libarchive/archive_hmac_private.h2
-rw-r--r--contrib/libarchive/libarchive/archive_integer.h267
-rw-r--r--contrib/libarchive/libarchive/archive_match.c45
-rw-r--r--contrib/libarchive/libarchive/archive_options.c20
-rw-r--r--contrib/libarchive/libarchive/archive_pack_dev.c2
-rw-r--r--contrib/libarchive/libarchive/archive_parse_date.c72
-rw-r--r--contrib/libarchive/libarchive/archive_pathmatch.c54
-rw-r--r--contrib/libarchive/libarchive/archive_private.h26
-rw-r--r--contrib/libarchive/libarchive/archive_random.c26
-rw-r--r--contrib/libarchive/libarchive/archive_read.c452
-rw-r--r--contrib/libarchive/libarchive/archive_read_append_filter.c82
-rw-r--r--contrib/libarchive/libarchive/archive_read_data_into_fd.c98
-rw-r--r--contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c7
-rw-r--r--contrib/libarchive/libarchive/archive_read_disk_posix.c21
-rw-r--r--contrib/libarchive/libarchive/archive_read_disk_set_standard_lookup.c7
-rw-r--r--contrib/libarchive/libarchive/archive_read_filter.35
-rw-r--r--contrib/libarchive/libarchive/archive_read_open.316
-rw-r--r--contrib/libarchive/libarchive/archive_read_open_fd.c5
-rw-r--r--contrib/libarchive/libarchive/archive_read_open_file.c5
-rw-r--r--contrib/libarchive/libarchive/archive_read_open_filename.c7
-rw-r--r--contrib/libarchive/libarchive/archive_read_open_memory.c5
-rw-r--r--contrib/libarchive/libarchive/archive_read_private.h15
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_filter_all.c14
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_filter_bzip2.c149
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_filter_compress.c235
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_filter_grzip.c19
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_filter_gzip.c223
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_filter_lrzip.c20
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_filter_lz4.c432
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_filter_lzop.c225
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_filter_program.c183
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_filter_rpm.c247
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_filter_uu.c269
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_filter_xz.c299
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_filter_zstd.c186
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_format_7zip.c1374
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_format_all.c2
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_format_ar.c166
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_format_cab.c883
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_format_cpio.c167
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_format_iso9660.c228
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_format_lha.c145
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_format_mtree.c122
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_format_rar.c223
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_format_rar5.c1265
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_format_raw.c65
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_format_tar.c349
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_format_warc.c547
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_format_xar.c443
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_format_zip.c638
-rw-r--r--contrib/libarchive/libarchive/archive_string.c7
-rw-r--r--contrib/libarchive/libarchive/archive_time.c27
-rw-r--r--contrib/libarchive/libarchive/archive_util.335
-rw-r--r--contrib/libarchive/libarchive/archive_util.c68
-rw-r--r--contrib/libarchive/libarchive/archive_version_details.c27
-rw-r--r--contrib/libarchive/libarchive/archive_write.c115
-rw-r--r--contrib/libarchive/libarchive/archive_write_add_filter.c2
-rw-r--r--contrib/libarchive/libarchive/archive_write_add_filter_b64encode.c121
-rw-r--r--contrib/libarchive/libarchive/archive_write_add_filter_bzip2.c204
-rw-r--r--contrib/libarchive/libarchive/archive_write_add_filter_compress.c238
-rw-r--r--contrib/libarchive/libarchive/archive_write_add_filter_grzip.c68
-rw-r--r--contrib/libarchive/libarchive/archive_write_add_filter_gzip.c274
-rw-r--r--contrib/libarchive/libarchive/archive_write_add_filter_lrzip.c88
-rw-r--r--contrib/libarchive/libarchive/archive_write_add_filter_lz4.c486
-rw-r--r--contrib/libarchive/libarchive/archive_write_add_filter_lzop.c260
-rw-r--r--contrib/libarchive/libarchive/archive_write_add_filter_program.c81
-rw-r--r--contrib/libarchive/libarchive/archive_write_add_filter_uuencode.c123
-rw-r--r--contrib/libarchive/libarchive/archive_write_add_filter_xz.c276
-rw-r--r--contrib/libarchive/libarchive/archive_write_add_filter_zstd.c270
-rw-r--r--contrib/libarchive/libarchive/archive_write_disk_posix.c83
-rw-r--r--contrib/libarchive/libarchive/archive_write_disk_set_standard_lookup.c7
-rw-r--r--contrib/libarchive/libarchive/archive_write_filter.38
-rw-r--r--contrib/libarchive/libarchive/archive_write_format.34
-rw-r--r--contrib/libarchive/libarchive/archive_write_private.h4
-rw-r--r--contrib/libarchive/libarchive/archive_write_set_format_7zip.c64
-rw-r--r--contrib/libarchive/libarchive/archive_write_set_format_ar.c99
-rw-r--r--contrib/libarchive/libarchive/archive_write_set_format_cpio_binary.c52
-rw-r--r--contrib/libarchive/libarchive/archive_write_set_format_cpio_newc.c37
-rw-r--r--contrib/libarchive/libarchive/archive_write_set_format_cpio_odc.c52
-rw-r--r--contrib/libarchive/libarchive/archive_write_set_format_gnutar.c47
-rw-r--r--contrib/libarchive/libarchive/archive_write_set_format_iso9660.c180
-rw-r--r--contrib/libarchive/libarchive/archive_write_set_format_mtree.c139
-rw-r--r--contrib/libarchive/libarchive/archive_write_set_format_pax.c258
-rw-r--r--contrib/libarchive/libarchive/archive_write_set_format_raw.c8
-rw-r--r--contrib/libarchive/libarchive/archive_write_set_format_shar.c77
-rw-r--r--contrib/libarchive/libarchive/archive_write_set_format_ustar.c23
-rw-r--r--contrib/libarchive/libarchive/archive_write_set_format_v7tar.c23
-rw-r--r--contrib/libarchive/libarchive/archive_write_set_format_warc.c534
-rw-r--r--contrib/libarchive/libarchive/archive_write_set_format_xar.c275
-rw-r--r--contrib/libarchive/libarchive/archive_write_set_format_zip.c64
-rw-r--r--contrib/libarchive/libarchive/archive_write_set_options.328
-rw-r--r--contrib/libarchive/libarchive/libarchive-formats.52
-rw-r--r--contrib/libarchive/libarchive/test/read_open_memory.c8
-rw-r--r--contrib/libarchive/libarchive/test/test_acl_from_text_overread.c98
-rw-r--r--contrib/libarchive/libarchive/test/test_acl_nfs4_null_id_overflow.c105
-rw-r--r--contrib/libarchive/libarchive/test/test_acl_nfs4_text.c426
-rw-r--r--contrib/libarchive/libarchive/test/test_acl_posix1e_text.c530
-rw-r--r--contrib/libarchive/libarchive/test/test_archive_match_path.c16
-rw-r--r--contrib/libarchive/libarchive/test/test_archive_parse_date.c83
-rw-r--r--contrib/libarchive/libarchive/test/test_archive_pathmatch.c16
-rw-r--r--contrib/libarchive/libarchive/test/test_archive_pathmatch_oob.c156
-rw-r--r--contrib/libarchive/libarchive/test/test_archive_pathmatch_oob_bracket.bin.uu4
-rw-r--r--contrib/libarchive/libarchive/test/test_archive_pathmatch_oob_strchr.bin.uu8
-rw-r--r--contrib/libarchive/libarchive/test/test_archive_read_close_twice.c46
-rw-r--r--contrib/libarchive/libarchive/test/test_archive_read_set_option.c68
-rw-r--r--contrib/libarchive/libarchive/test/test_archive_read_set_options.c150
-rw-r--r--contrib/libarchive/libarchive/test/test_archive_seek_data_unsupported.c95
-rw-r--r--contrib/libarchive/libarchive/test/test_archive_string.c1
-rw-r--r--contrib/libarchive/libarchive/test/test_archive_string_conversion.c14
-rw-r--r--contrib/libarchive/libarchive/test/test_archive_string_conversion_overread.c87
-rw-r--r--contrib/libarchive/libarchive/test/test_archive_write_add_filter.c208
-rw-r--r--contrib/libarchive/libarchive/test/test_archive_write_add_filter_by_name.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_archive_write_set_format_by_name.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_archive_write_set_format_filter_by_ext.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_archive_write_set_format_option.c66
-rw-r--r--contrib/libarchive/libarchive/test/test_archive_write_set_option.c68
-rw-r--r--contrib/libarchive/libarchive/test/test_archive_write_set_options.c150
-rw-r--r--contrib/libarchive/libarchive/test/test_compat_bzip2.c1
-rw-r--r--contrib/libarchive/libarchive/test/test_compat_cpio.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_compat_gtar.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_compat_gtar_large.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_compat_gzip.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_compat_lz4.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_compat_lzip.c6
-rw-r--r--contrib/libarchive/libarchive/test/test_compat_lzma.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_compat_lzop.c6
-rw-r--r--contrib/libarchive/libarchive/test/test_compat_mac.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_compat_perl_archive_tar.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_compat_plexus_archiver_tar.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_compat_solaris_pax_sparse.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_compat_tar_directory.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_compat_tar_hardlink.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_compat_xz.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_compat_zip.c22
-rw-r--r--contrib/libarchive/libarchive/test/test_compat_zstd.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_entry.c28
-rw-r--r--contrib/libarchive/libarchive/test/test_fuzz.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_fuzz_consumer.h143
-rw-r--r--contrib/libarchive/libarchive/test/test_gnutar_filename_encoding.c59
-rw-r--r--contrib/libarchive/libarchive/test/test_open_filename.c23
-rw-r--r--contrib/libarchive/libarchive/test/test_pax_filename_encoding.c8
-rw-r--r--contrib/libarchive/libarchive/test/test_pax_xattr_header.c8
-rw-r--r--contrib/libarchive/libarchive/test/test_read_data_into_fd_size_exceeds_declared.c119
-rw-r--r--contrib/libarchive/libarchive/test/test_read_data_into_fd_size_exceeds_declared_deflate.zip.uu23
-rw-r--r--contrib/libarchive/libarchive/test/test_read_data_into_fd_size_exceeds_declared_stored.zip.uu9
-rw-r--r--contrib/libarchive/libarchive/test/test_read_data_large.c92
-rw-r--r--contrib/libarchive/libarchive/test/test_read_disk_directory_traversals.c38
-rw-r--r--contrib/libarchive/libarchive/test/test_read_files_compressed.c (renamed from contrib/libarchive/libarchive/test/test_archive_write_set_filter_option.c)42
-rw-r--r--contrib/libarchive/libarchive/test/test_read_files_compressed.part01.uu4
-rw-r--r--contrib/libarchive/libarchive/test/test_read_files_compressed.part02.uu4
-rw-r--r--contrib/libarchive/libarchive/test/test_read_filter_compress.c6
-rw-r--r--contrib/libarchive/libarchive/test/test_read_filter_grzip.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_filter_gzip_recursive.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_filter_lrzip.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_filter_lz4_raw.c (renamed from contrib/libarchive/libarchive/test/test_archive_read_set_filter_option.c)36
-rw-r--r--contrib/libarchive/libarchive/test/test_read_filter_lz4_raw_skip.uu4
-rw-r--r--contrib/libarchive/libarchive/test/test_read_filter_lzop.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_filter_lzop_multiple_parts.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_filter_program.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_filter_uudecode_raw.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_read_filter_zstd_raw.c (renamed from contrib/libarchive/libarchive/test/test_archive_read_close_twice_open_fd.c)28
-rw-r--r--contrib/libarchive/libarchive/test/test_read_filter_zstd_raw_loop.uu4
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_7zip.c112
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_7zip_archive_properties.7z.uu5
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_7zip_encryption_data.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_7zip_encryption_header.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_7zip_encryption_partially.c6
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_7zip_entries_oom.7z.uu8
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_7zip_entries_oom.c56
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_7zip_folders_oom.7z.uu8
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_7zip_folders_oom.c50
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_7zip_issue2765.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_7zip_malformed.c43
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_7zip_malformed4.7z.uu5
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_7zip_malformed_numfiles_oom.7z.uu5
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_7zip_packinfo_digests.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_7zip_sfx_boundary_elf.elf.uu22
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_7zip_sfx_boundary_pe.exe.uu22
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_cab.c6
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_cab_filename.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_cab_lzx_16bit.c52
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_cab_lzx_16bit.cab.uu6
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_cab_lzx_e8.c59
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_cab_lzx_e8.cab.uu6
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_cab_mszip_oob.c93
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_cab_multi.c72
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_cab_multi.p1.cab.uu15
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_cab_multi.p2.cab.uu8
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_cpio_afio.c26
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_cpio_afio_header.part1.cpio.uu5
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_cpio_afio_header.part2.cpio.uu4
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_cpio_bin_bz2.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_cpio_bin_gz.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_cpio_filename.c86
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_bzip2_rpm.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_gzip.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_gzip_rpm.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_cpio_symlink_trailer.c58
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_cpio_symlink_trailer.cpio.uu2919
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_gtar_filename.c18
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_gtar_gz.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_gtar_redundant_L.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_gtar_sparse.c54
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_gtar_sparse_reuse.tar.uu48
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_gtar_sparse_skip_entry.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_huge_rpm.c17
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_iso_joliet_utf16be_overflow.c61
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_iso_joliet_utf16be_overflow.iso.uu1278
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_iso_rockridge_ce_loop.iso.Z.uu61
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_iso_rockridge_zf_overflow.c77
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_iso_rockridge_zf_overflow.iso.uu1096
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_isojoliet_compress.c (renamed from contrib/libarchive/libarchive/test/test_read_format_isojoliet_bz2.c)6
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_isorr_ce_loop.c58
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_isorr_compress.c (renamed from contrib/libarchive/libarchive/test/test_read_format_isorr_bz2.c)6
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_isorr_new_compress.c (renamed from contrib/libarchive/libarchive/test/test_read_format_isorr_new_bz2.c)6
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_isozisofs_compress.c (renamed from contrib/libarchive/libarchive/test/test_read_format_isozisofs_bz2.c)4
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_lha.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_lha_bugfix_0.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_lha_filename.c6
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_lha_filename_utf16.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_lha_symlink_missing_target.c159
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_lha_symlink_missing_target.lzh.uu11
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_mtree.c91
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_pax_bz2.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_rar.c129
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_rar3_lowdist_reset.rar.uu16
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_rar5.c122
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_rar5_bad_filter.c130
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_rar5_bad_tables.c59
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_rar5_bad_tables.rar.uu8
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_rar5_block_hdr_fail_loop.c37
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_rar5_bytes_remaining_underflow.rar.uu5
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_rar5_main_block_extra_bytes.rar.uu6
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_rar5_skip_block_extra_bytes.rar.uu6
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_rar5_unpacked_size_exceeds_declared.rar.uu10
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_rar_encryption.c10
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_rar_encryption_data.c6
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_rar_encryption_header.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_rar_encryption_partially.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_rar_invalid1.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_rar_newsub_rr_over_1m.rar.uu23307
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_rar_overflow.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_rar_seek_data_cursor0.rar.uu164
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_rar_unbound_staticdata.rar.uu6
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_tar_acl_oob_read.c (renamed from contrib/libarchive/libarchive/test/test_archive_read_close_twice_open_filename.c)36
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_tar_acl_oob_read.tar.uu129
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_tar_concatenated.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_tar_empty_filename.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_tar_empty_pax.c69
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_tar_empty_with_gnulabel.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_tar_filename.c12
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_tar_mac_metadata.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_tar_pax_g_large.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_tar_pax_large_attr.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_tar_pax_negative_time.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_tar_pax_sun_holesdata.c76
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_tar_pax_sun_holesdata.tar.uu95
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_tar_pax_timestamps.c64
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_tar_pax_timestamps.tar.uu60
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_tar_timestamp_overflow.c55
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_tar_timestamp_overflow.tar.uu38
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_tgz.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_ustar_filename.c18
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_warc.c100
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_xar.c184
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_xar_atou64_overread.xar.uu7
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_xar_base64_oob.xar.uu7
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_xar_large_mode.xar.uu11
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_xar_parse_time_overread.xar.uu8
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip.c130
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_7075_utf8_paths.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_comment_stored.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_encryption_data.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_encryption_header.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_encryption_partially.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_filename.c40
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_jar.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_mac_metadata.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_malformed.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_nested.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_nofiletype.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_padded.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_pkware_unix.zip.uu7
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_ppmd8_aes256_streaming.zipx.uu16
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_sfx.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_size_exceeds_declared.c145
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_size_exceeds_declared_deflate.zip.uu23
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_size_exceeds_declared_stored.zip.uu9
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_symlink_unsupported_compression.c168
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_symlink_unsupported_compression.zip.uu16
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_traditional_encryption_data.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_uncompressed_size_off_by_4gib.c106
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_uncompressed_size_off_by_4gib.zip.uu7
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_winzip_aes.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_winzip_aes256_large_bzip2.zip.uu1616
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_winzip_aes256_large_lzma.zip.uu1893
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_winzip_aes256_large_ppmd.zip.uu1399
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_winzip_aes256_large_xz.zip.uu1898
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_winzip_aes256_large_zstd.zip.uu2053
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_winzip_aes_large.c276
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_with_invalid_traditional_eocd.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_zip64.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_zipx_encrypted.c268
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_zipx_lzma_oom.c63
-rw-r--r--contrib/libarchive/libarchive/test/test_read_format_zip_zipx_lzma_oom.zipx.uu4
-rw-r--r--contrib/libarchive/libarchive/test/test_read_pax_empty_val_no_nl.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_pax_xattr_rht_security_selinux.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_pax_xattr_schily.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_read_set_format.c170
-rw-r--r--contrib/libarchive/libarchive/test/test_sparse_basic.c43
-rw-r--r--contrib/libarchive/libarchive/test/test_ustar_filename_encoding.c10
-rw-r--r--contrib/libarchive/libarchive/test/test_write_disk_appledouble.c6
-rw-r--r--contrib/libarchive/libarchive/test/test_write_disk_hfs_compression.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_write_disk_mac_metadata.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_write_disk_no_hfs_compression.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_write_disk_secure.c292
-rw-r--r--contrib/libarchive/libarchive/test/test_write_disk_secure744.c11
-rw-r--r--contrib/libarchive/libarchive/test/test_write_disk_secure745.c3
-rw-r--r--contrib/libarchive/libarchive/test/test_write_disk_secure746.c9
-rw-r--r--contrib/libarchive/libarchive/test/test_write_disk_secure_noabsolutepaths.c1
-rw-r--r--contrib/libarchive/libarchive/test/test_write_filter_b64encode.c6
-rw-r--r--contrib/libarchive/libarchive/test/test_write_filter_bzip2.c6
-rw-r--r--contrib/libarchive/libarchive/test/test_write_filter_gzip.c23
-rw-r--r--contrib/libarchive/libarchive/test/test_write_filter_lrzip.c6
-rw-r--r--contrib/libarchive/libarchive/test/test_write_filter_lz4.c8
-rw-r--r--contrib/libarchive/libarchive/test/test_write_filter_lzip.c6
-rw-r--r--contrib/libarchive/libarchive/test/test_write_filter_lzma.c82
-rw-r--r--contrib/libarchive/libarchive/test/test_write_filter_lzop.c6
-rw-r--r--contrib/libarchive/libarchive/test/test_write_filter_uuencode.c6
-rw-r--r--contrib/libarchive/libarchive/test/test_write_filter_xz.c95
-rw-r--r--contrib/libarchive/libarchive/test/test_write_filter_zstd.c6
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_7zip.c47
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_7zip_empty.c10
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_7zip_large.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_gnutar.c15
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_gnutar_filenames.c8
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_gnutar_huge.c57
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_iso9660.c12
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_iso9660_boot.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_iso9660_bugs.c305
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_iso9660_empty.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_iso9660_filename.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_iso9660_joliet_id.c113
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_iso9660_joliet_overflow.bin.uu4
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_iso9660_null_deref.bin.uu5
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_iso9660_rockridge.c (renamed from contrib/libarchive/libarchive/test/test_archive_read_set_format_option.c)64
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_iso9660_rockridge_overflow.c74
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_iso9660_underflow.bin.uu5
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_iso9660_zisofs.c12
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_iso9660_zisofs_overflow.c127
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_mtree.c4
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_mtree_absolute.c132
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_mtree_dotdot.c103
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_mtree_null_deref.bin.uu4
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_mtree_null_deref.c233
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_mtree_preset_digests.c105
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_pax.c35
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_pax_align.c246
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_tar_empty_dirname.c82
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_tar_ustar.c14
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_warc.c106
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_xar.c112
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_xar_bugs.c170
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_xar_empty.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_xar_fflags.c78
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_xar_strcpy_overlap.bin.uu6
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_xar_underflow.bin.uu6
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_zip.c8
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_zip_compression_lzma_xz.c (renamed from contrib/libarchive/libarchive/test/test_write_format_zip_compression_lzmaxz.c)20
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_zip_empty_pathname.c75
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_zip_long_pathname.c114
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_zip_windows_path.c3
-rw-r--r--contrib/libarchive/libarchive/test/test_write_format_zip_zip64.c2
-rw-r--r--contrib/libarchive/libarchive/test/test_write_read_format_zip.c8
-rw-r--r--contrib/libarchive/libarchive/xxhash.c2
-rw-r--r--contrib/libarchive/libarchive_fe/lafe_fnmatch.c317
-rw-r--r--contrib/libarchive/libarchive_fe/lafe_fnmatch.h56
-rw-r--r--contrib/libarchive/tar/bsdtar.h3
-rw-r--r--contrib/libarchive/tar/read.c31
-rw-r--r--contrib/libarchive/tar/subst.c17
-rw-r--r--contrib/libarchive/tar/test/test_option_P_upper.c1
-rw-r--r--contrib/libarchive/tar/test/test_option_mtime.c17
-rw-r--r--contrib/libarchive/tar/test/test_option_s.c4
-rw-r--r--contrib/libarchive/tar/test/test_option_stdout_size_exceeds_declared.c50
-rw-r--r--contrib/libarchive/tar/test/test_option_stdout_size_exceeds_declared_deflate.zip.uu23
-rw-r--r--contrib/libarchive/tar/test/test_option_stdout_size_exceeds_declared_stored.zip.uu9
-rw-r--r--contrib/libarchive/tar/test/test_stdio.c2
-rw-r--r--contrib/libarchive/tar/util.c40
-rw-r--r--contrib/libarchive/tar/write.c43
-rw-r--r--contrib/libarchive/test_utils/test_main.c109
-rw-r--r--contrib/libarchive/test_utils/test_utils.c2
-rw-r--r--contrib/libarchive/unzip/bsdunzip.c84
-rw-r--r--contrib/libarchive/unzip/bsdunzip_platform.h4
-rw-r--r--contrib/libarchive/unzip/test/test_I.c8
-rw-r--r--contrib/libarchive/unzip/test/test_P_encryption.c4
-rw-r--r--contrib/libarchive/unzip/test/test_f.c39
-rw-r--r--contrib/libarchive/unzip/test/test_f_new.zip.uu8
-rw-r--r--contrib/libarchive/unzip/test/test_f_old.zip.uu8
-rw-r--r--contrib/libarchive/unzip/test/test_symlink.c53
-rw-r--r--contrib/libarchive/unzip/test/test_symlink_1.zip.uu21
-rw-r--r--contrib/libarchive/unzip/test/test_symlink_2.zip.uu12
-rw-r--r--contrib/libarchive/unzip/test/test_symlink_dotdot.c36
-rw-r--r--contrib/libarchive/unzip/test/test_symlink_dotdot.zip.uu10
-rw-r--r--contrib/libarchive/unzip/test/test_u.c32
-rw-r--r--contrib/libarchive/unzip/test/test_u_new.zip.uu8
-rw-r--r--contrib/libarchive/unzip/test/test_u_old.zip.uu8
-rw-r--r--lib/libarchive/tests/Makefile132
-rw-r--r--usr.bin/tar/tests/Makefile3
-rw-r--r--usr.bin/unzip/tests/Makefile12
434 files changed, 57338 insertions, 8532 deletions
diff --git a/contrib/libarchive/FREEBSD-Xlist b/contrib/libarchive/FREEBSD-Xlist
index 70a015527c05..98a7099d7e04 100644
--- a/contrib/libarchive/FREEBSD-Xlist
+++ b/contrib/libarchive/FREEBSD-Xlist
@@ -1,5 +1,6 @@
.git
.gitattributes
+.github
.gitignore
.travis.yml
CMakeLists.txt
@@ -34,8 +35,13 @@ libarchive/mtree.5
libarchive/test/.cvsignore
libarchive/test/CMakeLists.txt
tar/CMakeLists.txt
+tar/bsdtar.exe.manifest
+tar/bsdtar.rc
tar/bsdtar_windows.c
tar/bsdtar_windows.h
tar/config_freebsd.h
tar/test/CMakeLists.txt
tar/test/test_windows.c
+unzip/bsdunzip.exe.manifest
+unzip/bsdunzip.rc
+unzip/bsdunzip_windows.h
diff --git a/contrib/libarchive/NEWS b/contrib/libarchive/NEWS
index d5e9769771e2..a46b69aaf3e9 100644
--- a/contrib/libarchive/NEWS
+++ b/contrib/libarchive/NEWS
@@ -1,3 +1,7 @@
+Jul 28, 2026: libarchive 3.8.9 released
+
+Jun 23, 2026: libarchive 3.8.8 released
+
Apr 13, 2026: libarchive 3.8.7 released
Mar 10, 2026: libarchive 3.8.6 released
diff --git a/contrib/libarchive/SECURITY.md b/contrib/libarchive/SECURITY.md
index f2f60e792a57..33c37e470004 100644
--- a/contrib/libarchive/SECURITY.md
+++ b/contrib/libarchive/SECURITY.md
@@ -1,9 +1,10 @@
# Security Policy
-If you have discovered a security vulnerability in this project, please report it
-privately. **Do not disclose it as a public issue.** This gives us time to work with you
-to fix the issue before public exposure, reducing the chance that the exploit will be
-used before a patch is released.
+If you have discovered a security vulnerability in this project,
+please report it privately.
+**Do not disclose it as a public issue.**
+This gives us time to work with you to fix the issue before public exposure,
+reducing the chance that the exploit will be used before a patch is released.
You may submit the report in the following ways:
@@ -15,5 +16,11 @@ Please provide the following information in your report:
- A description of the vulnerability and its impact
- How to reproduce the issue
-This project is maintained by volunteers on a reasonable-effort basis. As such, we ask
-that you give us 90 days to work on a fix before public exposure.
+While we welcome all reports, we can act most quickly if the report
+includes a complete libarchive test case and a proposed fix.
+See [doc/WRITING_TESTS.md](doc/WRITING_TESTS.md) for guidance on creating a reproduction test case.
+You can provide the test case and proposed fix as separate patch files
+prepared with `git format-patch` or `git diff`.
+
+This project is maintained by volunteers on a reasonable-effort basis.
+We ask that you give us 90 days to work on a fix before public exposure.
diff --git a/contrib/libarchive/build/ci/github_actions/install-macos-dependencies.sh b/contrib/libarchive/build/ci/github_actions/install-macos-dependencies.sh
deleted file mode 100755
index b33aed5e5562..000000000000
--- a/contrib/libarchive/build/ci/github_actions/install-macos-dependencies.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/sh
-set -eux
-
-# Uncommenting these adds a full minute to the CI time
-#brew update > /dev/null
-#brew upgrade > /dev/null
-
-# Workaround for cmake in local/pinned tap issue
-brew uninstall cmake
-
-# This does an upgrade if the package is already installed
-brew install \
- autoconf \
- automake \
- libtool \
- pkg-config \
- cmake \
- xz \
- lz4 \
- zstd \
- libxml2 \
- openssl
diff --git a/contrib/libarchive/cpio/cpio.c b/contrib/libarchive/cpio/cpio.c
index 6e6c2c3356c0..ebdace394cea 100644
--- a/contrib/libarchive/cpio/cpio.c
+++ b/contrib/libarchive/cpio/cpio.c
@@ -1002,7 +1002,10 @@ mode_in(struct cpio *cpio)
lafe_errc(1, archive_errno(a),
"%s", archive_error_string(a));
}
- if (archive_match_path_excluded(cpio->matching, entry))
+ r = archive_match_path_excluded(cpio->matching, entry);
+ if (r < 0)
+ lafe_errc(1, 0, "%s", archive_error_string(cpio->matching));
+ if (r)
continue;
if (cpio->option_rename)
cpio_rename(entry);
@@ -1117,7 +1120,10 @@ mode_list(struct cpio *cpio)
lafe_errc(1, archive_errno(a),
"%s", archive_error_string(a));
}
- if (archive_match_path_excluded(cpio->matching, entry))
+ r = archive_match_path_excluded(cpio->matching, entry);
+ if (r < 0)
+ lafe_errc(1, 0, "%s", archive_error_string(cpio->matching));
+ if (r)
continue;
if (cpio->verbose)
list_item_verbose(cpio, entry);
diff --git a/contrib/libarchive/cpio/test/test_extract_cpio_absolute_paths.c b/contrib/libarchive/cpio/test/test_extract_cpio_absolute_paths.c
index 51650bc00f5a..e3a72f9ccaf3 100644
--- a/contrib/libarchive/cpio/test/test_extract_cpio_absolute_paths.c
+++ b/contrib/libarchive/cpio/test/test_extract_cpio_absolute_paths.c
@@ -50,4 +50,5 @@ DEFINE_TEST(test_extract_cpio_absolute_paths)
r = systemf("%s -i --insecure < archive.cpio 2> stderr3.txt", testprog);
assert(r == 0);
assertFileExists(temp_absolute_file_name);
+ free(temp_absolute_file_name);
}
diff --git a/contrib/libarchive/cpio/test/test_format_newc.c b/contrib/libarchive/cpio/test/test_format_newc.c
index 9d4e4e9fb674..7363fc148f16 100644
--- a/contrib/libarchive/cpio/test/test_format_newc.c
+++ b/contrib/libarchive/cpio/test/test_format_newc.c
@@ -198,7 +198,7 @@ DEFINE_TEST(test_format_newc)
t = from_hex(e + 46, 8); /* mtime */
failure("t=%#08jx now=%#08jx=%jd", (uintmax_t)t, (uintmax_t)now,
(intmax_t)now);
- assert(t <= now); /* File wasn't created in future. */
+ assert(t <= now + 1); /* Allow 1 sec margin for timing variations. */
failure("t=%#08jx now - 2=%#08jx=%jd", (uintmax_t)t, (uintmax_t)now - 2,
(intmax_t)now - 2);
assert(t >= now - 2); /* File was created w/in last 2 secs. */
diff --git a/contrib/libarchive/libarchive/archive.h b/contrib/libarchive/libarchive/archive.h
index 41a5440cac75..a7de6f6dd85b 100644
--- a/contrib/libarchive/libarchive/archive.h
+++ b/contrib/libarchive/libarchive/archive.h
@@ -34,7 +34,7 @@
* assert that ARCHIVE_VERSION_NUMBER >= 2012108.
*/
/* Note: Compiler will complain if this does not match archive_entry.h! */
-#define ARCHIVE_VERSION_NUMBER 3008007
+#define ARCHIVE_VERSION_NUMBER 3008009
#include <sys/stat.h>
#include <stddef.h> /* for wchar_t */
@@ -177,7 +177,7 @@ __LA_DECL int archive_version_number(void);
/*
* Textual name/version of the library, useful for version displays.
*/
-#define ARCHIVE_VERSION_ONLY_STRING "3.8.7"
+#define ARCHIVE_VERSION_ONLY_STRING "3.8.9"
#define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
__LA_DECL const char * archive_version_string(void);
@@ -210,7 +210,9 @@ __LA_DECL const char * archive_openssl_version(void);
__LA_DECL const char * archive_libmd_version(void);
__LA_DECL const char * archive_commoncrypto_version(void);
__LA_DECL const char * archive_cng_version(void);
+#if ARCHIVE_VERSION_NUMBER < 4000000
__LA_DECL const char * archive_wincrypt_version(void);
+#endif
__LA_DECL const char * archive_librichacl_version(void);
__LA_DECL const char * archive_libacl_version(void);
__LA_DECL const char * archive_libattr_version(void);
@@ -653,7 +655,6 @@ __LA_DECL int archive_read_data_block(struct archive *a,
/*-
* 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 *);
@@ -1234,7 +1235,7 @@ __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.
+ * 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 *,
diff --git a/contrib/libarchive/libarchive/archive_acl.c b/contrib/libarchive/libarchive/archive_acl.c
index ab601833def6..f1b1232f5eef 100644
--- a/contrib/libarchive/libarchive/archive_acl.c
+++ b/contrib/libarchive/libarchive/archive_acl.c
@@ -56,9 +56,7 @@ static int archive_acl_add_entry_len_l(struct archive_acl *acl,
int type, int permset, int tag, int id, const char *name,
size_t len, struct archive_string_conv *sc);
static int archive_acl_text_want_type(struct archive_acl *acl, int flags);
-static size_t archive_acl_text_len(struct archive_acl *acl, int want_type,
- int flags, int wide, struct archive *a,
- struct archive_string_conv *sc);
+static size_t archive_acl_text_empty(struct archive_acl *acl, int want_type);
static int isint_w(const wchar_t *start, const wchar_t *end, int *result);
static int ismode_w(const wchar_t *start, const wchar_t *end, int *result);
static int is_nfs4_flags_w(const wchar_t *start, const wchar_t *end,
@@ -67,9 +65,9 @@ static int is_nfs4_perms_w(const wchar_t *start, const wchar_t *end,
int *result);
static void next_field_w(const wchar_t **wp, const wchar_t **start,
const wchar_t **end, wchar_t *sep);
-static void append_entry_w(wchar_t **wp, const wchar_t *prefix, int type,
+static void append_entry_w(struct archive_wstring *ws, const wchar_t *prefix, int type,
int tag, int flags, const wchar_t *wname, int perm, int id);
-static void append_id_w(wchar_t **wp, int id);
+static void append_id_w(struct archive_wstring *ws, int id);
static int isint(const char *start, const char *end, int *result);
static int ismode(const char *start, const char *end, int *result);
static int is_nfs4_flags(const char *start, const char *end,
@@ -78,9 +76,9 @@ static int is_nfs4_perms(const char *start, const char *end,
int *result);
static void next_field(const char **p, size_t *l, const char **start,
const char **end, char *sep);
-static void append_entry(char **p, const char *prefix, int type,
+static void append_entry(struct archive_string *s, const char *prefix, int type,
int tag, int flags, const char *name, int perm, int id);
-static void append_id(char **p, int id);
+static void append_id(struct archive_string *s, int id);
static const struct {
const int perm;
@@ -539,20 +537,12 @@ archive_acl_text_want_type(struct archive_acl *acl, int flags)
}
/*
- * Calculate ACL text string length
+ * Check if ACL text would be empty
*/
static size_t
-archive_acl_text_len(struct archive_acl *acl, int want_type, int flags,
- int wide, struct archive *a, struct archive_string_conv *sc) {
+archive_acl_text_empty(struct archive_acl *acl, int want_type) {
struct archive_acl_entry *ap;
- const char *name;
- const wchar_t *wname;
- int count, idlen, tmp, r;
- size_t length;
- size_t len;
- count = 0;
- length = 0;
for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
if ((ap->type & want_type) == 0)
continue;
@@ -565,107 +555,11 @@ archive_acl_text_len(struct archive_acl *acl, int want_type, int flags,
|| ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ
|| ap->tag == ARCHIVE_ENTRY_ACL_OTHER))
continue;
- count++;
- if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0
- && (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
- length += 8; /* "default:" */
- switch (ap->tag) {
- case ARCHIVE_ENTRY_ACL_USER_OBJ:
- if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
- length += 6; /* "owner@" */
- break;
- }
- /* FALLTHROUGH */
- case ARCHIVE_ENTRY_ACL_USER:
- case ARCHIVE_ENTRY_ACL_MASK:
- length += 4; /* "user", "mask" */
- break;
- case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
- if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
- length += 6; /* "group@" */
- break;
- }
- /* FALLTHROUGH */
- case ARCHIVE_ENTRY_ACL_GROUP:
- case ARCHIVE_ENTRY_ACL_OTHER:
- length += 5; /* "group", "other" */
- break;
- case ARCHIVE_ENTRY_ACL_EVERYONE:
- length += 9; /* "everyone@" */
- break;
- }
- length += 1; /* colon after tag */
- if (ap->tag == ARCHIVE_ENTRY_ACL_USER ||
- ap->tag == ARCHIVE_ENTRY_ACL_GROUP) {
- if (wide) {
- r = archive_mstring_get_wcs(a, &ap->name,
- &wname);
- if (r == 0 && wname != NULL)
- length += wcslen(wname);
- else if (r < 0 && errno == ENOMEM)
- return (0);
- else
- length += sizeof(uid_t) * 3 + 1;
- } else {
- r = archive_mstring_get_mbs_l(a, &ap->name, &name,
- &len, sc);
- if (r != 0)
- return (0);
- if (len > 0 && name != NULL)
- length += len;
- else
- length += sizeof(uid_t) * 3 + 1;
- }
- length += 1; /* colon after user or group name */
- } else if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4)
- length += 1; /* 2nd colon empty user,group or other */
- if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0)
- && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0)
- && (ap->tag == ARCHIVE_ENTRY_ACL_OTHER
- || ap->tag == ARCHIVE_ENTRY_ACL_MASK)) {
- /* Solaris has no colon after other: and mask: */
- length = length - 1;
- }
-
- if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
- /* rwxpdDaARWcCos:fdinSFI:deny */
- length += 27;
- if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DENY) == 0)
- length += 1; /* allow, alarm, audit */
- } else
- length += 3; /* rwx */
-
- if ((ap->tag == ARCHIVE_ENTRY_ACL_USER ||
- ap->tag == ARCHIVE_ENTRY_ACL_GROUP) &&
- (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0) {
- length += 1; /* colon */
- /* ID digit count */
- idlen = 1;
- tmp = ap->id;
- while (tmp > 9) {
- tmp = tmp / 10;
- idlen++;
- }
- length += idlen;
- }
- length ++; /* entry separator */
- }
-
- /* Add filemode-mapping access entries to the length */
- if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
- if ((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0) {
- /* "user::rwx\ngroup::rwx\nother:rwx\n" */
- length += 31;
- } else {
- /* "user::rwx\ngroup::rwx\nother::rwx\n" */
- length += 32;
- }
- } else if (count == 0)
return (0);
+ }
- /* The terminating character is included in count */
- return (length);
+ return (1);
}
/*
@@ -676,15 +570,12 @@ wchar_t *
archive_acl_to_text_w(struct archive_acl *acl, ssize_t *text_len, int flags,
struct archive *a)
{
- int count;
- size_t length;
- size_t len;
const wchar_t *wname;
const wchar_t *prefix;
wchar_t separator;
struct archive_acl_entry *ap;
+ struct archive_wstring ws;
int id, r, want_type;
- wchar_t *wp, *ws;
want_type = archive_acl_text_want_type(acl, flags);
@@ -695,9 +586,7 @@ archive_acl_to_text_w(struct archive_acl *acl, ssize_t *text_len, int flags,
if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)
flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT;
- length = archive_acl_text_len(acl, want_type, flags, 1, a, NULL);
-
- if (length == 0)
+ if (archive_acl_text_empty(acl, want_type))
return (NULL);
if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA)
@@ -705,28 +594,20 @@ archive_acl_to_text_w(struct archive_acl *acl, ssize_t *text_len, int flags,
else
separator = L'\n';
- /* Now, allocate the string and actually populate it. */
- wp = ws = malloc(length * sizeof(*wp));
- if (wp == NULL) {
- if (errno == ENOMEM)
- __archive_errx(1, "No memory");
- return (NULL);
- }
- count = 0;
+ archive_string_init(&ws);
if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
- append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ append_entry_w(&ws, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL,
acl->mode & 0700, -1);
- *wp++ = separator;
- append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ archive_wstrappend_wchar(&ws, separator);
+ append_entry_w(&ws, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL,
acl->mode & 0070, -1);
- *wp++ = separator;
- append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ archive_wstrappend_wchar(&ws, separator);
+ append_entry_w(&ws, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
ARCHIVE_ENTRY_ACL_OTHER, flags, NULL,
acl->mode & 0007, -1);
- count += 3;
}
for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
@@ -748,108 +629,95 @@ archive_acl_to_text_w(struct archive_acl *acl, ssize_t *text_len, int flags,
prefix = NULL;
r = archive_mstring_get_wcs(a, &ap->name, &wname);
if (r == 0) {
- if (count > 0)
- *wp++ = separator;
- if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
+ if (ws.length > 0)
+ archive_wstrappend_wchar(&ws, separator);
+ if ((flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) ||
+ wname == NULL)
id = ap->id;
else
id = -1;
- append_entry_w(&wp, prefix, ap->type, ap->tag, flags,
+ append_entry_w(&ws, prefix, ap->type, ap->tag, flags,
wname, ap->permset, id);
- count++;
} else if (r < 0 && errno == ENOMEM) {
- free(ws);
+ archive_wstring_free(&ws);
return (NULL);
}
}
- /* Add terminating character */
- *wp++ = L'\0';
-
- len = wcslen(ws);
-
- if (len > length - 1)
- __archive_errx(1, "Buffer overrun");
-
if (text_len != NULL)
- *text_len = len;
+ *text_len = ws.length;
- return (ws);
+ return (ws.s);
}
static void
-append_id_w(wchar_t **wp, int id)
+append_id_w(struct archive_wstring *ws, int id)
{
if (id < 0)
id = 0;
if (id > 9)
- append_id_w(wp, id / 10);
- *(*wp)++ = L"0123456789"[id % 10];
+ append_id_w(ws, id / 10);
+ archive_wstrappend_wchar(ws, L"0123456789"[id % 10]);
}
static void
-append_entry_w(wchar_t **wp, const wchar_t *prefix, int type,
+append_entry_w(struct archive_wstring *ws, const wchar_t *prefix, int type,
int tag, int flags, const wchar_t *wname, int perm, int id)
{
int i;
- if (prefix != NULL) {
- wcscpy(*wp, prefix);
- *wp += wcslen(*wp);
- }
+ if (prefix != NULL)
+ archive_wstrcat(ws, prefix);
switch (tag) {
case ARCHIVE_ENTRY_ACL_USER_OBJ:
wname = NULL;
id = -1;
if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
- wcscpy(*wp, L"owner@");
+ archive_wstrcat(ws, L"owner@");
break;
}
/* FALLTHROUGH */
case ARCHIVE_ENTRY_ACL_USER:
- wcscpy(*wp, L"user");
+ archive_wstrcat(ws, L"user");
break;
case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
wname = NULL;
id = -1;
if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
- wcscpy(*wp, L"group@");
+ archive_wstrcat(ws, L"group@");
break;
}
/* FALLTHROUGH */
case ARCHIVE_ENTRY_ACL_GROUP:
- wcscpy(*wp, L"group");
+ archive_wstrcat(ws, L"group");
break;
case ARCHIVE_ENTRY_ACL_MASK:
- wcscpy(*wp, L"mask");
+ archive_wstrcat(ws, L"mask");
wname = NULL;
id = -1;
break;
case ARCHIVE_ENTRY_ACL_OTHER:
- wcscpy(*wp, L"other");
+ archive_wstrcat(ws, L"other");
wname = NULL;
id = -1;
break;
case ARCHIVE_ENTRY_ACL_EVERYONE:
- wcscpy(*wp, L"everyone@");
+ archive_wstrcat(ws, L"everyone@");
wname = NULL;
id = -1;
break;
default:
- **wp = '\0';
break;
}
- *wp += wcslen(*wp);
- *(*wp)++ = L':';
+ archive_wstrappend_wchar(ws, L':');
if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) ||
tag == ARCHIVE_ENTRY_ACL_USER ||
tag == ARCHIVE_ENTRY_ACL_GROUP) {
if (wname != NULL) {
- wcscpy(*wp, wname);
- *wp += wcslen(*wp);
+ archive_wstrcat(ws, wname);
} else if (tag == ARCHIVE_ENTRY_ACL_USER
|| tag == ARCHIVE_ENTRY_ACL_GROUP) {
- append_id_w(wp, id);
+ append_id_w(ws, id);
if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0)
id = -1;
}
@@ -857,51 +725,49 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int type,
if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0)
|| (tag != ARCHIVE_ENTRY_ACL_OTHER
&& tag != ARCHIVE_ENTRY_ACL_MASK))
- *(*wp)++ = L':';
+ archive_wstrappend_wchar(ws, L':');
}
if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
/* POSIX.1e ACL perms */
- *(*wp)++ = (perm & 0444) ? L'r' : L'-';
- *(*wp)++ = (perm & 0222) ? L'w' : L'-';
- *(*wp)++ = (perm & 0111) ? L'x' : L'-';
+ archive_wstrappend_wchar(ws, (perm & 0444) ? L'r' : L'-');
+ archive_wstrappend_wchar(ws, (perm & 0222) ? L'w' : L'-');
+ archive_wstrappend_wchar(ws, (perm & 0111) ? L'x' : L'-');
} else {
/* NFSv4 ACL perms */
for (i = 0; i < nfsv4_acl_perm_map_size; i++) {
if (perm & nfsv4_acl_perm_map[i].perm)
- *(*wp)++ = nfsv4_acl_perm_map[i].wc;
+ archive_wstrappend_wchar(ws, nfsv4_acl_perm_map[i].wc);
else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0)
- *(*wp)++ = L'-';
+ archive_wstrappend_wchar(ws, L'-');
}
- *(*wp)++ = L':';
+ archive_wstrappend_wchar(ws, L':');
for (i = 0; i < nfsv4_acl_flag_map_size; i++) {
if (perm & nfsv4_acl_flag_map[i].perm)
- *(*wp)++ = nfsv4_acl_flag_map[i].wc;
+ archive_wstrappend_wchar(ws, nfsv4_acl_flag_map[i].wc);
else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0)
- *(*wp)++ = L'-';
+ archive_wstrappend_wchar(ws, L'-');
}
- *(*wp)++ = L':';
+ archive_wstrappend_wchar(ws, L':');
switch (type) {
case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
- wcscpy(*wp, L"allow");
+ archive_wstrcat(ws, L"allow");
break;
case ARCHIVE_ENTRY_ACL_TYPE_DENY:
- wcscpy(*wp, L"deny");
+ archive_wstrcat(ws, L"deny");
break;
case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
- wcscpy(*wp, L"audit");
+ archive_wstrcat(ws, L"audit");
break;
case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
- wcscpy(*wp, L"alarm");
+ archive_wstrcat(ws, L"alarm");
break;
default:
- *(*wp) = L'\0';
break;
}
- *wp += wcslen(*wp);
}
if (id != -1) {
- *(*wp)++ = L':';
- append_id_w(wp, id);
+ archive_wstrappend_wchar(ws, L':');
+ append_id_w(ws, id);
}
}
@@ -913,15 +779,13 @@ char *
archive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags,
struct archive_string_conv *sc)
{
- int count;
- size_t length;
size_t len;
const char *name;
const char *prefix;
char separator;
struct archive_acl_entry *ap;
+ struct archive_string s;
int id, r, want_type;
- char *p, *s;
want_type = archive_acl_text_want_type(acl, flags);
@@ -932,9 +796,7 @@ archive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags,
if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)
flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT;
- length = archive_acl_text_len(acl, want_type, flags, 0, NULL, sc);
-
- if (length == 0)
+ if (archive_acl_text_empty(acl, want_type))
return (NULL);
if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA)
@@ -942,28 +804,20 @@ archive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags,
else
separator = '\n';
- /* Now, allocate the string and actually populate it. */
- p = s = malloc(length * sizeof(*p));
- if (p == NULL) {
- if (errno == ENOMEM)
- __archive_errx(1, "No memory");
- return (NULL);
- }
- count = 0;
+ archive_string_init(&s);
if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
- append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ append_entry(&s, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL,
acl->mode & 0700, -1);
- *p++ = separator;
- append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ archive_strappend_char(&s, separator);
+ append_entry(&s, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL,
acl->mode & 0070, -1);
- *p++ = separator;
- append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ archive_strappend_char(&s, separator);
+ append_entry(&s, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
ARCHIVE_ENTRY_ACL_OTHER, flags, NULL,
acl->mode & 0007, -1);
- count += 3;
}
for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
@@ -986,109 +840,95 @@ archive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags,
r = archive_mstring_get_mbs_l(
NULL, &ap->name, &name, &len, sc);
if (r != 0) {
- free(s);
+ archive_string_free(&s);
return (NULL);
}
- if (count > 0)
- *p++ = separator;
+ if (s.length > 0)
+ archive_strappend_char(&s, separator);
if (name == NULL ||
(flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)) {
id = ap->id;
} else {
id = -1;
}
- append_entry(&p, prefix, ap->type, ap->tag, flags, name,
+ append_entry(&s, prefix, ap->type, ap->tag, flags, name,
ap->permset, id);
- count++;
}
- /* Add terminating character */
- *p++ = '\0';
-
- len = strlen(s);
-
- if (len > length - 1)
- __archive_errx(1, "Buffer overrun");
-
if (text_len != NULL)
- *text_len = len;
+ *text_len = s.length;
- return (s);
+ return (s.s);
}
static void
-append_id(char **p, int id)
+append_id(struct archive_string *s, int id)
{
if (id < 0)
id = 0;
if (id > 9)
- append_id(p, id / 10);
- *(*p)++ = "0123456789"[id % 10];
+ append_id(s, id / 10);
+ archive_strappend_char(s, "0123456789"[id % 10]);
}
static void
-append_entry(char **p, const char *prefix, int type,
+append_entry(struct archive_string *s, const char *prefix, int type,
int tag, int flags, const char *name, int perm, int id)
{
int i;
- if (prefix != NULL) {
- strcpy(*p, prefix);
- *p += strlen(*p);
- }
+ if (prefix != NULL)
+ archive_strcat(s, prefix);
switch (tag) {
case ARCHIVE_ENTRY_ACL_USER_OBJ:
name = NULL;
id = -1;
if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
- strcpy(*p, "owner@");
+ archive_strcat(s, "owner@");
break;
}
/* FALLTHROUGH */
case ARCHIVE_ENTRY_ACL_USER:
- strcpy(*p, "user");
+ archive_strcat(s, "user");
break;
case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
name = NULL;
id = -1;
if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
- strcpy(*p, "group@");
+ archive_strcat(s, "group@");
break;
}
/* FALLTHROUGH */
case ARCHIVE_ENTRY_ACL_GROUP:
- strcpy(*p, "group");
+ archive_strcat(s, "group");
break;
case ARCHIVE_ENTRY_ACL_MASK:
- strcpy(*p, "mask");
+ archive_strcat(s, "mask");
name = NULL;
id = -1;
break;
case ARCHIVE_ENTRY_ACL_OTHER:
- strcpy(*p, "other");
+ archive_strcat(s, "other");
name = NULL;
id = -1;
break;
case ARCHIVE_ENTRY_ACL_EVERYONE:
- strcpy(*p, "everyone@");
+ archive_strcat(s, "everyone@");
name = NULL;
id = -1;
break;
default:
- **p = '\0';
break;
}
- *p += strlen(*p);
- *(*p)++ = ':';
+ archive_strappend_char(s, ':');
if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) ||
tag == ARCHIVE_ENTRY_ACL_USER ||
tag == ARCHIVE_ENTRY_ACL_GROUP) {
if (name != NULL) {
- strcpy(*p, name);
- *p += strlen(*p);
+ archive_strcat(s, name);
} else if (tag == ARCHIVE_ENTRY_ACL_USER
|| tag == ARCHIVE_ENTRY_ACL_GROUP) {
- append_id(p, id);
+ append_id(s, id);
if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0)
id = -1;
}
@@ -1096,51 +936,49 @@ append_entry(char **p, const char *prefix, int type,
if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0)
|| (tag != ARCHIVE_ENTRY_ACL_OTHER
&& tag != ARCHIVE_ENTRY_ACL_MASK))
- *(*p)++ = ':';
+ archive_strappend_char(s, ':');
}
if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
/* POSIX.1e ACL perms */
- *(*p)++ = (perm & 0444) ? 'r' : '-';
- *(*p)++ = (perm & 0222) ? 'w' : '-';
- *(*p)++ = (perm & 0111) ? 'x' : '-';
+ archive_strappend_char(s, (perm & 0444) ? 'r' : '-');
+ archive_strappend_char(s, (perm & 0222) ? 'w' : '-');
+ archive_strappend_char(s, (perm & 0111) ? 'x' : '-');
} else {
/* NFSv4 ACL perms */
for (i = 0; i < nfsv4_acl_perm_map_size; i++) {
if (perm & nfsv4_acl_perm_map[i].perm)
- *(*p)++ = nfsv4_acl_perm_map[i].c;
+ archive_strappend_char(s, nfsv4_acl_perm_map[i].c);
else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0)
- *(*p)++ = '-';
+ archive_strappend_char(s, '-');
}
- *(*p)++ = ':';
+ archive_strappend_char(s, ':');
for (i = 0; i < nfsv4_acl_flag_map_size; i++) {
if (perm & nfsv4_acl_flag_map[i].perm)
- *(*p)++ = nfsv4_acl_flag_map[i].c;
+ archive_strappend_char(s, nfsv4_acl_flag_map[i].c);
else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0)
- *(*p)++ = '-';
+ archive_strappend_char(s, '-');
}
- *(*p)++ = ':';
+ archive_strappend_char(s, ':');
switch (type) {
case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
- strcpy(*p, "allow");
+ archive_strcat(s, "allow");
break;
case ARCHIVE_ENTRY_ACL_TYPE_DENY:
- strcpy(*p, "deny");
+ archive_strcat(s, "deny");
break;
case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
- strcpy(*p, "audit");
+ archive_strcat(s, "audit");
break;
case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
- strcpy(*p, "alarm");
+ archive_strcat(s, "alarm");
break;
default:
- *(*p) = '\0';
break;
}
- *p += strlen(*p);
}
if (id != -1) {
- *(*p)++ = ':';
- append_id(p, id);
+ archive_strappend_char(s, ':');
+ append_id(s, id);
}
}
@@ -1248,11 +1086,18 @@ archive_acl_from_text_w(struct archive_acl *acl, const wchar_t *text,
type = want_type;
/* Check for a numeric ID in field n+1 or n+3. */
- isint_w(field[n + 1].start, field[n + 1].end, &id);
+ if (isint_w(field[n + 1].start, field[n + 1].end,
+ &id) < 0) {
+ ret = ARCHIVE_WARN;
+ continue;
+ }
/* Field n+3 is optional. */
- if (id == -1 && fields > n+3)
- isint_w(field[n + 3].start, field[n + 3].end,
- &id);
+ if (id == -1 && fields > n+3 &&
+ isint_w(field[n + 3].start, field[n + 3].end,
+ &id) < 0) {
+ ret = ARCHIVE_WARN;
+ continue;
+ }
tag = 0;
s = field[n].start;
@@ -1367,7 +1212,10 @@ archive_acl_from_text_w(struct archive_acl *acl, const wchar_t *text,
tag == ARCHIVE_ENTRY_ACL_GROUP) {
n = 1;
name = field[1];
- isint_w(name.start, name.end, &id);
+ if (isint_w(name.start, name.end, &id) < 0) {
+ ret = ARCHIVE_WARN;
+ continue;
+ }
} else
n = 0;
@@ -1402,7 +1250,11 @@ archive_acl_from_text_w(struct archive_acl *acl, const wchar_t *text,
ret = ARCHIVE_WARN;
continue;
}
- isint_w(field[4 + n].start, field[4 + n].end, &id);
+ if (isint_w(field[4 + n].start, field[4 + n].end,
+ &id) < 0) {
+ ret = ARCHIVE_WARN;
+ continue;
+ }
}
/* Add entry to the internal list. */
@@ -1436,8 +1288,8 @@ isint_w(const wchar_t *start, const wchar_t *end, int *result)
if (*start < L'0' || *start > L'9')
return (0);
if (n > (INT_MAX / 10) ||
- (n == INT_MAX / 10 && (*start - L'0') > INT_MAX % 10)) {
- n = INT_MAX;
+ (n == INT_MAX / 10 && (*start - L'0') >= INT_MAX % 10)) {
+ return (-1);
} else {
n *= 10;
n += *start - L'0';
@@ -1664,7 +1516,7 @@ archive_acl_from_text_nl(struct archive_acl *acl, const char *text,
const char *end;
} field[6], name;
- const char *s, *st;
+ const char *s, *st, *text_end;
int numfields, fields, n, r, sol, ret;
int type, types, tag, permset, id;
size_t len;
@@ -1687,6 +1539,7 @@ archive_acl_from_text_nl(struct archive_acl *acl, const char *text,
ret = ARCHIVE_OK;
types = 0;
+ text_end = (text == NULL) ? text : text + length;
while (text != NULL && length > 0 && *text != '\0') {
/*
@@ -1713,6 +1566,18 @@ archive_acl_from_text_nl(struct archive_acl *acl, const char *text,
return (ARCHIVE_FATAL);
}
+ if (field[0].start == text_end) {
+ /*
+ * Empty entry: next_field() consumed the rest of the
+ * buffer as separators or whitespace, leaving
+ * field[0].start one past the end. 'text' is not
+ * guaranteed to be NUL terminated, so the byte after it
+ * must not be dereferenced.
+ */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+
if (*(field[0].start) == '#') {
/* Comment, skip entry */
continue;
@@ -1747,15 +1612,21 @@ archive_acl_from_text_nl(struct archive_acl *acl, const char *text,
type = want_type;
/* Check for a numeric ID in field n+1 or n+3. */
- isint(field[n + 1].start, field[n + 1].end, &id);
+ if (isint(field[n + 1].start, field[n + 1].end,
+ &id) < 0) {
+ ret = ARCHIVE_WARN;
+ continue;
+ }
/* Field n+3 is optional. */
- if (id == -1 && fields > (n + 3))
- isint(field[n + 3].start, field[n + 3].end,
- &id);
+ if (id == -1 && fields > (n + 3) &&
+ isint(field[n + 3].start, field[n + 3].end,
+ &id) < 0) {
+ ret = ARCHIVE_WARN;
+ continue;
+ }
tag = 0;
s = field[n].start;
- st = field[n].start + 1;
len = field[n].end - field[n].start;
if (len == 0) {
@@ -1763,6 +1634,8 @@ archive_acl_from_text_nl(struct archive_acl *acl, const char *text,
continue;
}
+ st = s + 1;
+
switch (*s) {
case 'u':
if (len == 1 || (len == 4
@@ -1868,7 +1741,10 @@ archive_acl_from_text_nl(struct archive_acl *acl, const char *text,
tag == ARCHIVE_ENTRY_ACL_GROUP) {
n = 1;
name = field[1];
- isint(name.start, name.end, &id);
+ if (isint(name.start, name.end, &id) < 0) {
+ ret = ARCHIVE_WARN;
+ continue;
+ }
} else
n = 0;
@@ -1903,8 +1779,11 @@ archive_acl_from_text_nl(struct archive_acl *acl, const char *text,
ret = ARCHIVE_WARN;
continue;
}
- isint(field[4 + n].start, field[4 + n].end,
- &id);
+ if (isint(field[4 + n].start, field[4 + n].end,
+ &id) < 0) {
+ ret = ARCHIVE_WARN;
+ continue;
+ }
}
/* Add entry to the internal list. */
@@ -1938,8 +1817,8 @@ isint(const char *start, const char *end, int *result)
if (*start < '0' || *start > '9')
return (0);
if (n > (INT_MAX / 10) ||
- (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) {
- n = INT_MAX;
+ (n == INT_MAX / 10 && (*start - '0') >= INT_MAX % 10)) {
+ return (-1);
} else {
n *= 10;
n += *start - '0';
@@ -2121,7 +2000,10 @@ next_field(const char **p, size_t *l, const char **start,
(*p)++;
(*l)--;
}
- *sep = **p;
+ if (*l > 0)
+ *sep = **p;
+ else
+ *sep = '\0';
/* Handle in-field comments */
if (*sep == '#') {
@@ -2129,7 +2011,10 @@ next_field(const char **p, size_t *l, const char **start,
(*p)++;
(*l)--;
}
- *sep = **p;
+ if (*l > 0)
+ *sep = **p;
+ else
+ *sep = '\0';
}
/* Skip separator. */
diff --git a/contrib/libarchive/libarchive/archive_acl_private.h b/contrib/libarchive/libarchive/archive_acl_private.h
index 54e4439692ed..4df8a0ac3a5c 100644
--- a/contrib/libarchive/libarchive/archive_acl_private.h
+++ b/contrib/libarchive/libarchive/archive_acl_private.h
@@ -27,8 +27,10 @@
#define ARCHIVE_ACL_PRIVATE_H_INCLUDED
#ifndef __LIBARCHIVE_BUILD
+#ifndef __LIBARCHIVE_TEST
#error This header is only to be used internally to libarchive.
#endif
+#endif
#include "archive_string.h"
diff --git a/contrib/libarchive/libarchive/archive_check_magic.c b/contrib/libarchive/libarchive/archive_check_magic.c
index b6e1257949e1..788a76070b7a 100644
--- a/contrib/libarchive/libarchive/archive_check_magic.c
+++ b/contrib/libarchive/libarchive/archive_check_magic.c
@@ -85,6 +85,7 @@ state_name(unsigned s)
case ARCHIVE_STATE_NEW: return ("new");
case ARCHIVE_STATE_HEADER: return ("header");
case ARCHIVE_STATE_DATA: return ("data");
+ case ARCHIVE_STATE_DATA_RECOVERY: return ("data_recovery");
case ARCHIVE_STATE_EOF: return ("eof");
case ARCHIVE_STATE_CLOSED: return ("closed");
case ARCHIVE_STATE_FATAL: return ("fatal");
diff --git a/contrib/libarchive/libarchive/archive_cmdline.c b/contrib/libarchive/libarchive/archive_cmdline.c
index 23bb05d6424a..ffc4f5474947 100644
--- a/contrib/libarchive/libarchive/archive_cmdline.c
+++ b/contrib/libarchive/libarchive/archive_cmdline.c
@@ -36,7 +36,6 @@
#include "archive_cmdline_private.h"
#include "archive_string.h"
-static int cmdline_set_path(struct archive_cmdline *, const char *);
static int cmdline_add_arg(struct archive_cmdline *, const char *);
static ssize_t
@@ -98,7 +97,7 @@ get_argument(struct archive_string *as, const char *p)
/*
* Set up command line arguments.
- * Returns ARCHIVE_OK if everything okey.
+ * Returns ARCHIVE_OK if everything okay.
* Returns ARCHIVE_FAILED if there is a lack of the `"' terminator or an
* empty command line.
* Returns ARCHIVE_FATAL if no memory.
@@ -123,9 +122,12 @@ __archive_cmdline_parse(struct archive_cmdline *data, const char *cmd)
r = ARCHIVE_FAILED;/* An empty command path. */
goto exit_function;
}
- r = cmdline_set_path(data, as.s);
- if (r != ARCHIVE_OK)
+ free(data->path);
+ data->path = strdup(as.s);
+ if (data->path == NULL) {
+ r = ARCHIVE_FATAL;
goto exit_function;
+ }
p = strrchr(as.s, '/');
if (p == NULL)
p = as.s;
@@ -158,23 +160,7 @@ exit_function:
}
/*
- * Set the program path.
- */
-static int
-cmdline_set_path(struct archive_cmdline *data, const char *path)
-{
- char *newptr;
-
- newptr = realloc(data->path, strlen(path) + 1);
- if (newptr == NULL)
- return (ARCHIVE_FATAL);
- data->path = newptr;
- strcpy(data->path, path);
- return (ARCHIVE_OK);
-}
-
-/*
- * Add a argument for the program.
+ * Add an argument for the program.
*/
static int
cmdline_add_arg(struct archive_cmdline *data, const char *arg)
diff --git a/contrib/libarchive/libarchive/archive_crc32.h b/contrib/libarchive/libarchive/archive_crc32.h
index d86a507ce78c..cbd25291a975 100644
--- a/contrib/libarchive/libarchive/archive_crc32.h
+++ b/contrib/libarchive/libarchive/archive_crc32.h
@@ -43,28 +43,65 @@
static unsigned long
crc32(unsigned long crc, const void *_p, size_t len)
{
- unsigned long crc2, b, i;
const unsigned char *p = _p;
- static volatile int crc_tbl_inited = 0;
- static unsigned long crc_tbl[256];
+ static const unsigned long crc_tbl[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+ 0x2d02ef8d
+ };
if (_p == NULL)
return (0);
- if (!crc_tbl_inited) {
- for (b = 0; b < 256; ++b) {
- crc2 = b;
- for (i = 8; i > 0; --i) {
- if (crc2 & 1)
- crc2 = (crc2 >> 1) ^ 0xedb88320UL;
- else
- crc2 = (crc2 >> 1);
- }
- crc_tbl[b] = crc2;
- }
- crc_tbl_inited = 1;
- }
-
crc = crc ^ 0xffffffffUL;
/* A use of this loop is about 20% - 30% faster than
* no use version in any optimization option of gcc. */
diff --git a/contrib/libarchive/libarchive/archive_cryptor.c b/contrib/libarchive/libarchive/archive_cryptor.c
index b6a02fd1e7cb..85b20ac9acc1 100644
--- a/contrib/libarchive/libarchive/archive_cryptor.c
+++ b/contrib/libarchive/libarchive/archive_cryptor.c
@@ -57,7 +57,7 @@ pbkdf2_sha1(const char *pw, size_t pw_len, const uint8_t *salt,
return 0;
}
-#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
#ifdef _MSC_VER
#pragma comment(lib, "Bcrypt.lib")
#endif
@@ -197,7 +197,7 @@ aes_ctr_release(archive_crypto_ctx *ctx)
return 0;
}
-#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
static int
aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len)
diff --git a/contrib/libarchive/libarchive/archive_cryptor_private.h b/contrib/libarchive/libarchive/archive_cryptor_private.h
index 1f9298ffdc46..069eccd994bf 100644
--- a/contrib/libarchive/libarchive/archive_cryptor_private.h
+++ b/contrib/libarchive/libarchive/archive_cryptor_private.h
@@ -62,7 +62,7 @@ typedef struct {
size_t encr_pos;
} archive_crypto_ctx;
-#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
#include <bcrypt.h>
#define ARCHIVE_CRYPTOR_USE_CNG 1
@@ -148,16 +148,6 @@ typedef struct {
#else
-#if defined(ARCHIVE_CRYPTO_MD5_WIN) ||\
- defined(ARCHIVE_CRYPTO_SHA1_WIN) ||\
- defined(ARCHIVE_CRYPTO_SHA256_WIN) ||\
- defined(ARCHIVE_CRYPTO_SHA384_WIN) ||\
- defined(ARCHIVE_CRYPTO_SHA512_WIN)
-#if defined(_WIN32) && !defined(__CYGWIN__) && !(defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA)
-#define ARCHIVE_CRYPTOR_USE_WINCRYPT 1
-#endif
-#endif
-
#define AES_BLOCK_SIZE 16
#define AES_MAX_KEY_SIZE 32
typedef int archive_crypto_ctx;
diff --git a/contrib/libarchive/libarchive/archive_digest.c b/contrib/libarchive/libarchive/archive_digest.c
index 45fc36af1145..ab6db12bebe2 100644
--- a/contrib/libarchive/libarchive/archive_digest.c
+++ b/contrib/libarchive/libarchive/archive_digest.c
@@ -44,16 +44,11 @@
/*
* Message digest functions for Windows platform.
*/
-#if defined(ARCHIVE_CRYPTO_MD5_WIN) ||\
- defined(ARCHIVE_CRYPTO_SHA1_WIN) ||\
- defined(ARCHIVE_CRYPTO_SHA256_WIN) ||\
- defined(ARCHIVE_CRYPTO_SHA384_WIN) ||\
- defined(ARCHIVE_CRYPTO_SHA512_WIN)
+#if defined(HAVE_BCRYPT_H)
/*
* Initialize a Message digest.
*/
-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
static int
win_crypto_init(Digest_CTX *ctx, const WCHAR *algo)
{
@@ -72,30 +67,6 @@ win_crypto_init(Digest_CTX *ctx, const WCHAR *algo)
ctx->valid = 1;
return (ARCHIVE_OK);
}
-#else
-static int
-win_crypto_init(Digest_CTX *ctx, DWORD prov, ALG_ID algId)
-{
-
- ctx->valid = 0;
- if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,
- prov, CRYPT_VERIFYCONTEXT)) {
- if (GetLastError() != (DWORD)NTE_BAD_KEYSET)
- return (ARCHIVE_FAILED);
- if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,
- prov, CRYPT_NEWKEYSET))
- return (ARCHIVE_FAILED);
- }
-
- if (!CryptCreateHash(ctx->cryptProv, algId, 0, 0, &ctx->hash)) {
- CryptReleaseContext(ctx->cryptProv, 0);
- return (ARCHIVE_FAILED);
- }
-
- ctx->valid = 1;
- return (ARCHIVE_OK);
-}
-#endif
/*
* Update a Message digest.
@@ -107,42 +78,26 @@ win_crypto_Update(Digest_CTX *ctx, const unsigned char *buf, size_t len)
if (!ctx->valid)
return (ARCHIVE_FAILED);
-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
BCryptHashData(ctx->hHash,
(PUCHAR)(uintptr_t)buf,
(ULONG)len, 0);
-#else
- CryptHashData(ctx->hash,
- (unsigned char *)(uintptr_t)buf,
- (DWORD)len, 0);
-#endif
return (ARCHIVE_OK);
}
static int
win_crypto_Final(unsigned char *buf, size_t bufsize, Digest_CTX *ctx)
{
-#if !(defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA)
- DWORD siglen = (DWORD)bufsize;
-#endif
-
if (!ctx->valid)
return (ARCHIVE_FAILED);
-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
BCryptFinishHash(ctx->hHash, buf, (ULONG)bufsize, 0);
BCryptDestroyHash(ctx->hHash);
BCryptCloseAlgorithmProvider(ctx->hAlg, 0);
-#else
- CryptGetHashParam(ctx->hash, HP_HASHVAL, buf, &siglen, 0);
- CryptDestroyHash(ctx->hash);
- CryptReleaseContext(ctx->cryptProv, 0);
-#endif
ctx->valid = 0;
return (ARCHIVE_OK);
}
-#endif /* defined(ARCHIVE_CRYPTO_*_WIN) */
+#endif /* defined(HAVE_BCRYPT_H) */
/* MD5 implementations */
@@ -234,11 +189,7 @@ __archive_md5final(archive_md5_ctx *ctx, void *md)
static int
__archive_md5init(archive_md5_ctx *ctx)
{
-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
return (win_crypto_init(ctx, BCRYPT_MD5_ALGORITHM));
-#else
- return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_MD5));
-#endif
}
static int
@@ -645,11 +596,7 @@ __archive_sha1final(archive_sha1_ctx *ctx, void *md)
static int
__archive_sha1init(archive_sha1_ctx *ctx)
{
-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
return (win_crypto_init(ctx, BCRYPT_SHA1_ALGORITHM));
-#else
- return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_SHA1));
-#endif
}
static int
@@ -925,11 +872,7 @@ __archive_sha256final(archive_sha256_ctx *ctx, void *md)
static int
__archive_sha256init(archive_sha256_ctx *ctx)
{
-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
return (win_crypto_init(ctx, BCRYPT_SHA256_ALGORITHM));
-#else
- return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_256));
-#endif
}
static int
@@ -1177,11 +1120,7 @@ __archive_sha384final(archive_sha384_ctx *ctx, void *md)
static int
__archive_sha384init(archive_sha384_ctx *ctx)
{
-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
return (win_crypto_init(ctx, BCRYPT_SHA384_ALGORITHM));
-#else
- return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_384));
-#endif
}
static int
@@ -1453,11 +1392,7 @@ __archive_sha512final(archive_sha512_ctx *ctx, void *md)
static int
__archive_sha512init(archive_sha512_ctx *ctx)
{
-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
return (win_crypto_init(ctx, BCRYPT_SHA512_ALGORITHM));
-#else
- return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_512));
-#endif
}
static int
diff --git a/contrib/libarchive/libarchive/archive_digest_private.h b/contrib/libarchive/libarchive/archive_digest_private.h
index deb134e4f8e8..7db999450e70 100644
--- a/contrib/libarchive/libarchive/archive_digest_private.h
+++ b/contrib/libarchive/libarchive/archive_digest_private.h
@@ -165,8 +165,7 @@
defined(ARCHIVE_CRYPTO_SHA256_WIN) ||\
defined(ARCHIVE_CRYPTO_SHA384_WIN) ||\
defined(ARCHIVE_CRYPTO_SHA512_WIN)
-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
-/* don't use bcrypt when XP needs to be supported */
+#if defined(HAVE_BCRYPT_H)
#include <bcrypt.h>
#define ARCHIVE_CRYPTO_CNG 1
typedef struct {
@@ -174,15 +173,6 @@ typedef struct {
BCRYPT_ALG_HANDLE hAlg;
BCRYPT_HASH_HANDLE hHash;
} Digest_CTX;
-#else
-#include <windows.h>
-#include <wincrypt.h>
-#define ARCHIVE_CRYPTO_WINCRYPT 1
-typedef struct {
- int valid;
- HCRYPTPROV cryptProv;
- HCRYPTHASH hash;
-} Digest_CTX;
#endif
#endif
diff --git a/contrib/libarchive/libarchive/archive_endian.h b/contrib/libarchive/libarchive/archive_endian.h
index 83b2efa531ef..939acc6670ea 100644
--- a/contrib/libarchive/libarchive/archive_endian.h
+++ b/contrib/libarchive/libarchive/archive_endian.h
@@ -71,6 +71,22 @@ archive_be16dec(const void *pp)
}
static inline uint32_t
+archive_be24dec(const void *pp)
+{
+ unsigned char const *p = (unsigned char const *)pp;
+
+ /* Store into unsigned temporaries before left shifting, to avoid
+ promotion to signed int and then left shifting into the sign bit,
+ which is undefined behaviour. */
+ unsigned int p2 = p[2];
+ unsigned int p1 = p[1];
+ unsigned int p0 = p[0];
+
+ return ((p0 << 16) | (p1 << 8) | p2);
+}
+
+
+static inline uint32_t
archive_be32dec(const void *pp)
{
unsigned char const *p = (unsigned char const *)pp;
@@ -109,6 +125,21 @@ archive_le16dec(const void *pp)
}
static inline uint32_t
+archive_le24dec(const void *pp)
+{
+ unsigned char const *p = (unsigned char const *)pp;
+
+ /* Store into unsigned temporaries before left shifting, to avoid
+ promotion to signed int and then left shifting into the sign bit,
+ which is undefined behaviour. */
+ unsigned int p2 = p[2];
+ unsigned int p1 = p[1];
+ unsigned int p0 = p[0];
+
+ return ((p2 << 16) | (p1 << 8) | p0);
+}
+
+static inline uint32_t
archive_le32dec(const void *pp)
{
unsigned char const *p = (unsigned char const *)pp;
@@ -171,6 +202,16 @@ archive_le16enc(void *pp, uint16_t u)
}
static inline void
+archive_le24enc(void *pp, uint32_t u)
+{
+ unsigned char *p = (unsigned char *)pp;
+
+ p[0] = u & 0xff;
+ p[1] = (u >> 8) & 0xff;
+ p[2] = (u >> 16) & 0xff;
+}
+
+static inline void
archive_le32enc(void *pp, uint32_t u)
{
unsigned char *p = (unsigned char *)pp;
diff --git a/contrib/libarchive/libarchive/archive_entry.c b/contrib/libarchive/libarchive/archive_entry.c
index 4ba361ebe24e..88abc45c17a9 100644
--- a/contrib/libarchive/libarchive/archive_entry.c
+++ b/contrib/libarchive/libarchive/archive_entry.c
@@ -1239,7 +1239,7 @@ _archive_entry_copy_link_l(struct archive_entry *entry,
}
void
-archive_entry_set_mode(struct archive_entry *entry, mode_t m)
+archive_entry_set_mode(struct archive_entry *entry, __LA_MODE_T m)
{
entry->stat_valid = 0;
entry->acl.mode = m;
@@ -1314,7 +1314,7 @@ _archive_entry_copy_pathname_l(struct archive_entry *entry,
}
void
-archive_entry_set_perm(struct archive_entry *entry, mode_t p)
+archive_entry_set_perm(struct archive_entry *entry, __LA_MODE_T p)
{
entry->stat_valid = 0;
entry->acl.mode &= AE_IFMT;
@@ -1562,17 +1562,21 @@ void
archive_entry_copy_mac_metadata(struct archive_entry *entry,
const void *p, size_t s)
{
- free(entry->mac_metadata);
- if (p == NULL || s == 0) {
- entry->mac_metadata = NULL;
- entry->mac_metadata_size = 0;
- } else {
- entry->mac_metadata_size = s;
- entry->mac_metadata = malloc(s);
- if (entry->mac_metadata == NULL)
- abort();
- memcpy(entry->mac_metadata, p, s);
- }
+ void *metadata;
+
+ if (p == NULL || s == 0) {
+ free(entry->mac_metadata);
+ entry->mac_metadata = NULL;
+ entry->mac_metadata_size = 0;
+ } else {
+ metadata = malloc(s);
+ if (metadata == NULL)
+ abort();
+ memcpy(metadata, p, s);
+ free(entry->mac_metadata);
+ entry->mac_metadata = metadata;
+ entry->mac_metadata_size = s;
+ }
}
/* Digest handling */
diff --git a/contrib/libarchive/libarchive/archive_entry.h b/contrib/libarchive/libarchive/archive_entry.h
index 7122a74ed007..9c859a44e340 100644
--- a/contrib/libarchive/libarchive/archive_entry.h
+++ b/contrib/libarchive/libarchive/archive_entry.h
@@ -28,7 +28,7 @@
#define ARCHIVE_ENTRY_H_INCLUDED
/* Note: Compiler will complain if this does not match archive.h! */
-#define ARCHIVE_VERSION_NUMBER 3008007
+#define ARCHIVE_VERSION_NUMBER 3008009
/*
* Note: archive_entry.h is for use outside of libarchive; the
@@ -666,7 +666,7 @@ __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
+ * To retrieve the sparse list, first "reset", then repeatedly ask for the
* "next" entry.
*/
diff --git a/contrib/libarchive/libarchive/archive_entry_link_resolver.c b/contrib/libarchive/libarchive/archive_entry_link_resolver.c
index 77fcad61fdea..947c65fca5fe 100644
--- a/contrib/libarchive/libarchive/archive_entry_link_resolver.c
+++ b/contrib/libarchive/libarchive/archive_entry_link_resolver.c
@@ -41,6 +41,7 @@
#include "archive.h"
#include "archive_entry.h"
+#include "archive_integer.h"
/*
* This is mostly a pretty straightforward hash table implementation.
@@ -78,7 +79,7 @@ struct links_entry {
struct archive_entry_linkresolver {
struct links_entry **buckets;
struct links_entry *spare;
- unsigned long number_entries;
+ size_t number_entries;
size_t number_buckets;
int strategy;
};
@@ -158,13 +159,12 @@ archive_entry_linkresolver_set_strategy(struct archive_entry_linkresolver *res,
void
archive_entry_linkresolver_free(struct archive_entry_linkresolver *res)
{
- struct links_entry *le;
-
if (res == NULL)
return;
- while ((le = next_entry(res, NEXT_ENTRY_ALL)) != NULL)
- archive_entry_free(le->entry);
+ while (next_entry(res, NEXT_ENTRY_ALL) != NULL) {
+ /* Actual freeing done by next_entry() */
+ }
free(res->buckets);
free(res);
}
@@ -382,9 +382,13 @@ insert_entry(struct archive_entry_linkresolver *res,
if (le == NULL)
return (NULL);
le->canonical = archive_entry_clone(entry);
+ if (le->canonical == NULL) {
+ free(le);
+ return (NULL);
+ }
/* If the links cache is getting too full, enlarge the hash table. */
- if (res->number_entries > res->number_buckets * 2)
+ if (res->number_entries / 2 > res->number_buckets)
grow_hash(res);
hash = (size_t)(archive_entry_dev(entry) ^ archive_entry_ino64(entry));
@@ -410,8 +414,7 @@ grow_hash(struct archive_entry_linkresolver *res)
size_t i, bucket;
/* Try to enlarge the bucket list. */
- new_size = res->number_buckets * 2;
- if (new_size < res->number_buckets)
+ if (archive_ckd_mul_size(&new_size, res->number_buckets, 2))
return;
new_buckets = calloc(new_size, sizeof(struct links_entry *));
diff --git a/contrib/libarchive/libarchive/archive_entry_sparse.c b/contrib/libarchive/libarchive/archive_entry_sparse.c
index c430896119fb..1e84ff7f8589 100644
--- a/contrib/libarchive/libarchive/archive_entry_sparse.c
+++ b/contrib/libarchive/libarchive/archive_entry_sparse.c
@@ -127,9 +127,10 @@ archive_entry_sparse_count(struct archive_entry *entry)
int
archive_entry_sparse_reset(struct archive_entry * entry)
{
+ /* Counting can change sparse_head, so do it first */
+ int count = archive_entry_sparse_count(entry);
entry->sparse_p = entry->sparse_head;
-
- return archive_entry_sparse_count(entry);
+ return (count);
}
int
diff --git a/contrib/libarchive/libarchive/archive_entry_strmode.c b/contrib/libarchive/libarchive/archive_entry_strmode.c
index 5faa2faeefa0..22171992dd49 100644
--- a/contrib/libarchive/libarchive/archive_entry_strmode.c
+++ b/contrib/libarchive/libarchive/archive_entry_strmode.c
@@ -28,9 +28,6 @@
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
#include "archive_entry.h"
#include "archive_entry_private.h"
@@ -38,16 +35,10 @@
const char *
archive_entry_strmode(struct archive_entry *entry)
{
- static const mode_t permbits[] =
- { 0400, 0200, 0100, 0040, 0020, 0010, 0004, 0002, 0001 };
char *bp = entry->strmode;
- mode_t mode;
+ mode_t mask, mode;
int i;
- /* Fill in a default string, then selectively override. */
- strcpy(bp, "?rwxrwxrwx ");
-
- mode = archive_entry_mode(entry);
switch (archive_entry_filetype(entry)) {
case AE_IFREG: bp[0] = '-'; break;
case AE_IFBLK: bp[0] = 'b'; break;
@@ -57,30 +48,22 @@ archive_entry_strmode(struct archive_entry *entry)
case AE_IFSOCK: bp[0] = 's'; break;
case AE_IFIFO: bp[0] = 'p'; break;
default:
- if (archive_entry_hardlink(entry) != NULL) {
- bp[0] = 'h';
- break;
- }
+ bp[0] = (archive_entry_hardlink(entry) != NULL) ? 'h' : '?';
+ break;
}
- for (i = 0; i < 9; i++)
- if (!(mode & permbits[i]))
- bp[i+1] = '-';
+ mode = archive_entry_mode(entry);
+ for (i = 0, mask = 0400; i < 9; i++, mask >>= 1)
+ bp[i + 1] = (mode & mask) ? "rwx"[i % 3] : '-';
- if (mode & S_ISUID) {
- if (mode & 0100) bp[3] = 's';
- else bp[3] = 'S';
- }
- if (mode & S_ISGID) {
- if (mode & 0010) bp[6] = 's';
- else bp[6] = 'S';
- }
- if (mode & S_ISVTX) {
- if (mode & 0001) bp[9] = 't';
- else bp[9] = 'T';
- }
- if (archive_entry_acl_types(entry) != 0)
- bp[10] = '+';
+ if (mode & S_ISUID)
+ bp[3] = (mode & 0100) ? 's' : 'S';
+ if (mode & S_ISGID)
+ bp[6] = (mode & 0010) ? 's' : 'S';
+ if (mode & S_ISVTX)
+ bp[9] = (mode & 0001) ? 't' : 'T';
+ bp[10] = (archive_entry_acl_types(entry) != 0) ? '+' : ' ';
+ bp[11] = '\0';
return (bp);
}
diff --git a/contrib/libarchive/libarchive/archive_entry_xattr.c b/contrib/libarchive/libarchive/archive_entry_xattr.c
index b92e1878bc43..7a78f0c3e1ab 100644
--- a/contrib/libarchive/libarchive/archive_entry_xattr.c
+++ b/contrib/libarchive/libarchive/archive_entry_xattr.c
@@ -96,11 +96,11 @@ archive_entry_xattr_add_entry(struct archive_entry *entry,
if ((xp->name = strdup(name)) == NULL)
__archive_errx(1, "Out of memory");
- if ((xp->value = malloc(size)) != NULL) {
- memcpy(xp->value, value, size);
- xp->size = size;
- } else
- xp->size = 0;
+ if ((xp->value = malloc(size)) == NULL)
+ __archive_errx(1, "Out of memory");
+
+ memcpy(xp->value, value, size);
+ xp->size = size;
xp->next = entry->xattr_head;
entry->xattr_head = xp;
diff --git a/contrib/libarchive/libarchive/archive_hmac.c b/contrib/libarchive/libarchive/archive_hmac.c
index 458092f41b29..e1e8f05ff0d3 100644
--- a/contrib/libarchive/libarchive/archive_hmac.c
+++ b/contrib/libarchive/libarchive/archive_hmac.c
@@ -74,7 +74,7 @@ __hmac_sha1_cleanup(archive_hmac_sha1_ctx *ctx)
memset(ctx, 0, sizeof(*ctx));
}
-#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
#ifndef BCRYPT_HASH_REUSABLE_FLAG
# define BCRYPT_HASH_REUSABLE_FLAG 0x00000020
diff --git a/contrib/libarchive/libarchive/archive_hmac_private.h b/contrib/libarchive/libarchive/archive_hmac_private.h
index 36b8e3320e38..af00beadb588 100644
--- a/contrib/libarchive/libarchive/archive_hmac_private.h
+++ b/contrib/libarchive/libarchive/archive_hmac_private.h
@@ -52,7 +52,7 @@ int __libarchive_hmac_build_hack(void);
typedef CCHmacContext archive_hmac_sha1_ctx;
-#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
+#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
#include <bcrypt.h>
typedef struct {
diff --git a/contrib/libarchive/libarchive/archive_integer.h b/contrib/libarchive/libarchive/archive_integer.h
new file mode 100644
index 000000000000..1e715927901e
--- /dev/null
+++ b/contrib/libarchive/libarchive/archive_integer.h
@@ -0,0 +1,267 @@
+/*-
+ * Copyright (c) 2026 Tobias Stoeckmann
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef ARCHIVE_INTEGER_H_INCLUDED
+#define ARCHIVE_INTEGER_H_INCLUDED
+
+#include "archive_platform.h"
+
+/* Note: This is a purely internal header! */
+/* Do not use this outside of libarchive internal code! */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifdef HAVE_INTSAFE_H
+#define ENABLE_INTSAFE_SIGNED_FUNCTIONS
+#include <intsafe.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_STDCKDINT_H
+#include <stdckdint.h>
+#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
+
+#ifdef HAVE_STDCKDINT_H
+#define USE_STDCKDINT 1
+#elif (__GNUC__ >= 5 && !defined(__INTEL_COMPILER))
+#define USE_BUILTIN 1
+#elif __has_builtin(__builtin_add_overflow)
+#define USE_BUILTIN 1
+#elif defined HAVE_INTSAFE_H
+#define USE_INTSAFE 1
+#endif
+
+/*
+ * Disabling inline keyword for compilers known to choke on it:
+ * - Watcom C++ in C code. (For any version?)
+ * - SGI MIPSpro
+ * - Microsoft Visual C++ 6.0 (supposedly newer versions too)
+ * - IBM VisualAge 6 (XL v6)
+ * - Sun WorkShop C (SunPro) before 5.9
+ */
+#if defined(__WATCOMC__) || defined(__sgi) || defined(__hpux) || defined(__BORLANDC__)
+#define inline
+#elif defined(__IBMC__) && __IBMC__ < 700
+#define inline
+#elif defined(__SUNPRO_C) && __SUNPRO_C < 0x590
+#define inline
+#elif defined(_MSC_VER) || defined(__osf__)
+#define inline __inline
+#endif
+
+/* Returns 0 on success, a non-zero value otherwise. */
+static inline int
+archive_ckd_add_i64(int64_t *result, int64_t a, int64_t b)
+{
+#if USE_STDCKDINT
+ return ckd_add(result, a, b);
+#elif USE_BUILTIN
+ return __builtin_add_overflow(a, b, result);
+#elif USE_INTSAFE
+ LONGLONG res;
+ int ret;
+
+ ret = LongLongAdd(a, b, &res);
+ *result = (int64_t)res;
+ return ret;
+#else
+ if ((b > 0 && a > INT64_MAX - b) ||
+ (b < 0 && a < INT64_MIN - b))
+ return 1;
+
+ *result = a + b;
+ return 0;
+#endif
+}
+
+/* Returns 0 on success, a non-zero value otherwise. */
+static inline int
+archive_ckd_add_size(size_t *result, size_t a, size_t b)
+{
+#if USE_STDCKDINT
+ return ckd_add(result, a, b);
+#elif USE_BUILTIN
+ return __builtin_add_overflow(a, b, result);
+#elif USE_INTSAFE
+ return SizeTAdd(a, b, result);
+#else
+ if (a > SIZE_MAX - b)
+ return 1;
+ *result = a + b;
+ return 0;
+#endif
+}
+
+/* Returns 0 on success, a non-zero value otherwise. */
+static inline int
+archive_ckd_add_u64(uint64_t *result, uint64_t a, uint64_t b)
+{
+#if USE_STDCKDINT
+ return ckd_add(result, a, b);
+#elif USE_BUILTIN
+ return __builtin_add_overflow(a, b, result);
+#elif USE_INTSAFE
+ ULONGLONG res;
+ int ret;
+
+ ret = ULongLongAdd(a, b, &res);
+ *result = (uint64_t)res;
+ return ret;
+#else
+ if (a > UINT64_MAX - b)
+ return 1;
+ *result = a + b;
+ return 0;
+#endif
+}
+
+/* Returns 0 on success, a non-zero value otherwise. */
+static inline int
+archive_ckd_mul_i64(int64_t *result, int64_t a, int64_t b)
+{
+#if USE_STDCKDINT
+ return ckd_mul(result, a, b);
+#elif USE_BUILTIN
+ return __builtin_mul_overflow(a, b, result);
+#elif USE_INTSAFE
+ LONGLONG res;
+ int ret;
+
+ ret = LongLongMult(a, b, &res);
+ *result = (int64_t)res;
+ return ret;
+#else
+ if ((a > 0 && b > 0 && a > INT64_MAX / b) ||
+ (a < 0 && b > 0 && a < INT64_MIN / b) ||
+ (a > 0 && b < 0 && b < INT64_MIN / a) ||
+ (a < 0 && b < 0 && a < INT64_MAX / b))
+ return 1;
+
+ *result = a * b;
+ return 0;
+#endif
+}
+
+/* Returns 0 on success, a non-zero value otherwise. */
+static inline int
+archive_ckd_mul_size(size_t *result, size_t a, size_t b)
+{
+#if USE_STDCKDINT
+ return ckd_mul(result, a, b);
+#elif USE_BUILTIN
+ return __builtin_mul_overflow(a, b, result);
+#elif USE_INTSAFE
+ return SizeTMult(a, b, result);
+#else
+ if (b != 0 && a > SIZE_MAX / b)
+ return 1;
+ *result = a * b;
+ return 0;
+#endif
+}
+
+/* Returns 0 on success, a non-zero value otherwise. */
+static inline int
+archive_ckd_mul_u64(uint64_t *result, uint64_t a, uint64_t b)
+{
+#if USE_STDCKDINT
+ return ckd_mul(result, a, b);
+#elif USE_BUILTIN
+ return __builtin_mul_overflow(a, b, result);
+#elif USE_INTSAFE
+ ULONGLONG res;
+ int ret;
+
+ ret = ULongLongMult(a, b, &res);
+ *result = (uint64_t)res;
+ return ret;
+#else
+ if (b != 0 && a > UINT64_MAX / b)
+ return 1;
+ *result = a * b;
+ return 0;
+#endif
+}
+
+/* Returns 0 on success, a non-zero value otherwise. */
+static inline int
+archive_ckd_sub_i64(int64_t *result, int64_t a, int64_t b)
+{
+#if USE_STDCKDINT
+ return ckd_sub(result, a, b);
+#elif USE_BUILTIN
+ return __builtin_sub_overflow(a, b, result);
+#elif USE_INTSAFE
+ LONGLONG res;
+ int ret;
+
+ ret = LongLongSub(a, b, &res);
+ *result = (int64_t)res;
+ return ret;
+#else
+ if ((b > 0 && a < INT64_MIN + b) ||
+ (b < 0 && a > INT64_MAX + b))
+ return 1;
+
+ *result = a - b;
+ return 0;
+#endif
+}
+
+#if !defined(TIME_MAX)
+#define TIME_MAX (((time_t)0 < (time_t)-1) ? (time_t)~0 : \
+ sizeof(time_t) == sizeof(long long) ? (time_t)LLONG_MAX : \
+ sizeof(time_t) == sizeof(long) ? (time_t)LONG_MAX : \
+ sizeof(time_t) == sizeof(int) ? (time_t)INT_MAX : \
+ sizeof(time_t) == sizeof(short) ? (time_t)SHRT_MAX : \
+ 1 /* I give up */)
+#endif
+#if !defined(TIME_MIN)
+#define TIME_MIN (((time_t)0 < (time_t)-1) ? (time_t)0 : \
+ sizeof(time_t) == sizeof(long long) ? (time_t)LLONG_MIN : \
+ sizeof(time_t) == sizeof(long) ? (time_t)LONG_MIN : \
+ sizeof(time_t) == sizeof(int) ? (time_t)INT_MIN : \
+ sizeof(time_t) == sizeof(short) ? (time_t)SHRT_MIN : \
+ -1 /* I give up */)
+#endif
+
+#endif
diff --git a/contrib/libarchive/libarchive/archive_match.c b/contrib/libarchive/libarchive/archive_match.c
index 51a0e3fd5778..ecd470bd15dd 100644
--- a/contrib/libarchive/libarchive/archive_match.c
+++ b/contrib/libarchive/libarchive/archive_match.c
@@ -40,6 +40,7 @@
#endif
#include "archive.h"
+#include "archive_integer.h"
#include "archive_private.h"
#include "archive_entry.h"
#include "archive_pathmatch.h"
@@ -216,6 +217,14 @@ error_nomem(struct archive_match *a)
return (ARCHIVE_FATAL);
}
+static int
+error_pattern(struct archive_match *a)
+{
+ archive_set_error(&(a->archive), EINVAL, "Failed to apply pattern");
+ a->archive.state = ARCHIVE_STATE_FATAL;
+ return (ARCHIVE_FATAL);
+}
+
/*
* Create an ARCHIVE_MATCH object.
*/
@@ -269,7 +278,7 @@ archive_match_free(struct archive *_a)
*
* Returns 1 if archive entry is excluded.
* Returns 0 if archive entry is not excluded.
- * Returns <0 if something error happened.
+ * Returns <0 if some error happened.
*/
int
archive_match_excluded(struct archive *_a, struct archive_entry *entry)
@@ -293,6 +302,8 @@ archive_match_excluded(struct archive *_a, struct archive_entry *entry)
#else
r = path_excluded(a, 1, archive_entry_pathname(entry));
#endif
+ if (r < 0)
+ return (error_pattern(a));
if (r != 0)
return (r);
}
@@ -449,13 +460,14 @@ archive_match_include_pattern_from_file_w(struct archive *_a,
*
* Returns 1 if archive entry is excluded.
* Returns 0 if archive entry is not excluded.
- * Returns <0 if something error happened.
+ * Returns <0 if some error happened.
*/
int
archive_match_path_excluded(struct archive *_a,
struct archive_entry *entry)
{
struct archive_match *a;
+ int r;
archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
ARCHIVE_STATE_NEW, "archive_match_path_excluded");
@@ -471,10 +483,13 @@ archive_match_path_excluded(struct archive *_a,
if ((a->setflag & PATTERN_IS_SET) == 0)
return (0);
#if defined(_WIN32) && !defined(__CYGWIN__)
- return (path_excluded(a, 0, archive_entry_pathname_w(entry)));
+ r = path_excluded(a, 0, archive_entry_pathname_w(entry));
#else
- return (path_excluded(a, 1, archive_entry_pathname(entry)));
+ r = path_excluded(a, 1, archive_entry_pathname(entry));
#endif
+ if (r < 0)
+ return (error_pattern(a));
+ return (r);
}
/*
@@ -629,11 +644,12 @@ add_pattern_from_file(struct archive_match *a, struct match_list *mlist,
}
r = archive_read_next_header(ar, &ae);
if (r != ARCHIVE_OK) {
- archive_read_free(ar);
if (r == ARCHIVE_EOF) {
+ archive_read_free(ar);
return (ARCHIVE_OK);
} else {
archive_copy_error(&(a->archive), ar);
+ archive_read_free(ar);
return (r);
}
}
@@ -1007,7 +1023,7 @@ archive_match_exclude_entry(struct archive *_a, int flag,
*
* Returns 1 if archive entry is excluded.
* Returns 0 if archive entry is not excluded.
- * Returns <0 if something error happened.
+ * Returns <0 if some error happened.
*/
int
archive_match_time_excluded(struct archive *_a,
@@ -1653,7 +1669,7 @@ archive_match_include_gname_w(struct archive *_a, const wchar_t *gname)
*
* Returns 1 if archive entry is excluded.
* Returns 0 if archive entry is not excluded.
- * Returns <0 if something error happened.
+ * Returns <0 if some error happened.
*/
int
archive_match_owner_excluded(struct archive *_a,
@@ -1684,15 +1700,22 @@ add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id)
if (ids->count + 1 >= ids->size) {
void *p;
+ size_t alloc_size, new_size;
if (ids->size == 0)
- ids->size = 8;
- else
- ids->size *= 2;
- p = realloc(ids->ids, sizeof(*ids->ids) * ids->size);
+ new_size = 8;
+ else {
+ if (archive_ckd_mul_size(&new_size, ids->size, 2))
+ return (error_nomem(a));
+ }
+ if (archive_ckd_mul_size(&alloc_size,
+ new_size, sizeof(*ids->ids)))
+ return (error_nomem(a));
+ p = realloc(ids->ids, alloc_size);
if (p == NULL)
return (error_nomem(a));
ids->ids = (int64_t *)p;
+ ids->size = new_size;
}
/* Find an insert point. */
diff --git a/contrib/libarchive/libarchive/archive_options.c b/contrib/libarchive/libarchive/archive_options.c
index 66491bd4183b..24480b97e25d 100644
--- a/contrib/libarchive/libarchive/archive_options.c
+++ b/contrib/libarchive/libarchive/archive_options.c
@@ -31,8 +31,8 @@
#include "archive_options_private.h"
-static const char *
-parse_option(const char **str,
+static char *
+parse_option(char **str,
const char **mod, const char **opt, const char **val);
int
@@ -102,8 +102,8 @@ _archive_set_options(struct archive *a, const char *options,
unsigned int magic, const char *fn, option_handler use_option)
{
int allok = 1, anyok = 0, ignore_mod_err = 0, r;
- char *data;
- const char *s, *mod, *opt, *val;
+ char *data, *s;
+ const char *mod, *opt, *val;
archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
@@ -115,7 +115,7 @@ _archive_set_options(struct archive *a, const char *options,
ENOMEM, "Out of memory adding file to list");
return (ARCHIVE_FATAL);
}
- s = (const char *)data;
+ s = data;
do {
mod = opt = val = NULL;
@@ -167,11 +167,11 @@ _archive_set_options(struct archive *a, const char *options,
return allok ? ARCHIVE_OK : anyok ? ARCHIVE_WARN : ARCHIVE_FAILED;
}
-static const char *
-parse_option(const char **s, const char **m, const char **o, const char **v)
+static char *
+parse_option(char **s, const char **m, const char **o, const char **v)
{
- const char *end, *mod, *opt, *val;
- char *p;
+ const char *mod, *val;
+ char *end, *opt, *p;
end = NULL;
mod = NULL;
@@ -182,7 +182,7 @@ parse_option(const char **s, const char **m, const char **o, const char **v)
if (p != NULL) {
*p = '\0';
- end = ((const char *)p) + 1;
+ end = p + 1;
}
if (0 == strlen(opt)) {
diff --git a/contrib/libarchive/libarchive/archive_pack_dev.c b/contrib/libarchive/libarchive/archive_pack_dev.c
index 3c6209b98405..e29351292895 100644
--- a/contrib/libarchive/libarchive/archive_pack_dev.c
+++ b/contrib/libarchive/libarchive/archive_pack_dev.c
@@ -319,7 +319,7 @@ compare_format(const void *key, const void *element)
pack_t *
pack_find(const char *name)
{
- struct format *format;
+ const struct format *format;
format = bsearch(name, formats,
sizeof(formats)/sizeof(formats[0]),
diff --git a/contrib/libarchive/libarchive/archive_parse_date.c b/contrib/libarchive/libarchive/archive_parse_date.c
index d9e968387d34..c1b0f1831165 100644
--- a/contrib/libarchive/libarchive/archive_parse_date.c
+++ b/contrib/libarchive/libarchive/archive_parse_date.c
@@ -36,6 +36,7 @@
#include <time.h>
#include "archive.h"
+#include "archive_integer.h"
/* Basic time units. */
#define EPOCH 1970
@@ -49,7 +50,7 @@ enum DSTMODE { DSTon, DSToff, DSTmaybe };
enum { tAM, tPM };
/* Token types returned by nexttoken() */
enum { tAGO = 260, tDAY, tDAYZONE, tAMPM, tMONTH, tMONTH_UNIT, tSEC_UNIT,
- tUNUMBER, tZONE, tDST };
+ tUNUMBER, tZONE, tDST, tERROR };
struct token { int token; time_t value; };
/*
@@ -818,20 +819,33 @@ RelativeMonth(time_t Start, time_t Timezone, time_t RelMonth)
}
/*
- * Parses and consumes an unsigned number.
- * Returns 1 if any number is parsed. Otherwise, *value is unchanged.
+ * Parses and consumes an unsigned 64-bit number.
+ * Returns UINT64_MAX if the number overflows.
*/
-static char
-consume_unsigned_number(const char **in, time_t *value)
-{
- char c;
- if (isdigit((unsigned char)(c = **in))) {
- for (*value = 0; isdigit((unsigned char)(c = *(*in)++)); )
- *value = 10 * *value + c - '0';
- (*in)--;
- return 1;
+static uint64_t
+consume_unsigned_number(const char **in) {
+ uint64_t value = 0;
+ unsigned char c;
+
+ /* Get the first character, abort if it's not a digit */
+ c = (unsigned char)(**in);
+ if (c < '0' || c > '9') {
+ return UINT64_MAX;
}
- return 0;
+
+ /* Fold digits into the value, abort on overflow */
+ while (c >= '0' && c <= '9') {
+ unsigned char digit = c - '0';
+
+ /* Return error if the result would overflow UINT64_MAX */
+ if (archive_ckd_mul_u64(&value, value, 10) ||
+ archive_ckd_add_u64(&value, value, digit)) {
+ return UINT64_MAX;
+ }
+ (*in)++;
+ c = (unsigned char)(**in);
+ }
+ return value;
}
/*
@@ -906,12 +920,19 @@ nexttoken(const char **in, time_t *value)
}
/*
- * Not in the word table, maybe it's a number. Note:
- * Because '-' and '+' have other special meanings, I
- * don't deal with signed numbers here.
+ * Not in the word table. If it starts with a digit,
+ * it must be a number. Note: Because '-' and '+' have
+ * other special meanings, I don't deal with signed
+ * numbers here.
*/
- if (consume_unsigned_number(in, value)) {
- return (tUNUMBER);
+ if (isdigit((unsigned char)(**in))) {
+ uint64_t val = consume_unsigned_number(in);
+ if (val > 9999) {
+ return (tERROR);
+ } else {
+ *value = val;
+ return (tUNUMBER);
+ }
}
return *(*in)++;
@@ -949,6 +970,7 @@ difftm (struct tm *a, struct tm *b)
static time_t
parse_unix_epoch(const char *p)
{
+ uint64_t val;
time_t epoch;
/* may begin with + */
@@ -957,12 +979,18 @@ parse_unix_epoch(const char *p)
}
/* followed by some number */
- if (!consume_unsigned_number(&p, &epoch))
+ val = consume_unsigned_number(&p);
+ /* Truncate to time_t */
+ epoch = (time_t)val;
+ /* If truncated value is different, then
+ * the value is too large for `time_t`. */
+ if (epoch < 0 || (uint64_t)epoch != val) {
return (time_t)-1;
-
- /* ...and nothing else */
- if (*p != '\0')
+ }
+ /* If there's any more characters, fail. */
+ if (*p != '\0') {
return (time_t)-1;
+ }
return epoch;
}
diff --git a/contrib/libarchive/libarchive/archive_pathmatch.c b/contrib/libarchive/libarchive/archive_pathmatch.c
index db0d2b791adf..46bdb51056a7 100644
--- a/contrib/libarchive/libarchive/archive_pathmatch.c
+++ b/contrib/libarchive/libarchive/archive_pathmatch.c
@@ -35,6 +35,8 @@
#include "archive_pathmatch.h"
+#define MAX_RECURSION 100
+
/*
* Check whether a character 'c' is matched by a list specification [...]:
* * Leading '!' or '^' negates the class.
@@ -167,9 +169,13 @@ pm_slashskip_w(const wchar_t *s) {
}
static int
-pm(const char *p, const char *s, int flags)
+pm(const char *p, const char *s, int flags, int depth)
{
const char *end;
+ int r;
+
+ if (depth > MAX_RECURSION)
+ return (-1);
/*
* Ignore leading './', './/', '././', etc.
@@ -202,8 +208,9 @@ pm(const char *p, const char *s, int flags)
if (*p == '\0')
return (1);
while (*s) {
- if (pm(p, s, flags))
- return (1);
+ r = pm(p, s, flags, depth + 1);
+ if (r)
+ return (r);
++s;
}
return (0);
@@ -220,7 +227,7 @@ pm(const char *p, const char *s, int flags)
}
if (*end == ']') {
/* We found [...], try to match it. */
- if (!pm_list(p + 1, end, *s, flags))
+ if (*s == '\0' || !pm_list(p + 1, end, *s, flags))
return (0);
p = end; /* Jump to trailing ']' char. */
break;
@@ -272,9 +279,13 @@ pm(const char *p, const char *s, int flags)
}
static int
-pm_w(const wchar_t *p, const wchar_t *s, int flags)
+pm_w(const wchar_t *p, const wchar_t *s, int flags, int depth)
{
const wchar_t *end;
+ int r;
+
+ if (depth > MAX_RECURSION)
+ return (-1);
/*
* Ignore leading './', './/', '././', etc.
@@ -307,8 +318,9 @@ pm_w(const wchar_t *p, const wchar_t *s, int flags)
if (*p == L'\0')
return (1);
while (*s) {
- if (pm_w(p, s, flags))
- return (1);
+ r = pm_w(p, s, flags, depth + 1);
+ if (r)
+ return (r);
++s;
}
return (0);
@@ -325,7 +337,7 @@ pm_w(const wchar_t *p, const wchar_t *s, int flags)
}
if (*end == L']') {
/* We found [...], try to match it. */
- if (!pm_list_w(p + 1, end, *s, flags))
+ if (*s == L'\0' || !pm_list_w(p + 1, end, *s, flags))
return (0);
p = end; /* Jump to trailing ']' char. */
break;
@@ -387,7 +399,7 @@ __archive_pathmatch(const char *p, const char *s, int flags)
return (0);
/* Leading '^' anchors the start of the pattern. */
- if (*p == '^') {
+ if ((flags & PATHMATCH_NO_ANCHOR_START) && *p == '^') {
++p;
flags &= ~PATHMATCH_NO_ANCHOR_START;
}
@@ -401,22 +413,25 @@ __archive_pathmatch(const char *p, const char *s, int flags)
++p;
while (*s == '/')
++s;
- return (pm(p, s, flags));
+ return (pm(p, s, flags, 0));
}
/* If start is unanchored, try to match start of each path element. */
if (flags & PATHMATCH_NO_ANCHOR_START) {
for ( ; s != NULL; s = strchr(s, '/')) {
+ int r;
+
if (*s == '/')
s++;
- if (pm(p, s, flags))
- return (1);
+ r = pm(p, s, flags, 0);
+ if (r)
+ return (r);
}
return (0);
}
/* Default: Match from beginning. */
- return (pm(p, s, flags));
+ return (pm(p, s, flags, 0));
}
int
@@ -429,7 +444,7 @@ __archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags)
return (0);
/* Leading '^' anchors the start of the pattern. */
- if (*p == L'^') {
+ if ((flags & PATHMATCH_NO_ANCHOR_START) && *p == L'^') {
++p;
flags &= ~PATHMATCH_NO_ANCHOR_START;
}
@@ -443,20 +458,23 @@ __archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags)
++p;
while (*s == L'/')
++s;
- return (pm_w(p, s, flags));
+ return (pm_w(p, s, flags, 0));
}
/* If start is unanchored, try to match start of each path element. */
if (flags & PATHMATCH_NO_ANCHOR_START) {
for ( ; s != NULL; s = wcschr(s, L'/')) {
+ int r;
+
if (*s == L'/')
s++;
- if (pm_w(p, s, flags))
- return (1);
+ r = pm_w(p, s, flags, 0);
+ if (r)
+ return (r);
}
return (0);
}
/* Default: Match from beginning. */
- return (pm_w(p, s, flags));
+ return (pm_w(p, s, flags, 0));
}
diff --git a/contrib/libarchive/libarchive/archive_private.h b/contrib/libarchive/libarchive/archive_private.h
index 3a926c6886ad..0f068639b9cc 100644
--- a/contrib/libarchive/libarchive/archive_private.h
+++ b/contrib/libarchive/libarchive/archive_private.h
@@ -61,12 +61,38 @@
#define ARCHIVE_READ_DISK_MAGIC (0xbadb0c5U)
#define ARCHIVE_MATCH_MAGIC (0xcad11c9U)
+/*
+ * Having the state be a bitmask makes it easy to check
+ * for combinations of allowed states. These should
+ * generally only be used in public API entry points,
+ * primarily in archive_read.c, archive_write.c, etc.
+ * Internal callbacks can rely on the core machinery
+ * to only call them when appropriate.
+ *
+ * Generally checked via `__archive_check_magic()`.
+ */
+
+/* Newly created archive object, not yet opened */
#define ARCHIVE_STATE_NEW 1U
+/* Archive is ready to read a header. */
#define ARCHIVE_STATE_HEADER 2U
+/* A header has been read: client can ask for data
+ * or they can ask for the next header and
+ * we'll automatically skip the remaining data. */
#define ARCHIVE_STATE_DATA 4U
+/* Similar to STATE_DATA but after a FAILED header:
+ * the client may not read data, but they may ask
+ * for the next header and we'll recover. */
+#define ARCHIVE_STATE_DATA_RECOVERY 8U
+/* End-of-archive has been reached. Client can only
+ * close or free the archive. */
#define ARCHIVE_STATE_EOF 0x10U
+/* Archive is closed; client is only allowed to free the archive. */
#define ARCHIVE_STATE_CLOSED 0x20U
+/* Archive is in a FATAL error state: a close request
+ * is permitted but ignored. */
#define ARCHIVE_STATE_FATAL 0x8000U
+/* Any valid (non-fatal) state. */
#define ARCHIVE_STATE_ANY (0xFFFFU & ~ARCHIVE_STATE_FATAL)
struct archive_vtable {
diff --git a/contrib/libarchive/libarchive/archive_random.c b/contrib/libarchive/libarchive/archive_random.c
index 8c48d2d3b5a9..28cba00bd3cd 100644
--- a/contrib/libarchive/libarchive/archive_random.c
+++ b/contrib/libarchive/libarchive/archive_random.c
@@ -58,18 +58,12 @@ static void la_arc4random_buf(void *, size_t);
#include "archive_random_private.h"
#if defined(_WIN32) && !defined(__CYGWIN__)
-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
-/* don't use bcrypt when XP needs to be supported */
#include <bcrypt.h>
/* Common in other bcrypt implementations, but missing from VS2008. */
#ifndef BCRYPT_SUCCESS
#define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS)
#endif
-
-#elif defined(HAVE_WINCRYPT_H)
-#include <wincrypt.h>
-#endif
#endif
#ifndef O_CLOEXEC
@@ -85,7 +79,6 @@ int
archive_random(void *buf, size_t nbytes)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
-# if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
NTSTATUS status;
BCRYPT_ALG_HANDLE hAlg;
@@ -98,25 +91,6 @@ archive_random(void *buf, size_t nbytes)
return ARCHIVE_FAILED;
return ARCHIVE_OK;
-# else
- HCRYPTPROV hProv;
- BOOL success;
-
- success = CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
- CRYPT_VERIFYCONTEXT);
- if (!success && GetLastError() == (DWORD)NTE_BAD_KEYSET) {
- success = CryptAcquireContext(&hProv, NULL, NULL,
- PROV_RSA_FULL, CRYPT_NEWKEYSET);
- }
- if (success) {
- success = CryptGenRandom(hProv, (DWORD)nbytes, (BYTE*)buf);
- CryptReleaseContext(hProv, 0);
- if (success)
- return ARCHIVE_OK;
- }
- /* TODO: Does this case really happen? */
- return ARCHIVE_FAILED;
-# endif
#elif !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__))
la_arc4random_buf(buf, nbytes);
return ARCHIVE_OK;
diff --git a/contrib/libarchive/libarchive/archive_read.c b/contrib/libarchive/libarchive/archive_read.c
index e5f89bdc8772..e844e42d1ac9 100644
--- a/contrib/libarchive/libarchive/archive_read.c
+++ b/contrib/libarchive/libarchive/archive_read.c
@@ -36,6 +36,9 @@
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
@@ -49,6 +52,7 @@
#include "archive.h"
#include "archive_entry.h"
+#include "archive_integer.h"
#include "archive_private.h"
#include "archive_read_private.h"
@@ -99,7 +103,12 @@ archive_read_new(void)
a->archive.state = ARCHIVE_STATE_NEW;
a->entry = archive_entry_new2(&a->archive);
+ if (a->entry == NULL) {
+ free(a);
+ return (NULL);
+ }
a->archive.vtable = &archive_read_vtable;
+ a->entry_bytes_declared = -1;
a->passphrases.last = &a->passphrases.first;
@@ -131,12 +140,16 @@ archive_read_open(struct archive *a, void *client_data,
archive_open_callback *client_opener, archive_read_callback *client_reader,
archive_close_callback *client_closer)
{
+ int r;
+
/* Old archive_read_open() is just a thin shell around
* archive_read_open1. */
archive_read_set_open_callback(a, client_opener);
archive_read_set_read_callback(a, client_reader);
archive_read_set_close_callback(a, client_closer);
- archive_read_set_callback_data(a, client_data);
+ r = archive_read_set_callback_data(a, client_data);
+ if (r < 0)
+ return (r);
return archive_read_open1(a);
}
@@ -148,9 +161,13 @@ archive_read_open2(struct archive *a, void *client_data,
archive_skip_callback *client_skipper,
archive_close_callback *client_closer)
{
+ int r;
+
/* Old archive_read_open2() is just a thin shell around
* archive_read_open1. */
- archive_read_set_callback_data(a, client_data);
+ r = archive_read_set_callback_data(a, client_data);
+ if (r < 0)
+ return (r);
archive_read_set_open_callback(a, client_opener);
archive_read_set_read_callback(a, client_reader);
archive_read_set_skip_callback(a, client_skipper);
@@ -159,28 +176,28 @@ archive_read_open2(struct archive *a, void *client_data,
}
static ssize_t
-client_read_proxy(struct archive_read_filter *self, const void **buff)
+client_read_proxy(struct archive_read_filter *f, const void **buff)
{
ssize_t r;
- r = (self->archive->client.reader)(&self->archive->archive,
- self->data, buff);
+ r = (f->archive->client.reader)(&f->archive->archive,
+ f->data, buff);
return (r);
}
static int64_t
-client_skip_proxy(struct archive_read_filter *self, int64_t request)
+client_skip_proxy(struct archive_read_filter *f, int64_t request)
{
if (request < 0)
__archive_errx(1, "Negative skip requested");
if (request == 0)
return 0;
- if (self->archive->client.skipper != NULL) {
+ if (f->archive->client.skipper != NULL) {
int64_t total = 0;
for (;;) {
int64_t get, ask = request;
- get = (self->archive->client.skipper)
- (&self->archive->archive, self->data, ask);
+ get = (f->archive->client.skipper)
+ (&f->archive->archive, f->data, ask);
total += get;
if (get == 0 || get == request)
return (total);
@@ -188,7 +205,7 @@ client_skip_proxy(struct archive_read_filter *self, int64_t request)
return ARCHIVE_FATAL;
request -= get;
}
- } else if (self->archive->client.seeker != NULL
+ } else if (f->archive->client.seeker != NULL
&& request > 64 * 1024) {
/* If the client provided a seeker but not a skipper,
* we can use the seeker to skip forward.
@@ -201,9 +218,9 @@ client_skip_proxy(struct archive_read_filter *self, int64_t request)
* to just reading and discarding. That's why we
* only do this for skips of over 64k.
*/
- int64_t before = self->position;
- int64_t after = (self->archive->client.seeker)
- (&self->archive->archive, self->data, request, SEEK_CUR);
+ int64_t before = f->position;
+ int64_t after = (f->archive->client.seeker)
+ (&f->archive->archive, f->data, request, SEEK_CUR);
if (after != before + request)
return ARCHIVE_FATAL;
return after - before;
@@ -212,20 +229,20 @@ client_skip_proxy(struct archive_read_filter *self, int64_t request)
}
static int64_t
-client_seek_proxy(struct archive_read_filter *self, int64_t offset, int whence)
+client_seek_proxy(struct archive_read_filter *f, int64_t offset, int whence)
{
/* DO NOT use the skipper here! If we transparently handled
* forward seek here by using the skipper, that will break
* other libarchive code that assumes a successful forward
* seek means it can also seek backwards.
*/
- if (self->archive->client.seeker == NULL) {
- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ if (f->archive->client.seeker == NULL) {
+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
"Current client reader does not support seeking a device");
return (ARCHIVE_FAILED);
}
- return (self->archive->client.seeker)(&self->archive->archive,
- self->data, offset, whence);
+ return (f->archive->client.seeker)(&f->archive->archive,
+ f->data, offset, whence);
}
static int
@@ -247,47 +264,44 @@ read_client_close_proxy(struct archive_read *a)
}
static int
-client_close_proxy(struct archive_read_filter *self)
+client_close_proxy(struct archive_read_filter *f)
{
- return read_client_close_proxy(self->archive);
+ return read_client_close_proxy(f->archive);
}
static int
-client_open_proxy(struct archive_read_filter *self)
+client_switch_proxy(struct archive_read_filter *f, unsigned int iindex)
{
- int r = ARCHIVE_OK;
- if (self->archive->client.opener != NULL)
- r = (self->archive->client.opener)(
- (struct archive *)self->archive, self->data);
- return (r);
-}
+ struct archive_read *a;
+ int r1 = ARCHIVE_OK, r2 = ARCHIVE_OK;
+ void *data2;
-static int
-client_switch_proxy(struct archive_read_filter *self, unsigned int iindex)
-{
- int r1 = ARCHIVE_OK, r2 = ARCHIVE_OK;
- void *data2 = NULL;
+ while (f->upstream != NULL)
+ f = f->upstream;
+ a = f->archive;
/* Don't do anything if already in the specified data node */
- if (self->archive->client.cursor == iindex)
+ if (a->client.cursor == iindex)
return (ARCHIVE_OK);
- self->archive->client.cursor = iindex;
- data2 = self->archive->client.dataset[self->archive->client.cursor].data;
- if (self->archive->client.switcher != NULL)
+ a->client.cursor = iindex;
+ data2 = a->client.dataset[a->client.cursor].data;
+ if (a->client.switcher != NULL)
{
- r1 = r2 = (self->archive->client.switcher)
- ((struct archive *)self->archive, self->data, data2);
- self->data = data2;
+ r1 = r2 = (a->client.switcher)
+ ((struct archive *)a, f->data, data2);
+ f->data = data2;
}
else
{
/* Attempt to call close and open instead */
- if (self->archive->client.closer != NULL)
- r1 = (self->archive->client.closer)
- ((struct archive *)self->archive, self->data);
- self->data = data2;
- r2 = client_open_proxy(self);
+ if (a->client.closer != NULL)
+ r1 = (a->client.closer)
+ ((struct archive *)a, f->data);
+ f->data = data2;
+ if (a->client.opener != NULL)
+ r2 = (a->client.opener)
+ ((struct archive *)a, f->data);
}
return (r1 < r2) ? r1 : r2;
}
@@ -403,7 +417,9 @@ archive_read_add_callback_data(struct archive *_a, void *client_data,
{
struct archive_read *a = (struct archive_read *)_a;
void *p;
+ size_t alloc_size;
unsigned int i;
+ unsigned int nodes;
archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
"archive_read_add_callback_data");
@@ -412,14 +428,26 @@ archive_read_add_callback_data(struct archive *_a, void *client_data,
"Invalid index specified");
return ARCHIVE_FATAL;
}
- p = realloc(a->client.dataset, sizeof(*a->client.dataset)
- * (++(a->client.nodes)));
+
+ if (a->client.nodes == UINT_MAX ||
+ archive_ckd_mul_size(&alloc_size,
+ (size_t)a->client.nodes + 1, sizeof(*a->client.dataset))) {
+ archive_set_error(&a->archive, ENOMEM,
+ "No memory");
+ return ARCHIVE_FATAL;
+ }
+
+ nodes = a->client.nodes + 1;
+ p = realloc(a->client.dataset, alloc_size);
if (p == NULL) {
archive_set_error(&a->archive, ENOMEM,
"No memory");
return ARCHIVE_FATAL;
}
+
a->client.dataset = (struct archive_read_data_node *)p;
+ a->client.nodes = nodes;
+
for (i = a->client.nodes - 1; i > iindex; i--) {
a->client.dataset[i].data = a->client.dataset[i-1].data;
a->client.dataset[i].begin_position = -1;
@@ -454,7 +482,7 @@ int
archive_read_open1(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
- struct archive_read_filter *filter, *tmp;
+ struct archive_read_filter *f, *tmp;
int slot, e = ARCHIVE_OK;
archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
@@ -478,23 +506,23 @@ archive_read_open1(struct archive *_a)
}
}
- filter = calloc(1, sizeof(*filter));
- if (filter == NULL)
+ f = calloc(1, sizeof(*f));
+ if (f == NULL)
return (ARCHIVE_FATAL);
- filter->bidder = NULL;
- filter->upstream = NULL;
- filter->archive = a;
- filter->data = a->client.dataset[0].data;
- filter->vtable = &none_reader_vtable;
- filter->name = "none";
- filter->code = ARCHIVE_FILTER_NONE;
- filter->can_skip = 1;
- filter->can_seek = 1;
+ f->bidder = NULL;
+ f->upstream = NULL;
+ f->archive = a;
+ f->data = a->client.dataset[0].data;
+ f->vtable = &none_reader_vtable;
+ f->name = "none";
+ f->code = ARCHIVE_FILTER_NONE;
+ f->can_skip = 1;
+ f->can_seek = 1;
a->client.dataset[0].begin_position = 0;
if (!a->filter || !a->bypass_filter_bidding)
{
- a->filter = filter;
+ a->filter = f;
/* Build out the input pipeline. */
e = choose_filters(a);
if (e < ARCHIVE_WARN) {
@@ -508,7 +536,7 @@ archive_read_open1(struct archive *_a)
tmp = a->filter;
while (tmp->upstream)
tmp = tmp->upstream;
- tmp->upstream = filter;
+ tmp->upstream = f;
}
if (!a->format)
@@ -543,7 +571,7 @@ choose_filters(struct archive_read *a)
{
int number_bidders, i, bid, best_bid, number_filters;
struct archive_read_filter_bidder *bidder, *best_bidder;
- struct archive_read_filter *filter;
+ struct archive_read_filter *f;
ssize_t avail;
int r;
@@ -575,13 +603,13 @@ choose_filters(struct archive_read *a)
return (ARCHIVE_OK);
}
- filter = calloc(1, sizeof(*filter));
- if (filter == NULL)
+ f = calloc(1, sizeof(*f));
+ if (f == NULL)
return (ARCHIVE_FATAL);
- filter->bidder = best_bidder;
- filter->archive = a;
- filter->upstream = a->filter;
- a->filter = filter;
+ f->bidder = best_bidder;
+ f->archive = a;
+ f->upstream = a->filter;
+ a->filter = f;
r = (best_bidder->vtable->init)(a->filter);
if (r != ARCHIVE_OK) {
__archive_read_free_filters(a);
@@ -611,7 +639,8 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
int r1 = ARCHIVE_OK, r2;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
+ ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA |
+ ARCHIVE_STATE_DATA_RECOVERY,
"archive_read_next_header");
archive_entry_clear(entry);
@@ -620,8 +649,12 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
/*
* If client didn't consume entire data, skip any remainder
* (This is especially important for GNU incremental directories.)
+ * A header that failed to parse (DATA_RECOVERY) still needs the
+ * same treatment: whatever of its body the format reader left
+ * unconsumed must be skipped before we can read the next header.
*/
- if (a->archive.state == ARCHIVE_STATE_DATA) {
+ if (a->archive.state == ARCHIVE_STATE_DATA ||
+ a->archive.state == ARCHIVE_STATE_DATA_RECOVERY) {
r1 = archive_read_data_skip(&a->archive);
if (r1 == ARCHIVE_EOF)
archive_set_error(&a->archive, EIO,
@@ -659,8 +692,26 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
case ARCHIVE_FATAL:
a->archive.state = ARCHIVE_STATE_FATAL;
break;
+ case ARCHIVE_FAILED:
+ /*
+ * This entry's header could not be parsed, so its metadata
+ * cannot be trusted. ARCHIVE_STATE_DATA_RECOVERY still
+ * permits skipping past it (the format reader is
+ * responsible for ensuring that's actually possible), but
+ * blocks archive_read_data() and friends, which all check
+ * for ARCHIVE_STATE_DATA specifically and would otherwise
+ * return content for an entry we don't actually understand.
+ */
+ a->archive.state = ARCHIVE_STATE_DATA_RECOVERY;
+ break;
}
+ if (r2 == ARCHIVE_OK || r2 == ARCHIVE_WARN)
+ a->entry_bytes_declared = archive_entry_size_is_set(entry)
+ ? archive_entry_size(entry) : -1;
+ else
+ a->entry_bytes_declared = -1;
+
__archive_reset_read_data(&a->archive);
a->data_start_node = a->client.cursor;
@@ -749,7 +800,7 @@ archive_read_header_position(struct archive *_a)
/*
* Returns 1 if the archive contains at least one encrypted entry.
- * If the archive format not support encryption at all
+ * If the archive format does 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
@@ -919,7 +970,8 @@ archive_read_data_skip(struct archive *_a)
size_t size;
int64_t offset;
- archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,
+ archive_check_magic(_a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_DATA | ARCHIVE_STATE_DATA_RECOVERY,
"archive_read_data_skip");
if (a->format->read_data_skip != NULL)
@@ -934,7 +986,10 @@ archive_read_data_skip(struct archive *_a)
if (r == ARCHIVE_EOF)
r = ARCHIVE_OK;
- a->archive.state = ARCHIVE_STATE_HEADER;
+ if (r == ARCHIVE_FATAL)
+ a->archive.state = ARCHIVE_STATE_FATAL;
+ else
+ a->archive.state = ARCHIVE_STATE_HEADER;
return (r);
}
@@ -942,17 +997,21 @@ la_int64_t
archive_seek_data(struct archive *_a, int64_t offset, int whence)
{
struct archive_read *a = (struct archive_read *)_a;
+ la_int64_t r;
+
archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,
"archive_seek_data_block");
if (a->format->seek_data == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
- "Internal error: "
- "No format_seek_data_block function registered");
- return (ARCHIVE_FATAL);
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Cannot seek data with this format");
+ return (ARCHIVE_FAILED);
}
- return (a->format->seek_data)(a, offset, whence);
+ r = (a->format->seek_data)(a, offset, whence);
+ if (r == ARCHIVE_FATAL)
+ a->archive.state = ARCHIVE_STATE_FATAL;
+ return (r);
}
/*
@@ -968,6 +1027,8 @@ _archive_read_data_block(struct archive *_a,
const void **buff, size_t *size, int64_t *offset)
{
struct archive_read *a = (struct archive_read *)_a;
+ int r;
+
archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,
"archive_read_data_block");
@@ -975,10 +1036,14 @@ _archive_read_data_block(struct archive *_a,
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Internal error: "
"No format->read_data function registered");
+ a->archive.state = ARCHIVE_STATE_FATAL;
return (ARCHIVE_FATAL);
}
- return (a->format->read_data)(a, buff, size, offset);
+ r = (a->format->read_data)(a, buff, size, offset);
+ if (r == ARCHIVE_FATAL)
+ a->archive.state = ARCHIVE_STATE_FATAL;
+ return (r);
}
static int
@@ -1317,13 +1382,13 @@ __archive_read_ahead(struct archive_read *a, size_t min, ssize_t *avail)
}
const void *
-__archive_read_filter_ahead(struct archive_read_filter *filter,
+__archive_read_filter_ahead(struct archive_read_filter *f,
size_t min, ssize_t *avail)
{
ssize_t bytes_read;
size_t tocopy;
- if (filter->fatal) {
+ if (f->fatal) {
if (avail)
*avail = ARCHIVE_FATAL;
return (NULL);
@@ -1340,79 +1405,79 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
* note that min == 0 is a perfectly well-defined
* request.
*/
- if (filter->avail >= min && filter->avail > 0) {
+ if (f->avail >= min && f->avail > 0) {
if (avail != NULL)
- *avail = filter->avail;
- return (filter->next);
+ *avail = f->avail;
+ return (f->next);
}
/*
* We can satisfy directly from client buffer if everything
* currently in the copy buffer is still in the client buffer.
*/
- if (filter->client_total >= filter->client_avail + filter->avail
- && filter->client_avail + filter->avail >= min) {
+ if (f->client_total >= f->client_avail + f->avail
+ && f->client_avail + f->avail >= min) {
/* "Roll back" to client buffer. */
- filter->client_avail += filter->avail;
- filter->client_next -= filter->avail;
+ f->client_avail += f->avail;
+ f->client_next -= f->avail;
/* Copy buffer is now empty. */
- filter->avail = 0;
- filter->next = filter->buffer;
+ f->avail = 0;
+ f->next = f->buffer;
/* Return data from client buffer. */
if (avail != NULL)
- *avail = filter->client_avail;
- return (filter->client_next);
+ *avail = f->client_avail;
+ return (f->client_next);
}
/* Move data forward in copy buffer if necessary. */
- if (filter->next > filter->buffer &&
- filter->next + min > filter->buffer + filter->buffer_size) {
- if (filter->avail > 0)
- memmove(filter->buffer, filter->next,
- filter->avail);
- filter->next = filter->buffer;
+ if (f->next > f->buffer &&
+ min > f->buffer_size - (f->next - f->buffer)) {
+ if (f->avail > 0)
+ memmove(f->buffer, f->next,
+ f->avail);
+ f->next = f->buffer;
}
/* If we've used up the client data, get more. */
- if (filter->client_avail <= 0) {
- if (filter->end_of_file) {
+ if (f->client_avail <= 0) {
+ if (f->end_of_file) {
if (avail != NULL)
- *avail = filter->avail;
+ *avail = f->avail;
return (NULL);
}
- bytes_read = (filter->vtable->read)(filter,
- &filter->client_buff);
+ bytes_read = (f->vtable->read)(f,
+ &f->client_buff);
if (bytes_read < 0) { /* Read error. */
- filter->client_total = filter->client_avail = 0;
- filter->client_next =
- filter->client_buff = NULL;
- filter->fatal = 1;
+ f->client_total = f->client_avail = 0;
+ f->client_next =
+ f->client_buff = NULL;
+ f->fatal = 1;
if (avail != NULL)
*avail = ARCHIVE_FATAL;
return (NULL);
}
if (bytes_read == 0) {
/* Check for another client object first */
- if (filter->archive->client.cursor !=
- filter->archive->client.nodes - 1) {
- if (client_switch_proxy(filter,
- filter->archive->client.cursor + 1)
+ if (f->archive->client.cursor !=
+ f->archive->client.nodes - 1) {
+ if (client_switch_proxy(f,
+ f->archive->client.cursor + 1)
== ARCHIVE_OK)
continue;
}
/* Premature end-of-file. */
- filter->client_total = filter->client_avail = 0;
- filter->client_next =
- filter->client_buff = NULL;
- filter->end_of_file = 1;
+ f->client_total = f->client_avail = 0;
+ f->client_next =
+ f->client_buff = NULL;
+ f->end_of_file = 1;
/* Return whatever we do have. */
if (avail != NULL)
- *avail = filter->avail;
+ *avail = f->avail;
return (NULL);
}
- filter->client_total = bytes_read;
- filter->client_avail = filter->client_total;
- filter->client_next = filter->client_buff;
+ f->client_total = bytes_read;
+ f->client_avail = f->client_total;
+ f->client_next = f->client_buff;
} else {
/*
* We can't satisfy the request from the copy
@@ -1422,67 +1487,66 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
*/
/* Ensure the buffer is big enough. */
- if (min > filter->buffer_size) {
- size_t s, t;
+ if (min > f->buffer_size) {
+ size_t s;
char *p;
/* Double the buffer; watch for overflow. */
- s = t = filter->buffer_size;
+ s = f->buffer_size;
if (s == 0)
s = min;
while (s < min) {
- t *= 2;
- if (t <= s) { /* Integer overflow! */
+ if (archive_ckd_mul_size(&s, s, 2)) {
+ /* Integer overflow! */
archive_set_error(
- &filter->archive->archive,
+ &f->archive->archive,
ENOMEM,
"Unable to allocate copy"
" buffer");
- filter->fatal = 1;
+ f->fatal = 1;
if (avail != NULL)
*avail = ARCHIVE_FATAL;
return (NULL);
}
- s = t;
}
/* Now s >= min, so allocate a new buffer. */
p = malloc(s);
if (p == NULL) {
archive_set_error(
- &filter->archive->archive,
+ &f->archive->archive,
ENOMEM,
"Unable to allocate copy buffer");
- filter->fatal = 1;
+ f->fatal = 1;
if (avail != NULL)
*avail = ARCHIVE_FATAL;
return (NULL);
}
/* Move data into newly-enlarged buffer. */
- if (filter->avail > 0)
- memmove(p, filter->next, filter->avail);
- free(filter->buffer);
- filter->next = filter->buffer = p;
- filter->buffer_size = s;
+ if (f->avail > 0)
+ memmove(p, f->next, f->avail);
+ free(f->buffer);
+ f->next = f->buffer = p;
+ f->buffer_size = s;
}
/* We can add client data to copy buffer. */
/* First estimate: copy to fill rest of buffer. */
- tocopy = (filter->buffer + filter->buffer_size)
- - (filter->next + filter->avail);
+ tocopy = (f->buffer + f->buffer_size)
+ - (f->next + f->avail);
/* Don't waste time buffering more than we need to. */
- if (tocopy + filter->avail > min)
- tocopy = min - filter->avail;
+ if (tocopy + f->avail > min)
+ tocopy = min - f->avail;
/* Don't copy more than is available. */
- if (tocopy > filter->client_avail)
- tocopy = filter->client_avail;
+ if (tocopy > f->client_avail)
+ tocopy = f->client_avail;
- memcpy(filter->next + filter->avail,
- filter->client_next, tocopy);
+ memcpy(f->next + f->avail,
+ f->client_next, tocopy);
/* Remove this data from client buffer. */
- filter->client_next += tocopy;
- filter->client_avail -= tocopy;
+ f->client_next += tocopy;
+ f->client_avail -= tocopy;
/* add it to copy buffer. */
- filter->avail += tocopy;
+ f->avail += tocopy;
}
}
}
@@ -1497,7 +1561,7 @@ __archive_read_consume(struct archive_read *a, int64_t request)
}
int64_t
-__archive_read_filter_consume(struct archive_read_filter * filter,
+__archive_read_filter_consume(struct archive_read_filter *f,
int64_t request)
{
int64_t skipped;
@@ -1507,13 +1571,13 @@ __archive_read_filter_consume(struct archive_read_filter * filter,
if (request == 0)
return 0;
- skipped = advance_file_pointer(filter, request);
+ skipped = advance_file_pointer(f, request);
if (skipped == request)
return (skipped);
/* We hit EOF before we satisfied the skip request. */
if (skipped < 0) /* Map error code to 0 for error message below. */
skipped = 0;
- archive_set_error(&filter->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Truncated input file (needed %jd bytes, only %jd available)",
(intmax_t)request, (intmax_t)skipped);
@@ -1527,45 +1591,45 @@ __archive_read_filter_consume(struct archive_read_filter * filter,
* Returns a negative value if there's an I/O error.
*/
static int64_t
-advance_file_pointer(struct archive_read_filter *filter, int64_t request)
+advance_file_pointer(struct archive_read_filter *f, int64_t request)
{
int64_t bytes_skipped, total_bytes_skipped = 0;
ssize_t bytes_read;
size_t min;
- if (filter->fatal)
+ if (f->fatal)
return (-1);
/* Use up the copy buffer first. */
- if (filter->avail > 0) {
- min = (size_t)minimum(request, (int64_t)filter->avail);
- filter->next += min;
- filter->avail -= min;
+ if (f->avail > 0) {
+ min = (size_t)minimum(request, (int64_t)f->avail);
+ f->next += min;
+ f->avail -= min;
request -= min;
- filter->position += min;
+ f->position += min;
total_bytes_skipped += min;
}
/* Then use up the client buffer. */
- if (filter->client_avail > 0) {
- min = (size_t)minimum(request, (int64_t)filter->client_avail);
- filter->client_next += min;
- filter->client_avail -= min;
+ if (f->client_avail > 0) {
+ min = (size_t)minimum(request, (int64_t)f->client_avail);
+ f->client_next += min;
+ f->client_avail -= min;
request -= min;
- filter->position += min;
+ f->position += min;
total_bytes_skipped += min;
}
if (request == 0)
return (total_bytes_skipped);
/* If there's an optimized skip function, use it. */
- if (filter->can_skip != 0) {
- bytes_skipped = client_skip_proxy(filter, request);
+ if (f->can_skip != 0) {
+ bytes_skipped = client_skip_proxy(f, request);
if (bytes_skipped < 0) { /* error */
- filter->fatal = 1;
+ f->fatal = 1;
return (bytes_skipped);
}
- filter->position += bytes_skipped;
+ f->position += bytes_skipped;
total_bytes_skipped += bytes_skipped;
request -= bytes_skipped;
if (request == 0)
@@ -1574,37 +1638,37 @@ advance_file_pointer(struct archive_read_filter *filter, int64_t request)
/* Use ordinary reads as necessary to complete the request. */
for (;;) {
- bytes_read = (filter->vtable->read)(filter, &filter->client_buff);
+ bytes_read = (f->vtable->read)(f, &f->client_buff);
if (bytes_read < 0) {
- filter->client_buff = NULL;
- filter->fatal = 1;
+ f->client_buff = NULL;
+ f->fatal = 1;
return (bytes_read);
}
if (bytes_read == 0) {
- if (filter->archive->client.cursor !=
- filter->archive->client.nodes - 1) {
- if (client_switch_proxy(filter,
- filter->archive->client.cursor + 1)
+ if (f->archive->client.cursor !=
+ f->archive->client.nodes - 1) {
+ if (client_switch_proxy(f,
+ f->archive->client.cursor + 1)
== ARCHIVE_OK)
continue;
}
- filter->client_buff = NULL;
- filter->end_of_file = 1;
+ f->client_buff = NULL;
+ f->end_of_file = 1;
return (total_bytes_skipped);
}
if (bytes_read >= request) {
- filter->client_next =
- ((const char *)filter->client_buff) + request;
- filter->client_avail = (size_t)(bytes_read - request);
- filter->client_total = bytes_read;
+ f->client_next =
+ ((const char *)f->client_buff) + request;
+ f->client_avail = (size_t)(bytes_read - request);
+ f->client_total = bytes_read;
total_bytes_skipped += request;
- filter->position += request;
+ f->position += request;
return (total_bytes_skipped);
}
- filter->position += bytes_read;
+ f->position += bytes_read;
total_bytes_skipped += bytes_read;
request -= bytes_read;
}
@@ -1620,23 +1684,23 @@ __archive_read_seek(struct archive_read *a, int64_t offset, int whence)
}
int64_t
-__archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,
+__archive_read_filter_seek(struct archive_read_filter *f, int64_t offset,
int whence)
{
struct archive_read_client *client;
int64_t r;
unsigned int cursor;
- if (filter->closed || filter->fatal)
+ if (f->closed || f->fatal)
return (ARCHIVE_FATAL);
- if (filter->can_seek == 0)
+ if (f->can_seek == 0)
return (ARCHIVE_FAILED);
- client = &(filter->archive->client);
+ client = &(f->archive->client);
switch (whence) {
case SEEK_CUR:
/* Adjust the offset and use SEEK_SET instead */
- offset += filter->position;
+ offset += f->position;
__LA_FALLTHROUGH;
case SEEK_SET:
cursor = 0;
@@ -1653,10 +1717,10 @@ __archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,
client->dataset[++cursor].begin_position = r;
}
while (1) {
- r = client_switch_proxy(filter, cursor);
+ r = client_switch_proxy(f, cursor);
if (r != ARCHIVE_OK)
return r;
- if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0)
+ if ((r = client_seek_proxy(f, 0, SEEK_END)) < 0)
return r;
client->dataset[cursor].total_size = r;
if (client->dataset[cursor].begin_position +
@@ -1671,7 +1735,7 @@ __archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,
if (offset < 0
|| offset > client->dataset[cursor].total_size)
return ARCHIVE_FATAL;
- if ((r = client_seek_proxy(filter, offset, SEEK_SET)) < 0)
+ if ((r = client_seek_proxy(f, offset, SEEK_SET)) < 0)
return r;
break;
@@ -1687,10 +1751,10 @@ __archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,
client->dataset[++cursor].begin_position = r;
}
while (1) {
- r = client_switch_proxy(filter, cursor);
+ r = client_switch_proxy(f, cursor);
if (r != ARCHIVE_OK)
return r;
- if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0)
+ if ((r = client_seek_proxy(f, 0, SEEK_END)) < 0)
return r;
client->dataset[cursor].total_size = r;
r = client->dataset[cursor].begin_position +
@@ -1711,9 +1775,9 @@ __archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,
client->dataset[cursor].total_size;
}
offset = (r + offset) - client->dataset[cursor].begin_position;
- if ((r = client_switch_proxy(filter, cursor)) != ARCHIVE_OK)
+ if ((r = client_switch_proxy(f, cursor)) != ARCHIVE_OK)
return r;
- r = client_seek_proxy(filter, offset, SEEK_SET);
+ r = client_seek_proxy(f, offset, SEEK_SET);
if (r < ARCHIVE_OK)
return r;
break;
@@ -1741,10 +1805,10 @@ __archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,
* size is (r - offset). Can we use that to simplify
* the TODO items above?
*/
- filter->avail = filter->client_avail = 0;
- filter->next = filter->buffer;
- filter->position = r;
- filter->end_of_file = 0;
+ f->avail = f->client_avail = 0;
+ f->next = f->buffer;
+ f->position = r;
+ f->end_of_file = 0;
}
return r;
}
diff --git a/contrib/libarchive/libarchive/archive_read_append_filter.c b/contrib/libarchive/libarchive/archive_read_append_filter.c
index d578b06fe714..8de1b2ea8fba 100644
--- a/contrib/libarchive/libarchive/archive_read_append_filter.c
+++ b/contrib/libarchive/libarchive/archive_read_append_filter.c
@@ -37,9 +37,9 @@ int
archive_read_append_filter(struct archive *_a, int code)
{
int r1, r2, number_bidders, i;
- char str[20];
- struct archive_read_filter_bidder *bidder;
- struct archive_read_filter *filter;
+ const char *str;
+ struct archive_read_filter_bidder *b;
+ struct archive_read_filter *f;
struct archive_read *a = (struct archive_read *)_a;
r2 = (ARCHIVE_OK);
@@ -53,15 +53,15 @@ archive_read_append_filter(struct archive *_a, int code)
r1 = (ARCHIVE_OK);
break;
case ARCHIVE_FILTER_GZIP:
- strcpy(str, "gzip");
+ str = "gzip";
r1 = archive_read_support_filter_gzip(_a);
break;
case ARCHIVE_FILTER_BZIP2:
- strcpy(str, "bzip2");
+ str = "bzip2";
r1 = archive_read_support_filter_bzip2(_a);
break;
case ARCHIVE_FILTER_COMPRESS:
- strcpy(str, "compress (.Z)");
+ str = "compress (.Z)";
r1 = archive_read_support_filter_compress(_a);
break;
case ARCHIVE_FILTER_PROGRAM:
@@ -69,43 +69,43 @@ archive_read_append_filter(struct archive *_a, int code)
"Cannot append program filter using archive_read_append_filter");
return (ARCHIVE_FATAL);
case ARCHIVE_FILTER_LZMA:
- strcpy(str, "lzma");
+ str = "lzma";
r1 = archive_read_support_filter_lzma(_a);
break;
case ARCHIVE_FILTER_XZ:
- strcpy(str, "xz");
+ str = "xz";
r1 = archive_read_support_filter_xz(_a);
break;
case ARCHIVE_FILTER_UU:
- strcpy(str, "uu");
+ str = "uu";
r1 = archive_read_support_filter_uu(_a);
break;
case ARCHIVE_FILTER_RPM:
- strcpy(str, "rpm");
+ str = "rpm";
r1 = archive_read_support_filter_rpm(_a);
break;
case ARCHIVE_FILTER_LZ4:
- strcpy(str, "lz4");
+ str = "lz4";
r1 = archive_read_support_filter_lz4(_a);
break;
case ARCHIVE_FILTER_ZSTD:
- strcpy(str, "zstd");
+ str = "zstd";
r1 = archive_read_support_filter_zstd(_a);
break;
case ARCHIVE_FILTER_LZIP:
- strcpy(str, "lzip");
+ str = "lzip";
r1 = archive_read_support_filter_lzip(_a);
break;
case ARCHIVE_FILTER_LZOP:
- strcpy(str, "lzop");
+ str = "lzop";
r1 = archive_read_support_filter_lzop(_a);
break;
case ARCHIVE_FILTER_LRZIP:
- strcpy(str, "lrzip");
+ str = "lrzip";
r1 = archive_read_support_filter_lrzip(_a);
break;
case ARCHIVE_FILTER_GRZIP:
- strcpy(str, "grzip");
+ str = "grzip";
r1 = archive_read_support_filter_grzip(_a);
break;
default:
@@ -118,30 +118,30 @@ archive_read_append_filter(struct archive *_a, int code)
{
number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);
- bidder = a->bidders;
- for (i = 1; i < number_bidders; i++, bidder++)
+ b = a->bidders;
+ for (i = 1; i < number_bidders; i++, b++)
{
- if (!bidder->name || !strcmp(bidder->name, str))
+ if (!b->name || !strcmp(b->name, str))
break;
}
- if (!bidder->name || strcmp(bidder->name, str))
+ if (!b->name || strcmp(b->name, str))
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Internal error: Unable to append filter");
return (ARCHIVE_FATAL);
}
- filter = calloc(1, sizeof(*filter));
- if (filter == NULL)
+ f = calloc(1, sizeof(*f));
+ if (f == NULL)
{
archive_set_error(&a->archive, ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
- filter->bidder = bidder;
- filter->archive = a;
- filter->upstream = a->filter;
- a->filter = filter;
- r2 = (bidder->vtable->init)(a->filter);
+ f->bidder = b;
+ f->archive = a;
+ f->upstream = a->filter;
+ a->filter = f;
+ r2 = (b->vtable->init)(a->filter);
if (r2 != ARCHIVE_OK) {
__archive_read_free_filters(a);
return (ARCHIVE_FATAL);
@@ -163,8 +163,8 @@ archive_read_append_filter_program_signature(struct archive *_a,
const char *cmd, const void *signature, size_t signature_len)
{
int r, number_bidders, i;
- struct archive_read_filter_bidder *bidder;
- struct archive_read_filter *filter;
+ struct archive_read_filter_bidder *b;
+ struct archive_read_filter *f;
struct archive_read *a = (struct archive_read *)_a;
if (archive_read_support_filter_program_signature(_a, cmd, signature,
@@ -173,36 +173,36 @@ archive_read_append_filter_program_signature(struct archive *_a,
number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);
- bidder = a->bidders;
- for (i = 0; i < number_bidders; i++, bidder++)
+ b = a->bidders;
+ for (i = 0; i < number_bidders; i++, b++)
{
/* Program bidder name set to filter name after initialization */
- if (bidder->data && !bidder->name)
+ if (b->data && !b->name)
break;
}
- if (!bidder->data)
+ if (!b->data)
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Internal error: Unable to append program filter");
return (ARCHIVE_FATAL);
}
- filter = calloc(1, sizeof(*filter));
- if (filter == NULL)
+ f = calloc(1, sizeof(*f));
+ if (f == NULL)
{
archive_set_error(&a->archive, ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
- filter->bidder = bidder;
- filter->archive = a;
- filter->upstream = a->filter;
- a->filter = filter;
- r = (bidder->vtable->init)(a->filter);
+ f->bidder = b;
+ f->archive = a;
+ f->upstream = a->filter;
+ a->filter = f;
+ r = (b->vtable->init)(a->filter);
if (r != ARCHIVE_OK) {
__archive_read_free_filters(a);
return (ARCHIVE_FATAL);
}
- bidder->name = a->filter->name;
+ b->name = a->filter->name;
a->bypass_filter_bidding = 1;
return r;
diff --git a/contrib/libarchive/libarchive/archive_read_data_into_fd.c b/contrib/libarchive/libarchive/archive_read_data_into_fd.c
index 8fd5e12442bc..d92ab9a51253 100644
--- a/contrib/libarchive/libarchive/archive_read_data_into_fd.c
+++ b/contrib/libarchive/libarchive/archive_read_data_into_fd.c
@@ -37,6 +37,7 @@
#include "archive.h"
#include "archive_private.h"
+#include "archive_read_private.h"
/* Maximum amount of data to write at one time. */
#define MAX_WRITE (1024 * 1024)
@@ -46,9 +47,9 @@
*/
static int
pad_to(struct archive *a, int fd, int can_lseek,
- size_t nulls_size, const char *nulls,
- int64_t target_offset, int64_t actual_offset)
+ char **nulls, int64_t target_offset, int64_t actual_offset)
{
+ const size_t nulls_size = 16384;
size_t to_write;
ssize_t bytes_written;
@@ -56,16 +57,26 @@ pad_to(struct archive *a, int fd, int can_lseek,
actual_offset = lseek(fd,
target_offset - actual_offset, SEEK_CUR);
if (actual_offset != target_offset) {
- archive_set_error(a, errno, "Seek error");
+ archive_set_error(a,
+ actual_offset == -1 ? errno : ARCHIVE_ERRNO_MISC,
+ "Seek error");
return (ARCHIVE_FATAL);
}
return (ARCHIVE_OK);
}
+ if (*nulls == NULL) {
+ *nulls = calloc(1, nulls_size);
+ if (*nulls == NULL) {
+ archive_set_error(a, errno, "Out of memory");
+ return (ARCHIVE_FATAL);
+ }
+ }
+
while (target_offset > actual_offset) {
to_write = nulls_size;
if (target_offset < actual_offset + (int64_t)nulls_size)
to_write = (size_t)(target_offset - actual_offset);
- bytes_written = write(fd, nulls, to_write);
+ bytes_written = write(fd, *nulls, to_write);
if (bytes_written < 0) {
archive_set_error(a, errno, "Write error");
return (ARCHIVE_FATAL);
@@ -84,29 +95,48 @@ archive_read_data_into_fd(struct archive *a, int fd)
const void *buff;
size_t size, bytes_to_write;
ssize_t bytes_written;
+ int64_t fd_offset;
int64_t target_offset;
int64_t actual_offset = 0;
+ int64_t declared_size;
int can_lseek;
char *nulls = NULL;
- size_t nulls_size = 16384;
archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,
"archive_read_data_into_fd");
+ declared_size = ((struct archive_read *)a)->entry_bytes_declared;
+
can_lseek = (fstat(fd, &st) == 0) && S_ISREG(st.st_mode);
- if (!can_lseek) {
- nulls = calloc(1, nulls_size);
- if (!nulls) {
- r = ARCHIVE_FATAL;
- goto cleanup;
- }
+ if (can_lseek) {
+ fd_offset = lseek(fd, 0, SEEK_CUR);
+ if (fd_offset == -1)
+ can_lseek = 0;
}
while ((r = archive_read_data_block(a, &buff, &size, &target_offset)) ==
ARCHIVE_OK) {
const char *p = buff;
+ int overran = 0;
+
+ if (declared_size >= 0) {
+ /* We know the expected size, let's enforce that we don't overrun. */
+ if (target_offset > declared_size) {
+ /* We're already beyond the end? Don't write any more. */
+ target_offset = declared_size;
+ size = 0;
+ overran = 1;
+ } else if (size > (uint64_t)(declared_size - target_offset)) {
+ /* Above is safe because target_offset <= declared_size */
+ /* This block is bigger than the expected remainder */
+ size = (size_t)(declared_size - target_offset);
+ overran = 1;
+ }
+ /* Else size <= expected remainder of data and we're OK. */
+ }
+
if (target_offset > actual_offset) {
- r = pad_to(a, fd, can_lseek, nulls_size, nulls,
+ r = pad_to(a, fd, can_lseek, &nulls,
target_offset, actual_offset);
if (r != ARCHIVE_OK)
break;
@@ -126,18 +156,52 @@ archive_read_data_into_fd(struct archive *a, int fd)
p += bytes_written;
size -= bytes_written;
}
+ if (overran) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Actual entry size exceeds the declared size "
+ "(%jd); truncated output at the declared size",
+ (intmax_t)declared_size);
+ r = ARCHIVE_FAILED;
+ goto cleanup;
+ }
}
if (r == ARCHIVE_EOF && target_offset > actual_offset) {
- r2 = pad_to(a, fd, can_lseek, nulls_size, nulls,
- target_offset, actual_offset);
- if (r2 != ARCHIVE_OK)
- r = r2;
+ int trailing_hole_overran =
+ declared_size >= 0 && target_offset > declared_size;
+ if (trailing_hole_overran)
+ target_offset = declared_size;
+ if (target_offset > actual_offset) {
+ r2 = pad_to(a, fd, can_lseek, &nulls,
+ target_offset, actual_offset);
+ if (r2 != ARCHIVE_OK)
+ r = r2;
+ else
+ actual_offset = target_offset;
+ }
+ if (trailing_hole_overran) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Actual entry size exceeds the declared size "
+ "(%jd); truncated output at the declared size",
+ (intmax_t)declared_size);
+ r = ARCHIVE_FAILED;
+ goto cleanup;
+ }
}
cleanup:
free(nulls);
if (r != ARCHIVE_EOF)
return (r);
- return (ARCHIVE_OK);
+ r = ARCHIVE_OK;
+ if (can_lseek) {
+ int64_t offset = lseek(fd, 0, SEEK_CUR);
+ if (offset - fd_offset != actual_offset) {
+ archive_set_error(a,
+ offset == -1 ? errno : ARCHIVE_ERRNO_MISC,
+ "Seek error");
+ r = ARCHIVE_FATAL;
+ }
+ }
+ return (r);
}
diff --git a/contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c b/contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c
index 6e6bae6a4e06..c4ad595fa4d8 100644
--- a/contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c
+++ b/contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c
@@ -256,6 +256,11 @@ archive_read_disk_entry_from_file(struct archive *_a,
char *linkbuffer;
ssize_t lnklen;
+ if (st->st_size >= SSIZE_MAX) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Couldn't read link data");
+ return (ARCHIVE_FAILED);
+ }
linkbuffer = malloc(linkbuffer_len + 1);
if (linkbuffer == NULL) {
archive_set_error(&a->archive, ENOMEM,
@@ -894,7 +899,7 @@ setup_sparse_fiemap(struct archive_read_disk *a,
r = ioctl(*fd, FS_IOC_FIEMAP, fm);
if (r < 0) {
- /* When something error happens, it is better we
+ /* When some error happens, it is better we
* should return ARCHIVE_OK because an earlier
* version(<2.6.28) cannot perform FS_IOC_FIEMAP. */
goto exit_setup_sparse_fiemap;
diff --git a/contrib/libarchive/libarchive/archive_read_disk_posix.c b/contrib/libarchive/libarchive/archive_read_disk_posix.c
index a7176bdd939d..a3c9e5833a94 100644
--- a/contrib/libarchive/libarchive/archive_read_disk_posix.c
+++ b/contrib/libarchive/libarchive/archive_read_disk_posix.c
@@ -453,6 +453,10 @@ archive_read_disk_new(void)
a->archive.state = ARCHIVE_STATE_NEW;
a->archive.vtable = &archive_read_disk_vtable;
a->entry = archive_entry_new2(&a->archive);
+ if (a->entry == NULL) {
+ free(a);
+ return (NULL);
+ }
a->lookup_uname = trivial_lookup_uname;
a->lookup_gname = trivial_lookup_gname;
a->flags = ARCHIVE_READDISK_MAC_COPYFILE;
@@ -920,7 +924,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
if (a->matching) {
r = archive_match_path_excluded(a->matching, entry);
if (r < 0) {
- archive_set_error(&(a->archive), errno,
+ archive_set_error(&(a->archive), archive_errno(a->matching),
"%s", archive_error_string(a->matching));
return (r);
}
@@ -1034,7 +1038,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
if (a->matching) {
r = archive_match_time_excluded(a->matching, entry);
if (r < 0) {
- archive_set_error(&(a->archive), errno,
+ archive_set_error(&(a->archive), archive_errno(a->matching),
"%s", archive_error_string(a->matching));
return (r);
}
@@ -1060,7 +1064,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
if (a->matching) {
r = archive_match_owner_excluded(a->matching, entry);
if (r < 0) {
- archive_set_error(&(a->archive), errno,
+ archive_set_error(&(a->archive), archive_errno(a->matching),
"%s", archive_error_string(a->matching));
return (r);
}
@@ -1413,18 +1417,18 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
/*
* This is the new filesystem which we have to generate a new ID for.
*/
- fid = t->max_filesystem_id++;
- if (fid > MAX_FILESYSTEM_ID) {
+ fid = t->max_filesystem_id;
+ if (fid >= MAX_FILESYSTEM_ID) {
archive_set_error(&a->archive, ENOMEM, "Too many filesystems");
return (ARCHIVE_FATAL);
}
- if (t->max_filesystem_id > t->allocated_filesystem) {
+ if (fid + 1 > t->allocated_filesystem) {
int s;
void *p;
- s = t->max_filesystem_id * 2;
+ s = (fid + 1) * 2;
p = realloc(t->filesystem_table,
- s * sizeof(*t->filesystem_table));
+ s * sizeof(*t->filesystem_table));
if (p == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate tar data");
@@ -1433,6 +1437,7 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
t->filesystem_table = (struct filesystem *)p;
t->allocated_filesystem = s;
}
+ t->max_filesystem_id = fid + 1;
t->current_filesystem_id = fid;
t->current_filesystem = &(t->filesystem_table[fid]);
t->current_filesystem->dev = dev;
diff --git a/contrib/libarchive/libarchive/archive_read_disk_set_standard_lookup.c b/contrib/libarchive/libarchive/archive_read_disk_set_standard_lookup.c
index 3512d343f65b..01285d91bb56 100644
--- a/contrib/libarchive/libarchive/archive_read_disk_set_standard_lookup.c
+++ b/contrib/libarchive/libarchive/archive_read_disk_set_standard_lookup.c
@@ -45,6 +45,7 @@
#endif
#include "archive.h"
+#include "archive_integer.h"
#if defined(_WIN32) && !defined(__CYGWIN__)
int
@@ -209,7 +210,8 @@ lookup_uname_helper(struct name_cache *cache, id_t id)
* we just double it and try again. Because the buffer
* is kept around in the cache object, we shouldn't
* have to do this very often. */
- nbuff_size = cache->buff_size * 2;
+ if (archive_ckd_mul_size(&nbuff_size, cache->buff_size, 2))
+ break;
nbuff = realloc(cache->buff, nbuff_size);
if (nbuff == NULL)
break;
@@ -276,7 +278,8 @@ lookup_gname_helper(struct name_cache *cache, id_t id)
/* ERANGE means our buffer was too small, but POSIX
* doesn't tell us how big the buffer should be, so
* we just double it and try again. */
- nbuff_size = cache->buff_size * 2;
+ if (archive_ckd_mul_size(&nbuff_size, cache->buff_size, 2))
+ break;
nbuff = realloc(cache->buff, nbuff_size);
if (nbuff == NULL)
break;
diff --git a/contrib/libarchive/libarchive/archive_read_filter.3 b/contrib/libarchive/libarchive/archive_read_filter.3
index 72ff240fd393..05513ececda6 100644
--- a/contrib/libarchive/libarchive/archive_read_filter.3
+++ b/contrib/libarchive/libarchive/archive_read_filter.3
@@ -142,7 +142,9 @@ These functions return
.Cm ARCHIVE_OK
if the compression is fully supported,
.Cm ARCHIVE_WARN
-if the compression is supported only through an external program.
+if the compression is supported only through an external program, or
+.Cm ARCHIVE_FATAL
+on error.
.Pp
.Fn archive_read_support_filter_none
always succeeds.
@@ -158,5 +160,4 @@ functions.
.Xr archive_read 3 ,
.Xr archive_read_data 3 ,
.Xr archive_read_format 3 ,
-.Xr archive_read_format 3 ,
.Xr libarchive 3
diff --git a/contrib/libarchive/libarchive/archive_read_open.3 b/contrib/libarchive/libarchive/archive_read_open.3
index 081b7114bea6..0e85d16f0d2f 100644
--- a/contrib/libarchive/libarchive/archive_read_open.3
+++ b/contrib/libarchive/libarchive/archive_read_open.3
@@ -31,6 +31,7 @@
.Nm archive_read_open_fd ,
.Nm archive_read_open_FILE ,
.Nm archive_read_open_filename ,
+.Nm archive_read_open_filenames ,
.Nm archive_read_open_memory
.Nd functions for reading streaming archives
.Sh LIBRARY
@@ -65,6 +66,12 @@ Streaming Archive Library (libarchive, -larchive)
.Fa "size_t block_size"
.Fc
.Ft int
+.Fo archive_read_open_filenames
+.Fa "struct archive *"
+.Fa "const char **filenames"
+.Fa "size_t block_size"
+.Fc
+.Ft int
.Fn archive_read_open_memory "struct archive *" "const void *buff" "size_t size"
.Sh DESCRIPTION
.Bl -tag -compact -width indent
@@ -111,6 +118,15 @@ Like
except that it accepts a simple filename and a block size.
A NULL filename represents standard input.
This function is safe for use with tape drives or other blocked devices.
+.It Fn archive_read_open_filenames
+Like
+.Fn archive_read_open ,
+except that it accepts a NULL-terminated array of filenames to open in
+sequence (as would be created by the
+.Xr split 1
+command) and a block size.
+A NULL filename at the beginning of the array represents standard input.
+This function is safe for use with tape drives or other blocked devices.
.It Fn archive_read_open_memory
Like
.Fn archive_read_open ,
diff --git a/contrib/libarchive/libarchive/archive_read_open_fd.c b/contrib/libarchive/libarchive/archive_read_open_fd.c
index c85a62a3e2d7..358e516faf18 100644
--- a/contrib/libarchive/libarchive/archive_read_open_fd.c
+++ b/contrib/libarchive/libarchive/archive_read_open_fd.c
@@ -69,6 +69,7 @@ archive_read_open_fd(struct archive *a, int fd, size_t block_size)
la_seek_stat_t st;
struct read_fd_data *mine;
void *b;
+ int r;
archive_clear_error(a);
if (la_seek_fstat(fd, &st) != 0) {
@@ -107,7 +108,9 @@ archive_read_open_fd(struct archive *a, int fd, size_t block_size)
archive_read_set_skip_callback(a, file_skip);
archive_read_set_seek_callback(a, file_seek);
archive_read_set_close_callback(a, file_close);
- archive_read_set_callback_data(a, mine);
+ r = archive_read_set_callback_data(a, mine);
+ if (r < 0)
+ return (r);
return (archive_read_open1(a));
}
diff --git a/contrib/libarchive/libarchive/archive_read_open_file.c b/contrib/libarchive/libarchive/archive_read_open_file.c
index 6ca2ff191aa8..e82069e502bf 100644
--- a/contrib/libarchive/libarchive/archive_read_open_file.c
+++ b/contrib/libarchive/libarchive/archive_read_open_file.c
@@ -70,6 +70,7 @@ archive_read_open_FILE(struct archive *a, FILE *f)
struct read_FILE_data *mine;
size_t block_size = 128 * 1024;
void *b;
+ int r;
archive_clear_error(a);
mine = calloc(1, sizeof(*mine));
@@ -104,7 +105,9 @@ archive_read_open_FILE(struct archive *a, FILE *f)
archive_read_set_skip_callback(a, FILE_skip);
archive_read_set_seek_callback(a, FILE_seek);
archive_read_set_close_callback(a, FILE_close);
- archive_read_set_callback_data(a, mine);
+ r = archive_read_set_callback_data(a, mine);
+ if (r < 0)
+ return (r);
return (archive_read_open1(a));
}
diff --git a/contrib/libarchive/libarchive/archive_read_open_filename.c b/contrib/libarchive/libarchive/archive_read_open_filename.c
index 9ec1e6c0e808..91f64b694a0c 100644
--- a/contrib/libarchive/libarchive/archive_read_open_filename.c
+++ b/contrib/libarchive/libarchive/archive_read_open_filename.c
@@ -40,6 +40,9 @@
#ifdef HAVE_IO_H
#include <io.h>
#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
@@ -181,7 +184,7 @@ archive_read_open_filenames_w(struct archive *a, const wchar_t **wfilenames,
if (wfilename == NULL)
wfilename = L"";
mine = calloc(1,
- sizeof(*mine) + wcslen(wfilename) * sizeof(wchar_t));
+ sizeof(*mine) + wcslen(wfilename) * MB_LEN_MAX);
if (mine == NULL)
goto no_memory;
mine->block_size = block_size;
@@ -315,7 +318,7 @@ file_open(struct archive *a, void *client_data)
}
#else
archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "Unexpedted operation in archive_read_open_filename");
+ "Unexpected operation in archive_read_open_filename");
goto fail;
#endif
}
diff --git a/contrib/libarchive/libarchive/archive_read_open_memory.c b/contrib/libarchive/libarchive/archive_read_open_memory.c
index 460bb5ae6a4d..441662d464d7 100644
--- a/contrib/libarchive/libarchive/archive_read_open_memory.c
+++ b/contrib/libarchive/libarchive/archive_read_open_memory.c
@@ -68,6 +68,7 @@ archive_read_open_memory2(struct archive *a, const void *buff,
size_t size, size_t read_size)
{
struct read_memory_data *mine;
+ int r;
mine = calloc(1, sizeof(*mine));
if (mine == NULL) {
@@ -82,7 +83,9 @@ archive_read_open_memory2(struct archive *a, const void *buff,
archive_read_set_seek_callback(a, memory_read_seek);
archive_read_set_skip_callback(a, memory_read_skip);
archive_read_set_close_callback(a, memory_read_close);
- archive_read_set_callback_data(a, mine);
+ r = archive_read_set_callback_data(a, mine);
+ if (r < 0)
+ return (r);
return (archive_read_open1(a));
}
diff --git a/contrib/libarchive/libarchive/archive_read_private.h b/contrib/libarchive/libarchive/archive_read_private.h
index 0c374f487eba..3bd8de2de663 100644
--- a/contrib/libarchive/libarchive/archive_read_private.h
+++ b/contrib/libarchive/libarchive/archive_read_private.h
@@ -76,10 +76,10 @@ struct archive_read_filter_bidder {
struct archive_read_filter_vtable {
/* Return next block. */
ssize_t (*read)(struct archive_read_filter *, const void **);
- /* Close (just this filter) and free(self). */
- int (*close)(struct archive_read_filter *self);
+ /* Close (just this filter) and free(filter). */
+ int (*close)(struct archive_read_filter *);
/* Read any header metadata if available. */
- int (*read_header)(struct archive_read_filter *self, struct archive_entry *entry);
+ int (*read_header)(struct archive_read_filter *, struct archive_entry *);
};
/*
@@ -180,6 +180,15 @@ struct archive_read {
/* File offset of beginning of most recently-read header. */
int64_t header_position;
+ /*
+ * Declared uncompressed size of the entry whose header was most
+ * recently read, or -1 if no size was declared. Lets format-
+ * agnostic consumers like archive_read_data_into_fd() cap their
+ * output at the size an entry actually promised, regardless of
+ * whether the format reader enforces that itself.
+ */
+ int64_t entry_bytes_declared;
+
/* Nodes and offsets of compressed data block */
unsigned int data_start_node;
unsigned int data_end_node;
diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_all.c b/contrib/libarchive/libarchive/archive_read_support_filter_all.c
index cb46d120d102..f08677301fb3 100644
--- a/contrib/libarchive/libarchive/archive_read_support_filter_all.c
+++ b/contrib/libarchive/libarchive/archive_read_support_filter_all.c
@@ -43,34 +43,34 @@ archive_read_support_filter_all(struct archive *a)
archive_check_magic(a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_all");
- /* Bzip falls back to "bunzip2" command-line */
+ /* Bzip falls back to "bzip2 -d" command-line */
archive_read_support_filter_bzip2(a);
/* The decompress code doesn't use an outside library. */
archive_read_support_filter_compress(a);
/* Gzip decompress falls back to "gzip -d" command-line. */
archive_read_support_filter_gzip(a);
- /* Lzip falls back to "unlzip" command-line program. */
+ /* Lzip falls back to "lzip -d -q" command-line. */
archive_read_support_filter_lzip(a);
/* The LZMA file format has a very weak signature, so it
* may not be feasible to keep this here, but we'll try.
* This will come back out if there are problems. */
- /* Lzma falls back to "unlzma" command-line program. */
+ /* Lzma falls back to "lzma -d -qq" command-line. */
archive_read_support_filter_lzma(a);
- /* Xz falls back to "unxz" command-line program. */
+ /* Xz falls back to "xz -d -qq" command-line. */
archive_read_support_filter_xz(a);
/* The decode code doesn't use an outside library. */
archive_read_support_filter_uu(a);
/* The decode code doesn't use an outside library. */
archive_read_support_filter_rpm(a);
- /* The decode code always uses "lrzip -q -d" command-line. */
+ /* The decode code always uses "lrzip -d -q" command-line. */
archive_read_support_filter_lrzip(a);
/* Lzop decompress falls back to "lzop -d" command-line. */
archive_read_support_filter_lzop(a);
/* The decode code always uses "grzip -d" command-line. */
archive_read_support_filter_grzip(a);
- /* Lz4 falls back to "lz4 -d" command-line program. */
+ /* Lz4 falls back to "lz4 -d -q" command-line. */
archive_read_support_filter_lz4(a);
- /* Zstd falls back to "zstd -d" command-line program. */
+ /* Zstd falls back to "zstd -d -qq" command-line. */
archive_read_support_filter_zstd(a);
/* Note: We always return ARCHIVE_OK here, even if some of the
diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_bzip2.c b/contrib/libarchive/libarchive/archive_read_support_filter_bzip2.c
index 479237c27792..588953f2aa94 100644
--- a/contrib/libarchive/libarchive/archive_read_support_filter_bzip2.c
+++ b/contrib/libarchive/libarchive/archive_read_support_filter_bzip2.c
@@ -28,6 +28,9 @@
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
@@ -47,7 +50,7 @@
#include "archive_read_private.h"
#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
-struct private_data {
+struct bzip2 {
bz_stream stream;
char *out_block;
size_t out_block_size;
@@ -63,8 +66,7 @@ static int bzip2_filter_close(struct archive_read_filter *);
/*
* Note that we can detect bzip2 archives even if we can't decompress
* them. (In fact, we like detecting them because we can give better
- * error messages.) So the bid framework here gets compiled even
- * if bzlib is unavailable.
+ * error messages.)
*/
static int bzip2_reader_bid(struct archive_read_filter_bidder *, struct archive_read_filter *);
static int bzip2_reader_init(struct archive_read_filter *);
@@ -110,16 +112,15 @@ archive_read_support_filter_bzip2(struct archive *_a)
* from verifying as much as we would like.
*/
static int
-bzip2_reader_bid(struct archive_read_filter_bidder *self, struct archive_read_filter *filter)
+bzip2_reader_bid(struct archive_read_filter_bidder *b, struct archive_read_filter *f)
{
const unsigned char *buffer;
- ssize_t avail;
int bits_checked;
- (void)self; /* UNUSED */
+ (void)b; /* UNUSED */
/* Minimal bzip2 archive is 14 bytes. */
- buffer = __archive_read_filter_ahead(filter, 14, &avail);
+ buffer = __archive_read_filter_ahead(f, 14, NULL);
if (buffer == NULL)
return (0);
@@ -150,21 +151,21 @@ bzip2_reader_bid(struct archive_read_filter_bidder *self, struct archive_read_fi
#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR)
/*
- * If we don't have the library on this system, we can't actually do the
- * decompression. We can, however, still detect compressed archives
- * and emit a useful message.
+ * If we don't have the library on this system, we can't do the
+ * decompression directly. We can, however, try to run "bzip2 -d"
+ * in case that's available.
*/
static int
-bzip2_reader_init(struct archive_read_filter *self)
+bzip2_reader_init(struct archive_read_filter *f)
{
int r;
- r = __archive_read_program(self, "bzip2 -d");
+ r = __archive_read_program(f, "bzip2 -d");
/* Note: We set the format here even if __archive_read_program()
* above fails. We do, after all, know what the format is
* even if we weren't able to read it. */
- self->code = ARCHIVE_FILTER_BZIP2;
- self->name = "bzip2";
+ f->code = ARCHIVE_FILTER_BZIP2;
+ f->name = "bzip2";
return (r);
}
@@ -181,29 +182,29 @@ bzip2_reader_vtable = {
* Setup the callbacks.
*/
static int
-bzip2_reader_init(struct archive_read_filter *self)
+bzip2_reader_init(struct archive_read_filter *f)
{
static const size_t out_block_size = 64 * 1024;
void *out_block;
- struct private_data *state;
+ struct bzip2 *bzip2;
- self->code = ARCHIVE_FILTER_BZIP2;
- self->name = "bzip2";
+ f->code = ARCHIVE_FILTER_BZIP2;
+ f->name = "bzip2";
- state = calloc(1, sizeof(*state));
+ bzip2 = calloc(1, sizeof(*bzip2));
out_block = malloc(out_block_size);
- if (state == NULL || out_block == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
+ if (bzip2 == NULL || out_block == NULL) {
+ archive_set_error(&f->archive->archive, ENOMEM,
"Can't allocate data for bzip2 decompression");
free(out_block);
- free(state);
+ free(bzip2);
return (ARCHIVE_FATAL);
}
- self->data = state;
- state->out_block_size = out_block_size;
- state->out_block = out_block;
- self->vtable = &bzip2_reader_vtable;
+ f->data = bzip2;
+ bzip2->out_block_size = out_block_size;
+ bzip2->out_block = out_block;
+ f->vtable = &bzip2_reader_vtable;
return (ARCHIVE_OK);
}
@@ -212,42 +213,42 @@ bzip2_reader_init(struct archive_read_filter *self)
* Return the next block of decompressed data.
*/
static ssize_t
-bzip2_filter_read(struct archive_read_filter *self, const void **p)
+bzip2_filter_read(struct archive_read_filter *f, const void **p)
{
- struct private_data *state;
+ struct bzip2 *bzip2 = f->data;
size_t decompressed;
const char *read_buf;
ssize_t ret;
- state = (struct private_data *)self->data;
-
- if (state->eof) {
+ if (bzip2->eof) {
*p = NULL;
return (0);
}
/* Empty our output buffer. */
- state->stream.next_out = state->out_block;
- state->stream.avail_out = (uint32_t)state->out_block_size;
+ bzip2->stream.next_out = bzip2->out_block;
+ bzip2->stream.avail_out = (uint32_t)bzip2->out_block_size;
/* Try to fill the output buffer. */
for (;;) {
- if (!state->valid) {
- if (bzip2_reader_bid(self->bidder, self->upstream) == 0) {
- state->eof = 1;
- *p = state->out_block;
- decompressed = state->stream.next_out
- - state->out_block;
+ ssize_t max_in;
+
+ if (!bzip2->valid) {
+ if (bzip2_reader_bid(f->bidder, f->upstream) == 0) {
+ bzip2->eof = 1;
+ *p = bzip2->out_block;
+ decompressed = bzip2->stream.next_out
+ - bzip2->out_block;
return (decompressed);
}
/* Initialize compression library. */
- ret = BZ2_bzDecompressInit(&(state->stream),
+ ret = BZ2_bzDecompressInit(&(bzip2->stream),
0 /* library verbosity */,
0 /* don't use low-mem algorithm */);
/* If init fails, try low-memory algorithm instead. */
if (ret == BZ_MEM_ERROR)
- ret = BZ2_bzDecompressInit(&(state->stream),
+ ret = BZ2_bzDecompressInit(&(bzip2->stream),
0 /* library verbosity */,
1 /* do use low-mem algo */);
@@ -266,65 +267,63 @@ bzip2_filter_read(struct archive_read_filter *self, const void **p)
detail = "mis-compiled library";
break;
}
- archive_set_error(&self->archive->archive, err,
+ archive_set_error(&f->archive->archive, err,
"Internal error initializing decompressor%s%s",
detail == NULL ? "" : ": ",
detail);
return (ARCHIVE_FATAL);
}
- state->valid = 1;
+ bzip2->valid = 1;
}
/* stream.next_in is really const, but bzlib
* doesn't declare it so. <sigh> */
read_buf =
- __archive_read_filter_ahead(self->upstream, 1, &ret);
+ __archive_read_filter_ahead(f->upstream, 1, &ret);
if (read_buf == NULL) {
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"truncated bzip2 input");
return (ARCHIVE_FATAL);
}
- state->stream.next_in = (char *)(uintptr_t)read_buf;
- state->stream.avail_in = (uint32_t)ret;
- /* There is no more data, return whatever we have. */
- if (ret == 0) {
- state->eof = 1;
- *p = state->out_block;
- decompressed = state->stream.next_out
- - state->out_block;
- return (decompressed);
- }
+ bzip2->stream.next_in = (char *)(uintptr_t)read_buf;
+ if (UINT_MAX >= SSIZE_MAX)
+ max_in = SSIZE_MAX;
+ else
+ max_in = UINT_MAX;
+ if (ret > max_in)
+ ret = max_in;
+ bzip2->stream.avail_in = (uint32_t)ret;
/* Decompress as much as we can in one pass. */
- ret = BZ2_bzDecompress(&(state->stream));
- __archive_read_filter_consume(self->upstream,
- state->stream.next_in - read_buf);
+ ret = BZ2_bzDecompress(&(bzip2->stream));
+ __archive_read_filter_consume(f->upstream,
+ bzip2->stream.next_in - read_buf);
switch (ret) {
case BZ_STREAM_END: /* Found end of stream. */
- switch (BZ2_bzDecompressEnd(&(state->stream))) {
+ switch (BZ2_bzDecompressEnd(&(bzip2->stream))) {
case BZ_OK:
break;
default:
- archive_set_error(&(self->archive->archive),
+ archive_set_error(&(f->archive->archive),
ARCHIVE_ERRNO_MISC,
"Failed to clean up decompressor");
return (ARCHIVE_FATAL);
}
- state->valid = 0;
+ bzip2->valid = 0;
/* FALLTHROUGH */
case BZ_OK: /* Decompressor made some progress. */
/* If we filled our buffer, update stats and return. */
- if (state->stream.avail_out == 0) {
- *p = state->out_block;
- decompressed = state->stream.next_out
- - state->out_block;
+ if (bzip2->stream.avail_out == 0) {
+ *p = bzip2->out_block;
+ decompressed = bzip2->stream.next_out
+ - bzip2->out_block;
return (decompressed);
}
break;
default: /* Return an error. */
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC, "bzip decompression failed");
return (ARCHIVE_FATAL);
}
@@ -335,28 +334,26 @@ bzip2_filter_read(struct archive_read_filter *self, const void **p)
* Clean up the decompressor.
*/
static int
-bzip2_filter_close(struct archive_read_filter *self)
+bzip2_filter_close(struct archive_read_filter *f)
{
- struct private_data *state;
+ struct bzip2 *bzip2 = f->data;
int ret = ARCHIVE_OK;
- state = (struct private_data *)self->data;
-
- if (state->valid) {
- switch (BZ2_bzDecompressEnd(&state->stream)) {
+ if (bzip2->valid) {
+ switch (BZ2_bzDecompressEnd(&bzip2->stream)) {
case BZ_OK:
break;
default:
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Failed to clean up decompressor");
ret = ARCHIVE_FATAL;
}
- state->valid = 0;
+ bzip2->valid = 0;
}
- free(state->out_block);
- free(state);
+ free(bzip2->out_block);
+ free(bzip2);
return (ret);
}
diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_compress.c b/contrib/libarchive/libarchive/archive_read_support_filter_compress.c
index d03013b36187..ee69582924e6 100644
--- a/contrib/libarchive/libarchive/archive_read_support_filter_compress.c
+++ b/contrib/libarchive/libarchive/archive_read_support_filter_compress.c
@@ -90,7 +90,7 @@
* names and structure here don't exactly match those used by compress.
*/
-struct private_data {
+struct compress {
/* Input variables. */
const unsigned char *next_in;
size_t avail_in;
@@ -104,6 +104,7 @@ struct private_data {
void *out_block;
/* Decompression status variables. */
+ int initialized;
int use_reset_code;
int end_of_stream; /* EOF status. */
int maxcode; /* Largest code. */
@@ -168,17 +169,16 @@ archive_read_support_filter_compress(struct archive *_a)
* This logic returns zero if any part of the signature fails.
*/
static int
-compress_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
+compress_bidder_bid(struct archive_read_filter_bidder *b,
+ struct archive_read_filter *f)
{
const unsigned char *buffer;
- ssize_t avail;
int bits_checked;
- (void)self; /* UNUSED */
+ (void)b; /* UNUSED */
/* Shortest valid compress file is 3 bytes. */
- buffer = __archive_read_filter_ahead(filter, 3, &avail);
+ buffer = __archive_read_filter_ahead(f, 3, NULL);
if (buffer == NULL)
return (0);
@@ -207,61 +207,69 @@ compress_reader_vtable = {
* Setup the callbacks.
*/
static int
-compress_bidder_init(struct archive_read_filter *self)
+compress_bidder_init(struct archive_read_filter *f)
{
- struct private_data *state;
+ struct compress *compress;
static const size_t out_block_size = 64 * 1024;
void *out_block;
- int code;
- self->code = ARCHIVE_FILTER_COMPRESS;
- self->name = "compress (.Z)";
+ f->code = ARCHIVE_FILTER_COMPRESS;
+ f->name = "compress (.Z)";
- state = calloc(1, sizeof(*state));
+ compress = calloc(1, sizeof(*compress));
out_block = malloc(out_block_size);
- if (state == NULL || out_block == NULL) {
+ if (compress == NULL || out_block == NULL) {
free(out_block);
- free(state);
- archive_set_error(&self->archive->archive, ENOMEM,
+ free(compress);
+ archive_set_error(&f->archive->archive, ENOMEM,
"Can't allocate data for %s decompression",
- self->name);
+ f->name);
return (ARCHIVE_FATAL);
}
- self->data = state;
- state->out_block_size = out_block_size;
- state->out_block = out_block;
- self->vtable = &compress_reader_vtable;
+ f->data = compress;
+ compress->out_block_size = out_block_size;
+ compress->out_block = out_block;
+ f->vtable = &compress_reader_vtable;
- /* XXX MOVE THE FOLLOWING OUT OF INIT() XXX */
+ return (ARCHIVE_OK);
+}
- (void)getbits(self, 8); /* Skip first signature byte. */
- (void)getbits(self, 8); /* Skip second signature byte. */
+static int
+compress_filter_init(struct archive_read_filter *f)
+{
+ struct compress *compress = f->data;
+ int code;
+
+ compress->initialized = 1;
+
+ (void)getbits(f, 8); /* Skip first signature byte. */
+ (void)getbits(f, 8); /* Skip second signature byte. */
/* Get compression parameters. */
- code = getbits(self, 8);
- if ((code & 0x1f) > 16) {
- archive_set_error(&self->archive->archive, -1,
+ code = getbits(f, 8);
+ if (code < 0 || (code & 0x1f) > 16) {
+ archive_set_error(&f->archive->archive, -1,
"Invalid compressed data");
return (ARCHIVE_FATAL);
}
- state->maxcode_bits = code & 0x1f;
- state->maxcode = (1 << state->maxcode_bits);
- state->use_reset_code = code & 0x80;
+ compress->maxcode_bits = code & 0x1f;
+ compress->maxcode = (1 << compress->maxcode_bits);
+ compress->use_reset_code = code & 0x80;
/* Initialize decompressor. */
- state->free_ent = 256;
- state->stackp = state->stack;
- if (state->use_reset_code)
- state->free_ent++;
- state->bits = 9;
- state->section_end_code = (1<<state->bits) - 1;
- state->oldcode = -1;
+ compress->free_ent = 256;
+ compress->stackp = compress->stack;
+ if (compress->use_reset_code)
+ compress->free_ent++;
+ compress->bits = 9;
+ compress->section_end_code = (1<<compress->bits) - 1;
+ compress->oldcode = -1;
for (code = 255; code >= 0; code--) {
- state->prefix[code] = 0;
- state->suffix[code] = code;
+ compress->prefix[code] = 0;
+ compress->suffix[code] = code;
}
- next_code(self);
+ next_code(f);
return (ARCHIVE_OK);
}
@@ -271,27 +279,31 @@ compress_bidder_init(struct archive_read_filter *self)
* as necessary.
*/
static ssize_t
-compress_filter_read(struct archive_read_filter *self, const void **pblock)
+compress_filter_read(struct archive_read_filter *f, const void **pblock)
{
- struct private_data *state;
+ struct compress *compress = f->data;
unsigned char *p, *start, *end;
int ret;
- state = (struct private_data *)self->data;
- if (state->end_of_stream) {
+ if (!compress->initialized) {
+ ret = compress_filter_init(f);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ }
+ if (compress->end_of_stream) {
*pblock = NULL;
return (0);
}
- p = start = (unsigned char *)state->out_block;
- end = start + state->out_block_size;
+ p = start = (unsigned char *)compress->out_block;
+ end = start + compress->out_block_size;
- while (p < end && !state->end_of_stream) {
- if (state->stackp > state->stack) {
- *p++ = *--state->stackp;
+ while (p < end && !compress->end_of_stream) {
+ if (compress->stackp > compress->stack) {
+ *p++ = *--compress->stackp;
} else {
- ret = next_code(self);
+ ret = next_code(f);
if (ret == -1)
- state->end_of_stream = ret;
+ compress->end_of_stream = ret;
else if (ret != ARCHIVE_OK)
return (ret);
}
@@ -305,12 +317,12 @@ compress_filter_read(struct archive_read_filter *self, const void **pblock)
* Close and release the filter.
*/
static int
-compress_filter_close(struct archive_read_filter *self)
+compress_filter_close(struct archive_read_filter *f)
{
- struct private_data *state = (struct private_data *)self->data;
+ struct compress *compress = f->data;
- free(state->out_block);
- free(state);
+ free(compress->out_block);
+ free(compress);
return (ARCHIVE_OK);
}
@@ -320,25 +332,18 @@ compress_filter_close(struct archive_read_filter *self)
* format error, ARCHIVE_EOF if we hit end of data, ARCHIVE_OK otherwise.
*/
static int
-next_code(struct archive_read_filter *self)
+next_code(struct archive_read_filter *f)
{
- struct private_data *state = (struct private_data *)self->data;
+ struct compress *compress = f->data;
int code, newcode;
- static int debug_buff[1024];
- static unsigned debug_index;
-
again:
- code = newcode = getbits(self, state->bits);
+ code = newcode = getbits(f, compress->bits);
if (code < 0)
return (code);
- debug_buff[debug_index++] = code;
- if (debug_index >= sizeof(debug_buff)/sizeof(debug_buff[0]))
- debug_index = 0;
-
/* If it's a reset code, reset the dictionary. */
- if ((code == 256) && state->use_reset_code) {
+ if ((code == 256) && compress->use_reset_code) {
/*
* The original 'compress' implementation blocked its
* I/O in a manner that resulted in junk bytes being
@@ -346,63 +351,63 @@ again:
* this junk. (Yes, the number of *bytes* to skip is
* a function of the current *bit* length.)
*/
- int skip_bytes = state->bits -
- (state->bytes_in_section % state->bits);
- skip_bytes %= state->bits;
- state->bits_avail = 0; /* Discard rest of this byte. */
+ int skip_bytes = compress->bits -
+ (compress->bytes_in_section % compress->bits);
+ skip_bytes %= compress->bits;
+ compress->bits_avail = 0; /* Discard rest of this byte. */
while (skip_bytes-- > 0) {
- code = getbits(self, 8);
+ code = getbits(f, 8);
if (code < 0)
return (code);
}
/* Now, actually do the reset. */
- state->bytes_in_section = 0;
- state->bits = 9;
- state->section_end_code = (1 << state->bits) - 1;
- state->free_ent = 257;
- state->oldcode = -1;
+ compress->bytes_in_section = 0;
+ compress->bits = 9;
+ compress->section_end_code = (1 << compress->bits) - 1;
+ compress->free_ent = 257;
+ compress->oldcode = -1;
goto again;
}
- if (code > state->free_ent
- || (code == state->free_ent && state->oldcode < 0)) {
+ if (code > compress->free_ent
+ || (code == compress->free_ent && compress->oldcode < 0)) {
/* An invalid code is a fatal error. */
- archive_set_error(&(self->archive->archive), -1,
+ archive_set_error(&(f->archive->archive), -1,
"Invalid compressed data");
return (ARCHIVE_FATAL);
}
/* Special case for KwKwK string. */
- if (code >= state->free_ent) {
- *state->stackp++ = state->finbyte;
- code = state->oldcode;
+ if (code >= compress->free_ent) {
+ *compress->stackp++ = compress->finbyte;
+ code = compress->oldcode;
}
/* Generate output characters in reverse order. */
while (code >= 256) {
- *state->stackp++ = state->suffix[code];
- code = state->prefix[code];
+ *compress->stackp++ = compress->suffix[code];
+ code = compress->prefix[code];
}
- *state->stackp++ = state->finbyte = code;
+ *compress->stackp++ = compress->finbyte = code;
/* Generate the new entry. */
- code = state->free_ent;
- if (code < state->maxcode && state->oldcode >= 0) {
- state->prefix[code] = state->oldcode;
- state->suffix[code] = state->finbyte;
- ++state->free_ent;
+ code = compress->free_ent;
+ if (code < compress->maxcode && compress->oldcode >= 0) {
+ compress->prefix[code] = compress->oldcode;
+ compress->suffix[code] = compress->finbyte;
+ ++compress->free_ent;
}
- if (state->free_ent > state->section_end_code) {
- state->bits++;
- state->bytes_in_section = 0;
- if (state->bits == state->maxcode_bits)
- state->section_end_code = state->maxcode;
+ if (compress->free_ent > compress->section_end_code) {
+ compress->bits++;
+ compress->bytes_in_section = 0;
+ if (compress->bits == compress->maxcode_bits)
+ compress->section_end_code = compress->maxcode;
else
- state->section_end_code = (1 << state->bits) - 1;
+ compress->section_end_code = (1 << compress->bits) - 1;
}
/* Remember previous code. */
- state->oldcode = newcode;
+ compress->oldcode = newcode;
return (ARCHIVE_OK);
}
@@ -412,9 +417,9 @@ again:
* -1 indicates end of available data.
*/
static int
-getbits(struct archive_read_filter *self, int n)
+getbits(struct archive_read_filter *f, int n)
{
- struct private_data *state = (struct private_data *)self->data;
+ struct compress *compress = f->data;
int code;
ssize_t ret;
static const int mask[] = {
@@ -422,31 +427,31 @@ getbits(struct archive_read_filter *self, int n)
0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff
};
- while (state->bits_avail < n) {
- if (state->avail_in <= 0) {
- if (state->consume_unnotified) {
- __archive_read_filter_consume(self->upstream,
- state->consume_unnotified);
- state->consume_unnotified = 0;
+ while (compress->bits_avail < n) {
+ if (compress->avail_in <= 0) {
+ if (compress->consume_unnotified) {
+ __archive_read_filter_consume(f->upstream,
+ compress->consume_unnotified);
+ compress->consume_unnotified = 0;
}
- state->next_in
- = __archive_read_filter_ahead(self->upstream,
+ compress->next_in
+ = __archive_read_filter_ahead(f->upstream,
1, &ret);
if (ret == 0)
return (-1);
- if (ret < 0 || state->next_in == NULL)
+ if (compress->next_in == NULL)
return (ARCHIVE_FATAL);
- state->consume_unnotified = state->avail_in = ret;
+ compress->consume_unnotified = compress->avail_in = ret;
}
- state->bit_buffer |= *state->next_in++ << state->bits_avail;
- state->avail_in--;
- state->bits_avail += 8;
- state->bytes_in_section++;
+ compress->bit_buffer |= *compress->next_in++ << compress->bits_avail;
+ compress->avail_in--;
+ compress->bits_avail += 8;
+ compress->bytes_in_section++;
}
- code = state->bit_buffer;
- state->bit_buffer >>= n;
- state->bits_avail -= n;
+ code = compress->bit_buffer;
+ compress->bit_buffer >>= n;
+ compress->bits_avail -= n;
return (code & mask[n]);
}
diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_grzip.c b/contrib/libarchive/libarchive/archive_read_support_filter_grzip.c
index 8ec5d1f855cb..9d9ad46eaef4 100644
--- a/contrib/libarchive/libarchive/archive_read_support_filter_grzip.c
+++ b/contrib/libarchive/libarchive/archive_read_support_filter_grzip.c
@@ -76,16 +76,15 @@ archive_read_support_filter_grzip(struct archive *_a)
* Bidder just verifies the header and returns the number of verified bits.
*/
static int
-grzip_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
+grzip_bidder_bid(struct archive_read_filter_bidder *b,
+ struct archive_read_filter *f)
{
const unsigned char *p;
- ssize_t avail;
- (void)self; /* UNUSED */
+ (void)b; /* UNUSED */
- p = __archive_read_filter_ahead(filter, sizeof(grzip_magic), &avail);
- if (p == NULL || avail == 0)
+ p = __archive_read_filter_ahead(f, sizeof(grzip_magic), NULL);
+ if (p == NULL)
return (0);
if (memcmp(p, grzip_magic, sizeof(grzip_magic)))
@@ -95,15 +94,15 @@ grzip_bidder_bid(struct archive_read_filter_bidder *self,
}
static int
-grzip_bidder_init(struct archive_read_filter *self)
+grzip_bidder_init(struct archive_read_filter *f)
{
int r;
- r = __archive_read_program(self, "grzip -d");
+ r = __archive_read_program(f, "grzip -d");
/* Note: We set the format here even if __archive_read_program()
* above fails. We do, after all, know what the format is
* even if we weren't able to read it. */
- self->code = ARCHIVE_FILTER_GRZIP;
- self->name = "grzip";
+ f->code = ARCHIVE_FILTER_GRZIP;
+ f->name = "grzip";
return (r);
}
diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_gzip.c b/contrib/libarchive/libarchive/archive_read_support_filter_gzip.c
index 726385e328a0..89ae0f371493 100644
--- a/contrib/libarchive/libarchive/archive_read_support_filter_gzip.c
+++ b/contrib/libarchive/libarchive/archive_read_support_filter_gzip.c
@@ -51,12 +51,11 @@
#include "archive_read_private.h"
#ifdef HAVE_ZLIB_H
-struct private_data {
+struct gzip {
z_stream stream;
char in_stream;
unsigned char *out_block;
size_t out_block_size;
- int64_t total_out;
unsigned long crc;
uint32_t mtime;
char *name;
@@ -71,12 +70,7 @@ static int gzip_filter_close(struct archive_read_filter *);
/*
* Note that we can detect gzip archives even if we can't decompress
* them. (In fact, we like detecting them because we can give better
- * error messages.) So the bid framework here gets compiled even
- * if zlib is unavailable.
- *
- * TODO: If zlib is unavailable, gzip_bidder_init() should
- * use the compress_program framework to try to fire up an external
- * gzip program.
+ * error messages.)
*/
static int gzip_bidder_bid(struct archive_read_filter_bidder *,
struct archive_read_filter *);
@@ -126,9 +120,9 @@ archive_read_support_filter_gzip(struct archive *_a)
#define MAX_FILENAME_LENGTH (1024 * 1024L)
#define MAX_COMMENT_LENGTH (1024 * 1024L)
static ssize_t
-peek_at_header(struct archive_read_filter *filter, int *pbits,
+peek_at_header(struct archive_read_filter *f, int *pbits,
#ifdef HAVE_ZLIB_H
- struct private_data *state
+ struct gzip *gzip
#else
void *state
#endif
@@ -145,8 +139,8 @@ peek_at_header(struct archive_read_filter *filter, int *pbits,
/* Start by looking at the first ten bytes of the header, which
* is all fixed layout. */
len = 10;
- p = __archive_read_filter_ahead(filter, len, &avail);
- if (p == NULL || avail == 0)
+ p = __archive_read_filter_ahead(f, len, &avail);
+ if (p == NULL)
return (0);
/* We only support deflation- third byte must be 0x08. */
if (memcmp(p, "\x1F\x8B\x08", 3) != 0)
@@ -158,8 +152,8 @@ peek_at_header(struct archive_read_filter *filter, int *pbits,
header_flags = p[3];
/* Bytes 4-7 are mod time in little endian. */
#ifdef HAVE_ZLIB_H
- if (state)
- state->mtime = archive_le32dec(p + 4);
+ if (gzip)
+ gzip->mtime = archive_le32dec(p + 4);
#endif
/* Byte 8 is deflate flags. */
/* XXXX TODO: return deflate flags back to consume_header for use
@@ -168,10 +162,10 @@ peek_at_header(struct archive_read_filter *filter, int *pbits,
/* Optional extra data: 2 byte length plus variable body. */
if (header_flags & 4) {
- p = __archive_read_filter_ahead(filter, len + 2, &avail);
+ p = __archive_read_filter_ahead(f, len + 2, &avail);
if (p == NULL)
return (0);
- len += ((int)p[len + 1] << 8) | (int)p[len];
+ len += archive_le16dec(p + len);
len += 2;
}
@@ -186,7 +180,7 @@ peek_at_header(struct archive_read_filter *filter, int *pbits,
if (avail > MAX_FILENAME_LENGTH) {
return (0);
}
- p = __archive_read_filter_ahead(filter,
+ p = __archive_read_filter_ahead(f,
len, &avail);
}
if (p == NULL)
@@ -194,10 +188,10 @@ peek_at_header(struct archive_read_filter *filter, int *pbits,
} while (p[len - 1] != 0);
#ifdef HAVE_ZLIB_H
- if (state) {
+ if (gzip) {
/* Reset the name in case of repeat header reads. */
- free(state->name);
- state->name = strdup((const char *)&p[file_start]);
+ free(gzip->name);
+ gzip->name = strdup((const char *)&p[file_start]);
}
#endif
}
@@ -210,7 +204,7 @@ peek_at_header(struct archive_read_filter *filter, int *pbits,
if (avail > MAX_COMMENT_LENGTH) {
return (0);
}
- p = __archive_read_filter_ahead(filter,
+ p = __archive_read_filter_ahead(f,
len, &avail);
}
if (p == NULL)
@@ -220,7 +214,7 @@ peek_at_header(struct archive_read_filter *filter, int *pbits,
/* Optional header CRC */
if ((header_flags & 2)) {
- p = __archive_read_filter_ahead(filter, len + 2, &avail);
+ p = __archive_read_filter_ahead(f, len + 2, &avail);
if (p == NULL)
return (0);
#if 0
@@ -242,14 +236,14 @@ peek_at_header(struct archive_read_filter *filter, int *pbits,
* Bidder just verifies the header and returns the number of verified bits.
*/
static int
-gzip_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
+gzip_bidder_bid(struct archive_read_filter_bidder *b,
+ struct archive_read_filter *f)
{
int bits_checked;
- (void)self; /* UNUSED */
+ (void)b; /* UNUSED */
- if (peek_at_header(filter, &bits_checked, NULL))
+ if (peek_at_header(f, &bits_checked, NULL))
return (bits_checked);
return (0);
}
@@ -262,35 +256,33 @@ gzip_bidder_bid(struct archive_read_filter_bidder *self,
* in case that's available.
*/
static int
-gzip_bidder_init(struct archive_read_filter *self)
+gzip_bidder_init(struct archive_read_filter *f)
{
int r;
- r = __archive_read_program(self, "gzip -d");
+ r = __archive_read_program(f, "gzip -d");
/* Note: We set the format here even if __archive_read_program()
* above fails. We do, after all, know what the format is
* even if we weren't able to read it. */
- self->code = ARCHIVE_FILTER_GZIP;
- self->name = "gzip";
+ f->code = ARCHIVE_FILTER_GZIP;
+ f->name = "gzip";
return (r);
}
#else
static int
-gzip_read_header(struct archive_read_filter *self, struct archive_entry *entry)
+gzip_read_header(struct archive_read_filter *f, struct archive_entry *entry)
{
- struct private_data *state;
-
- state = (struct private_data *)self->data;
+ struct gzip *gzip = f->data;
- /* A mtime of 0 is considered invalid/missing. */
- if (state->mtime != 0)
- archive_entry_set_mtime(entry, state->mtime, 0);
+ /* An mtime of 0 is considered invalid/missing. */
+ if (gzip->mtime != 0)
+ archive_entry_set_mtime(entry, gzip->mtime, 0);
/* If the name is available, extract it. */
- if (state->name)
- archive_entry_set_pathname(entry, state->name);
+ if (gzip->name)
+ archive_entry_set_pathname(entry, gzip->name);
return (ARCHIVE_OK);
}
@@ -308,85 +300,95 @@ gzip_reader_vtable = {
* Initialize the filter object.
*/
static int
-gzip_bidder_init(struct archive_read_filter *self)
+gzip_bidder_init(struct archive_read_filter *f)
{
- struct private_data *state;
+ struct gzip *gzip;
static const size_t out_block_size = 64 * 1024;
void *out_block;
- self->code = ARCHIVE_FILTER_GZIP;
- self->name = "gzip";
+ f->code = ARCHIVE_FILTER_GZIP;
+ f->name = "gzip";
- state = calloc(1, sizeof(*state));
+ gzip = calloc(1, sizeof(*gzip));
out_block = malloc(out_block_size);
- if (state == NULL || out_block == NULL) {
+ if (gzip == NULL || out_block == NULL) {
free(out_block);
- free(state);
- archive_set_error(&self->archive->archive, ENOMEM,
+ free(gzip);
+ archive_set_error(&f->archive->archive, ENOMEM,
"Can't allocate data for gzip decompression");
return (ARCHIVE_FATAL);
}
- self->data = state;
- state->out_block_size = out_block_size;
- state->out_block = out_block;
- self->vtable = &gzip_reader_vtable;
+ f->data = gzip;
+ gzip->out_block_size = out_block_size;
+ gzip->out_block = out_block;
+ f->vtable = &gzip_reader_vtable;
- state->in_stream = 0; /* We're not actually within a stream yet. */
+ gzip->in_stream = 0; /* We're not actually within a stream yet. */
return (ARCHIVE_OK);
}
static int
-consume_header(struct archive_read_filter *self)
+consume_header(struct archive_read_filter *f)
{
- struct private_data *state;
- ssize_t avail;
+ struct gzip *gzip = f->data;
+ ssize_t avail, max_in;
size_t len;
int ret;
- state = (struct private_data *)self->data;
-
/* If this is a real header, consume it. */
- len = peek_at_header(self->upstream, NULL, state);
+ len = peek_at_header(f->upstream, NULL, gzip);
if (len == 0)
return (ARCHIVE_EOF);
- __archive_read_filter_consume(self->upstream, len);
+ __archive_read_filter_consume(f->upstream, len);
/* Initialize CRC accumulator. */
- state->crc = crc32(0L, NULL, 0);
+ gzip->crc = crc32(0L, NULL, 0);
/* Initialize compression library. */
- state->stream.next_in = (unsigned char *)(uintptr_t)
- __archive_read_filter_ahead(self->upstream, 1, &avail);
- state->stream.avail_in = (uInt)avail;
- ret = inflateInit2(&(state->stream),
+ gzip->stream.next_in = (unsigned char *)(uintptr_t)
+ __archive_read_filter_ahead(f->upstream, 1, &avail);
+ if (avail < 0) {
+ archive_set_error(&f->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Failed to read gzip input");
+ return (ARCHIVE_FATAL);
+ }
+ if (UINT_MAX >= SSIZE_MAX)
+ max_in = SSIZE_MAX;
+ else
+ max_in = UINT_MAX;
+ if (avail > max_in)
+ avail = max_in;
+ gzip->stream.avail_in = (uInt)avail;
+ ret = inflateInit2(&(gzip->stream),
-15 /* Don't check for zlib header */);
/* Decipher the error code. */
switch (ret) {
case Z_OK:
- state->in_stream = 1;
+ gzip->in_stream = 1;
return (ARCHIVE_OK);
case Z_STREAM_ERROR:
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library: "
"invalid setup parameter");
break;
case Z_MEM_ERROR:
- archive_set_error(&self->archive->archive, ENOMEM,
+ archive_set_error(&f->archive->archive, ENOMEM,
"Internal error initializing compression library: "
"out of memory");
break;
case Z_VERSION_ERROR:
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library: "
"invalid library version");
break;
default:
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library: "
" Zlib error %d", ret);
@@ -396,60 +398,55 @@ consume_header(struct archive_read_filter *self)
}
static int
-consume_trailer(struct archive_read_filter *self)
+consume_trailer(struct archive_read_filter *f)
{
- struct private_data *state;
+ struct gzip *gzip = f->data;
const unsigned char *p;
- ssize_t avail;
- state = (struct private_data *)self->data;
-
- state->in_stream = 0;
- switch (inflateEnd(&(state->stream))) {
+ gzip->in_stream = 0;
+ switch (inflateEnd(&(gzip->stream))) {
case Z_OK:
break;
default:
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Failed to clean up gzip decompressor");
return (ARCHIVE_FATAL);
}
/* GZip trailer is a fixed 8 byte structure. */
- p = __archive_read_filter_ahead(self->upstream, 8, &avail);
- if (p == NULL || avail == 0)
+ p = __archive_read_filter_ahead(f->upstream, 8, NULL);
+ if (p == NULL)
return (ARCHIVE_FATAL);
/* XXX TODO: Verify the length and CRC. */
/* We've verified the trailer, so consume it now. */
- __archive_read_filter_consume(self->upstream, 8);
+ __archive_read_filter_consume(f->upstream, 8);
return (ARCHIVE_OK);
}
static ssize_t
-gzip_filter_read(struct archive_read_filter *self, const void **p)
+gzip_filter_read(struct archive_read_filter *f, const void **p)
{
- struct private_data *state;
+ struct gzip *gzip = f->data;
size_t decompressed;
ssize_t avail_in, max_in;
int ret;
- state = (struct private_data *)self->data;
-
/* Empty our output buffer. */
- state->stream.next_out = state->out_block;
- state->stream.avail_out = (uInt)state->out_block_size;
+ gzip->stream.next_out = gzip->out_block;
+ gzip->stream.avail_out = (uInt)gzip->out_block_size;
/* Try to fill the output buffer. */
- while (state->stream.avail_out > 0 && !state->eof) {
+ while (gzip->stream.avail_out > 0 && !gzip->eof) {
/* If we're not in a stream, read a header
* and initialize the decompression library. */
- if (!state->in_stream) {
- ret = consume_header(self);
+ if (!gzip->in_stream) {
+ ret = consume_header(f);
if (ret == ARCHIVE_EOF) {
- state->eof = 1;
+ gzip->eof = 1;
break;
}
if (ret < ARCHIVE_OK)
@@ -459,10 +456,10 @@ gzip_filter_read(struct archive_read_filter *self, const void **p)
/* Peek at the next available data. */
/* ZLib treats stream.next_in as const but doesn't declare
* it so, hence this ugly cast. */
- state->stream.next_in = (unsigned char *)(uintptr_t)
- __archive_read_filter_ahead(self->upstream, 1, &avail_in);
- if (state->stream.next_in == NULL) {
- archive_set_error(&self->archive->archive,
+ gzip->stream.next_in = (unsigned char *)(uintptr_t)
+ __archive_read_filter_ahead(f->upstream, 1, &avail_in);
+ if (gzip->stream.next_in == NULL) {
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"truncated gzip input");
return (ARCHIVE_FATAL);
@@ -473,27 +470,27 @@ gzip_filter_read(struct archive_read_filter *self, const void **p)
max_in = UINT_MAX;
if (avail_in > max_in)
avail_in = max_in;
- state->stream.avail_in = (uInt)avail_in;
+ gzip->stream.avail_in = (uInt)avail_in;
/* Decompress and consume some of that data. */
- ret = inflate(&(state->stream), 0);
+ ret = inflate(&(gzip->stream), 0);
switch (ret) {
case Z_OK: /* Decompressor made some progress. */
- __archive_read_filter_consume(self->upstream,
- avail_in - state->stream.avail_in);
+ __archive_read_filter_consume(f->upstream,
+ avail_in - gzip->stream.avail_in);
break;
case Z_STREAM_END: /* Found end of stream. */
- __archive_read_filter_consume(self->upstream,
- avail_in - state->stream.avail_in);
+ __archive_read_filter_consume(f->upstream,
+ avail_in - gzip->stream.avail_in);
/* Consume the stream trailer; release the
* decompression library. */
- ret = consume_trailer(self);
+ ret = consume_trailer(f);
if (ret < ARCHIVE_OK)
return (ret);
break;
default:
/* Return an error. */
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"gzip decompression failed");
return (ARCHIVE_FATAL);
@@ -501,12 +498,11 @@ gzip_filter_read(struct archive_read_filter *self, const void **p)
}
/* We've read as much as we can. */
- decompressed = state->stream.next_out - state->out_block;
- state->total_out += decompressed;
+ decompressed = gzip->stream.next_out - gzip->out_block;
if (decompressed == 0)
*p = NULL;
else
- *p = state->out_block;
+ *p = gzip->out_block;
return (decompressed);
}
@@ -514,29 +510,28 @@ gzip_filter_read(struct archive_read_filter *self, const void **p)
* Clean up the decompressor.
*/
static int
-gzip_filter_close(struct archive_read_filter *self)
+gzip_filter_close(struct archive_read_filter *f)
{
- struct private_data *state;
+ struct gzip *gzip = f->data;
int ret;
- state = (struct private_data *)self->data;
ret = ARCHIVE_OK;
- if (state->in_stream) {
- switch (inflateEnd(&(state->stream))) {
+ if (gzip->in_stream) {
+ switch (inflateEnd(&(gzip->stream))) {
case Z_OK:
break;
default:
- archive_set_error(&(self->archive->archive),
+ archive_set_error(&(f->archive->archive),
ARCHIVE_ERRNO_MISC,
"Failed to clean up gzip compressor");
ret = ARCHIVE_FATAL;
}
}
- free(state->name);
- free(state->out_block);
- free(state);
+ free(gzip->name);
+ free(gzip->out_block);
+ free(gzip);
return (ret);
}
diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_lrzip.c b/contrib/libarchive/libarchive/archive_read_support_filter_lrzip.c
index a562d538ed81..33910fe10a09 100644
--- a/contrib/libarchive/libarchive/archive_read_support_filter_lrzip.c
+++ b/contrib/libarchive/libarchive/archive_read_support_filter_lrzip.c
@@ -75,19 +75,19 @@ archive_read_support_filter_lrzip(struct archive *_a)
* Bidder just verifies the header and returns the number of verified bits.
*/
static int
-lrzip_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
+lrzip_bidder_bid(struct archive_read_filter_bidder *b,
+ struct archive_read_filter *f)
{
const unsigned char *p;
- ssize_t avail, len;
+ ssize_t len;
int i;
- (void)self; /* UNUSED */
+ (void)b; /* UNUSED */
/* Start by looking at the first six bytes of the header, which
* is all fixed layout. */
len = 6;
- p = __archive_read_filter_ahead(filter, len, &avail);
- if (p == NULL || avail == 0)
+ p = __archive_read_filter_ahead(f, len, NULL);
+ if (p == NULL)
return (0);
if (memcmp(p, LRZIP_HEADER_MAGIC, LRZIP_HEADER_MAGIC_LEN))
@@ -105,15 +105,15 @@ lrzip_bidder_bid(struct archive_read_filter_bidder *self,
}
static int
-lrzip_bidder_init(struct archive_read_filter *self)
+lrzip_bidder_init(struct archive_read_filter *f)
{
int r;
- r = __archive_read_program(self, "lrzip -d -q");
+ r = __archive_read_program(f, "lrzip -d -q");
/* Note: We set the format here even if __archive_read_program()
* above fails. We do, after all, know what the format is
* even if we weren't able to read it. */
- self->code = ARCHIVE_FILTER_LRZIP;
- self->name = "lrzip";
+ f->code = ARCHIVE_FILTER_LRZIP;
+ f->name = "lrzip";
return (r);
}
diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_lz4.c b/contrib/libarchive/libarchive/archive_read_support_filter_lz4.c
index acd7f5157997..19086a1fefb2 100644
--- a/contrib/libarchive/libarchive/archive_read_support_filter_lz4.c
+++ b/contrib/libarchive/libarchive/archive_read_support_filter_lz4.c
@@ -44,6 +44,7 @@
#include "archive.h"
#include "archive_endian.h"
+#include "archive_integer.h"
#include "archive_private.h"
#include "archive_read_private.h"
#include "archive_xxhash.h"
@@ -56,7 +57,7 @@
#define LZ4_SKIPPABLE_MASK 0xFFFFFFF0
#if defined(HAVE_LIBLZ4)
-struct private_data {
+struct lz4 {
enum { SELECT_STREAM,
READ_DEFAULT_STREAM,
READ_DEFAULT_BLOCK,
@@ -95,8 +96,7 @@ static int lz4_filter_close(struct archive_read_filter *);
/*
* Note that we can detect lz4 archives even if we can't decompress
* them. (In fact, we like detecting them because we can give better
- * error messages.) So the bid framework here gets compiled even
- * if liblz4 is unavailable.
+ * error messages.)
*/
static int lz4_reader_bid(struct archive_read_filter_bidder *, struct archive_read_filter *);
static int lz4_reader_init(struct archive_read_filter *);
@@ -139,58 +139,81 @@ archive_read_support_filter_lz4(struct archive *_a)
* from verifying as much as we would like.
*/
static int
-lz4_reader_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
+lz4_reader_bid(struct archive_read_filter_bidder *b,
+ struct archive_read_filter *f)
{
const unsigned char *buffer;
ssize_t avail;
int bits_checked = 0;
- ssize_t min_lz4_archive_size = 11;
+ const size_t min_lz4_archive_size = 11;
- // LZ4 skippable frames contain a 4 byte magic number followed by
- // a 4 byte frame data size, then that number of bytes of data. Regular
- // frames contain a 4 byte magic number followed by a 2-14 byte frame
- // header, some data, and a 3 byte end marker.
- ssize_t min_lz4_frame_size = 8;
+ /*
+ * LZ4 skippable frames contain a 4 byte magic number followed by
+ * a 4 byte frame data size, then that number of bytes of data.
+ * Regular frames contain a 4 byte magic number followed by a 2-14
+ * byte frame header, some data, and a 3 byte end marker.
+ */
+ const size_t min_lz4_frame_size = 8;
- ssize_t offset_in_buffer = 0;
- ssize_t max_lookahead = 64 * 1024;
+ size_t offset_in_buffer = 0;
+ const size_t max_lookahead = 64 * 1024;
+ uint32_t magic_number;
- (void)self; // UNUSED
+ (void)b; /* UNUSED */
- // Zstd and LZ4 skippable frame magic numbers are identical. To
- // differentiate these two, we need to look for a non-skippable
- // frame.
+ /*
+ * Zstd and LZ4 skippable frame magic numbers are identical. To
+ * differentiate these two, we need to look for a non-skippable
+ * frame.
+ */
- // Minimal lz4 archive is 11 bytes.
- buffer = __archive_read_filter_ahead(filter, min_lz4_archive_size, &avail);
+ /* Minimal lz4 archive is 11 bytes. */
+ buffer = __archive_read_filter_ahead(f, min_lz4_archive_size,
+ &avail);
if (buffer == NULL)
return (0);
- uint32_t magic_number = archive_le32dec(buffer);
+ magic_number = archive_le32dec(buffer);
while ((magic_number & LZ4_SKIPPABLE_MASK) == LZ4_SKIPPABLE_START) {
+ size_t min;
+ uint32_t frame_data_size;
- offset_in_buffer += 4; // Skip over the magic number
+ /* Skip over the magic number */
+ offset_in_buffer += 4;
- // Ensure that we can read another 4 bytes.
- if (offset_in_buffer + 4 > avail) {
- buffer = __archive_read_filter_ahead(filter, offset_in_buffer + 4, &avail);
+ /* Ensure that we can read another 4 bytes. */
+ if (offset_in_buffer + 4 > (size_t)avail) {
+ buffer = __archive_read_filter_ahead(f,
+ offset_in_buffer + 4, &avail);
if (buffer == NULL)
return (0);
}
- uint32_t frame_data_size = archive_le32dec(buffer + offset_in_buffer);
+ frame_data_size = archive_le32dec(buffer + offset_in_buffer);
+
+ /* Skip over the 4 frame data size bytes */
+ offset_in_buffer += 4;
- // Skip over the 4 frame data size bytes, plus the value stored there.
- offset_in_buffer += 4 + frame_data_size;
+ /* Skip over the value stored there. */
+ if (archive_ckd_add_size(&offset_in_buffer,
+ offset_in_buffer, frame_data_size))
+ return (0);
- // There should be at least one more frame if this is LZ4 data.
- if (offset_in_buffer + min_lz4_frame_size > avail) { // TODO: should this be >= ?
- if (offset_in_buffer + min_lz4_frame_size > max_lookahead)
+ /*
+ * There should be at least one more frame
+ * if this is LZ4 data.
+ */
+ if (archive_ckd_add_size(&min,
+ offset_in_buffer, min_lz4_frame_size))
+ return (0);
+ /* TODO: should this be >= ? */
+ if (min > (size_t)avail) {
+ if (min > max_lookahead)
return (0);
- buffer = __archive_read_filter_ahead(filter, offset_in_buffer + min_lz4_frame_size, &avail);
+ buffer = __archive_read_filter_ahead(f,
+ min, &avail);
if (buffer == NULL)
return (0);
}
@@ -198,8 +221,10 @@ lz4_reader_bid(struct archive_read_filter_bidder *self,
magic_number = archive_le32dec(buffer + offset_in_buffer);
}
- // We have skipped over any skippable frames. Either a regular LZ4 frame
- // follows, or this isn't LZ4 data.
+ /*
+ * We have skipped over any skippable frames. Either a regular LZ4 frame
+ * follows, or this isn't LZ4 data.
+ */
bits_checked = offset_in_buffer;
buffer = buffer + offset_in_buffer;
@@ -241,21 +266,21 @@ lz4_reader_bid(struct archive_read_filter_bidder *self,
#if !defined(HAVE_LIBLZ4)
/*
- * If we don't have the library on this system, we can't actually do the
- * decompression. We can, however, still detect compressed archives
- * and emit a useful message.
+ * If we don't have the library on this system, we can't do the
+ * decompression directly. We can, however, try to run "lz4 -d -q"
+ * in case that's available.
*/
static int
-lz4_reader_init(struct archive_read_filter *self)
+lz4_reader_init(struct archive_read_filter *f)
{
int r;
- r = __archive_read_program(self, "lz4 -d -q");
+ r = __archive_read_program(f, "lz4 -d -q");
/* Note: We set the format here even if __archive_read_program()
* above fails. We do, after all, know what the format is
* even if we weren't able to read it. */
- self->code = ARCHIVE_FILTER_LZ4;
- self->name = "lz4";
+ f->code = ARCHIVE_FILTER_LZ4;
+ f->name = "lz4";
return (r);
}
@@ -272,69 +297,73 @@ lz4_reader_vtable = {
* Setup the callbacks.
*/
static int
-lz4_reader_init(struct archive_read_filter *self)
+lz4_reader_init(struct archive_read_filter *f)
{
- struct private_data *state;
+ struct lz4 *lz4;
- self->code = ARCHIVE_FILTER_LZ4;
- self->name = "lz4";
+ f->code = ARCHIVE_FILTER_LZ4;
+ f->name = "lz4";
- state = calloc(1, sizeof(*state));
- if (state == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
+ lz4 = calloc(1, sizeof(*lz4));
+ if (lz4 == NULL) {
+ archive_set_error(&f->archive->archive, ENOMEM,
"Can't allocate data for lz4 decompression");
return (ARCHIVE_FATAL);
}
- self->data = state;
- state->stage = SELECT_STREAM;
- self->vtable = &lz4_reader_vtable;
+ f->data = lz4;
+ lz4->stage = SELECT_STREAM;
+ f->vtable = &lz4_reader_vtable;
return (ARCHIVE_OK);
}
static int
-lz4_allocate_out_block(struct archive_read_filter *self)
+lz4_allocate_out_block(struct archive_read_filter *f)
{
- struct private_data *state = (struct private_data *)self->data;
- size_t out_block_size = state->flags.block_maximum_size;
+ struct lz4 *lz4 = f->data;
+ size_t out_block_size = lz4->flags.block_maximum_size;
void *out_block;
- if (!state->flags.block_independence)
+ if (!lz4->flags.block_independence)
out_block_size += 64 * 1024;
- if (state->out_block_size < out_block_size) {
- free(state->out_block);
+ if (lz4->out_block_size < out_block_size) {
+ free(lz4->out_block);
+ lz4->out_block = NULL;
out_block = malloc(out_block_size);
- state->out_block_size = out_block_size;
if (out_block == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
+ lz4->out_block_size = 0;
+ archive_set_error(&f->archive->archive, ENOMEM,
"Can't allocate data for lz4 decompression");
return (ARCHIVE_FATAL);
}
- state->out_block = out_block;
+ lz4->out_block_size = out_block_size;
+ lz4->out_block = out_block;
}
- if (!state->flags.block_independence)
- memset(state->out_block, 0, 64 * 1024);
+ if (!lz4->flags.block_independence)
+ memset(lz4->out_block, 0, 64 * 1024);
return (ARCHIVE_OK);
}
static int
-lz4_allocate_out_block_for_legacy(struct archive_read_filter *self)
+lz4_allocate_out_block_for_legacy(struct archive_read_filter *f)
{
- struct private_data *state = (struct private_data *)self->data;
+ struct lz4 *lz4 = f->data;
size_t out_block_size = LEGACY_BLOCK_SIZE;
void *out_block;
- if (state->out_block_size < out_block_size) {
- free(state->out_block);
+ if (lz4->out_block_size < out_block_size) {
+ free(lz4->out_block);
+ lz4->out_block = NULL;
out_block = malloc(out_block_size);
- state->out_block_size = out_block_size;
if (out_block == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
+ lz4->out_block_size = 0;
+ archive_set_error(&f->archive->archive, ENOMEM,
"Can't allocate data for lz4 decompression");
return (ARCHIVE_FATAL);
}
- state->out_block = out_block;
+ lz4->out_block_size = out_block_size;
+ lz4->out_block = out_block;
}
return (ARCHIVE_OK);
}
@@ -343,90 +372,96 @@ lz4_allocate_out_block_for_legacy(struct archive_read_filter *self)
* Return the next block of decompressed data.
*/
static ssize_t
-lz4_filter_read(struct archive_read_filter *self, const void **p)
+lz4_filter_read(struct archive_read_filter *f, const void **p)
{
- struct private_data *state = (struct private_data *)self->data;
+ struct lz4 *lz4 = f->data;
ssize_t ret;
- if (state->eof) {
+ if (lz4->eof) {
*p = NULL;
return (0);
}
- __archive_read_filter_consume(self->upstream, state->unconsumed);
- state->unconsumed = 0;
+ __archive_read_filter_consume(f->upstream, lz4->unconsumed);
+ lz4->unconsumed = 0;
- switch (state->stage) {
+ switch (lz4->stage) {
case SELECT_STREAM:
break;
case READ_DEFAULT_STREAM:
case READ_LEGACY_STREAM:
- /* Reading a lz4 stream already failed. */
- archive_set_error(&self->archive->archive,
+ /* Reading an lz4 stream already failed. */
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC, "Invalid sequence");
return (ARCHIVE_FATAL);
case READ_DEFAULT_BLOCK:
- ret = lz4_filter_read_default_stream(self, p);
- if (ret != 0 || state->stage != SELECT_STREAM)
+ ret = lz4_filter_read_default_stream(f, p);
+ if (ret != 0 || lz4->stage != SELECT_STREAM)
return ret;
break;
case READ_LEGACY_BLOCK:
- ret = lz4_filter_read_legacy_stream(self, p);
- if (ret != 0 || state->stage != SELECT_STREAM)
+ ret = lz4_filter_read_legacy_stream(f, p);
+ if (ret != 0 || lz4->stage != SELECT_STREAM)
return ret;
break;
default:
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC, "Program error");
return (ARCHIVE_FATAL);
}
- while (state->stage == SELECT_STREAM) {
+ while (lz4->stage == SELECT_STREAM) {
const char *read_buf;
/* Read a magic number. */
- read_buf = __archive_read_filter_ahead(self->upstream, 4,
+ read_buf = __archive_read_filter_ahead(f->upstream, 4,
NULL);
if (read_buf == NULL) {
- state->eof = 1;
+ lz4->eof = 1;
*p = NULL;
return (0);
}
uint32_t number = archive_le32dec(read_buf);
- __archive_read_filter_consume(self->upstream, 4);
+ __archive_read_filter_consume(f->upstream, 4);
if (number == LZ4_MAGICNUMBER)
- return lz4_filter_read_default_stream(self, p);
+ return lz4_filter_read_default_stream(f, p);
else if (number == LZ4_LEGACY)
- return lz4_filter_read_legacy_stream(self, p);
+ return lz4_filter_read_legacy_stream(f, p);
else if ((number & LZ4_SKIPPABLE_MASK) == LZ4_SKIPPABLE_START) {
read_buf = __archive_read_filter_ahead(
- self->upstream, 4, NULL);
+ f->upstream, 4, NULL);
if (read_buf == NULL) {
archive_set_error(
- &self->archive->archive,
+ &f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Malformed lz4 data");
return (ARCHIVE_FATAL);
}
- uint32_t skip_bytes = archive_le32dec(read_buf);
- __archive_read_filter_consume(self->upstream,
- 4 + skip_bytes);
+ int64_t skip_bytes = archive_le32dec(read_buf);
+ if (__archive_read_filter_consume(f->upstream,
+ 4 + skip_bytes) < 0) {
+ archive_set_error(
+ &f->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Malformed lz4 data");
+ return (ARCHIVE_FATAL);
+ }
} else {
/* Ignore following unrecognized data. */
- state->eof = 1;
+ lz4->eof = 1;
*p = NULL;
return (0);
}
}
- state->eof = 1;
+ lz4->eof = 1;
*p = NULL;
return (0);
}
static int
-lz4_filter_read_descriptor(struct archive_read_filter *self)
+lz4_filter_read_descriptor(struct archive_read_filter *f)
{
- struct private_data *state = (struct private_data *)self->data;
+ struct lz4 *lz4 = f->data;
const char *read_buf;
ssize_t bytes_remaining;
ssize_t descriptor_bytes;
@@ -434,10 +469,10 @@ lz4_filter_read_descriptor(struct archive_read_filter *self)
unsigned int chsum, chsum_verifier;
/* Make sure we have 2 bytes for flags. */
- read_buf = __archive_read_filter_ahead(self->upstream, 2,
+ read_buf = __archive_read_filter_ahead(f->upstream, 2,
&bytes_remaining);
if (read_buf == NULL) {
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"truncated lz4 input");
return (ARCHIVE_FATAL);
@@ -453,11 +488,11 @@ lz4_filter_read_descriptor(struct archive_read_filter *self)
/* A reserved bit must be zero. */
if (flag & 0x02)
goto malformed_error;
- state->flags.block_independence = (flag & 0x20) != 0;
- state->flags.block_checksum = (flag & 0x10)?4:0;
- state->flags.stream_size = (flag & 0x08) != 0;
- state->flags.stream_checksum = (flag & 0x04) != 0;
- state->flags.preset_dictionary = (flag & 0x01) != 0;
+ lz4->flags.block_independence = (flag & 0x20) != 0;
+ lz4->flags.block_checksum = (flag & 0x10)?4:0;
+ lz4->flags.stream_size = (flag & 0x08) != 0;
+ lz4->flags.stream_checksum = (flag & 0x04) != 0;
+ lz4->flags.preset_dictionary = (flag & 0x01) != 0;
/* BD */
bd = (unsigned char)read_buf[1];
@@ -467,16 +502,16 @@ lz4_filter_read_descriptor(struct archive_read_filter *self)
/* Get a maximum block size. */
switch (read_buf[1] >> 4) {
case 4: /* 64 KB */
- state->flags.block_maximum_size = 64 * 1024;
+ lz4->flags.block_maximum_size = 64 * 1024;
break;
case 5: /* 256 KB */
- state->flags.block_maximum_size = 256 * 1024;
+ lz4->flags.block_maximum_size = 256 * 1024;
break;
case 6: /* 1 MB */
- state->flags.block_maximum_size = 1024 * 1024;
+ lz4->flags.block_maximum_size = 1024 * 1024;
break;
case 7: /* 4 MB */
- state->flags.block_maximum_size = 4 * 1024 * 1024;
+ lz4->flags.block_maximum_size = 4 * 1024 * 1024;
break;
default:
goto malformed_error;
@@ -484,15 +519,15 @@ lz4_filter_read_descriptor(struct archive_read_filter *self)
/* Read the whole descriptor in a stream block. */
descriptor_bytes = 3;
- if (state->flags.stream_size)
+ if (lz4->flags.stream_size)
descriptor_bytes += 8;
- if (state->flags.preset_dictionary)
+ if (lz4->flags.preset_dictionary)
descriptor_bytes += 4;
if (bytes_remaining < descriptor_bytes) {
- read_buf = __archive_read_filter_ahead(self->upstream,
+ read_buf = __archive_read_filter_ahead(f->upstream,
descriptor_bytes, &bytes_remaining);
if (read_buf == NULL) {
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"truncated lz4 input");
return (ARCHIVE_FATAL);
@@ -507,30 +542,32 @@ lz4_filter_read_descriptor(struct archive_read_filter *self)
goto malformed_error;
#endif
- __archive_read_filter_consume(self->upstream, descriptor_bytes);
+ __archive_read_filter_consume(f->upstream, descriptor_bytes);
/* Make sure we have a large enough buffer for uncompressed data. */
- if (lz4_allocate_out_block(self) != ARCHIVE_OK)
+ if (lz4_allocate_out_block(f) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
- if (state->flags.stream_checksum)
- state->xxh32_state = __archive_xxhash.XXH32_init(0);
+ if (lz4->flags.stream_checksum) {
+ lz4->xxh32_state = __archive_xxhash.XXH32_init(0);
+ if (lz4->xxh32_state == NULL)
+ return (ARCHIVE_FATAL);
+ }
- state->decoded_size = 0;
+ lz4->decoded_size = 0;
/* Success */
return (ARCHIVE_OK);
malformed_error:
- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
"malformed lz4 data");
return (ARCHIVE_FATAL);
}
static ssize_t
-lz4_filter_read_data_block(struct archive_read_filter *self, const void **p)
+lz4_filter_read_data_block(struct archive_read_filter *f, const void **p)
{
- struct private_data *state = (struct private_data *)self->data;
+ struct lz4 *lz4 = f->data;
ssize_t compressed_size;
const char *read_buf;
- ssize_t bytes_remaining;
int checksum_size;
ssize_t uncompressed_size;
size_t prefix64k;
@@ -538,20 +575,19 @@ lz4_filter_read_data_block(struct archive_read_filter *self, const void **p)
*p = NULL;
/* Make sure we have 4 bytes for a block size. */
- read_buf = __archive_read_filter_ahead(self->upstream, 4,
- &bytes_remaining);
+ read_buf = __archive_read_filter_ahead(f->upstream, 4, NULL);
if (read_buf == NULL)
goto truncated_error;
compressed_size = archive_le32dec(read_buf);
- if ((compressed_size & 0x7fffffff) > state->flags.block_maximum_size)
+ if ((compressed_size & 0x7fffffff) > lz4->flags.block_maximum_size)
goto malformed_error;
/* A compressed size == 0 means the end of stream blocks. */
if (compressed_size == 0) {
- __archive_read_filter_consume(self->upstream, 4);
+ __archive_read_filter_consume(f->upstream, 4);
return 0;
}
- checksum_size = state->flags.block_checksum;
+ checksum_size = lz4->flags.block_checksum;
/* Check if the block is uncompressed. */
if (compressed_size & 0x80000000U) {
compressed_size &= 0x7fffffff;
@@ -564,8 +600,8 @@ lz4_filter_read_data_block(struct archive_read_filter *self, const void **p)
for its decompression speed, so we read a whole block and allocate
a huge buffer used for decoded data.
*/
- read_buf = __archive_read_filter_ahead(self->upstream,
- 4 + compressed_size + checksum_size, &bytes_remaining);
+ read_buf = __archive_read_filter_ahead(f->upstream,
+ 4 + compressed_size + checksum_size, NULL);
if (read_buf == NULL)
goto truncated_error;
@@ -585,24 +621,24 @@ lz4_filter_read_data_block(struct archive_read_filter *self, const void **p)
/* If the block is uncompressed, there is nothing to do. */
if (uncompressed_size) {
/* Prepare a prefix 64k block for next block. */
- if (!state->flags.block_independence) {
+ if (!lz4->flags.block_independence) {
prefix64k = 64 * 1024;
if (uncompressed_size < (ssize_t)prefix64k) {
- memcpy(state->out_block
+ memcpy(lz4->out_block
+ prefix64k - uncompressed_size,
read_buf + 4,
uncompressed_size);
- memset(state->out_block, 0,
+ memset(lz4->out_block, 0,
prefix64k - uncompressed_size);
} else {
- memcpy(state->out_block,
+ memcpy(lz4->out_block,
read_buf + 4
+ uncompressed_size - prefix64k,
prefix64k);
}
- state->decoded_size = 0;
+ lz4->decoded_size = 0;
}
- state->unconsumed = 4 + uncompressed_size + checksum_size;
+ lz4->unconsumed = 4 + uncompressed_size + checksum_size;
*p = read_buf + 4;
return uncompressed_size;
}
@@ -610,169 +646,168 @@ lz4_filter_read_data_block(struct archive_read_filter *self, const void **p)
/*
Decompress a block data.
*/
- if (state->flags.block_independence) {
+ if (lz4->flags.block_independence) {
prefix64k = 0;
uncompressed_size = LZ4_decompress_safe(read_buf + 4,
- state->out_block, (int)compressed_size,
- state->flags.block_maximum_size);
+ lz4->out_block, (int)compressed_size,
+ lz4->flags.block_maximum_size);
} else {
prefix64k = 64 * 1024;
- if (state->decoded_size) {
- if (state->decoded_size < prefix64k) {
- memmove(state->out_block
- + prefix64k - state->decoded_size,
- state->out_block + prefix64k,
- state->decoded_size);
- memset(state->out_block, 0,
- prefix64k - state->decoded_size);
+ if (lz4->decoded_size) {
+ if (lz4->decoded_size < prefix64k) {
+ memmove(lz4->out_block
+ + prefix64k - lz4->decoded_size,
+ lz4->out_block + prefix64k,
+ lz4->decoded_size);
+ memset(lz4->out_block, 0,
+ prefix64k - lz4->decoded_size);
} else {
- memmove(state->out_block,
- state->out_block + state->decoded_size,
+ memmove(lz4->out_block,
+ lz4->out_block + lz4->decoded_size,
prefix64k);
}
}
#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
uncompressed_size = LZ4_decompress_safe_usingDict(
read_buf + 4,
- state->out_block + prefix64k, (int)compressed_size,
- state->flags.block_maximum_size,
- state->out_block,
+ lz4->out_block + prefix64k, (int)compressed_size,
+ lz4->flags.block_maximum_size,
+ lz4->out_block,
(int)prefix64k);
#else
uncompressed_size = LZ4_decompress_safe_withPrefix64k(
read_buf + 4,
- state->out_block + prefix64k, (int)compressed_size,
- state->flags.block_maximum_size);
+ lz4->out_block + prefix64k, (int)compressed_size,
+ lz4->flags.block_maximum_size);
#endif
}
/* Check if an error occurred in the decompression process. */
if (uncompressed_size < 0) {
- archive_set_error(&(self->archive->archive),
+ archive_set_error(&(f->archive->archive),
ARCHIVE_ERRNO_MISC, "lz4 decompression failed");
return (ARCHIVE_FATAL);
}
- state->unconsumed = 4 + compressed_size + checksum_size;
- *p = state->out_block + prefix64k;
- state->decoded_size = uncompressed_size;
+ lz4->unconsumed = 4 + compressed_size + checksum_size;
+ *p = lz4->out_block + prefix64k;
+ lz4->decoded_size = uncompressed_size;
return uncompressed_size;
malformed_error:
- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
"malformed lz4 data");
return (ARCHIVE_FATAL);
truncated_error:
- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
"truncated lz4 input");
return (ARCHIVE_FATAL);
}
static ssize_t
-lz4_filter_read_default_stream(struct archive_read_filter *self, const void **p)
+lz4_filter_read_default_stream(struct archive_read_filter *f, const void **p)
{
- struct private_data *state = (struct private_data *)self->data;
+ struct lz4 *lz4 = f->data;
const char *read_buf;
- ssize_t bytes_remaining;
ssize_t ret;
- if (state->stage == SELECT_STREAM) {
- state->stage = READ_DEFAULT_STREAM;
+ if (lz4->stage == SELECT_STREAM) {
+ lz4->stage = READ_DEFAULT_STREAM;
/* First, read a descriptor. */
- if((ret = lz4_filter_read_descriptor(self)) != ARCHIVE_OK)
+ if((ret = lz4_filter_read_descriptor(f)) != ARCHIVE_OK)
return (ret);
- state->stage = READ_DEFAULT_BLOCK;
+ lz4->stage = READ_DEFAULT_BLOCK;
}
/* Decompress a block. */
- ret = lz4_filter_read_data_block(self, p);
+ ret = lz4_filter_read_data_block(f, p);
/* If the end of block is detected, change the filter status
to read next stream. */
if (ret == 0 && *p == NULL)
- state->stage = SELECT_STREAM;
+ lz4->stage = SELECT_STREAM;
/* Optional processing, checking a stream sum. */
- if (state->flags.stream_checksum) {
- if (state->stage == SELECT_STREAM) {
+ if (lz4->flags.stream_checksum) {
+ if (lz4->stage == SELECT_STREAM) {
unsigned int checksum;
unsigned int checksum_stream;
- read_buf = __archive_read_filter_ahead(self->upstream,
- 4, &bytes_remaining);
+ read_buf = __archive_read_filter_ahead(f->upstream,
+ 4, NULL);
if (read_buf == NULL) {
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC, "truncated lz4 input");
return (ARCHIVE_FATAL);
}
checksum = archive_le32dec(read_buf);
- __archive_read_filter_consume(self->upstream, 4);
+ __archive_read_filter_consume(f->upstream, 4);
checksum_stream = __archive_xxhash.XXH32_digest(
- state->xxh32_state);
- state->xxh32_state = NULL;
+ lz4->xxh32_state);
+ lz4->xxh32_state = NULL;
if (checksum != checksum_stream) {
#ifndef DONT_FAIL_ON_CRC_ERROR
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"lz4 stream checksum error");
return (ARCHIVE_FATAL);
#endif
}
} else if (ret > 0)
- __archive_xxhash.XXH32_update(state->xxh32_state,
+ __archive_xxhash.XXH32_update(lz4->xxh32_state,
*p, (int)ret);
}
return (ret);
}
static ssize_t
-lz4_filter_read_legacy_stream(struct archive_read_filter *self, const void **p)
+lz4_filter_read_legacy_stream(struct archive_read_filter *f, const void **p)
{
- struct private_data *state = (struct private_data *)self->data;
+ struct lz4 *lz4 = f->data;
uint32_t compressed;
const char *read_buf;
ssize_t ret;
*p = NULL;
- ret = lz4_allocate_out_block_for_legacy(self);
+ ret = lz4_allocate_out_block_for_legacy(f);
if (ret != ARCHIVE_OK)
return ret;
/* Make sure we have 4 bytes for a block size. */
- read_buf = __archive_read_filter_ahead(self->upstream, 4, NULL);
+ read_buf = __archive_read_filter_ahead(f->upstream, 4, NULL);
if (read_buf == NULL) {
- if (state->stage == SELECT_STREAM) {
- state->stage = READ_LEGACY_STREAM;
- archive_set_error(&self->archive->archive,
+ if (lz4->stage == SELECT_STREAM) {
+ lz4->stage = READ_LEGACY_STREAM;
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"truncated lz4 input");
return (ARCHIVE_FATAL);
}
- state->stage = SELECT_STREAM;
+ lz4->stage = SELECT_STREAM;
return 0;
}
- state->stage = READ_LEGACY_BLOCK;
+ lz4->stage = READ_LEGACY_BLOCK;
compressed = archive_le32dec(read_buf);
if (compressed > LZ4_COMPRESSBOUND(LEGACY_BLOCK_SIZE)) {
- state->stage = SELECT_STREAM;
+ lz4->stage = SELECT_STREAM;
return 0;
}
/* Make sure we have a whole block. */
- read_buf = __archive_read_filter_ahead(self->upstream,
+ read_buf = __archive_read_filter_ahead(f->upstream,
4 + compressed, NULL);
if (read_buf == NULL) {
- archive_set_error(&(self->archive->archive),
+ archive_set_error(&(f->archive->archive),
ARCHIVE_ERRNO_MISC, "truncated lz4 input");
return (ARCHIVE_FATAL);
}
- ret = LZ4_decompress_safe(read_buf + 4, state->out_block,
- compressed, (int)state->out_block_size);
+ ret = LZ4_decompress_safe(read_buf + 4, lz4->out_block,
+ compressed, (int)lz4->out_block_size);
if (ret < 0) {
- archive_set_error(&(self->archive->archive),
+ archive_set_error(&(f->archive->archive),
ARCHIVE_ERRNO_MISC, "lz4 decompression failed");
return (ARCHIVE_FATAL);
}
- *p = state->out_block;
- state->unconsumed = 4 + compressed;
+ *p = lz4->out_block;
+ lz4->unconsumed = 4 + compressed;
return ret;
}
@@ -780,15 +815,14 @@ lz4_filter_read_legacy_stream(struct archive_read_filter *self, const void **p)
* Clean up the decompressor.
*/
static int
-lz4_filter_close(struct archive_read_filter *self)
+lz4_filter_close(struct archive_read_filter *f)
{
- struct private_data *state;
+ struct lz4 *lz4 = f->data;
int ret = ARCHIVE_OK;
- state = (struct private_data *)self->data;
- free(state->xxh32_state);
- free(state->out_block);
- free(state);
+ free(lz4->xxh32_state);
+ free(lz4->out_block);
+ free(lz4);
return (ret);
}
diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_lzop.c b/contrib/libarchive/libarchive/archive_read_support_filter_lzop.c
index 12ed78c578cd..ebfaf01e8533 100644
--- a/contrib/libarchive/libarchive/archive_read_support_filter_lzop.c
+++ b/contrib/libarchive/libarchive/archive_read_support_filter_lzop.c
@@ -68,10 +68,9 @@
#define LZOP_HEADER_MAGIC_LEN 9
#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
-struct read_lzop {
+struct lzop {
unsigned char *out_block;
size_t out_block_size;
- int64_t total_out;
int flags;
uint32_t compressed_cksum;
uint32_t uncompressed_cksum;
@@ -118,7 +117,6 @@ archive_read_support_filter_lzop(struct archive *_a)
#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
return (ARCHIVE_OK);
#else
- /* Return ARCHIVE_WARN since this always uses an external program. */
archive_set_error(_a, ARCHIVE_ERRNO_MISC,
"Using external lzop program for lzop decompression");
return (ARCHIVE_WARN);
@@ -129,16 +127,15 @@ archive_read_support_filter_lzop(struct archive *_a)
* Bidder just verifies the header and returns the number of verified bits.
*/
static int
-lzop_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
+lzop_bidder_bid(struct archive_read_filter_bidder *b,
+ struct archive_read_filter *f)
{
const unsigned char *p;
- ssize_t avail;
- (void)self; /* UNUSED */
+ (void)b; /* UNUSED */
- p = __archive_read_filter_ahead(filter, LZOP_HEADER_MAGIC_LEN, &avail);
- if (p == NULL || avail == 0)
+ p = __archive_read_filter_ahead(f, LZOP_HEADER_MAGIC_LEN, NULL);
+ if (p == NULL)
return (0);
if (memcmp(p, LZOP_HEADER_MAGIC, LZOP_HEADER_MAGIC_LEN))
@@ -154,16 +151,16 @@ lzop_bidder_bid(struct archive_read_filter_bidder *self,
* in case that's available.
*/
static int
-lzop_bidder_init(struct archive_read_filter *self)
+lzop_bidder_init(struct archive_read_filter *f)
{
int r;
- r = __archive_read_program(self, "lzop -d");
+ r = __archive_read_program(f, "lzop -d");
/* Note: We set the format here even if __archive_read_program()
* above fails. We do, after all, know what the format is
* even if we weren't able to read it. */
- self->code = ARCHIVE_FILTER_LZOP;
- self->name = "lzop";
+ f->code = ARCHIVE_FILTER_LZOP;
+ f->name = "lzop";
return (r);
}
#else
@@ -178,47 +175,47 @@ lzop_reader_vtable = {
* Initialize the filter object.
*/
static int
-lzop_bidder_init(struct archive_read_filter *self)
+lzop_bidder_init(struct archive_read_filter *f)
{
- struct read_lzop *state;
+ struct lzop *lzop;
- self->code = ARCHIVE_FILTER_LZOP;
- self->name = "lzop";
+ f->code = ARCHIVE_FILTER_LZOP;
+ f->name = "lzop";
- state = calloc(1, sizeof(*state));
- if (state == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
+ lzop = calloc(1, sizeof(*lzop));
+ if (lzop == NULL) {
+ archive_set_error(&f->archive->archive, ENOMEM,
"Can't allocate data for lzop decompression");
return (ARCHIVE_FATAL);
}
- self->data = state;
- self->vtable = &lzop_reader_vtable;
+ f->data = lzop;
+ f->vtable = &lzop_reader_vtable;
return (ARCHIVE_OK);
}
static int
-consume_header(struct archive_read_filter *self)
+consume_header(struct archive_read_filter *f)
{
- struct read_lzop *state = (struct read_lzop *)self->data;
+ struct lzop *lzop = f->data;
const unsigned char *p, *_p;
unsigned checksum, flags, len, method, version;
/*
* Check LZOP magic code.
*/
- p = __archive_read_filter_ahead(self->upstream,
+ p = __archive_read_filter_ahead(f->upstream,
LZOP_HEADER_MAGIC_LEN, NULL);
if (p == NULL)
return (ARCHIVE_EOF);
if (memcmp(p, LZOP_HEADER_MAGIC, LZOP_HEADER_MAGIC_LEN))
return (ARCHIVE_EOF);
- __archive_read_filter_consume(self->upstream,
+ __archive_read_filter_consume(f->upstream,
LZOP_HEADER_MAGIC_LEN);
- p = __archive_read_filter_ahead(self->upstream, 29, NULL);
+ p = __archive_read_filter_ahead(f->upstream, 29, NULL);
if (p == NULL)
goto truncated;
_p = p;
@@ -228,7 +225,7 @@ consume_header(struct archive_read_filter *self)
if (version >= 0x940) {
unsigned reqversion = archive_be16dec(p); p += 2;
if (reqversion < 0x900) {
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC, "Invalid required version");
return (ARCHIVE_FAILED);
}
@@ -236,7 +233,7 @@ consume_header(struct archive_read_filter *self)
method = *p++;
if (method < 1 || method > 3) {
- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
"Unsupported method");
return (ARCHIVE_FAILED);
}
@@ -255,7 +252,7 @@ consume_header(struct archive_read_filter *self)
;/* NOP */
#endif
else if (level > 9) {
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC, "Invalid level");
return (ARCHIVE_FAILED);
}
@@ -273,7 +270,7 @@ consume_header(struct archive_read_filter *self)
len = *p++; /* Read filename length */
len += p - _p;
/* Make sure we have all bytes we need to calculate checksum. */
- p = __archive_read_filter_ahead(self->upstream, len + 4, NULL);
+ p = __archive_read_filter_ahead(f->upstream, len + 4, NULL);
if (p == NULL)
goto truncated;
if (flags & CRC32_HEADER)
@@ -284,201 +281,199 @@ consume_header(struct archive_read_filter *self)
if (archive_be32dec(p + len) != checksum)
goto corrupted;
#endif
- __archive_read_filter_consume(self->upstream, len + 4);
+ __archive_read_filter_consume(f->upstream, len + 4);
if (flags & EXTRA_FIELD) {
/* Skip extra field */
- p = __archive_read_filter_ahead(self->upstream, 4, NULL);
+ p = __archive_read_filter_ahead(f->upstream, 4, NULL);
if (p == NULL)
goto truncated;
len = archive_be32dec(p);
- __archive_read_filter_consume(self->upstream,
+ __archive_read_filter_consume(f->upstream,
(int64_t)len + 4 + 4);
}
- state->flags = flags;
- state->in_stream = 1;
+ lzop->flags = flags;
+ lzop->in_stream = 1;
return (ARCHIVE_OK);
truncated:
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
return (ARCHIVE_FAILED);
corrupted:
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header");
return (ARCHIVE_FAILED);
}
static int
-consume_block_info(struct archive_read_filter *self)
+consume_block_info(struct archive_read_filter *f)
{
- struct read_lzop *state = (struct read_lzop *)self->data;
+ struct lzop *lzop = f->data;
const unsigned char *p;
- unsigned flags = state->flags;
+ unsigned flags = lzop->flags;
- p = __archive_read_filter_ahead(self->upstream, 4, NULL);
+ p = __archive_read_filter_ahead(f->upstream, 4, NULL);
if (p == NULL)
goto truncated;
- state->uncompressed_size = archive_be32dec(p);
- __archive_read_filter_consume(self->upstream, 4);
- if (state->uncompressed_size == 0)
+ lzop->uncompressed_size = archive_be32dec(p);
+ __archive_read_filter_consume(f->upstream, 4);
+ if (lzop->uncompressed_size == 0)
return (ARCHIVE_EOF);
- if (state->uncompressed_size > MAX_BLOCK_SIZE)
+ if (lzop->uncompressed_size > MAX_BLOCK_SIZE)
goto corrupted;
- p = __archive_read_filter_ahead(self->upstream, 4, NULL);
+ p = __archive_read_filter_ahead(f->upstream, 4, NULL);
if (p == NULL)
goto truncated;
- state->compressed_size = archive_be32dec(p);
- __archive_read_filter_consume(self->upstream, 4);
- if (state->compressed_size > state->uncompressed_size)
+ lzop->compressed_size = archive_be32dec(p);
+ __archive_read_filter_consume(f->upstream, 4);
+ if (lzop->compressed_size > lzop->uncompressed_size)
goto corrupted;
if (flags & (CRC32_UNCOMPRESSED | ADLER32_UNCOMPRESSED)) {
- p = __archive_read_filter_ahead(self->upstream, 4, NULL);
+ p = __archive_read_filter_ahead(f->upstream, 4, NULL);
if (p == NULL)
goto truncated;
- state->compressed_cksum = state->uncompressed_cksum =
+ lzop->compressed_cksum = lzop->uncompressed_cksum =
archive_be32dec(p);
- __archive_read_filter_consume(self->upstream, 4);
+ __archive_read_filter_consume(f->upstream, 4);
}
if ((flags & (CRC32_COMPRESSED | ADLER32_COMPRESSED)) &&
- state->compressed_size < state->uncompressed_size) {
- p = __archive_read_filter_ahead(self->upstream, 4, NULL);
+ lzop->compressed_size < lzop->uncompressed_size) {
+ p = __archive_read_filter_ahead(f->upstream, 4, NULL);
if (p == NULL)
goto truncated;
- state->compressed_cksum = archive_be32dec(p);
- __archive_read_filter_consume(self->upstream, 4);
+ lzop->compressed_cksum = archive_be32dec(p);
+ __archive_read_filter_consume(f->upstream, 4);
}
return (ARCHIVE_OK);
truncated:
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
return (ARCHIVE_FAILED);
corrupted:
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header");
return (ARCHIVE_FAILED);
}
static ssize_t
-lzop_filter_read(struct archive_read_filter *self, const void **p)
+lzop_filter_read(struct archive_read_filter *f, const void **p)
{
- struct read_lzop *state = (struct read_lzop *)self->data;
+ struct lzop *lzop = f->data;
const void *b;
lzo_uint out_size;
uint32_t cksum;
int ret, r;
- if (state->unconsumed_bytes) {
- __archive_read_filter_consume(self->upstream,
- state->unconsumed_bytes);
- state->unconsumed_bytes = 0;
+ if (lzop->unconsumed_bytes) {
+ __archive_read_filter_consume(f->upstream,
+ lzop->unconsumed_bytes);
+ lzop->unconsumed_bytes = 0;
}
- if (state->eof)
+ if (lzop->eof)
return (0);
for (;;) {
- if (!state->in_stream) {
- ret = consume_header(self);
+ if (!lzop->in_stream) {
+ ret = consume_header(f);
if (ret < ARCHIVE_OK)
return (ret);
if (ret == ARCHIVE_EOF) {
- state->eof = 1;
+ lzop->eof = 1;
return (0);
}
}
- ret = consume_block_info(self);
+ ret = consume_block_info(f);
if (ret < ARCHIVE_OK)
return (ret);
if (ret == ARCHIVE_EOF)
- state->in_stream = 0;
+ lzop->in_stream = 0;
else
break;
}
- if (state->out_block == NULL ||
- state->out_block_size < state->uncompressed_size) {
+ if (lzop->out_block == NULL ||
+ lzop->out_block_size < lzop->uncompressed_size) {
void *new_block;
- new_block = realloc(state->out_block, state->uncompressed_size);
+ new_block = realloc(lzop->out_block, lzop->uncompressed_size);
if (new_block == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
+ archive_set_error(&f->archive->archive, ENOMEM,
"Can't allocate data for lzop decompression");
return (ARCHIVE_FATAL);
}
- state->out_block = new_block;
- state->out_block_size = state->uncompressed_size;
+ lzop->out_block = new_block;
+ lzop->out_block_size = lzop->uncompressed_size;
}
- b = __archive_read_filter_ahead(self->upstream,
- state->compressed_size, NULL);
+ b = __archive_read_filter_ahead(f->upstream,
+ lzop->compressed_size, NULL);
if (b == NULL) {
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
return (ARCHIVE_FATAL);
}
- if (state->flags & CRC32_COMPRESSED)
- cksum = crc32(crc32(0, NULL, 0), b, state->compressed_size);
- else if (state->flags & ADLER32_COMPRESSED)
- cksum = adler32(adler32(0, NULL, 0), b, state->compressed_size);
+ if (lzop->flags & CRC32_COMPRESSED)
+ cksum = crc32(crc32(0, NULL, 0), b, lzop->compressed_size);
+ else if (lzop->flags & ADLER32_COMPRESSED)
+ cksum = adler32(adler32(0, NULL, 0), b, lzop->compressed_size);
else
- cksum = state->compressed_cksum;
- if (cksum != state->compressed_cksum) {
- archive_set_error(&self->archive->archive,
+ cksum = lzop->compressed_cksum;
+ if (cksum != lzop->compressed_cksum) {
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC, "Corrupted data");
return (ARCHIVE_FATAL);
}
/*
- * If the both uncompressed size and compressed size are the same,
+ * If both uncompressed size and compressed size are the same,
* we do not decompress this block.
*/
- if (state->uncompressed_size == state->compressed_size) {
+ if (lzop->uncompressed_size == lzop->compressed_size) {
*p = b;
- state->total_out += state->compressed_size;
- state->unconsumed_bytes = state->compressed_size;
- return ((ssize_t)state->uncompressed_size);
+ lzop->unconsumed_bytes = lzop->compressed_size;
+ return ((ssize_t)lzop->uncompressed_size);
}
/*
* Drive lzo uncompression.
*/
- out_size = (lzo_uint)state->uncompressed_size;
- r = lzo1x_decompress_safe(b, (lzo_uint)state->compressed_size,
- state->out_block, &out_size, NULL);
+ out_size = (lzo_uint)lzop->uncompressed_size;
+ r = lzo1x_decompress_safe(b, (lzo_uint)lzop->compressed_size,
+ lzop->out_block, &out_size, NULL);
switch (r) {
case LZO_E_OK:
- if (out_size == state->uncompressed_size)
+ if (out_size == lzop->uncompressed_size)
break;
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC, "Corrupted data");
return (ARCHIVE_FATAL);
case LZO_E_OUT_OF_MEMORY:
- archive_set_error(&self->archive->archive, ENOMEM,
+ archive_set_error(&f->archive->archive, ENOMEM,
"lzop decompression failed: out of memory");
return (ARCHIVE_FATAL);
default:
- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
"lzop decompression failed: %d", r);
return (ARCHIVE_FATAL);
}
- if (state->flags & CRC32_UNCOMPRESSED)
- cksum = crc32(crc32(0, NULL, 0), state->out_block,
- state->uncompressed_size);
- else if (state->flags & ADLER32_UNCOMPRESSED)
- cksum = adler32(adler32(0, NULL, 0), state->out_block,
- state->uncompressed_size);
+ if (lzop->flags & CRC32_UNCOMPRESSED)
+ cksum = crc32(crc32(0, NULL, 0), lzop->out_block,
+ lzop->uncompressed_size);
+ else if (lzop->flags & ADLER32_UNCOMPRESSED)
+ cksum = adler32(adler32(0, NULL, 0), lzop->out_block,
+ lzop->uncompressed_size);
else
- cksum = state->uncompressed_cksum;
- if (cksum != state->uncompressed_cksum) {
- archive_set_error(&self->archive->archive,
+ cksum = lzop->uncompressed_cksum;
+ if (cksum != lzop->uncompressed_cksum) {
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC, "Corrupted data");
return (ARCHIVE_FATAL);
}
- __archive_read_filter_consume(self->upstream, state->compressed_size);
- *p = state->out_block;
- state->total_out += out_size;
+ __archive_read_filter_consume(f->upstream, lzop->compressed_size);
+ *p = lzop->out_block;
return ((ssize_t)out_size);
}
@@ -486,12 +481,12 @@ lzop_filter_read(struct archive_read_filter *self, const void **p)
* Clean up the decompressor.
*/
static int
-lzop_filter_close(struct archive_read_filter *self)
+lzop_filter_close(struct archive_read_filter *f)
{
- struct read_lzop *state = (struct read_lzop *)self->data;
+ struct lzop *lzop = f->data;
- free(state->out_block);
- free(state);
+ free(lzop->out_block);
+ free(lzop);
return (ARCHIVE_OK);
}
diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_program.c b/contrib/libarchive/libarchive/archive_read_support_filter_program.c
index 9f187f852df3..cf7c36137e1b 100644
--- a/contrib/libarchive/libarchive/archive_read_support_filter_program.c
+++ b/contrib/libarchive/libarchive/archive_read_support_filter_program.c
@@ -87,7 +87,7 @@ archive_read_support_filter_program(struct archive *a, const char *cmd)
* bid twice in the same pipeline.
*/
struct program_bidder {
- char *description;
+ struct archive_string description;
char *cmd;
void *signature;
size_t signature_len;
@@ -102,7 +102,7 @@ static void program_bidder_free(struct archive_read_filter_bidder *);
/*
* The actual filter needs to track input and output data.
*/
-struct program_filter {
+struct program {
struct archive_string description;
#if defined(_WIN32) && !defined(__CYGWIN__)
HANDLE child;
@@ -145,6 +145,8 @@ archive_read_support_filter_program_signature(struct archive *_a,
state->cmd = strdup(cmd);
if (state->cmd == NULL)
goto memerr;
+ archive_strcpy(&state->description, "Program: ");
+ archive_strcat(&state->description, cmd);
if (signature != NULL && signature_len > 0) {
state->signature_len = signature_len;
@@ -168,9 +170,9 @@ memerr:
}
static void
-program_bidder_free(struct archive_read_filter_bidder *self)
+program_bidder_free(struct archive_read_filter_bidder *b)
{
- struct program_bidder *state = (struct program_bidder *)self->data;
+ struct program_bidder *state = (struct program_bidder *)b->data;
free_state(state);
}
@@ -180,6 +182,7 @@ free_state(struct program_bidder *state)
{
if (state) {
+ archive_string_free(&state->description);
free(state->cmd);
free(state->signature);
free(state);
@@ -193,15 +196,15 @@ free_state(struct program_bidder *state)
* we're called, then never bid again.
*/
static int
-program_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *upstream)
+program_bidder_bid(struct archive_read_filter_bidder *b,
+ struct archive_read_filter *f)
{
- struct program_bidder *state = self->data;
+ struct program_bidder *state = b->data;
const char *p;
/* If we have a signature, use that to match. */
if (state->signature_len > 0) {
- p = __archive_read_filter_ahead(upstream,
+ p = __archive_read_filter_ahead(f,
state->signature_len, NULL);
if (p == NULL)
return (0);
@@ -226,36 +229,36 @@ program_bidder_bid(struct archive_read_filter_bidder *self,
* (including error message if the child came to a bad end).
*/
static int
-child_stop(struct archive_read_filter *self, struct program_filter *state)
+child_stop(struct archive_read_filter *f, struct program *program)
{
/* Close our side of the I/O with the child. */
- if (state->child_stdin != -1) {
- close(state->child_stdin);
- state->child_stdin = -1;
+ if (program->child_stdin != -1) {
+ close(program->child_stdin);
+ program->child_stdin = -1;
}
- if (state->child_stdout != -1) {
- close(state->child_stdout);
- state->child_stdout = -1;
+ if (program->child_stdout != -1) {
+ close(program->child_stdout);
+ program->child_stdout = -1;
}
- if (state->child != 0) {
+ if (program->child != 0) {
/* Reap the child. */
do {
- state->waitpid_return
- = waitpid(state->child, &state->exit_status, 0);
- } while (state->waitpid_return == -1 && errno == EINTR);
- state->child = 0;
+ program->waitpid_return
+ = waitpid(program->child, &program->exit_status, 0);
+ } while (program->waitpid_return == -1 && errno == EINTR);
+ program->child = 0;
}
- if (state->waitpid_return < 0) {
+ if (program->waitpid_return < 0) {
/* waitpid() failed? This is ugly. */
- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
"Error closing child process");
return (ARCHIVE_WARN);
}
#if !defined(_WIN32) || defined(__CYGWIN__)
- if (WIFSIGNALED(state->exit_status)) {
+ if (WIFSIGNALED(program->exit_status)) {
#ifdef SIGPIPE
/* If the child died because we stopped reading before
* it was done, that's okay. Some archive formats
@@ -263,24 +266,24 @@ child_stop(struct archive_read_filter *self, struct program_filter *state)
/* The alternative to this would be to add a step
* before close(child_stdout) above to read from the
* child until the child has no more to write. */
- if (WTERMSIG(state->exit_status) == SIGPIPE)
+ if (WTERMSIG(program->exit_status) == SIGPIPE)
return (ARCHIVE_OK);
#endif
- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
"Child process exited with signal %d",
- WTERMSIG(state->exit_status));
+ WTERMSIG(program->exit_status));
return (ARCHIVE_WARN);
}
#endif /* !_WIN32 || __CYGWIN__ */
- if (WIFEXITED(state->exit_status)) {
- if (WEXITSTATUS(state->exit_status) == 0)
+ if (WIFEXITED(program->exit_status)) {
+ if (WEXITSTATUS(program->exit_status) == 0)
return (ARCHIVE_OK);
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Child process exited with status %d",
- WEXITSTATUS(state->exit_status));
+ WEXITSTATUS(program->exit_status));
return (ARCHIVE_WARN);
}
@@ -291,13 +294,13 @@ child_stop(struct archive_read_filter *self, struct program_filter *state)
* Use select() to decide whether the child is ready for read or write.
*/
static ssize_t
-child_read(struct archive_read_filter *self, char *buf, size_t buf_len)
+child_read(struct archive_read_filter *f, char *buf, size_t buf_len)
{
- struct program_filter *state = self->data;
+ struct program *program = f->data;
ssize_t ret, requested, avail;
const char *p;
#if defined(_WIN32) && !defined(__CYGWIN__)
- HANDLE handle = (HANDLE)_get_osfhandle(state->child_stdout);
+ HANDLE handle = (HANDLE)_get_osfhandle(program->child_stdout);
#endif
requested = buf_len > SSIZE_MAX ? SSIZE_MAX : buf_len;
@@ -325,7 +328,7 @@ child_read(struct archive_read_filter *self, char *buf, size_t buf_len)
break;
}
#endif
- ret = read(state->child_stdout, buf, requested);
+ ret = read(program->child_stdout, buf, requested);
} while (ret == -1 && errno == EINTR);
if (ret > 0)
@@ -333,44 +336,44 @@ child_read(struct archive_read_filter *self, char *buf, size_t buf_len)
if (ret == 0 || (ret == -1 && errno == EPIPE))
/* Child has closed its output; reap the child
* and return the status. */
- return (child_stop(self, state));
+ return (child_stop(f, program));
if (ret == -1 && errno != EAGAIN)
return (-1);
- if (state->child_stdin == -1) {
+ if (program->child_stdin == -1) {
/* Block until child has some I/O ready. */
- __archive_check_child(state->child_stdin,
- state->child_stdout);
+ __archive_check_child(program->child_stdin,
+ program->child_stdout);
continue;
}
/* Get some more data from upstream. */
- p = __archive_read_filter_ahead(self->upstream, 1, &avail);
+ p = __archive_read_filter_ahead(f->upstream, 1, &avail);
if (p == NULL) {
- close(state->child_stdin);
- state->child_stdin = -1;
- fcntl(state->child_stdout, F_SETFL, 0);
+ close(program->child_stdin);
+ program->child_stdin = -1;
+ fcntl(program->child_stdout, F_SETFL, 0);
if (avail < 0)
return (avail);
continue;
}
do {
- ret = write(state->child_stdin, p, avail);
+ ret = write(program->child_stdin, p, avail);
} while (ret == -1 && errno == EINTR);
if (ret > 0) {
/* Consume whatever we managed to write. */
- __archive_read_filter_consume(self->upstream, ret);
+ __archive_read_filter_consume(f->upstream, ret);
} else if (ret == -1 && errno == EAGAIN) {
/* Block until child has some I/O ready. */
- __archive_check_child(state->child_stdin,
- state->child_stdout);
+ __archive_check_child(program->child_stdin,
+ program->child_stdout);
} else {
/* Write failed. */
- close(state->child_stdin);
- state->child_stdin = -1;
- fcntl(state->child_stdout, F_SETFL, 0);
+ close(program->child_stdin);
+ program->child_stdin = -1;
+ fcntl(program->child_stdout, F_SETFL, 0);
/* If it was a bad error, we're done; otherwise
* it was EPIPE or EOF, and we can still read
* from the child. */
@@ -387,9 +390,9 @@ program_reader_vtable = {
};
int
-__archive_read_program(struct archive_read_filter *self, const char *cmd)
+__archive_read_program(struct archive_read_filter *f, const char *cmd)
{
- struct program_filter *state;
+ struct program *program;
static const size_t out_buf_len = 65536;
char *out_buf;
const char *prefix = "Program: ";
@@ -397,70 +400,71 @@ __archive_read_program(struct archive_read_filter *self, const char *cmd)
size_t l;
l = strlen(prefix) + strlen(cmd) + 1;
- state = calloc(1, sizeof(*state));
+ program = calloc(1, sizeof(*program));
out_buf = malloc(out_buf_len);
- if (state == NULL || out_buf == NULL ||
- archive_string_ensure(&state->description, l) == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
+ if (program == NULL || out_buf == NULL ||
+ archive_string_ensure(&program->description, l) == NULL) {
+ archive_set_error(&f->archive->archive, ENOMEM,
"Can't allocate input data");
- if (state != NULL) {
- archive_string_free(&state->description);
- free(state);
+ if (program != NULL) {
+ archive_string_free(&program->description);
+ free(program);
}
free(out_buf);
return (ARCHIVE_FATAL);
}
- archive_strcpy(&state->description, prefix);
- archive_strcat(&state->description, cmd);
+ archive_strcpy(&program->description, prefix);
+ archive_strcat(&program->description, cmd);
- self->code = ARCHIVE_FILTER_PROGRAM;
- self->name = state->description.s;
+ f->code = ARCHIVE_FILTER_PROGRAM;
+ f->name = program->description.s;
- state->out_buf = out_buf;
- state->out_buf_len = out_buf_len;
+ program->out_buf = out_buf;
+ program->out_buf_len = out_buf_len;
- ret = __archive_create_child(cmd, &state->child_stdin,
- &state->child_stdout, &state->child);
+ ret = __archive_create_child(cmd, &program->child_stdin,
+ &program->child_stdout, &program->child);
if (ret != ARCHIVE_OK) {
- free(state->out_buf);
- archive_string_free(&state->description);
- free(state);
- archive_set_error(&self->archive->archive, EINVAL,
+ free(program->out_buf);
+ archive_string_free(&program->description);
+ free(program);
+ archive_set_error(&f->archive->archive, EINVAL,
"Can't initialize filter; unable to run program \"%s\"",
cmd);
return (ARCHIVE_FATAL);
}
- self->data = state;
- self->vtable = &program_reader_vtable;
+ f->data = program;
+ f->vtable = &program_reader_vtable;
/* XXX Check that we can read at least one byte? */
return (ARCHIVE_OK);
}
static int
-program_bidder_init(struct archive_read_filter *self)
+program_bidder_init(struct archive_read_filter *f)
{
struct program_bidder *bidder_state;
+ int r;
- bidder_state = (struct program_bidder *)self->bidder->data;
- return (__archive_read_program(self, bidder_state->cmd));
+ bidder_state = (struct program_bidder *)f->bidder->data;
+ r = __archive_read_program(f, bidder_state->cmd);
+ f->name = bidder_state->description.s;
+ return (r);
}
static ssize_t
-program_filter_read(struct archive_read_filter *self, const void **buff)
+program_filter_read(struct archive_read_filter *f, const void **buff)
{
- struct program_filter *state;
+ struct program *program = f->data;
ssize_t bytes;
size_t total;
char *p;
- state = (struct program_filter *)self->data;
-
total = 0;
- p = state->out_buf;
- while (state->child_stdout != -1 && total < state->out_buf_len) {
- bytes = child_read(self, p, state->out_buf_len - total);
+ p = program->out_buf;
+ while (program->child_stdout != -1 && total < program->out_buf_len) {
+ bytes = child_read(f, p, program->out_buf_len - total);
if (bytes < 0)
/* No recovery is possible if we can no longer
* read from the child. */
@@ -472,23 +476,22 @@ program_filter_read(struct archive_read_filter *self, const void **buff)
p += bytes;
}
- *buff = state->out_buf;
+ *buff = program->out_buf;
return (total);
}
static int
-program_filter_close(struct archive_read_filter *self)
+program_filter_close(struct archive_read_filter *f)
{
- struct program_filter *state;
+ struct program *program = f->data;
int e;
- state = (struct program_filter *)self->data;
- e = child_stop(self, state);
+ e = child_stop(f, program);
/* Release our private data. */
- free(state->out_buf);
- archive_string_free(&state->description);
- free(state);
+ free(program->out_buf);
+ archive_string_free(&program->description);
+ free(program);
return (e);
}
diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_rpm.c b/contrib/libarchive/libarchive/archive_read_support_filter_rpm.c
index 25ace4a25bc9..01bd1bf7af5b 100644
--- a/contrib/libarchive/libarchive/archive_read_support_filter_rpm.c
+++ b/contrib/libarchive/libarchive/archive_read_support_filter_rpm.c
@@ -38,20 +38,7 @@
#include "archive_read_private.h"
struct rpm {
- int64_t total_in;
- uint64_t hpos;
- uint64_t hlen;
- unsigned char header[16];
- enum {
- ST_LEAD, /* Skipping 'Lead' section. */
- ST_HEADER, /* Reading 'Header' section;
- * first 16 bytes. */
- ST_HEADER_DATA, /* Skipping 'Header' section. */
- ST_PADDING, /* Skipping padding data after the
- * 'Header' section. */
- ST_ARCHIVE /* Reading 'Archive' section. */
- } state;
- int first_header;
+ int data_reached;
};
#define RPM_LEAD_SIZE 96 /* Size of 'Lead' section. */
#define RPM_MIN_HEAD_SIZE 16 /* Minimum size of 'Head'. */
@@ -64,8 +51,6 @@ static ssize_t rpm_filter_read(struct archive_read_filter *,
const void **);
static int rpm_filter_close(struct archive_read_filter *);
-static inline size_t rpm_limit_bytes(uint64_t, size_t);
-
#if ARCHIVE_VERSION_NUMBER < 4000000
/* Deprecated; remove in libarchive 4.0 */
int
@@ -91,39 +76,38 @@ archive_read_support_filter_rpm(struct archive *_a)
}
static int
-rpm_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
+rpm_bidder_bid(struct archive_read_filter_bidder *b,
+ struct archive_read_filter *f)
{
- const unsigned char *b;
- ssize_t avail;
+ const unsigned char *p;
int bits_checked;
- (void)self; /* UNUSED */
+ (void)b; /* UNUSED */
- b = __archive_read_filter_ahead(filter, 8, &avail);
- if (b == NULL)
+ p = __archive_read_filter_ahead(f, 8, NULL);
+ if (p == NULL)
return (0);
bits_checked = 0;
/*
* Verify Header Magic Bytes : 0XED 0XAB 0XEE 0XDB
*/
- if (memcmp(b, "\xED\xAB\xEE\xDB", 4) != 0)
+ if (memcmp(p, "\xED\xAB\xEE\xDB", 4) != 0)
return (0);
bits_checked += 32;
/*
* Check major version.
*/
- if (b[4] != 3 && b[4] != 4)
+ if (p[4] != 3 && p[4] != 4)
return (0);
bits_checked += 8;
/*
* Check package type; binary or source.
*/
- if (b[6] != 0)
+ if (p[6] != 0)
return (0);
bits_checked += 8;
- if (b[7] != 0 && b[7] != 1)
+ if (p[7] != 0 && p[7] != 1)
return (0);
bits_checked += 8;
@@ -137,156 +121,127 @@ rpm_reader_vtable = {
};
static int
-rpm_bidder_init(struct archive_read_filter *self)
+rpm_bidder_init(struct archive_read_filter *f)
{
struct rpm *rpm;
- self->code = ARCHIVE_FILTER_RPM;
- self->name = "rpm";
+ f->code = ARCHIVE_FILTER_RPM;
+ f->name = "rpm";
rpm = calloc(1, sizeof(*rpm));
if (rpm == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
+ archive_set_error(&f->archive->archive, ENOMEM,
"Can't allocate data for rpm");
return (ARCHIVE_FATAL);
}
- self->data = rpm;
- rpm->state = ST_LEAD;
- self->vtable = &rpm_reader_vtable;
+ f->data = rpm;
+ rpm->data_reached = 0;
+ f->vtable = &rpm_reader_vtable;
return (ARCHIVE_OK);
}
-static inline size_t
-rpm_limit_bytes(uint64_t bytes, size_t max)
+static ssize_t
+skip_padding(struct archive_read_filter *f)
{
- return (bytes > max ? max : (size_t)bytes);
+ const unsigned char *h;
+ ssize_t avail, count, r;
+
+ do {
+ h = __archive_read_filter_ahead(f->upstream, 1, &avail);
+ if (h == NULL)
+ return (ARCHIVE_FATAL);
+ for (count = 0; count < avail && *h++ == '\0'; count++)
+ ;
+ r = __archive_read_filter_consume(f->upstream, count);
+ if (r < 0)
+ return (r);
+ } while (count == avail);
+
+ return (ARCHIVE_OK);
}
static ssize_t
-rpm_filter_read(struct archive_read_filter *self, const void **buff)
+skip_prologue(struct archive_read_filter *f)
{
- struct rpm *rpm;
- const unsigned char *b;
- ssize_t avail_in, total, used;
- size_t n;
- uint64_t section;
- uint64_t bytes;
+ const unsigned char *h;
+ ssize_t r;
+ int header, seen_header = 0;
+
+ /* Skip lead size. */
+ r = __archive_read_filter_consume(f->upstream, RPM_LEAD_SIZE);
+ if (r < 0)
+ return (r);
- rpm = (struct rpm *)self->data;
- *buff = NULL;
- total = avail_in = 0;
- b = NULL;
- used = 0;
do {
- if (b == NULL) {
- b = __archive_read_filter_ahead(self->upstream, 1,
- &avail_in);
- if (b == NULL) {
- if (avail_in < 0)
- return (ARCHIVE_FATAL);
- else
- break;
- }
- }
+ /* Read header intro. */
+ h = __archive_read_filter_ahead(f->upstream,
+ RPM_MIN_HEAD_SIZE, NULL);
+ if (h == NULL)
+ return (ARCHIVE_FATAL);
- switch (rpm->state) {
- case ST_LEAD:
- if (rpm->total_in + avail_in < RPM_LEAD_SIZE)
- used += avail_in;
- else {
- n = (size_t)(RPM_LEAD_SIZE - rpm->total_in);
- used += n;
- b += n;
- rpm->state = ST_HEADER;
- rpm->hpos = 0;
- rpm->hlen = 0;
- rpm->first_header = 1;
- }
- break;
- case ST_HEADER:
- n = rpm_limit_bytes(RPM_MIN_HEAD_SIZE - rpm->hpos,
- avail_in - used);
- memcpy(rpm->header+rpm->hpos, b, n);
- b += n;
- used += n;
- rpm->hpos += n;
+ header = (memcmp(h, "\x8E\xAD\xE8\x01", 4) == 0);
+ if (header) {
+ int64_t bytes, length, section;
- if (rpm->hpos == RPM_MIN_HEAD_SIZE) {
- if (rpm->header[0] != 0x8e ||
- rpm->header[1] != 0xad ||
- rpm->header[2] != 0xe8 ||
- rpm->header[3] != 0x01) {
- if (rpm->first_header) {
- archive_set_error(
- &self->archive->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Unrecognized rpm header");
- return (ARCHIVE_FATAL);
- }
- rpm->state = ST_ARCHIVE;
- *buff = rpm->header;
- total = RPM_MIN_HEAD_SIZE;
- break;
- }
- /* Calculate 'Header' length. */
- section = archive_be32dec(rpm->header+8);
- bytes = archive_be32dec(rpm->header+12);
- rpm->hlen = rpm->hpos + section * 16 + bytes;
- rpm->state = ST_HEADER_DATA;
- rpm->first_header = 0;
- }
- break;
- case ST_HEADER_DATA:
- n = rpm_limit_bytes(rpm->hlen - rpm->hpos,
- avail_in - used);
- b += n;
- used += n;
- rpm->hpos += n;
- if (rpm->hpos == rpm->hlen)
- rpm->state = ST_PADDING;
- break;
- case ST_PADDING:
- while (used < avail_in) {
- if (*b != 0) {
- /* Read next header. */
- rpm->state = ST_HEADER;
- rpm->hpos = 0;
- rpm->hlen = 0;
- break;
- }
- b++;
- used++;
- }
- break;
- case ST_ARCHIVE:
- *buff = b;
- total = avail_in;
- used = avail_in;
- break;
- }
- if (used == avail_in) {
- rpm->total_in += used;
- __archive_read_filter_consume(self->upstream, used);
- b = NULL;
- used = 0;
+ seen_header = 1;
+
+ /* Calculate header length. */
+ section = archive_be32dec(h + 8);
+ bytes = archive_be32dec(h + 12);
+ length = RPM_MIN_HEAD_SIZE + section * 16 + bytes;
+
+ /* Skip header. */
+ r = __archive_read_filter_consume(f->upstream,
+ length);
+ if (r < 0)
+ return (r);
+
+ /* Skip padding. */
+ r = skip_padding(f);
+ if (r != ARCHIVE_OK)
+ return (r);
}
- } while (total == 0 && avail_in > 0);
+ } while (header);
- if (used > 0 && b != NULL) {
- rpm->total_in += used;
- __archive_read_filter_consume(self->upstream, used);
+ /* At least one header must have been encountered. */
+ if (!seen_header) {
+ archive_set_error(
+ &f->archive->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Unrecognized rpm header");
+ return (ARCHIVE_FATAL);
}
- return (total);
+
+ return (ARCHIVE_OK);
+}
+
+static ssize_t
+rpm_filter_read(struct archive_read_filter *f, const void **buff)
+{
+ struct rpm *rpm = f->data;
+ ssize_t r;
+
+ if (!rpm->data_reached) {
+ r = skip_prologue(f);
+ if (r != ARCHIVE_OK)
+ return (r);
+ rpm->data_reached = 1;
+ }
+
+ *buff = __archive_read_filter_ahead(f->upstream, 1, &r);
+ if (r > 0)
+ __archive_read_filter_consume(f->upstream, r);
+
+ return r;
}
static int
-rpm_filter_close(struct archive_read_filter *self)
+rpm_filter_close(struct archive_read_filter *f)
{
- struct rpm *rpm;
+ struct rpm *rpm = f->data;
- rpm = (struct rpm *)self->data;
free(rpm);
return (ARCHIVE_OK);
diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_uu.c b/contrib/libarchive/libarchive/archive_read_support_filter_uu.c
index acb8feb79b2d..c0f6f48ed413 100644
--- a/contrib/libarchive/libarchive/archive_read_support_filter_uu.c
+++ b/contrib/libarchive/libarchive/archive_read_support_filter_uu.c
@@ -43,9 +43,7 @@
/* Maximum lookahead during bid phase */
#define UUENCODE_BID_MAX_READ 128*1024 /* in bytes */
-#define UUENCODE_MAX_LINE_LENGTH 34*1024 /* in bytes */
-
-struct uudecode {
+struct uu {
int64_t total;
unsigned char *in_buff;
#define IN_BUFF_SIZE (1024)
@@ -65,7 +63,7 @@ struct uudecode {
};
static int uudecode_bidder_bid(struct archive_read_filter_bidder *,
- struct archive_read_filter *filter);
+ struct archive_read_filter *f);
static int uudecode_bidder_init(struct archive_read_filter *);
static int uudecode_read_header(struct archive_read_filter *,
@@ -209,7 +207,7 @@ get_line(const unsigned char *b, ssize_t avail, ssize_t *nlsize)
}
static ssize_t
-bid_get_line(struct archive_read_filter *filter,
+bid_get_line(struct archive_read_filter *f,
const unsigned char **b, ssize_t *avail, ssize_t *ravail,
ssize_t *nl, size_t* nbytes_read)
{
@@ -224,7 +222,7 @@ bid_get_line(struct archive_read_filter *filter,
len = get_line(*b, *avail, nl);
/*
- * Read bytes more while it does not reach the end of line.
+ * Read more bytes while it does not reach the end of line.
*/
while (*nl == 0 && len == *avail && !quit &&
*nbytes_read < UUENCODE_BID_MAX_READ) {
@@ -237,12 +235,12 @@ bid_get_line(struct archive_read_filter *filter,
if (nbytes_req < (size_t)*ravail + 160)
nbytes_req <<= 1;
- *b = __archive_read_filter_ahead(filter, nbytes_req, avail);
+ *b = __archive_read_filter_ahead(f, nbytes_req, avail);
if (*b == NULL) {
if (*ravail >= *avail)
return (0);
/* Reading bytes reaches the end of a stream. */
- *b = __archive_read_filter_ahead(filter, *avail, avail);
+ *b = __archive_read_filter_ahead(f, *avail, avail);
quit = 1;
}
*nbytes_read = *avail;
@@ -260,42 +258,42 @@ bid_get_line(struct archive_read_filter *filter,
#define UUDECODE(c) (((c) - 0x20) & 0x3f)
static int
-uudecode_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
+uudecode_bidder_bid(struct archive_read_filter_bidder *b,
+ struct archive_read_filter *f)
{
- const unsigned char *b;
+ const unsigned char *p;
ssize_t avail, ravail;
ssize_t len, nl;
int l;
int firstline;
size_t nbytes_read;
- (void)self; /* UNUSED */
+ (void)b; /* UNUSED */
- b = __archive_read_filter_ahead(filter, 1, &avail);
- if (b == NULL)
+ p = __archive_read_filter_ahead(f, 1, &avail);
+ if (p == NULL)
return (0);
firstline = 20;
ravail = avail;
nbytes_read = avail;
for (;;) {
- len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read);
+ len = bid_get_line(f, &p, &avail, &ravail, &nl, &nbytes_read);
if (len < 0 || nl == 0)
return (0); /* No match found. */
- if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0)
+ if (len - nl >= 11 && memcmp(p, "begin ", 6) == 0)
l = 6;
- else if (len -nl >= 18 && memcmp(b, "begin-base64 ", 13) == 0)
+ else if (len -nl >= 18 && memcmp(p, "begin-base64 ", 13) == 0)
l = 13;
else
l = 0;
- if (l > 0 && (b[l] < '0' || b[l] > '7' ||
- b[l+1] < '0' || b[l+1] > '7' ||
- b[l+2] < '0' || b[l+2] > '7' || b[l+3] != ' '))
+ if (l > 0 && (p[l] < '0' || p[l] > '7' ||
+ p[l+1] < '0' || p[l+1] > '7' ||
+ p[l+2] < '0' || p[l+2] > '7' || p[l+3] != ' '))
l = 0;
- b += len;
+ p += len;
avail -= len;
if (l)
break;
@@ -307,51 +305,51 @@ uudecode_bidder_bid(struct archive_read_filter_bidder *self,
}
if (!avail)
return (0);
- len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read);
+ len = bid_get_line(f, &p, &avail, &ravail, &nl, &nbytes_read);
if (len < 0 || nl == 0)
return (0);/* There are non-ascii characters. */
avail -= len;
if (l == 6) {
/* "begin " */
- if (!uuchar[*b])
+ if (!uuchar[*p])
return (0);
/* Get a length of decoded bytes. */
- l = UUDECODE(*b++); len--;
+ l = UUDECODE(*p++); len--;
if (l > 45)
/* Normally, maximum length is 45(character 'M'). */
return (0);
if (l > len - nl)
return (0); /* Line too short. */
while (l) {
- if (!uuchar[*b++])
+ if (!uuchar[*p++])
return (0);
--len;
--l;
}
if (len-nl == 1 &&
- (uuchar[*b] || /* Check sum. */
- (*b >= 'a' && *b <= 'z'))) {/* Padding data(MINIX). */
- ++b;
+ (uuchar[*p] || /* Check sum. */
+ (*p >= 'a' && *p <= 'z'))) {/* Padding data(MINIX). */
+ ++p;
--len;
}
- b += nl;
- if (avail && uuchar[*b])
+ p += nl;
+ if (avail && uuchar[*p])
return (firstline+30);
} else if (l == 13) {
/* "begin-base64 " */
while (len-nl > 0) {
- if (!base64[*b++])
+ if (!base64[*p++])
return (0);
--len;
}
- b += nl;
+ p += nl;
- if (avail >= 5 && memcmp(b, "====\n", 5) == 0)
+ if (avail >= 5 && memcmp(p, "====\n", 5) == 0)
return (firstline+40);
- if (avail >= 6 && memcmp(b, "====\r\n", 6) == 0)
+ if (avail >= 6 && memcmp(p, "====\r\n", 6) == 0)
return (firstline+40);
- if (avail > 0 && base64[*b])
+ if (avail > 0 && base64[*p])
return (firstline+30);
}
@@ -366,46 +364,46 @@ uudecode_reader_vtable = {
};
static int
-uudecode_bidder_init(struct archive_read_filter *self)
+uudecode_bidder_init(struct archive_read_filter *f)
{
- struct uudecode *uudecode;
+ struct uu *uu;
void *out_buff;
void *in_buff;
- self->code = ARCHIVE_FILTER_UU;
- self->name = "uu";
+ f->code = ARCHIVE_FILTER_UU;
+ f->name = "uu";
- uudecode = calloc(1, sizeof(*uudecode));
+ uu = calloc(1, sizeof(*uu));
out_buff = malloc(OUT_BUFF_SIZE);
in_buff = malloc(IN_BUFF_SIZE);
- if (uudecode == NULL || out_buff == NULL || in_buff == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
+ if (uu == NULL || out_buff == NULL || in_buff == NULL) {
+ archive_set_error(&f->archive->archive, ENOMEM,
"Can't allocate data for uudecode");
- free(uudecode);
+ free(uu);
free(out_buff);
free(in_buff);
return (ARCHIVE_FATAL);
}
- self->data = uudecode;
- uudecode->in_buff = in_buff;
- uudecode->in_cnt = 0;
- uudecode->in_allocated = IN_BUFF_SIZE;
- uudecode->out_buff = out_buff;
- uudecode->state = ST_FIND_HEAD;
- uudecode->mode_set = 0;
- uudecode->name = NULL;
- self->vtable = &uudecode_reader_vtable;
+ f->data = uu;
+ uu->in_buff = in_buff;
+ uu->in_cnt = 0;
+ uu->in_allocated = IN_BUFF_SIZE;
+ uu->out_buff = out_buff;
+ uu->state = ST_FIND_HEAD;
+ uu->mode_set = 0;
+ uu->name = NULL;
+ f->vtable = &uudecode_reader_vtable;
return (ARCHIVE_OK);
}
static int
-ensure_in_buff_size(struct archive_read_filter *self,
- struct uudecode *uudecode, size_t size)
+ensure_in_buff_size(struct archive_read_filter *f,
+ struct uu *uu, size_t size)
{
- if (size > uudecode->in_allocated) {
+ if (size > uu->in_allocated) {
unsigned char *ptr;
size_t newsize;
@@ -413,7 +411,7 @@ ensure_in_buff_size(struct archive_read_filter *self,
* Calculate a new buffer size for in_buff.
* Increase its value until it is enough for our needs.
*/
- newsize = uudecode->in_allocated;
+ newsize = uu->in_allocated;
do {
if (newsize < IN_BUFF_SIZE*32)
newsize <<= 1;
@@ -423,43 +421,40 @@ ensure_in_buff_size(struct archive_read_filter *self,
/* Allocate the new buffer. */
ptr = malloc(newsize);
if (ptr == NULL) {
- free(ptr);
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ENOMEM,
"Can't allocate data for uudecode");
return (ARCHIVE_FATAL);
}
/* Move the remaining data in in_buff into the new buffer. */
- if (uudecode->in_cnt)
- memmove(ptr, uudecode->in_buff, uudecode->in_cnt);
+ if (uu->in_cnt)
+ memmove(ptr, uu->in_buff, uu->in_cnt);
/* Replace in_buff with the new buffer. */
- free(uudecode->in_buff);
- uudecode->in_buff = ptr;
- uudecode->in_allocated = newsize;
+ free(uu->in_buff);
+ uu->in_buff = ptr;
+ uu->in_allocated = newsize;
}
return (ARCHIVE_OK);
}
static int
-uudecode_read_header(struct archive_read_filter *self, struct archive_entry *entry)
+uudecode_read_header(struct archive_read_filter *f, struct archive_entry *entry)
{
+ struct uu *uu = f->data;
- struct uudecode *uudecode;
- uudecode = (struct uudecode *)self->data;
-
- if (uudecode->mode_set != 0)
- archive_entry_set_mode(entry, S_IFREG | uudecode->mode);
+ if (uu->mode_set != 0)
+ archive_entry_set_mode(entry, S_IFREG | uu->mode);
- if (uudecode->name != NULL)
- archive_entry_set_pathname(entry, uudecode->name);
+ if (uu->name != NULL)
+ archive_entry_set_pathname(entry, uu->name);
return (ARCHIVE_OK);
}
static ssize_t
-uudecode_filter_read(struct archive_read_filter *self, const void **buff)
+uudecode_filter_read(struct archive_read_filter *f, const void **buff)
{
- struct uudecode *uudecode;
+ struct uu *uu = f->data;
const unsigned char *b, *d;
unsigned char *out;
ssize_t avail_in, ravail;
@@ -467,10 +462,8 @@ uudecode_filter_read(struct archive_read_filter *self, const void **buff)
ssize_t total;
ssize_t len, llen, nl, namelen;
- uudecode = (struct uudecode *)self->data;
-
read_more:
- d = __archive_read_filter_ahead(self->upstream, 1, &avail_in);
+ d = __archive_read_filter_ahead(f->upstream, 1, &avail_in);
if (d == NULL && avail_in < 0)
return (ARCHIVE_FATAL);
/* Quiet a code analyzer; make sure avail_in must be zero
@@ -479,15 +472,17 @@ read_more:
avail_in = 0;
used = 0;
total = 0;
- out = uudecode->out_buff;
+ out = uu->out_buff;
+ if (avail_in > 2 * UUENCODE_BID_MAX_READ)
+ avail_in = 2 * UUENCODE_BID_MAX_READ;
ravail = avail_in;
- if (uudecode->state == ST_IGNORE) {
+ if (uu->state == ST_IGNORE) {
used = avail_in;
goto finish;
}
- if (uudecode->in_cnt) {
- if (uudecode->in_cnt > UUENCODE_MAX_LINE_LENGTH) {
- archive_set_error(&self->archive->archive,
+ if (uu->in_cnt) {
+ if (uu->in_cnt > UUENCODE_BID_MAX_READ) {
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid format data");
return (ARCHIVE_FATAL);
@@ -496,14 +491,15 @@ read_more:
* If there is remaining data which is saved by
* a previous call, use it first.
*/
- if (ensure_in_buff_size(self, uudecode,
- avail_in + uudecode->in_cnt) != ARCHIVE_OK)
+ if (ensure_in_buff_size(f, uu,
+ avail_in + uu->in_cnt) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
- memcpy(uudecode->in_buff + uudecode->in_cnt,
- d, avail_in);
- d = uudecode->in_buff;
- avail_in += uudecode->in_cnt;
- uudecode->in_cnt = 0;
+ if (avail_in > 0)
+ memcpy(uu->in_buff + uu->in_cnt,
+ d, avail_in);
+ d = uu->in_buff;
+ avail_in += uu->in_cnt;
+ uu->in_cnt = 0;
}
for (;used < avail_in; d += llen, used += llen) {
ssize_t l, body;
@@ -512,22 +508,28 @@ read_more:
len = get_line(b, avail_in - used, &nl);
if (len < 0) {
/* Non-ascii character is found. */
- if (uudecode->state == ST_FIND_HEAD &&
- (uudecode->total > 0 || total > 0)) {
- uudecode->state = ST_IGNORE;
+ if (uu->state == ST_FIND_HEAD &&
+ (uu->total > 0 || total > 0)) {
+ uu->state = ST_IGNORE;
used = avail_in;
goto finish;
}
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Insufficient compressed data");
return (ARCHIVE_FATAL);
}
+ if (len > UUENCODE_BID_MAX_READ) {
+ archive_set_error(&f->archive->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid format data");
+ return (ARCHIVE_FATAL);
+ }
llen = len;
- if ((nl == 0) && (uudecode->state != ST_UUEND)) {
+ if ((nl == 0) && (uu->state != ST_UUEND)) {
if (total == 0 && ravail <= 0) {
/* There is nothing more to read, fail */
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Missing format data");
return (ARCHIVE_FATAL);
@@ -536,28 +538,28 @@ read_more:
* Save remaining data which does not contain
* NL('\n','\r').
*/
- if (ensure_in_buff_size(self, uudecode, len)
+ if (ensure_in_buff_size(f, uu, len)
!= ARCHIVE_OK)
return (ARCHIVE_FATAL);
- if (uudecode->in_buff != b)
- memmove(uudecode->in_buff, b, len);
- uudecode->in_cnt = len;
+ if (uu->in_buff != b)
+ memmove(uu->in_buff, b, len);
+ uu->in_cnt = len;
if (total == 0) {
/* Do not return 0; it means end-of-file.
- * We should try to read bytes more. */
+ * We should try to read more bytes. */
__archive_read_filter_consume(
- self->upstream, ravail);
+ f->upstream, ravail);
goto read_more;
}
used += len;
break;
}
- switch (uudecode->state) {
+ switch (uu->state) {
default:
case ST_FIND_HEAD:
/* Do not read more than UUENCODE_BID_MAX_READ bytes */
if (total + len >= UUENCODE_BID_MAX_READ) {
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid format data");
return (ARCHIVE_FATAL);
@@ -573,30 +575,30 @@ read_more:
b[l+1] >= '0' && b[l+1] <= '7' &&
b[l+2] >= '0' && b[l+2] <= '7' && b[l+3] == ' ') {
if (l == 6)
- uudecode->state = ST_READ_UU;
+ uu->state = ST_READ_UU;
else
- uudecode->state = ST_READ_BASE64;
- uudecode->mode = (mode_t)(
+ uu->state = ST_READ_BASE64;
+ uu->mode = (mode_t)(
((int)(b[l] - '0') * 64) +
((int)(b[l+1] - '0') * 8) +
(int)(b[l+2] - '0'));
- uudecode->mode_set = 1;
+ uu->mode_set = 1;
namelen = len - nl - 4 - l;
if (namelen > 1) {
- if (uudecode->name != NULL)
- free(uudecode->name);
- uudecode->name = malloc(namelen + 1);
- if (uudecode->name == NULL) {
- archive_set_error(
- &self->archive->archive,
- ENOMEM,
- "Can't allocate data for uudecode");
+ if (uu->name != NULL)
+ free(uu->name);
+ uu->name = malloc(namelen + 1);
+ if (uu->name == NULL) {
+ archive_set_error(
+ &f->archive->archive,
+ ENOMEM,
+ "Can't allocate data for uudecode");
return (ARCHIVE_FATAL);
}
- strncpy(uudecode->name,
+ strncpy(uu->name,
(const char *)(b + l + 4),
namelen);
- uudecode->name[namelen] = '\0';
+ uu->name[namelen] = '\0';
}
}
break;
@@ -605,7 +607,7 @@ read_more:
goto finish;
body = len - nl;
if (!uuchar[*b] || body <= 0) {
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Insufficient compressed data");
return (ARCHIVE_FATAL);
@@ -614,13 +616,13 @@ read_more:
l = UUDECODE(*b++);
body--;
if (l > body) {
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Insufficient compressed data");
return (ARCHIVE_FATAL);
}
if (l == 0) {
- uudecode->state = ST_UUEND;
+ uu->state = ST_UUEND;
break;
}
while (l > 0) {
@@ -649,7 +651,7 @@ read_more:
}
}
if (l) {
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Insufficient compressed data");
return (ARCHIVE_FATAL);
@@ -657,9 +659,9 @@ read_more:
break;
case ST_UUEND:
if (len - nl == 3 && memcmp(b, "end ", 3) == 0)
- uudecode->state = ST_FIND_HEAD;
+ uu->state = ST_FIND_HEAD;
else {
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Insufficient compressed data");
return (ARCHIVE_FATAL);
@@ -671,7 +673,7 @@ read_more:
l = len - nl;
if (l >= 3 && b[0] == '=' && b[1] == '=' &&
b[2] == '=') {
- uudecode->state = ST_FIND_HEAD;
+ uu->state = ST_FIND_HEAD;
break;
}
while (l > 0) {
@@ -704,7 +706,7 @@ read_more:
}
}
if (l && *b != '=') {
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Insufficient compressed data");
return (ARCHIVE_FATAL);
@@ -715,23 +717,22 @@ read_more:
finish:
if (ravail < avail_in)
used -= avail_in - ravail;
- __archive_read_filter_consume(self->upstream, used);
+ __archive_read_filter_consume(f->upstream, used);
- *buff = uudecode->out_buff;
- uudecode->total += total;
+ *buff = uu->out_buff;
+ uu->total += total;
return (total);
}
static int
-uudecode_filter_close(struct archive_read_filter *self)
+uudecode_filter_close(struct archive_read_filter *f)
{
- struct uudecode *uudecode;
+ struct uu *uu = f->data;
- uudecode = (struct uudecode *)self->data;
- free(uudecode->in_buff);
- free(uudecode->out_buff);
- free(uudecode->name);
- free(uudecode);
+ free(uu->in_buff);
+ free(uu->out_buff);
+ free(uu->name);
+ free(uu);
return (ARCHIVE_OK);
}
diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_xz.c b/contrib/libarchive/libarchive/archive_read_support_filter_xz.c
index dcbf734ecacb..7c8e0cb52e36 100644
--- a/contrib/libarchive/libarchive/archive_read_support_filter_xz.c
+++ b/contrib/libarchive/libarchive/archive_read_support_filter_xz.c
@@ -50,11 +50,10 @@
#if HAVE_LZMA_H && HAVE_LIBLZMA
-struct private_data {
+struct xz {
lzma_stream stream;
unsigned char *out_block;
size_t out_block_size;
- int64_t total_out;
char eof; /* True = found end of compressed data. */
char in_stream;
@@ -83,8 +82,7 @@ static int xz_lzma_bidder_init(struct archive_read_filter *);
/*
* Note that we can detect xz and lzma compressed files even if we
* can't decompress them. (In fact, we like detecting them because we
- * can give better error messages.) So the bid framework here gets
- * compiled even if no lzma library is available.
+ * can give better error messages.)
*/
static int xz_bidder_bid(struct archive_read_filter_bidder *,
struct archive_read_filter *);
@@ -199,15 +197,14 @@ archive_read_support_filter_lzip(struct archive *_a)
* Test whether we can handle this data.
*/
static int
-xz_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
+xz_bidder_bid(struct archive_read_filter_bidder *b,
+ struct archive_read_filter *f)
{
const unsigned char *buffer;
- ssize_t avail;
- (void)self; /* UNUSED */
+ (void)b; /* UNUSED */
- buffer = __archive_read_filter_ahead(filter, 6, &avail);
+ buffer = __archive_read_filter_ahead(f, 6, NULL);
if (buffer == NULL)
return (0);
@@ -233,18 +230,17 @@ xz_bidder_bid(struct archive_read_filter_bidder *self,
* they have other evidence (file name, command-line option) to go on.
*/
static int
-lzma_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
+lzma_bidder_bid(struct archive_read_filter_bidder *b,
+ struct archive_read_filter *f)
{
const unsigned char *buffer;
- ssize_t avail;
uint32_t dicsize;
uint64_t uncompressed_size;
int bits_checked;
- (void)self; /* UNUSED */
+ (void)b; /* UNUSED */
- buffer = __archive_read_filter_ahead(filter, 14, &avail);
+ buffer = __archive_read_filter_ahead(f, 14, NULL);
if (buffer == NULL)
return (0);
@@ -340,14 +336,13 @@ lzma_bidder_bid(struct archive_read_filter_bidder *self,
}
static int
-lzip_has_member(struct archive_read_filter *filter)
+lzip_has_member(struct archive_read_filter *f)
{
const unsigned char *buffer;
- ssize_t avail;
int bits_checked;
int log2dic;
- buffer = __archive_read_filter_ahead(filter, 6, &avail);
+ buffer = __archive_read_filter_ahead(f, 6, NULL);
if (buffer == NULL)
return (0);
@@ -374,12 +369,12 @@ lzip_has_member(struct archive_read_filter *filter)
}
static int
-lzip_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
+lzip_bidder_bid(struct archive_read_filter_bidder *b,
+ struct archive_read_filter *f)
{
- (void)self; /* UNUSED */
- return (lzip_has_member(filter));
+ (void)b; /* UNUSED */
+ return (lzip_has_member(f));
}
#if HAVE_LZMA_H && HAVE_LIBLZMA
@@ -388,34 +383,34 @@ lzip_bidder_bid(struct archive_read_filter_bidder *self,
* liblzma 4.999.7 and later support both lzma and xz streams.
*/
static int
-xz_bidder_init(struct archive_read_filter *self)
+xz_bidder_init(struct archive_read_filter *f)
{
- self->code = ARCHIVE_FILTER_XZ;
- self->name = "xz";
- return (xz_lzma_bidder_init(self));
+ f->code = ARCHIVE_FILTER_XZ;
+ f->name = "xz";
+ return (xz_lzma_bidder_init(f));
}
static int
-lzma_bidder_init(struct archive_read_filter *self)
+lzma_bidder_init(struct archive_read_filter *f)
{
- self->code = ARCHIVE_FILTER_LZMA;
- self->name = "lzma";
- return (xz_lzma_bidder_init(self));
+ f->code = ARCHIVE_FILTER_LZMA;
+ f->name = "lzma";
+ return (xz_lzma_bidder_init(f));
}
static int
-lzip_bidder_init(struct archive_read_filter *self)
+lzip_bidder_init(struct archive_read_filter *f)
{
- self->code = ARCHIVE_FILTER_LZIP;
- self->name = "lzip";
- return (xz_lzma_bidder_init(self));
+ f->code = ARCHIVE_FILTER_LZIP;
+ f->name = "lzip";
+ return (xz_lzma_bidder_init(f));
}
/*
* Set an error code and choose an error message
*/
static void
-set_error(struct archive_read_filter *self, int ret)
+set_error(struct archive_read_filter *f, int ret)
{
switch (ret) {
@@ -423,36 +418,36 @@ set_error(struct archive_read_filter *self, int ret)
case LZMA_OK: /* Decompressor made some progress. */
break;
case LZMA_MEM_ERROR:
- archive_set_error(&self->archive->archive, ENOMEM,
+ archive_set_error(&f->archive->archive, ENOMEM,
"Lzma library error: Cannot allocate memory");
break;
case LZMA_MEMLIMIT_ERROR:
- archive_set_error(&self->archive->archive, ENOMEM,
+ archive_set_error(&f->archive->archive, ENOMEM,
"Lzma library error: Out of memory");
break;
case LZMA_FORMAT_ERROR:
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Lzma library error: format not recognized");
break;
case LZMA_OPTIONS_ERROR:
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Lzma library error: Invalid options");
break;
case LZMA_DATA_ERROR:
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Lzma library error: Corrupted input data");
break;
case LZMA_BUF_ERROR:
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Lzma library error: No progress is possible");
break;
default:
/* Return an error. */
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Lzma decompression failed: Unknown error");
break;
@@ -469,84 +464,83 @@ xz_lzma_reader_vtable = {
* Setup the callbacks.
*/
static int
-xz_lzma_bidder_init(struct archive_read_filter *self)
+xz_lzma_bidder_init(struct archive_read_filter *f)
{
static const size_t out_block_size = 64 * 1024;
void *out_block;
- struct private_data *state;
+ struct xz *xz;
int ret;
- state = calloc(1, sizeof(*state));
+ xz = calloc(1, sizeof(*xz));
out_block = malloc(out_block_size);
- if (state == NULL || out_block == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
+ if (xz == NULL || out_block == NULL) {
+ archive_set_error(&f->archive->archive, ENOMEM,
"Can't allocate data for xz decompression");
free(out_block);
- free(state);
+ free(xz);
return (ARCHIVE_FATAL);
}
- self->data = state;
- state->out_block_size = out_block_size;
- state->out_block = out_block;
- self->vtable = &xz_lzma_reader_vtable;
+ f->data = xz;
+ xz->out_block_size = out_block_size;
+ xz->out_block = out_block;
+ f->vtable = &xz_lzma_reader_vtable;
- state->stream.avail_in = 0;
+ xz->stream.avail_in = 0;
- state->stream.next_out = state->out_block;
- state->stream.avail_out = state->out_block_size;
+ xz->stream.next_out = xz->out_block;
+ xz->stream.avail_out = xz->out_block_size;
- state->crc32 = 0;
- if (self->code == ARCHIVE_FILTER_LZIP) {
+ xz->crc32 = 0;
+ if (f->code == ARCHIVE_FILTER_LZIP) {
/*
* We have to read a lzip header and use it to initialize
* compression library, thus we cannot initialize the
* library for lzip here.
*/
- state->in_stream = 0;
+ xz->in_stream = 0;
return (ARCHIVE_OK);
} else
- state->in_stream = 1;
+ xz->in_stream = 1;
/* Initialize compression library. */
- if (self->code == ARCHIVE_FILTER_XZ)
- ret = lzma_stream_decoder(&(state->stream),
+ if (f->code == ARCHIVE_FILTER_XZ)
+ ret = lzma_stream_decoder(&(xz->stream),
LZMA_MEMLIMIT,/* memlimit */
LZMA_CONCATENATED);
else
- ret = lzma_alone_decoder(&(state->stream),
+ ret = lzma_alone_decoder(&(xz->stream),
LZMA_MEMLIMIT);/* memlimit */
if (ret == LZMA_OK)
return (ARCHIVE_OK);
/* Library setup failed: Choose an error message and clean up. */
- set_error(self, ret);
+ set_error(f, ret);
- free(state->out_block);
- free(state);
- self->data = NULL;
+ free(xz->out_block);
+ free(xz);
+ f->data = NULL;
+ f->vtable = NULL;
return (ARCHIVE_FATAL);
}
static int
-lzip_init(struct archive_read_filter *self)
+lzip_init(struct archive_read_filter *f)
{
- struct private_data *state;
+ struct xz *xz = f->data;
const unsigned char *h;
lzma_filter filters[2];
unsigned char props[5];
- ssize_t avail_in;
uint32_t dicsize;
int log2dic, ret;
- state = (struct private_data *)self->data;
- h = __archive_read_filter_ahead(self->upstream, 6, &avail_in);
+ h = __archive_read_filter_ahead(f->upstream, 6, NULL);
if (h == NULL)
return (ARCHIVE_FATAL);
/* Get a version number. */
- state->lzip_ver = h[4];
+ xz->lzip_ver = h[4];
/*
* Setup lzma property.
@@ -563,8 +557,8 @@ lzip_init(struct archive_read_filter *self)
archive_le32enc(props+1, dicsize);
/* Consume lzip header. */
- __archive_read_filter_consume(self->upstream, 6);
- state->member_in = 6;
+ __archive_read_filter_consume(f->upstream, 6);
+ xz->member_in = 6;
filters[0].id = LZMA_FILTER_LZMA1;
filters[0].options = NULL;
@@ -573,74 +567,73 @@ lzip_init(struct archive_read_filter *self)
ret = lzma_properties_decode(&filters[0], NULL, props, sizeof(props));
if (ret != LZMA_OK) {
- set_error(self, ret);
+ set_error(f, ret);
return (ARCHIVE_FATAL);
}
- ret = lzma_raw_decoder(&(state->stream), filters);
+ ret = lzma_raw_decoder(&(xz->stream), filters);
free(filters[0].options);
if (ret != LZMA_OK) {
- set_error(self, ret);
+ set_error(f, ret);
return (ARCHIVE_FATAL);
}
return (ARCHIVE_OK);
}
static int
-lzip_tail(struct archive_read_filter *self)
+lzip_tail(struct archive_read_filter *f)
{
- struct private_data *state;
- const unsigned char *f;
+ struct xz *xz = f->data;
+ const unsigned char *p;
ssize_t avail_in;
int tail;
- state = (struct private_data *)self->data;
- if (state->lzip_ver == 0)
+ if (xz->lzip_ver == 0)
tail = 12;
else
tail = 20;
- f = __archive_read_filter_ahead(self->upstream, tail, &avail_in);
- if (f == NULL && avail_in < 0)
+ p = __archive_read_filter_ahead(f->upstream, tail, &avail_in);
+ if (p == NULL && avail_in < 0)
return (ARCHIVE_FATAL);
- if (f == NULL || avail_in < tail) {
- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ if (p == NULL || avail_in < tail) {
+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
"Lzip: Remaining data is less bytes");
return (ARCHIVE_FAILED);
}
/* Check the crc32 value of the uncompressed data of the current
* member */
- if (state->crc32 != archive_le32dec(f)) {
+ if (xz->crc32 != archive_le32dec(p)) {
#ifndef DONT_FAIL_ON_CRC_ERROR
- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
"Lzip: CRC32 error");
return (ARCHIVE_FAILED);
#endif
}
/* Check the uncompressed size of the current member */
- if ((uint64_t)state->member_out != archive_le64dec(f + 4)) {
- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ if ((uint64_t)xz->member_out != archive_le64dec(p + 4)) {
+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
"Lzip: Uncompressed size error");
return (ARCHIVE_FAILED);
}
/* Check the total size of the current member */
- if (state->lzip_ver == 1 &&
- (uint64_t)state->member_in + tail != archive_le64dec(f + 12)) {
- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ if (xz->lzip_ver == 1 &&
+ (uint64_t)xz->member_in + tail != archive_le64dec(p + 12)) {
+ archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
"Lzip: Member size error");
return (ARCHIVE_FAILED);
}
- __archive_read_filter_consume(self->upstream, tail);
+ __archive_read_filter_consume(f->upstream, tail);
/* If current lzip data consists of multi member, try decompressing
* a next member. */
- if (lzip_has_member(self->upstream) != 0) {
- state->in_stream = 0;
- state->crc32 = 0;
- state->member_out = 0;
- state->member_in = 0;
- state->eof = 0;
+ if (lzip_has_member(f->upstream) != 0) {
+ xz->in_stream = 0;
+ xz->crc32 = 0;
+ xz->member_out = 0;
+ xz->member_in = 0;
+ xz->eof = 0;
}
return (ARCHIVE_OK);
}
@@ -649,83 +642,80 @@ lzip_tail(struct archive_read_filter *self)
* Return the next block of decompressed data.
*/
static ssize_t
-xz_filter_read(struct archive_read_filter *self, const void **p)
+xz_filter_read(struct archive_read_filter *f, const void **p)
{
- struct private_data *state;
+ struct xz *xz = f->data;
size_t decompressed;
ssize_t avail_in;
int64_t member_in;
int ret;
- state = (struct private_data *)self->data;
-
redo:
/* Empty our output buffer. */
- state->stream.next_out = state->out_block;
- state->stream.avail_out = state->out_block_size;
- member_in = state->member_in;
+ xz->stream.next_out = xz->out_block;
+ xz->stream.avail_out = xz->out_block_size;
+ member_in = xz->member_in;
/* Try to fill the output buffer. */
- while (state->stream.avail_out > 0 && !state->eof) {
- if (!state->in_stream) {
+ while (xz->stream.avail_out > 0 && !xz->eof) {
+ if (!xz->in_stream) {
/*
* Initialize liblzma for lzip
*/
- ret = lzip_init(self);
+ ret = lzip_init(f);
if (ret != ARCHIVE_OK)
return (ret);
- state->in_stream = 1;
+ xz->in_stream = 1;
}
- state->stream.next_in =
- __archive_read_filter_ahead(self->upstream, 1, &avail_in);
- if (state->stream.next_in == NULL && avail_in < 0) {
- archive_set_error(&self->archive->archive,
+ xz->stream.next_in =
+ __archive_read_filter_ahead(f->upstream, 1, &avail_in);
+ if (xz->stream.next_in == NULL && avail_in < 0) {
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"truncated input");
return (ARCHIVE_FATAL);
}
- state->stream.avail_in = avail_in;
+ xz->stream.avail_in = avail_in;
/* Decompress as much as we can in one pass. */
- ret = lzma_code(&(state->stream),
- (state->stream.avail_in == 0)? LZMA_FINISH: LZMA_RUN);
+ ret = lzma_code(&(xz->stream),
+ (xz->stream.avail_in == 0)? LZMA_FINISH: LZMA_RUN);
switch (ret) {
case LZMA_STREAM_END: /* Found end of stream. */
- state->eof = 1;
+ xz->eof = 1;
/* FALL THROUGH */
case LZMA_OK: /* Decompressor made some progress. */
- __archive_read_filter_consume(self->upstream,
- avail_in - state->stream.avail_in);
- state->member_in +=
- avail_in - state->stream.avail_in;
+ __archive_read_filter_consume(f->upstream,
+ avail_in - xz->stream.avail_in);
+ xz->member_in +=
+ avail_in - xz->stream.avail_in;
break;
default:
- set_error(self, ret);
+ set_error(f, ret);
return (ARCHIVE_FATAL);
}
}
- decompressed = state->stream.next_out - state->out_block;
- state->total_out += decompressed;
- state->member_out += decompressed;
+ decompressed = xz->stream.next_out - xz->out_block;
+ xz->member_out += decompressed;
if (decompressed == 0) {
- if (member_in != state->member_in &&
- self->code == ARCHIVE_FILTER_LZIP &&
- state->eof) {
- ret = lzip_tail(self);
+ if (member_in != xz->member_in &&
+ f->code == ARCHIVE_FILTER_LZIP &&
+ xz->eof) {
+ ret = lzip_tail(f);
if (ret != ARCHIVE_OK)
return (ret);
- if (!state->eof)
+ if (!xz->eof)
goto redo;
}
*p = NULL;
} else {
- *p = state->out_block;
- if (self->code == ARCHIVE_FILTER_LZIP) {
- state->crc32 = lzma_crc32(state->out_block,
- decompressed, state->crc32);
- if (state->eof) {
- ret = lzip_tail(self);
+ *p = xz->out_block;
+ if (f->code == ARCHIVE_FILTER_LZIP) {
+ xz->crc32 = lzma_crc32(xz->out_block,
+ decompressed, xz->crc32);
+ if (xz->eof) {
+ ret = lzip_tail(f);
if (ret != ARCHIVE_OK)
return (ret);
}
@@ -738,14 +728,13 @@ xz_filter_read(struct archive_read_filter *self, const void **p)
* Clean up the decompressor.
*/
static int
-xz_filter_close(struct archive_read_filter *self)
+xz_filter_close(struct archive_read_filter *f)
{
- struct private_data *state;
+ struct xz *xz = f->data;
- state = (struct private_data *)self->data;
- lzma_end(&(state->stream));
- free(state->out_block);
- free(state);
+ lzma_end(&(xz->stream));
+ free(xz->out_block);
+ free(xz);
return (ARCHIVE_OK);
}
@@ -759,44 +748,44 @@ xz_filter_close(struct archive_read_filter *self)
*
*/
static int
-lzma_bidder_init(struct archive_read_filter *self)
+lzma_bidder_init(struct archive_read_filter *f)
{
int r;
- r = __archive_read_program(self, "lzma -d -qq");
+ r = __archive_read_program(f, "lzma -d -qq");
/* Note: We set the format here even if __archive_read_program()
* above fails. We do, after all, know what the format is
* even if we weren't able to read it. */
- self->code = ARCHIVE_FILTER_LZMA;
- self->name = "lzma";
+ f->code = ARCHIVE_FILTER_LZMA;
+ f->name = "lzma";
return (r);
}
static int
-xz_bidder_init(struct archive_read_filter *self)
+xz_bidder_init(struct archive_read_filter *f)
{
int r;
- r = __archive_read_program(self, "xz -d -qq");
+ r = __archive_read_program(f, "xz -d -qq");
/* Note: We set the format here even if __archive_read_program()
* above fails. We do, after all, know what the format is
* even if we weren't able to read it. */
- self->code = ARCHIVE_FILTER_XZ;
- self->name = "xz";
+ f->code = ARCHIVE_FILTER_XZ;
+ f->name = "xz";
return (r);
}
static int
-lzip_bidder_init(struct archive_read_filter *self)
+lzip_bidder_init(struct archive_read_filter *f)
{
int r;
- r = __archive_read_program(self, "lzip -d -q");
+ r = __archive_read_program(f, "lzip -d -q");
/* Note: We set the format here even if __archive_read_program()
* above fails. We do, after all, know what the format is
* even if we weren't able to read it. */
- self->code = ARCHIVE_FILTER_LZIP;
- self->name = "lzip";
+ f->code = ARCHIVE_FILTER_LZIP;
+ f->name = "lzip";
return (r);
}
diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_zstd.c b/contrib/libarchive/libarchive/archive_read_support_filter_zstd.c
index da7c540dbcd9..12eac04ca3aa 100644
--- a/contrib/libarchive/libarchive/archive_read_support_filter_zstd.c
+++ b/contrib/libarchive/libarchive/archive_read_support_filter_zstd.c
@@ -48,16 +48,16 @@
#include "archive.h"
#include "archive_endian.h"
+#include "archive_integer.h"
#include "archive_private.h"
#include "archive_read_private.h"
#if HAVE_ZSTD_H && HAVE_LIBZSTD
-struct private_data {
+struct zstd {
ZSTD_DStream *dstream;
unsigned char *out_block;
size_t out_block_size;
- int64_t total_out;
char in_frame; /* True = in the middle of a zstd frame. */
char eof; /* True = found end of compressed data. */
};
@@ -70,8 +70,7 @@ static int zstd_filter_close(struct archive_read_filter *);
/*
* Note that we can detect zstd compressed files even if we can't decompress
* them. (In fact, we like detecting them because we can give better error
- * messages.) So the bid framework here gets compiled even if no zstd library
- * is available.
+ * messages.)
*/
static int zstd_bidder_bid(struct archive_read_filter_bidder *,
struct archive_read_filter *);
@@ -105,60 +104,82 @@ archive_read_support_filter_zstd(struct archive *_a)
* Test whether we can handle this data.
*/
static int
-zstd_bidder_bid(struct archive_read_filter_bidder *self,
- struct archive_read_filter *filter)
+zstd_bidder_bid(struct archive_read_filter_bidder *b,
+ struct archive_read_filter *f)
{
const unsigned char *buffer;
ssize_t avail;
+ /*
+ * Zstandard skippable frames contain a 4 byte magic number followed
+ * by a 4 byte frame data size, then that number of bytes of data.
+ * Regular frames contain a 4 byte magic number followed by a 2-14
+ * byte frame header, some data, and a 3 byte end marker.
+ */
+ const size_t min_zstd_frame_size = 8;
- // Zstandard skippable frames contain a 4 byte magic number followed by
- // a 4 byte frame data size, then that number of bytes of data. Regular
- // frames contain a 4 byte magic number followed by a 2-14 byte frame
- // header, some data, and a 3 byte end marker.
- ssize_t min_zstd_frame_size = 8;
+ size_t offset_in_buffer = 0;
+ const size_t max_lookahead = 64 * 1024;
+ uint32_t magic_number;
- ssize_t offset_in_buffer = 0;
- ssize_t max_lookahead = 64 * 1024;
+ /* Zstd regular frame magic number. */
+ const uint32_t zstd_magic = 0xFD2FB528U;
- // Zstd regular frame magic number.
- uint32_t zstd_magic = 0xFD2FB528U;
+ /*
+ * Note: Zstd and LZ4 skippable frame magic numbers are identical.
+ * To differentiate these two, we need to look for a non-skippable
+ * frame.
+ */
+ const uint32_t zstd_magic_skippable_start = 0x184D2A50;
+ const uint32_t zstd_magic_skippable_mask = 0xFFFFFFF0;
- // Note: Zstd and LZ4 skippable frame magic numbers are identical.
- // To differentiate these two, we need to look for a non-skippable
- // frame.
- uint32_t zstd_magic_skippable_start = 0x184D2A50;
- uint32_t zstd_magic_skippable_mask = 0xFFFFFFF0;
+ (void) b; /* UNUSED */
- (void) self; // UNUSED
-
- buffer = __archive_read_filter_ahead(filter, min_zstd_frame_size, &avail);
+ buffer = __archive_read_filter_ahead(f, min_zstd_frame_size,
+ &avail);
if (buffer == NULL)
return (0);
- uint32_t magic_number = archive_le32dec(buffer);
+ magic_number = archive_le32dec(buffer);
- while ((magic_number & zstd_magic_skippable_mask) == zstd_magic_skippable_start) {
+ while ((magic_number & zstd_magic_skippable_mask) ==
+ zstd_magic_skippable_start) {
+ size_t min;
+ uint32_t frame_data_size;
- offset_in_buffer += 4; // Skip over the magic number
+ /* Skip over the magic number */
+ offset_in_buffer += 4;
- // Ensure that we can read another 4 bytes.
- if (offset_in_buffer + 4 > avail) {
- buffer = __archive_read_filter_ahead(filter, offset_in_buffer + 4, &avail);
+ /* Ensure that we can read another 4 bytes. */
+ if (offset_in_buffer + 4 > (size_t)avail) {
+ buffer = __archive_read_filter_ahead(f,
+ offset_in_buffer + 4, &avail);
if (buffer == NULL)
return (0);
}
- uint32_t frame_data_size = archive_le32dec(buffer + offset_in_buffer);
+ frame_data_size = archive_le32dec(buffer + offset_in_buffer);
+
+ /* Skip over the 4 frame data size bytes */
+ offset_in_buffer += 4;
- // Skip over the 4 frame data size bytes, plus the value stored there.
- offset_in_buffer += 4 + frame_data_size;
+ /* Skip over the value stored there. */
+ if (archive_ckd_add_size(&offset_in_buffer,
+ offset_in_buffer, frame_data_size))
+ return (0);
- // There should be at least one more frame if this is zstd data.
- if (offset_in_buffer + min_zstd_frame_size > avail) {
- if (offset_in_buffer + min_zstd_frame_size > max_lookahead)
+ /*
+ * There should be at least one more frame
+ * if this is zstd data.
+ */
+ if (archive_ckd_add_size(&min,
+ offset_in_buffer, min_zstd_frame_size))
+ return (0);
+ if (min > (size_t)avail) {
+ if (min > max_lookahead)
return (0);
- buffer = __archive_read_filter_ahead(filter, offset_in_buffer + min_zstd_frame_size, &avail);
+ buffer = __archive_read_filter_ahead(f,
+ min, &avail);
if (buffer == NULL)
return (0);
}
@@ -166,8 +187,10 @@ zstd_bidder_bid(struct archive_read_filter_bidder *self,
magic_number = archive_le32dec(buffer + offset_in_buffer);
}
- // We have skipped over any skippable frames. Either a regular zstd frame
- // follows, or this isn't zstd data.
+ /*
+ * We have skipped over any skippable frames. Either a regular zstd
+ * frame follows, or this isn't zstd data.
+ */
if (magic_number == zstd_magic)
return (offset_in_buffer + 4);
@@ -179,20 +202,20 @@ zstd_bidder_bid(struct archive_read_filter_bidder *self,
/*
* If we don't have the library on this system, we can't do the
- * decompression directly. We can, however, try to run "zstd -d"
+ * decompression directly. We can, however, try to run "zstd -d -qq"
* in case that's available.
*/
static int
-zstd_bidder_init(struct archive_read_filter *self)
+zstd_bidder_init(struct archive_read_filter *f)
{
int r;
- r = __archive_read_program(self, "zstd -d -qq");
+ r = __archive_read_program(f, "zstd -d -qq");
/* Note: We set the format here even if __archive_read_program()
* above fails. We do, after all, know what the format is
* even if we weren't able to read it. */
- self->code = ARCHIVE_FILTER_ZSTD;
- self->name = "zstd";
+ f->code = ARCHIVE_FILTER_ZSTD;
+ f->name = "zstd";
return (r);
}
@@ -208,80 +231,78 @@ zstd_reader_vtable = {
* Initialize the filter object
*/
static int
-zstd_bidder_init(struct archive_read_filter *self)
+zstd_bidder_init(struct archive_read_filter *f)
{
- struct private_data *state;
+ struct zstd *zstd;
size_t out_block_size = ZSTD_DStreamOutSize();
void *out_block;
ZSTD_DStream *dstream;
- self->code = ARCHIVE_FILTER_ZSTD;
- self->name = "zstd";
+ f->code = ARCHIVE_FILTER_ZSTD;
+ f->name = "zstd";
- state = calloc(1, sizeof(*state));
+ zstd = calloc(1, sizeof(*zstd));
out_block = malloc(out_block_size);
dstream = ZSTD_createDStream();
- if (state == NULL || out_block == NULL || dstream == NULL) {
+ if (zstd == NULL || out_block == NULL || dstream == NULL) {
free(out_block);
- free(state);
+ free(zstd);
ZSTD_freeDStream(dstream); /* supports free on NULL */
- archive_set_error(&self->archive->archive, ENOMEM,
+ archive_set_error(&f->archive->archive, ENOMEM,
"Can't allocate data for zstd decompression");
return (ARCHIVE_FATAL);
}
- self->data = state;
+ f->data = zstd;
- state->out_block_size = out_block_size;
- state->out_block = out_block;
- state->dstream = dstream;
- self->vtable = &zstd_reader_vtable;
+ zstd->out_block_size = out_block_size;
+ zstd->out_block = out_block;
+ zstd->dstream = dstream;
+ f->vtable = &zstd_reader_vtable;
- state->eof = 0;
- state->in_frame = 0;
+ zstd->eof = 0;
+ zstd->in_frame = 0;
return (ARCHIVE_OK);
}
static ssize_t
-zstd_filter_read(struct archive_read_filter *self, const void **p)
+zstd_filter_read(struct archive_read_filter *f, const void **p)
{
- struct private_data *state;
+ struct zstd *zstd = f->data;
size_t decompressed;
ssize_t avail_in;
ZSTD_outBuffer out;
ZSTD_inBuffer in;
size_t ret;
- state = (struct private_data *)self->data;
-
- out = (ZSTD_outBuffer) { state->out_block, state->out_block_size, 0 };
+ out = (ZSTD_outBuffer) { zstd->out_block, zstd->out_block_size, 0 };
/* Try to fill the output buffer. */
- while (out.pos < out.size && !state->eof) {
- if (!state->in_frame) {
- ret = ZSTD_initDStream(state->dstream);
+ while (out.pos < out.size && !zstd->eof) {
+ if (!zstd->in_frame) {
+ ret = ZSTD_initDStream(zstd->dstream);
if (ZSTD_isError(ret)) {
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Error initializing zstd decompressor: %s",
ZSTD_getErrorName(ret));
return (ARCHIVE_FATAL);
}
}
- in.src = __archive_read_filter_ahead(self->upstream, 1,
+ in.src = __archive_read_filter_ahead(f->upstream, 1,
&avail_in);
if (avail_in < 0) {
return avail_in;
}
if (in.src == NULL && avail_in == 0) {
- if (!state->in_frame) {
+ if (!zstd->in_frame) {
/* end of stream */
- state->eof = 1;
+ zstd->eof = 1;
break;
} else {
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Truncated zstd input");
return (ARCHIVE_FATAL);
@@ -291,10 +312,10 @@ zstd_filter_read(struct archive_read_filter *self, const void **p)
in.pos = 0;
{
- ret = ZSTD_decompressStream(state->dstream, &out, &in);
+ ret = ZSTD_decompressStream(zstd->dstream, &out, &in);
if (ZSTD_isError(ret)) {
- archive_set_error(&self->archive->archive,
+ archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Zstd decompression failed: %s",
ZSTD_getErrorName(ret));
@@ -302,19 +323,18 @@ zstd_filter_read(struct archive_read_filter *self, const void **p)
}
/* Decompressor made some progress */
- __archive_read_filter_consume(self->upstream, in.pos);
+ __archive_read_filter_consume(f->upstream, in.pos);
/* ret guaranteed to be > 0 if frame isn't done yet */
- state->in_frame = (ret != 0);
+ zstd->in_frame = (ret != 0);
}
}
decompressed = out.pos;
- state->total_out += decompressed;
if (decompressed == 0)
*p = NULL;
else
- *p = state->out_block;
+ *p = zstd->out_block;
return (decompressed);
}
@@ -322,15 +342,13 @@ zstd_filter_read(struct archive_read_filter *self, const void **p)
* Clean up the decompressor.
*/
static int
-zstd_filter_close(struct archive_read_filter *self)
+zstd_filter_close(struct archive_read_filter *f)
{
- struct private_data *state;
-
- state = (struct private_data *)self->data;
+ struct zstd *zstd = f->data;
- ZSTD_freeDStream(state->dstream);
- free(state->out_block);
- free(state);
+ ZSTD_freeDStream(zstd->dstream);
+ free(zstd->out_block);
+ free(zstd);
return (ARCHIVE_OK);
}
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_7zip.c b/contrib/libarchive/libarchive/archive_read_support_format_7zip.c
index 8926ac50a1ed..9c9f9a0eefdf 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_7zip.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_7zip.c
@@ -53,6 +53,7 @@
#include "archive.h"
#include "archive_entry.h"
#include "archive_entry_locale.h"
+#include "archive_integer.h"
#include "archive_ppmd7_private.h"
#include "archive_private.h"
#include "archive_read_private.h"
@@ -67,16 +68,17 @@
#define SFX_MIN_ADDR 0x27000
#define SFX_MAX_ADDR 0x60000
#define SFX_MAX_OFFSET (SFX_MAX_ADDR - SFX_MIN_ADDR)
+#define SFX_MAX_SEEK 0x800000
/*
* PE format
*/
-#define PE_DOS_HDR_LEN 0x40
+#define PE_DOS_HDR_LEN 0x40
#define PE_DOS_HDR_ELFANEW_OFFSET 0x3c
-#define PE_COFF_HDR_LEN 0x18
+#define PE_COFF_HDR_LEN 0x18
#define PE_COFF_HDR_SEC_CNT_OFFSET 0x6
#define PE_COFF_HDR_OPT_SZ_OFFSET 0x14
-#define PE_SEC_HDR_LEN 0x28
+#define PE_SEC_HDR_LEN 0x28
#define PE_SEC_HDR_RAW_ADDR_OFFSET 0x14
#define PE_SEC_HDR_RAW_SZ_OFFSET 0x10
@@ -97,8 +99,8 @@
#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_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 */
@@ -172,50 +174,48 @@ struct _7z_digests {
};
struct _7z_folder {
- uint64_t numCoders;
+ size_t numCoders;
struct _7z_coder {
- unsigned long codec;
- uint64_t numInStreams;
- uint64_t numOutStreams;
- uint64_t propertiesSize;
+ int64_t codec;
+ size_t numInStreams;
+ size_t numOutStreams;
+ size_t propertiesSize;
unsigned char *properties;
} *coders;
- uint64_t numBindPairs;
+ size_t numBindPairs;
struct {
- uint64_t inIndex;
- uint64_t outIndex;
+ size_t inIndex;
+ size_t outIndex;
} *bindPairs;
- uint64_t numPackedStreams;
- uint64_t *packedStreams;
- uint64_t numInStreams;
- uint64_t numOutStreams;
- uint64_t *unPackSize;
+ size_t numPackedStreams;
+ size_t numInStreams;
+ size_t numOutStreams;
+ int64_t *unPackSize;
unsigned char digest_defined;
uint32_t digest;
- uint64_t numUnpackStreams;
- uint32_t packIndex;
+ size_t numUnpackStreams;
+ size_t packIndex;
/* Unoperated bytes. */
- uint64_t skipped_bytes;
+ int64_t skipped_bytes;
};
struct _7z_coders_info {
- uint64_t numFolders;
+ size_t numFolders;
struct _7z_folder *folders;
- uint64_t dataStreamIndex;
};
struct _7z_pack_info {
- uint64_t pos;
- uint64_t numPackStreams;
- uint64_t *sizes;
+ int64_t pos;
+ size_t numPackStreams;
+ int64_t *sizes;
struct _7z_digests digest;
/* Calculated from pos and numPackStreams. */
- uint64_t *positions;
+ int64_t *positions;
};
struct _7z_substream_info {
size_t unpack_streams;
- uint64_t *unpackSizes;
+ int64_t *unpackSizes;
unsigned char *digestsDefined;
uint32_t *digests;
};
@@ -227,8 +227,6 @@ struct _7z_stream_info {
};
struct _7z_header_info {
- uint64_t dataIndex;
-
unsigned char *emptyStreamBools;
unsigned char *emptyFileBools;
unsigned char *antiBools;
@@ -241,8 +239,8 @@ struct _7zip_entry {
#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
const wchar_t *wname;
#endif
- uint32_t folderIndex;
- uint32_t ssIndex;
+ size_t folderIndex;
+ size_t ssIndex;
unsigned flg;
#define MTIME_IS_SET (1<<0)
#define ATIME_IS_SET (1<<1)
@@ -266,24 +264,24 @@ struct _7zip {
int header_is_being_read;
int header_is_encoded;
- uint64_t header_bytes_remaining;
+ int64_t header_bytes_remaining;
unsigned long header_crc32;
/* Header offset to check that reading points of the file contents
* will not exceed the header. */
- uint64_t header_offset;
+ int64_t header_offset;
/* Base offset of the archive file for a seek in case reading SFX. */
- uint64_t seek_base;
+ int64_t seek_base;
/* List of entries */
size_t entries_remaining;
- uint64_t numFiles;
+ size_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;
+ int64_t entry_bytes_remaining;
/* Running CRC32 of the decompressed data */
unsigned long entry_crc32;
@@ -304,16 +302,16 @@ struct _7zip {
/*
* 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;
+ size_t folder_index;
+ int64_t folder_outbytes_remaining;
+ size_t pack_stream_index;
+ size_t pack_stream_remaining;
+ int64_t pack_stream_inbytes_remaining;
+ int64_t pack_stream_bytes_unconsumed;
/* The codec information of a folder. */
- unsigned long codec;
- unsigned long codec2;
+ int64_t codec;
+ int64_t codec2;
/*
* Decompressor controllers.
@@ -334,7 +332,7 @@ struct _7zip {
int stream_valid;
#endif
/* Decoding Zstandard data. */
-#if HAVE_ZSTD_H
+#if HAVE_ZSTD_H && HAVE_LIBZSTD
ZSTD_DStream *zstd_dstream;
int zstdstream_valid;
#endif
@@ -345,12 +343,10 @@ struct _7zip {
IByteIn bytein;
struct {
const unsigned char *next_in;
- int64_t avail_in;
- int64_t total_in;
- int64_t stream_in;
+ size_t avail_in;
+ size_t stream_in;
unsigned char *next_out;
- int64_t avail_out;
- int64_t total_out;
+ size_t avail_out;
int overconsumed;
} ppstream;
int ppmd7_valid;
@@ -365,7 +361,7 @@ struct _7zip {
uint32_t bcj_ip;
/* Decoding BCJ2 data. */
- size_t main_stream_bytes_remaining;
+ int64_t main_stream_bytes_remaining;
unsigned char *sub_stream_buff[3];
size_t sub_stream_size[3];
size_t sub_stream_bytes_remaining[3];
@@ -382,13 +378,11 @@ struct _7zip {
uint8_t bcj2_prevByte;
uint32_t bcj2_range;
uint32_t bcj2_code;
- uint64_t bcj2_outPos;
+ size_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;
};
@@ -396,10 +390,14 @@ struct _7zip {
/* 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)
+#define UMAX_ENTRY ARCHIVE_LITERAL_LL(100000000)
+
+/* Don't try to read more than 16 MB at a time */
+#define MAX_READ 16 * 1024 * 1024
+static size_t align_size(size_t);
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_support_format_7zip_capabilities(struct archive_read *);
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 *,
@@ -407,14 +405,15 @@ static int archive_read_format_7zip_read_data(struct archive_read *,
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 size_t check_7zip_header_in_sfx(const unsigned char *);
+static int decode_codec_id(const unsigned char *, size_t, int64_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 uint64_t folder_uncompressed_size(struct _7z_folder *);
+static int files_info_numfiles_is_sane(const struct _7zip *);
+static int64_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 *);
@@ -425,10 +424,11 @@ 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 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 parse_7zip_size(struct archive_read *, size_t *);
+static int parse_7zip_int64(struct archive_read *, int64_t *);
static int read_Bools(struct archive_read *, unsigned char *, size_t);
static int read_CodersInfo(struct archive_read *,
struct _7z_coders_info *);
@@ -442,16 +442,15 @@ 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 int read_Times(struct archive_read *, int);
+static int 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 *, const ssize_t);
-static ssize_t find_pe_overlay(struct archive_read *);
-static ssize_t find_elf_data_sec(struct archive_read *);
+static int skip_stream(struct archive_read *, int64_t);
+static int get_data_offset(struct archive_read *, int64_t *, int);
+static int get_pe_sfx_offset(struct archive_read *, int64_t *);
+static int get_elf_sfx_offset(struct archive_read *, int64_t *, int);
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 *,
@@ -461,9 +460,10 @@ static size_t x86_Convert(struct _7zip *, uint8_t *, size_t);
static void arm_Init(struct _7zip *);
static size_t arm_Convert(struct _7zip *, uint8_t *, size_t);
static size_t arm64_Convert(struct _7zip *, uint8_t *, size_t);
-static ssize_t Bcj2_Decode(struct _7zip *, uint8_t *, size_t);
+static ssize_t Bcj2_Decode(struct _7zip *, uint8_t *, size_t);
static size_t sparc_Convert(struct _7zip *, uint8_t *, size_t);
static size_t powerpc_Convert(struct _7zip *, uint8_t *, size_t);
+static int64_t seek_compat(struct archive_read *, int64_t, int, int);
int
@@ -509,19 +509,18 @@ archive_read_support_format_7zip(struct archive *_a)
}
static int
-archive_read_support_format_7zip_capabilities(struct archive_read * a)
+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)
+archive_read_format_7zip_has_encrypted_entries(struct archive_read *a)
{
- if (_a && _a->format) {
- struct _7zip * zip = (struct _7zip *)_a->format->data;
+ if (a && a->format) {
+ struct _7zip *zip = a->format->data;
if (zip) {
return zip->has_encrypted_entries;
}
@@ -530,64 +529,92 @@ archive_read_format_7zip_has_encrypted_entries(struct archive_read *_a)
}
static int
-archive_read_format_7zip_bid(struct archive_read *a, int best_bid)
+get_data_offset(struct archive_read *a, int64_t *data_offset, int compat)
{
- 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);
+ const unsigned char *p;
+ int64_t offset, sfx_offset;
+ int r, window;
- if ((p = __archive_read_ahead(a, 6, NULL)) == NULL)
- return (0);
+ if ((p = __archive_read_ahead(a, 6, NULL)) == NULL) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated 7-Zip file body");
+ return (ARCHIVE_FATAL);
+ }
/* If first six bytes are the 7-Zip signature,
- * return the bid right now. */
- if (memcmp(p, _7ZIP_SIGNATURE, 6) == 0)
- return (48);
+ * return the offset right now. */
+ if (memcmp(p, _7ZIP_SIGNATURE, 6) == 0) {
+ *data_offset = 0;
+ return (ARCHIVE_OK);
+ }
/*
- * 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. While find_pe_overlay can be performed without
- * performing a seek, find_elf_data_sec requires one,
+ * It may be a 7-Zip SFX archive file. If first two bytes are
+ * 'M' and 'Z' (PE, Windows) or first four bytes are
+ * "\x7F\x45LF" (ELF, Posix-like systems), seek the 7-Zip
+ * signature. While get_pe_sfx_offset can be performed without
+ * performing a seek, get_elf_sfx_offset requires one,
* thus a performance difference between the two is expected.
*/
- if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {
- const ssize_t min_addr = p[0] == 'M' ? find_pe_overlay(a) :
- find_elf_data_sec(a);
- ssize_t offset = min_addr;
- ssize_t window = 4096;
+ if ((p[0] == 'M' && p[1] == 'Z'))
+ r = get_pe_sfx_offset(a, &sfx_offset);
+ else if (memcmp(p, "\x7F\x45LF", 4) == 0)
+ r = get_elf_sfx_offset(a, &sfx_offset, compat);
+ else
+ r = ARCHIVE_FATAL;
+ if (r < ARCHIVE_WARN || sfx_offset > SFX_MAX_SEEK)
+ goto fail;
+
+ offset = sfx_offset;
+ window = 4096;
+ while (offset + window <= (sfx_offset + SFX_MAX_OFFSET)) {
ssize_t bytes_avail;
- while (offset + window <= (min_addr + SFX_MAX_OFFSET)) {
- 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;
+ const unsigned char *buff = __archive_read_ahead(a,
+ offset + window, &bytes_avail);
+ if (buff == NULL) {
+ /* Remaining bytes are less than window. */
+ window >>= 1;
+ if (window < 0x40)
+ goto fail;
+ continue;
+ }
+ p = buff + offset;
+ while (buff + bytes_avail - p >= 32) {
+ size_t step = check_7zip_header_in_sfx(p);
+ if (step == 0) {
+ *data_offset = p - buff;
+ return (ARCHIVE_OK);
}
- offset = p - buff;
+ p += step;
}
+ offset = p - buff;
}
- return (0);
+fail:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Couldn't find out 7-Zip header");
+ return (ARCHIVE_FATAL);
}
static int
-check_7zip_header_in_sfx(const char *p)
+archive_read_format_7zip_bid(struct archive_read *a, int best_bid)
+{
+ int64_t data_offset;
+
+ /* 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 (get_data_offset(a, &data_offset, 0) < 0)
+ return (0);
+
+ return (48);
+}
+
+static size_t
+check_7zip_header_in_sfx(const unsigned char *p)
{
- switch ((unsigned char)p[5]) {
+ switch (p[5]) {
case 0x1C:
if (memcmp(p, _7ZIP_SIGNATURE, 6) != 0)
return (6);
@@ -596,8 +623,7 @@ check_7zip_header_in_sfx(const char *p)
* 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))
+ if (crc32(0, p + 12, 20) != archive_le32dec(p + 8))
return (6);
/* Hit the header! */
return (0);
@@ -611,79 +637,33 @@ check_7zip_header_in_sfx(const char *p)
}
static int
-skip_sfx(struct archive_read *a, const ssize_t min_addr)
-{
- const void *h;
- const char *p, *q;
- size_t skip, offset;
- ssize_t bytes, window;
-
- if (__archive_read_seek(a, 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 = 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 ssize_t
-find_pe_overlay(struct archive_read *a)
+get_pe_sfx_offset(struct archive_read *a, int64_t *sfx_offset)
{
const char *h;
- ssize_t bytes, max_offset, offset, sec_end;
- ssize_t opt_hdr_sz, sec_cnt;
+ int64_t max_offset, offset;
+ ssize_t bytes;
+ uint16_t opt_hdr_sz, sec_cnt;
+
+ /*
+ * If encounter any weirdness, revert to old brute-force style search
+ */
+ *sfx_offset = SFX_MIN_ADDR;
for (;;) {
/*
* Read Dos header to find e_lfanew
*/
h = __archive_read_ahead(a, PE_DOS_HDR_LEN, &bytes);
- if (h == NULL || h[0] != 'M' || h[1] != 'Z') {
+ if (h == NULL) {
+ return (ARCHIVE_FATAL);
+ }
+ if (h[0] != 'M' || h[1] != 'Z') {
break;
}
offset = archive_le32dec(h + PE_DOS_HDR_ELFANEW_OFFSET);
+ if (offset > SFX_MAX_SEEK) {
+ return (ARCHIVE_FATAL);
+ }
/*
* Read COFF header to find opt header size and sec cnt
@@ -691,8 +671,10 @@ find_pe_overlay(struct archive_read *a)
if (bytes < offset + PE_COFF_HDR_LEN) {
h = __archive_read_ahead(a, offset + PE_COFF_HDR_LEN,
&bytes);
- if (h == NULL || h[offset] != 'P' ||
- h[offset + 1] != 'E') {
+ if (h == NULL) {
+ return (ARCHIVE_FATAL);
+ }
+ if (h[offset] != 'P' || h[offset + 1] != 'E') {
break;
}
}
@@ -710,6 +692,10 @@ find_pe_overlay(struct archive_read *a)
break;
}
+ if (offset + sec_cnt * PE_SEC_HDR_LEN > SFX_MAX_SEEK) {
+ return (ARCHIVE_FATAL);
+ }
+
/*
* Traverse sec table to find max raw offset (i.e., overlay)
*/
@@ -717,12 +703,14 @@ find_pe_overlay(struct archive_read *a)
h = __archive_read_ahead(a,
offset + sec_cnt * PE_SEC_HDR_LEN, NULL);
if (h == NULL) {
- break;
+ return (ARCHIVE_FATAL);
}
}
max_offset = offset;
while (sec_cnt > 0) {
- sec_end = archive_le32dec(
+ int64_t sec_end;
+
+ sec_end = (int64_t)archive_le32dec(
h + offset + PE_SEC_HDR_RAW_SZ_OFFSET) +
archive_le32dec(
h + offset + PE_SEC_HDR_RAW_ADDR_OFFSET);
@@ -732,34 +720,40 @@ find_pe_overlay(struct archive_read *a)
offset += PE_SEC_HDR_LEN;
sec_cnt--;
}
- return (max_offset);
+ *sfx_offset = max_offset;
+ break;
}
- /*
- * If encounter any weirdness, revert to old brute-force style search
- */
- return (SFX_MIN_ADDR);
+ return (ARCHIVE_OK);
}
-static ssize_t
-find_elf_data_sec(struct archive_read *a)
+static int
+get_elf_sfx_offset(struct archive_read *a, int64_t *sfx_offset, int compat)
{
+ int64_t r;
const char *h;
char big_endian, format_64;
- ssize_t bytes, min_addr = SFX_MIN_ADDR;
- ssize_t request;
+ size_t request;
uint64_t e_shoff, strtab_offset, strtab_size;
uint16_t e_shentsize, e_shnum, e_shstrndx;
uint16_t (*dec16)(const void *);
uint32_t (*dec32)(const void *);
uint64_t (*dec64)(const void *);
+ /*
+ * If encounter any weirdness, revert to old brute-force style search
+ */
+ *sfx_offset = SFX_MIN_ADDR;
+
for (;;) {
/*
* Read Elf header to find bitness & endianness
*/
- h = __archive_read_ahead(a, ELF_HDR_MIN_LEN, &bytes);
- if (h == NULL || memcmp(h, "\x7F\x45LF", 4) != 0) {
+ h = __archive_read_ahead(a, ELF_HDR_MIN_LEN, NULL);
+ if (h == NULL) {
+ return (ARCHIVE_FATAL);
+ }
+ if (memcmp(h, "\x7F\x45LF", 4) != 0) {
break;
}
format_64 = h[ELF_HDR_EI_CLASS_OFFSET] == 0x2;
@@ -782,7 +776,7 @@ find_elf_data_sec(struct archive_read *a)
e_shentsize = (*dec16)(h + 0x3A);
e_shnum = (*dec16)(h + 0x3C);
e_shstrndx = (*dec16)(h + 0x3E);
- if (e_shnum < e_shstrndx || e_shentsize < 0x28)
+ if (e_shnum <= e_shstrndx || e_shentsize < 0x28)
break;
} else {
@@ -790,24 +784,32 @@ find_elf_data_sec(struct archive_read *a)
e_shentsize = (*dec16)(h + 0x2E);
e_shnum = (*dec16)(h + 0x30);
e_shstrndx = (*dec16)(h + 0x32);
- if (e_shnum < e_shstrndx || e_shentsize < 0x18)
+ if (e_shnum <= e_shstrndx || e_shentsize < 0x18)
break;
}
+ if ((int64_t)e_shoff < 0) {
+ return (ARCHIVE_FATAL);
+ }
+
/*
* Reading the section table to find strtab section
*/
- if (__archive_read_seek(a, e_shoff, SEEK_SET) < 0) {
- break;
+ if (seek_compat(a, e_shoff, SEEK_SET, compat) < 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error");
+ return (ARCHIVE_FATAL);
}
if (format_64) {
- request = (size_t)e_shnum * (size_t)e_shentsize + 0x28;
+ request = (size_t)e_shnum * e_shentsize + 0x28;
} else {
- request = (size_t)e_shnum * (size_t)e_shentsize + 0x18;
+ request = (size_t)e_shnum * e_shentsize + 0x18;
+ }
+ if (request > SFX_MAX_SEEK) {
+ return (ARCHIVE_FATAL);
}
- h = __archive_read_ahead(a, request, &bytes);
+ h = __archive_read_ahead(a, request, NULL);
if (h == NULL) {
- break;
+ return (ARCHIVE_FATAL);
}
if (format_64) {
strtab_offset = (*dec64)(
@@ -820,45 +822,50 @@ find_elf_data_sec(struct archive_read *a)
strtab_size = (*dec32)(
h + e_shstrndx * e_shentsize + 0x14);
}
- if (strtab_size < 6 || strtab_size > SIZE_MAX)
- break;
+ if ((int64_t)strtab_offset < 0 || strtab_size < 6 ||
+ strtab_size > SFX_MAX_SEEK)
+ return (ARCHIVE_FATAL);
/*
* Read the STRTAB section to find the .data offset
*/
- if (__archive_read_seek(a, strtab_offset, SEEK_SET) < 0) {
- break;
+ if (seek_compat(a, strtab_offset, SEEK_SET, compat) < 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error");
+ return (ARCHIVE_FATAL);
}
h = __archive_read_ahead(a, strtab_size, NULL);
if (h == NULL) {
- break;
+ return (ARCHIVE_FATAL);
}
- ssize_t data_sym_offset = -1;
- for (size_t offset = 0; offset < strtab_size - 6; offset++) {
+ size_t data_sym_offset = strtab_size;
+ for (size_t offset = 0; offset + 6 <= strtab_size; offset++) {
if (memcmp(h + offset, ".data\00", 6) == 0) {
data_sym_offset = offset;
break;
}
}
- if (data_sym_offset == -1) {
+ if (data_sym_offset == strtab_size) {
break;
}
/*
* Find the section with the .data name
*/
- if (__archive_read_seek(a, e_shoff, SEEK_SET) < 0) {
- break;
+ if (seek_compat(a, e_shoff, SEEK_SET, compat) < 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error");
+ return (ARCHIVE_FATAL);
}
- h = __archive_read_ahead(a, (size_t)e_shnum * (size_t)e_shentsize, NULL);
+ h = __archive_read_ahead(a, (size_t)e_shnum * e_shentsize, NULL);
if (h == NULL) {
- break;
+ return (ARCHIVE_FATAL);
}
- ssize_t sec_tbl_offset = 0, name_offset;
+ size_t sec_tbl_offset = 0;
while (e_shnum > 0) {
+ uint32_t name_offset;
+
name_offset = (*dec32)(h + sec_tbl_offset);
if (name_offset == data_sym_offset) {
- uint64_t sel_offset;
+ int64_t sel_offset;
if (format_64) {
sel_offset = (*dec64)(
@@ -867,9 +874,8 @@ find_elf_data_sec(struct archive_read *a)
sel_offset = (*dec32)(
h + sec_tbl_offset + 0x10);
}
- if (sel_offset > SSIZE_MAX)
- break;
- min_addr = (ssize_t)sel_offset;
+ if (sel_offset >= 0)
+ *sfx_offset = sel_offset;
break;
}
sec_tbl_offset += e_shentsize;
@@ -878,19 +884,20 @@ find_elf_data_sec(struct archive_read *a)
break;
}
- __archive_read_seek(a, 0, SEEK_SET);
- return (min_addr);
+ r = seek_compat(a, 0, SEEK_SET, compat);
+ if (r < 0)
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error");
+ return (int)r;
}
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 *zip = 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
@@ -904,8 +911,7 @@ archive_read_format_7zip_read_header(struct archive_read *a,
}
a->archive.archive_format = ARCHIVE_FORMAT_7ZIP;
- if (a->archive.archive_format_name == NULL)
- a->archive.archive_format_name = "7-Zip";
+ a->archive.archive_format_name = "7-Zip";
if (zip->entries == NULL) {
struct _7z_header_info header;
@@ -915,20 +921,20 @@ archive_read_format_7zip_read_header(struct archive_read *a,
free_Header(&header);
if (r != ARCHIVE_OK)
return (r);
- zip->entries_remaining = (size_t)zip->numFiles;
+ zip->entries_remaining = zip->numFiles;
zip->entry = zip->entries;
} else {
++zip->entry;
}
zip_entry = zip->entry;
- if (zip->entries_remaining <= 0 || zip_entry == NULL)
+ 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);
+ zip->entry_crc32 = 0;
/* Setup a string conversion for a filename. */
if (zip->sconv == NULL) {
@@ -942,9 +948,11 @@ archive_read_format_7zip_read_header(struct archive_read *a,
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) {
+ if (zip_entry->folderIndex < zip->si.ci.numFolders) {
+ size_t fidx = 0;
+
folder = &(zip->si.ci.folders[zip_entry->folderIndex]);
- for (fidx=0; folder && fidx<folder->numCoders; fidx++) {
+ for (fidx = 0; fidx < folder->numCoders; fidx++) {
switch(folder->coders[fidx].codec) {
case _7Z_CRYPTO_MAIN_ZIP:
case _7Z_CRYPTO_RAR_29:
@@ -957,13 +965,6 @@ archive_read_format_7zip_read_header(struct archive_read *a,
}
}
- /* 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) {
@@ -991,7 +992,7 @@ archive_read_format_7zip_read_header(struct archive_read *a,
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) {
+ if (zip_entry->ssIndex != (size_t)-1) {
zip->entry_bytes_remaining =
zip->si.ss.unpackSizes[zip_entry->ssIndex];
archive_entry_set_size(entry, zip->entry_bytes_remaining);
@@ -1004,29 +1005,19 @@ archive_read_format_7zip_read_header(struct archive_read *a,
const int supported_attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
if (zip_entry->attr & supported_attrs) {
- char *fflags_text, *ptr;
- /* allocate for ",rdonly,hidden,system" */
- fflags_text = malloc(22 * sizeof(*fflags_text));
- if (fflags_text != NULL) {
- ptr = fflags_text;
- if (zip_entry->attr & FILE_ATTRIBUTE_READONLY) {
- strcpy(ptr, ",rdonly");
- ptr = ptr + 7;
- }
- if (zip_entry->attr & FILE_ATTRIBUTE_HIDDEN) {
- strcpy(ptr, ",hidden");
- ptr = ptr + 7;
- }
- if (zip_entry->attr & FILE_ATTRIBUTE_SYSTEM) {
- strcpy(ptr, ",system");
- ptr = ptr + 7;
- }
- if (ptr > fflags_text) {
- archive_entry_copy_fflags_text(entry,
- fflags_text + 1);
- }
- free(fflags_text);
- }
+ char buf[sizeof(",rdonly,hidden,system")];
+ const char *fflags[3] = { "", "", "" };
+ const char **flag = fflags;
+
+ if (zip_entry->attr & FILE_ATTRIBUTE_READONLY)
+ *flag++ = ",rdonly";
+ if (zip_entry->attr & FILE_ATTRIBUTE_HIDDEN)
+ *flag++ = ",hidden";
+ if (zip_entry->attr & FILE_ATTRIBUTE_SYSTEM)
+ *flag++ = ",system";
+
+ snprintf(buf, sizeof(buf), "%s%s%s", fflags[0], fflags[1], fflags[2]);
+ archive_entry_copy_fflags_text(entry, buf + 1);
}
/* If there's no body, force read_data() to return EOF immediately. */
@@ -1037,6 +1028,13 @@ archive_read_format_7zip_read_header(struct archive_read *a,
unsigned char *symname = NULL;
size_t symsize = 0;
+ if (zip->entry_bytes_remaining > 1024 * 1024) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Rejecting malformed 7zip archive: "
+ "symlink contents exceed 1 megabyte");
+ return (ARCHIVE_FATAL);
+ }
+
/*
* Symbolic-name is recorded as its contents. We have to
* read the contents at this time.
@@ -1090,10 +1088,6 @@ archive_read_format_7zip_read_header(struct archive_read *a,
archive_entry_set_size(entry, 0);
}
- /* Set up a more descriptive format name. */
- snprintf(zip->format_name, sizeof(zip->format_name), "7-Zip");
- a->archive.archive_format_name = zip->format_name;
-
return (ret);
}
@@ -1101,12 +1095,10 @@ static int
archive_read_format_7zip_read_data(struct archive_read *a,
const void **buff, size_t *size, int64_t *offset)
{
- struct _7zip *zip;
+ struct _7zip *zip = a->format->data;
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;
}
@@ -1124,8 +1116,8 @@ archive_read_format_7zip_read_data(struct archive_read *a,
if (zip->end_of_entry)
return (ARCHIVE_EOF);
- size_t bytes_to_read = 16 * 1024 * 1024; // Don't try to read more than 16 MB at a time
- if ((uint64_t)bytes_to_read > zip->entry_bytes_remaining) {
+ size_t bytes_to_read = MAX_READ;
+ if ((int64_t)bytes_to_read > zip->entry_bytes_remaining) {
bytes_to_read = (size_t)zip->entry_bytes_remaining;
}
bytes = read_stream(a, buff, bytes_to_read, 0);
@@ -1154,7 +1146,7 @@ archive_read_format_7zip_read_data(struct archive_read *a,
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,
+ zip->entry_crc32,
(unsigned long)zip->si.ss.digests[
zip->entry->ssIndex]);
ret = ARCHIVE_WARN;
@@ -1171,10 +1163,8 @@ archive_read_format_7zip_read_data(struct archive_read *a,
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);
+ struct _7zip *zip = a->format->data;
+ int r;
if (zip->pack_stream_bytes_unconsumed)
read_consume(a);
@@ -1187,9 +1177,9 @@ archive_read_format_7zip_read_data_skip(struct archive_read *a)
* 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);
+ r = skip_stream(a, zip->entry_bytes_remaining);
+ if (r < 0)
+ return (r);
zip->entry_bytes_remaining = 0;
/* This entry is finished and done. */
@@ -1200,9 +1190,8 @@ archive_read_format_7zip_read_data_skip(struct archive_read *a)
static int
archive_read_format_7zip_cleanup(struct archive_read *a)
{
- struct _7zip *zip;
+ struct _7zip *zip = a->format->data;
- zip = (struct _7zip *)(a->format->data);
free_StreamsInfo(&(zip->si));
free(zip->entries);
free(zip->entry_names);
@@ -1213,24 +1202,30 @@ archive_read_format_7zip_cleanup(struct archive_read *a)
free(zip->sub_stream_buff[2]);
free(zip->tmp_stream_buff);
free(zip);
- (a->format->data) = NULL;
+ a->format->data = NULL;
return (ARCHIVE_OK);
}
-static void
+static int
read_consume(struct archive_read *a)
{
- struct _7zip *zip = (struct _7zip *)a->format->data;
+ struct _7zip *zip = a->format->data;
if (zip->pack_stream_bytes_unconsumed) {
- __archive_read_consume(a, zip->pack_stream_bytes_unconsumed);
+ int64_t r;
+
+ if ((r = __archive_read_consume(a,
+ zip->pack_stream_bytes_unconsumed)) < 0)
+ return ((int)r);
+
zip->stream_offset += zip->pack_stream_bytes_unconsumed;
zip->pack_stream_bytes_unconsumed = 0;
}
+
+ return (ARCHIVE_OK);
}
#ifdef HAVE_LZMA_H
-
/*
* Set an error code and choose an error message for liblzma.
*/
@@ -1278,52 +1273,49 @@ set_error(struct archive_read *a, int ret)
break;
}
}
-
#endif
-static unsigned long
-decode_codec_id(const unsigned char *codecId, size_t id_size)
+static int
+decode_codec_id(const unsigned char *codecId, size_t id_size, int64_t *id)
{
- unsigned i;
- unsigned long id = 0;
+ size_t i;
+ *id = 0;
for (i = 0; i < id_size; i++) {
- id <<= 8;
- id += codecId[i];
+ if (archive_ckd_mul_i64(id, *id, 256) ||
+ archive_ckd_add_i64(id, *id, codecId[i]))
+ return (-1);
}
- return (id);
+ return (0);
}
static Byte
ppmd_read(void *p)
{
struct archive_read *a = ((IByteIn*)p)->a;
- struct _7zip *zip = (struct _7zip *)(a->format->data);
+ struct _7zip *zip = a->format->data;
Byte b;
- if (zip->ppstream.avail_in <= 0) {
+ if (zip->ppstream.avail_in == 0) {
/*
* Ppmd7_DecodeSymbol might require reading multiple bytes
* and we are on boundary;
* last resort to read using __archive_read_ahead.
*/
- ssize_t bytes_avail = 0;
- const uint8_t* data = __archive_read_ahead(a,
- (size_t)zip->ppstream.stream_in+1, &bytes_avail);
- if(data == NULL || bytes_avail < zip->ppstream.stream_in+1) {
+ const uint8_t *data = __archive_read_ahead(a,
+ zip->ppstream.stream_in + 1, NULL);
+ if (data == NULL) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated 7z file data");
zip->ppstream.overconsumed = 1;
return (0);
}
- zip->ppstream.next_in++;
b = data[zip->ppstream.stream_in];
} else {
b = *zip->ppstream.next_in++;
+ zip->ppstream.avail_in--;
}
- zip->ppstream.avail_in--;
- zip->ppstream.total_in++;
zip->ppstream.stream_in++;
return (b);
}
@@ -1352,8 +1344,9 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
coder2->codec != _7Z_SPARC) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "Unsupported filter %lx for %lx",
- coder2->codec, coder1->codec);
+ "Unsupported filter %jx for %jx",
+ (uintmax_t)coder2->codec,
+ (uintmax_t)coder1->codec);
return (ARCHIVE_FAILED);
}
zip->codec2 = coder2->codec;
@@ -1438,7 +1431,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
memset(&delta_opt, 0, sizeof(delta_opt));
delta_opt.type = LZMA_DELTA_TYPE_BYTE;
delta_opt.dist =
- (uint32_t)coder2->properties[0] + 1;
+ coder2->properties[0] + 1;
filters[fi].options = &delta_opt;
fi++;
break;
@@ -1478,7 +1471,8 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
default:
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "Unexpected codec ID: %lX", zip->codec2);
+ "Unexpected codec ID: %jX",
+ (uintmax_t)zip->codec2);
return (ARCHIVE_FAILED);
}
}
@@ -1490,7 +1484,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
filters[fi].options = NULL;
ff = &filters[fi];
r = lzma_properties_decode(&filters[fi], NULL,
- coder1->properties, (size_t)coder1->propertiesSize);
+ coder1->properties, coder1->propertiesSize);
if (r != LZMA_OK) {
set_error(a, r);
return (ARCHIVE_FAILED);
@@ -1558,7 +1552,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
#endif
case _7Z_ZSTD:
{
-#if defined(HAVE_ZSTD_H)
+#if HAVE_ZSTD_H && HAVE_LIBZSTD
if (zip->zstdstream_valid) {
ZSTD_freeDStream(zip->zstd_dstream);
zip->zstdstream_valid = 0;
@@ -1632,8 +1626,6 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
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:
@@ -1647,7 +1639,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
case _7Z_SPARC:
case _7Z_DELTA:
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Unexpected codec ID: %lX", zip->codec);
+ "Unexpected codec ID: %jX", (uintmax_t)zip->codec);
return (ARCHIVE_FAILED);
case _7Z_CRYPTO_MAIN_ZIP:
case _7Z_CRYPTO_RAR_29:
@@ -1658,11 +1650,12 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
zip->has_encrypted_entries = 1;
}
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Crypto codec not supported yet (ID: 0x%lX)", zip->codec);
+ "Crypto codec not supported yet (ID: 0x%jX)",
+ (uintmax_t)zip->codec);
return (ARCHIVE_FAILED);
default:
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Unknown codec ID: %lX", zip->codec);
+ "Unknown codec ID: %jX", (uintmax_t)zip->codec);
return (ARCHIVE_FAILED);
}
@@ -1714,7 +1707,7 @@ decompress(struct archive_read *a, struct _7zip *zip,
bcj2_avail_out = t_avail_out;
if (zip->codec2 == _7Z_X86_BCJ2) {
/*
- * Decord a remaining decompressed main stream for BCJ2.
+ * Decode a remaining decompressed main stream for BCJ2.
*/
if (zip->tmp_stream_bytes_remaining) {
ssize_t bytes;
@@ -1748,8 +1741,8 @@ decompress(struct archive_read *a, struct _7zip *zip,
switch (zip->codec) {
case _7Z_COPY:
{
- size_t bytes =
- (t_avail_in > t_avail_out)?t_avail_out:t_avail_in;
+ 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;
@@ -1787,10 +1780,14 @@ decompress(struct archive_read *a, struct _7zip *zip,
#endif
#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
case _7Z_BZ2:
+ if (t_avail_in > UINT_MAX)
+ t_avail_in = UINT_MAX;
+ if (t_avail_out > UINT_MAX)
+ t_avail_out = UINT_MAX;
zip->bzstream.next_in = (char *)(uintptr_t)t_next_in;
- zip->bzstream.avail_in = (uint32_t)t_avail_in;
+ zip->bzstream.avail_in = (unsigned int)t_avail_in;
zip->bzstream.next_out = (char *)(uintptr_t)t_next_out;
- zip->bzstream.avail_out = (uint32_t)t_avail_out;
+ zip->bzstream.avail_out = (unsigned int)t_avail_out;
r = BZ2_bzDecompress(&(zip->bzstream));
switch (r) {
case BZ_STREAM_END: /* Found end of stream. */
@@ -1820,6 +1817,10 @@ decompress(struct archive_read *a, struct _7zip *zip,
#endif
#ifdef HAVE_ZLIB_H
case _7Z_DEFLATE:
+ if (t_avail_in > UINT_MAX)
+ t_avail_in = UINT_MAX;
+ if (t_avail_out > UINT_MAX)
+ t_avail_out = UINT_MAX;
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;
@@ -1840,15 +1841,20 @@ decompress(struct archive_read *a, struct _7zip *zip,
t_avail_out = zip->stream.avail_out;
break;
#endif
-#ifdef HAVE_ZSTD_H
+#if HAVE_ZSTD_H && HAVE_LIBZSTD
case _7Z_ZSTD:
{
- ZSTD_inBuffer input = { t_next_in, t_avail_in, 0 }; // src, size, pos
- ZSTD_outBuffer output = { t_next_out, t_avail_out, 0 }; // dst, size, pos
+ /* src, size, pos */
+ ZSTD_inBuffer input = { t_next_in, t_avail_in, 0 };
+ /* dst, size, pos */
+ ZSTD_outBuffer output = { t_next_out, t_avail_out, 0 };
- size_t const zret = ZSTD_decompressStream(zip->zstd_dstream, &output, &input);
+ size_t const zret = ZSTD_decompressStream(zip->zstd_dstream,
+ &output, &input);
if (ZSTD_isError(zret)) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Zstd decompression failed: %s", ZSTD_getErrorName(zret));
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Zstd decompression failed: %s",
+ ZSTD_getErrorName(zret));
return ARCHIVE_FAILED;
}
t_avail_in -= input.pos;
@@ -1858,7 +1864,7 @@ decompress(struct archive_read *a, struct _7zip *zip,
#endif
case _7Z_PPMD:
{
- uint64_t flush_bytes;
+ int64_t flush_bytes;
if (!zip->ppmd7_valid || zip->ppmd7_stat < 0 ||
t_avail_out <= 0) {
@@ -1916,14 +1922,13 @@ decompress(struct archive_read *a, struct _7zip *zip,
}
*zip->ppstream.next_out++ = (unsigned char)sym;
zip->ppstream.avail_out--;
- zip->ppstream.total_out++;
- if (flush_bytes)
+ if (flush_bytes > 0)
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;
+ t_avail_in = zip->ppstream.avail_in;
+ t_avail_out = zip->ppstream.avail_out;
break;
}
default:
@@ -1938,7 +1943,7 @@ decompress(struct archive_read *a, struct _7zip *zip,
*outbytes = o_avail_out - t_avail_out;
/*
- * Decord BCJ.
+ * Decode BCJ.
*/
if (zip->codec != _7Z_LZMA2) {
if (zip->codec2 == _7Z_X86) {
@@ -1946,9 +1951,10 @@ decompress(struct archive_read *a, struct _7zip *zip,
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);
+ 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;
@@ -1964,7 +1970,7 @@ decompress(struct archive_read *a, struct _7zip *zip,
}
/*
- * Decord BCJ2 with a decompressed main stream.
+ * Decode BCJ2 with a decompressed main stream.
*/
if (zip->codec2 == _7Z_X86_BCJ2) {
ssize_t bytes;
@@ -1972,7 +1978,7 @@ decompress(struct archive_read *a, struct _7zip *zip,
zip->tmp_stream_bytes_avail =
zip->tmp_stream_buff_size - t_avail_out;
if (zip->tmp_stream_bytes_avail >
- zip->main_stream_bytes_remaining)
+ (uint64_t)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;
@@ -2027,7 +2033,7 @@ free_decompression(struct archive_read *a, struct _7zip *zip)
zip->stream_valid = 0;
}
#endif
-#ifdef HAVE_ZSTD_H
+#if HAVE_ZSTD_H && HAVE_LIBZSTD
if (zip->zstdstream_valid)
ZSTD_freeDStream(zip->zstd_dstream);
#endif
@@ -2040,8 +2046,21 @@ free_decompression(struct archive_read *a, struct _7zip *zip)
}
static int
-parse_7zip_uint64(struct archive_read *a, uint64_t *val)
+parse_7zip_size(struct archive_read *a, size_t *val)
{
+ int64_t v;
+
+ if (parse_7zip_int64(a, &v) < 0 || v > UMAX_ENTRY)
+ return (-1);
+
+ *val = (size_t)v;
+ return (0);
+}
+
+static int
+parse_7zip_int64(struct archive_read *a, int64_t *val)
+{
+ uint64_t v;
const unsigned char *p;
unsigned char avail, mask;
int i;
@@ -2050,18 +2069,21 @@ parse_7zip_uint64(struct archive_read *a, uint64_t *val)
return (-1);
avail = *p;
mask = 0x80;
- *val = 0;
+ v = 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);
+ v |= ((uint64_t)*p) << (8 * i);
mask >>= 1;
continue;
}
- *val += ((uint64_t)(avail & (mask -1))) << (8 * i);
+ v += ((uint64_t)(avail & (mask - 1))) << (8 * i);
break;
}
+ if (v > (uint64_t)INT64_MAX)
+ return (-1);
+ *val = (int64_t)v;
return (0);
}
@@ -2069,7 +2091,8 @@ static int
read_Bools(struct archive_read *a, unsigned char *data, size_t num)
{
const unsigned char *p;
- unsigned i, mask = 0, avail = 0;
+ size_t i;
+ unsigned mask = 0, avail = 0;
for (i = 0; i < num; i++) {
if (mask == 0) {
@@ -2078,7 +2101,7 @@ read_Bools(struct archive_read *a, unsigned char *data, size_t num)
avail = *p;
mask = 0x80;
}
- data[i] = (avail & mask)?1:0;
+ data[i] = (avail & mask) ? 1 : 0;
mask >>= 1;
}
return (0);
@@ -2095,7 +2118,7 @@ static int
read_Digests(struct archive_read *a, struct _7z_digests *d, size_t num)
{
const unsigned char *p;
- unsigned i;
+ size_t i;
if (num == 0)
return (-1);
@@ -2142,25 +2165,23 @@ static int
read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
{
const unsigned char *p;
- unsigned i;
+ size_t i;
memset(pi, 0, sizeof(*pi));
/*
* Read PackPos.
*/
- if (parse_7zip_uint64(a, &(pi->pos)) < 0)
+ if (parse_7zip_int64(a, &(pi->pos)) < 0)
return (-1);
/*
* Read NumPackStreams.
*/
- if (parse_7zip_uint64(a, &(pi->numPackStreams)) < 0)
+ if (parse_7zip_size(a, &(pi->numPackStreams)) < 0)
return (-1);
if (pi->numPackStreams == 0)
return (-1);
- if (UMAX_ENTRY < pi->numPackStreams)
- return (-1);
/*
* Read PackSizes[num]
@@ -2172,13 +2193,13 @@ read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
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));
+ pi->sizes = calloc(pi->numPackStreams, sizeof(int64_t));
+ pi->positions = calloc(pi->numPackStreams, sizeof(int64_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)
+ if (parse_7zip_int64(a, &(pi->sizes[i])) < 0)
return (-1);
}
@@ -2190,9 +2211,9 @@ read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
if (*p == kEnd) {
/* PackStreamDigests[num] are not present. */
pi->digest.defineds =
- calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.defineds));
+ calloc(pi->numPackStreams, sizeof(*pi->digest.defineds));
pi->digest.digests =
- calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.digests));
+ calloc(pi->numPackStreams, sizeof(*pi->digest.digests));
if (pi->digest.defineds == NULL || pi->digest.digests == NULL)
return (-1);
return (0);
@@ -2201,7 +2222,7 @@ read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
if (*p != kCRC)
return (-1);
- if (read_Digests(a, &(pi->digest), (size_t)pi->numPackStreams) < 0)
+ if (read_Digests(a, &(pi->digest), pi->numPackStreams) < 0)
return (-1);
/*
@@ -2217,40 +2238,39 @@ read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
static void
free_Folder(struct _7z_folder *f)
{
- unsigned i;
-
if (f->coders) {
+ size_t i;
+
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;
+ struct _7zip *zip = a->format->data;
const unsigned char *p;
- uint64_t numInStreamsTotal = 0;
- uint64_t numOutStreamsTotal = 0;
- unsigned i;
+ size_t numInStreamsTotal = 0;
+ size_t numOutStreamsTotal = 0;
+ size_t i;
memset(f, 0, sizeof(*f));
/*
* Read NumCoders.
*/
- if (parse_7zip_uint64(a, &(f->numCoders)) < 0)
+ if (parse_7zip_size(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));
+ f->coders = calloc(f->numCoders, sizeof(*f->coders));
if (f->coders == NULL)
return (-1);
for (i = 0; i< f->numCoders; i++) {
@@ -2268,7 +2288,7 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
* 7: Must be zero.
*/
codec_size = *p & 0xf;
- simple = (*p & 0x10)?0:1;
+ simple = (*p & 0x10) ? 0 : 1;
attr = *p & 0x20;
if (*p & 0x80)
return (-1);/* Not supported. */
@@ -2279,43 +2299,41 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
if ((p = header_bytes(a, codec_size)) == NULL)
return (-1);
- f->coders[i].codec = decode_codec_id(p, codec_size);
+ if (decode_codec_id(p, codec_size, &f->coders[i].codec) < 0)
+ return (-1);
if (simple) {
f->coders[i].numInStreams = 1;
f->coders[i].numOutStreams = 1;
} else {
- if (parse_7zip_uint64(
+ if (parse_7zip_size(
a, &(f->coders[i].numInStreams)) < 0)
return (-1);
- if (UMAX_ENTRY < f->coders[i].numInStreams)
- return (-1);
- if (parse_7zip_uint64(
+ if (parse_7zip_size(
a, &(f->coders[i].numOutStreams)) < 0)
return (-1);
- if (UMAX_ENTRY < f->coders[i].numOutStreams)
- return (-1);
}
if (attr) {
- if (parse_7zip_uint64(
+ if (parse_7zip_size(
a, &(f->coders[i].propertiesSize)) < 0)
return (-1);
- if (UMAX_ENTRY < f->coders[i].propertiesSize)
- return (-1);
if ((p = header_bytes(
- a, (size_t)f->coders[i].propertiesSize)) == NULL)
+ a, f->coders[i].propertiesSize)) == NULL)
return (-1);
f->coders[i].properties =
- malloc((size_t)f->coders[i].propertiesSize);
+ malloc(f->coders[i].propertiesSize);
if (f->coders[i].properties == NULL)
return (-1);
memcpy(f->coders[i].properties, p,
- (size_t)f->coders[i].propertiesSize);
+ f->coders[i].propertiesSize);
}
- numInStreamsTotal += f->coders[i].numInStreams;
- numOutStreamsTotal += f->coders[i].numOutStreams;
+ if (archive_ckd_add_size(&numInStreamsTotal,
+ numInStreamsTotal, f->coders[i].numInStreams) ||
+ archive_ckd_add_size(&numOutStreamsTotal,
+ numOutStreamsTotal, f->coders[i].numOutStreams))
+ return (-1);
}
if (numOutStreamsTotal == 0 ||
@@ -2323,34 +2341,27 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
return (-1);
f->numBindPairs = numOutStreamsTotal - 1;
- if (zip->header_bytes_remaining < f->numBindPairs)
+ if ((uint64_t)zip->header_bytes_remaining < f->numBindPairs)
return (-1);
if (f->numBindPairs > 0) {
f->bindPairs =
- calloc((size_t)f->numBindPairs, sizeof(*f->bindPairs));
+ calloc(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)
+ if (parse_7zip_size(a, &(f->bindPairs[i].inIndex)) < 0)
return (-1);
- if (UMAX_ENTRY < f->bindPairs[i].outIndex)
+ if (parse_7zip_size(a, &(f->bindPairs[i].outIndex)) < 0)
return (-1);
}
f->numPackedStreams = numInStreamsTotal - f->numBindPairs;
- f->packedStreams =
- calloc((size_t)f->numPackedStreams, sizeof(*f->packedStreams));
- if (f->packedStreams == NULL)
- return (-1);
+ /* packedStreams are not needed; parse/verify nonetheless */
if (f->numPackedStreams == 1) {
for (i = 0; i < numInStreamsTotal; i++) {
- unsigned j;
+ size_t j;
for (j = 0; j < f->numBindPairs; j++) {
if (f->bindPairs[j].inIndex == i)
break;
@@ -2360,12 +2371,10 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
}
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])
+ size_t packedStream;
+ if (parse_7zip_size(a, &packedStream) < 0)
return (-1);
}
}
@@ -2378,7 +2387,7 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
static void
free_CodersInfo(struct _7z_coders_info *ci)
{
- unsigned i;
+ size_t i;
if (ci->folders) {
for (i = 0; i < ci->numFolders; i++)
@@ -2390,9 +2399,10 @@ free_CodersInfo(struct _7z_coders_info *ci)
static int
read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
{
+ struct _7zip *zip = a->format->data;
const unsigned char *p;
struct _7z_digests digest;
- unsigned i;
+ size_t dataStreamIndex, i;
memset(ci, 0, sizeof(*ci));
memset(&digest, 0, sizeof(digest));
@@ -2405,10 +2415,16 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
/*
* Read NumFolders.
*/
- if (parse_7zip_uint64(a, &(ci->numFolders)) < 0)
+ if (parse_7zip_size(a, &(ci->numFolders)) < 0)
+ goto failed;
+ /*
+ * Each folder is encoded by at least one byte in the coders
+ * list that follows, so a folder count larger than the bytes
+ * left in the header cannot be honored and is rejected here
+ * before it is used to size the folders allocation.
+ */
+ if (ci->numFolders > (uint64_t)zip->header_bytes_remaining)
goto failed;
- if (UMAX_ENTRY < ci->numFolders)
- return (-1);
/*
* Read External.
@@ -2418,7 +2434,7 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
switch (*p) {
case 0:
ci->folders =
- calloc((size_t)ci->numFolders, sizeof(*ci->folders));
+ calloc(ci->numFolders, sizeof(*ci->folders));
if (ci->folders == NULL)
return (-1);
for (i = 0; i < ci->numFolders; i++) {
@@ -2427,9 +2443,7 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
}
break;
case 1:
- if (parse_7zip_uint64(a, &(ci->dataStreamIndex)) < 0)
- return (-1);
- if (UMAX_ENTRY < ci->dataStreamIndex)
+ if (parse_7zip_size(a, &dataStreamIndex) < 0)
return (-1);
if (ci->numFolders > 0) {
archive_set_error(&a->archive, -1,
@@ -2450,14 +2464,14 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
for (i = 0; i < ci->numFolders; i++) {
struct _7z_folder *folder = &(ci->folders[i]);
- unsigned j;
+ size_t j;
folder->unPackSize =
- calloc((size_t)folder->numOutStreams, sizeof(*folder->unPackSize));
+ calloc(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)
+ if (parse_7zip_int64(a, &(folder->unPackSize[j])) < 0)
goto failed;
}
}
@@ -2471,7 +2485,7 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
return (0);
if (*p != kCRC)
goto failed;
- if (read_Digests(a, &digest, (size_t)ci->numFolders) < 0)
+ if (read_Digests(a, &digest, ci->numFolders) < 0)
goto failed;
for (i = 0; i < ci->numFolders; i++) {
ci->folders[i].digest_defined = digest.defineds[i];
@@ -2492,16 +2506,16 @@ failed:
return (-1);
}
-static uint64_t
+static int64_t
folder_uncompressed_size(struct _7z_folder *f)
{
- int n = (int)f->numOutStreams;
- unsigned pairs = (unsigned)f->numBindPairs;
+ size_t n = f->numOutStreams;
+ size_t pairs = f->numBindPairs;
- while (--n >= 0) {
- unsigned i;
+ while (n-- > 0) {
+ size_t i;
for (i = 0; i < pairs; i++) {
- if (f->bindPairs[i].outIndex == (uint64_t)n)
+ if (f->bindPairs[i].outIndex == n)
break;
}
if (i >= pairs)
@@ -2523,11 +2537,11 @@ 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;
+ int64_t *usizes;
+ size_t numDigests;
size_t unpack_streams;
+ size_t i;
int type;
- unsigned i;
- uint32_t numDigests;
memset(ss, 0, sizeof(*ss));
@@ -2541,14 +2555,11 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
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)
+ if (parse_7zip_size(a, &(f[i].numUnpackStreams)) < 0)
return (-1);
- if (unpack_streams > SIZE_MAX - UMAX_ENTRY) {
+ if (archive_ckd_add_size(&unpack_streams,
+ unpack_streams, f[i].numUnpackStreams))
return (-1);
- }
- unpack_streams += (size_t)f[i].numUnpackStreams;
}
if ((p = header_bytes(a, 1)) == NULL)
return (-1);
@@ -2556,6 +2567,16 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
} else
unpack_streams = numFolders;
+ if (unpack_streams > UMAX_ENTRY)
+ return (-1);
+
+ if (type != kSize) {
+ for (i = 0; i < numFolders; i++) {
+ if (f[i].numUnpackStreams > 1)
+ return (-1);
+ }
+ }
+
ss->unpack_streams = unpack_streams;
if (unpack_streams) {
ss->unpackSizes = calloc(unpack_streams,
@@ -2571,8 +2592,8 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
usizes = ss->unpackSizes;
for (i = 0; i < numFolders; i++) {
- unsigned pack;
- uint64_t size, sum;
+ int64_t size, sum;
+ size_t pack;
if (f[i].numUnpackStreams == 0)
continue;
@@ -2580,11 +2601,10 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
sum = 0;
if (type == kSize) {
for (pack = 1; pack < f[i].numUnpackStreams; pack++) {
- if (parse_7zip_uint64(a, usizes) < 0)
+ if (parse_7zip_int64(a, usizes) < 0)
return (-1);
- if (*usizes > UINT64_MAX - sum)
+ if (archive_ckd_add_i64(&sum, sum, *usizes++))
return (-1);
- sum += *usizes++;
}
}
size = folder_uncompressed_size(&f[i]);
@@ -2599,22 +2619,21 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
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 (archive_ckd_add_size(&numDigests,
+ numDigests, f[i].numUnpackStreams)) {
+ errno = ENOMEM;
+ return (-1);
+ }
}
if (type == kCRC) {
struct _7z_digests tmpDigests;
unsigned char *digestsDefined = ss->digestsDefined;
- uint32_t * digests = ss->digests;
- int di = 0;
+ uint32_t *digests = ss->digests;
+ size_t di = 0;
memset(&tmpDigests, 0, sizeof(tmpDigests));
if (read_Digests(a, &(tmpDigests), numDigests) < 0) {
@@ -2626,7 +2645,7 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
*digestsDefined++ = 1;
*digests++ = f[i].digest;
} else {
- unsigned j;
+ size_t j;
for (j = 0; j < f[i].numUnpackStreams;
j++, di++) {
@@ -2662,16 +2681,16 @@ free_StreamsInfo(struct _7z_stream_info *si)
static int
read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)
{
- struct _7zip *zip = (struct _7zip *)a->format->data;
+ struct _7zip *zip = a->format->data;
const unsigned char *p;
- unsigned i;
+ size_t i;
memset(si, 0, sizeof(*si));
if ((p = header_bytes(a, 1)) == NULL)
return (-1);
if (*p == kPackInfo) {
- uint64_t packPos;
+ int64_t packPos;
if (read_PackInfo(a, &(si->pi)) < 0)
return (-1);
@@ -2684,9 +2703,9 @@ read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)
packPos = si->pi.pos;
for (i = 0; i < si->pi.numPackStreams; i++) {
si->pi.positions[i] = packPos;
- if (packPos > UINT64_MAX - si->pi.sizes[i])
+ if (archive_ckd_add_i64(&packPos,
+ packPos, si->pi.sizes[i]))
return (-1);
- packPos += si->pi.sizes[i];
if (packPos > zip->header_offset)
return (-1);
}
@@ -2694,7 +2713,7 @@ read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)
return (-1);
}
if (*p == kUnPackInfo) {
- uint32_t packIndex;
+ size_t packIndex;
struct _7z_folder *f;
if (read_CodersInfo(a, &(si->ci)) < 0)
@@ -2707,12 +2726,9 @@ read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)
f = si->ci.folders;
for (i = 0; i < si->ci.numFolders; i++) {
f[i].packIndex = packIndex;
- if (f[i].numPackedStreams > UINT32_MAX)
- return (-1);
- if (packIndex > UINT32_MAX - (uint32_t)f[i].numPackedStreams)
- return (-1);
- packIndex += (uint32_t)f[i].numPackedStreams;
- if (packIndex > si->pi.numPackStreams)
+ if (archive_ckd_add_size(&packIndex,
+ packIndex, f[i].numPackedStreams) ||
+ packIndex > si->pi.numPackStreams)
return (-1);
}
if ((p = header_bytes(a, 1)) == NULL)
@@ -2721,7 +2737,7 @@ read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)
if (*p == kSubStreamsInfo) {
if (read_SubStreamsInfo(a, &(si->ss),
- si->ci.folders, (size_t)si->ci.numFolders) < 0)
+ si->ci.folders, si->ci.numFolders) < 0)
return (-1);
if ((p = header_bytes(a, 1)) == NULL)
return (-1);
@@ -2744,18 +2760,38 @@ free_Header(struct _7z_header_info *h)
free(h->attrBools);
}
+/*
+ * Files without unpack streams must be described by the EmptyStream bitmap,
+ * which consumes one bit for every file entry in FilesInfo.
+ */
+static int
+files_info_numfiles_is_sane(const struct _7zip *zip)
+{
+ int64_t empty_stream_map_bytes;
+
+ if (zip->numFiles > SIZE_MAX / sizeof(*zip->entries))
+ return (0);
+
+ if (zip->numFiles <= zip->si.ss.unpack_streams)
+ return (1);
+
+ empty_stream_map_bytes = (zip->numFiles + 7) / 8;
+ return (empty_stream_map_bytes <= zip->header_bytes_remaining);
+}
+
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;
+ struct _7zip *zip = 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;
+ size_t folderIndex, indexInFolder;
+ size_t i;
+ size_t eindex, empty_streams, sindex;
+ int attr_seen = 0;
if (check_header_id) {
/*
@@ -2774,13 +2810,26 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
return (-1);
if (*p == kArchiveProperties) {
for (;;) {
- uint64_t size;
+ int64_t size;
if ((p = header_bytes(a, 1)) == NULL)
return (-1);
- if (*p == 0)
+ if (*p == kEnd)
break;
- if (parse_7zip_uint64(a, &size) < 0)
+ if (parse_7zip_int64(a, &size) < 0)
+ return (-1);
+ if (size < 0 || zip->header_bytes_remaining < size)
return (-1);
+
+ /* Skip the property data to keep header parsing aligned. */
+ while (size > 0) {
+ int64_t skip = size;
+
+ if (skip > UBUFF_SIZE)
+ skip = UBUFF_SIZE;
+ if (header_bytes(a, (size_t)skip) == NULL)
+ return (-1);
+ size -= skip;
+ }
}
if ((p = header_bytes(a, 1)) == NULL)
return (-1);
@@ -2804,12 +2853,12 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
if (*p != kFilesInfo)
return (-1);
- if (parse_7zip_uint64(a, &(zip->numFiles)) < 0)
+ if (parse_7zip_size(a, &(zip->numFiles)) < 0)
return (-1);
- if (UMAX_ENTRY < zip->numFiles)
+ if (!files_info_numfiles_is_sane(zip))
return (-1);
- zip->entries = calloc((size_t)zip->numFiles, sizeof(*zip->entries));
+ zip->entries = calloc(zip->numFiles, sizeof(*zip->entries));
if (zip->entries == NULL)
return (-1);
entries = zip->entries;
@@ -2817,7 +2866,7 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
empty_streams = 0;
for (;;) {
int type;
- uint64_t size;
+ int64_t size;
size_t ll;
if ((p = header_bytes(a, 1)) == NULL)
@@ -2826,9 +2875,10 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
if (type == kEnd)
break;
- if (parse_7zip_uint64(a, &size) < 0)
+ if (parse_7zip_int64(a, &size) < 0)
return (-1);
- if (zip->header_bytes_remaining < size)
+ if (zip->header_bytes_remaining < size ||
+ size > (int64_t)(SIZE_MAX / 4))
return (-1);
ll = (size_t)size;
@@ -2836,12 +2886,12 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
case kEmptyStream:
if (h->emptyStreamBools != NULL)
return (-1);
- h->emptyStreamBools = calloc((size_t)zip->numFiles,
+ h->emptyStreamBools = calloc(zip->numFiles,
sizeof(*h->emptyStreamBools));
if (h->emptyStreamBools == NULL)
return (-1);
if (read_Bools(
- a, h->emptyStreamBools, (size_t)zip->numFiles) < 0)
+ a, h->emptyStreamBools, zip->numFiles) < 0)
return (-1);
empty_streams = 0;
for (i = 0; i < zip->numFiles; i++) {
@@ -2884,7 +2934,7 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
case kCTime:
case kATime:
case kMTime:
- if (read_Times(a, h, type) < 0)
+ if (read_Times(a, type) < 0)
return (-1);
break;
case kName:
@@ -2954,21 +3004,20 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
if ((p = header_bytes(a, 2)) == NULL)
return (-1);
allAreDefined = *p;
- if (h->attrBools != NULL)
- return (-1);
- h->attrBools = calloc((size_t)zip->numFiles,
- sizeof(*h->attrBools));
- if (h->attrBools == NULL)
+ if (attr_seen)
return (-1);
- if (allAreDefined)
- memset(h->attrBools, 1, (size_t)zip->numFiles);
- else {
+ attr_seen = 1;
+ if (!allAreDefined) {
+ h->attrBools = calloc(zip->numFiles,
+ sizeof(*h->attrBools));
+ if (h->attrBools == NULL)
+ return (-1);
if (read_Bools(a, h->attrBools,
- (size_t)zip->numFiles) < 0)
+ zip->numFiles) < 0)
return (-1);
}
for (i = 0; i < zip->numFiles; i++) {
- if (h->attrBools[i]) {
+ if (allAreDefined || h->attrBools[i]) {
if ((p = header_bytes(a, 4)) == NULL)
return (-1);
entries[i].attr = archive_le32dec(p);
@@ -3021,7 +3070,7 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
}
if (entries[i].flg & HAS_STREAM) {
- if ((size_t)sindex >= si->ss.unpack_streams)
+ if (sindex >= si->ss.unpack_streams)
return (-1);
if (entries[i].mode == 0)
entries[i].mode = AE_IFREG | 0666;
@@ -3030,14 +3079,10 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
entries[i].ssIndex = sindex;
sindex++;
} else {
- int dir;
- if (h->emptyFileBools == NULL)
- dir = 1;
- else {
- if (h->emptyFileBools[eindex])
- dir = 0;
- else
- dir = 1;
+ int dir = 1;
+
+ if (h->emptyFileBools != NULL) {
+ dir = !h->emptyFileBools[eindex];
eindex++;
}
if (entries[i].mode == 0) {
@@ -3094,27 +3139,25 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
}
static int
-read_Times(struct archive_read *a, struct _7z_header_info *h, int type)
+read_Times(struct archive_read *a, int type)
{
- struct _7zip *zip = (struct _7zip *)a->format->data;
+ struct _7zip *zip = a->format->data;
const unsigned char *p;
struct _7zip_entry *entries = zip->entries;
- unsigned char *timeBools;
+ unsigned char *timeBools = NULL;
int allAreDefined;
- unsigned i;
-
- timeBools = calloc((size_t)zip->numFiles, sizeof(*timeBools));
- if (timeBools == NULL)
- return (-1);
+ size_t dataIndex, i;
/* 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)
+
+ if (!allAreDefined) {
+ timeBools = calloc(zip->numFiles, sizeof(*timeBools));
+ if (timeBools == NULL)
+ goto failed;
+ if (read_Bools(a, timeBools, zip->numFiles) < 0)
goto failed;
}
@@ -3122,14 +3165,12 @@ read_Times(struct archive_read *a, struct _7z_header_info *h, int type)
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)
+ if (parse_7zip_size(a, &dataIndex) < 0)
goto failed;
}
for (i = 0; i < zip->numFiles; i++) {
- if (!timeBools[i])
+ if (!allAreDefined && !timeBools[i])
continue;
if ((p = header_bytes(a, 8)) == NULL)
goto failed;
@@ -3165,7 +3206,8 @@ failed:
static int
decode_encoded_header_info(struct archive_read *a, struct _7z_stream_info *si)
{
- struct _7zip *zip = (struct _7zip *)a->format->data;
+ struct _7zip *zip = a->format->data;
+ int64_t pi_end;
errno = 0;
if (read_StreamsInfo(a, si) < 0) {
@@ -3183,9 +3225,12 @@ decode_encoded_header_info(struct archive_read *a, struct _7z_stream_info *si)
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) {
+ if (archive_ckd_add_i64(&pi_end, si->pi.pos, si->pi.sizes[0])) {
+ archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");
+ return (ARCHIVE_FATAL);
+ }
+
+ if (zip->header_offset < pi_end) {
archive_set_error(&a->archive, -1, "Malformed Header offset");
return (ARCHIVE_FATAL);
}
@@ -3196,10 +3241,10 @@ decode_encoded_header_info(struct archive_read *a, struct _7z_stream_info *si)
static const unsigned char *
header_bytes(struct archive_read *a, size_t rbytes)
{
- struct _7zip *zip = (struct _7zip *)a->format->data;
+ struct _7zip *zip = a->format->data;
const unsigned char *p;
- if (zip->header_bytes_remaining < rbytes)
+ if ((uint64_t)zip->header_bytes_remaining < rbytes)
return (NULL);
if (zip->pack_stream_bytes_unconsumed)
read_consume(a);
@@ -3231,26 +3276,29 @@ 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;
+ int64_t next_header_offset;
+ int64_t next_header_size;
uint32_t next_header_crc;
ssize_t bytes_avail;
+ int64_t data_offset;
int check_header_crc, r;
- if ((p = __archive_read_ahead(a, 32, &bytes_avail)) == NULL)
+ if (get_data_offset(a, &data_offset, 1) < 0)
return (ARCHIVE_FATAL);
+ if (__archive_read_consume(a, data_offset) < 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error");
+ return (ARCHIVE_FATAL);
+ }
+ if ((p = __archive_read_ahead(a, 32, &bytes_avail)) == NULL) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated 7-Zip file header");
+ return (ARCHIVE_FATAL);
+ }
- if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {
- /* This is an executable ? Must be self-extracting... */
- const ssize_t min_addr = p[0] == 'M' ? find_pe_overlay(a) :
- find_elf_data_sec(a);
- r = skip_sfx(a, min_addr);
- if (r < ARCHIVE_WARN)
- return (r);
- if ((p = __archive_read_ahead(a, 32, &bytes_avail)) == NULL)
- return (ARCHIVE_FATAL);
+ if (archive_ckd_add_i64(&zip->seek_base, data_offset, 32)) {
+ archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");
+ 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");
@@ -3258,7 +3306,7 @@ slurp_central_directory(struct archive_read *a, struct _7zip *zip,
}
/* CRC check. */
- if (crc32(0, (const unsigned char *)p + 12, 20)
+ if (crc32(0, p + 12, 20)
!= archive_le32dec(p + 8)) {
#ifndef DONT_FAIL_ON_CRC_ERROR
archive_set_error(&a->archive, -1, "Header CRC error");
@@ -3267,24 +3315,36 @@ slurp_central_directory(struct archive_read *a, struct _7zip *zip,
}
next_header_offset = archive_le64dec(p + 12);
+ if (next_header_offset < 0) {
+ archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");
+ return (ARCHIVE_FATAL);
+ }
next_header_size = archive_le64dec(p + 20);
+ if (next_header_size < 0) {
+ archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");
+ return (ARCHIVE_FATAL);
+ }
next_header_crc = archive_le32dec(p + 28);
if (next_header_size == 0)
- /* There is no entry in an archive file. */
+ /* There is no entry in the 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)
+ if (bytes_avail >= 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);
+ else {
+ int64_t target;
+
+ if (archive_ckd_add_i64(&target,
+ zip->seek_base, next_header_offset) ||
+ seek_compat(a, target, SEEK_SET, 1) < 0) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC, "Seek error");
+ return (ARCHIVE_FATAL);
+ }
+ }
}
zip->stream_offset = next_header_offset;
zip->header_offset = next_header_offset;
@@ -3395,10 +3455,10 @@ 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;
+ struct _7zip *zip = a->format->data;
ssize_t bytes_avail;
- if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {
+ if (zip->codec == _7Z_COPY && zip->codec2 == -1) {
/* Copy mode. */
*buff = __archive_read_ahead(a, minimum, &bytes_avail);
@@ -3444,14 +3504,25 @@ get_uncompressed_data(struct archive_read *a, const void **buff, size_t size,
return (bytes_avail);
}
+static size_t
+align_size(size_t s)
+{
+ size_t r;
+
+ if (archive_ckd_add_size(&r, s, 1023))
+ return (s);
+ r &= ~0x3ff;
+ return (r);
+}
+
static ssize_t
extract_pack_stream(struct archive_read *a, size_t minimum)
{
- struct _7zip *zip = (struct _7zip *)a->format->data;
+ struct _7zip *zip = a->format->data;
ssize_t bytes_avail;
int r;
- if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {
+ if (zip->codec == _7Z_COPY && zip->codec2 == -1) {
if (minimum == 0)
minimum = 1;
if (__archive_read_ahead(a, minimum, &bytes_avail) == NULL
@@ -3461,10 +3532,10 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
"Truncated 7-Zip file body");
return (ARCHIVE_FATAL);
}
- if ((uint64_t)bytes_avail > zip->pack_stream_inbytes_remaining)
+ if (bytes_avail > zip->pack_stream_inbytes_remaining)
bytes_avail = (ssize_t)zip->pack_stream_inbytes_remaining;
zip->pack_stream_inbytes_remaining -= bytes_avail;
- if ((uint64_t)bytes_avail > zip->folder_outbytes_remaining)
+ if (bytes_avail > 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;
@@ -3473,18 +3544,17 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
/* 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);
+ size_t new_size = UBUFF_SIZE;
+
+ if (new_size < minimum)
+ new_size = align_size(minimum);
+ zip->uncompressed_buffer = malloc(new_size);
if (zip->uncompressed_buffer == NULL) {
archive_set_error(&a->archive, ENOMEM,
"No memory for 7-Zip decompression");
return (ARCHIVE_FATAL);
}
+ zip->uncompressed_buffer_size = new_size;
zip->uncompressed_buffer_bytes_remaining = 0;
} else if (zip->uncompressed_buffer_size < minimum ||
zip->uncompressed_buffer_bytes_remaining < minimum) {
@@ -3505,10 +3575,8 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
* the minimum size.
*/
void *p;
- size_t new_size;
+ size_t new_size = align_size(minimum);
- new_size = minimum + 1023;
- new_size &= ~0x3ff;
p = realloc(zip->uncompressed_buffer, new_size);
if (p == NULL) {
archive_set_error(&a->archive, ENOMEM,
@@ -3554,7 +3622,7 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
bytes_out = zip->uncompressed_buffer_size
- zip->uncompressed_buffer_bytes_remaining;
bytes_in = bytes_avail;
- if (bytes_in > zip->pack_stream_inbytes_remaining)
+ if (bytes_in > (uint64_t)zip->pack_stream_inbytes_remaining)
bytes_in = (size_t)zip->pack_stream_inbytes_remaining;
/* Drive decompression. */
r = decompress(a, zip, buff_out, &bytes_out,
@@ -3570,7 +3638,7 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
return (ARCHIVE_FATAL);
}
zip->pack_stream_inbytes_remaining -= bytes_in;
- if (bytes_out > zip->folder_outbytes_remaining)
+ if (bytes_out > (uint64_t)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;
@@ -3608,10 +3676,10 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
static int
seek_pack(struct archive_read *a)
{
- struct _7zip *zip = (struct _7zip *)a->format->data;
+ struct _7zip *zip = a->format->data;
int64_t pack_offset;
- if (zip->pack_stream_remaining <= 0) {
+ if (zip->pack_stream_remaining == 0) {
archive_set_error(&(a->archive),
ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");
return (ARCHIVE_FATAL);
@@ -3620,9 +3688,14 @@ seek_pack(struct archive_read *a)
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))
+ int64_t target;
+
+ if (archive_ckd_add_i64(&target,
+ zip->seek_base, pack_offset) ||
+ 0 > seek_compat(a, target, SEEK_SET, 1)) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error");
return (ARCHIVE_FATAL);
+ }
zip->stream_offset = pack_offset;
}
zip->pack_stream_index++;
@@ -3634,8 +3707,8 @@ 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;
+ struct _7zip *zip = a->format->data;
+ int64_t skip_bytes = 0;
ssize_t r;
if (zip->uncompressed_buffer_bytes_remaining == 0) {
@@ -3688,7 +3761,7 @@ read_stream(struct archive_read *a, const void **buff, size_t size,
r = setup_decode_folder(a,
&(zip->si.ci.folders[zip->folder_index]), 0);
if (r != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
+ return (r);
zip->folder_index++;
}
@@ -3706,9 +3779,10 @@ read_stream(struct archive_read *a, const void **buff, size_t size,
return (r);
/*
- * Skip the bytes we already has skipped in skip_stream().
+ * Skip the bytes we already have skipped in skip_stream().
*/
while (1) {
+ size_t request;
ssize_t skipped;
if (zip->uncompressed_buffer_bytes_remaining == 0) {
@@ -3732,8 +3806,12 @@ read_stream(struct archive_read *a, const void **buff, size_t size,
if (!skip_bytes)
break;
- skipped = get_uncompressed_data(
- a, buff, (size_t)skip_bytes, 0);
+ if (skip_bytes > MAX_READ)
+ request = MAX_READ;
+ else
+ request = (size_t)skip_bytes;
+
+ skipped = get_uncompressed_data(a, buff, request, 0);
if (skipped < 0)
return (skipped);
skip_bytes -= skipped;
@@ -3748,10 +3826,10 @@ static int
setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
int header)
{
- struct _7zip *zip = (struct _7zip *)a->format->data;
+ struct _7zip *zip = a->format->data;
const struct _7z_coder *coder1, *coder2;
const char *cname = (header)?"archive header":"file content";
- unsigned i;
+ size_t i;
int r, found_bcj2 = 0;
/*
@@ -3763,15 +3841,9 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
}
/*
- * 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.
+ * Check coder types before modifying any stream-reader state, so that
+ * an early return leaves zip unchanged (avoids partially-initialized
+ * state that callers would have to reason about).
*/
for (i = 0; i < folder->numCoders; i++) {
switch(folder->coders[i].codec) {
@@ -3789,7 +3861,7 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
ARCHIVE_ERRNO_MISC,
"The %s is encrypted, "
"but currently not supported", cname);
- return (ARCHIVE_FATAL);
+ return (header ? ARCHIVE_FATAL : ARCHIVE_FAILED);
}
case _7Z_X86_BCJ2: {
found_bcj2++;
@@ -3809,8 +3881,16 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
ARCHIVE_ERRNO_MISC,
"The %s is encoded with many filters, "
"but currently not supported", cname);
- return (ARCHIVE_FATAL);
+ return (header ? ARCHIVE_FATAL : ARCHIVE_FAILED);
}
+
+ /*
+ * Initialize a stream reader.
+ */
+ zip->pack_stream_remaining = folder->numPackedStreams;
+ zip->pack_stream_index = folder->packIndex;
+ zip->folder_outbytes_remaining = folder_uncompressed_size(folder);
+ zip->uncompressed_buffer_bytes_remaining = 0;
coder1 = &(folder->coders[0]);
if (folder->numCoders == 2)
coder2 = &(folder->coders[1]);
@@ -3830,7 +3910,8 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
const void *buff;
ssize_t bytes;
unsigned char *b[3] = {NULL, NULL, NULL};
- uint64_t sunpack[3] ={-1, -1, -1};
+ int64_t sunpack[3] ={-1, -1, -1};
+ int64_t remaining;
size_t s[3] = {0, 0, 0};
int idx[3] = {0, 1, 2};
@@ -3883,14 +3964,12 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
}
}
coder2 = &(fc[3]);
- zip->main_stream_bytes_remaining =
- (size_t)folder->unPackSize[2];
+ remaining = 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];
+ remaining = folder->unPackSize[0];
} else {
/* We got an unexpected form. */
archive_set_error(&(a->archive),
@@ -3898,13 +3977,16 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
"Unsupported form of BCJ2 streams");
return (ARCHIVE_FATAL);
}
+ zip->main_stream_bytes_remaining = remaining;
+
/* 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);
+ zip->pack_stream_inbytes_remaining;
+ if ((r = read_consume(a)) < 0)
+ return (r);
/* Read following three sub streams. */
for (i = 0; i < 3; i++) {
@@ -3915,7 +3997,7 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
return (r);
}
- if (sunpack[i] == (uint64_t)-1)
+ if (sunpack[i] == -1)
zip->folder_outbytes_remaining =
zip->pack_stream_inbytes_remaining;
else
@@ -3929,6 +4011,14 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
/* Allocate memory for the decoded data of a sub
* stream. */
+ if ((uint64_t)zip->folder_outbytes_remaining > SIZE_MAX) {
+ free(b[0]); free(b[1]); free(b[2]);
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "7-Zip sub-stream size exceeds "
+ "platform maximum");
+ return (ARCHIVE_FATAL);
+ }
b[i] = malloc((size_t)zip->folder_outbytes_remaining);
if (b[i] == NULL) {
free(b[0]); free(b[1]); free(b[2]);
@@ -3986,7 +4076,7 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
* of BCJ2.
*/
zip->pack_stream_remaining = 1;
- zip->pack_stream_index = (unsigned)folder->packIndex;
+ zip->pack_stream_index = folder->packIndex;
zip->folder_outbytes_remaining =
folder_uncompressed_size(folder);
zip->uncompressed_buffer_bytes_remaining = 0;
@@ -4001,26 +4091,40 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
return (ARCHIVE_OK);
}
-static int64_t
-skip_stream(struct archive_read *a, size_t skip_bytes)
+static int
+skip_stream(struct archive_read *a, int64_t skip_bytes)
{
- struct _7zip *zip = (struct _7zip *)a->format->data;
+ struct _7zip *zip = a->format->data;
const void *p;
int64_t skipped_bytes;
- size_t bytes = skip_bytes;
+ int64_t bytes = skip_bytes;
if (zip->folder_index == 0) {
+ int64_t *v;
+
/*
* Optimization for a list mode.
* Avoid unnecessary decoding operations.
*/
- zip->si.ci.folders[zip->entry->folderIndex].skipped_bytes
- += skip_bytes;
- return (skip_bytes);
+ v = &zip->si.ci.folders[zip->entry->folderIndex].skipped_bytes;
+ if (archive_ckd_add_i64(v, *v, skip_bytes)) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Too many bytes to skip");
+ return (ARCHIVE_FATAL);
+ }
+ return (ARCHIVE_OK);
}
while (bytes) {
- skipped_bytes = read_stream(a, &p, bytes, 0);
+ size_t request;
+
+ if (bytes > MAX_READ)
+ request = MAX_READ;
+ else
+ request = (size_t)bytes;
+
+ skipped_bytes = read_stream(a, &p, request, 0);
if (skipped_bytes < 0)
return (skipped_bytes);
if (skipped_bytes == 0) {
@@ -4029,11 +4133,11 @@ skip_stream(struct archive_read *a, size_t skip_bytes)
"Truncated 7-Zip file body");
return (ARCHIVE_FATAL);
}
- bytes -= (size_t)skipped_bytes;
+ bytes -= skipped_bytes;
if (zip->pack_stream_bytes_unconsumed)
read_consume(a);
}
- return (skip_bytes);
+ return (ARCHIVE_OK);
}
/*
@@ -4082,7 +4186,7 @@ x86_Convert(struct _7zip *zip, uint8_t *data, size_t size)
if (p >= limit)
break;
prevPosT = bufferPos - prevPosT;
- if (prevPosT > 3)
+ if (prevPosT == 0 || prevPosT > 3)
prevMask = 0;
else {
prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7;
@@ -4101,9 +4205,7 @@ x86_Convert(struct _7zip *zip, uint8_t *data, size_t size)
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 src = archive_le32dec(p + 1);
uint32_t dest;
for (;;) {
uint8_t b;
@@ -4163,16 +4265,13 @@ arm_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
for (i = 0; i + 4 <= size; i += 4) {
if (buf[i + 3] == 0xEB) {
// Calculate the transformed addr.
- addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8)
- | ((uint32_t)buf[i + 2] << 16);
+ addr = archive_le24dec(buf + i);
addr <<= 2;
addr -= zip->bcj_ip + (uint32_t)i;
addr >>= 2;
// Store the transformed addr in buf.
- buf[i] = (uint8_t)addr;
- buf[i + 1] = (uint8_t)(addr >> 8);
- buf[i + 2] = (uint8_t)(addr >> 16);
+ archive_le24enc(buf + i, addr);
}
}
@@ -4203,20 +4302,14 @@ arm64_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
uint32_t addr;
for (i = 0; i + 4 <= size; i += 4) {
- instr = (uint32_t)buf[i]
- | ((uint32_t)buf[i+1] << 8)
- | ((uint32_t)buf[i+2] << 16)
- | ((uint32_t)buf[i+3] << 24);
+ instr = archive_le32dec(buf + i);
if ((instr >> 26) == 0x25) {
/* BL instruction */
addr = instr - ((zip->bcj_ip + (uint32_t)i) >> 2);
instr = 0x94000000 | (addr & 0x03FFFFFF);
- buf[i] = (uint8_t)instr;
- buf[i+1] = (uint8_t)(instr >> 8);
- buf[i+2] = (uint8_t)(instr >> 16);
- buf[i+3] = (uint8_t)(instr >> 24);
+ archive_le32enc(buf + i, instr);
} else if ((instr & 0x9F000000) == 0x90000000) {
/* ADRP instruction */
addr = ((instr >> 29) & 3) | ((instr >> 3) & 0x1FFFFC);
@@ -4232,10 +4325,7 @@ arm64_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
instr |= (addr & 0x03FFFC) << 3;
instr |= (0U - (addr & 0x020000)) & 0xE00000;
- buf[i] = (uint8_t)instr;
- buf[i+1] = (uint8_t)(instr >> 8);
- buf[i+2] = (uint8_t)(instr >> 16);
- buf[i+3] = (uint8_t)(instr >> 24);
+ archive_le32enc(buf + i, instr);
}
}
@@ -4278,10 +4368,7 @@ sparc_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
size &= ~(size_t)3;
for (i = 0; i < size; i += 4) {
- instr = (uint32_t)(buf[i] << 24)
- | ((uint32_t)buf[i+1] << 16)
- | ((uint32_t)buf[i+2] << 8)
- | (uint32_t)buf[i+3];
+ instr = archive_be32dec(buf + i);
if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) {
instr <<= 2;
@@ -4290,10 +4377,7 @@ sparc_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
instr = ((uint32_t)0x40000000 - (instr & 0x400000))
| 0x40000000 | (instr & 0x3FFFFF);
- buf[i] = (uint8_t)(instr >> 24);
- buf[i+1] = (uint8_t)(instr >> 16);
- buf[i+2] = (uint8_t)(instr >> 8);
- buf[i+3] = (uint8_t)instr;
+ archive_be32enc(buf + i, instr);
}
}
@@ -4406,7 +4490,7 @@ Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize)
const uint8_t *buf0, *buf1, *buf2, *buf3;
size_t size0, size1, size2, size3;
const uint8_t *buffer, *bufferLim;
- unsigned int i, j;
+ size_t i, j;
size0 = zip->tmp_stream_bytes_remaining;
buf0 = zip->tmp_stream_buff + zip->tmp_stream_bytes_avail - size0;
@@ -4504,15 +4588,10 @@ Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize)
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);
+ dest = archive_be32dec(v) -
+ (zip->bcj2_outPos + outPos + 4);
+ archive_le32enc(out, dest);
+ zip->bcj2_prevByte = out[3];
for (i = 0; i < 4 && outPos < outSize; i++)
outBuf[outPos++] = out[i];
@@ -4521,7 +4600,7 @@ Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize)
* Save odd bytes which we could not add into
* the output buffer because of out of space.
*/
- zip->odd_bcj_size = 4 -i;
+ zip->odd_bcj_size = 4 - i;
for (; i < 4; i++) {
j = i - 4 + (unsigned)zip->odd_bcj_size;
zip->odd_bcj[j] = out[i];
@@ -4538,3 +4617,34 @@ Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize)
return ((ssize_t)outPos);
}
+
+/*
+ * Perform a seek to given position. If seeking is not supported,
+ * target position is in front of current position, and compat is requested,
+ * try to consume bytes until position is reached.
+ */
+int64_t
+seek_compat(struct archive_read *a, int64_t offset, int whence, int compat)
+{
+ int64_t ret = ARCHIVE_FAILED;
+
+ if (a->filter->can_seek)
+ ret = __archive_read_seek(a, offset, whence);
+ else if (compat) {
+ switch (whence) {
+ case SEEK_CUR:
+ ret = __archive_read_consume(a, offset);
+ break;
+ case SEEK_SET:
+ if (a->filter->position > offset)
+ break;
+ ret = __archive_read_consume(a,
+ offset - a->filter->position);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return (ret);
+}
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_all.c b/contrib/libarchive/libarchive/archive_read_support_format_all.c
index 3b53c9ad5f57..a2c5a4c6f540 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_all.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_all.c
@@ -80,7 +80,7 @@ archive_read_support_format_all(struct archive *a)
/* Note: We always return ARCHIVE_OK here, even if some of the
* above return ARCHIVE_WARN. The intent here is to enable
* "as much as possible." Clients who need specific
- * compression should enable those individually so they can
+ * formats should enable those individually so they can
* verify the level of support. */
/* Clear any warning messages set by the above functions. */
archive_clear_error(a);
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_ar.c b/contrib/libarchive/libarchive/archive_read_support_format_ar.c
index 6dfe2939d090..8585de28fd14 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_ar.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_ar.c
@@ -45,6 +45,7 @@
#include "archive.h"
#include "archive_entry.h"
+#include "archive_integer.h"
#include "archive_private.h"
#include "archive_read_private.h"
@@ -54,7 +55,7 @@ struct ar {
* but haven't yet marked as consumed. Must be paired with
* entry_bytes_remaining usage/modification.
*/
- size_t entry_bytes_unconsumed;
+ int64_t entry_bytes_unconsumed;
int64_t entry_offset;
int64_t entry_padding;
char *strtab;
@@ -80,18 +81,18 @@ struct ar {
#define AR_fmag_offset 58
#define AR_fmag_size 2
-static int archive_read_format_ar_bid(struct archive_read *a, int);
-static int archive_read_format_ar_cleanup(struct archive_read *a);
-static int archive_read_format_ar_read_data(struct archive_read *a,
- const void **buff, size_t *size, int64_t *offset);
-static int archive_read_format_ar_skip(struct archive_read *a);
-static int archive_read_format_ar_read_header(struct archive_read *a,
- struct archive_entry *e);
-static uint64_t ar_atol8(const char *p, unsigned char_cnt);
-static uint64_t ar_atol10(const char *p, unsigned char_cnt);
-static int ar_parse_gnu_filename_table(struct archive_read *a);
-static int ar_parse_common_header(struct ar *ar, struct archive_entry *,
- const char *h);
+static int archive_read_format_ar_bid(struct archive_read *, int);
+static int archive_read_format_ar_cleanup(struct archive_read *);
+static int archive_read_format_ar_read_data(struct archive_read *,
+ const void **, size_t *, int64_t *);
+static int archive_read_format_ar_skip(struct archive_read *);
+static int archive_read_format_ar_read_header(struct archive_read *,
+ struct archive_entry *);
+static uint64_t ar_atol8(const char *, size_t);
+static uint64_t ar_atol10(const char *, size_t);
+static int ar_parse_gnu_filename_table(struct archive_read *);
+static void ar_parse_common_header(struct ar *, struct archive_entry *,
+ const char *);
int
archive_read_support_format_ar(struct archive *_a)
@@ -134,12 +135,12 @@ archive_read_support_format_ar(struct archive *_a)
static int
archive_read_format_ar_cleanup(struct archive_read *a)
{
- struct ar *ar;
+ struct ar *ar = a->format->data;
- ar = (struct ar *)(a->format->data);
free(ar->strtab);
free(ar);
- (a->format->data) = NULL;
+ a->format->data = NULL;
+
return (ARCHIVE_OK);
}
@@ -164,14 +165,12 @@ archive_read_format_ar_bid(struct archive_read *a, int best_bid)
static int
_ar_read_header(struct archive_read *a, struct archive_entry *entry,
- struct ar *ar, const char *h, size_t *unconsumed)
+ struct ar *ar, const char *h, int64_t *unconsumed)
{
char filename[AR_name_size + 1];
uint64_t number; /* Used to hold parsed numbers before validation. */
- size_t bsd_name_length, entry_size;
- char *p, *st;
+ char *p;
const void *b;
- int r;
/* Verify the magic signature on the file header. */
if (strncmp(h + AR_fmag_offset, "`\n", 2) != 0) {
@@ -247,14 +246,20 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
}
/*
+ * Parse the time, owner, mode, size fields.
+ * This must come before any call to _read_ahead.
+ */
+ ar_parse_common_header(ar, entry, h);
+
+ /*
* '//' is the GNU filename table.
* Later entries can refer to names in this table.
*/
if (strcmp(filename, "//") == 0) {
- /* This must come before any call to _read_ahead. */
- ar_parse_common_header(ar, entry, h);
+ char *st;
+ size_t entry_size;
+
archive_entry_copy_pathname(entry, filename);
- archive_entry_set_filetype(entry, AE_IFREG);
/* Get the size of the filename table. */
number = ar_atol10(h + AR_size_offset, AR_size_size);
if (number > SIZE_MAX || number > 1024 * 1024 * 1024) {
@@ -309,22 +314,15 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
*/
if (filename[0] == '/' && filename[1] >= '0' && filename[1] <= '9') {
number = ar_atol10(h + AR_name_offset + 1, AR_name_size - 1);
- /*
- * If we can't look up the real name, warn and return
- * the entry with the wrong name.
- */
+ /* Fail if we can't look up the real name. */
if (ar->strtab == NULL || number >= ar->strtab_size) {
archive_set_error(&a->archive, EINVAL,
"Can't find long filename for GNU/SVR4 archive entry");
- archive_entry_copy_pathname(entry, filename);
- /* Parse the time, owner, mode, size fields. */
- ar_parse_common_header(ar, entry, h);
return (ARCHIVE_FATAL);
}
archive_entry_copy_pathname(entry, &ar->strtab[(size_t)number]);
- /* Parse the time, owner, mode, size fields. */
- return (ar_parse_common_header(ar, entry, h));
+ return (ARCHIVE_OK);
}
/*
@@ -333,9 +331,7 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
* the filename to the file contents.
*/
if (strncmp(filename, "#1/", 3) == 0) {
- /* Parse the time, owner, mode, size fields. */
- /* This must occur before _read_ahead is called again. */
- ar_parse_common_header(ar, entry, h);
+ size_t bsd_name_length;
/* Parse the size of the name, adjust the file size. */
number = ar_atol10(h + AR_name_offset + 3, AR_name_size - 3);
@@ -346,7 +342,7 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
*/
if (number > SIZE_MAX - 1
|| number > 1024 * 1024
- || (int64_t)number > ar->entry_bytes_remaining) {
+ || number > (uint64_t)ar->entry_bytes_remaining) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Bad input file size");
return (ARCHIVE_FATAL);
@@ -385,49 +381,33 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
}
/*
- * "/" is the SVR4/GNU archive symbol table.
- * "/SYM64/" is the SVR4/GNU 64-bit variant archive symbol table.
- */
- if (strcmp(filename, "/") == 0 || strcmp(filename, "/SYM64/") == 0) {
- archive_entry_copy_pathname(entry, filename);
- /* Parse the time, owner, mode, size fields. */
- r = ar_parse_common_header(ar, entry, h);
- /* Force the file type to a regular file. */
- archive_entry_set_filetype(entry, AE_IFREG);
- return (r);
- }
-
- /*
- * "__.SYMDEF" is a BSD archive symbol table.
- */
- if (strcmp(filename, "__.SYMDEF") == 0) {
- archive_entry_copy_pathname(entry, filename);
- /* Parse the time, owner, mode, size fields. */
- return (ar_parse_common_header(ar, entry, h));
- }
-
- /*
* Otherwise, this is a standard entry. The filename
* has already been trimmed as much as possible, based
* on our current knowledge of the format.
+ *
+ * Note for future implementations:
+ *
+ * - "/" is the SVR4/GNU archive symbol table.
+ * - "/SYM64/" is the SVR4/GNU 64-bit variant archive symbol table.
+ * - "__.SYMDEF" is a BSD archive symbol table.
*/
archive_entry_copy_pathname(entry, filename);
- return (ar_parse_common_header(ar, entry, h));
+ return (ARCHIVE_OK);
}
static int
archive_read_format_ar_read_header(struct archive_read *a,
struct archive_entry *entry)
{
- struct ar *ar = (struct ar*)(a->format->data);
- size_t unconsumed;
+ struct ar *ar = a->format->data;
+ int64_t unconsumed;
const void *header_data;
int ret;
if (!ar->read_global_header) {
/*
- * We are now at the beginning of the archive,
- * so we need first consume the ar global header.
+ * We are at the beginning of the archive now,
+ * so we have to consume the ar global header first.
*/
__archive_read_consume(a, 8);
ar->read_global_header = 1;
@@ -451,11 +431,11 @@ archive_read_format_ar_read_header(struct archive_read *a,
}
-static int
+static void
ar_parse_common_header(struct ar *ar, struct archive_entry *entry,
const char *h)
{
- uint64_t n;
+ int64_t n;
/* Copy remaining header */
archive_entry_set_mtime(entry,
@@ -467,23 +447,20 @@ ar_parse_common_header(struct ar *ar, struct archive_entry *entry,
archive_entry_set_mode(entry,
(mode_t)ar_atol8(h + AR_mode_offset, AR_mode_size));
archive_entry_set_filetype(entry, AE_IFREG);
- n = ar_atol10(h + AR_size_offset, AR_size_size);
+ n = (int64_t)ar_atol10(h + AR_size_offset, AR_size_size);
ar->entry_offset = 0;
ar->entry_padding = n % 2;
archive_entry_set_size(entry, n);
ar->entry_bytes_remaining = n;
- return (ARCHIVE_OK);
}
static int
archive_read_format_ar_read_data(struct archive_read *a,
const void **buff, size_t *size, int64_t *offset)
{
+ struct ar *ar = a->format->data;
ssize_t bytes_read;
- struct ar *ar;
-
- ar = (struct ar *)(a->format->data);
if (ar->entry_bytes_unconsumed) {
__archive_read_consume(a, ar->entry_bytes_unconsumed);
@@ -508,17 +485,9 @@ archive_read_format_ar_read_data(struct archive_read *a,
ar->entry_bytes_remaining -= bytes_read;
return (ARCHIVE_OK);
} else {
- int64_t skipped = __archive_read_consume(a, ar->entry_padding);
- if (skipped >= 0) {
- ar->entry_padding -= skipped;
- }
- if (ar->entry_padding) {
- if (skipped >= 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Truncated ar archive - failed consuming padding");
- }
+ if (__archive_read_consume(a, ar->entry_padding) < 0)
return (ARCHIVE_FATAL);
- }
+ ar->entry_padding = 0;
*buff = NULL;
*size = 0;
*offset = ar->entry_offset;
@@ -529,15 +498,11 @@ archive_read_format_ar_read_data(struct archive_read *a,
static int
archive_read_format_ar_skip(struct archive_read *a)
{
- int64_t bytes_skipped;
- struct ar* ar;
-
- ar = (struct ar *)(a->format->data);
+ struct ar *ar = a->format->data;
- bytes_skipped = __archive_read_consume(a,
- ar->entry_bytes_remaining + ar->entry_padding
- + ar->entry_bytes_unconsumed);
- if (bytes_skipped < 0)
+ if (__archive_read_consume(a,
+ ar->entry_bytes_remaining + ar->entry_padding +
+ ar->entry_bytes_unconsumed) < 0)
return (ARCHIVE_FATAL);
ar->entry_bytes_remaining = 0;
@@ -550,11 +515,10 @@ archive_read_format_ar_skip(struct archive_read *a)
static int
ar_parse_gnu_filename_table(struct archive_read *a)
{
- struct ar *ar;
+ struct ar *ar = a->format->data;
char *p;
size_t size;
- ar = (struct ar*)(a->format->data);
size = ar->strtab_size;
for (p = ar->strtab; p < ar->strtab + size - 1; ++p) {
@@ -586,51 +550,47 @@ bad_string_table:
}
static uint64_t
-ar_atol8(const char *p, unsigned char_cnt)
+ar_atol8(const char *p, size_t char_cnt)
{
- uint64_t l, limit, last_digit_limit;
+ uint64_t l;
unsigned int digit, base;
base = 8;
- limit = UINT64_MAX / base;
- last_digit_limit = UINT64_MAX % base;
while ((*p == ' ' || *p == '\t') && char_cnt-- > 0)
p++;
l = 0;
digit = *p - '0';
- while (*p >= '0' && digit < base && char_cnt-- > 0) {
- if (l>limit || (l == limit && digit > last_digit_limit)) {
+ while (*p >= '0' && digit < base && char_cnt-- > 0) {
+ if (archive_ckd_mul_u64(&l, l, base) ||
+ archive_ckd_add_u64(&l, l, digit)) {
l = UINT64_MAX; /* Truncate on overflow. */
break;
}
- l = (l * base) + digit;
digit = *++p - '0';
}
return (l);
}
static uint64_t
-ar_atol10(const char *p, unsigned char_cnt)
+ar_atol10(const char *p, size_t char_cnt)
{
- uint64_t l, limit, last_digit_limit;
+ uint64_t l;
unsigned int base, digit;
base = 10;
- limit = UINT64_MAX / base;
- last_digit_limit = UINT64_MAX % base;
while ((*p == ' ' || *p == '\t') && char_cnt-- > 0)
p++;
l = 0;
digit = *p - '0';
while (*p >= '0' && digit < base && char_cnt-- > 0) {
- if (l > limit || (l == limit && digit > last_digit_limit)) {
+ if (archive_ckd_mul_u64(&l, l, base) ||
+ archive_ckd_add_u64(&l, l, digit)) {
l = UINT64_MAX; /* Truncate on overflow. */
break;
}
- l = (l * base) + digit;
digit = *++p - '0';
}
return (l);
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_cab.c b/contrib/libarchive/libarchive/archive_read_support_format_cab.c
index bf8ac6b1ca77..f90250e1952e 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_cab.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_cab.c
@@ -49,85 +49,186 @@
#include "archive_endian.h"
+/*
+ * Huffman coding.
+ *
+ * Array representation of a Huffman tree for codes of up to 16 bit lengths.
+ * Lookups are performed through a direct, expanded lookup table.
+ *
+ * An expanded table has as many elements as needed to cover all possible
+ * indices formable with bit patterns of given lookup_bits length.
+ *
+ * If less codes exist, these span multiple entries for all possible
+ * combinations of following bits.
+ *
+ * Example of a Huffman tree with len_size = 3, lookup_bits = 2:
+ *
+ * Symbol | Code
+ * -------+-----
+ * A | 0b0
+ * B | 0b10
+ * C | 0b11
+ *
+ * The bit sequences 0b00 and 0b01 are rightfully not covered by a code,
+ * since code 0b0 already maps to symbol A. The table will contain two
+ * entries for symbol A instead:
+ *
+ * idx | tbl[idx]
+ * -----+---------
+ * 0b00 | A
+ * 0b01 | A
+ * 0b10 | B
+ * 0b11 | C
+ *
+ * By using lookup_bits bits as a lookup, it becomes apparent that 0b00 and
+ * 0b01 point to a symbol which actually has the code 0b0. A user of this
+ * data structure must check the code bit length of a retrieved symbol after
+ * the lookup to properly advance the bit stream:
+ *
+ * idx | bitlen[idx]
+ * ----+------------
+ * A | 1
+ * B | 2
+ * C | 2
+ *
+ * Thus, a proper code sequence would be:
+ *
+ * symbol = tbl[read_bits(lookup_bits)]
+ * consume_bits(bitlen[symbol])
+ */
+struct huffman {
+ /*
+ * Amount of symbols.
+ *
+ * This implementation keeps track of unused symbols as well,
+ * thus symbols start with 0x0000 up to given symbol amount:
+ * [0..symbol_count)
+ *
+ * Used to construct tbl.
+ */
+ uint16_t symbol_count;
+ /*
+ * Frequency of code bit lengths.
+ *
+ * Represents the amount of occurrences of given bit lengths.
+ * Index 0 is used for "empty" codes (aka unused symbols),
+ * otherwise index represents the bit length
+ * (index 1 is bit length 1 and so on).
+ *
+ * Used to construct tbl.
+ */
+ uint16_t freq[17];
+ /* Map of symbols to their code bit lengths. */
+ uint8_t *bitlen;
+ /* Amount of bits to use for lookup (<= tbl_bits). */
+ uint8_t lookup_bits;
+ /*
+ * Code bit length used for allocation (<= 16).
+ *
+ * Used to construct tbl.
+ */
+ uint8_t tbl_bits;
+ /* Direct, expanded lookup table. */
+ uint16_t *tbl;
+};
+
+/*
+ * Bit stream reader.
+ */
+struct lzx_br {
+#define CACHE_TYPE uint64_t
+#define CACHE_BITS (8 * sizeof(CACHE_TYPE))
+ /* Cache buffer. */
+ CACHE_TYPE cache_buffer;
+ /* Indicates how many bits avail in cache_buffer. */
+ size_t cache_avail;
+ uint8_t odd;
+ int have_odd;
+};
+
+struct lzx_pos_tbl {
+ uint32_t base;
+ uint8_t footer_bits;
+};
+
struct lzx_dec {
/* Decoding status. */
int state;
+#define ST_RD_TRANSLATION 0
+#define ST_RD_TRANSLATION_SIZE 1
+#define ST_RD_BLOCK_TYPE 2
+#define ST_RD_BLOCK_SIZE 3
+#define ST_RD_ALIGNMENT 4
+#define ST_RD_R0 5
+#define ST_RD_R1 6
+#define ST_RD_R2 7
+#define ST_COPY_UNCOMP1 8
+#define ST_COPY_UNCOMP2 9
+#define ST_RD_ALIGNED_OFFSET 10
+#define ST_RD_VERBATIM 11
+#define ST_RD_PRE_MAIN_TREE_256 12
+#define ST_MAIN_TREE_256 13
+#define ST_RD_PRE_MAIN_TREE_REM 14
+#define ST_MAIN_TREE_REM 15
+#define ST_RD_PRE_LENGTH_TREE 16
+#define ST_LENGTH_TREE 17
+#define ST_MAIN 18
+#define ST_LENGTH 19
+#define ST_OFFSET 20
+#define ST_REAL_POS 21
+#define ST_COPY 22
/*
- * Window to see last decoded data, from 32KBi to 2MBi.
+ * Window to see last decoded data, from 32 KiB to 2 MiB.
*/
- int w_size;
- int w_mask;
+ size_t w_size;
+ size_t w_mask;
/* Window buffer, which is a loop buffer. */
- unsigned char *w_buff;
+ uint8_t *w_buff;
/* The insert position to the window. */
- int w_pos;
+ size_t w_pos;
/* The position where we can copy decoded code from the window. */
- int copy_pos;
+ size_t copy_pos;
/* The length how many bytes we can copy decoded code from
* the window. */
- int copy_len;
+ size_t copy_len;
/* Translation reversal for x86 processor CALL byte sequence(E8).
* This is used for LZX only. */
- uint32_t translation_size;
- char translation;
- char block_type;
+ int32_t translation_size;
+ int translation;
+ uint8_t block_type;
#define VERBATIM_BLOCK 1
#define ALIGNED_OFFSET_BLOCK 2
#define UNCOMPRESSED_BLOCK 3
size_t block_size;
size_t block_bytes_avail;
/* Repeated offset. */
- int r0, r1, r2;
- unsigned char rbytes[4];
- int rbytes_avail;
- int length_header;
- int position_slot;
- int offset_bits;
+ size_t r0, r1, r2;
+ uint8_t rbytes[4];
+ size_t rbytes_avail;
+ uint8_t length_header;
+ uint16_t position_slot;
+ uint8_t offset_bits;
- struct lzx_pos_tbl {
- int base;
- int footer_bits;
- } *pos_tbl;
+ struct lzx_pos_tbl *pos_tbl;
/*
* Bit stream reader.
*/
- struct lzx_br {
-#define CACHE_TYPE uint64_t
-#define CACHE_BITS (8 * sizeof(CACHE_TYPE))
- /* Cache buffer. */
- CACHE_TYPE cache_buffer;
- /* Indicates how many bits avail in cache_buffer. */
- int cache_avail;
- unsigned char odd;
- char have_odd;
- } br;
+ struct lzx_br br;
/*
* Huffman coding.
*/
- struct huffman {
- int len_size;
- int freq[17];
- unsigned char *bitlen;
-
- /*
- * Use a index table. It's faster than searching a huffman
- * coding tree, which is a binary tree. But a use of a large
- * index table causes L1 cache read miss many times.
- */
- int max_bits;
- int tbl_bits;
- int tree_used;
- /* Direct access table. */
- uint16_t *tbl;
- } at, lt, mt, pt;
+ struct huffman at;
+ struct huffman lt;
+ struct huffman mt;
+ struct huffman pt;
- int loop;
+ uint16_t loop;
int error;
};
-static const int slots[] = {
+static const size_t slots[] = {
30, 32, 34, 36, 38, 42, 50, 66, 98, 162, 290
};
#define SLOT_BASE 15
@@ -135,11 +236,11 @@ static const int slots[] = {
struct lzx_stream {
const unsigned char *next_in;
- int64_t avail_in;
- int64_t total_in;
+ size_t avail_in;
+ size_t total_in;
unsigned char *next_out;
- int64_t avail_out;
- int64_t total_out;
+ size_t avail_out;
+ size_t total_out;
struct lzx_dec *ds;
};
@@ -179,6 +280,11 @@ struct lzx_stream {
#define CFDATA_cbData 4
#define CFDATA_cbUncomp 6
+/* Limits */
+#define MAX_UNCOMPRESS_SIZE 0x8000
+#define MAX_FILE_SIZE (UINT16_MAX * MAX_UNCOMPRESS_SIZE)
+#define MAX_E8_TRANSLATION (0x8000 * MAX_UNCOMPRESS_SIZE)
+
static const char * const compression_name[] = {
"NONE",
"MSZIP",
@@ -240,8 +346,6 @@ struct cffile {
};
struct cfheader {
- /* Total bytes of all file size in a Cabinet. */
- uint32_t total_bytes;
uint32_t files_offset;
uint16_t folder_count;
uint16_t file_count;
@@ -249,7 +353,6 @@ struct cfheader {
#define PREV_CABINET 0x0001
#define NEXT_CABINET 0x0002
#define RESERVE_PRESENT 0x0004
- uint16_t setid;
uint16_t cabinet;
/* Version number. */
unsigned char major;
@@ -264,12 +367,10 @@ struct cfheader {
};
struct cab {
- /* entry_bytes_remaining is the number of bytes we expect. */
+ /* entry_bytes_remaining is the number of bytes we expect. */
int64_t entry_offset;
int64_t entry_bytes_remaining;
int64_t entry_unconsumed;
- int64_t entry_compressed_bytes_read;
- int64_t entry_uncompressed_bytes_read;
struct cffolder *entry_cffolder;
struct cffile *entry_cffile;
struct cfdata *entry_cfdata;
@@ -279,7 +380,7 @@ struct cab {
struct cfheader cfheader;
struct archive_wstring ws;
- /* Flag to mark progress that an archive was read their first header.*/
+ /* Flag to mark progress that first header of an archive was read.*/
char found_header;
char end_of_archive;
char end_of_entry;
@@ -314,7 +415,7 @@ static int archive_read_format_cab_read_data_skip(struct archive_read *);
static int archive_read_format_cab_cleanup(struct archive_read *);
static int cab_skip_sfx(struct archive_read *);
-static time_t cab_dos_time(const unsigned char *);
+static time_t cab_dos_time(const char *);
static int cab_read_data(struct archive_read *, const void **,
size_t *, int64_t *);
static int cab_read_header(struct archive_read *);
@@ -335,15 +436,15 @@ static int lzx_decode_init(struct lzx_stream *, int);
static int lzx_read_blocks(struct lzx_stream *, int);
static int lzx_decode_blocks(struct lzx_stream *, int);
static void lzx_decode_free(struct lzx_stream *);
-static void lzx_translation(struct lzx_stream *, void *, size_t, uint32_t);
+static void lzx_translation(struct lzx_stream *, unsigned char *, size_t, int32_t);
static void lzx_cleanup_bitstream(struct lzx_stream *);
static int lzx_decode(struct lzx_stream *, int);
static int lzx_read_pre_tree(struct lzx_stream *);
-static int lzx_read_bitlen(struct lzx_stream *, struct huffman *, int);
-static int lzx_huffman_init(struct huffman *, size_t, int);
+static int lzx_read_bitlen(struct lzx_stream *, struct huffman *, uint16_t);
+static int lzx_huffman_init(struct huffman *, uint16_t, uint8_t);
static void lzx_huffman_free(struct huffman *);
static int lzx_make_huffman_table(struct huffman *);
-static inline int lzx_decode_huffman(struct huffman *, unsigned);
+static uint16_t lzx_decode_huffman(struct huffman *, uint16_t);
int
@@ -433,7 +534,7 @@ archive_read_format_cab_bid(struct archive_read *a, int best_bid)
/*
* Attempt to handle self-extracting archives
* by noting a PE header and searching forward
- * up to 128k for a 'MSCF' marker.
+ * up to 128k for an 'MSCF' marker.
*/
if (p[0] == 'M' && p[1] == 'Z') {
offset = 0;
@@ -465,10 +566,9 @@ static int
archive_read_format_cab_options(struct archive_read *a,
const char *key, const char *val)
{
- struct cab *cab;
+ struct cab *cab = a->format->data;
int ret = ARCHIVE_FAILED;
- cab = (struct cab *)(a->format->data);
if (strcmp(key, "hdrcharset") == 0) {
if (val == NULL || val[0] == 0)
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
@@ -501,7 +601,7 @@ cab_skip_sfx(struct archive_read *a)
for (;;) {
const char *h = __archive_read_ahead(a, window, &bytes);
if (h == NULL) {
- /* Remaining size are less than window. */
+ /* Remaining size is less than window. */
window >>= 1;
if (window < 128) {
archive_set_error(&a->archive,
@@ -540,33 +640,34 @@ truncated_error(struct archive_read *a)
return (ARCHIVE_FATAL);
}
-static ssize_t
-cab_strnlen(const unsigned char *p, size_t maxlen)
+#ifdef HAVE_STRNLEN
+#define cab_strnlen(a,b) strnlen(a,b)
+#else
+static size_t
+cab_strnlen(const char *p, size_t maxlen)
{
size_t i;
- for (i = 0; i <= maxlen; i++) {
+ for (i = 0; i < maxlen; i++) {
if (p[i] == 0)
break;
}
- if (i > maxlen)
- return (-1);/* invalid */
- return ((ssize_t)i);
+ return (i);
}
+#endif
-/* Read bytes as much as remaining. */
+/* Read up to max remaining bytes. */
static const void *
-cab_read_ahead_remaining(struct archive_read *a, size_t min, ssize_t *avail)
+cab_read_ahead_remaining(struct archive_read *a, size_t max, ssize_t *avail)
{
- const void *p;
+ const void *p = __archive_read_ahead(a, max, avail);
- while (min > 0) {
- p = __archive_read_ahead(a, min, avail);
- if (p != NULL)
- return (p);
- min--;
- }
- return (NULL);
+ if (p == NULL && *avail > 0)
+ p = __archive_read_ahead(a, *avail, avail);
+ if (p != NULL && (size_t)*avail > max)
+ *avail = max;
+
+ return (p);
}
/* Convert a path separator '\' -> '/' */
@@ -623,11 +724,11 @@ cab_convert_path_separator_2(struct cab *cab, struct archive_entry *entry)
static int
cab_read_header(struct archive_read *a)
{
- const unsigned char *p;
- struct cab *cab;
+ struct cab *cab = a->format->data;
+ const char *p;
struct cfheader *hd;
- size_t bytes, used;
- ssize_t len;
+ size_t bytes, len, maxlen, used;
+ ssize_t avail;
int64_t skip;
int err, i;
int cur_folder, prev_folder;
@@ -640,7 +741,6 @@ cab_read_header(struct archive_read *a)
if ((p = __archive_read_ahead(a, 42, NULL)) == NULL)
return (truncated_error(a));
- cab = (struct cab *)(a->format->data);
if (cab->found_header == 0 &&
p[0] == 'M' && p[1] == 'Z') {
/* This is an executable? Must be self-extracting... */
@@ -664,7 +764,6 @@ cab_read_header(struct archive_read *a)
"Couldn't find out CAB header");
return (ARCHIVE_FATAL);
}
- hd->total_bytes = archive_le32dec(p + CFHEADER_cbCabinet);
hd->files_offset = archive_le32dec(p + CFHEADER_coffFiles);
hd->minor = p[CFHEADER_versionMinor];
hd->major = p[CFHEADER_versionMajor];
@@ -675,7 +774,6 @@ cab_read_header(struct archive_read *a)
if (hd->file_count == 0)
goto invalid;
hd->flags = archive_le16dec(p + CFHEADER_flags);
- hd->setid = archive_le16dec(p + CFHEADER_setID);
hd->cabinet = archive_le16dec(p + CFHEADER_iCabinet);
used = CFHEADER_iCabinet + 2;
if (hd->flags & RESERVE_PRESENT) {
@@ -691,29 +789,42 @@ cab_read_header(struct archive_read *a)
hd->cffolder = 0;/* Avoid compiling warning. */
if (hd->flags & PREV_CABINET) {
/* How many bytes are used for szCabinetPrev. */
- if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
+ if ((p = cab_read_ahead_remaining(a, used + 256,
+ &avail)) == NULL || (size_t)avail <= used)
return (truncated_error(a));
- if ((len = cab_strnlen(p + used, 255)) <= 0)
+ maxlen = avail - used;
+ len = cab_strnlen(p + used, maxlen);
+ if (len == 0 || len == maxlen) {
goto invalid;
+ }
used += len + 1;
/* How many bytes are used for szDiskPrev. */
- if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
+ if ((p = cab_read_ahead_remaining(a, used + 256,
+ &avail)) == NULL || (size_t)avail <= used)
return (truncated_error(a));
- if ((len = cab_strnlen(p + used, 255)) <= 0)
+ maxlen = avail - used;
+ len = cab_strnlen(p + used, maxlen);
+ if (len == maxlen)
goto invalid;
used += len + 1;
}
if (hd->flags & NEXT_CABINET) {
/* How many bytes are used for szCabinetNext. */
- if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
+ if ((p = cab_read_ahead_remaining(a, used + 256,
+ &avail)) == NULL || (size_t)avail <= used)
return (truncated_error(a));
- if ((len = cab_strnlen(p + used, 255)) <= 0)
+ maxlen = avail - used;
+ len = cab_strnlen(p + used, maxlen);
+ if (len == 0 || len == maxlen)
goto invalid;
used += len + 1;
/* How many bytes are used for szDiskNext. */
- if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
+ if ((p = cab_read_ahead_remaining(a, used + 256,
+ &avail)) == NULL || (size_t)avail <= used)
return (truncated_error(a));
- if ((len = cab_strnlen(p + used, 255)) <= 0)
+ maxlen = avail - used;
+ len = cab_strnlen(p + used, maxlen);
+ if (len == maxlen)
goto invalid;
used += len + 1;
}
@@ -776,14 +887,15 @@ cab_read_header(struct archive_read *a)
*/
/* Seek read pointer to the offset of CFFILE if needed. */
skip = (int64_t)hd->files_offset - cab->cab_offset;
- if (skip < 0) {
+ if (skip < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Invalid offset of CFFILE %jd < %jd",
(intmax_t)hd->files_offset, (intmax_t)cab->cab_offset);
return (ARCHIVE_FATAL);
}
if (skip) {
- __archive_read_consume(a, skip);
+ if (__archive_read_consume(a, skip) < 0)
+ return (truncated_error(a));
cab->cab_offset += skip;
}
/* Allocate memory for CFDATA */
@@ -795,7 +907,6 @@ cab_read_header(struct archive_read *a)
prev_folder = -1;
for (i = 0; i < hd->file_count; i++) {
struct cffile *file = &(hd->file_array[i]);
- ssize_t avail;
if ((p = __archive_read_ahead(a, 16, NULL)) == NULL)
return (truncated_error(a));
@@ -809,7 +920,9 @@ cab_read_header(struct archive_read *a)
cab->cab_offset += 16;
if ((p = cab_read_ahead_remaining(a, 256, &avail)) == NULL)
return (truncated_error(a));
- if ((len = cab_strnlen(p, avail-1)) <= 0)
+ maxlen = avail;
+ len = cab_strnlen(p, maxlen);
+ if (len == 0 || len == maxlen)
goto invalid;
/* Copy a pathname. */
@@ -821,10 +934,10 @@ cab_read_header(struct archive_read *a)
/*
* Sanity check if each data is acceptable.
*/
- if (file->uncompressed_size > 0x7FFF8000)
+ if (file->uncompressed_size > MAX_FILE_SIZE)
goto invalid;/* Too large */
if ((int64_t)file->offset + (int64_t)file->uncompressed_size
- > ARCHIVE_LITERAL_LL(0x7FFF8000))
+ > (int64_t)MAX_FILE_SIZE)
goto invalid;/* Too large */
switch (file->folder) {
case iFoldCONTINUED_TO_NEXT:
@@ -890,14 +1003,13 @@ static int
archive_read_format_cab_read_header(struct archive_read *a,
struct archive_entry *entry)
{
- struct cab *cab;
+ struct cab *cab = a->format->data;
struct cfheader *hd;
struct cffolder *prev_folder;
struct cffile *file;
struct archive_string_conv *sconv;
int err = ARCHIVE_OK, r;
-
- cab = (struct cab *)(a->format->data);
+
if (cab->found_header == 0) {
err = cab_read_header(a);
if (err < ARCHIVE_WARN)
@@ -915,8 +1027,6 @@ archive_read_format_cab_read_header(struct archive_read *a,
cab->end_of_entry = 0;
cab->end_of_entry_cleanup = 0;
- cab->entry_compressed_bytes_read = 0;
- cab->entry_uncompressed_bytes_read = 0;
cab->entry_unconsumed = 0;
cab->entry_cffile = file;
@@ -1014,7 +1124,7 @@ static int
archive_read_format_cab_read_data(struct archive_read *a,
const void **buff, size_t *size, int64_t *offset)
{
- struct cab *cab = (struct cab *)(a->format->data);
+ struct cab *cab = a->format->data;
int r;
switch (cab->entry_cffile->folder) {
@@ -1114,7 +1224,7 @@ cab_checksum_cfdata(const void *p, size_t bytes, uint32_t seed)
static void
cab_checksum_update(struct archive_read *a, size_t bytes)
{
- struct cab *cab = (struct cab *)(a->format->data);
+ struct cab *cab = a->format->data;
struct cfdata *cfdata = cab->entry_cfdata;
const unsigned char *p;
size_t sumbytes;
@@ -1154,7 +1264,7 @@ cab_checksum_update(struct archive_read *a, size_t bytes)
static int
cab_checksum_finish(struct archive_read *a)
{
- struct cab *cab = (struct cab *)(a->format->data);
+ struct cab *cab = a->format->data;
struct cfdata *cfdata = cab->entry_cfdata;
int l;
@@ -1199,7 +1309,7 @@ cab_checksum_finish(struct archive_read *a)
static int
cab_next_cfdata(struct archive_read *a)
{
- struct cab *cab = (struct cab *)(a->format->data);
+ struct cab *cab = a->format->data;
struct cfdata *cfdata = cab->entry_cfdata;
/* There are remaining bytes in current CFDATA, use it first. */
@@ -1277,9 +1387,9 @@ cab_next_cfdata(struct archive_read *a)
* Sanity check if data size is acceptable.
*/
if (cfdata->compressed_size == 0 ||
- cfdata->compressed_size > (0x8000+6144))
+ cfdata->compressed_size > (MAX_UNCOMPRESS_SIZE + 6144))
goto invalid;
- if (cfdata->uncompressed_size > 0x8000)
+ if (cfdata->uncompressed_size > MAX_UNCOMPRESS_SIZE)
goto invalid;
if (cfdata->uncompressed_size == 0) {
switch (cab->entry_cffile->folder) {
@@ -1292,10 +1402,10 @@ cab_next_cfdata(struct archive_read *a)
}
}
/* If CFDATA is not last in a folder, an uncompressed
- * size must be 0x8000(32KBi) */
+ * size must be 0x8000 (32 KiB) */
if ((cab->entry_cffolder->cfdata_index <
cab->entry_cffolder->cfdata_count) &&
- cfdata->uncompressed_size != 0x8000)
+ cfdata->uncompressed_size != MAX_UNCOMPRESS_SIZE)
goto invalid;
/* A compressed data size and an uncompressed data size must
@@ -1347,7 +1457,7 @@ invalid:
static const void *
cab_read_ahead_cfdata(struct archive_read *a, ssize_t *avail)
{
- struct cab *cab = (struct cab *)(a->format->data);
+ struct cab *cab = a->format->data;
int err;
err = cab_next_cfdata(a);
@@ -1378,7 +1488,7 @@ cab_read_ahead_cfdata(struct archive_read *a, ssize_t *avail)
static const void *
cab_read_ahead_cfdata_none(struct archive_read *a, ssize_t *avail)
{
- struct cab *cab = (struct cab *)(a->format->data);
+ struct cab *cab = a->format->data;
struct cfdata *cfdata;
const void *d;
@@ -1410,7 +1520,7 @@ cab_read_ahead_cfdata_none(struct archive_read *a, ssize_t *avail)
static const void *
cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
{
- struct cab *cab = (struct cab *)(a->format->data);
+ struct cab *cab = a->format->data;
struct cfdata *cfdata;
const void *d;
int r, mszip;
@@ -1420,7 +1530,7 @@ cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
cfdata = cab->entry_cfdata;
/* If the buffer hasn't been allocated, allocate it now. */
if (cab->uncompressed_buffer == NULL) {
- cab->uncompressed_buffer_size = 0x8000;
+ cab->uncompressed_buffer_size = MAX_UNCOMPRESS_SIZE;
cab->uncompressed_buffer
= malloc(cab->uncompressed_buffer_size);
if (cab->uncompressed_buffer == NULL) {
@@ -1565,11 +1675,9 @@ cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
* correctly compute the sum of CFDATA accordingly.
*/
if (cfdata->compressed_bytes_remaining > 0) {
- ssize_t bytes_avail;
-
d = __archive_read_ahead(a, cfdata->compressed_bytes_remaining,
- &bytes_avail);
- if (bytes_avail <= 0) {
+ NULL);
+ if (d == NULL) {
*avail = truncated_error(a);
return (NULL);
}
@@ -1640,7 +1748,7 @@ cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
static const void *
cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail)
{
- struct cab *cab = (struct cab *)(a->format->data);
+ struct cab *cab = a->format->data;
struct cfdata *cfdata;
const void *d;
int r;
@@ -1649,7 +1757,7 @@ cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail)
cfdata = cab->entry_cfdata;
/* If the buffer hasn't been allocated, allocate it now. */
if (cab->uncompressed_buffer == NULL) {
- cab->uncompressed_buffer_size = 0x8000;
+ cab->uncompressed_buffer_size = MAX_UNCOMPRESS_SIZE;
cab->uncompressed_buffer
= malloc(cab->uncompressed_buffer_size);
if (cab->uncompressed_buffer == NULL) {
@@ -1690,13 +1798,6 @@ cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail)
cab->uncompressed_buffer + cab->xstrm.total_out;
cab->xstrm.avail_out =
cfdata->uncompressed_size - cab->xstrm.total_out;
-
- if ((size_t)cfdata->uncompressed_size > cab->uncompressed_buffer_size) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid CFDATA uncompressed size");
- *avail = ARCHIVE_FATAL;
- return (NULL);
- }
d = __archive_read_ahead(a, 1, &bytes_avail);
if (d == NULL) {
@@ -1737,11 +1838,9 @@ cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail)
* Make sure a read pointer advances to next CFDATA.
*/
if (cfdata->compressed_bytes_remaining > 0) {
- ssize_t bytes_avail;
-
d = __archive_read_ahead(a, cfdata->compressed_bytes_remaining,
- &bytes_avail);
- if (bytes_avail <= 0) {
+ NULL);
+ if (d == NULL) {
*avail = truncated_error(a);
return (NULL);
}
@@ -1758,7 +1857,7 @@ cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail)
*/
lzx_translation(&cab->xstrm, cab->uncompressed_buffer,
cfdata->uncompressed_size,
- (cab->entry_cffolder->cfdata_index-1) * 0x8000);
+ (cab->entry_cffolder->cfdata_index - 1) * MAX_UNCOMPRESS_SIZE);
d = cab->uncompressed_buffer + cfdata->read_offset;
*avail = uavail - cfdata->read_offset;
@@ -1779,7 +1878,7 @@ cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail)
static int64_t
cab_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
{
- struct cab *cab = (struct cab *)(a->format->data);
+ struct cab *cab = a->format->data;
struct cfdata *cfdata;
int64_t cbytes, rbytes;
int err;
@@ -1872,7 +1971,7 @@ cab_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
static int64_t
cab_minimum_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
{
- struct cab *cab = (struct cab *)(a->format->data);
+ struct cab *cab = a->format->data;
struct cfdata *cfdata;
int64_t cbytes, rbytes;
int err;
@@ -1929,7 +2028,7 @@ static int
cab_read_data(struct archive_read *a, const void **buff,
size_t *size, int64_t *offset)
{
- struct cab *cab = (struct cab *)(a->format->data);
+ struct cab *cab = a->format->data;
ssize_t bytes_avail;
if (cab->entry_bytes_remaining == 0) {
@@ -1975,12 +2074,10 @@ cab_read_data(struct archive_read *a, const void **buff,
static int
archive_read_format_cab_read_data_skip(struct archive_read *a)
{
- struct cab *cab;
+ struct cab *cab = a->format->data;
int64_t bytes_skipped;
int r;
- cab = (struct cab *)(a->format->data);
-
if (cab->end_of_archive)
return (ARCHIVE_EOF);
@@ -2030,9 +2127,9 @@ archive_read_format_cab_read_data_skip(struct archive_read *a)
static int
archive_read_format_cab_cleanup(struct archive_read *a)
{
- struct cab *cab = (struct cab *)(a->format->data);
+ struct cab *cab = a->format->data;
struct cfheader *hd = &cab->cfheader;
- int i;
+ uint16_t i;
if (hd->folder_array != NULL) {
for (i = 0; i < hd->folder_count; i++)
@@ -2052,13 +2149,13 @@ archive_read_format_cab_cleanup(struct archive_read *a)
archive_wstring_free(&cab->ws);
free(cab->uncompressed_buffer);
free(cab);
- (a->format->data) = NULL;
+ a->format->data = NULL;
return (ARCHIVE_OK);
}
/* Convert an MSDOS-style date/time into Unix-style time. */
static time_t
-cab_dos_time(const unsigned char *p)
+cab_dos_time(const char *p)
{
int msTime, msDate;
struct tm ts;
@@ -2094,10 +2191,11 @@ cab_dos_time(const unsigned char *p)
static int
lzx_decode_init(struct lzx_stream *strm, int w_bits)
{
- struct lzx_dec *ds;
- int slot, w_size, w_slot;
- int base, footer;
int base_inc[18];
+ struct lzx_dec *ds;
+ uint32_t base;
+ uint16_t slot, w_size, w_slot;
+ uint8_t footer;
if (strm->ds == NULL) {
strm->ds = calloc(1, sizeof(*strm->ds));
@@ -2107,7 +2205,7 @@ lzx_decode_init(struct lzx_stream *strm, int w_bits)
ds = strm->ds;
ds->error = ARCHIVE_FAILED;
- /* Allow bits from 15(32KBi) up to 21(2MBi) */
+ /* Allow bits from 15 (32 KiB) up to 21 (2 MiB) */
if (w_bits < SLOT_BASE || w_bits > SLOT_MAX)
return (ARCHIVE_FAILED);
@@ -2119,7 +2217,7 @@ lzx_decode_init(struct lzx_stream *strm, int w_bits)
w_size = ds->w_size;
w_slot = slots[w_bits - SLOT_BASE];
ds->w_size = 1U << w_bits;
- ds->w_mask = ds->w_size -1;
+ ds->w_mask = ds->w_size - 1;
if (ds->w_buff == NULL || w_size != ds->w_size) {
free(ds->w_buff);
ds->w_buff = malloc(ds->w_size);
@@ -2141,18 +2239,20 @@ lzx_decode_init(struct lzx_stream *strm, int w_bits)
else
base += base_inc[footer];
if (footer < 17) {
- footer = -2;
+ footer = 0;
for (n = base; n; n >>= 1)
footer++;
- if (footer <= 0)
+ if (footer <= 2)
footer = 0;
+ else
+ footer -= 2;
}
ds->pos_tbl[slot].base = base;
ds->pos_tbl[slot].footer_bits = footer;
}
ds->w_pos = 0;
- ds->state = 0;
+ ds->state = ST_RD_TRANSLATION;
ds->br.cache_buffer = 0;
ds->br.cache_avail = 0;
ds->r0 = ds->r1 = ds->r2 = 1;
@@ -2166,7 +2266,7 @@ lzx_decode_init(struct lzx_stream *strm, int w_bits)
return (ARCHIVE_FATAL);
/* Initialize Main tree. */
- if (lzx_huffman_init(&(ds->mt), 256+(w_slot<<3), 16)
+ if (lzx_huffman_init(&(ds->mt), 256 + (w_slot << 3), 16)
!= ARCHIVE_OK)
return (ARCHIVE_FATAL);
@@ -2202,29 +2302,36 @@ lzx_decode_free(struct lzx_stream *strm)
* E8 Call Translation reversal.
*/
static void
-lzx_translation(struct lzx_stream *strm, void *p, size_t size, uint32_t offset)
+lzx_translation(struct lzx_stream *strm, unsigned char *buffer, size_t size,
+ int32_t offset)
{
struct lzx_dec *ds = strm->ds;
- unsigned char *b, *end;
+ unsigned char *p, *end;
- if (!ds->translation || size <= 10)
+ if (!ds->translation || offset >= MAX_E8_TRANSLATION || size <= 10)
return;
- b = p;
- end = b + size - 10;
- while (b < end && (b = memchr(b, 0xE8, end - b)) != NULL) {
- size_t i = b - (unsigned char *)p;
- int32_t cp, displacement, value;
- cp = (int32_t)(offset + (uint32_t)i);
- value = archive_le32dec(&b[1]);
- if (value >= -cp && value < (int32_t)ds->translation_size) {
- if (value >= 0)
- displacement = value - cp;
+ p = buffer;
+ end = buffer + size - 10;
+
+ while (p < end && (p = memchr(p, 0xE8, end - p)) != NULL) {
+ int32_t address, position;
+
+ address = archive_le32dec(p + 1);
+ position = offset + (p - buffer);
+
+ if (address >= -position && address < ds->translation_size) {
+ uint32_t relative;
+
+ if (address >= 0)
+ relative = address - position;
else
- displacement = value + ds->translation_size;
- archive_le32enc(&b[1], (uint32_t)displacement);
+ relative = address + ds->translation_size;
+
+ archive_le32enc(p + 1, relative);
}
- b += 5;
+
+ p += 5;
}
}
@@ -2246,7 +2353,7 @@ lzx_translation(struct lzx_stream *strm, void *p, size_t size, uint32_t offset)
* False : we met that strm->next_in is empty, we have to get following
* bytes. */
#define lzx_br_read_ahead_0(strm, br, n) \
- (lzx_br_has((br), (n)) || lzx_br_fillup(strm, br))
+ (lzx_br_has((br), (n)) || lzx_br_fillup(strm, br) == ARCHIVE_OK)
/* True : the cache buffer has some bits as much as we need.
* False : there are no enough bits in the cache buffer to be used,
* we have to get following bytes if we could. */
@@ -2275,8 +2382,8 @@ static const uint32_t cache_masks[] = {
* 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.
+ * Returns ARCHIVE_OK if the cache buffer is full.
+ * Returns ARCHIVE_EOF if the cache buffer is not full; input buffer is empty.
*/
static int
lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
@@ -2284,7 +2391,7 @@ lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
/*
* x86 processor family can read misaligned data without an access error.
*/
- int n = CACHE_BITS - br->cache_avail;
+ ssize_t n = CACHE_BITS - br->cache_avail;
for (;;) {
switch (n >> 4) {
@@ -2302,7 +2409,7 @@ lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
strm->next_in += 8;
strm->avail_in -= 8;
br->cache_avail += 8 * 8;
- return (1);
+ return (ARCHIVE_OK);
}
break;
case 3:
@@ -2318,13 +2425,13 @@ lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
strm->next_in += 6;
strm->avail_in -= 6;
br->cache_avail += 6 * 8;
- return (1);
+ return (ARCHIVE_OK);
}
break;
case 0:
/* We have enough compressed data in
* the cache buffer.*/
- return (1);
+ return (ARCHIVE_EOF);
default:
break;
}
@@ -2336,7 +2443,7 @@ lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
strm->avail_in--;
br->have_odd = 1;
}
- return (0);
+ return (ARCHIVE_EOF);
}
br->cache_buffer =
(br->cache_buffer << 16) |
@@ -2351,7 +2458,7 @@ lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
static void
lzx_br_fixup(struct lzx_stream *strm, struct lzx_br *br)
{
- int n = CACHE_BITS - br->cache_avail;
+ ssize_t n = CACHE_BITS - br->cache_avail;
if (br->have_odd && n >= 16 && strm->avail_in > 0) {
br->cache_buffer =
@@ -2380,35 +2487,11 @@ lzx_cleanup_bitstream(struct lzx_stream *strm)
* 3. Returns ARCHIVE_FAILED if an error occurred; compressed data
* is broken or you do not set 'last' flag properly.
*/
-#define ST_RD_TRANSLATION 0
-#define ST_RD_TRANSLATION_SIZE 1
-#define ST_RD_BLOCK_TYPE 2
-#define ST_RD_BLOCK_SIZE 3
-#define ST_RD_ALIGNMENT 4
-#define ST_RD_R0 5
-#define ST_RD_R1 6
-#define ST_RD_R2 7
-#define ST_COPY_UNCOMP1 8
-#define ST_COPY_UNCOMP2 9
-#define ST_RD_ALIGNED_OFFSET 10
-#define ST_RD_VERBATIM 11
-#define ST_RD_PRE_MAIN_TREE_256 12
-#define ST_MAIN_TREE_256 13
-#define ST_RD_PRE_MAIN_TREE_REM 14
-#define ST_MAIN_TREE_REM 15
-#define ST_RD_PRE_LENGTH_TREE 16
-#define ST_LENGTH_TREE 17
-#define ST_MAIN 18
-#define ST_LENGTH 19
-#define ST_OFFSET 20
-#define ST_REAL_POS 21
-#define ST_COPY 22
-
static int
lzx_decode(struct lzx_stream *strm, int last)
{
struct lzx_dec *ds = strm->ds;
- int64_t avail_in;
+ size_t avail_in;
int r;
if (ds->error)
@@ -2420,7 +2503,8 @@ lzx_decode(struct lzx_stream *strm, int last)
if (ds->state < ST_MAIN)
r = lzx_read_blocks(strm, last);
else {
- int64_t bytes_written = strm->avail_out;
+ size_t bytes_written = strm->avail_out;
+
r = lzx_decode_blocks(strm, last);
bytes_written -= strm->avail_out;
strm->next_out += bytes_written;
@@ -2436,7 +2520,8 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
{
struct lzx_dec *ds = strm->ds;
struct lzx_br *br = &(ds->br);
- int i, r;
+ int r;
+ uint16_t i;
for (;;) {
switch (ds->state) {
@@ -2452,16 +2537,21 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
/* FALL THROUGH */
case ST_RD_TRANSLATION_SIZE:
if (ds->translation) {
+ uint32_t v;
+
if (!lzx_br_read_ahead(strm, br, 32)) {
ds->state = ST_RD_TRANSLATION_SIZE;
if (last)
goto failed;
return (ARCHIVE_OK);
}
- ds->translation_size = lzx_br_bits(br, 16);
+ v = lzx_br_bits(br, 16);
lzx_br_consume(br, 16);
- ds->translation_size <<= 16;
- ds->translation_size |= lzx_br_bits(br, 16);
+ v <<= 16;
+ v |= lzx_br_bits(br, 16);
+ if (v > MAX_FILE_SIZE)
+ goto failed;
+ ds->translation_size = (int32_t)v;
lzx_br_consume(br, 16);
}
/* FALL THROUGH */
@@ -2568,17 +2658,17 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
ds->rbytes_avail = 0;
if (ds->state == ST_RD_R0) {
ds->r0 = archive_le32dec(ds->rbytes);
- if (ds->r0 < 0)
+ if (ds->r0 > (size_t)INT32_MAX)
goto failed;
ds->state = ST_RD_R1;
} else if (ds->state == ST_RD_R1) {
ds->r1 = archive_le32dec(ds->rbytes);
- if (ds->r1 < 0)
+ if (ds->r1 > (size_t)INT32_MAX)
goto failed;
ds->state = ST_RD_R2;
} else if (ds->state == ST_RD_R2) {
ds->r2 = archive_le32dec(ds->rbytes);
- if (ds->r2 < 0)
+ if (ds->r2 > (size_t)INT32_MAX)
goto failed;
/* We've gotten all repeated offsets. */
ds->state = ST_COPY_UNCOMP1;
@@ -2587,10 +2677,10 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
/* FALL THROUGH */
case ST_COPY_UNCOMP1:
/*
- * Copy bytes form next_in to next_out directly.
+ * Copy bytes from next_in to next_out directly.
*/
while (ds->block_bytes_avail) {
- int l;
+ size_t l;
if (strm->avail_out <= 0)
/* Output buffer is empty. */
@@ -2601,13 +2691,13 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
goto failed;
return (ARCHIVE_OK);
}
- l = (int)ds->block_bytes_avail;
+ l = ds->block_bytes_avail;
if (l > ds->w_size - ds->w_pos)
l = ds->w_size - ds->w_pos;
if (l > strm->avail_out)
- l = (int)strm->avail_out;
+ l = strm->avail_out;
if (l > strm->avail_in)
- l = (int)strm->avail_in;
+ l = strm->avail_in;
memcpy(strm->next_out, strm->next_in, l);
memcpy(&(ds->w_buff[ds->w_pos]),
strm->next_in, l);
@@ -2641,19 +2731,19 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
/*
* Read Aligned offset tree.
*/
- if (!lzx_br_read_ahead(strm, br, 3 * ds->at.len_size)) {
+ if (!lzx_br_read_ahead(strm, br, 3 * ds->at.symbol_count)) {
ds->state = ST_RD_ALIGNED_OFFSET;
if (last)
goto failed;
return (ARCHIVE_OK);
}
memset(ds->at.freq, 0, sizeof(ds->at.freq));
- for (i = 0; i < ds->at.len_size; i++) {
+ for (i = 0; i < ds->at.symbol_count; i++) {
ds->at.bitlen[i] = lzx_br_bits(br, 3);
ds->at.freq[ds->at.bitlen[i]]++;
lzx_br_consume(br, 3);
}
- if (!lzx_make_huffman_table(&ds->at))
+ if (lzx_make_huffman_table(&ds->at) < 0)
goto failed;
/* FALL THROUGH */
case ST_RD_VERBATIM:
@@ -2663,13 +2753,13 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
/*
* Read Pre-tree for first 256 elements of main tree.
*/
- if (!lzx_read_pre_tree(strm)) {
+ if (lzx_read_pre_tree(strm) < 0) {
ds->state = ST_RD_PRE_MAIN_TREE_256;
if (last)
goto failed;
return (ARCHIVE_OK);
}
- if (!lzx_make_huffman_table(&ds->pt))
+ if (lzx_make_huffman_table(&ds->pt) < 0)
goto failed;
ds->loop = 0;
/* FALL THROUGH */
@@ -2678,27 +2768,26 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
* Get path lengths of first 256 elements of main tree.
*/
r = lzx_read_bitlen(strm, &ds->mt, 256);
- if (r < 0)
- goto failed;
- else if (!r) {
+ if (r == ARCHIVE_EOF) {
ds->state = ST_MAIN_TREE_256;
if (last)
goto failed;
return (ARCHIVE_OK);
- }
+ } else if (r < 0)
+ goto failed;
ds->loop = 0;
/* FALL THROUGH */
case ST_RD_PRE_MAIN_TREE_REM:
/*
* Read Pre-tree for remaining elements of main tree.
*/
- if (!lzx_read_pre_tree(strm)) {
+ if (lzx_read_pre_tree(strm) < 0) {
ds->state = ST_RD_PRE_MAIN_TREE_REM;
if (last)
goto failed;
return (ARCHIVE_OK);
}
- if (!lzx_make_huffman_table(&ds->pt))
+ if (lzx_make_huffman_table(&ds->pt) < 0)
goto failed;
ds->loop = 256;
/* FALL THROUGH */
@@ -2706,16 +2795,15 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
/*
* Get path lengths of remaining elements of main tree.
*/
- r = lzx_read_bitlen(strm, &ds->mt, -1);
- if (r < 0)
- goto failed;
- else if (!r) {
+ r = lzx_read_bitlen(strm, &ds->mt, 0);
+ if (r == ARCHIVE_EOF) {
ds->state = ST_MAIN_TREE_REM;
if (last)
goto failed;
return (ARCHIVE_OK);
- }
- if (!lzx_make_huffman_table(&ds->mt))
+ } else if (r < 0)
+ goto failed;
+ if (lzx_make_huffman_table(&ds->mt) < 0)
goto failed;
ds->loop = 0;
/* FALL THROUGH */
@@ -2723,13 +2811,13 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
/*
* Read Pre-tree for remaining elements of main tree.
*/
- if (!lzx_read_pre_tree(strm)) {
+ if (lzx_read_pre_tree(strm) < 0) {
ds->state = ST_RD_PRE_LENGTH_TREE;
if (last)
goto failed;
return (ARCHIVE_OK);
}
- if (!lzx_make_huffman_table(&ds->pt))
+ if (lzx_make_huffman_table(&ds->pt) < 0)
goto failed;
ds->loop = 0;
/* FALL THROUGH */
@@ -2737,16 +2825,15 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
/*
* Get path lengths of remaining elements of main tree.
*/
- r = lzx_read_bitlen(strm, &ds->lt, -1);
- if (r < 0)
- goto failed;
- else if (!r) {
+ r = lzx_read_bitlen(strm, &ds->lt, 0);
+ if (r == ARCHIVE_EOF) {
ds->state = ST_LENGTH_TREE;
if (last)
goto failed;
return (ARCHIVE_OK);
- }
- if (!lzx_make_huffman_table(&ds->lt))
+ } else if (r < 0)
+ goto failed;
+ if (lzx_make_huffman_table(&ds->lt) < 0)
goto failed;
ds->state = ST_MAIN;
return (100);
@@ -2765,22 +2852,23 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
const struct lzx_pos_tbl *pos_tbl = ds->pos_tbl;
unsigned char *noutp = strm->next_out;
unsigned char *endp = noutp + strm->avail_out;
- unsigned char *w_buff = ds->w_buff;
- unsigned char *at_bitlen = at->bitlen;
- unsigned char *lt_bitlen = lt->bitlen;
- unsigned char *mt_bitlen = mt->bitlen;
+ uint8_t *w_buff = ds->w_buff;
+ uint8_t *at_bitlen = at->bitlen;
+ uint8_t *lt_bitlen = lt->bitlen;
+ uint8_t *mt_bitlen = mt->bitlen;
size_t block_bytes_avail = ds->block_bytes_avail;
- int at_max_bits = at->max_bits;
- int lt_max_bits = lt->max_bits;
- int mt_max_bits = mt->max_bits;
- int c, copy_len = ds->copy_len, copy_pos = ds->copy_pos;
- int w_pos = ds->w_pos, w_mask = ds->w_mask, w_size = ds->w_size;
- int length_header = ds->length_header;
- int offset_bits = ds->offset_bits;
- int position_slot = ds->position_slot;
- int r0 = ds->r0, r1 = ds->r1, r2 = ds->r2;
+ uint8_t at_lookup_bits = at->lookup_bits;
+ uint8_t lt_lookup_bits = lt->lookup_bits;
+ uint8_t mt_lookup_bits = mt->lookup_bits;
+ size_t copy_len = ds->copy_len, copy_pos = ds->copy_pos;
+ size_t w_pos = ds->w_pos, w_mask = ds->w_mask, w_size = ds->w_size;
+ uint8_t length_header = ds->length_header;
+ uint8_t offset_bits = ds->offset_bits;
+ uint16_t position_slot = ds->position_slot;
+ size_t r0 = ds->r0, r1 = ds->r1, r2 = ds->r2;
int state = ds->state;
- char block_type = ds->block_type;
+ uint16_t c;
+ uint8_t block_type = ds->block_type;
for (;;) {
switch (state) {
@@ -2806,26 +2894,26 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
goto next_data;
if (!lzx_br_read_ahead(strm, &bre,
- mt_max_bits)) {
+ mt_lookup_bits)) {
if (!last)
goto next_data;
/* Remaining bits are less than
- * maximum bits(mt.max_bits) but maybe
- * it still remains as much as we need,
- * so we should try to use it with
- * dummy bits. */
+ * maximum bits (mt.lookup_bits) but
+ * maybe it still remains as much as we
+ * need, so we should try to use it
+ * with dummy bits. */
c = lzx_decode_huffman(mt,
lzx_br_bits_forced(
- &bre, mt_max_bits));
- lzx_br_consume(&bre, mt_bitlen[c]);
- if (!lzx_br_has(&bre, 0))
+ &bre, mt_lookup_bits));
+ if (!lzx_br_has(&bre, mt_bitlen[c]))
goto failed;/* Over read. */
+ lzx_br_consume(&bre, mt_bitlen[c]);
} else {
c = lzx_decode_huffman(mt,
- lzx_br_bits(&bre, mt_max_bits));
+ lzx_br_bits(&bre, mt_lookup_bits));
lzx_br_consume(&bre, mt_bitlen[c]);
}
- if ((unsigned int)c > UCHAR_MAX)
+ if (c > UCHAR_MAX)
break;
/*
* 'c' is exactly literal code.
@@ -2851,26 +2939,26 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
*/
if (length_header == 7) {
if (!lzx_br_read_ahead(strm, &bre,
- lt_max_bits)) {
+ lt_lookup_bits)) {
if (!last) {
state = ST_LENGTH;
goto next_data;
}
c = lzx_decode_huffman(lt,
lzx_br_bits_forced(
- &bre, lt_max_bits));
- lzx_br_consume(&bre, lt_bitlen[c]);
- if (!lzx_br_has(&bre, 0))
+ &bre, lt_lookup_bits));
+ if (!lzx_br_has(&bre, lt_bitlen[c]))
goto failed;/* Over read. */
+ lzx_br_consume(&bre, lt_bitlen[c]);
} else {
c = lzx_decode_huffman(lt,
- lzx_br_bits(&bre, lt_max_bits));
+ lzx_br_bits(&bre, lt_lookup_bits));
lzx_br_consume(&bre, lt_bitlen[c]);
}
copy_len = c + 7 + 2;
} else
copy_len = length_header + 2;
- if ((size_t)copy_len > block_bytes_avail)
+ if (copy_len > block_bytes_avail)
goto failed;
/*
* Get an offset.
@@ -2907,7 +2995,7 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
*/
if (block_type == ALIGNED_OFFSET_BLOCK &&
offset_bits >= 3) {
- int offbits = offset_bits - 3;
+ unsigned offbits = offset_bits - 3;
if (!lzx_br_read_ahead(strm, &bre, offbits)) {
state = ST_OFFSET;
@@ -2919,7 +3007,7 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
/* Get an aligned number. */
if (!lzx_br_read_ahead(strm, &bre,
- offbits + at_max_bits)) {
+ offbits + at_lookup_bits)) {
if (!last) {
state = ST_OFFSET;
goto next_data;
@@ -2927,14 +3015,14 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
lzx_br_consume(&bre, offbits);
c = lzx_decode_huffman(at,
lzx_br_bits_forced(&bre,
- at_max_bits));
- lzx_br_consume(&bre, at_bitlen[c]);
- if (!lzx_br_has(&bre, 0))
+ at_lookup_bits));
+ if (!lzx_br_has(&bre, at_bitlen[c]))
goto failed;/* Over read. */
+ lzx_br_consume(&bre, at_bitlen[c]);
} else {
lzx_br_consume(&bre, offbits);
c = lzx_decode_huffman(at,
- lzx_br_bits(&bre, at_max_bits));
+ lzx_br_bits(&bre, at_lookup_bits));
lzx_br_consume(&bre, at_bitlen[c]);
}
/* Add an aligned number. */
@@ -2950,7 +3038,7 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
copy_pos = lzx_br_bits(&bre, offset_bits);
lzx_br_consume(&bre, offset_bits);
}
- copy_pos += pos_tbl[position_slot].base -2;
+ copy_pos += pos_tbl[position_slot].base - 2;
/* Update repeated offset LRU queue. */
r2 = r1;
@@ -2969,8 +3057,8 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
* into the output buffer.
*/
for (;;) {
- const unsigned char *s;
- int l;
+ const uint8_t *s;
+ size_t l;
l = copy_len;
if (copy_pos > w_pos) {
@@ -2981,15 +3069,15 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
l = w_size - w_pos;
}
if (noutp + l >= endp)
- l = (int)(endp - noutp);
+ l = endp - noutp;
s = w_buff + copy_pos;
if (l >= 8 && ((copy_pos + l < w_pos)
|| (w_pos + l < copy_pos))) {
memcpy(w_buff + w_pos, s, l);
memcpy(noutp, s, l);
} else {
- unsigned char *d;
- int li;
+ uint8_t *d;
+ size_t li;
d = w_buff + w_pos;
for (li = 0; li < l; li++)
@@ -3035,122 +3123,124 @@ lzx_read_pre_tree(struct lzx_stream *strm)
{
struct lzx_dec *ds = strm->ds;
struct lzx_br *br = &(ds->br);
- int i;
+ uint16_t i;
if (ds->loop == 0)
memset(ds->pt.freq, 0, sizeof(ds->pt.freq));
- for (i = ds->loop; i < ds->pt.len_size; i++) {
+ for (i = ds->loop; i < ds->pt.symbol_count; i++) {
if (!lzx_br_read_ahead(strm, br, 4)) {
ds->loop = i;
- return (0);
+ return (ARCHIVE_EOF);
}
ds->pt.bitlen[i] = lzx_br_bits(br, 4);
ds->pt.freq[ds->pt.bitlen[i]]++;
lzx_br_consume(br, 4);
}
ds->loop = i;
- return (1);
+ return (ARCHIVE_OK);
}
/*
* Read a bunch of bit-lengths from pre-tree.
*/
static int
-lzx_read_bitlen(struct lzx_stream *strm, struct huffman *d, int end)
+lzx_read_bitlen(struct lzx_stream *strm, struct huffman *d, uint16_t end)
{
struct lzx_dec *ds = strm->ds;
struct lzx_br *br = &(ds->br);
- int c, i, j, ret, same;
- unsigned rbits;
+ int ret;
+ uint16_t c, i, j, rbits, same;
i = ds->loop;
if (i == 0)
memset(d->freq, 0, sizeof(d->freq));
- ret = 0;
- if (end < 0)
- end = d->len_size;
+ ret = ARCHIVE_EOF;
+ if (end == 0)
+ end = d->symbol_count;
while (i < end) {
ds->loop = i;
- if (!lzx_br_read_ahead(strm, br, ds->pt.max_bits))
+ if (!lzx_br_read_ahead(strm, br, (unsigned)ds->pt.lookup_bits))
goto getdata;
- rbits = lzx_br_bits(br, ds->pt.max_bits);
+ rbits = lzx_br_bits(br, ds->pt.lookup_bits);
c = lzx_decode_huffman(&(ds->pt), rbits);
switch (c) {
case 17:/* several zero lengths, from 4 to 19. */
- if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+4))
+ if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c] + 4U))
goto getdata;
lzx_br_consume(br, ds->pt.bitlen[c]);
same = lzx_br_bits(br, 4) + 4;
- if (i + same > end)
- return (-1);/* Invalid */
+ if (same > end - i)
+ return (ARCHIVE_FATAL);
lzx_br_consume(br, 4);
for (j = 0; j < same; j++)
d->bitlen[i++] = 0;
break;
case 18:/* many zero lengths, from 20 to 51. */
- if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+5))
+ if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c] + 5U))
goto getdata;
lzx_br_consume(br, ds->pt.bitlen[c]);
same = lzx_br_bits(br, 5) + 20;
- if (i + same > end)
- return (-1);/* Invalid */
+ if (same > end - i)
+ return (ARCHIVE_FATAL);
lzx_br_consume(br, 5);
memset(d->bitlen + i, 0, same);
i += same;
break;
case 19:/* a few same lengths. */
if (!lzx_br_read_ahead(strm, br,
- ds->pt.bitlen[c]+1+ds->pt.max_bits))
+ ds->pt.bitlen[c] + 1U + ds->pt.lookup_bits))
goto getdata;
lzx_br_consume(br, ds->pt.bitlen[c]);
same = lzx_br_bits(br, 1) + 4;
- if (i + same > end)
- return (-1);
+ if (same > end - i)
+ return (ARCHIVE_FATAL);
lzx_br_consume(br, 1);
- rbits = lzx_br_bits(br, ds->pt.max_bits);
+ rbits = lzx_br_bits(br, ds->pt.lookup_bits);
c = lzx_decode_huffman(&(ds->pt), rbits);
lzx_br_consume(br, ds->pt.bitlen[c]);
- c = (d->bitlen[i] - c + 17) % 17;
- if (c < 0)
- return (-1);/* Invalid */
+ if (c > d->bitlen[i] + 17)
+ return (ARCHIVE_FATAL);
+ c = (d->bitlen[i] + 17 - c) % 17;
for (j = 0; j < same; j++)
d->bitlen[i++] = c;
d->freq[c] += same;
break;
default:
lzx_br_consume(br, ds->pt.bitlen[c]);
- c = (d->bitlen[i] - c + 17) % 17;
- if (c < 0)
- return (-1);/* Invalid */
+ if (c > d->bitlen[i] + 17)
+ return (ARCHIVE_FATAL);
+ c = (d->bitlen[i] + 17 - c) % 17;
d->freq[c]++;
d->bitlen[i++] = c;
break;
}
}
- ret = 1;
+ ret = ARCHIVE_OK;
getdata:
ds->loop = i;
return (ret);
}
static int
-lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
+lzx_huffman_init(struct huffman *hf, uint16_t symbol_count, uint8_t tbl_bits)
{
+ size_t tbl_size = (size_t)1 << tbl_bits;
- if (hf->bitlen == NULL || hf->len_size != (int)len_size) {
+ if (hf->bitlen == NULL || hf->symbol_count != symbol_count) {
free(hf->bitlen);
- hf->bitlen = calloc(len_size, sizeof(hf->bitlen[0]));
+ hf->bitlen = calloc(symbol_count, sizeof(hf->bitlen[0]));
if (hf->bitlen == NULL)
return (ARCHIVE_FATAL);
- hf->len_size = (int)len_size;
+ hf->symbol_count = symbol_count;
} else
- memset(hf->bitlen, 0, len_size * sizeof(hf->bitlen[0]));
+ memset(hf->bitlen, 0, symbol_count * sizeof(hf->bitlen[0]));
if (hf->tbl == NULL) {
- hf->tbl = malloc(((size_t)1 << tbl_bits) * sizeof(hf->tbl[0]));
+ hf->tbl = calloc(tbl_size, sizeof(hf->tbl[0]));
if (hf->tbl == NULL)
return (ARCHIVE_FATAL);
hf->tbl_bits = tbl_bits;
- }
+ } else
+ memset(hf->tbl, 0, tbl_size * sizeof(hf->bitlen[0]));
return (ARCHIVE_OK);
}
@@ -3162,19 +3252,47 @@ lzx_huffman_free(struct huffman *hf)
}
/*
- * Make a huffman coding table.
+ * Create a direct, expanded Huffman lookup table based on
+ * canonical representation.
*/
static int
lzx_make_huffman_table(struct huffman *hf)
{
+ uint16_t bitptn[17], weight[17];
uint16_t *tbl;
- const unsigned char *bitlen;
- int bitptn[17], weight[17];
- int i, maxbits = 0, ptn, tbl_size, w;
- int len_avail;
+ const uint8_t *bitlen;
+ uint8_t maxbits = 0;
+ uint32_t ptn;
+ uint16_t i, symbol_count, w;
/*
* Initialize bit patterns.
+ *
+ * Each bitptn element represents the smallest possible
+ * code sequence allowed. The weight represents the amount
+ * of lookup bit patterns covered by a code of this length.
+ *
+ * Example of a Huffman tree:
+ *
+ * idx | freq[idx]
+ * ----+----------
+ * 1 | 1
+ * 2 | 2
+ *
+ * The result will be:
+ *
+ * idx | bitptn[idx] | weight[idx]
+ * ----+-------------+------------
+ * 1 | 0x0000 | 32768
+ * 2 | 0x8000 | 16384
+ *
+ * This means that a code with bit length 1 will take 32768
+ * possible combinations starting with 0b0. Since one such code exists
+ * (freq[1] = 1), codes with bit length 2 must start with 0b1. Since
+ * two codes with bit length 2 exist (freq[2] = 2), no more codes can
+ * be added.
+ *
+ * In this example, maxbits will be 2 (longest code length is 2).
*/
ptn = 0;
for (i = 1, w = 1 << 15; i <= 16; i++, w >>= 1) {
@@ -3185,61 +3303,108 @@ lzx_make_huffman_table(struct huffman *hf)
maxbits = i;
}
}
- if ((ptn & 0xffff) != 0 || maxbits > hf->tbl_bits)
- return (0);/* Invalid */
-
- hf->max_bits = maxbits;
+ /* Verify Kraft's inequality. */
+ if (ptn != 0 && ptn != 0x10000)
+ return (ARCHIVE_FATAL);
/*
- * Cut out extra bits which we won't house in the table.
- * This preparation reduces the same calculation in the for-loop
- * making the table.
+ * Shrink codes to smallest size by removing extra bits after
+ * the actual code sequences as good as possible.
+ *
+ * Continuing the example above:
+ *
+ * idx | bitptn[idx] | weight[idx]
+ * ----+-------------+-------------
+ * 1 | 0x0000 | 32768
+ * 2 | 0x8000 | 16384
+ *
+ * As can be seen, a total of 65536 entries must be created even
+ * though 4 would be sufficient (indices 0b00 to 0b11). Right shift
+ * the pattern and divide weight as much as possible:
+ *
+ * idx | bitptn[idx] | weight[idx]
+ * ----+-------------+-------------
+ * 1 | 0x0000 | 2
+ * 2 | 0x0002 | 1
+ *
+ * Thus, the direct, expanded lookup table only needs 4 entries.
*/
if (maxbits < 16) {
- int ebits = 16 - maxbits;
+ uint8_t ebits = 16 - maxbits;
for (i = 1; i <= maxbits; i++) {
bitptn[i] >>= ebits;
weight[i] >>= ebits;
}
}
+ /* Grow table if necessary. */
+ if (maxbits > hf->tbl_bits) {
+ size_t tbl_size;
+
+ hf->tbl_bits = 16;
+ tbl_size = (size_t)1 << hf->tbl_bits;
+
+ free(hf->tbl);
+ hf->tbl = calloc(tbl_size, sizeof(hf->tbl[0]));
+ if (hf->tbl == NULL)
+ return (ARCHIVE_FATAL);
+ }
+ hf->lookup_bits = maxbits;
+
/*
- * Make the table.
+ * Construct the direct, expanded lookup table.
+ *
+ * Store each symbol in table for every possible bit patterns starting
+ * with their code.
+ *
+ * Following the example with len_avail being 4:
+ *
+ * idx | bitlen[idx]
+ * ----+------------
+ * 0 | 0
+ * 1 | 1
+ * 2 | 0
+ * 3 | 2
+ * 4 | 2
+ *
+ * The resulting table contains all used symbols (1, 3, 4) for up to
+ * max_len bit patterns:
+ *
+ * idx | tbl[idx]
+ * ----------+---------
+ * 0 (0b00) | 1
+ * 1 (0b01) | 1
+ * 2 (0b10) | 3
+ * 3 (0b11) | 4
*/
- tbl_size = 1 << hf->tbl_bits;
tbl = hf->tbl;
bitlen = hf->bitlen;
- len_avail = hf->len_size;
- hf->tree_used = 0;
- for (i = 0; i < len_avail; i++) {
+ symbol_count = hf->symbol_count;
+ for (i = 0; i < symbol_count; i++) {
uint16_t *p;
- int len, cnt;
+ uint16_t cnt;
+ uint8_t len;
if (bitlen[i] == 0)
continue;
/* Get a bit pattern */
len = bitlen[i];
- if (len > tbl_size)
- return (0);
+ if (len > maxbits)
+ return (ARCHIVE_FATAL);
ptn = bitptn[len];
cnt = weight[len];
/* Calculate next bit pattern */
- if ((bitptn[len] = ptn + cnt) > tbl_size)
- return (0);/* Invalid */
+ bitptn[len] = ptn + cnt;
/* Update the table */
- p = &(tbl[ptn]);
- while (--cnt >= 0)
- p[cnt] = (uint16_t)i;
+ p = tbl + ptn;
+ while (cnt-- > 0)
+ *p++ = i;
}
- return (1);
+ return (ARCHIVE_OK);
}
-static inline int
-lzx_decode_huffman(struct huffman *hf, unsigned rbits)
+static uint16_t
+lzx_decode_huffman(struct huffman *hf, uint16_t rbits)
{
- int c;
- c = hf->tbl[rbits];
- if (c < hf->len_size)
- return (c);
- return (0);
+ return hf->tbl[rbits];
}
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_cpio.c b/contrib/libarchive/libarchive/archive_read_support_format_cpio.c
index 43169f61806d..7902cdf84918 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_cpio.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_cpio.c
@@ -38,6 +38,7 @@
#endif
#include "archive.h"
+#include "archive_endian.h"
#include "archive_entry.h"
#include "archive_entry_locale.h"
#include "archive_private.h"
@@ -160,6 +161,8 @@
#define afiol_filesize_c_offset 115 /* ':' */
#define afiol_header_size 116
+/* CPIO name fields store a full pathname, including the terminating NUL. */
+#define CPIO_PATHNAME_MAX (1024 * 1024)
struct links_entry {
struct links_entry *next;
@@ -200,7 +203,7 @@ static int archive_read_format_cpio_read_data(struct archive_read *,
static int archive_read_format_cpio_read_header(struct archive_read *,
struct archive_entry *);
static int archive_read_format_cpio_skip(struct archive_read *);
-static int64_t be4(const unsigned char *);
+static int64_t be32dec(const unsigned char *);
static int find_odc_header(struct archive_read *);
static int find_newc_header(struct archive_read *);
static int header_bin_be(struct archive_read *, struct cpio *,
@@ -215,7 +218,7 @@ static int header_afiol(struct archive_read *, struct cpio *,
struct archive_entry *, size_t *, size_t *);
static int is_octal(const char *, size_t);
static int is_hex(const char *, size_t);
-static int64_t le4(const unsigned char *);
+static int64_t le32dec(const unsigned char *);
static int record_hardlink(struct archive_read *a,
struct cpio *cpio, struct archive_entry *entry);
@@ -258,14 +261,12 @@ archive_read_support_format_cpio(struct archive *_a)
static int
archive_read_format_cpio_bid(struct archive_read *a, int best_bid)
{
+ struct cpio *cpio = a->format->data;
const unsigned char *p;
- struct cpio *cpio;
int bid;
(void)best_bid; /* UNUSED */
- cpio = (struct cpio *)(a->format->data);
-
if ((p = __archive_read_ahead(a, 6, NULL)) == NULL)
return (-1);
@@ -303,12 +304,12 @@ archive_read_format_cpio_bid(struct archive_read *a, int best_bid)
* XXX TODO: More verification; Could check that only hex
* digits appear in appropriate header locations. XXX
*/
- } else if (p[0] * 256 + p[1] == 070707) {
+ } else if (archive_be16dec(p) == 070707) {
/* big-endian binary cpio archives */
cpio->read_header = header_bin_be;
bid += 16;
/* Is more verification possible here? */
- } else if (p[0] + p[1] * 256 == 070707) {
+ } else if (archive_le16dec(p) == 070707) {
/* little-endian binary cpio archives */
cpio->read_header = header_bin_le;
bid += 16;
@@ -323,10 +324,9 @@ static int
archive_read_format_cpio_options(struct archive_read *a,
const char *key, const char *val)
{
- struct cpio *cpio;
+ struct cpio *cpio = a->format->data;
int ret = ARCHIVE_FAILED;
- cpio = (struct cpio *)(a->format->data);
if (strcmp(key, "compat-2x") == 0) {
/* Handle filenames as libarchive 2.x */
cpio->init_default_conversion = (val != NULL)?1:0;
@@ -361,14 +361,14 @@ static int
archive_read_format_cpio_read_header(struct archive_read *a,
struct archive_entry *entry)
{
- struct cpio *cpio;
+ struct cpio *cpio = a->format->data;
const void *h, *hl;
struct archive_string_conv *sconv;
size_t namelength;
size_t name_pad;
+ int is_trailer;
int r;
- cpio = (struct cpio *)(a->format->data);
sconv = cpio->opt_sconv;
if (sconv == NULL) {
if (!cpio->init_default_conversion) {
@@ -385,8 +385,15 @@ archive_read_format_cpio_read_header(struct archive_read *a,
if (r < ARCHIVE_WARN)
return (r);
+ if (namelength > CPIO_PATHNAME_MAX) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Rejecting malformed cpio archive: "
+ "pathname exceeds 1 megabyte");
+ return (ARCHIVE_FATAL);
+ }
+
/* Read name from buffer. */
- h = __archive_read_ahead(a, namelength + name_pad, NULL);
+ h = __archive_read_ahead(a, namelength, NULL);
if (h == NULL)
return (ARCHIVE_FATAL);
if (archive_entry_copy_pathname_l(entry,
@@ -401,9 +408,13 @@ archive_read_format_cpio_read_header(struct archive_read *a,
archive_string_conversion_charset_name(sconv));
r = ARCHIVE_WARN;
}
+ /* Save this before consuming the name buffer below. */
+ is_trailer = (namelength == 11 &&
+ memcmp((const char *)h, "TRAILER!!!", 10) == 0);
cpio->entry_offset = 0;
- __archive_read_consume(a, namelength + name_pad);
+ __archive_read_consume(a, namelength);
+ __archive_read_consume(a, name_pad);
/* If this is a symlink, read the link contents. */
if (archive_entry_filetype(entry) == AE_IFLNK) {
@@ -440,8 +451,7 @@ archive_read_format_cpio_read_header(struct archive_read *a,
* header. XXX */
/* Compare name to "TRAILER!!!" to test for end-of-archive. */
- if (namelength == 11 && strncmp((const char *)h, "TRAILER!!!",
- 10) == 0) {
+ if (is_trailer) {
/* TODO: Store file location of start of block. */
archive_clear_error(&a->archive);
return (ARCHIVE_EOF);
@@ -459,10 +469,8 @@ static int
archive_read_format_cpio_read_data(struct archive_read *a,
const void **buff, size_t *size, int64_t *offset)
{
+ struct cpio *cpio = a->format->data;
ssize_t bytes_read;
- struct cpio *cpio;
-
- cpio = (struct cpio *)(a->format->data);
if (cpio->entry_bytes_unconsumed) {
__archive_read_consume(a, cpio->entry_bytes_unconsumed);
@@ -497,7 +505,7 @@ archive_read_format_cpio_read_data(struct archive_read *a,
static int
archive_read_format_cpio_skip(struct archive_read *a)
{
- struct cpio *cpio = (struct cpio *)(a->format->data);
+ struct cpio *cpio = a->format->data;
int64_t to_skip = cpio->entry_bytes_remaining + cpio->entry_padding +
cpio->entry_bytes_unconsumed;
@@ -534,7 +542,8 @@ find_newc_header(struct archive_read *a)
{
const void *h;
const char *p, *q;
- size_t skip, skipped = 0;
+ int64_t skip;
+ uintmax_t skipped = 0;
ssize_t bytes;
for (;;) {
@@ -566,9 +575,9 @@ find_newc_header(struct archive_read *a)
if (skipped > 0) {
archive_set_error(&a->archive,
0,
- "Skipped %d bytes before "
+ "Skipped %ju bytes before "
"finding valid header",
- (int)skipped);
+ skipped);
return (ARCHIVE_WARN);
}
return (ARCHIVE_OK);
@@ -703,13 +712,24 @@ find_odc_header(struct archive_read *a)
{
const void *h;
const char *p, *q;
- size_t skip, skipped = 0;
+ int64_t skip;
+ uintmax_t skipped = 0;
ssize_t bytes;
for (;;) {
- h = __archive_read_ahead(a, odc_header_size, &bytes);
- if (h == NULL)
- return (ARCHIVE_FATAL);
+ size_t header_size;
+
+ header_size = afiol_header_size;
+ h = __archive_read_ahead(a, afiol_header_size, &bytes);
+ if (h == NULL) {
+ if (bytes >= odc_header_size) {
+ header_size = odc_header_size;
+ h = __archive_read_ahead(a, odc_header_size,
+ &bytes);
+ }
+ if (h == NULL)
+ return (ARCHIVE_FATAL);
+ }
p = h;
q = p + bytes;
@@ -725,7 +745,7 @@ find_odc_header(struct archive_read *a)
* Scan ahead until we find something that looks
* like an odc header.
*/
- while (p + odc_header_size <= q) {
+ while (p + header_size <= q) {
switch (p[5]) {
case '7':
if ((memcmp("070707", p, 6) == 0
@@ -741,9 +761,9 @@ find_odc_header(struct archive_read *a)
if (skipped > 0) {
archive_set_error(&a->archive,
0,
- "Skipped %d bytes before "
+ "Skipped %ju bytes before "
"finding valid header",
- (int)skipped);
+ skipped);
return (ARCHIVE_WARN);
}
return (ARCHIVE_OK);
@@ -828,7 +848,7 @@ header_odc(struct archive_read *a, struct cpio *cpio,
* NOTE: if a filename suffix is ".z", it is a file gzipped by afio.
* it would be nice if we could show uncompressed file size and
* uncompress file contents automatically, unfortunately we have nothing
- * to get a uncompressed file size while reading each header. It means
+ * to get an uncompressed file size while reading each header. It means
* we also cannot uncompress file contents under our framework.
*/
static int
@@ -873,7 +893,8 @@ header_afiol(struct archive_read *a, struct cpio *cpio,
t = atol16(header + afiol_filesize_offset, afiol_filesize_size);
if (t < 0) {
- archive_set_error(&a->archive, 0, "Nonsensical file size");
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Nonsensical file size");
return (ARCHIVE_FATAL);
}
cpio->entry_bytes_remaining = t;
@@ -897,7 +918,7 @@ header_bin_le(struct archive_read *a, struct cpio *cpio,
/* Read fixed-size portion of header. */
h = __archive_read_ahead(a, bin_header_size, NULL);
if (h == NULL) {
- archive_set_error(&a->archive, 0,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"End of file trying to read next cpio header");
return (ARCHIVE_FATAL);
}
@@ -905,24 +926,24 @@ header_bin_le(struct archive_read *a, struct cpio *cpio,
/* Parse out binary fields. */
header = (const unsigned char *)h;
- archive_entry_set_dev(entry, header[bin_dev_offset] + header[bin_dev_offset + 1] * 256);
- archive_entry_set_ino(entry, header[bin_ino_offset] + header[bin_ino_offset + 1] * 256);
- archive_entry_set_mode(entry, header[bin_mode_offset] + header[bin_mode_offset + 1] * 256);
+ archive_entry_set_dev(entry, archive_le16dec(header + bin_dev_offset));
+ archive_entry_set_ino(entry, archive_le16dec(header + bin_ino_offset));
+ archive_entry_set_mode(entry, archive_le16dec(header + bin_mode_offset));
if (cpio->option_pwb) {
/* turn off random bits left over from V6 inode */
archive_entry_set_mode(entry, archive_entry_mode(entry) & 067777);
if ((archive_entry_mode(entry) & AE_IFMT) == 0)
archive_entry_set_mode(entry, archive_entry_mode(entry) | AE_IFREG);
}
- archive_entry_set_uid(entry, header[bin_uid_offset] + header[bin_uid_offset + 1] * 256);
- archive_entry_set_gid(entry, header[bin_gid_offset] + header[bin_gid_offset + 1] * 256);
- archive_entry_set_nlink(entry, header[bin_nlink_offset] + header[bin_nlink_offset + 1] * 256);
- archive_entry_set_rdev(entry, header[bin_rdev_offset] + header[bin_rdev_offset + 1] * 256);
- archive_entry_set_mtime(entry, le4(header + bin_mtime_offset), 0);
- *namelength = header[bin_namesize_offset] + header[bin_namesize_offset + 1] * 256;
+ archive_entry_set_uid(entry, archive_le16dec(header + bin_uid_offset));
+ archive_entry_set_gid(entry, archive_le16dec(header + bin_gid_offset));
+ archive_entry_set_nlink(entry, archive_le16dec(header + bin_nlink_offset));
+ archive_entry_set_rdev(entry, archive_le16dec(header + bin_rdev_offset));
+ archive_entry_set_mtime(entry, le32dec(header + bin_mtime_offset), 0);
+ *namelength = archive_le16dec(header + bin_namesize_offset);
*name_pad = *namelength & 1; /* Pad to even. */
- cpio->entry_bytes_remaining = le4(header + bin_filesize_offset);
+ cpio->entry_bytes_remaining = le32dec(header + bin_filesize_offset);
archive_entry_set_size(entry, cpio->entry_bytes_remaining);
cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */
__archive_read_consume(a, bin_header_size);
@@ -942,7 +963,7 @@ header_bin_be(struct archive_read *a, struct cpio *cpio,
/* Read fixed-size portion of header. */
h = __archive_read_ahead(a, bin_header_size, NULL);
if (h == NULL) {
- archive_set_error(&a->archive, 0,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"End of file trying to read next cpio header");
return (ARCHIVE_FATAL);
}
@@ -950,24 +971,24 @@ header_bin_be(struct archive_read *a, struct cpio *cpio,
/* Parse out binary fields. */
header = (const unsigned char *)h;
- archive_entry_set_dev(entry, header[bin_dev_offset] * 256 + header[bin_dev_offset + 1]);
- archive_entry_set_ino(entry, header[bin_ino_offset] * 256 + header[bin_ino_offset + 1]);
- archive_entry_set_mode(entry, header[bin_mode_offset] * 256 + header[bin_mode_offset + 1]);
+ archive_entry_set_dev(entry, archive_be16dec(header + bin_dev_offset));
+ archive_entry_set_ino(entry, archive_be16dec(header + bin_ino_offset));
+ archive_entry_set_mode(entry, archive_be16dec(header + bin_mode_offset));
if (cpio->option_pwb) {
/* turn off random bits left over from V6 inode */
archive_entry_set_mode(entry, archive_entry_mode(entry) & 067777);
if ((archive_entry_mode(entry) & AE_IFMT) == 0)
archive_entry_set_mode(entry, archive_entry_mode(entry) | AE_IFREG);
}
- archive_entry_set_uid(entry, header[bin_uid_offset] * 256 + header[bin_uid_offset + 1]);
- archive_entry_set_gid(entry, header[bin_gid_offset] * 256 + header[bin_gid_offset + 1]);
- archive_entry_set_nlink(entry, header[bin_nlink_offset] * 256 + header[bin_nlink_offset + 1]);
- archive_entry_set_rdev(entry, header[bin_rdev_offset] * 256 + header[bin_rdev_offset + 1]);
- archive_entry_set_mtime(entry, be4(header + bin_mtime_offset), 0);
- *namelength = header[bin_namesize_offset] * 256 + header[bin_namesize_offset + 1];
+ archive_entry_set_uid(entry, archive_be16dec(header + bin_uid_offset));
+ archive_entry_set_gid(entry, archive_be16dec(header + bin_gid_offset));
+ archive_entry_set_nlink(entry, archive_be16dec(header + bin_nlink_offset));
+ archive_entry_set_rdev(entry, archive_be16dec(header + bin_rdev_offset));
+ archive_entry_set_mtime(entry, be32dec(header + bin_mtime_offset), 0);
+ *namelength = archive_be16dec(header + bin_namesize_offset);
*name_pad = *namelength & 1; /* Pad to even. */
- cpio->entry_bytes_remaining = be4(header + bin_filesize_offset);
+ cpio->entry_bytes_remaining = be32dec(header + bin_filesize_offset);
archive_entry_set_size(entry, cpio->entry_bytes_remaining);
cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */
__archive_read_consume(a, bin_header_size);
@@ -977,9 +998,8 @@ header_bin_be(struct archive_read *a, struct cpio *cpio,
static int
archive_read_format_cpio_cleanup(struct archive_read *a)
{
- struct cpio *cpio;
+ struct cpio *cpio = a->format->data;
- cpio = (struct cpio *)(a->format->data);
/* Free inode->name map */
while (cpio->links_head != NULL) {
struct links_entry *lp = cpio->links_head->next;
@@ -989,21 +1009,20 @@ archive_read_format_cpio_cleanup(struct archive_read *a)
cpio->links_head = lp;
}
free(cpio);
- (a->format->data) = NULL;
+ a->format->data = NULL;
return (ARCHIVE_OK);
}
static int64_t
-le4(const unsigned char *p)
+le32dec(const unsigned char *p)
{
- return ((p[0] << 16) | (((int64_t)p[1]) << 24) | (p[2] << 0) | (p[3] << 8));
+ return ((int64_t)archive_le16dec(p) << 16) | archive_le16dec(p + 2);
}
-
static int64_t
-be4(const unsigned char *p)
+be32dec(const unsigned char *p)
{
- return ((((int64_t)p[0]) << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]));
+ return ((int64_t)archive_be16dec(p) << 16) | archive_be16dec(p + 2);
}
/*
@@ -1051,7 +1070,7 @@ atol16u(const char *p, unsigned char_cnt)
else if (*p >= '0' && *p <= '9')
digit = *p - '0';
else
- return ((int64_t)l);
+ return (l);
p++;
l <<= 4;
l |= digit;
@@ -1102,20 +1121,32 @@ record_hardlink(struct archive_read *a,
ENOMEM, "Out of memory adding file to list");
return (ARCHIVE_FATAL);
}
- if (cpio->links_head != NULL)
- cpio->links_head->previous = le;
- le->next = cpio->links_head;
- le->previous = NULL;
- cpio->links_head = le;
+
+ const char *pathname = archive_entry_pathname(entry);
+ if (pathname == NULL) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid hardlink entry with no pathname");
+ free(le);
+ return (ARCHIVE_FATAL);
+ }
+
le->dev = dev;
le->ino = ino;
le->links = archive_entry_nlink(entry) - 1;
- le->name = strdup(archive_entry_pathname(entry));
+ le->name = strdup(pathname);
if (le->name == NULL) {
archive_set_error(&a->archive,
ENOMEM, "Out of memory adding file to list");
+ free(le);
return (ARCHIVE_FATAL);
}
+ if (cpio->links_head != NULL)
+ cpio->links_head->previous = le;
+ le->next = cpio->links_head;
+ le->previous = NULL;
+ cpio->links_head = le;
+
return (ARCHIVE_OK);
}
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_iso9660.c b/contrib/libarchive/libarchive/archive_read_support_format_iso9660.c
index c69fcd272bcd..c3da44c8266c 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_iso9660.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_iso9660.c
@@ -47,6 +47,7 @@
#include "archive_endian.h"
#include "archive_entry.h"
#include "archive_entry_locale.h"
+#include "archive_integer.h"
#include "archive_private.h"
#include "archive_read_private.h"
#include "archive_string.h"
@@ -268,6 +269,7 @@ struct file_info {
uint64_t size; /* File size in bytes. */
uint32_t ce_offset; /* Offset of CE. */
uint32_t ce_size; /* Size of CE. */
+ uint64_t ce_processed_end;/* End offset of processed CE. */
char rr_moved; /* Flag to rr_moved. */
char rr_moved_has_re_only;
char re; /* Having RRIP "RE" extension. */
@@ -313,8 +315,8 @@ struct file_info {
struct heap_queue {
struct file_info **files;
- int allocated;
- int used;
+ size_t allocated;
+ size_t used;
};
struct iso9660 {
@@ -336,8 +338,8 @@ struct iso9660 {
uint64_t offset;/* Offset of CE on disk. */
struct file_info *file;
} *reqs;
- int cnt;
- int allocated;
+ size_t cnt;
+ size_t allocated;
} read_ce_req;
int64_t previous_number;
@@ -378,8 +380,6 @@ struct iso9660 {
size_t utf16be_path_len;
unsigned char *utf16be_previous_path;
size_t utf16be_previous_path_len;
- /* Null buffer used in bidder to improve its performance. */
- unsigned char null[2048];
};
static int archive_read_format_iso9660_bid(struct archive_read *, int);
@@ -402,12 +402,12 @@ static time_t isodate17(const unsigned char *);
static int isodate17_valid(const unsigned char *);
static time_t isodate7(const unsigned char *);
static int isodate7_valid(const unsigned char *);
-static int isBootRecord(struct iso9660 *, const unsigned char *);
+static int isBootRecord(const unsigned char *);
static int isVolumePartition(struct iso9660 *, const unsigned char *);
-static int isVDSetTerminator(struct iso9660 *, const unsigned char *);
+static int isVDSetTerminator(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 isSVD(const unsigned char *);
+static int isEVD(const unsigned char *);
static int isPVD(struct iso9660 *, const unsigned char *);
static int isRootDirectoryRecord(const unsigned char *);
static int isValid723Integer(const unsigned char *);
@@ -436,7 +436,6 @@ 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 *);
@@ -503,7 +502,7 @@ archive_read_support_format_iso9660(struct archive *_a)
static int
archive_read_format_iso9660_bid(struct archive_read *a, int best_bid)
{
- struct iso9660 *iso9660;
+ struct iso9660 *iso9660 = a->format->data;
ssize_t bytes_read;
const unsigned char *p;
int seenTerminator;
@@ -513,8 +512,6 @@ archive_read_format_iso9660_bid(struct archive_read *a, int best_bid)
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,
@@ -547,15 +544,15 @@ archive_read_format_iso9660_bid(struct archive_read *a, int best_bid)
if (isJolietSVD(iso9660, p))
continue;
}
- if (isBootRecord(iso9660, p))
+ if (isBootRecord(p))
continue;
- if (isEVD(iso9660, p))
+ if (isEVD(p))
continue;
- if (isSVD(iso9660, p))
+ if (isSVD(p))
continue;
if (isVolumePartition(iso9660, p))
continue;
- if (isVDSetTerminator(iso9660, p)) {
+ if (isVDSetTerminator(p)) {
seenTerminator = 1;
break;
}
@@ -576,9 +573,7 @@ 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);
+ struct iso9660 *iso9660 = a->format->data;
if (strcmp(key, "joliet") == 0) {
if (val == NULL || strcmp(val, "off") == 0 ||
@@ -603,26 +598,23 @@ archive_read_format_iso9660_options(struct archive_read *a,
}
static int
-isNull(struct iso9660 *iso9660, const unsigned char *h, unsigned offset,
-unsigned bytes)
+isNull(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
+ if (bytes == 0)
return (1);
+
+ /*
+ * If the first byte is zero and every byte equals the following
+ * byte, the entire range is zero.
+ */
+ return (h[offset] == 0 &&
+ (bytes == 1 ||
+ memcmp(h + offset, h + offset + 1, bytes - 1) == 0));
}
static int
-isBootRecord(struct iso9660 *iso9660, const unsigned char *h)
+isBootRecord(const unsigned char *h)
{
- (void)iso9660; /* UNUSED */
/* Type of the Volume Descriptor Boot Record must be 0. */
if (h[0] != 0)
@@ -662,9 +654,8 @@ isVolumePartition(struct iso9660 *iso9660, const unsigned char *h)
}
static int
-isVDSetTerminator(struct iso9660 *iso9660, const unsigned char *h)
+isVDSetTerminator(const unsigned char *h)
{
- (void)iso9660; /* UNUSED */
/* Type of the Volume Descriptor Set Terminator must be 255. */
if (h[0] != 255)
@@ -675,7 +666,7 @@ isVDSetTerminator(struct iso9660 *iso9660, const unsigned char *h)
return (0);
/* Reserved field must be 0. */
- if (!isNull(iso9660, h, 7, 2048-7))
+ if (!isNull(h, 7, 2048-7))
return (0);
return (1);
@@ -690,7 +681,7 @@ isJolietSVD(struct iso9660 *iso9660, const unsigned char *h)
/* Check if current sector is a kind of Supplementary Volume
* Descriptor. */
- if (!isSVD(iso9660, h))
+ if (!isSVD(h))
return (0);
/* FIXME: do more validations according to joliet spec. */
@@ -731,25 +722,24 @@ isJolietSVD(struct iso9660 *iso9660, const unsigned char *h)
}
static int
-isSVD(struct iso9660 *iso9660, const unsigned char *h)
+isSVD(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))
+ if (!isNull(h, SVD_reserved1_offset, SVD_reserved1_size))
return (0);
- if (!isNull(iso9660, h, SVD_reserved2_offset, SVD_reserved2_size))
+ if (!isNull(h, SVD_reserved2_offset, SVD_reserved2_size))
return (0);
- if (!isNull(iso9660, h, SVD_reserved3_offset, SVD_reserved3_size))
+ if (!isNull(h, SVD_reserved3_offset, SVD_reserved3_size))
return (0);
/* File structure version must be 1 for ISO9660/ECMA119. */
@@ -791,14 +781,13 @@ isSVD(struct iso9660 *iso9660, const unsigned char *h)
}
static int
-isEVD(struct iso9660 *iso9660, const unsigned char *h)
+isEVD(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)
@@ -813,11 +802,11 @@ isEVD(struct iso9660 *iso9660, const unsigned char *h)
return (0);
/* Reserved field must be 0. */
- if (!isNull(iso9660, h, PVD_reserved2_offset, PVD_reserved2_size))
+ if (!isNull(h, PVD_reserved2_offset, PVD_reserved2_size))
return (0);
/* Reserved field must be 0. */
- if (!isNull(iso9660, h, PVD_reserved3_offset, PVD_reserved3_size))
+ if (!isNull(h, PVD_reserved3_offset, PVD_reserved3_size))
return (0);
/* Logical block size must be > 0. */
@@ -853,11 +842,11 @@ isEVD(struct iso9660 *iso9660, const unsigned char *h)
return (0);
/* Reserved field must be 0. */
- if (!isNull(iso9660, h, PVD_reserved4_offset, PVD_reserved4_size))
+ if (!isNull(h, PVD_reserved4_offset, PVD_reserved4_size))
return (0);
/* Reserved field must be 0. */
- if (!isNull(iso9660, h, PVD_reserved5_offset, PVD_reserved5_size))
+ if (!isNull(h, PVD_reserved5_offset, PVD_reserved5_size))
return (0);
/* Read Root Directory Record in Volume Descriptor. */
@@ -891,7 +880,7 @@ isPVD(struct iso9660 *iso9660, const unsigned char *h)
return (0);
/* Reserved field must be 0. */
- if (!isNull(iso9660, h, PVD_reserved2_offset, PVD_reserved2_size))
+ if (!isNull(h, PVD_reserved2_offset, PVD_reserved2_size))
return (0);
/* Volume space size must be encoded according to 7.3.3 */
@@ -903,7 +892,7 @@ isPVD(struct iso9660 *iso9660, const unsigned char *h)
return (0);
/* Reserved field must be 0. */
- if (!isNull(iso9660, h, PVD_reserved3_offset, PVD_reserved3_size))
+ if (!isNull(h, PVD_reserved3_offset, PVD_reserved3_size))
return (0);
/* Volume set size must be encoded according to 7.2.3 */
@@ -961,7 +950,7 @@ isPVD(struct iso9660 *iso9660, const unsigned char *h)
return (0);
/* Reserved field must be 0. */
- if (!isNull(iso9660, h, PVD_reserved5_offset, PVD_reserved5_size))
+ if (!isNull(h, PVD_reserved5_offset, PVD_reserved5_size))
return (0);
/* XXX TODO: Check other values for sanity; reject more
@@ -1034,12 +1023,11 @@ isRootDirectoryRecord(const unsigned char *p) {
static int
read_children(struct archive_read *a, struct file_info *parent)
{
- struct iso9660 *iso9660;
+ struct iso9660 *iso9660 = a->format->data;
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) {
@@ -1086,7 +1074,7 @@ read_children(struct archive_read *a, struct file_info *parent)
p = b;
b += iso9660->logical_block_size;
step -= iso9660->logical_block_size;
- for (; *p != 0 && p + DR_name_offset < b && p + *p <= b;
+ for (; p < b && b - p > DR_name_offset && *p != 0 && *p <= b - p;
p += *p) {
struct file_info *child;
@@ -1247,12 +1235,10 @@ static int
archive_read_format_iso9660_read_header(struct archive_read *a,
struct archive_entry *entry)
{
- struct iso9660 *iso9660;
+ struct iso9660 *iso9660 = a->format->data;
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";
@@ -1499,7 +1485,7 @@ static int
zisofs_read_data(struct archive_read *a,
const void **buff, size_t *size, int64_t *offset)
{
- struct iso9660 *iso9660;
+ struct iso9660 *iso9660 = a->format->data;
struct zisofs *zisofs;
const unsigned char *p;
size_t avail;
@@ -1507,7 +1493,6 @@ zisofs_read_data(struct archive_read *a,
size_t uncompressed_size;
int r;
- iso9660 = (struct iso9660 *)(a->format->data);
zisofs = &iso9660->entry_zisofs;
p = __archive_read_ahead(a, 1, &bytes_read);
@@ -1738,10 +1723,8 @@ static int
archive_read_format_iso9660_read_data(struct archive_read *a,
const void **buff, size_t *size, int64_t *offset)
{
+ struct iso9660 *iso9660 = a->format->data;
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);
@@ -1805,10 +1788,9 @@ archive_read_format_iso9660_read_data(struct archive_read *a,
static int
archive_read_format_iso9660_cleanup(struct archive_read *a)
{
- struct iso9660 *iso9660;
+ struct iso9660 *iso9660 = a->format->data;
int r = ARCHIVE_OK;
- iso9660 = (struct iso9660 *)(a->format->data);
release_files(iso9660);
free(iso9660->read_ce_req.reqs);
archive_string_free(&iso9660->pathname);
@@ -1828,7 +1810,7 @@ archive_read_format_iso9660_cleanup(struct archive_read *a)
free(iso9660->utf16be_path);
free(iso9660->utf16be_previous_path);
free(iso9660);
- (a->format->data) = NULL;
+ a->format->data = NULL;
return (r);
}
@@ -1840,7 +1822,7 @@ static struct file_info *
parse_file_info(struct archive_read *a, struct file_info *parent,
const unsigned char *isodirrec, size_t reclen)
{
- struct iso9660 *iso9660;
+ struct iso9660 *iso9660 = a->format->data;
struct file_info *file, *filep;
size_t name_len;
const unsigned char *rr_start, *rr_end;
@@ -1850,8 +1832,6 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
int32_t location;
int flags;
- iso9660 = (struct iso9660 *)(a->format->data);
-
if (reclen != 0)
dr_len = (size_t)isodirrec[DR_length_offset];
/*
@@ -1865,7 +1845,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
}
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);
+ fsize = archive_le32dec(isodirrec + DR_size_offset);
/* 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,
@@ -2162,7 +2142,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
fprintf(stderr, "\n ** Unrecognized flag: ");
dump_isodirrec(stderr, isodirrec);
fprintf(stderr, "\n");
- } else if (toi(isodirrec + DR_volume_sequence_number_offset, 2) != 1) {
+ } else if (archive_le16dec(isodirrec + DR_volume_sequence_number_offset) != 1) {
fprintf(stderr, "\n ** Unrecognized sequence number: ");
dump_isodirrec(stderr, isodirrec);
fprintf(stderr, "\n");
@@ -2192,11 +2172,9 @@ static int
parse_rockridge(struct archive_read *a, struct file_info *file,
const unsigned char *p, const unsigned char *end)
{
- struct iso9660 *iso9660;
+ struct iso9660 *iso9660 = a->format->data;
int entry_seen = 0;
- 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. */
@@ -2255,9 +2233,10 @@ parse_rockridge(struct archive_read *a, struct file_info *file,
*/
if (p[1] == 'N') {
if (version == 1 && data_length == 16) {
- file->rdev = toi(data,4);
+ file->rdev = archive_le32dec(data);
file->rdev <<= 32;
- file->rdev |= toi(data + 8, 4);
+ file->rdev |=
+ archive_le32dec(data + 8);
iso9660->seenRockridge = 1;
}
}
@@ -2272,20 +2251,20 @@ parse_rockridge(struct archive_read *a, struct file_info *file,
*/
if (version == 1) {
if (data_length >= 8)
- file->mode
- = (__LA_MODE_T)toi(data, 4);
+ file->mode = (__LA_MODE_T)
+ archive_le32dec(data);
if (data_length >= 16)
- file->nlinks
- = toi(data + 8, 4);
+ file->nlinks =
+ archive_le32dec(data + 8);
if (data_length >= 24)
- file->uid
- = toi(data + 16, 4);
+ file->uid =
+ archive_le32dec(data + 16);
if (data_length >= 32)
- file->gid
- = toi(data + 24, 4);
+ file->gid =
+ archive_le32dec(data + 24);
if (data_length >= 40)
- file->number
- = toi(data + 32, 4);
+ file->number =
+ archive_le32dec(data + 32);
iso9660->seenRockridge = 1;
}
}
@@ -2365,13 +2344,11 @@ static int
register_CE(struct archive_read *a, int32_t location,
struct file_info *file)
{
- struct iso9660 *iso9660;
+ struct iso9660 *iso9660 = a->format->data;
struct read_ce_queue *heap;
- struct read_ce_req *p;
uint64_t offset, parent_offset;
- int hole, parent;
+ size_t 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) ||
@@ -2388,14 +2365,13 @@ register_CE(struct archive_read *a, int32_t location,
/* Expand our CE list as necessary. */
heap = &(iso9660->read_ce_req);
if (heap->cnt >= heap->allocated) {
- int new_size;
+ struct read_ce_req *p;
+ size_t 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) {
+ else if (archive_ckd_mul_size(&new_size, heap->allocated, 2)) {
+ /* Overflow keeps us from growing the list. */
archive_set_error(&a->archive, ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
@@ -2437,7 +2413,7 @@ static void
next_CE(struct read_ce_queue *heap)
{
uint64_t a_offset, b_offset, c_offset;
- int a, b, c;
+ size_t a, b, c;
struct read_ce_req tmp;
if (heap->cnt < 1)
@@ -2483,6 +2459,7 @@ read_CE(struct archive_read *a, struct iso9660 *iso9660)
const unsigned char *b, *p, *end;
struct file_info *file;
size_t step;
+ uint64_t ce_start, ce_end;
int r;
/* Read data which RRIP "CE" extension points. */
@@ -2506,8 +2483,16 @@ read_CE(struct archive_read *a, struct iso9660 *iso9660)
"Malformed CE information");
return (ARCHIVE_FATAL);
}
+ ce_start = heap->reqs[0].offset + file->ce_offset;
+ ce_end = ce_start + file->ce_size;
+ if (ce_start < file->ce_processed_end) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Invalid parameter in SUSP \"CE\" extension");
+ return (ARCHIVE_FATAL);
+ }
p = b + file->ce_offset;
end = p + file->ce_size;
+ file->ce_processed_end = ce_end;
next_CE(heap);
r = parse_rockridge(a, file, p, end);
if (r != ARCHIVE_OK)
@@ -2755,7 +2740,7 @@ parse_rockridge_ZF1(struct file_info *file, const unsigned char *data,
int data_length)
{
- if (data[0] == 0x70 && data[1] == 0x7a && data_length == 12) {
+ if (data_length == 12 && data[0] == 0x70 && data[1] == 0x7a) {
/* paged zlib */
file->pz = 1;
file->pz_log2_bs = data[3];
@@ -3134,7 +3119,7 @@ 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;
+ size_t hole, parent;
/* Reserve 16 bits for possible key collisions (needed for linked items) */
/* For ISO files with more than 65535 entries, reordering will still occur */
@@ -3144,12 +3129,12 @@ heap_add_entry(struct archive_read *a, struct heap_queue *heap,
/* Expand our pending files list as necessary. */
if (heap->used >= heap->allocated) {
struct file_info **new_pending_files;
- int new_size = heap->allocated * 2;
+ size_t new_size;
if (heap->allocated < 1024)
new_size = 1024;
- /* Overflow might keep us from growing the list. */
- if (new_size <= heap->allocated) {
+ else if (archive_ckd_mul_size(&new_size, heap->allocated, 2)) {
+ /* Overflow keeps us from growing the list. */
archive_set_error(&a->archive,
ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
@@ -3176,7 +3161,7 @@ heap_add_entry(struct archive_read *a, struct heap_queue *heap,
*/
hole = heap->used++;
while (hole > 0) {
- parent = (hole - 1)/2;
+ parent = (hole - 1) / 2;
parent_key = heap->files[parent]->key;
if (file_key >= parent_key) {
heap->files[hole] = file;
@@ -3195,7 +3180,7 @@ static struct file_info *
heap_get_entry(struct heap_queue *heap)
{
uint64_t a_key, b_key, c_key;
- int a, b, c;
+ size_t a, b, c;
struct file_info *r, *tmp;
if (heap->used < 1)
@@ -3238,17 +3223,6 @@ heap_get_entry(struct heap_queue *heap)
}
}
-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);
-}
-
/*
* ECMA119/ISO9660 stores multi-byte integers in one of
* three different formats:
@@ -3493,6 +3467,8 @@ build_pathname_utf16be(unsigned char *p, size_t max, size_t *len,
if (file->parent != NULL && file->parent->utf16be_bytes > 0) {
if (build_pathname_utf16be(p, max, len, file->parent) != 0)
return (-1);
+ if (*len + 2 > max)
+ return (-1);/* Path is too long! */
p[*len] = 0;
p[*len + 1] = '/';
*len += 2;
@@ -3517,26 +3493,24 @@ static void
dump_isodirrec(FILE *out, const unsigned char *isodirrec)
{
fprintf(out, " l %d,",
- toi(isodirrec + DR_length_offset, DR_length_size));
+ isodirrec[DR_length_offset]);
fprintf(out, " a %d,",
- toi(isodirrec + DR_ext_attr_length_offset, DR_ext_attr_length_size));
+ isodirrec[DR_ext_attr_length_offset]);
fprintf(out, " ext 0x%x,",
- toi(isodirrec + DR_extent_offset, DR_extent_size));
+ archive_le32dec(isodirrec + DR_extent_offset));
fprintf(out, " s %d,",
- toi(isodirrec + DR_size_offset, DR_extent_size));
+ archive_le32dec(isodirrec + DR_size_offset));
fprintf(out, " f 0x%x,",
- toi(isodirrec + DR_flags_offset, DR_flags_size));
+ isodirrec[DR_flags_offset]);
fprintf(out, " u %d,",
- toi(isodirrec + DR_file_unit_size_offset, DR_file_unit_size_size));
+ isodirrec[DR_file_unit_size_offset]);
fprintf(out, " ilv %d,",
- toi(isodirrec + DR_interleave_offset, DR_interleave_size));
+ isodirrec[DR_interleave_offset]);
fprintf(out, " seq %d,",
- toi(isodirrec + DR_volume_sequence_number_offset,
- DR_volume_sequence_number_size));
+ archive_le16dec(isodirrec + DR_volume_sequence_number_offset));
fprintf(out, " nl %d:",
- toi(isodirrec + DR_name_len_offset, DR_name_len_size));
+ isodirrec[DR_name_len_offset]);
fprintf(out, " `%.*s'",
- toi(isodirrec + DR_name_len_offset, DR_name_len_size),
- isodirrec + DR_name_offset);
+ isodirrec[DR_name_len_offset], isodirrec + DR_name_offset);
}
#endif
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_lha.c b/contrib/libarchive/libarchive/archive_read_support_format_lha.c
index ff6dbb8df1cd..0a475461576d 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_lha.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_lha.c
@@ -107,8 +107,8 @@ struct lzh_dec {
unsigned char *bitlen;
/*
- * Use a index table. It's faster than searching a huffman
- * coding tree, which is a binary tree. But a use of a large
+ * Use an index table. It's faster than searching a huffman
+ * coding tree, which is a binary tree. But usage of a large
* index table causes L1 cache read miss many times.
*/
#define HTBL_BITS 10
@@ -142,7 +142,6 @@ struct lzh_stream {
int64_t total_in;
const unsigned char *ref_ptr;
int avail_out;
- int64_t total_out;
struct lzh_dec *ds;
};
@@ -239,7 +238,6 @@ static int lha_read_data_none(struct archive_read *, const void **,
size_t *, int64_t *);
static int lha_read_data_lzh(struct archive_read *, const void **,
size_t *, int64_t *);
-static void lha_crc16_init(void);
static uint16_t lha_crc16(uint16_t, const void *, size_t);
static int lzh_decode_init(struct lzh_stream *, const char *);
static void lzh_decode_free(struct lzh_stream *);
@@ -392,10 +390,9 @@ static int
archive_read_format_lha_options(struct archive_read *a,
const char *key, const char *val)
{
- struct lha *lha;
+ struct lha *lha = a->format->data;
int ret = ARCHIVE_FAILED;
- lha = (struct lha *)(a->format->data);
if (strcmp(key, "hdrcharset") == 0) {
if (val == NULL || val[0] == 0)
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
@@ -474,22 +471,19 @@ static int
archive_read_format_lha_read_header(struct archive_read *a,
struct archive_entry *entry)
{
+ struct lha *lha = a->format->data;
struct archive_wstring linkname;
struct archive_wstring pathname;
- struct lha *lha;
const unsigned char *p;
const char *signature;
int err;
struct archive_mstring conv_buffer;
const wchar_t *conv_buffer_p;
- lha_crc16_init();
-
a->archive.archive_format = ARCHIVE_FORMAT_LHA;
if (a->archive.archive_format_name == NULL)
a->archive.archive_format_name = "lha";
- lha = (struct lha *)(a->format->data);
lha->decompress_init = 0;
lha->end_of_entry = 0;
lha->end_of_entry_cleanup = 0;
@@ -904,7 +898,7 @@ lha_read_file_header_1(struct archive_read *a, struct lha *lha)
{
const unsigned char *p;
size_t extdsize;
- int i, err, err2;
+ int err, err2;
int namelen, padding;
unsigned char headersum, sum_calculated;
@@ -929,10 +923,9 @@ lha_read_file_header_1(struct archive_read *a, struct lha *lha)
if ((p = __archive_read_ahead(a, lha->header_size, NULL)) == NULL)
return (truncated_error(a));
- for (i = 0; i < namelen; i++) {
- if (p[i + H1_FILE_NAME_OFFSET] == 0xff)
- goto invalid;/* Invalid filename. */
- }
+ if (memchr(p + H1_FILE_NAME_OFFSET, 0xff,
+ (size_t)namelen) != NULL)
+ goto invalid; /* Invalid filename. */
archive_strncpy(&lha->filename, p + H1_FILE_NAME_OFFSET, namelen);
lha->crc = archive_le16dec(p + H1_FILE_NAME_OFFSET + namelen);
lha->setflag |= CRC_IS_SET;
@@ -1101,7 +1094,7 @@ lha_read_file_header_3(struct archive_read *a, struct lha *lha)
header_crc = lha_crc16(0, p, H3_FIXED_SIZE);
__archive_read_consume(a, H3_FIXED_SIZE);
- /* Reject rediculously large header */
+ /* Reject ridiculously large header */
if (lha->header_size > 65536) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"LHa header size too large");
@@ -1456,7 +1449,7 @@ invalid:
static int
lha_end_of_entry(struct archive_read *a)
{
- struct lha *lha = (struct lha *)(a->format->data);
+ struct lha *lha = a->format->data;
int r = ARCHIVE_EOF;
if (!lha->end_of_entry_cleanup) {
@@ -1477,7 +1470,7 @@ static int
archive_read_format_lha_read_data(struct archive_read *a,
const void **buff, size_t *size, int64_t *offset)
{
- struct lha *lha = (struct lha *)(a->format->data);
+ struct lha *lha = a->format->data;
int r;
if (lha->entry_unconsumed) {
@@ -1510,7 +1503,7 @@ static int
lha_read_data_none(struct archive_read *a, const void **buff,
size_t *size, int64_t *offset)
{
- struct lha *lha = (struct lha *)(a->format->data);
+ struct lha *lha = a->format->data;
ssize_t bytes_avail;
if (lha->entry_bytes_remaining == 0) {
@@ -1557,7 +1550,7 @@ static int
lha_read_data_lzh(struct archive_read *a, const void **buff,
size_t *size, int64_t *offset)
{
- struct lha *lha = (struct lha *)(a->format->data);
+ struct lha *lha = a->format->data;
ssize_t bytes_avail;
int r;
@@ -1588,7 +1581,6 @@ lha_read_data_lzh(struct archive_read *a, const void **buff,
/* We've initialized decompression for this stream. */
lha->decompress_init = 1;
lha->strm.avail_out = 0;
- lha->strm.total_out = 0;
}
/*
@@ -1648,11 +1640,9 @@ lha_read_data_lzh(struct archive_read *a, const void **buff,
static int
archive_read_format_lha_read_data_skip(struct archive_read *a)
{
- struct lha *lha;
+ struct lha *lha = a->format->data;
int64_t bytes_skipped;
- lha = (struct lha *)(a->format->data);
-
if (lha->entry_unconsumed) {
/* Consume as much as the decompressor actually used. */
__archive_read_consume(a, lha->entry_unconsumed);
@@ -1679,7 +1669,7 @@ archive_read_format_lha_read_data_skip(struct archive_read *a)
static int
archive_read_format_lha_cleanup(struct archive_read *a)
{
- struct lha *lha = (struct lha *)(a->format->data);
+ struct lha *lha = a->format->data;
lzh_decode_free(&(lha->strm));
archive_string_free(&(lha->dirname));
@@ -1688,7 +1678,7 @@ archive_read_format_lha_cleanup(struct archive_read *a)
archive_string_free(&(lha->gname));
archive_wstring_free(&(lha->ws));
free(lha);
- (a->format->data) = NULL;
+ a->format->data = NULL;
return (ARCHIVE_OK);
}
@@ -1733,30 +1723,86 @@ lha_calcsum(unsigned char sum, const void *pp, int offset, size_t size)
return (sum);
}
-static uint16_t crc16tbl[2][256];
-static void
-lha_crc16_init(void)
-{
- unsigned int i;
- static int crc16init = 0;
-
- if (crc16init)
- return;
- crc16init = 1;
-
- for (i = 0; i < 256; i++) {
- unsigned int j;
- uint16_t crc = (uint16_t)i;
- for (j = 8; j; j--)
- crc = (crc >> 1) ^ ((crc & 1) * 0xA001);
- crc16tbl[0][i] = crc;
+static const uint16_t crc16tbl[2][256] = {
+ {
+ 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280,
+ 0xc241, 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1,
+ 0xc481, 0x0440, 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00,
+ 0xcfc1, 0xce81, 0x0e40, 0x0a00, 0xcac1, 0xcb81, 0x0b40,
+ 0xc901, 0x09c0, 0x0880, 0xc841, 0xd801, 0x18c0, 0x1980,
+ 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, 0x1e00, 0xdec1,
+ 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, 0x1400,
+ 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
+ 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081,
+ 0x1040, 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1,
+ 0xf281, 0x3240, 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501,
+ 0x35c0, 0x3480, 0xf441, 0x3c00, 0xfcc1, 0xfd81, 0x3d40,
+ 0xff01, 0x3fc0, 0x3e80, 0xfe41, 0xfa01, 0x3ac0, 0x3b80,
+ 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, 0x2800, 0xe8c1,
+ 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, 0xee01,
+ 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
+ 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681,
+ 0x2640, 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0,
+ 0x2080, 0xe041, 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300,
+ 0xa3c1, 0xa281, 0x6240, 0x6600, 0xa6c1, 0xa781, 0x6740,
+ 0xa501, 0x65c0, 0x6480, 0xa441, 0x6c00, 0xacc1, 0xad81,
+ 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, 0xaa01, 0x6ac0,
+ 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, 0x7800,
+ 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
+ 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81,
+ 0x7c40, 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1,
+ 0xb681, 0x7640, 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101,
+ 0x71c0, 0x7080, 0xb041, 0x5000, 0x90c1, 0x9181, 0x5140,
+ 0x9301, 0x53c0, 0x5280, 0x9241, 0x9601, 0x56c0, 0x5780,
+ 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, 0x9c01, 0x5cc0,
+ 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, 0x5a00,
+ 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
+ 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81,
+ 0x4a40, 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0,
+ 0x4c80, 0x8c41, 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701,
+ 0x47c0, 0x4680, 0x8641, 0x8201, 0x42c0, 0x4380, 0x8341,
+ 0x4100, 0x81c1, 0x8081, 0x4040
+ },
+ {
+ 0x0000, 0x9001, 0x6001, 0xf000, 0xc002, 0x5003, 0xa003,
+ 0x3002, 0xc007, 0x5006, 0xa006, 0x3007, 0x0005, 0x9004,
+ 0x6004, 0xf005, 0xc00d, 0x500c, 0xa00c, 0x300d, 0x000f,
+ 0x900e, 0x600e, 0xf00f, 0x000a, 0x900b, 0x600b, 0xf00a,
+ 0xc008, 0x5009, 0xa009, 0x3008, 0xc019, 0x5018, 0xa018,
+ 0x3019, 0x001b, 0x901a, 0x601a, 0xf01b, 0x001e, 0x901f,
+ 0x601f, 0xf01e, 0xc01c, 0x501d, 0xa01d, 0x301c, 0x0014,
+ 0x9015, 0x6015, 0xf014, 0xc016, 0x5017, 0xa017, 0x3016,
+ 0xc013, 0x5012, 0xa012, 0x3013, 0x0011, 0x9010, 0x6010,
+ 0xf011, 0xc031, 0x5030, 0xa030, 0x3031, 0x0033, 0x9032,
+ 0x6032, 0xf033, 0x0036, 0x9037, 0x6037, 0xf036, 0xc034,
+ 0x5035, 0xa035, 0x3034, 0x003c, 0x903d, 0x603d, 0xf03c,
+ 0xc03e, 0x503f, 0xa03f, 0x303e, 0xc03b, 0x503a, 0xa03a,
+ 0x303b, 0x0039, 0x9038, 0x6038, 0xf039, 0x0028, 0x9029,
+ 0x6029, 0xf028, 0xc02a, 0x502b, 0xa02b, 0x302a, 0xc02f,
+ 0x502e, 0xa02e, 0x302f, 0x002d, 0x902c, 0x602c, 0xf02d,
+ 0xc025, 0x5024, 0xa024, 0x3025, 0x0027, 0x9026, 0x6026,
+ 0xf027, 0x0022, 0x9023, 0x6023, 0xf022, 0xc020, 0x5021,
+ 0xa021, 0x3020, 0xc061, 0x5060, 0xa060, 0x3061, 0x0063,
+ 0x9062, 0x6062, 0xf063, 0x0066, 0x9067, 0x6067, 0xf066,
+ 0xc064, 0x5065, 0xa065, 0x3064, 0x006c, 0x906d, 0x606d,
+ 0xf06c, 0xc06e, 0x506f, 0xa06f, 0x306e, 0xc06b, 0x506a,
+ 0xa06a, 0x306b, 0x0069, 0x9068, 0x6068, 0xf069, 0x0078,
+ 0x9079, 0x6079, 0xf078, 0xc07a, 0x507b, 0xa07b, 0x307a,
+ 0xc07f, 0x507e, 0xa07e, 0x307f, 0x007d, 0x907c, 0x607c,
+ 0xf07d, 0xc075, 0x5074, 0xa074, 0x3075, 0x0077, 0x9076,
+ 0x6076, 0xf077, 0x0072, 0x9073, 0x6073, 0xf072, 0xc070,
+ 0x5071, 0xa071, 0x3070, 0x0050, 0x9051, 0x6051, 0xf050,
+ 0xc052, 0x5053, 0xa053, 0x3052, 0xc057, 0x5056, 0xa056,
+ 0x3057, 0x0055, 0x9054, 0x6054, 0xf055, 0xc05d, 0x505c,
+ 0xa05c, 0x305d, 0x005f, 0x905e, 0x605e, 0xf05f, 0x005a,
+ 0x905b, 0x605b, 0xf05a, 0xc058, 0x5059, 0xa059, 0x3058,
+ 0xc049, 0x5048, 0xa048, 0x3049, 0x004b, 0x904a, 0x604a,
+ 0xf04b, 0x004e, 0x904f, 0x604f, 0xf04e, 0xc04c, 0x504d,
+ 0xa04d, 0x304c, 0x0044, 0x9045, 0x6045, 0xf044, 0xc046,
+ 0x5047, 0xa047, 0x3046, 0xc043, 0x5042, 0xa042, 0x3043,
+ 0x0041, 0x9040, 0x6040, 0xf041
}
-
- for (i = 0; i < 256; i++) {
- crc16tbl[1][i] = (crc16tbl[0][i] >> 8)
- ^ crc16tbl[0][crc16tbl[0][i] & 0xff];
- }
-}
+};
static uint16_t
lha_crc16(uint16_t crc, const void *pp, size_t len)
@@ -2084,7 +2130,6 @@ lzh_emit_window(struct lzh_stream *strm, size_t s)
{
strm->ref_ptr = strm->ds->w_buff;
strm->avail_out = (int)s;
- strm->total_out += s;
}
static int
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_mtree.c b/contrib/libarchive/libarchive/archive_read_support_format_mtree.c
index 4a5a49ca8136..dab580a30376 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_mtree.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_mtree.c
@@ -51,6 +51,7 @@
#include "archive.h"
#include "archive_entry.h"
#include "archive_entry_private.h"
+#include "archive_integer.h"
#include "archive_platform_stat.h"
#include "archive_private.h"
#include "archive_rb.h"
@@ -140,56 +141,6 @@ static int64_t mtree_atol(char **, int base);
static size_t mtree_strnlen(const char *, size_t);
#endif
-/*
- * There's no standard for TIME_T_MAX/TIME_T_MIN. So we compute them
- * here. TODO: Move this to configure time, but be careful
- * about cross-compile environments.
- */
-static int64_t
-get_time_t_max(void)
-{
-#if defined(TIME_T_MAX)
- return TIME_T_MAX;
-#else
- /* ISO C allows time_t to be a floating-point type,
- but POSIX requires an integer type. The following
- should work on any system that follows the POSIX
- conventions. */
- if (((time_t)0) < ((time_t)-1)) {
- /* Time_t is unsigned */
- return (~(time_t)0);
- } else {
- /* Time_t is signed. */
- /* Assume it's the same as int64_t or int32_t */
- if (sizeof(time_t) == sizeof(int64_t)) {
- return (time_t)INT64_MAX;
- } else {
- return (time_t)INT32_MAX;
- }
- }
-#endif
-}
-
-static int64_t
-get_time_t_min(void)
-{
-#if defined(TIME_T_MIN)
- return TIME_T_MIN;
-#else
- if (((time_t)0) < ((time_t)-1)) {
- /* Time_t is unsigned */
- return (time_t)0;
- } else {
- /* Time_t is signed. */
- if (sizeof(time_t) == sizeof(int64_t)) {
- return (time_t)INT64_MIN;
- } else {
- return (time_t)INT32_MIN;
- }
- }
-#endif
-}
-
#ifdef HAVE_STRNLEN
#define mtree_strnlen(a,b) strnlen(a,b)
#else
@@ -198,12 +149,10 @@ mtree_strnlen(const char *p, size_t maxlen)
{
size_t i;
- for (i = 0; i <= maxlen; i++) {
+ for (i = 0; i < maxlen; i++) {
if (p[i] == 0)
break;
}
- if (i > maxlen)
- return (-1);/* invalid */
return (i);
}
#endif
@@ -212,9 +161,8 @@ static int
archive_read_format_mtree_options(struct archive_read *a,
const char *key, const char *val)
{
- struct mtree *mtree;
+ struct mtree *mtree = a->format->data;
- mtree = (struct mtree *)(a->format->data);
if (strcmp(key, "checkfs") == 0) {
/* Allows to read information missing from the mtree from the file system */
if (val == NULL || val[0] == 0) {
@@ -296,11 +244,9 @@ archive_read_support_format_mtree(struct archive *_a)
static int
cleanup(struct archive_read *a)
{
- struct mtree *mtree;
+ struct mtree *mtree = a->format->data;
struct mtree_entry *p, *q;
- mtree = (struct mtree *)(a->format->data);
-
/* Close any dangling file descriptor before freeing */
if (mtree->fd >= 0) {
close(mtree->fd);
@@ -321,7 +267,7 @@ cleanup(struct archive_read *a)
free(mtree->buff);
free(mtree);
- (a->format->data) = NULL;
+ a->format->data = NULL;
return (ARCHIVE_OK);
}
@@ -386,7 +332,7 @@ next_line(struct archive_read *a,
*/
while (*nl == 0 && len == *avail && !quit) {
ssize_t diff = *ravail - *avail;
- size_t nbytes_req = (*ravail+1023) & ~1023U;
+ size_t nbytes_req = ((size_t)*ravail + 1023) & ~1023U;
ssize_t tested;
/*
@@ -875,7 +821,7 @@ process_global_set(struct archive_read *a,
line = next;
next = line + strcspn(line, " \t\r\n");
eq = strchr(line, '=');
- if (eq > next)
+ if (eq == NULL || eq > next)
len = next - line;
else
len = eq - line;
@@ -1120,12 +1066,10 @@ read_mtree(struct archive_read *a, struct mtree *mtree)
static int
read_header(struct archive_read *a, struct archive_entry *entry)
{
- struct mtree *mtree;
+ struct mtree *mtree = a->format->data;
char *p;
int r, use_next;
- mtree = (struct mtree *)(a->format->data);
-
if (mtree->fd >= 0) {
close(mtree->fd);
mtree->fd = -1;
@@ -1780,8 +1724,6 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
}
if (strcmp(key, "time") == 0) {
int64_t m;
- int64_t my_time_t_max = get_time_t_max();
- int64_t my_time_t_min = get_time_t_min();
long ns = 0;
*parsed_kws |= MTREE_HAS_MTIME;
@@ -1790,17 +1732,21 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
* 123456789.1 represents 123456789
* seconds and 1 nanosecond. */
if (*val == '.') {
+ int64_t v;
+
++val;
- ns = (long)mtree_atol(&val, 10);
- if (ns < 0)
+ v = mtree_atol(&val, 10);
+ if (v < 0)
ns = 0;
- else if (ns > 999999999)
+ else if (v > 999999999)
ns = 999999999;
+ else
+ ns = (long)v;
}
- if (m > my_time_t_max)
- m = my_time_t_max;
- else if (m < my_time_t_min)
- m = my_time_t_min;
+ if (m > TIME_MAX)
+ m = TIME_MAX;
+ else if (m < TIME_MIN)
+ m = TIME_MIN;
archive_entry_set_mtime(entry, (time_t)m, ns);
return (ARCHIVE_OK);
}
@@ -1887,11 +1833,10 @@ static int
read_data(struct archive_read *a, const void **buff, size_t *size,
int64_t *offset)
{
+ struct mtree *mtree = a->format->data;
size_t bytes_to_read;
ssize_t bytes_read;
- struct mtree *mtree;
- mtree = (struct mtree *)(a->format->data);
if (mtree->fd < 0) {
*buff = NULL;
*offset = 0;
@@ -1932,9 +1877,8 @@ read_data(struct archive_read *a, const void **buff, size_t *size,
static int
skip(struct archive_read *a)
{
- struct mtree *mtree;
+ struct mtree *mtree = a->format->data;
- mtree = (struct mtree *)(a->format->data);
if (mtree->fd >= 0) {
close(mtree->fd);
mtree->fd = -1;
@@ -2029,9 +1973,9 @@ parsedigit(char c)
if (c >= '0' && c <= '9')
return c - '0';
else if (c >= 'a' && c <= 'f')
- return c - 'a';
+ return 10 + c - 'a';
else if (c >= 'A' && c <= 'F')
- return c - 'A';
+ return 10 + c - 'A';
else
return -1;
}
@@ -2044,8 +1988,8 @@ parsedigit(char c)
static int64_t
mtree_atol(char **p, int base)
{
- int64_t l, limit;
- int digit, last_digit_limit;
+ int64_t l;
+ int digit;
if (base == 0) {
if (**p != '0')
@@ -2059,29 +2003,24 @@ mtree_atol(char **p, int base)
}
if (**p == '-') {
- limit = INT64_MIN / base;
- last_digit_limit = -(INT64_MIN % base);
++(*p);
l = 0;
digit = parsedigit(**p);
while (digit >= 0 && digit < base) {
- if (l < limit || (l == limit && digit >= last_digit_limit))
+ if (archive_ckd_mul_i64(&l, l, base) ||
+ archive_ckd_sub_i64(&l, l, digit))
return INT64_MIN;
- l = (l * base) - digit;
digit = parsedigit(*++(*p));
}
return l;
} else {
- limit = INT64_MAX / base;
- last_digit_limit = INT64_MAX % base;
-
l = 0;
digit = parsedigit(**p);
while (digit >= 0 && digit < base) {
- if (l > limit || (l == limit && digit > last_digit_limit))
+ if (archive_ckd_mul_i64(&l, l, base) ||
+ archive_ckd_add_i64(&l, l, digit))
return INT64_MAX;
- l = (l * base) + digit;
digit = parsedigit(*++(*p));
}
return l;
@@ -2100,8 +2039,7 @@ readline(struct archive_read *a, struct mtree *mtree, char **start,
ssize_t bytes_read;
ssize_t total_size = 0;
ssize_t find_off = 0;
- const void *t;
- void *nl;
+ const void *nl, *t;
char *u;
/* Accumulate line in a line buffer. */
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_rar.c b/contrib/libarchive/libarchive/archive_read_support_format_rar.c
index 0ed2540cd0a8..ff764f503042 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_rar.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_rar.c
@@ -42,6 +42,7 @@
#include "archive_endian.h"
#include "archive_entry.h"
#include "archive_entry_locale.h"
+#include "archive_integer.h"
#include "archive_ppmd7_private.h"
#include "archive_private.h"
#include "archive_read_private.h"
@@ -154,7 +155,7 @@
#define UNP_BUFFER_SIZE (128 * 1024)
/* Define this here for non-Windows platforms */
-#if !((defined(__WIN32__) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__))
+#ifndef FILE_ATTRIBUTE_DIRECTORY
#define FILE_ATTRIBUTE_DIRECTORY 0x10
#endif
@@ -201,8 +202,8 @@ struct huffman_table_entry
struct huffman_code
{
struct huffman_tree_node *tree;
- int numentries;
- int numallocatedentries;
+ size_t numentries;
+ size_t numallocatedentries;
int minlength;
int maxlength;
int tablesize;
@@ -227,8 +228,6 @@ struct rar_program_code
{
uint8_t *staticdata;
uint32_t staticdatalen;
- uint8_t *globalbackup;
- uint32_t globalbackuplen;
uint64_t fingerprint;
uint32_t usagecount;
uint32_t oldfilterlength;
@@ -499,7 +498,7 @@ static const uint32_t cache_masks[] = {
static int
rar_br_fillup(struct archive_read *a, struct rar_br *br)
{
- struct rar *rar = (struct rar *)(a->format->data);
+ struct rar *rar = a->format->data;
int n = CACHE_BITS - br->cache_avail;
for (;;) {
@@ -594,7 +593,7 @@ rar_br_fillup(struct archive_read *a, struct rar_br *br)
static int
rar_br_preparation(struct archive_read *a, struct rar_br *br)
{
- struct rar *rar = (struct rar *)(a->format->data);
+ struct rar *rar = a->format->data;
if (rar->bytes_remaining > 0) {
br->next_in = rar_read_ahead(a, 1, &(br->avail_in));
@@ -709,7 +708,7 @@ static Byte
ppmd_read(void *p)
{
struct archive_read *a = ((IByteIn*)p)->a;
- struct rar *rar = (struct rar *)(a->format->data);
+ struct rar *rar = a->format->data;
struct rar_br *br = &(rar->br);
Byte b;
if (!rar_br_read_ahead(a, br, 8))
@@ -777,7 +776,7 @@ 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;
+ struct rar *rar = _a->format->data;
if (rar) {
return rar->has_encrypted_entries;
}
@@ -877,10 +876,9 @@ static int
archive_read_format_rar_options(struct archive_read *a,
const char *key, const char *val)
{
- struct rar *rar;
+ struct rar *rar = a->format->data;
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,
@@ -907,9 +905,9 @@ static int
archive_read_format_rar_read_header(struct archive_read *a,
struct archive_entry *entry)
{
+ struct rar *rar = a->format->data;
const void *h;
const char *p;
- struct rar *rar;
int64_t skip;
char head_type;
int ret;
@@ -920,8 +918,6 @@ archive_read_format_rar_read_header(struct archive_read *a,
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
@@ -1100,7 +1096,7 @@ 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);
+ struct rar *rar = a->format->data;
int ret;
if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
@@ -1142,7 +1138,7 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff,
default:
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Unsupported compression method for RAR file");
- ret = ARCHIVE_FATAL;
+ ret = ARCHIVE_FAILED;
break;
}
return (ret);
@@ -1151,12 +1147,10 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff,
static int
archive_read_format_rar_read_data_skip(struct archive_read *a)
{
- struct rar *rar;
+ struct rar *rar = a->format->data;
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);
@@ -1189,9 +1183,9 @@ static int64_t
archive_read_format_rar_seek_data(struct archive_read *a, int64_t offset,
int whence)
{
+ struct rar *rar = a->format->data;
int64_t client_offset, ret;
size_t i;
- struct rar *rar = (struct rar *)(a->format->data);
if (rar->compression_method == COMPRESS_METHOD_STORE)
{
@@ -1294,6 +1288,12 @@ archive_read_format_rar_seek_data(struct archive_read *a, int64_t offset,
"Error during seek of RAR file");
return (ARCHIVE_FAILED);
}
+ if (rar->cursor == 0)
+ {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Invalid RAR seek cursor state");
+ return (ARCHIVE_FAILED);
+ }
client_offset += rar->dbo[rar->cursor].start_offset -
rar->dbo[rar->cursor-1].end_offset;
continue;
@@ -1342,9 +1342,8 @@ archive_read_format_rar_seek_data(struct archive_read *a, int64_t offset,
static int
archive_read_format_rar_cleanup(struct archive_read *a)
{
- struct rar *rar;
+ struct rar *rar = a->format->data;
- rar = (struct rar *)(a->format->data);
free_codes(a);
clear_filters(&rar->filters);
free(rar->filename);
@@ -1354,7 +1353,7 @@ archive_read_format_rar_cleanup(struct archive_read *a)
free(rar->lzss.window);
__archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context);
free(rar);
- (a->format->data) = NULL;
+ a->format->data = NULL;
return (ARCHIVE_OK);
}
@@ -1362,9 +1361,9 @@ static int
read_header(struct archive_read *a, struct archive_entry *entry,
char head_type)
{
+ struct rar *rar = a->format->data;
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;
@@ -1380,8 +1379,6 @@ read_header(struct archive_read *a, struct archive_entry *entry,
char *newptr;
size_t newsize;
- rar = (struct rar *)(a->format->data);
-
/* Setup a string conversion object for non-rar-unicode filenames. */
sconv = rar->opt_sconv;
if (sconv == NULL) {
@@ -1513,27 +1510,23 @@ read_header(struct archive_read *a, struct archive_entry *entry,
* consumed at the end.
*/
if (head_type == NEWSUB_HEAD) {
- size_t distance = p - (const char *)h;
if (rar->packed_size > INT64_MAX - header_size) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Extended header size too large");
+ "Invalid RAR file: Overlarge extended header");
return (ARCHIVE_FATAL);
}
- header_size += rar->packed_size;
- if ((uintmax_t)header_size > SIZE_MAX) {
+ if (__archive_read_consume(a, header_size + rar->packed_size - 7) < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Unable to read extended header data");
+ "Invalid RAR file: Cannot read extended header data");
return (ARCHIVE_FATAL);
}
- /* Make sure we have the extended data. */
- if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Failed to read extended header data");
- return (ARCHIVE_FATAL);
- }
- p = h;
- endp = p + header_size - 7;
- p += distance;
+
+ /*
+ * NEWSUB records are metadata-only in this reader. The block header
+ * has already been validated, so it is safe to skip exactly the
+ * remaining header bytes and the associated data payload.
+ */
+ return ret;
}
filename_size = archive_le16dec(file_header.name_size);
@@ -1672,16 +1665,18 @@ read_header(struct archive_read *a, struct archive_entry *entry,
return (ARCHIVE_FATAL);
}
fn_sconv = rar->sconv_utf8;
- while ((strp = strchr(filename, '\\')) != NULL)
- *strp = '/';
+ strp = filename;
+ while ((strp = strchr(strp, '\\')) != NULL)
+ *strp++ = '/';
p += filename_size;
}
}
else
{
fn_sconv = sconv;
- while ((strp = strchr(filename, '\\')) != NULL)
- *strp = '/';
+ strp = filename;
+ while ((strp = strchr(strp, '\\')) != NULL)
+ *strp++ = '/';
p += filename_size;
}
@@ -1829,10 +1824,6 @@ read_header(struct archive_read *a, struct archive_entry *entry,
rar->ppmd_valid = rar->ppmd_eod = 0;
rar->filters.filterstart = INT64_MAX;
- /* 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);
@@ -1970,12 +1961,11 @@ static int
read_symlink_stored(struct archive_read *a, struct archive_entry *entry,
struct archive_string_conv *sconv)
{
+ struct rar *rar = a->format->data;
const void *h;
const char *p;
- struct rar *rar;
int ret = (ARCHIVE_OK);
- rar = (struct rar *)(a->format->data);
if ((uintmax_t)rar->packed_size > SIZE_MAX)
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
@@ -2012,10 +2002,9 @@ static int
read_data_stored(struct archive_read *a, const void **buff, size_t *size,
int64_t *offset)
{
- struct rar *rar;
+ struct rar *rar = a->format->data;
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))
{
@@ -2026,7 +2015,7 @@ read_data_stored(struct archive_read *a, const void **buff, size_t *size,
#ifndef DONT_FAIL_ON_CRC_ERROR
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"File CRC error");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
#endif
}
rar->entry_eof = 1;
@@ -2038,7 +2027,7 @@ read_data_stored(struct archive_read *a, const void **buff, size_t *size,
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated RAR file data");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
*size = bytes_avail;
@@ -2058,18 +2047,16 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
int64_t *offset, size_t looper)
{
if (looper++ > MAX_COMPRESS_DEPTH)
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
- struct rar *rar;
+ struct rar *rar = a->format->data;
int64_t start, end;
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);
+ return (ARCHIVE_FAILED);
if (rar->filters.bytes_ready > 0)
{
@@ -2121,7 +2108,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
#ifndef DONT_FAIL_ON_CRC_ERROR
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"File CRC error");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
#endif
}
rar->entry_eof = 1;
@@ -2155,7 +2142,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
if (rar->filters.lastend == rar->filters.filterstart)
{
if (!run_filters(a))
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
continue;
}
@@ -2172,7 +2159,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid symbol");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
if(sym != rar->ppmd_escape)
{
@@ -2186,7 +2173,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid symbol");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
switch(code)
@@ -2213,7 +2200,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid symbol");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
lzss_offset |= code << (i * 8);
}
@@ -2222,7 +2209,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid symbol");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
lzss_emit_match(rar, lzss_offset + 2, length + 32);
rar->bytes_uncopied += length + 32;
@@ -2234,7 +2221,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid symbol");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
lzss_emit_match(rar, 1, length + 4);
rar->bytes_uncopied += length + 4;
@@ -2280,7 +2267,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
* what we would do to solve it. */
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Internal error extracting RAR file");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
}
if (rar->bytes_uncopied > (rar->unp_buffer_size - rar->unp_offset))
@@ -2311,11 +2298,11 @@ ending_block:
static int
parse_codes(struct archive_read *a)
{
+ struct rar *rar = a->format->data;
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);
@@ -2363,7 +2350,7 @@ parse_codes(struct archive_read *a)
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated RAR file data");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
/* Make sure ppmd7_context is freed before Ppmd7_Construct
@@ -2379,7 +2366,7 @@ parse_codes(struct archive_read *a)
if (rar->dictionary_size == 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid zero dictionary size");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
if (!__archive_ppmd7_functions.Ppmd7_Alloc(&rar->ppmd7_context,
@@ -2393,7 +2380,7 @@ parse_codes(struct archive_read *a)
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Unable to initialize PPMd range decoder");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
__archive_ppmd7_functions.Ppmd7_Init(&rar->ppmd7_context, maxorder);
rar->ppmd_valid = 1;
@@ -2403,13 +2390,13 @@ parse_codes(struct archive_read *a)
if (!rar->ppmd_valid) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid PPMd sequence");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
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);
+ return (ARCHIVE_FAILED);
}
}
}
@@ -2417,6 +2404,13 @@ parse_codes(struct archive_read *a)
{
rar_br_consume(br, 1);
+ /*
+ * Low-distance repeat state belongs to the current LZ table and
+ * must not be reused after starting a new table.
+ */
+ rar->lastlowoffset = 0;
+ rar->numlowoffsetrepeats = 0;
+
/* Keep existing table flag */
if (!rar_br_read_ahead(a, br, 1))
goto truncated_data;
@@ -2459,7 +2453,7 @@ parse_codes(struct archive_read *a)
if ((val = read_next_symbol(a, &precode)) < 0) {
free(precode.tree);
free(precode.table);
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
if (val < 16)
{
@@ -2474,7 +2468,7 @@ parse_codes(struct archive_read *a)
free(precode.table);
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Internal error extracting RAR file");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
if(val == 16) {
@@ -2564,7 +2558,7 @@ parse_codes(struct archive_read *a)
if (new_size == 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Zero window size is invalid");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
new_window = realloc(rar->lzss.window, new_size);
if (new_window == NULL) {
@@ -2584,13 +2578,13 @@ truncated_data:
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated RAR file data");
rar->valid = 0;
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
static void
free_codes(struct archive_read *a)
{
- struct rar *rar = (struct rar *)(a->format->data);
+ struct rar *rar = a->format->data;
free(rar->maincode.tree);
free(rar->offsetcode.tree);
free(rar->lowoffsetcode.tree);
@@ -2609,10 +2603,10 @@ free_codes(struct archive_read *a)
static int
read_next_symbol(struct archive_read *a, struct huffman_code *code)
{
+ struct rar *rar = a->format->data;
unsigned char bit;
unsigned int bits;
int length, value, node;
- struct rar *rar;
struct rar_br *br;
if (!code->table)
@@ -2621,7 +2615,6 @@ read_next_symbol(struct archive_read *a, struct huffman_code *code)
return -1;
}
- rar = (struct rar *)(a->format->data);
br = &(rar->br);
/* Look ahead (peek) at bits */
@@ -2700,7 +2693,7 @@ create_code(struct archive_read *a, struct huffman_code *code,
{
if (lengths[j] != i) continue;
if (add_value(a, code, j, codebits, i) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
codebits++;
if (--symbolsleft <= 0)
break;
@@ -2752,7 +2745,7 @@ add_value(struct archive_read *a, struct huffman_code *code, int value,
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Prefix found");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
/*
@@ -2811,7 +2804,7 @@ add_value(struct archive_read *a, struct huffman_code *code, int value,
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Prefix found");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
/* Set leaf value */
@@ -2826,11 +2819,16 @@ 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));
+ size_t size, new_num_entries;
+
+ if (code->numentries == 0)
+ new_num_entries = 256;
+ else if (archive_ckd_mul_size(&new_num_entries, code->numentries, 2)
+ || new_num_entries > INT_MAX)
+ return -1;
+ if (archive_ckd_mul_size(&size, new_num_entries, sizeof(*code->tree)))
+ return -1;
+ new_tree = realloc(code->tree, size);
if (new_tree == NULL)
return (-1);
code->tree = (struct huffman_tree_node *)new_tree;
@@ -2850,6 +2848,10 @@ make_table(struct archive_read *a, struct huffman_code *code)
code->tablesize = code->maxlength;
code->table = calloc(((size_t)1U) << code->tablesize, sizeof(*code->table));
+ if (code->table == NULL) {
+ archive_set_error(&a->archive, ENOMEM, "Can't allocate memory");
+ return (ARCHIVE_FATAL);
+ }
return make_table_recurse(a, code, 0, code->table, 0, code->tablesize);
}
@@ -2865,13 +2867,13 @@ make_table_recurse(struct archive_read *a, struct huffman_code *code, int node,
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Huffman tree was not created");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
- if (node < 0 || node >= code->numentries)
+ if (node < 0 || (size_t)node >= code->numentries)
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid location to Huffman tree specified");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
currtablesize = 1 << (maxdepth - depth);
@@ -2955,9 +2957,9 @@ expand(struct archive_read *a, int64_t *end)
static const unsigned char shortbits[] =
{ 2, 2, 3, 4, 5, 6, 6, 6 };
+ struct rar *rar = a->format->data;
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->filters.filterstart < *end)
@@ -3134,31 +3136,31 @@ truncated_data:
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated RAR file data");
rar->valid = 0;
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
bad_data:
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Bad RAR file data");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
static int
copy_from_lzss_window(struct archive_read *a, uint8_t *buffer,
int64_t startpos, int length)
{
+ struct rar *rar = a->format->data;
int windowoffs, firstpart;
- struct rar *rar = (struct rar *)(a->format->data);
windowoffs = lzss_offset_for_position(&rar->lzss, startpos);
firstpart = lzss_size(&rar->lzss) - windowoffs;
if (length > lzss_size(&rar->lzss)) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Bad RAR file data");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
if (firstpart < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Bad RAR file data");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
if (firstpart < length) {
memcpy(buffer, &rar->lzss.window[windowoffs], firstpart);
@@ -3173,8 +3175,8 @@ static int
copy_from_lzss_window_to_unp(struct archive_read *a, const void **buffer,
int64_t startpos, size_t length)
{
+ struct rar *rar = a->format->data;
int windowoffs, firstpart;
- struct rar *rar = (struct rar *)(a->format->data);
if (length > rar->unp_buffer_size)
{
@@ -3200,7 +3202,7 @@ copy_from_lzss_window_to_unp(struct archive_read *a, const void **buffer,
if (firstpart < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Bad RAR file data");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
if ((size_t)firstpart < length) {
memcpy(&rar->unp_buffer[rar->unp_offset],
@@ -3224,13 +3226,13 @@ copy_from_lzss_window_to_unp(struct archive_read *a, const void **buffer,
fatal:
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Bad RAR file data");
- return (ARCHIVE_FATAL);
+ return (ARCHIVE_FAILED);
}
static const void *
rar_read_ahead(struct archive_read *a, size_t min, ssize_t *avail)
{
- struct rar *rar = (struct rar *)(a->format->data);
+ struct rar *rar = a->format->data;
const void *h;
int ret;
@@ -3267,7 +3269,7 @@ again:
static int
parse_filter(struct archive_read *a, const uint8_t *bytes, uint16_t length, uint8_t flags)
{
- struct rar *rar = (struct rar *)(a->format->data);
+ struct rar *rar = a->format->data;
struct rar_filters *filters = &rar->filters;
struct memory_bit_reader br = { 0 };
@@ -3435,7 +3437,7 @@ create_filter(struct rar_program_code *prog, const uint8_t *globaldata, uint32_t
static int
run_filters(struct archive_read *a)
{
- struct rar *rar = (struct rar *)(a->format->data);
+ struct rar *rar = a->format->data;
struct rar_filters *filters = &rar->filters;
struct rar_filter *filter = filters->stack;
struct rar_filter *f;
@@ -3556,7 +3558,13 @@ compile_program(const uint8_t *bytes, size_t length)
if (membr_bits(&br, 1))
{
- prog->staticdatalen = membr_next_rarvm_number(&br) + 1;
+ uint32_t staticdatalen = membr_next_rarvm_number(&br);
+ if (staticdatalen >= VM_MEMORY_SIZE)
+ {
+ delete_program_code(prog);
+ return NULL;
+ }
+ prog->staticdatalen = staticdatalen + 1;
prog->staticdata = malloc(prog->staticdatalen);
if (!prog->staticdata)
{
@@ -3597,7 +3605,6 @@ delete_program_code(struct rar_program_code *prog)
{
struct rar_program_code *next = prog->next;
free(prog->staticdata);
- free(prog->globalbackup);
free(prog);
prog = next;
}
@@ -3650,7 +3657,7 @@ membr_fill(struct memory_bit_reader *br, int bits)
static int
read_filter(struct archive_read *a, int64_t *end)
{
- struct rar *rar = (struct rar *)(a->format->data);
+ struct rar *rar = a->format->data;
uint8_t flags, val, *code;
uint16_t length, i;
@@ -3846,7 +3853,7 @@ execute_filter_audio(struct rar_filter *filter, struct rar_virtual_machine *vm)
state.delta[0] = state.lastdelta;
predbyte = ((8 * state.lastbyte + state.weight[0] * state.delta[0] + state.weight[1] * state.delta[1] + state.weight[2] * state.delta[2]) >> 3) & 0xFF;
byte = (predbyte - delta) & 0xFF;
- prederror = delta << 3;
+ prederror = delta * 8;
state.error[0] += abs(prederror);
state.error[1] += abs(prederror - state.delta[0]); state.error[2] += abs(prederror + state.delta[0]);
state.error[3] += abs(prederror - state.delta[1]); state.error[4] += abs(prederror + state.delta[1]);
@@ -3903,7 +3910,7 @@ execute_filter(struct archive_read *a, struct rar_filter *filter, struct rar_vir
static int
rar_decode_byte(struct archive_read *a, uint8_t *byte)
{
- struct rar *rar = (struct rar *)(a->format->data);
+ struct rar *rar = a->format->data;
struct rar_br *br = &(rar->br);
if (!rar_br_read_ahead(a, br, 8))
return 0;
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_rar5.c b/contrib/libarchive/libarchive/archive_read_support_format_rar5.c
index 63dd97b3008a..faddad9ff497 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_rar5.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_rar5.c
@@ -44,6 +44,7 @@
#include "archive_entry.h"
#include "archive_entry_locale.h"
+#include "archive_integer.h"
#include "archive_ppmd7_private.h"
#include "archive_entry_private.h"
#include "archive_time_private.h"
@@ -81,7 +82,9 @@
*
* The array itself is decrypted in `rar5_init` function. */
-static unsigned char rar5_signature_xor[] = { 243, 192, 211, 128, 187, 166, 160, 161 };
+static const unsigned char rar5_signature_xor[] = {
+ 243, 192, 211, 128, 187, 166, 160, 161
+};
static const size_t g_unpack_window_size = 0x20000;
/* These could have been static const's, but they aren't, because of
@@ -165,11 +168,9 @@ enum FILTER_TYPE {
struct filter_info {
int type;
int channels;
- int pos_r;
int64_t block_start;
ssize_t block_length;
- uint16_t width;
};
struct data_ready {
@@ -372,10 +373,10 @@ struct rar5 {
static void rar5_signature(char *buf);
static int verify_global_checksums(struct archive_read* a);
static int rar5_read_data_skip(struct archive_read *a);
-static int push_data_ready(struct archive_read* a, struct rar5* rar,
+static int push_data_ready(struct archive_read* a, struct rar5 *rar5,
const uint8_t* buf, size_t size, int64_t offset);
-static void clear_data_ready_stack(struct rar5* rar);
-static void rar5_deinit(struct rar5* rar);
+static void clear_data_ready_stack(struct rar5 *rar5);
+static void rar5_deinit(struct rar5 *rar5);
/* CDE_xxx = Circular Double Ended (Queue) return values. */
enum CDE_RETURN_VALUES {
@@ -514,10 +515,6 @@ uint8_t bf_is_last_block(const struct compressed_block_header* hdr) {
return (hdr->block_flags_u8 >> 6) & 1;
}
-static inline struct rar5* get_context(struct archive_read* a) {
- return (struct rar5*) a->format->data;
-}
-
/* Convenience functions used by filter implementations. */
static void circular_memcpy(uint8_t* dst, uint8_t* window, const ssize_t mask,
int64_t start, int64_t end)
@@ -533,28 +530,28 @@ static void circular_memcpy(uint8_t* dst, uint8_t* window, const ssize_t mask,
}
}
-static uint32_t read_filter_data(struct rar5* rar, uint32_t offset) {
+static uint32_t read_filter_data(struct rar5 *rar5, uint32_t offset) {
uint8_t linear_buf[4];
- circular_memcpy(linear_buf, rar->cstate.window_buf,
- rar->cstate.window_mask, offset, offset + 4);
+ circular_memcpy(linear_buf, rar5->cstate.window_buf,
+ rar5->cstate.window_mask, offset, offset + 4);
return archive_le32dec(linear_buf);
}
-static void write_filter_data(struct rar5* rar, uint32_t offset,
+static void write_filter_data(struct rar5 *rar5, uint32_t offset,
uint32_t value)
{
- archive_le32enc(&rar->cstate.filtered_buf[offset], value);
+ archive_le32enc(&rar5->cstate.filtered_buf[offset], value);
}
/* Allocates a new filter descriptor and adds it to the filter array. */
-static struct filter_info* add_new_filter(struct rar5* rar) {
+static struct filter_info* add_new_filter(struct rar5 *rar5) {
struct filter_info* f = calloc(1, sizeof(*f));
if(!f) {
return NULL;
}
- if (CDE_OK != cdeque_push_back(&rar->cstate.filters, cdeque_filter(f))) {
+ if (CDE_OK != cdeque_push_back(&rar5->cstate.filters, cdeque_filter(f))) {
free(f);
return NULL;
}
@@ -562,7 +559,7 @@ static struct filter_info* add_new_filter(struct rar5* rar) {
return f;
}
-static int run_delta_filter(struct rar5* rar, struct filter_info* flt) {
+static int run_delta_filter(struct rar5 *rar5, struct filter_info* flt) {
int i;
ssize_t dest_pos, src_pos = 0;
@@ -574,12 +571,12 @@ static int run_delta_filter(struct rar5* rar, struct filter_info* flt) {
{
uint8_t byte;
- byte = rar->cstate.window_buf[
- (rar->cstate.solid_offset + flt->block_start +
- src_pos) & rar->cstate.window_mask];
+ byte = rar5->cstate.window_buf[
+ (rar5->cstate.solid_offset + flt->block_start +
+ src_pos) & rar5->cstate.window_mask];
prev_byte -= byte;
- rar->cstate.filtered_buf[dest_pos] = prev_byte;
+ rar5->cstate.filtered_buf[dest_pos] = prev_byte;
src_pos++;
}
}
@@ -587,21 +584,21 @@ static int run_delta_filter(struct rar5* rar, struct filter_info* flt) {
return ARCHIVE_OK;
}
-static int run_e8e9_filter(struct rar5* rar, struct filter_info* flt,
+static int run_e8e9_filter(struct rar5 *rar5, struct filter_info* flt,
int extended)
{
const uint32_t file_size = 0x1000000;
ssize_t i;
- circular_memcpy(rar->cstate.filtered_buf,
- rar->cstate.window_buf, rar->cstate.window_mask,
- rar->cstate.solid_offset + flt->block_start,
- rar->cstate.solid_offset + flt->block_start + flt->block_length);
+ circular_memcpy(rar5->cstate.filtered_buf,
+ rar5->cstate.window_buf, rar5->cstate.window_mask,
+ rar5->cstate.solid_offset + flt->block_start,
+ rar5->cstate.solid_offset + flt->block_start + flt->block_length);
for(i = 0; i < flt->block_length - 4;) {
- uint8_t b = rar->cstate.window_buf[
- (rar->cstate.solid_offset + flt->block_start +
- i++) & rar->cstate.window_mask];
+ uint8_t b = rar5->cstate.window_buf[
+ (rar5->cstate.solid_offset + flt->block_start +
+ i++) & rar5->cstate.window_mask];
/*
* 0xE8 = x86's call <relative_addr_uint32> (function call)
@@ -612,19 +609,19 @@ static int run_e8e9_filter(struct rar5* rar, struct filter_info* flt,
uint32_t addr;
uint32_t offset = (i + flt->block_start) % file_size;
- addr = read_filter_data(rar,
- (uint32_t)(rar->cstate.solid_offset +
- flt->block_start + i) & rar->cstate.window_mask);
+ addr = read_filter_data(rar5,
+ (uint32_t)(rar5->cstate.solid_offset +
+ flt->block_start + i) & rar5->cstate.window_mask);
if(addr & 0x80000000) {
if(((addr + offset) & 0x80000000) == 0) {
- write_filter_data(rar, (uint32_t)i,
+ write_filter_data(rar5, (uint32_t)i,
addr + file_size);
}
} else {
if((addr - file_size) & 0x80000000) {
uint32_t naddr = addr - offset;
- write_filter_data(rar, (uint32_t)i,
+ write_filter_data(rar5, (uint32_t)i,
naddr);
}
}
@@ -636,29 +633,29 @@ static int run_e8e9_filter(struct rar5* rar, struct filter_info* flt,
return ARCHIVE_OK;
}
-static int run_arm_filter(struct rar5* rar, struct filter_info* flt) {
+static int run_arm_filter(struct rar5 *rar5, struct filter_info* flt) {
ssize_t i = 0;
uint32_t offset;
- circular_memcpy(rar->cstate.filtered_buf,
- rar->cstate.window_buf, rar->cstate.window_mask,
- rar->cstate.solid_offset + flt->block_start,
- rar->cstate.solid_offset + flt->block_start + flt->block_length);
+ circular_memcpy(rar5->cstate.filtered_buf,
+ rar5->cstate.window_buf, rar5->cstate.window_mask,
+ rar5->cstate.solid_offset + flt->block_start,
+ rar5->cstate.solid_offset + flt->block_start + flt->block_length);
for(i = 0; i < flt->block_length - 3; i += 4) {
- uint8_t* b = &rar->cstate.window_buf[
- (rar->cstate.solid_offset +
- flt->block_start + i + 3) & rar->cstate.window_mask];
+ uint8_t* b = &rar5->cstate.window_buf[
+ (rar5->cstate.solid_offset +
+ flt->block_start + i + 3) & rar5->cstate.window_mask];
if(*b == 0xEB) {
/* 0xEB = ARM's BL (branch + link) instruction. */
- offset = read_filter_data(rar,
- (rar->cstate.solid_offset + flt->block_start + i) &
- (uint32_t)rar->cstate.window_mask) & 0x00ffffff;
+ offset = read_filter_data(rar5,
+ (rar5->cstate.solid_offset + flt->block_start + i) &
+ (uint32_t)rar5->cstate.window_mask) & 0x00ffffff;
offset -= (uint32_t) ((i + flt->block_start) / 4);
offset = (offset & 0x00ffffff) | 0xeb000000;
- write_filter_data(rar, (uint32_t)i, offset);
+ write_filter_data(rar5, (uint32_t)i, offset);
}
}
@@ -666,14 +663,14 @@ static int run_arm_filter(struct rar5* rar, struct filter_info* flt) {
}
static int run_filter(struct archive_read* a, struct filter_info* flt) {
+ struct rar5 *rar5 = a->format->data;
int ret;
- struct rar5* rar = get_context(a);
- clear_data_ready_stack(rar);
- free(rar->cstate.filtered_buf);
+ clear_data_ready_stack(rar5);
+ free(rar5->cstate.filtered_buf);
- rar->cstate.filtered_buf = malloc(flt->block_length);
- if(!rar->cstate.filtered_buf) {
+ rar5->cstate.filtered_buf = malloc(flt->block_length);
+ if(!rar5->cstate.filtered_buf) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory for filter data");
return ARCHIVE_FATAL;
@@ -681,18 +678,18 @@ static int run_filter(struct archive_read* a, struct filter_info* flt) {
switch(flt->type) {
case FILTER_DELTA:
- ret = run_delta_filter(rar, flt);
+ ret = run_delta_filter(rar5, flt);
break;
case FILTER_E8:
/* fallthrough */
case FILTER_E8E9:
- ret = run_e8e9_filter(rar, flt,
+ ret = run_e8e9_filter(rar5, flt,
flt->type == FILTER_E8E9);
break;
case FILTER_ARM:
- ret = run_arm_filter(rar, flt);
+ ret = run_arm_filter(rar5, flt);
break;
default:
@@ -700,7 +697,7 @@ static int run_filter(struct archive_read* a, struct filter_info* flt) {
ARCHIVE_ERRNO_FILE_FORMAT,
"Unsupported filter type: 0x%x",
(unsigned int)flt->type);
- return ARCHIVE_FATAL;
+ return ARCHIVE_FAILED;
}
if(ret != ARCHIVE_OK) {
@@ -708,8 +705,8 @@ static int run_filter(struct archive_read* a, struct filter_info* flt) {
return ret;
}
- if(ARCHIVE_OK != push_data_ready(a, rar, rar->cstate.filtered_buf,
- flt->block_length, rar->cstate.last_write_ptr))
+ if(ARCHIVE_OK != push_data_ready(a, rar5, rar5->cstate.filtered_buf,
+ flt->block_length, rar5->cstate.last_write_ptr))
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Stack overflow when submitting unpacked data");
@@ -717,7 +714,7 @@ static int run_filter(struct archive_read* a, struct filter_info* flt) {
return ARCHIVE_FATAL;
}
- rar->cstate.last_write_ptr += flt->block_length;
+ rar5->cstate.last_write_ptr += flt->block_length;
return ARCHIVE_OK;
}
@@ -725,15 +722,15 @@ static int run_filter(struct archive_read* a, struct filter_info* flt) {
* Next call of `use_data` will use the pointer, size and offset arguments
* that are specified here. These arguments are pushed to the FIFO stack here,
* and popped from the stack by the `use_data` function. */
-static void push_data(struct archive_read* a, struct rar5* rar,
+static void push_data(struct archive_read* a, struct rar5 *rar5,
const uint8_t* buf, int64_t idx_begin, int64_t idx_end)
{
- const ssize_t wmask = rar->cstate.window_mask;
- const ssize_t solid_write_ptr = (rar->cstate.solid_offset +
- rar->cstate.last_write_ptr) & wmask;
+ const ssize_t wmask = rar5->cstate.window_mask;
+ const ssize_t solid_write_ptr = (rar5->cstate.solid_offset +
+ rar5->cstate.last_write_ptr) & wmask;
- idx_begin += rar->cstate.solid_offset;
- idx_end += rar->cstate.solid_offset;
+ idx_begin += rar5->cstate.solid_offset;
+ idx_end += rar5->cstate.solid_offset;
/* Check if our unpacked data is wrapped inside the window circular
* buffer. If it's not wrapped, it can be copied out by using
@@ -743,57 +740,57 @@ static void push_data(struct archive_read* a, struct rar5* rar,
if((idx_begin & wmask) > (idx_end & wmask)) {
/* The data is wrapped (begin offset sis bigger than end
* offset). */
- const ssize_t frag1_size = rar->cstate.window_size -
+ const ssize_t frag1_size = rar5->cstate.window_size -
(idx_begin & wmask);
const ssize_t frag2_size = idx_end & wmask;
/* Copy the first part of the buffer first. */
- push_data_ready(a, rar, buf + solid_write_ptr, frag1_size,
- rar->cstate.last_write_ptr);
+ push_data_ready(a, rar5, buf + solid_write_ptr, frag1_size,
+ rar5->cstate.last_write_ptr);
/* Copy the second part of the buffer. */
- push_data_ready(a, rar, buf, frag2_size,
- rar->cstate.last_write_ptr + frag1_size);
+ push_data_ready(a, rar5, buf, frag2_size,
+ rar5->cstate.last_write_ptr + frag1_size);
- rar->cstate.last_write_ptr += frag1_size + frag2_size;
+ rar5->cstate.last_write_ptr += frag1_size + frag2_size;
} else {
/* Data is not wrapped, so we can just use one call to copy the
* data. */
- push_data_ready(a, rar,
+ push_data_ready(a, rar5,
buf + solid_write_ptr, (idx_end - idx_begin) & wmask,
- rar->cstate.last_write_ptr);
+ rar5->cstate.last_write_ptr);
- rar->cstate.last_write_ptr += idx_end - idx_begin;
+ rar5->cstate.last_write_ptr += idx_end - idx_begin;
}
}
/* Convenience function that submits the data to the user. It uses the
* unpack window buffer as a source location. */
-static void push_window_data(struct archive_read* a, struct rar5* rar,
+static void push_window_data(struct archive_read* a, struct rar5 *rar5,
int64_t idx_begin, int64_t idx_end)
{
- push_data(a, rar, rar->cstate.window_buf, idx_begin, idx_end);
+ push_data(a, rar5, rar5->cstate.window_buf, idx_begin, idx_end);
}
static int apply_filters(struct archive_read* a) {
+ struct rar5 *rar5 = a->format->data;
struct filter_info* flt;
- struct rar5* rar = get_context(a);
int ret;
- rar->cstate.all_filters_applied = 0;
+ rar5->cstate.all_filters_applied = 0;
/* Get the first filter that can be applied to our data. The data
* needs to be fully unpacked before the filter can be run. */
- if(CDE_OK == cdeque_front(&rar->cstate.filters,
+ if(CDE_OK == cdeque_front(&rar5->cstate.filters,
cdeque_filter_p(&flt))) {
/* Check if our unpacked data fully covers this filter's
* range. */
- if(rar->cstate.write_ptr > flt->block_start &&
- rar->cstate.write_ptr >= flt->block_start +
+ if(rar5->cstate.write_ptr > flt->block_start &&
+ rar5->cstate.write_ptr >= flt->block_start +
flt->block_length) {
/* Check if we have some data pending to be written
* right before the filter's start offset. */
- if(rar->cstate.last_write_ptr == flt->block_start) {
+ if(rar5->cstate.last_write_ptr == flt->block_start) {
/* Run the filter specified by descriptor
* `flt`. */
ret = run_filter(a, flt);
@@ -805,15 +802,15 @@ static int apply_filters(struct archive_read* a) {
/* Filter descriptor won't be needed anymore
* after it's used, * so remove it from the
* filter list and free its memory. */
- (void) cdeque_pop_front(&rar->cstate.filters,
+ (void) cdeque_pop_front(&rar5->cstate.filters,
cdeque_filter_p(&flt));
free(flt);
} else {
/* We can't run filters yet, dump the memory
* right before the filter. */
- push_window_data(a, rar,
- rar->cstate.last_write_ptr,
+ push_window_data(a, rar5,
+ rar5->cstate.last_write_ptr,
flt->block_start);
}
@@ -823,12 +820,12 @@ static int apply_filters(struct archive_read* a) {
}
}
- rar->cstate.all_filters_applied = 1;
+ rar5->cstate.all_filters_applied = 1;
return ARCHIVE_OK;
}
-static void dist_cache_push(struct rar5* rar, int value) {
- int* q = rar->cstate.dist_cache;
+static void dist_cache_push(struct rar5 *rar5, int value) {
+ int* q = rar5->cstate.dist_cache;
q[3] = q[2];
q[2] = q[1];
@@ -836,8 +833,8 @@ static void dist_cache_push(struct rar5* rar, int value) {
q[0] = value;
}
-static int dist_cache_touch(struct rar5* rar, int idx) {
- int* q = rar->cstate.dist_cache;
+static int dist_cache_touch(struct rar5 *rar5, int idx) {
+ int* q = rar5->cstate.dist_cache;
int i, dist = q[idx];
for(i = idx; i > 0; i--)
@@ -847,8 +844,8 @@ static int dist_cache_touch(struct rar5* rar, int idx) {
return dist;
}
-static void free_filters(struct rar5* rar) {
- struct cdeque* d = &rar->cstate.filters;
+static void free_filters(struct rar5 *rar5) {
+ struct cdeque* d = &rar5->cstate.filters;
/* Free any remaining filters. All filters should be naturally
* consumed by the unpacking function, so remaining filters after
@@ -868,28 +865,28 @@ static void free_filters(struct rar5* rar) {
cdeque_clear(d);
/* Also clear out the variables needed for sanity checking. */
- rar->cstate.last_block_start = 0;
- rar->cstate.last_block_length = 0;
+ rar5->cstate.last_block_start = 0;
+ rar5->cstate.last_block_length = 0;
}
-static void reset_file_context(struct rar5* rar) {
- memset(&rar->file, 0, sizeof(rar->file));
- blake2sp_init(&rar->file.b2state, 32);
+static void reset_file_context(struct rar5 *rar5) {
+ memset(&rar5->file, 0, sizeof(rar5->file));
+ blake2sp_init(&rar5->file.b2state, 32);
- if(rar->main.solid) {
- rar->cstate.solid_offset += rar->cstate.write_ptr;
+ if(rar5->main.solid) {
+ rar5->cstate.solid_offset += rar5->cstate.write_ptr;
} else {
- rar->cstate.solid_offset = 0;
+ rar5->cstate.solid_offset = 0;
}
- rar->cstate.write_ptr = 0;
- rar->cstate.last_write_ptr = 0;
- rar->cstate.last_unstore_ptr = 0;
+ rar5->cstate.write_ptr = 0;
+ rar5->cstate.last_write_ptr = 0;
+ rar5->cstate.last_unstore_ptr = 0;
- rar->file.redir_type = REDIR_TYPE_NONE;
- rar->file.redir_flags = 0;
+ rar5->file.redir_type = REDIR_TYPE_NONE;
+ rar5->file.redir_flags = 0;
- free_filters(rar);
+ free_filters(rar5);
}
static inline int get_archive_read(struct archive* a,
@@ -905,11 +902,10 @@ static inline int get_archive_read(struct archive* a,
static int read_ahead(struct archive_read* a, size_t how_many,
const uint8_t** ptr)
{
- ssize_t avail = -1;
if(!ptr)
return 0;
- *ptr = __archive_read_ahead(a, how_many, &avail);
+ *ptr = __archive_read_ahead(a, how_many, NULL);
if(*ptr == NULL) {
return 0;
}
@@ -947,23 +943,30 @@ static int consume(struct archive_read* a, int64_t how_many) {
static int read_var(struct archive_read* a, uint64_t* pvalue,
uint64_t* pvalue_len)
{
+ uint64_t multiplier;
uint64_t result = 0;
- size_t shift, i;
+ size_t i;
const uint8_t* p;
- uint8_t b;
- /* We will read maximum of 8 bytes. We don't have to handle the
+ /* We will read maximum of 10 bytes. We don't have to handle the
* situation to read the RAR5 variable-sized value stored at the end of
* the file, because such situation will never happen. */
- if(!read_ahead(a, 8, &p))
+ if(!read_ahead(a, 10, &p))
return 0;
- for(shift = 0, i = 0; i < 8; i++, shift += 7) {
+ for(multiplier = 1, i = 0; i < 10; i++, multiplier *= 128) {
+ uint64_t val;
+ uint8_t b;
+
b = p[i];
/* Strip the MSB from the input byte and add the resulting
* number to the `result`. */
- result += (b & (uint64_t)0x7F) << shift;
+ if(archive_ckd_mul_u64(&val, b & 0x7F, multiplier) ||
+ archive_ckd_add_u64(&result, result, val)) {
+ /* Integer overflow occurred. */
+ return 0;
+ }
/* MSB set to 1 means we need to continue decoding process.
* MSB set to 0 means we're done.
@@ -997,22 +1000,8 @@ static int read_var(struct archive_read* a, uint64_t* pvalue,
}
}
- /* The decoded value takes the maximum number of 8 bytes.
- * It's a maximum number of bytes, so end decoding process here
- * even if the first bit of last byte is 1. */
- if(pvalue) {
- *pvalue = result;
- }
-
- if(pvalue_len) {
- *pvalue_len = 9;
- } else {
- if(ARCHIVE_OK != consume(a, 9)) {
- return 0;
- }
- }
-
- return 1;
+ /* All continuation bits were set. This is an error. */
+ return 0;
}
static int read_var_sized(struct archive_read* a, size_t* pvalue,
@@ -1036,52 +1025,47 @@ static int read_var_sized(struct archive_read* a, size_t* pvalue,
return ret;
}
-static int read_bits_32(struct archive_read* a, struct rar5* rar,
+static int read_bits_32(struct archive_read* a, struct rar5 *rar5,
const uint8_t* p, uint32_t* value)
{
- if(rar->bits.in_addr >= rar->cstate.cur_block_size) {
+ if(rar5->bits.in_addr >= rar5->cstate.cur_block_size) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_PROGRAMMER,
"Premature end of stream during extraction of data (#1)");
return ARCHIVE_FATAL;
}
- uint32_t bits = ((uint32_t) p[rar->bits.in_addr]) << 24;
- bits |= p[rar->bits.in_addr + 1] << 16;
- bits |= p[rar->bits.in_addr + 2] << 8;
- bits |= p[rar->bits.in_addr + 3];
- bits <<= rar->bits.bit_addr;
- bits |= p[rar->bits.in_addr + 4] >> (8 - rar->bits.bit_addr);
+ uint32_t bits = archive_be32dec(p + rar5->bits.in_addr);
+ bits <<= rar5->bits.bit_addr;
+ bits |= p[rar5->bits.in_addr + 4] >> (8 - rar5->bits.bit_addr);
*value = bits;
return ARCHIVE_OK;
}
-static int read_bits_16(struct archive_read* a, struct rar5* rar,
+static int read_bits_16(struct archive_read* a, struct rar5 *rar5,
const uint8_t* p, uint16_t* value)
{
- if(rar->bits.in_addr >= rar->cstate.cur_block_size) {
+ if(rar5->bits.in_addr >= rar5->cstate.cur_block_size) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_PROGRAMMER,
"Premature end of stream during extraction of data (#2)");
return ARCHIVE_FATAL;
}
- int bits = (int) ((uint32_t) p[rar->bits.in_addr]) << 16;
- bits |= (int) p[rar->bits.in_addr + 1] << 8;
- bits |= (int) p[rar->bits.in_addr + 2];
- bits >>= (8 - rar->bits.bit_addr);
+ uint32_t bits = archive_be24dec(p + (unsigned)rar5->bits.in_addr);
+ bits >>= (8 - rar5->bits.bit_addr);
*value = bits & 0xffff;
return ARCHIVE_OK;
}
-static void skip_bits(struct rar5* rar, int bits) {
- const int new_bits = rar->bits.bit_addr + bits;
- rar->bits.in_addr += new_bits >> 3;
- rar->bits.bit_addr = new_bits & 7;
+static void skip_bits(struct rar5 *rar5, int bits) {
+ const int new_bits = rar5->bits.bit_addr + bits;
+ rar5->bits.in_addr += new_bits >> 3;
+ rar5->bits.bit_addr = new_bits & 7;
}
/* n = up to 16 */
-static int read_consume_bits(struct archive_read* a, struct rar5* rar,
+static int read_consume_bits(struct archive_read* a, struct rar5 *rar5,
const uint8_t* p, int n, int* value)
{
uint16_t v;
@@ -1093,14 +1077,14 @@ static int read_consume_bits(struct archive_read* a, struct rar5* rar,
return ARCHIVE_FATAL;
}
- ret = read_bits_16(a, rar, p, &v);
+ ret = read_bits_16(a, rar5, p, &v);
if(ret != ARCHIVE_OK)
return ret;
num = (int) v;
num >>= 16 - n;
- skip_bits(rar, n);
+ skip_bits(rar5, n);
if(value)
*value = num;
@@ -1215,11 +1199,11 @@ static void init_header(struct archive_read* a) {
a->archive.archive_format_name = "RAR5";
}
-static void init_window_mask(struct rar5* rar) {
- if (rar->cstate.window_size)
- rar->cstate.window_mask = rar->cstate.window_size - 1;
+static void init_window_mask(struct rar5 *rar5) {
+ if (rar5->cstate.window_size)
+ rar5->cstate.window_mask = rar5->cstate.window_size - 1;
else
- rar->cstate.window_mask = 0;
+ rar5->cstate.window_mask = 0;
}
enum HEADER_FLAGS {
@@ -1233,7 +1217,7 @@ enum HEADER_FLAGS {
};
static int process_main_locator_extra_block(struct archive_read* a,
- struct rar5* rar)
+ struct rar5 *rar5)
{
uint64_t locator_flags;
@@ -1246,7 +1230,7 @@ static int process_main_locator_extra_block(struct archive_read* a,
}
if(locator_flags & QLIST) {
- if(!read_var(a, &rar->qlist_offset, NULL)) {
+ if(!read_var(a, &rar5->qlist_offset, NULL)) {
return ARCHIVE_EOF;
}
@@ -1254,7 +1238,7 @@ static int process_main_locator_extra_block(struct archive_read* a,
}
if(locator_flags & RECOVERY) {
- if(!read_var(a, &rar->rr_offset, NULL)) {
+ if(!read_var(a, &rar5->rr_offset, NULL)) {
return ARCHIVE_EOF;
}
@@ -1264,7 +1248,7 @@ static int process_main_locator_extra_block(struct archive_read* a,
return ARCHIVE_OK;
}
-static int parse_file_extra_hash(struct archive_read* a, struct rar5* rar,
+static int parse_file_extra_hash(struct archive_read* a, struct rar5 *rar5,
int64_t* extra_data_size)
{
size_t hash_type = 0;
@@ -1286,13 +1270,13 @@ static int parse_file_extra_hash(struct archive_read* a, struct rar5* rar,
* CRC32. */
if(hash_type == BLAKE2sp) {
const uint8_t* p;
- const int hash_size = sizeof(rar->file.blake2sp);
+ const int hash_size = sizeof(rar5->file.blake2sp);
if(!read_ahead(a, hash_size, &p))
return ARCHIVE_EOF;
- rar->file.has_blake2 = 1;
- memcpy(&rar->file.blake2sp, p, hash_size);
+ rar5->file.has_blake2 = 1;
+ memcpy(&rar5->file.blake2sp, p, hash_size);
if(ARCHIVE_OK != consume(a, hash_size)) {
return ARCHIVE_EOF;
@@ -1385,7 +1369,7 @@ static int parse_file_extra_version(struct archive_read* a,
}
static int parse_file_extra_htime(struct archive_read* a,
- struct archive_entry* e, struct rar5* rar, int64_t* extra_data_size)
+ struct archive_entry* e, struct rar5 *rar5, int64_t* extra_data_size)
{
char unix_time, has_unix_ns, has_mtime, has_ctime, has_atime;
size_t flags = 0;
@@ -1412,39 +1396,39 @@ static int parse_file_extra_htime(struct archive_read* a,
has_mtime = flags & HAS_MTIME;
has_atime = flags & HAS_ATIME;
has_ctime = flags & HAS_CTIME;
- rar->file.e_atime_ns = rar->file.e_ctime_ns = rar->file.e_mtime_ns = 0;
+ rar5->file.e_atime_ns = rar5->file.e_ctime_ns = rar5->file.e_mtime_ns = 0;
if(has_mtime) {
- parse_htime_item(a, unix_time, &rar->file.e_mtime,
- &rar->file.e_mtime_ns, extra_data_size);
+ parse_htime_item(a, unix_time, &rar5->file.e_mtime,
+ &rar5->file.e_mtime_ns, extra_data_size);
}
if(has_ctime) {
- parse_htime_item(a, unix_time, &rar->file.e_ctime,
- &rar->file.e_ctime_ns, extra_data_size);
+ parse_htime_item(a, unix_time, &rar5->file.e_ctime,
+ &rar5->file.e_ctime_ns, extra_data_size);
}
if(has_atime) {
- parse_htime_item(a, unix_time, &rar->file.e_atime,
- &rar->file.e_atime_ns, extra_data_size);
+ parse_htime_item(a, unix_time, &rar5->file.e_atime,
+ &rar5->file.e_atime_ns, extra_data_size);
}
if(has_mtime && has_unix_ns) {
- if(!read_u32(a, &rar->file.e_mtime_ns))
+ if(!read_u32(a, &rar5->file.e_mtime_ns))
return ARCHIVE_EOF;
*extra_data_size -= 4;
}
if(has_ctime && has_unix_ns) {
- if(!read_u32(a, &rar->file.e_ctime_ns))
+ if(!read_u32(a, &rar5->file.e_ctime_ns))
return ARCHIVE_EOF;
*extra_data_size -= 4;
}
if(has_atime && has_unix_ns) {
- if(!read_u32(a, &rar->file.e_atime_ns))
+ if(!read_u32(a, &rar5->file.e_atime_ns))
return ARCHIVE_EOF;
*extra_data_size -= 4;
@@ -1453,35 +1437,35 @@ static int parse_file_extra_htime(struct archive_read* a,
/* The seconds and nanoseconds are either together, or separated in two
* fields so we parse them, then set the archive_entry's times. */
if(has_mtime) {
- archive_entry_set_mtime(e, rar->file.e_mtime, rar->file.e_mtime_ns);
+ archive_entry_set_mtime(e, rar5->file.e_mtime, rar5->file.e_mtime_ns);
}
if(has_ctime) {
- archive_entry_set_ctime(e, rar->file.e_ctime, rar->file.e_ctime_ns);
+ archive_entry_set_ctime(e, rar5->file.e_ctime, rar5->file.e_ctime_ns);
}
if(has_atime) {
- archive_entry_set_atime(e, rar->file.e_atime, rar->file.e_atime_ns);
+ archive_entry_set_atime(e, rar5->file.e_atime, rar5->file.e_atime_ns);
}
return ARCHIVE_OK;
}
static int parse_file_extra_redir(struct archive_read* a,
- struct archive_entry* e, struct rar5* rar, int64_t* extra_data_size)
+ struct archive_entry* e, struct rar5 *rar5, int64_t* extra_data_size)
{
uint64_t value_size = 0;
size_t target_size = 0;
char target_utf8_buf[MAX_NAME_IN_BYTES];
const uint8_t* p;
- if(!read_var(a, &rar->file.redir_type, &value_size))
+ if(!read_var(a, &rar5->file.redir_type, &value_size))
return ARCHIVE_EOF;
if(ARCHIVE_OK != consume(a, (int64_t)value_size))
return ARCHIVE_EOF;
*extra_data_size -= value_size;
- if(!read_var(a, &rar->file.redir_flags, &value_size))
+ if(!read_var(a, &rar5->file.redir_flags, &value_size))
return ARCHIVE_EOF;
if(ARCHIVE_OK != consume(a, (int64_t)value_size))
return ARCHIVE_EOF;
@@ -1512,12 +1496,12 @@ static int parse_file_extra_redir(struct archive_read* a,
if(ARCHIVE_OK != consume(a, (int64_t)target_size))
return ARCHIVE_EOF;
- switch(rar->file.redir_type) {
+ switch(rar5->file.redir_type) {
case REDIR_TYPE_UNIXSYMLINK:
case REDIR_TYPE_WINSYMLINK:
archive_entry_set_filetype(e, AE_IFLNK);
archive_entry_update_symlink_utf8(e, target_utf8_buf);
- if (rar->file.redir_flags & REDIR_SYMLINK_IS_DIR) {
+ if (rar5->file.redir_flags & REDIR_SYMLINK_IS_DIR) {
archive_entry_set_symlink_type(e,
AE_SYMLINK_TYPE_DIRECTORY);
} else {
@@ -1619,7 +1603,7 @@ static int parse_file_extra_owner(struct archive_read* a,
}
static int process_head_file_extra(struct archive_read* a,
- struct archive_entry* e, struct rar5* rar, int64_t extra_data_size)
+ struct archive_entry* e, struct rar5 *rar5, int64_t extra_data_size)
{
uint64_t extra_field_size;
uint64_t extra_field_id = 0;
@@ -1649,15 +1633,15 @@ static int process_head_file_extra(struct archive_read* a,
switch(extra_field_id) {
case EX_HASH:
- ret = parse_file_extra_hash(a, rar,
+ ret = parse_file_extra_hash(a, rar5,
&extra_data_size);
break;
case EX_HTIME:
- ret = parse_file_extra_htime(a, e, rar,
+ ret = parse_file_extra_htime(a, e, rar5,
&extra_data_size);
break;
case EX_REDIR:
- ret = parse_file_extra_redir(a, e, rar,
+ ret = parse_file_extra_redir(a, e, rar5,
&extra_data_size);
break;
case EX_UOWNER:
@@ -1671,8 +1655,8 @@ static int process_head_file_extra(struct archive_read* a,
case EX_CRYPT:
/* Mark the entry as encrypted */
archive_entry_set_is_data_encrypted(e, 1);
- rar->has_encrypted_entries = 1;
- rar->cstate.data_encrypted = 1;
+ rar5->has_encrypted_entries = 1;
+ rar5->cstate.data_encrypted = 1;
/* fallthrough */
case EX_SUBDATA:
/* fallthrough */
@@ -1734,7 +1718,7 @@ static int file_entry_sanity_checks(struct archive_read* a,
return ARCHIVE_OK;
}
-static int process_head_file(struct archive_read* a, struct rar5* rar,
+static int process_head_file(struct archive_read* a, struct rar5 *rar5,
struct archive_entry* entry, size_t block_flags)
{
int64_t extra_data_size = 0;
@@ -1773,8 +1757,8 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
archive_entry_clear(entry);
/* Do not reset file context if we're switching archives. */
- if(!rar->cstate.switch_multivolume) {
- reset_file_context(rar);
+ if(!rar5->cstate.switch_multivolume) {
+ reset_file_context(rar5);
}
if(block_flags & HFL_EXTRA_DATA) {
@@ -1790,9 +1774,16 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
if(!read_var_sized(a, &data_size, NULL))
return ARCHIVE_EOF;
- rar->file.bytes_remaining = data_size;
+ if(data_size > SSIZE_MAX) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "File data size is too large");
+ return ARCHIVE_FATAL;
+ }
+
+ rar5->file.bytes_remaining = data_size;
} else {
- rar->file.bytes_remaining = 0;
+ rar5->file.bytes_remaining = 0;
}
if(!read_var_sized(a, &file_flags, NULL))
@@ -1807,9 +1798,9 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
return ARCHIVE_FATAL;
}
- rar->file.dir = (uint8_t) ((file_flags & DIRECTORY) > 0);
+ rar5->file.dir = (uint8_t) ((file_flags & DIRECTORY) > 0);
- sanity_ret = file_entry_sanity_checks(a, block_flags, rar->file.dir,
+ sanity_ret = file_entry_sanity_checks(a, block_flags, rar5->file.dir,
unpacked_size, data_size);
if (sanity_ret != ARCHIVE_OK) {
@@ -1836,19 +1827,19 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
c_version = (int) (compression_info & 0x3f);
/* RAR5 seems to limit the dictionary size to 64MB. */
- window_size = (rar->file.dir > 0) ?
+ window_size = (rar5->file.dir > 0) ?
0 :
g_unpack_window_size << ((compression_info >> 10) & 15);
- rar->cstate.method = c_method;
- rar->cstate.version = c_version + 50;
- rar->file.solid = (compression_info & SOLID) > 0;
+ rar5->cstate.method = c_method;
+ rar5->cstate.version = c_version + 50;
+ rar5->file.solid = (compression_info & SOLID) > 0;
/* Archives which declare solid files without initializing the window
* buffer first are invalid, unless previous data was encrypted, in
* which case we may never have had the chance */
- if(rar->file.solid > 0 && rar->cstate.data_encrypted == 0 &&
- rar->cstate.window_buf == NULL) {
+ if(rar5->file.solid > 0 && rar5->cstate.data_encrypted == 0 &&
+ rar5->cstate.window_buf == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Declared solid file, but no window buffer "
"initialized yet");
@@ -1858,18 +1849,18 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
/* Check if window_size is a sane value. Also, if the file is not
* declared as a directory, disallow window_size == 0. */
if(window_size > (64 * 1024 * 1024) ||
- (rar->file.dir == 0 && window_size == 0))
+ (rar5->file.dir == 0 && window_size == 0))
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Declared dictionary size is not supported");
return ARCHIVE_FATAL;
}
- if(rar->file.solid > 0) {
+ if(rar5->file.solid > 0) {
/* Re-check if current window size is the same as previous
* window size (for solid files only). */
- if(rar->file.solid_window_size > 0 &&
- rar->file.solid_window_size != (ssize_t) window_size)
+ if(rar5->file.solid_window_size > 0 &&
+ rar5->file.solid_window_size != (ssize_t) window_size)
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Window size for this solid file doesn't match "
@@ -1878,23 +1869,23 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
}
}
else
- rar->cstate.data_encrypted = 0; /* Reset for new buffer */
+ rar5->cstate.data_encrypted = 0; /* Reset for new buffer */
- if(rar->cstate.window_size < (ssize_t) window_size &&
- rar->cstate.window_buf)
+ if(rar5->cstate.window_size < (ssize_t) window_size &&
+ rar5->cstate.window_buf)
{
/* The `data_ready` stack contains pointers to the `window_buf` or
* `filtered_buf` buffers. Since we're about to reallocate the first
* buffer, some of those pointers could become invalid. Therefore, we
* need to dispose of all entries from the stack before attempting the
* realloc. */
- clear_data_ready_stack(rar);
+ clear_data_ready_stack(rar5);
/* If window_buf has been allocated before, reallocate it, so
* that its size will match new window_size. */
uint8_t* new_window_buf =
- realloc(rar->cstate.window_buf, (size_t) window_size);
+ realloc(rar5->cstate.window_buf, (size_t) window_size);
if(!new_window_buf) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
@@ -1903,23 +1894,23 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
return ARCHIVE_FATAL;
}
- rar->cstate.window_buf = new_window_buf;
+ rar5->cstate.window_buf = new_window_buf;
}
/* Values up to 64M should fit into ssize_t on every
* architecture. */
- rar->cstate.window_size = (ssize_t) window_size;
+ rar5->cstate.window_size = (ssize_t) window_size;
- if(rar->file.solid > 0 && rar->file.solid_window_size == 0) {
+ if(rar5->file.solid > 0 && rar5->file.solid_window_size == 0) {
/* Solid files have to have the same window_size across
whole archive. Remember the window_size parameter
for first solid file found. */
- rar->file.solid_window_size = rar->cstate.window_size;
+ rar5->file.solid_window_size = rar5->cstate.window_size;
}
- init_window_mask(rar);
+ init_window_mask(rar5);
- rar->file.service = 0;
+ rar5->file.service = 0;
if(!read_var_sized(a, &host_os, NULL))
return ARCHIVE_EOF;
@@ -1946,29 +1937,20 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
archive_entry_set_mode(entry, mode);
if (file_attr & (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM)) {
- char *fflags_text, *ptr;
- /* allocate for ",rdonly,hidden,system" */
- fflags_text = malloc(22 * sizeof(*fflags_text));
- if (fflags_text != NULL) {
- ptr = fflags_text;
- if (file_attr & ATTR_READONLY) {
- strcpy(ptr, ",rdonly");
- ptr = ptr + 7;
- }
- if (file_attr & ATTR_HIDDEN) {
- strcpy(ptr, ",hidden");
- ptr = ptr + 7;
- }
- if (file_attr & ATTR_SYSTEM) {
- strcpy(ptr, ",system");
- ptr = ptr + 7;
- }
- if (ptr > fflags_text) {
- archive_entry_copy_fflags_text(entry,
- fflags_text + 1);
- }
- free(fflags_text);
- }
+ char buf[sizeof(",rdonly,hidden,system")];
+ const char *fflags[3] = { "", "", "" };
+ const char **flag = fflags;
+
+ if (file_attr & ATTR_READONLY)
+ *flag++ = ",rdonly";
+ if (file_attr & ATTR_HIDDEN)
+ *flag++ = ",hidden";
+ if (file_attr & ATTR_SYSTEM)
+ *flag++ = ",system";
+
+ snprintf(buf, sizeof(buf), "%s%s%s",
+ fflags[0], fflags[1], fflags[2]);
+ archive_entry_copy_fflags_text(entry, buf + 1);
}
} else if(host_os == HOST_UNIX) {
/* Host OS is Unix */
@@ -2011,7 +1993,7 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
archive_entry_update_pathname_utf8(entry, name_utf8_buf);
if(extra_data_size > 0) {
- int ret = process_head_file_extra(a, entry, rar,
+ int ret = process_head_file_extra(a, entry, rar5,
extra_data_size);
/*
@@ -2030,8 +2012,8 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
}
if((file_flags & UNKNOWN_UNPACKED_SIZE) == 0) {
- rar->file.unpacked_size = (ssize_t) unpacked_size;
- if(rar->file.redir_type == REDIR_TYPE_NONE)
+ rar5->file.unpacked_size = (ssize_t) unpacked_size;
+ if(rar5->file.redir_type == REDIR_TYPE_NONE)
archive_entry_set_size(entry, unpacked_size);
}
@@ -2040,18 +2022,18 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
}
if(file_flags & CRC32) {
- rar->file.stored_crc32 = crc;
+ rar5->file.stored_crc32 = crc;
}
- if(!rar->cstate.switch_multivolume) {
+ if(!rar5->cstate.switch_multivolume) {
/* Do not reinitialize unpacking state if we're switching
* archives. */
- rar->cstate.block_parsing_finished = 1;
- rar->cstate.all_filters_applied = 1;
- rar->cstate.initialized = 0;
+ rar5->cstate.block_parsing_finished = 1;
+ rar5->cstate.all_filters_applied = 1;
+ rar5->cstate.initialized = 0;
}
- if(rar->generic.split_before > 0) {
+ if(rar5->generic.split_before > 0) {
/* If now we're standing on a header that has a 'split before'
* mark, it means we're standing on a 'continuation' file
* header. Signal the caller that if it wants to move to
@@ -2064,15 +2046,15 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
}
}
-static int process_head_service(struct archive_read* a, struct rar5* rar,
+static int process_head_service(struct archive_read* a, struct rar5 *rar5,
struct archive_entry* entry, size_t block_flags)
{
/* Process this SERVICE block the same way as FILE blocks. */
- int ret = process_head_file(a, rar, entry, block_flags);
+ int ret = process_head_file(a, rar5, entry, block_flags);
if(ret != ARCHIVE_OK)
return ret;
- rar->file.service = 1;
+ rar5->file.service = 1;
/* But skip the data part automatically. It's no use for the user
* anyway. It contains only service data, not even needed to
@@ -2085,7 +2067,7 @@ static int process_head_service(struct archive_read* a, struct rar5* rar,
return ARCHIVE_RETRY;
}
-static int process_head_main(struct archive_read* a, struct rar5* rar,
+static int process_head_main(struct archive_read* a, struct rar5 *rar5,
struct archive_entry* entry, size_t block_flags)
{
int ret;
@@ -2121,8 +2103,8 @@ static int process_head_main(struct archive_read* a, struct rar5* rar,
return ARCHIVE_EOF;
}
- rar->main.volume = (archive_flags & VOLUME) > 0;
- rar->main.solid = (archive_flags & SOLID) > 0;
+ rar5->main.volume = (archive_flags & VOLUME) > 0;
+ rar5->main.solid = (archive_flags & SOLID) > 0;
if(archive_flags & VOLUME_NUMBER) {
size_t v = 0;
@@ -2137,13 +2119,13 @@ static int process_head_main(struct archive_read* a, struct rar5* rar,
return ARCHIVE_FATAL;
}
- rar->main.vol_no = (unsigned int) v;
+ rar5->main.vol_no = (unsigned int) v;
} else {
- rar->main.vol_no = 0;
+ rar5->main.vol_no = 0;
}
- if(rar->vol.expected_vol_no > 0 &&
- rar->main.vol_no != rar->vol.expected_vol_no)
+ if(rar5->vol.expected_vol_no > 0 &&
+ rar5->main.vol_no != rar5->vol.expected_vol_no)
{
/* Returning EOF instead of FATAL because of strange
* libarchive behavior. When opening multiple files via
@@ -2174,7 +2156,7 @@ static int process_head_main(struct archive_read* a, struct rar5* rar,
switch(extra_field_id) {
case LOCATOR:
- ret = process_main_locator_extra_block(a, rar);
+ ret = process_main_locator_extra_block(a, rar5);
if(ret != ARCHIVE_OK) {
/* Error while parsing main locator extra
* block. */
@@ -2194,25 +2176,25 @@ static int process_head_main(struct archive_read* a, struct rar5* rar,
}
static int skip_unprocessed_bytes(struct archive_read* a) {
- struct rar5* rar = get_context(a);
+ struct rar5 *rar5 = a->format->data;
int ret;
- if(rar->file.bytes_remaining) {
+ if(rar5->file.bytes_remaining) {
/* Use different skipping method in block merging mode than in
* normal mode. If merge mode is active, rar5_read_data_skip
* can't be used, because it could allow recursive use of
* merge_block() * function, and this function doesn't support
* recursive use. */
- if(rar->merge_mode) {
+ if(rar5->merge_mode) {
/* Discard whole merged block. This is valid in solid
* mode as well, because the code will discard blocks
* only if those blocks are safe to discard (i.e.
* they're not FILE blocks). */
- ret = consume(a, rar->file.bytes_remaining);
+ ret = consume(a, rar5->file.bytes_remaining);
if(ret != ARCHIVE_OK) {
return ret;
}
- rar->file.bytes_remaining = 0;
+ rar5->file.bytes_remaining = 0;
} else {
/* If we're not in merge mode, use safe skipping code.
* This will ensure we'll handle solid archives
@@ -2274,17 +2256,45 @@ static int scan_for_signature(struct archive_read* a);
* <FILE> block.
*/
+/*
+ * A header that carries no file data (HEAD_MAIN, or an unknown block
+ * flagged HFL_SKIP_IF_UNKNOWN) may leave bytes in its body that the
+ * sub-parser did not read. Skip them before returning ARCHIVE_RETRY,
+ * otherwise rar5_read_header() re-parses the same block region O(N)
+ * times instead of O(1), letting a crafted RAR5 file stall the reader
+ * (GHSA-9h2c-464f-j3hj).
+ *
+ * Safe because read_ahead(a, hdr_size, &p) pre-loaded the whole block
+ * into one contiguous buffer with no compaction until we return, so
+ * body_start stays valid and (cur - body_start) is the exact number of
+ * body bytes consumed so far.
+ */
+static void
+rar5_skip_remaining_block(struct archive_read* a,
+ const uint8_t* body_start, size_t raw_hdr_size)
+{
+ const uint8_t* cur;
+
+ if(read_ahead(a, 1, &cur)) {
+ size_t body_used = (size_t)(cur - body_start);
+
+ if(body_used < raw_hdr_size)
+ (void)consume(a, raw_hdr_size - body_used);
+ }
+}
+
static int process_base_block(struct archive_read* a,
struct archive_entry* entry)
{
const size_t SMALLEST_RAR5_BLOCK_SIZE = 3;
- struct rar5* rar = get_context(a);
+ struct rar5 *rar5 = a->format->data;
uint32_t hdr_crc, computed_crc;
size_t raw_hdr_size = 0, hdr_size_len, hdr_size;
size_t header_id = 0;
size_t header_flags = 0;
const uint8_t* p;
+ const uint8_t* body_start;
int ret;
enum HEADER_TYPE {
@@ -2346,6 +2356,10 @@ static int process_base_block(struct archive_read* a,
#endif
}
+ /* Remember the first byte of the block body so we can later skip
+ * any bytes the sub-parser leaves unconsumed. */
+ body_start = p + hdr_size_len;
+
/* If the checksum is OK, we proceed with parsing. */
if(ARCHIVE_OK != consume(a, hdr_size_len)) {
return ARCHIVE_EOF;
@@ -2357,47 +2371,50 @@ static int process_base_block(struct archive_read* a,
if(!read_var_sized(a, &header_flags, NULL))
return ARCHIVE_EOF;
- rar->generic.split_after = (header_flags & HFL_SPLIT_AFTER) > 0;
- rar->generic.split_before = (header_flags & HFL_SPLIT_BEFORE) > 0;
- rar->generic.size = (int)hdr_size;
- rar->generic.last_header_id = (int)header_id;
- rar->main.endarc = 0;
+ rar5->generic.split_after = (header_flags & HFL_SPLIT_AFTER) > 0;
+ rar5->generic.split_before = (header_flags & HFL_SPLIT_BEFORE) > 0;
+ rar5->generic.size = (int)hdr_size;
+ rar5->generic.last_header_id = (int)header_id;
+ rar5->main.endarc = 0;
/* Those are possible header ids in RARv5. */
switch(header_id) {
case HEAD_MAIN:
- ret = process_head_main(a, rar, entry, header_flags);
+ ret = process_head_main(a, rar5, entry, header_flags);
/* Main header doesn't have any files in it, so it's
* pointless to return to the caller. Retry to next
* header, which should be HEAD_FILE/HEAD_SERVICE. */
- if(ret == ARCHIVE_OK)
+ if(ret == ARCHIVE_OK) {
+ rar5_skip_remaining_block(a, body_start,
+ raw_hdr_size);
return ARCHIVE_RETRY;
+ }
return ret;
case HEAD_SERVICE:
- ret = process_head_service(a, rar, entry, header_flags);
+ ret = process_head_service(a, rar5, entry, header_flags);
return ret;
case HEAD_FILE:
- ret = process_head_file(a, rar, entry, header_flags);
+ ret = process_head_file(a, rar5, entry, header_flags);
return ret;
case HEAD_CRYPT:
archive_entry_set_is_metadata_encrypted(entry, 1);
archive_entry_set_is_data_encrypted(entry, 1);
- rar->has_encrypted_entries = 1;
- rar->headers_are_encrypted = 1;
+ rar5->has_encrypted_entries = 1;
+ rar5->headers_are_encrypted = 1;
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Encryption is not supported");
return ARCHIVE_FATAL;
case HEAD_ENDARC:
- rar->main.endarc = 1;
+ rar5->main.endarc = 1;
/* After encountering an end of file marker, we need
* to take into consideration if this archive is
* continued in another file (i.e. is it part01.rar:
* is there a part02.rar?) */
- if(rar->main.volume) {
+ if(rar5->main.volume) {
/* In case there is part02.rar, position the
* read pointer in a proper place, so we can
* resume parsing. */
@@ -2405,7 +2422,7 @@ static int process_base_block(struct archive_read* a,
if(ret == ARCHIVE_FATAL) {
return ARCHIVE_EOF;
} else {
- if(rar->vol.expected_vol_no ==
+ if(rar5->vol.expected_vol_no ==
UINT_MAX) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
@@ -2413,8 +2430,8 @@ static int process_base_block(struct archive_read* a,
return ARCHIVE_FATAL;
}
- rar->vol.expected_vol_no =
- rar->main.vol_no + 1;
+ rar5->vol.expected_vol_no =
+ rar5->main.vol_no + 1;
return ARCHIVE_OK;
}
} else {
@@ -2432,6 +2449,8 @@ static int process_base_block(struct archive_read* a,
/* If the block is marked as 'skip if unknown',
* do as the flag says: skip the block
* instead on failing on it. */
+ rar5_skip_remaining_block(a, body_start,
+ raw_hdr_size);
return ARCHIVE_RETRY;
}
}
@@ -2445,13 +2464,16 @@ static int process_base_block(struct archive_read* a,
}
static int skip_base_block(struct archive_read* a) {
+ struct rar5 *rar5 = a->format->data;
int ret;
- struct rar5* rar = get_context(a);
/* Create a new local archive_entry structure that will be operated on
* by header reader; operations on this archive_entry will be discarded.
*/
struct archive_entry* entry = archive_entry_new();
+ if (entry == NULL)
+ return ARCHIVE_FATAL;
+
ret = process_base_block(a, entry);
/* Discard operations on this archive_entry structure. */
@@ -2459,7 +2481,7 @@ static int skip_base_block(struct archive_read* a) {
if(ret == ARCHIVE_FATAL)
return ret;
- if(rar->generic.last_header_id == 2 && rar->generic.split_before > 0)
+ if(rar5->generic.last_header_id == 2 && rar5->generic.split_before > 0)
return ARCHIVE_OK;
if(ret == ARCHIVE_OK)
@@ -2527,71 +2549,77 @@ fatal:
static int rar5_read_header(struct archive_read *a,
struct archive_entry *entry)
{
- struct rar5* rar = get_context(a);
+ struct rar5 *rar5 = a->format->data;
int ret;
/*
* It should be sufficient to call archive_read_next_header() for
* a reader to determine if an entry is encrypted or not.
*/
- if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
- rar->has_encrypted_entries = 0;
+ if (rar5->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
+ rar5->has_encrypted_entries = 0;
}
- if(rar->header_initialized == 0) {
+ if(rar5->header_initialized == 0) {
init_header(a);
if ((ret = try_skip_sfx(a)) < ARCHIVE_WARN)
return ret;
- rar->header_initialized = 1;
+ rar5->header_initialized = 1;
}
- if(rar->skipped_magic == 0) {
+ if(rar5->skipped_magic == 0) {
if(ARCHIVE_OK != consume(a, sizeof(rar5_signature_xor))) {
return ARCHIVE_EOF;
}
- rar->skipped_magic = 1;
+ rar5->skipped_magic = 1;
}
do {
ret = process_base_block(a, entry);
} while(ret == ARCHIVE_RETRY ||
- (rar->main.endarc > 0 && ret == ARCHIVE_OK));
+ (rar5->main.endarc > 0 && ret == ARCHIVE_OK));
return ret;
}
-static void init_unpack(struct rar5* rar) {
- rar->file.calculated_crc32 = 0;
- init_window_mask(rar);
+static int init_unpack(struct rar5 *rar5) {
+ rar5->file.calculated_crc32 = 0;
+ init_window_mask(rar5);
- free(rar->cstate.window_buf);
- free(rar->cstate.filtered_buf);
+ free(rar5->cstate.window_buf);
+ free(rar5->cstate.filtered_buf);
- if(rar->cstate.window_size > 0) {
- rar->cstate.window_buf = calloc(1, rar->cstate.window_size);
- rar->cstate.filtered_buf = calloc(1, rar->cstate.window_size);
- } else {
- rar->cstate.window_buf = NULL;
- rar->cstate.filtered_buf = NULL;
+ rar5->cstate.window_buf = NULL;
+ rar5->cstate.filtered_buf = NULL;
+
+ if(rar5->cstate.window_size > 0) {
+ rar5->cstate.window_buf = calloc(1, rar5->cstate.window_size);
+ if(rar5->cstate.window_buf == NULL)
+ return ARCHIVE_FATAL;
+ rar5->cstate.filtered_buf = calloc(1,
+ rar5->cstate.window_size);
+ if(rar5->cstate.filtered_buf == NULL)
+ return ARCHIVE_FATAL;
}
- clear_data_ready_stack(rar);
+ clear_data_ready_stack(rar5);
- rar->cstate.write_ptr = 0;
- rar->cstate.last_write_ptr = 0;
+ rar5->cstate.write_ptr = 0;
+ rar5->cstate.last_write_ptr = 0;
- memset(&rar->cstate.bd, 0, sizeof(rar->cstate.bd));
- memset(&rar->cstate.ld, 0, sizeof(rar->cstate.ld));
- memset(&rar->cstate.dd, 0, sizeof(rar->cstate.dd));
- memset(&rar->cstate.ldd, 0, sizeof(rar->cstate.ldd));
- memset(&rar->cstate.rd, 0, sizeof(rar->cstate.rd));
+ memset(&rar5->cstate.bd, 0, sizeof(rar5->cstate.bd));
+ memset(&rar5->cstate.ld, 0, sizeof(rar5->cstate.ld));
+ memset(&rar5->cstate.dd, 0, sizeof(rar5->cstate.dd));
+ memset(&rar5->cstate.ldd, 0, sizeof(rar5->cstate.ldd));
+ memset(&rar5->cstate.rd, 0, sizeof(rar5->cstate.rd));
+ return ARCHIVE_OK;
}
-static void update_crc(struct rar5* rar, const uint8_t* p, size_t to_read) {
+static void update_crc(struct rar5 *rar5, const uint8_t* p, size_t to_read) {
int verify_crc;
- if(rar->skip_mode) {
+ if(rar5->skip_mode) {
#if defined CHECK_CRC_ON_SOLID_SKIP
verify_crc = 1;
#else
@@ -2603,17 +2631,19 @@ static void update_crc(struct rar5* rar, const uint8_t* p, size_t to_read) {
if(verify_crc) {
/* Don't update CRC32 if the file doesn't have the
* `stored_crc32` info filled in. */
- if(rar->file.stored_crc32 > 0) {
- rar->file.calculated_crc32 =
- crc32(rar->file.calculated_crc32, p, (unsigned int)to_read);
+ if(rar5->file.stored_crc32 > 0) {
+ rar5->file.calculated_crc32 =
+ crc32(rar5->file.calculated_crc32, p,
+ (unsigned int)to_read);
}
/* Check if the file uses an optional BLAKE2sp checksum
* algorithm. */
- if(rar->file.has_blake2 > 0) {
+ if(rar5->file.has_blake2 > 0) {
/* Return value of the `update` function is always 0,
* so we can explicitly ignore it here. */
- (void) blake2sp_update(&rar->file.b2state, p, to_read);
+ (void) blake2sp_update(&rar5->file.b2state, p,
+ to_read);
}
}
}
@@ -2647,6 +2677,15 @@ static int create_decode_tables(uint8_t* bit_length,
upper_limit <<= 1;
}
+ /* Verify the code-length distribution is not over-subscribed.
+ * After the loop above, upper_limit == sum(lc[i] * 2^(16-i)).
+ * For a valid prefix-free code this must be <= 2^16 = 65536.
+ * An over-subscribed table (> 65536) cannot produce a valid
+ * decode table and must be rejected. */
+ if(upper_limit > 65536) {
+ return ARCHIVE_FAILED;
+ }
+
memcpy(decode_pos_clone, table->decode_pos, sizeof(decode_pos_clone));
for(i = 0; i < size; i++) {
@@ -2688,12 +2727,12 @@ static int create_decode_tables(uint8_t* bit_length,
static int decode_number(struct archive_read* a, struct decode_table* table,
const uint8_t* p, uint16_t* num)
{
+ struct rar5 *rar5 = a->format->data;
int i, bits, dist, ret;
uint16_t bitfield;
uint32_t pos;
- struct rar5* rar = get_context(a);
- if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &bitfield))) {
+ if(ARCHIVE_OK != (ret = read_bits_16(a, rar5, p, &bitfield))) {
return ret;
}
@@ -2701,7 +2740,7 @@ static int decode_number(struct archive_read* a, struct decode_table* table,
if(bitfield < table->decode_len[table->quick_bits]) {
int code = bitfield >> (16 - table->quick_bits);
- skip_bits(rar, table->quick_len[code]);
+ skip_bits(rar5, table->quick_len[code]);
*num = table->quick_num[code];
return ARCHIVE_OK;
}
@@ -2715,7 +2754,7 @@ static int decode_number(struct archive_read* a, struct decode_table* table,
}
}
- skip_bits(rar, bits);
+ skip_bits(rar5, bits);
dist = bitfield - table->decode_len[bits - 1];
dist >>= (16 - bits);
@@ -2729,7 +2768,7 @@ static int decode_number(struct archive_read* a, struct decode_table* table,
}
/* Reads and parses Huffman tables from the beginning of the block. */
-static int parse_tables(struct archive_read* a, struct rar5* rar,
+static int parse_tables(struct archive_read* a, struct rar5 *rar5,
const uint8_t* p)
{
int ret, value, i, w, idx = 0;
@@ -2743,12 +2782,12 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
/* The data for table generation is compressed using a simple RLE-like
* algorithm when storing zeroes, so we need to unpack it first. */
for(w = 0, i = 0; w < HUFF_BC;) {
- if(i >= rar->cstate.cur_block_size) {
+ if(i >= rar5->cstate.cur_block_size) {
/* Truncated data, can't continue. */
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated data in huffman tables");
- return ARCHIVE_FATAL;
+ return ARCHIVE_FAILED;
}
value = (p[i] & nibble_mask) >> nibble_shift;
@@ -2787,25 +2826,25 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
}
}
- rar->bits.in_addr = i;
- rar->bits.bit_addr = nibble_shift ^ 4;
+ rar5->bits.in_addr = i;
+ rar5->bits.bit_addr = nibble_shift ^ 4;
- ret = create_decode_tables(bit_length, &rar->cstate.bd, HUFF_BC);
+ ret = create_decode_tables(bit_length, &rar5->cstate.bd, HUFF_BC);
if(ret != ARCHIVE_OK) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Decoding huffman tables failed");
- return ARCHIVE_FATAL;
+ return ARCHIVE_FAILED;
}
for(i = 0; i < HUFF_TABLE_SIZE;) {
uint16_t num;
- ret = decode_number(a, &rar->cstate.bd, p, &num);
+ ret = decode_number(a, &rar5->cstate.bd, p, &num);
if(ret != ARCHIVE_OK) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Decoding huffman tables failed");
- return ARCHIVE_FATAL;
+ return ARCHIVE_FAILED;
}
if(num < 16) {
@@ -2816,17 +2855,17 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
/* 16..17: repeat previous code */
uint16_t n;
- if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &n)))
+ if(ARCHIVE_OK != (ret = read_bits_16(a, rar5, p, &n)))
return ret;
if(num == 16) {
n >>= 13;
n += 3;
- skip_bits(rar, 3);
+ skip_bits(rar5, 3);
} else {
n >>= 9;
n += 11;
- skip_bits(rar, 7);
+ skip_bits(rar5, 7);
}
if(i > 0) {
@@ -2839,23 +2878,23 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
ARCHIVE_ERRNO_FILE_FORMAT,
"Unexpected error when decoding "
"huffman tables");
- return ARCHIVE_FATAL;
+ return ARCHIVE_FAILED;
}
} else {
/* other codes: fill with zeroes `n` times */
uint16_t n;
- if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &n)))
+ if(ARCHIVE_OK != (ret = read_bits_16(a, rar5, p, &n)))
return ret;
if(num == 18) {
n >>= 13;
n += 3;
- skip_bits(rar, 3);
+ skip_bits(rar5, 3);
} else {
n >>= 9;
n += 11;
- skip_bits(rar, 7);
+ skip_bits(rar5, 7);
}
while(n-- > 0 && i < HUFF_TABLE_SIZE)
@@ -2863,38 +2902,38 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
}
}
- ret = create_decode_tables(&table[idx], &rar->cstate.ld, HUFF_NC);
+ ret = create_decode_tables(&table[idx], &rar5->cstate.ld, HUFF_NC);
if(ret != ARCHIVE_OK) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Failed to create literal table");
- return ARCHIVE_FATAL;
+ return ARCHIVE_FAILED;
}
idx += HUFF_NC;
- ret = create_decode_tables(&table[idx], &rar->cstate.dd, HUFF_DC);
+ ret = create_decode_tables(&table[idx], &rar5->cstate.dd, HUFF_DC);
if(ret != ARCHIVE_OK) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Failed to create distance table");
- return ARCHIVE_FATAL;
+ return ARCHIVE_FAILED;
}
idx += HUFF_DC;
- ret = create_decode_tables(&table[idx], &rar->cstate.ldd, HUFF_LDC);
+ ret = create_decode_tables(&table[idx], &rar5->cstate.ldd, HUFF_LDC);
if(ret != ARCHIVE_OK) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Failed to create lower bits of distances table");
- return ARCHIVE_FATAL;
+ return ARCHIVE_FAILED;
}
idx += HUFF_LDC;
- ret = create_decode_tables(&table[idx], &rar->cstate.rd, HUFF_RC);
+ ret = create_decode_tables(&table[idx], &rar5->cstate.rd, HUFF_RC);
if(ret != ARCHIVE_OK) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Failed to create repeating distances table");
- return ARCHIVE_FATAL;
+ return ARCHIVE_FAILED;
}
return ARCHIVE_OK;
@@ -2912,7 +2951,7 @@ static int parse_block_header(struct archive_read* a, const uint8_t* p,
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Unsupported block header size (was %d, max is 2)",
bf_byte_count(hdr));
- return ARCHIVE_FATAL;
+ return ARCHIVE_FAILED;
}
/* This should probably use bit reader interface in order to be more
@@ -2956,7 +2995,7 @@ static int parse_block_header(struct archive_read* a, const uint8_t* p,
"Block checksum error: got 0x%x, expected 0x%x",
hdr->block_cksum, calculated_cksum);
- return ARCHIVE_FATAL;
+ return ARCHIVE_FAILED;
#endif
}
@@ -2964,13 +3003,13 @@ static int parse_block_header(struct archive_read* a, const uint8_t* p,
}
/* Convenience function used during filter processing. */
-static int parse_filter_data(struct archive_read* a, struct rar5* rar,
+static int parse_filter_data(struct archive_read* a, struct rar5 *rar5,
const uint8_t* p, uint32_t* filter_data)
{
int i, bytes, ret;
uint32_t data = 0;
- if(ARCHIVE_OK != (ret = read_consume_bits(a, rar, p, 2, &bytes)))
+ if(ARCHIVE_OK != (ret = read_consume_bits(a, rar5, p, 2, &bytes)))
return ret;
bytes++;
@@ -2978,14 +3017,14 @@ static int parse_filter_data(struct archive_read* a, struct rar5* rar,
for(i = 0; i < bytes; i++) {
uint16_t byte;
- if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &byte))) {
+ if(ARCHIVE_OK != (ret = read_bits_16(a, rar5, p, &byte))) {
return ret;
}
/* Cast to uint32_t will ensure the shift operation will not
* produce undefined result. */
data += ((uint32_t) byte >> 8) << (i * 8);
- skip_bits(rar, 8);
+ skip_bits(rar5, 8);
}
*filter_data = data;
@@ -2993,12 +3032,12 @@ static int parse_filter_data(struct archive_read* a, struct rar5* rar,
}
/* Function is used during sanity checking. */
-static int is_valid_filter_block_start(struct rar5* rar,
+static int is_valid_filter_block_start(struct rar5 *rar5,
uint32_t start)
{
- const int64_t block_start = (ssize_t) start + rar->cstate.write_ptr;
- const int64_t last_bs = rar->cstate.last_block_start;
- const ssize_t last_bl = rar->cstate.last_block_length;
+ const int64_t block_start = (ssize_t) start + rar5->cstate.write_ptr;
+ const int64_t last_bs = rar5->cstate.last_block_start;
+ const ssize_t last_bl = rar5->cstate.last_block_length;
if(last_bs == 0 || last_bl == 0) {
/* We didn't have any filters yet, so accept this offset. */
@@ -3018,43 +3057,40 @@ static int is_valid_filter_block_start(struct rar5* rar,
/* The function will create a new filter, read its parameters from the input
* stream and add it to the filter collection. */
static int parse_filter(struct archive_read* ar, const uint8_t* p) {
+ struct rar5 *rar5 = ar->format->data;
uint32_t block_start, block_length;
uint16_t filter_type;
struct filter_info* filt = NULL;
- struct rar5* rar = get_context(ar);
int ret;
/* Read the parameters from the input stream. */
- if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar, p, &block_start)))
+ if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar5, p, &block_start)))
return ret;
- if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar, p, &block_length)))
+ if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar5, p, &block_length)))
return ret;
- if(ARCHIVE_OK != (ret = read_bits_16(ar, rar, p, &filter_type)))
+ if(ARCHIVE_OK != (ret = read_bits_16(ar, rar5, p, &filter_type)))
return ret;
filter_type >>= 13;
- skip_bits(rar, 3);
+ skip_bits(rar5, 3);
- /* Perform some sanity checks on this filter parameters. Note that we
- * allow only DELTA, E8/E9 and ARM filters here, because rest of
- * filters are not used in RARv5. */
+ /* Perform some sanity checks on this filter parameters. */
if(block_length < 4 ||
block_length > 0x400000 ||
- filter_type > FILTER_ARM ||
- !is_valid_filter_block_start(rar, block_start) ||
- (rar->cstate.window_size > 0 &&
- (ssize_t)block_length > rar->cstate.window_size >> 1))
+ !is_valid_filter_block_start(rar5, block_start) ||
+ (rar5->cstate.window_size > 0 &&
+ (ssize_t)block_length > rar5->cstate.window_size >> 1))
{
archive_set_error(&ar->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid filter encountered");
- return ARCHIVE_FATAL;
+ return ARCHIVE_FAILED;
}
/* Allocate a new filter. */
- filt = add_new_filter(rar);
+ filt = add_new_filter(rar5);
if(filt == NULL) {
archive_set_error(&ar->archive, ENOMEM,
"Can't allocate memory for a filter descriptor");
@@ -3062,11 +3098,11 @@ static int parse_filter(struct archive_read* ar, const uint8_t* p) {
}
filt->type = filter_type;
- filt->block_start = rar->cstate.write_ptr + block_start;
+ filt->block_start = rar5->cstate.write_ptr + block_start;
filt->block_length = block_length;
- rar->cstate.last_block_start = filt->block_start;
- rar->cstate.last_block_length = filt->block_length;
+ rar5->cstate.last_block_start = filt->block_start;
+ rar5->cstate.last_block_length = filt->block_length;
/* Read some more data in case this is a DELTA filter. Other filter
* types don't require any additional data over what was already
@@ -3074,7 +3110,7 @@ static int parse_filter(struct archive_read* ar, const uint8_t* p) {
if(filter_type == FILTER_DELTA) {
int channels;
- if(ARCHIVE_OK != (ret = read_consume_bits(ar, rar, p, 5, &channels)))
+ if(ARCHIVE_OK != (ret = read_consume_bits(ar, rar5, p, 5, &channels)))
return ret;
filt->channels = channels + 1;
@@ -3083,7 +3119,7 @@ static int parse_filter(struct archive_read* ar, const uint8_t* p) {
return ARCHIVE_OK;
}
-static int decode_code_length(struct archive_read* a, struct rar5* rar,
+static int decode_code_length(struct archive_read* a, struct rar5 *rar5,
const uint8_t* p, uint16_t code)
{
int lbits, length = 2;
@@ -3099,7 +3135,7 @@ static int decode_code_length(struct archive_read* a, struct rar5* rar,
if(lbits > 0) {
int add;
- if(ARCHIVE_OK != read_consume_bits(a, rar, p, lbits, &add))
+ if(ARCHIVE_OK != read_consume_bits(a, rar5, p, lbits, &add))
return -1;
length += add;
@@ -3109,15 +3145,22 @@ static int decode_code_length(struct archive_read* a, struct rar5* rar,
}
static int copy_string(struct archive_read* a, int len, int dist) {
- struct rar5* rar = get_context(a);
- const ssize_t cmask = rar->cstate.window_mask;
- const uint64_t write_ptr = rar->cstate.write_ptr +
- rar->cstate.solid_offset;
+ struct rar5 *rar5 = a->format->data;
+ const ssize_t cmask = rar5->cstate.window_mask;
+ const uint64_t write_ptr = rar5->cstate.write_ptr +
+ rar5->cstate.solid_offset;
int i;
- if (rar->cstate.window_buf == NULL)
+ if (rar5->cstate.window_buf == NULL)
return ARCHIVE_FATAL;
+ if (rar5->cstate.write_ptr > rar5->file.unpacked_size ||
+ len > rar5->file.unpacked_size - rar5->cstate.write_ptr) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Uncompressed data exceeds declared size");
+ return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
+ }
+
/* The unpacker spends most of the time in this function. It would be
* a good idea to introduce some optimizations here.
*
@@ -3128,26 +3171,26 @@ static int copy_string(struct archive_read* a, int len, int dist) {
for(i = 0; i < len; i++) {
const ssize_t write_idx = (write_ptr + i) & cmask;
const ssize_t read_idx = (write_ptr + i - dist) & cmask;
- rar->cstate.window_buf[write_idx] =
- rar->cstate.window_buf[read_idx];
+ rar5->cstate.window_buf[write_idx] =
+ rar5->cstate.window_buf[read_idx];
}
- rar->cstate.write_ptr += len;
+ rar5->cstate.write_ptr += len;
return ARCHIVE_OK;
}
static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
- struct rar5* rar = get_context(a);
+ struct rar5 *rar5 = a->format->data;
uint16_t num;
int ret;
- const uint64_t cmask = rar->cstate.window_mask;
- const struct compressed_block_header* hdr = &rar->last_block_hdr;
+ const uint64_t cmask = rar5->cstate.window_mask;
+ const struct compressed_block_header* hdr = &rar5->last_block_hdr;
const uint8_t bit_size = 1 + bf_bit_size(hdr);
while(1) {
- if(rar->cstate.write_ptr - rar->cstate.last_write_ptr >
- (rar->cstate.window_size >> 1)) {
+ if(rar5->cstate.write_ptr - rar5->cstate.last_write_ptr >
+ (rar5->cstate.window_size >> 1)) {
/* Don't allow growing data by more than half of the
* window size at a time. In such case, break the loop;
* next call to this function will continue processing
@@ -3155,18 +3198,18 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
break;
}
- if(rar->bits.in_addr > rar->cstate.cur_block_size - 1 ||
- (rar->bits.in_addr == rar->cstate.cur_block_size - 1 &&
- rar->bits.bit_addr >= bit_size))
+ if(rar5->bits.in_addr > rar5->cstate.cur_block_size - 1 ||
+ (rar5->bits.in_addr == rar5->cstate.cur_block_size - 1 &&
+ rar5->bits.bit_addr >= bit_size))
{
/* If the program counter is here, it means the
* function has finished processing the block. */
- rar->cstate.block_parsing_finished = 1;
+ rar5->cstate.block_parsing_finished = 1;
break;
}
/* Decode the next literal. */
- if(ARCHIVE_OK != decode_number(a, &rar->cstate.ld, p, &num)) {
+ if(ARCHIVE_OK != decode_number(a, &rar5->cstate.ld, p, &num)) {
return ARCHIVE_EOF;
}
@@ -3186,15 +3229,25 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
if(num < 256) {
/* Directly store the byte. */
- int64_t write_idx = rar->cstate.solid_offset +
- rar->cstate.write_ptr++;
+ int64_t write_idx;
- rar->cstate.window_buf[write_idx & cmask] =
+ /* A literal write emits one byte; copy_string() checks len. */
+ if(rar5->cstate.write_ptr >= rar5->file.unpacked_size) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Uncompressed data exceeds declared size");
+ return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
+ }
+
+ write_idx = rar5->cstate.solid_offset +
+ rar5->cstate.write_ptr++;
+
+ rar5->cstate.window_buf[write_idx & cmask] =
(uint8_t) num;
continue;
} else if(num >= 262) {
uint16_t dist_slot;
- int len = decode_code_length(a, rar, p, num - 262),
+ int len = decode_code_length(a, rar5, p, num - 262),
dbits,
dist = 1;
@@ -3203,17 +3256,17 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
ARCHIVE_ERRNO_PROGRAMMER,
"Failed to decode the code length");
- return ARCHIVE_FATAL;
+ return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
}
- if(ARCHIVE_OK != decode_number(a, &rar->cstate.dd, p,
+ if(ARCHIVE_OK != decode_number(a, &rar5->cstate.dd, p,
&dist_slot))
{
archive_set_error(&a->archive,
ARCHIVE_ERRNO_PROGRAMMER,
"Failed to decode the distance slot");
- return ARCHIVE_FATAL;
+ return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
}
if(dist_slot < 4) {
@@ -3237,28 +3290,28 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
if(dbits > 4) {
if(ARCHIVE_OK != (ret = read_bits_32(
- a, rar, p, &add))) {
+ a, rar5, p, &add))) {
/* Return EOF if we
* can't read more
* data. */
return ret;
}
- skip_bits(rar, dbits - 4);
+ skip_bits(rar5, dbits - 4);
add = (add >> (
36 - dbits)) << 4;
dist += add;
}
if(ARCHIVE_OK != decode_number(a,
- &rar->cstate.ldd, p, &low_dist))
+ &rar5->cstate.ldd, p, &low_dist))
{
archive_set_error(&a->archive,
ARCHIVE_ERRNO_PROGRAMMER,
"Failed to decode the "
"distance slot");
- return ARCHIVE_FATAL;
+ return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
}
if(dist >= INT_MAX - low_dist - 1) {
@@ -3268,7 +3321,7 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
ARCHIVE_ERRNO_FILE_FORMAT,
"Distance pointer "
"overflow");
- return ARCHIVE_FATAL;
+ return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
}
dist += low_dist;
@@ -3276,7 +3329,7 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
/* dbits is one of [0,1,2,3] */
int add;
- if(ARCHIVE_OK != (ret = read_consume_bits(a, rar,
+ if(ARCHIVE_OK != (ret = read_consume_bits(a, rar5,
p, dbits, &add))) {
/* Return EOF if we can't read
* more data. */
@@ -3299,11 +3352,12 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
}
}
- dist_cache_push(rar, dist);
- rar->cstate.last_len = len;
+ dist_cache_push(rar5, dist);
+ rar5->cstate.last_len = len;
- if(ARCHIVE_OK != copy_string(a, len, dist))
- return ARCHIVE_FATAL;
+ ret = copy_string(a, len, dist);
+ if(ret != ARCHIVE_OK)
+ return ret;
continue;
} else if(num == 256) {
@@ -3314,38 +3368,38 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
continue;
} else if(num == 257) {
- if(rar->cstate.last_len != 0) {
- if(ARCHIVE_OK != copy_string(a,
- rar->cstate.last_len,
- rar->cstate.dist_cache[0]))
- {
- return ARCHIVE_FATAL;
- }
+ if(rar5->cstate.last_len != 0) {
+ ret = copy_string(a,
+ rar5->cstate.last_len,
+ rar5->cstate.dist_cache[0]);
+ if(ret != ARCHIVE_OK)
+ return ret;
}
continue;
} else {
/* num < 262 */
const int idx = num - 258;
- const int dist = dist_cache_touch(rar, idx);
+ const int dist = dist_cache_touch(rar5, idx);
uint16_t len_slot;
int len;
- if(ARCHIVE_OK != decode_number(a, &rar->cstate.rd, p,
+ if(ARCHIVE_OK != decode_number(a, &rar5->cstate.rd, p,
&len_slot)) {
- return ARCHIVE_FATAL;
+ return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
}
- len = decode_code_length(a, rar, p, len_slot);
+ len = decode_code_length(a, rar5, p, len_slot);
if (len == -1) {
- return ARCHIVE_FATAL;
+ return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
}
- rar->cstate.last_len = len;
+ rar5->cstate.last_len = len;
- if(ARCHIVE_OK != copy_string(a, len, dist))
- return ARCHIVE_FATAL;
+ ret = copy_string(a, len, dist);
+ if(ret != ARCHIVE_OK)
+ return ret;
continue;
}
@@ -3403,15 +3457,15 @@ static int scan_for_signature(struct archive_read* a) {
/* This function will switch the multivolume archive file to another file,
* i.e. from part03 to part 04. */
static int advance_multivolume(struct archive_read* a) {
+ struct rar5 *rar5 = a->format->data;
int lret;
- struct rar5* rar = get_context(a);
/* A small state machine that will skip unnecessary data, needed to
* switch from one multivolume to another. Such skipping is needed if
* we want to be an stream-oriented (instead of file-oriented)
* unpacker.
*
- * The state machine starts with `rar->main.endarc` == 0. It also
+ * The state machine starts with `rar5->main.endarc` == 0. It also
* assumes that current stream pointer points to some base block
* header.
*
@@ -3420,10 +3474,10 @@ static int advance_multivolume(struct archive_read* a) {
*/
while(1) {
- if(rar->main.endarc == 1) {
+ if(rar5->main.endarc == 1) {
int looping = 1;
- rar->main.endarc = 0;
+ rar5->main.endarc = 0;
while(looping) {
lret = skip_base_block(a);
@@ -3461,7 +3515,7 @@ static int advance_multivolume(struct archive_read* a) {
/* If there was an error during skipping, or we
* have just skipped a FILE base block... */
- if(rar->main.endarc == 0) {
+ if(rar5->main.endarc == 0) {
return lret;
} else {
continue;
@@ -3480,12 +3534,12 @@ static int advance_multivolume(struct archive_read* a) {
static int merge_block(struct archive_read* a, ssize_t block_size,
const uint8_t** p)
{
- struct rar5* rar = get_context(a);
+ struct rar5 *rar5 = a->format->data;
ssize_t cur_block_size, partial_offset = 0;
const uint8_t* lp;
int ret;
- if(rar->merge_mode) {
+ if(rar5->merge_mode) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Recursive merge is not allowed");
@@ -3493,26 +3547,27 @@ static int merge_block(struct archive_read* a, ssize_t block_size,
}
/* Set a flag that we're in the switching mode. */
- rar->cstate.switch_multivolume = 1;
+ rar5->cstate.switch_multivolume = 1;
/* Reallocate the memory which will hold the whole block. */
- if(rar->vol.push_buf)
- free((void*) rar->vol.push_buf);
+ if(rar5->vol.push_buf)
+ free((void*) rar5->vol.push_buf);
/* Increasing the allocation block by 8 is due to bit reading functions,
* which are using additional 2 or 4 bytes. Allocating the block size
* by exact value would make bit reader perform reads from invalid
* memory block when reading the last byte from the buffer. */
- rar->vol.push_buf = malloc(block_size + 8);
- if(!rar->vol.push_buf) {
+ rar5->vol.push_buf = malloc(block_size + 8);
+ if(!rar5->vol.push_buf) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory for a merge block buffer");
+ rar5->cstate.switch_multivolume = 0;
return ARCHIVE_FATAL;
}
/* Valgrind complains if the extension block for bit reader is not
* initialized, so initialize it. */
- memset(&rar->vol.push_buf[block_size], 0, 8);
+ memset(&rar5->vol.push_buf[block_size], 0, 8);
/* A single block can span across multiple multivolume archive files,
* so we use a loop here. This loop will consume enough multivolume
@@ -3521,18 +3576,24 @@ static int merge_block(struct archive_read* a, ssize_t block_size,
while(1) {
/* Get the size of current block chunk in this multivolume
* archive file and read it. */
- cur_block_size = rar5_min(rar->file.bytes_remaining,
+ cur_block_size = rar5_min(rar5->file.bytes_remaining,
block_size - partial_offset);
- if(cur_block_size == 0) {
+ if(cur_block_size < 1) {
+ /* bytes_remaining is less than 1 at the wrong point in
+ * the merge loop, indicating corrupt volume
+ * accounting. */
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
- "Encountered block size == 0 during block merge");
+ "Encountered invalid block size during block merge");
+ rar5->cstate.switch_multivolume = 0;
return ARCHIVE_FATAL;
}
- if(!read_ahead(a, cur_block_size, &lp))
+ if(!read_ahead(a, cur_block_size, &lp)) {
+ rar5->cstate.switch_multivolume = 0;
return ARCHIVE_EOF;
+ }
/* Sanity check; there should never be a situation where this
* function reads more data than the block's size. */
@@ -3540,22 +3601,27 @@ static int merge_block(struct archive_read* a, ssize_t block_size,
archive_set_error(&a->archive,
ARCHIVE_ERRNO_PROGRAMMER,
"Consumed too much data when merging blocks");
+ rar5->cstate.switch_multivolume = 0;
return ARCHIVE_FATAL;
}
/* Merge previous block chunk with current block chunk,
* or create first block chunk if this is our first
* iteration. */
- memcpy(&rar->vol.push_buf[partial_offset], lp, cur_block_size);
+ memcpy(&rar5->vol.push_buf[partial_offset], lp, cur_block_size);
/* Advance the stream read pointer by this block chunk size. */
- if(ARCHIVE_OK != consume(a, cur_block_size))
- return ARCHIVE_EOF;
+ if(ARCHIVE_OK != consume(a, cur_block_size)) {
+ /* Data was copied but stream pointer didn't advance;
+ * stream position is unrecoverable. */
+ rar5->cstate.switch_multivolume = 0;
+ return ARCHIVE_FATAL;
+ }
/* Update the pointers. `partial_offset` contains information
* about the sum of merged block chunks. */
partial_offset += cur_block_size;
- rar->file.bytes_remaining -= cur_block_size;
+ rar5->file.bytes_remaining -= cur_block_size;
/* If `partial_offset` is the same as `block_size`, this means
* we've merged all block chunks and we have a valid full
@@ -3566,17 +3632,18 @@ static int merge_block(struct archive_read* a, ssize_t block_size,
/* If we don't have any bytes to read, this means we should
* switch to another multivolume archive file. */
- if(rar->file.bytes_remaining == 0) {
- rar->merge_mode++;
+ if(rar5->file.bytes_remaining == 0) {
+ rar5->merge_mode++;
ret = advance_multivolume(a);
- rar->merge_mode--;
+ rar5->merge_mode--;
if(ret != ARCHIVE_OK) {
+ rar5->cstate.switch_multivolume = 0;
return ret;
}
}
}
- *p = rar->vol.push_buf;
+ *p = rar5->vol.push_buf;
/* If we're here, we can resume unpacking by processing the block
* pointed to by the `*p` memory pointer. */
@@ -3585,19 +3652,19 @@ static int merge_block(struct archive_read* a, ssize_t block_size,
}
static int process_block(struct archive_read* a) {
+ struct rar5 *rar5 = a->format->data;
const uint8_t* p;
- struct rar5* rar = get_context(a);
int ret;
/* If we don't have any data to be processed, this most probably means
* we need to switch to the next volume. */
- if(rar->main.volume && rar->file.bytes_remaining == 0) {
+ if(rar5->main.volume && rar5->file.bytes_remaining == 0) {
ret = advance_multivolume(a);
if(ret != ARCHIVE_OK)
return ret;
}
- if(rar->cstate.block_parsing_finished) {
+ if(rar5->cstate.block_parsing_finished) {
ssize_t block_size;
ssize_t to_skip;
ssize_t cur_block_size;
@@ -3617,7 +3684,7 @@ static int process_block(struct archive_read* a) {
* `parse_block_header` as the second argument. */
ret = parse_block_header(a, p, &block_size,
- &rar->last_block_hdr);
+ &rar5->last_block_hdr);
if(ret != ARCHIVE_OK) {
return ret;
}
@@ -3625,12 +3692,21 @@ static int process_block(struct archive_read* a) {
/* Skip block header. Next data is huffman tables,
* if present. */
to_skip = sizeof(struct compressed_block_header) +
- bf_byte_count(&rar->last_block_hdr) + 1;
+ bf_byte_count(&rar5->last_block_hdr) + 1;
+
+ /* If the block header's to_skip value exceeds the declared
+ * remaining data, the archive is malformed. */
+ if(to_skip > rar5->file.bytes_remaining) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Block header size exceeds remaining file data");
+ return ARCHIVE_FATAL;
+ }
if(ARCHIVE_OK != consume(a, to_skip))
return ARCHIVE_EOF;
- rar->file.bytes_remaining -= to_skip;
+ rar5->file.bytes_remaining -= to_skip;
/* The block size gives information about the whole block size,
* but the block could be stored in split form when using
@@ -3639,9 +3715,9 @@ static int process_block(struct archive_read* a) {
* part of the data will be in another file. */
cur_block_size =
- rar5_min(rar->file.bytes_remaining, block_size);
+ rar5_min(rar5->file.bytes_remaining, block_size);
- if(block_size > rar->file.bytes_remaining) {
+ if(block_size > rar5->file.bytes_remaining) {
/* If current blocks' size is bigger than our data
* size, this means we have a multivolume archive.
* In this case, skip all base headers until the end
@@ -3665,7 +3741,7 @@ static int process_block(struct archive_read* a) {
* the *whole* block (merged from partial blocks
* stored in multiple archives files). */
} else {
- rar->cstate.switch_multivolume = 0;
+ rar5->cstate.switch_multivolume = 0;
/* Read the whole block size into memory. This can take
* up to 8 megabytes of memory in theoretical cases.
@@ -3677,16 +3753,16 @@ static int process_block(struct archive_read* a) {
}
}
- rar->cstate.block_buf = p;
- rar->cstate.cur_block_size = cur_block_size;
- rar->cstate.block_parsing_finished = 0;
+ rar5->cstate.block_buf = p;
+ rar5->cstate.cur_block_size = cur_block_size;
+ rar5->cstate.block_parsing_finished = 0;
- rar->bits.in_addr = 0;
- rar->bits.bit_addr = 0;
+ rar5->bits.in_addr = 0;
+ rar5->bits.bit_addr = 0;
- if(bf_is_table_present(&rar->last_block_hdr)) {
+ if(bf_is_table_present(&rar5->last_block_hdr)) {
/* Load Huffman tables. */
- ret = parse_tables(a, rar, p);
+ ret = parse_tables(a, rar5, p);
if(ret != ARCHIVE_OK) {
/* Error during decompression of Huffman
* tables. */
@@ -3695,7 +3771,7 @@ static int process_block(struct archive_read* a) {
}
} else {
/* Block parsing not finished, reuse previous memory buffer. */
- p = rar->cstate.block_buf;
+ p = rar5->cstate.block_buf;
}
/* Uncompress the block, or a part of it, depending on how many bytes
@@ -3708,22 +3784,22 @@ static int process_block(struct archive_read* a) {
return ret;
}
- if(rar->cstate.block_parsing_finished &&
- rar->cstate.switch_multivolume == 0 &&
- rar->cstate.cur_block_size > 0)
+ if(rar5->cstate.block_parsing_finished &&
+ rar5->cstate.switch_multivolume == 0 &&
+ rar5->cstate.cur_block_size > 0)
{
/* If we're processing a normal block, consume the whole
* block. We can do this because we've already read the whole
* block to memory. */
- if(ARCHIVE_OK != consume(a, rar->cstate.cur_block_size))
+ if(ARCHIVE_OK != consume(a, rar5->cstate.cur_block_size))
return ARCHIVE_FATAL;
- rar->file.bytes_remaining -= rar->cstate.cur_block_size;
- } else if(rar->cstate.switch_multivolume) {
+ rar5->file.bytes_remaining -= rar5->cstate.cur_block_size;
+ } else if(rar5->cstate.switch_multivolume) {
/* Don't consume the block if we're doing multivolume
* processing. The volume switching function will consume
* the proper count of bytes instead. */
- rar->cstate.switch_multivolume = 0;
+ rar5->cstate.switch_multivolume = 0;
}
return ARCHIVE_OK;
@@ -3733,13 +3809,13 @@ static int process_block(struct archive_read* a) {
*
* Returns ARCHIVE_OK when those arguments can be used, ARCHIVE_RETRY
* when there is no data on the stack. */
-static int use_data(struct rar5* rar, const void** buf, size_t* size,
+static int use_data(struct rar5 *rar5, const void** buf, size_t* size,
int64_t* offset)
{
int i;
- for(i = 0; i < rar5_countof(rar->cstate.dready); i++) {
- struct data_ready *d = &rar->cstate.dready[i];
+ for(i = 0; i < rar5_countof(rar5->cstate.dready); i++) {
+ struct data_ready *d = &rar5->cstate.dready[i];
if(d->used) {
if(buf) *buf = d->buf;
@@ -3754,14 +3830,14 @@ static int use_data(struct rar5* rar, const void** buf, size_t* size,
return ARCHIVE_RETRY;
}
-static void clear_data_ready_stack(struct rar5* rar) {
- memset(&rar->cstate.dready, 0, sizeof(rar->cstate.dready));
+static void clear_data_ready_stack(struct rar5 *rar5) {
+ memset(&rar5->cstate.dready, 0, sizeof(rar5->cstate.dready));
}
-/* Pushes the `buf`, `size` and `offset` arguments to the rar->cstate.dready
+/* Pushes the `buf`, `size` and `offset` arguments to the rar5->cstate.dready
* FIFO stack. Those values will be popped from this stack by the `use_data`
* function. */
-static int push_data_ready(struct archive_read* a, struct rar5* rar,
+static int push_data_ready(struct archive_read* a, struct rar5 *rar5,
const uint8_t* buf, size_t size, int64_t offset)
{
int i;
@@ -3772,18 +3848,18 @@ static int push_data_ready(struct archive_read* a, struct rar5* rar,
* because we're interested only in the side effect: building up the
* internal window circular buffer. This window buffer will be used
* later during unpacking of requested data. */
- if(rar->skip_mode)
+ if(rar5->skip_mode)
return ARCHIVE_OK;
/* Sanity check. */
- if(offset != rar->file.last_offset + rar->file.last_size) {
+ if(offset != rar5->file.last_offset + rar5->file.last_size) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Sanity check error: output stream is not continuous");
return ARCHIVE_FATAL;
}
- for(i = 0; i < rar5_countof(rar->cstate.dready); i++) {
- struct data_ready* d = &rar->cstate.dready[i];
+ for(i = 0; i < rar5_countof(rar5->cstate.dready); i++) {
+ struct data_ready* d = &rar5->cstate.dready[i];
if(!d->used) {
d->used = 1;
d->buf = buf;
@@ -3791,21 +3867,21 @@ static int push_data_ready(struct archive_read* a, struct rar5* rar,
d->offset = offset;
/* These fields are used only in sanity checking. */
- rar->file.last_offset = offset;
- rar->file.last_size = size;
+ rar5->file.last_offset = offset;
+ rar5->file.last_size = size;
/* Calculate the checksum of this new block before
* submitting data to libarchive's engine. */
- update_crc(rar, d->buf, d->size);
+ update_crc(rar5, d->buf, d->size);
return ARCHIVE_OK;
}
}
- /* Program counter will reach this code if the `rar->cstate.data_ready`
- * stack will be filled up so that no new entries will be allowed. The
- * code shouldn't allow such situation to occur. So we treat this case
- * as an internal error. */
+ /* Program counter will reach this code if the
+ * `rar5->cstate.data_ready` stack will be filled up so that no new
+ * entries will be allowed. The code shouldn't allow such situation to
+ * occur. So we treat this case as an internal error. */
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Premature end of data_ready stack");
@@ -3855,31 +3931,32 @@ static int push_data_ready(struct archive_read* a, struct rar5* rar,
* */
static int do_uncompress_file(struct archive_read* a) {
- struct rar5* rar = get_context(a);
+ struct rar5 *rar5 = a->format->data;
int ret;
int64_t max_end_pos;
- if(!rar->cstate.initialized) {
+ if(!rar5->cstate.initialized) {
/* Don't perform full context reinitialization if we're
* processing a solid archive. */
- if(!rar->main.solid || !rar->cstate.window_buf) {
- init_unpack(rar);
+ if(!rar5->main.solid || !rar5->cstate.window_buf) {
+ if((ret = init_unpack(rar5)) != ARCHIVE_OK)
+ return ret;
}
- rar->cstate.initialized = 1;
+ rar5->cstate.initialized = 1;
}
/* Don't allow extraction if window_size is invalid. */
- if(rar->cstate.window_size == 0) {
+ if(rar5->cstate.window_size == 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid window size declaration in this file");
/* This should never happen in valid files. */
- return ARCHIVE_FATAL;
+ return ARCHIVE_FAILED;
}
- if(rar->cstate.all_filters_applied == 1) {
+ if(rar5->cstate.all_filters_applied == 1) {
/* We use while(1) here, but standard case allows for just 1
* iteration. The loop will iterate if process_block() didn't
* generate any data at all. This can happen if the block
@@ -3887,15 +3964,15 @@ static int do_uncompress_file(struct archive_read* a) {
* files). */
while(1) {
ret = process_block(a);
- if(ret == ARCHIVE_EOF || ret == ARCHIVE_FATAL)
+ if(ret != ARCHIVE_OK)
return ret;
- if(rar->cstate.last_write_ptr ==
- rar->cstate.write_ptr) {
+ if(rar5->cstate.last_write_ptr ==
+ rar5->cstate.write_ptr) {
/* The block didn't generate any new data,
* so just process a new block if this one
* wasn't the last block in the file. */
- if (bf_is_last_block(&rar->last_block_hdr)) {
+ if (bf_is_last_block(&rar5->last_block_hdr)) {
return ARCHIVE_EOF;
}
@@ -3913,19 +3990,17 @@ static int do_uncompress_file(struct archive_read* a) {
ret = apply_filters(a);
if(ret == ARCHIVE_RETRY) {
return ARCHIVE_OK;
- } else if(ret == ARCHIVE_FATAL) {
- return ARCHIVE_FATAL;
+ } else if(ret != ARCHIVE_OK) {
+ return ret;
}
- /* If apply_filters() will return ARCHIVE_OK, we can continue here. */
-
- if(cdeque_size(&rar->cstate.filters) > 0) {
+ if(cdeque_size(&rar5->cstate.filters) > 0) {
/* Check if we can write something before hitting first
* filter. */
struct filter_info* flt;
/* Get the block_start offset from the first filter. */
- if(CDE_OK != cdeque_front(&rar->cstate.filters,
+ if(CDE_OK != cdeque_front(&rar5->cstate.filters,
cdeque_filter_p(&flt)))
{
archive_set_error(&a->archive,
@@ -3935,15 +4010,15 @@ static int do_uncompress_file(struct archive_read* a) {
}
max_end_pos = rar5_min(flt->block_start,
- rar->cstate.write_ptr);
+ rar5->cstate.write_ptr);
} else {
/* There are no filters defined, or all filters were applied.
* This means we can just store the data without any
* postprocessing. */
- max_end_pos = rar->cstate.write_ptr;
+ max_end_pos = rar5->cstate.write_ptr;
}
- if(max_end_pos == rar->cstate.last_write_ptr) {
+ if(max_end_pos == rar5->cstate.last_write_ptr) {
/* We can't write anything yet. The block uncompression
* function did not generate enough data, and no filter can be
* applied. At the same time we don't have any data that can be
@@ -3960,9 +4035,9 @@ static int do_uncompress_file(struct archive_read* a) {
* So let's do it. The push_window_data() function will
* effectively return the selected data block to the user
* application. */
- push_window_data(a, rar, rar->cstate.last_write_ptr,
+ push_window_data(a, rar5, rar5->cstate.last_write_ptr,
max_end_pos);
- rar->cstate.last_write_ptr = max_end_pos;
+ rar5->cstate.last_write_ptr = max_end_pos;
}
return ARCHIVE_OK;
@@ -3983,19 +4058,19 @@ static int uncompress_file(struct archive_read* a) {
static int do_unstore_file(struct archive_read* a,
- struct rar5* rar, const void** buf, size_t* size, int64_t* offset)
+ struct rar5 *rar5, const void** buf, size_t* size, int64_t* offset)
{
size_t to_read;
const uint8_t* p;
- if(rar->file.bytes_remaining == 0 && rar->main.volume > 0 &&
- rar->generic.split_after > 0)
+ if(rar5->file.bytes_remaining == 0 && rar5->main.volume > 0 &&
+ rar5->generic.split_after > 0)
{
int ret;
- rar->cstate.switch_multivolume = 1;
+ rar5->cstate.switch_multivolume = 1;
ret = advance_multivolume(a);
- rar->cstate.switch_multivolume = 0;
+ rar5->cstate.switch_multivolume = 0;
if(ret != ARCHIVE_OK) {
/* Failed to advance to next multivolume archive
@@ -4004,7 +4079,7 @@ static int do_unstore_file(struct archive_read* a,
}
}
- to_read = rar5_min(rar->file.bytes_remaining, 64 * 1024);
+ to_read = rar5_min(rar5->file.bytes_remaining, 64 * 1024);
if(to_read == 0) {
return ARCHIVE_EOF;
}
@@ -4021,16 +4096,16 @@ static int do_unstore_file(struct archive_read* a,
if(buf) *buf = p;
if(size) *size = to_read;
- if(offset) *offset = rar->cstate.last_unstore_ptr;
+ if(offset) *offset = rar5->cstate.last_unstore_ptr;
- rar->file.bytes_remaining -= to_read;
- rar->cstate.last_unstore_ptr += to_read;
+ rar5->file.bytes_remaining -= to_read;
+ rar5->cstate.last_unstore_ptr += to_read;
- update_crc(rar, p, to_read);
+ update_crc(rar5, p, to_read);
return ARCHIVE_OK;
}
-static int do_unpack(struct archive_read* a, struct rar5* rar,
+static int do_unpack(struct archive_read* a, struct rar5 *rar5,
const void** buf, size_t* size, int64_t* offset)
{
enum COMPRESSION_METHOD {
@@ -4038,12 +4113,12 @@ static int do_unpack(struct archive_read* a, struct rar5* rar,
BEST = 5
};
- if(rar->file.service > 0) {
- return do_unstore_file(a, rar, buf, size, offset);
+ if(rar5->file.service > 0) {
+ return do_unstore_file(a, rar5, buf, size, offset);
} else {
- switch(rar->cstate.method) {
+ switch(rar5->cstate.method) {
case STORE:
- return do_unstore_file(a, rar, buf, size,
+ return do_unstore_file(a, rar5, buf, size,
offset);
case FASTEST:
/* fallthrough */
@@ -4060,13 +4135,13 @@ static int do_unpack(struct archive_read* a, struct rar5* rar,
* accordingly. At this point the decoder doesn't have any
* pending uncompressed data blocks, so the current position in
* the output file should be last_write_ptr. */
- if (offset) *offset = rar->cstate.last_write_ptr;
+ if (offset) *offset = rar5->cstate.last_write_ptr;
return uncompress_file(a);
default:
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Compression method not supported: 0x%x",
- (unsigned int)rar->cstate.method);
+ (unsigned int)rar5->cstate.method);
return ARCHIVE_FATAL;
}
@@ -4079,15 +4154,15 @@ static int do_unpack(struct archive_read* a, struct rar5* rar,
}
static int verify_checksums(struct archive_read* a) {
+ struct rar5 *rar5 = a->format->data;
int verify_crc;
- struct rar5* rar = get_context(a);
/* Check checksums only when actually unpacking the data. There's no
* need to calculate checksum when we're skipping data in solid archives
* (skipping in solid archives is the same thing as unpacking compressed
* data and discarding the result). */
- if(!rar->skip_mode) {
+ if(!rar5->skip_mode) {
/* Always check checksums if we're not in skip mode */
verify_crc = 1;
} else {
@@ -4111,39 +4186,39 @@ static int verify_checksums(struct archive_read* a) {
* process is already over and we can check if calculated
* checksum (CRC32 or BLAKE2sp) is the same as what is stored
* in the archive. */
- if(rar->file.stored_crc32 > 0) {
+ if(rar5->file.stored_crc32 > 0) {
/* Check CRC32 only when the file contains a CRC32
* value for this file. */
- if(rar->file.calculated_crc32 !=
- rar->file.stored_crc32) {
+ if(rar5->file.calculated_crc32 !=
+ rar5->file.stored_crc32) {
/* Checksums do not match; the unpacked file
* is corrupted. */
DEBUG_CODE {
printf("Checksum error: CRC32 "
"(was: %08" PRIx32 ", expected: %08" PRIx32 ")\n",
- rar->file.calculated_crc32,
- rar->file.stored_crc32);
+ rar5->file.calculated_crc32,
+ rar5->file.stored_crc32);
}
#ifndef DONT_FAIL_ON_CRC_ERROR
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Checksum error: CRC32");
- return ARCHIVE_FATAL;
+ return ARCHIVE_FAILED;
#endif
} else {
DEBUG_CODE {
printf("Checksum OK: CRC32 "
"(%08" PRIx32 "/%08" PRIx32 ")\n",
- rar->file.stored_crc32,
- rar->file.calculated_crc32);
+ rar5->file.stored_crc32,
+ rar5->file.calculated_crc32);
}
}
}
- if(rar->file.has_blake2 > 0) {
+ if(rar5->file.has_blake2 > 0) {
/* BLAKE2sp is an optional checksum algorithm that is
* added to RARv5 archives when using the `-htb` switch
* during creation of archive.
@@ -4158,15 +4233,15 @@ static int verify_checksums(struct archive_read* a) {
* This is why we're explicitly ignoring it. */
uint8_t b2_buf[32];
- (void) blake2sp_final(&rar->file.b2state, b2_buf, 32);
+ (void) blake2sp_final(&rar5->file.b2state, b2_buf, 32);
- if(memcmp(&rar->file.blake2sp, b2_buf, 32) != 0) {
+ if(memcmp(&rar5->file.blake2sp, b2_buf, 32) != 0) {
#ifndef DONT_FAIL_ON_CRC_ERROR
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Checksum error: BLAKE2");
- return ARCHIVE_FATAL;
+ return ARCHIVE_FAILED;
#endif
}
}
@@ -4194,23 +4269,23 @@ static void rar5_signature(char *buf) {
static int rar5_read_data(struct archive_read *a, const void **buff,
size_t *size, int64_t *offset) {
+ struct rar5 *rar5 = a->format->data;
int ret;
- struct rar5* rar = get_context(a);
if (size)
*size = 0;
- if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
- rar->has_encrypted_entries = 0;
+ if (rar5->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
+ rar5->has_encrypted_entries = 0;
}
- if (rar->headers_are_encrypted || rar->cstate.data_encrypted) {
+ if (rar5->headers_are_encrypted || rar5->cstate.data_encrypted) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Reading encrypted data is not currently supported");
- return ARCHIVE_FATAL;
+ return ARCHIVE_FAILED;
}
- if(rar->file.dir > 0) {
+ if(rar5->file.dir > 0) {
/* Don't process any data if this file entry was declared
* as a directory. This is needed, because entries marked as
* directory doesn't have any dictionary buffer allocated, so
@@ -4220,28 +4295,28 @@ static int rar5_read_data(struct archive_read *a, const void **buff,
return ARCHIVE_FATAL;
}
- if(!rar->skip_mode && (rar->cstate.last_write_ptr > rar->file.unpacked_size)) {
+ if(!rar5->skip_mode && (rar5->cstate.last_write_ptr > rar5->file.unpacked_size)) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Unpacker has written too many bytes");
return ARCHIVE_FATAL;
}
- ret = use_data(rar, buff, size, offset);
+ ret = use_data(rar5, buff, size, offset);
if(ret == ARCHIVE_OK) {
return ret;
}
- if(rar->file.eof == 1) {
+ if(rar5->file.eof == 1) {
return ARCHIVE_EOF;
}
- ret = do_unpack(a, rar, buff, size, offset);
+ ret = do_unpack(a, rar5, buff, size, offset);
if(ret != ARCHIVE_OK) {
return ret;
}
- if(rar->file.bytes_remaining == 0 &&
- rar->cstate.last_write_ptr == rar->file.unpacked_size)
+ if(rar5->file.bytes_remaining == 0 &&
+ rar5->cstate.last_write_ptr == rar5->file.unpacked_size)
{
/* If all bytes of current file were processed, run
* finalization.
@@ -4251,7 +4326,7 @@ static int rar5_read_data(struct archive_read *a, const void **buff,
* value in the last `archive_read_data` call to signal an error
* to the user. */
- rar->file.eof = 1;
+ rar5->file.eof = 1;
return verify_global_checksums(a);
}
@@ -4259,21 +4334,21 @@ static int rar5_read_data(struct archive_read *a, const void **buff,
}
static int rar5_read_data_skip(struct archive_read *a) {
- struct rar5* rar = get_context(a);
+ struct rar5 *rar5 = a->format->data;
- if(rar->main.solid && (rar->cstate.data_encrypted == 0)) {
+ if(rar5->main.solid && (rar5->cstate.data_encrypted == 0)) {
/* In solid archives, instead of skipping the data, we need to
* extract it, and dispose the result. The side effect of this
* operation will be setting up the initial window buffer state
* needed to be able to extract the selected file. Note that
- * this is only possible when data withing this solid block is
+ * this is only possible when data within this solid block is
* not encrypted, in which case we'll skip and fail if the user
* tries to read data. */
int ret;
/* Make sure to process all blocks in the compressed stream. */
- while(rar->file.bytes_remaining > 0) {
+ while(rar5->file.bytes_remaining > 0) {
/* Setting the "skip mode" will allow us to skip
* checksum checks during data skipping. Checking the
* checksum of skipped data isn't really necessary and
@@ -4282,14 +4357,14 @@ static int rar5_read_data_skip(struct archive_read *a) {
* This is incremented instead of setting to 1 because
* this data skipping function can be called
* recursively. */
- rar->skip_mode++;
+ rar5->skip_mode++;
/* We're disposing 1 block of data, so we use triple
* NULLs in arguments. */
ret = rar5_read_data(a, NULL, NULL, NULL);
/* Turn off "skip mode". */
- rar->skip_mode--;
+ rar5->skip_mode--;
if(ret < 0 || ret == ARCHIVE_EOF) {
/* Propagate any potential error conditions
@@ -4302,11 +4377,11 @@ static int rar5_read_data_skip(struct archive_read *a) {
* stream. Each file in non-solid archives starts from an empty
* window buffer. */
- if(ARCHIVE_OK != consume(a, rar->file.bytes_remaining)) {
+ if(ARCHIVE_OK != consume(a, rar5->file.bytes_remaining)) {
return ARCHIVE_FATAL;
}
- rar->file.bytes_remaining = 0;
+ rar5->file.bytes_remaining = 0;
}
return ARCHIVE_OK;
@@ -4315,28 +4390,30 @@ static int rar5_read_data_skip(struct archive_read *a) {
static int64_t rar5_seek_data(struct archive_read *a, int64_t offset,
int whence)
{
- (void) a;
(void) offset;
(void) whence;
- /* We're a streaming unpacker, and we don't support seeking. */
+ /* We're a streaming unpacker, and we don't support seeking.
+ * That's a capability gap, not a fatal error. */
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Seeking of RAR5 files is unsupported");
- return ARCHIVE_FATAL;
+ return (ARCHIVE_FAILED);
}
static int rar5_cleanup(struct archive_read *a) {
- struct rar5* rar = get_context(a);
+ struct rar5 *rar5 = a->format->data;
- free(rar->cstate.window_buf);
- free(rar->cstate.filtered_buf);
- clear_data_ready_stack(rar);
+ free(rar5->cstate.window_buf);
+ free(rar5->cstate.filtered_buf);
+ clear_data_ready_stack(rar5);
- free(rar->vol.push_buf);
+ free(rar5->vol.push_buf);
- free_filters(rar);
- rar5_deinit(rar);
+ free_filters(rar5);
+ rar5_deinit(rar5);
- free(rar);
+ free(rar5);
a->format->data = NULL;
return ARCHIVE_OK;
@@ -4350,9 +4427,9 @@ static int rar5_capabilities(struct archive_read * a) {
static int rar5_has_encrypted_entries(struct archive_read *_a) {
if (_a && _a->format) {
- struct rar5 *rar = (struct rar5 *)_a->format->data;
- if (rar) {
- return rar->has_encrypted_entries;
+ struct rar5 *rar5 = _a->format->data;
+ if (rar5) {
+ return rar5->has_encrypted_entries;
}
}
@@ -4360,50 +4437,50 @@ static int rar5_has_encrypted_entries(struct archive_read *_a) {
}
/* Must match deallocations in rar5_deinit */
-static int rar5_init(struct rar5* rar) {
- memset(rar, 0, sizeof(struct rar5));
+static int rar5_init(struct rar5 *rar5) {
+ memset(rar5, 0, sizeof(struct rar5));
- if(CDE_OK != cdeque_init(&rar->cstate.filters, 8192))
+ if(CDE_OK != cdeque_init(&rar5->cstate.filters, 8192))
return ARCHIVE_FATAL;
/*
* Until enough data has been read, we cannot tell about
* any encrypted entries yet.
*/
- rar->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
+ rar5->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
return ARCHIVE_OK;
}
/* Must match allocations in rar5_init */
-static void rar5_deinit(struct rar5* rar) {
- cdeque_free(&rar->cstate.filters);
+static void rar5_deinit(struct rar5 *rar5) {
+ cdeque_free(&rar5->cstate.filters);
}
int archive_read_support_format_rar5(struct archive *_a) {
struct archive_read* ar;
int ret;
- struct rar5* rar;
+ struct rar5 *rar5;
if(ARCHIVE_OK != (ret = get_archive_read(_a, &ar)))
return ret;
- rar = malloc(sizeof(*rar));
- if(rar == NULL) {
+ rar5 = malloc(sizeof(*rar5));
+ if(rar5 == NULL) {
archive_set_error(&ar->archive, ENOMEM,
"Can't allocate rar5 data");
return ARCHIVE_FATAL;
}
- if(ARCHIVE_OK != rar5_init(rar)) {
+ if(ARCHIVE_OK != rar5_init(rar5)) {
archive_set_error(&ar->archive, ENOMEM,
"Can't allocate rar5 filter buffer");
- free(rar);
+ free(rar5);
return ARCHIVE_FATAL;
}
ret = __archive_read_register_format(ar,
- rar,
+ rar5,
"rar5",
rar5_bid,
rar5_options,
@@ -4416,8 +4493,8 @@ int archive_read_support_format_rar5(struct archive *_a) {
rar5_has_encrypted_entries);
if(ret != ARCHIVE_OK) {
- rar5_deinit(rar);
- free(rar);
+ rar5_deinit(rar5);
+ free(rar5);
}
return ARCHIVE_OK;
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_raw.c b/contrib/libarchive/libarchive/archive_read_support_format_raw.c
index e935396dda6f..cda3c1e49c59 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_raw.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_raw.c
@@ -34,10 +34,11 @@
#include "archive.h"
#include "archive_entry.h"
+#include "archive_integer.h"
#include "archive_private.h"
#include "archive_read_private.h"
-struct raw_info {
+struct raw {
int64_t offset; /* Current position in the file. */
int64_t unconsumed;
int end_of_file;
@@ -54,22 +55,22 @@ static int archive_read_format_raw_read_header(struct archive_read *,
int
archive_read_support_format_raw(struct archive *_a)
{
- struct raw_info *info;
struct archive_read *a = (struct archive_read *)_a;
+ struct raw *raw;
int r;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_format_raw");
- info = calloc(1, sizeof(*info));
- if (info == NULL) {
+ raw = calloc(1, sizeof(*raw));
+ if (raw == NULL) {
archive_set_error(&a->archive, ENOMEM,
- "Can't allocate raw_info data");
+ "Can't allocate raw data");
return (ARCHIVE_FATAL);
}
r = __archive_read_register_format(a,
- info,
+ raw,
"raw",
archive_read_format_raw_bid,
NULL,
@@ -81,7 +82,7 @@ archive_read_support_format_raw(struct archive *_a)
NULL,
NULL);
if (r != ARCHIVE_OK)
- free(info);
+ free(raw);
return (r);
}
@@ -107,10 +108,9 @@ static int
archive_read_format_raw_read_header(struct archive_read *a,
struct archive_entry *entry)
{
- struct raw_info *info;
+ struct raw *raw = a->format->data;
- info = (struct raw_info *)(a->format->data);
- if (info->end_of_file)
+ if (raw->end_of_file)
return (ARCHIVE_EOF);
a->archive.archive_format = ARCHIVE_FORMAT_RAW;
@@ -128,39 +128,43 @@ static int
archive_read_format_raw_read_data(struct archive_read *a,
const void **buff, size_t *size, int64_t *offset)
{
- struct raw_info *info;
+ struct raw *raw = a->format->data;
ssize_t avail;
- info = (struct raw_info *)(a->format->data);
-
/* Consume the bytes we read last time. */
- if (info->unconsumed) {
- __archive_read_consume(a, info->unconsumed);
- info->unconsumed = 0;
+ if (raw->unconsumed) {
+ __archive_read_consume(a, raw->unconsumed);
+ raw->unconsumed = 0;
}
- if (info->end_of_file)
+ if (raw->end_of_file)
return (ARCHIVE_EOF);
/* Get whatever bytes are immediately available. */
*buff = __archive_read_ahead(a, 1, &avail);
if (avail > 0) {
/* Return the bytes we just read */
+ *offset = raw->offset;
+ if (archive_ckd_add_i64(&raw->offset, raw->offset, avail)) {
+ avail = INT64_MAX - *offset;
+ if (avail == 0) {
+ *size = 0;
+ return (ARCHIVE_FATAL);
+ }
+ }
*size = avail;
- *offset = info->offset;
- info->offset += *size;
- info->unconsumed = avail;
+ raw->unconsumed = avail;
return (ARCHIVE_OK);
} else if (0 == avail) {
/* Record and return end-of-file. */
- info->end_of_file = 1;
+ raw->end_of_file = 1;
*size = 0;
- *offset = info->offset;
+ *offset = raw->offset;
return (ARCHIVE_EOF);
} else {
/* Record and return an error. */
*size = 0;
- *offset = info->offset;
+ *offset = raw->offset;
return ((int)avail);
}
}
@@ -168,24 +172,23 @@ archive_read_format_raw_read_data(struct archive_read *a,
static int
archive_read_format_raw_read_data_skip(struct archive_read *a)
{
- struct raw_info *info = (struct raw_info *)(a->format->data);
+ struct raw *raw = a->format->data;
/* Consume the bytes we read last time. */
- if (info->unconsumed) {
- __archive_read_consume(a, info->unconsumed);
- info->unconsumed = 0;
+ if (raw->unconsumed) {
+ __archive_read_consume(a, raw->unconsumed);
+ raw->unconsumed = 0;
}
- info->end_of_file = 1;
+ raw->end_of_file = 1;
return (ARCHIVE_OK);
}
static int
archive_read_format_raw_cleanup(struct archive_read *a)
{
- struct raw_info *info;
+ struct raw *raw = a->format->data;
- info = (struct raw_info *)(a->format->data);
- free(info);
+ free(raw);
a->format->data = NULL;
return (ARCHIVE_OK);
}
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_tar.c b/contrib/libarchive/libarchive/archive_read_support_format_tar.c
index 2979492767ed..b73c0d9372e4 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_tar.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_tar.c
@@ -42,6 +42,7 @@
#include "archive_acl_private.h" /* For ACL parsing routines. */
#include "archive_entry.h"
#include "archive_entry_locale.h"
+#include "archive_integer.h"
#include "archive_private.h"
#include "archive_read_private.h"
@@ -153,6 +154,8 @@ struct tar {
int compat_2x;
int process_mac_extensions;
int read_concatenated_archives;
+ int default_inode;
+ int default_dev;
};
/* Track which size fields were present in the headers */
@@ -297,9 +300,8 @@ archive_read_support_format_tar(struct archive *_a)
static int
archive_read_format_tar_cleanup(struct archive_read *a)
{
- struct tar *tar;
+ struct tar *tar = a->format->data;
- tar = (struct tar *)(a->format->data);
gnu_clear_sparse_list(tar);
archive_string_free(&tar->entry_pathname);
archive_string_free(&tar->entry_pathname_override);
@@ -309,7 +311,7 @@ archive_read_format_tar_cleanup(struct archive_read *a)
archive_string_free(&tar->line);
archive_string_free(&tar->localname);
free(tar);
- (a->format->data) = NULL;
+ a->format->data = NULL;
return (ARCHIVE_OK);
}
@@ -436,10 +438,9 @@ static int
archive_read_format_tar_options(struct archive_read *a,
const char *key, const char *val)
{
- struct tar *tar;
+ struct tar *tar = a->format->data;
int ret = ARCHIVE_FAILED;
- tar = (struct tar *)(a->format->data);
if (strcmp(key, "compat-2x") == 0) {
/* Handle UTF-8 filenames as libarchive 2.x */
tar->compat_2x = (val != NULL && val[0] != 0);
@@ -522,11 +523,7 @@ archive_read_format_tar_read_header(struct archive_read *a,
* probably not worthwhile just to support the relatively
* obscure tar->cpio conversion case.
*/
- /* TODO: Move this into `struct tar` to avoid conflicts
- * when reading multiple archives */
- static int default_inode;
- static int default_dev;
- struct tar *tar;
+ struct tar *tar = a->format->data;
const char *p;
const wchar_t *wp;
int r;
@@ -534,15 +531,14 @@ archive_read_format_tar_read_header(struct archive_read *a,
int64_t unconsumed = 0;
/* Assign default device/inode values. */
- archive_entry_set_dev(entry, 1 + default_dev); /* Don't use zero. */
- archive_entry_set_ino(entry, ++default_inode); /* Don't use zero. */
+ archive_entry_set_dev(entry, 1 + tar->default_dev); /* Don't use zero. */
+ archive_entry_set_ino(entry, ++tar->default_inode); /* Don't use zero. */
/* Limit generated st_ino number to 16 bits. */
- if (default_inode >= 0xffff) {
- ++default_dev;
- default_inode = 0;
+ if (tar->default_inode >= 0xffff) {
+ ++tar->default_dev;
+ tar->default_inode = 0;
}
- tar = (struct tar *)(a->format->data);
tar->entry_offset = 0;
gnu_clear_sparse_list(tar);
tar->size_fields = 0; /* We don't have any size info yet */
@@ -586,16 +582,16 @@ archive_read_format_tar_read_header(struct archive_read *a,
* directory: This is needed for certain old tar
* variants and even for some broken newer ones.
*/
- if ((wp = archive_entry_pathname_w(entry)) != NULL) {
- l = wcslen(wp);
- if (l > 0 && wp[l - 1] == L'/') {
+ if ((p = archive_entry_pathname(entry)) != NULL) {
+ l = strlen(p);
+ if (l > 0 && p[l - 1] == '/') {
archive_entry_set_filetype(entry, AE_IFDIR);
tar->entry_bytes_remaining = 0;
tar->entry_padding = 0;
}
- } else if ((p = archive_entry_pathname(entry)) != NULL) {
- l = strlen(p);
- if (l > 0 && p[l - 1] == '/') {
+ } else if ((wp = archive_entry_pathname_w(entry)) != NULL) {
+ l = wcslen(wp);
+ if (l > 0 && wp[l - 1] == L'/') {
archive_entry_set_filetype(entry, AE_IFDIR);
tar->entry_bytes_remaining = 0;
tar->entry_padding = 0;
@@ -609,12 +605,10 @@ static int
archive_read_format_tar_read_data(struct archive_read *a,
const void **buff, size_t *size, int64_t *offset)
{
+ struct tar *tar = a->format->data;
ssize_t bytes_read;
- struct tar *tar;
struct sparse_block *p;
- tar = (struct tar *)(a->format->data);
-
for (;;) {
/* Remove exhausted entries from sparse list. */
while (tar->sparse_list != NULL &&
@@ -673,10 +667,8 @@ archive_read_format_tar_read_data(struct archive_read *a,
static int
archive_read_format_tar_skip(struct archive_read *a)
{
+ struct tar *tar = a->format->data;
int64_t request;
- struct tar* tar;
-
- tar = (struct tar *)(a->format->data);
request = tar->entry_bytes_remaining + tar->entry_padding +
tar->entry_bytes_unconsumed;
@@ -1074,21 +1066,19 @@ static int
header_Solaris_ACL(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, const void *h, int64_t *unconsumed)
{
- const struct archive_entry_header_ustar *header;
struct archive_string acl_text;
size_t size;
int err, acl_type;
uint64_t type;
char *acl, *p;
- header = (const struct archive_entry_header_ustar *)h;
- size = (size_t)tar_atol(header->size, sizeof(header->size));
archive_string_init(&acl_text);
err = read_body_to_string(a, tar, &acl_text, h, unconsumed);
if (err != ARCHIVE_OK) {
archive_string_free(&acl_text);
return (err);
}
+ size = archive_strlen(&acl_text);
/* TODO: Examine the first characters to see if this
* is an AIX ACL descriptor. We'll likely never support
@@ -1347,6 +1337,7 @@ header_common(struct archive_read *a, struct tar *tar,
const struct archive_entry_header_ustar *header;
const char *existing_linkpath;
const wchar_t *existing_wcs_linkpath;
+ mode_t header_mode;
int err = ARCHIVE_OK;
header = (const struct archive_entry_header_ustar *)h;
@@ -1354,12 +1345,10 @@ header_common(struct archive_read *a, struct tar *tar,
/* Parse out the numeric fields (all are octal) */
/* Split mode handling: Set filetype always, perm only if not already set */
- archive_entry_set_filetype(entry,
- (mode_t)tar_atol(header->mode, sizeof(header->mode)));
- if (!archive_entry_perm_is_set(entry)) {
- archive_entry_set_perm(entry,
- (mode_t)tar_atol(header->mode, sizeof(header->mode)));
- }
+ header_mode = (mode_t)tar_atol(header->mode, sizeof(header->mode));
+ archive_entry_set_filetype(entry, header_mode);
+ if (!archive_entry_perm_is_set(entry))
+ archive_entry_set_perm(entry, header_mode);
/* Set uid, gid, mtime if not already set */
if (!archive_entry_uid_is_set(entry)) {
@@ -1369,7 +1358,12 @@ header_common(struct archive_read *a, struct tar *tar,
archive_entry_set_gid(entry, tar_atol(header->gid, sizeof(header->gid)));
}
if (!archive_entry_mtime_is_set(entry)) {
- archive_entry_set_mtime(entry, tar_atol(header->mtime, sizeof(header->mtime)), 0);
+ int64_t t64 = tar_atol(header->mtime, sizeof(header->mtime));
+ time_t t = (time_t)t64;
+ if ((int64_t)t != t64) { /* time_t overflowed */
+ t = TIME_MAX;
+ }
+ archive_entry_set_mtime(entry, t, 0);
}
/* Reconcile the size info. */
@@ -1644,33 +1638,33 @@ is_mac_metadata_entry(struct archive_entry *entry) {
const char *p, *name;
const wchar_t *wp, *wname;
- wname = wp = archive_entry_pathname_w(entry);
- if (wp != NULL) {
+ name = p = archive_entry_pathname(entry);
+ if (p != NULL) {
/* Find the last path element. */
- for (; *wp != L'\0'; ++wp) {
- if (wp[0] == '/' && wp[1] != L'\0')
- wname = wp + 1;
+ for (; *p != '\0'; ++p) {
+ if (p[0] == '/' && p[1] != '\0')
+ name = p + 1;
}
/*
* If last path element starts with "._", then
* this is a Mac extension.
*/
- if (wname[0] == L'.' && wname[1] == L'_' && wname[2] != L'\0')
+ if (name[0] == '.' && name[1] == '_' && name[2] != '\0')
return 1;
} else {
/* Find the last path element. */
- name = p = archive_entry_pathname(entry);
- if (p == NULL)
- return (ARCHIVE_FAILED);
- for (; *p != '\0'; ++p) {
- if (p[0] == '/' && p[1] != '\0')
- name = p + 1;
+ wname = wp = archive_entry_pathname_w(entry);
+ if (wp == NULL)
+ return 0;
+ for (; *wp != L'\0'; ++wp) {
+ if (wp[0] == L'/' && wp[1] != L'\0')
+ wname = wp + 1;
}
/*
* If last path element starts with "._", then
* this is a Mac extension.
*/
- if (name[0] == '.' && name[1] == '_' && name[2] != '\0')
+ if (wname[0] == L'.' && wname[1] == L'_' && wname[2] != L'\0')
return 1;
}
/* Not a mac extension */
@@ -1752,7 +1746,6 @@ header_pax_global(struct archive_read *a, struct tar *tar,
const struct archive_entry_header_ustar *header;
int64_t size, to_consume;
- (void)a; /* UNUSED */
(void)tar; /* UNUSED */
(void)entry; /* UNUSED */
@@ -1764,6 +1757,11 @@ header_pax_global(struct archive_read *a, struct tar *tar,
(long long)size);
return (ARCHIVE_FATAL);
}
+ if (size == 0) {
+ archive_set_error(&a->archive, EINVAL,
+ "Invalid empty pax global extended header");
+ return (ARCHIVE_FATAL);
+ }
to_consume = ((size + 511) & ~511);
*unconsumed += to_consume;
return (ARCHIVE_OK);
@@ -1782,32 +1780,42 @@ header_ustar(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, const void *h)
{
const struct archive_entry_header_ustar *header;
- struct archive_string as;
int err = ARCHIVE_OK, r;
header = (const struct archive_entry_header_ustar *)h;
- /* Copy name into an internal buffer to ensure null-termination. */
+ /*
+ * The name field is fixed-width and may not be NUL-terminated.
+ * Use a temporary string only when prefix/name joining is required.
+ */
const char *existing_pathname = archive_entry_pathname(entry);
const wchar_t *existing_wcs_pathname = archive_entry_pathname_w(entry);
if ((existing_pathname == NULL || existing_pathname[0] == '\0')
&& (existing_wcs_pathname == NULL || existing_wcs_pathname[0] == '\0')) {
+ struct archive_string as;
+ const char *pathname;
+ size_t pathname_length;
+
archive_string_init(&as);
if (header->prefix[0]) {
archive_strncpy(&as, header->prefix, sizeof(header->prefix));
if (as.s[archive_strlen(&as) - 1] != '/')
archive_strappend_char(&as, '/');
archive_strncat(&as, header->name, sizeof(header->name));
+ pathname = as.s;
+ pathname_length = archive_strlen(&as);
} else {
- archive_strncpy(&as, header->name, sizeof(header->name));
+ pathname = header->name;
+ pathname_length = sizeof(header->name);
}
- if (archive_entry_copy_pathname_l(entry, as.s, archive_strlen(&as),
- tar->sconv) != 0) {
+ r = archive_entry_copy_pathname_l(entry, pathname,
+ pathname_length, tar->sconv);
+ archive_string_free(&as);
+ if (r != 0) {
err = set_conversion_failed_error(a, tar->sconv, "Pathname");
if (err == ARCHIVE_FATAL)
return (err);
}
- archive_string_free(&as);
}
/* Handle rest of common fields. */
@@ -1900,6 +1908,11 @@ header_pax_extension(struct archive_read *a, struct tar *tar,
(long long)ext_size);
return (ARCHIVE_FATAL);
}
+ if (ext_size == 0) {
+ archive_set_error(&a->archive, EINVAL,
+ "Invalid empty pax extended header");
+ return (ARCHIVE_FATAL);
+ }
ext_padding = 0x1ff & (-ext_size);
if (ext_size > ext_size_limit) {
@@ -2009,6 +2022,7 @@ header_pax_extension(struct archive_read *a, struct tar *tar,
/* Consume size, name, and `=` */
*unconsumed += p - attr_start;
if (tar_flush_unconsumed(a, unconsumed) != ARCHIVE_OK) {
+ archive_string_free(&attr_name);
return (ARCHIVE_FATAL);
}
@@ -2016,6 +2030,7 @@ header_pax_extension(struct archive_read *a, struct tar *tar,
archive_set_error(&a->archive, EINVAL,
"Malformed pax attributes");
*unconsumed += ext_size + ext_padding;
+ archive_string_free(&attr_name);
return (ARCHIVE_WARN);
}
@@ -2266,7 +2281,7 @@ pax_attribute_SCHILY_acl(struct archive_read *a, struct tar *tar,
}
static int
-pax_attribute_read_time(struct archive_read *a, size_t value_length, int64_t *ps, long *pn, int64_t *unconsumed) {
+pax_attribute_read_time(struct archive_read *a, size_t value_length, __LA_TIME_T *ps, long *pn, int64_t *unconsumed) {
struct archive_string as;
int r;
@@ -2286,12 +2301,16 @@ pax_attribute_read_time(struct archive_read *a, size_t value_length, int64_t *ps
return (r);
}
- pax_time(as.s, archive_strlen(&as), ps, pn);
+ int64_t sec = 0;
+ pax_time(as.s, archive_strlen(&as), &sec, pn);
archive_string_free(&as);
- if (*ps == INT64_MIN) {
+
+ if (sec == INT64_MIN) {
*ps = 0;
*pn = 0;
return (ARCHIVE_WARN);
+ } else {
+ *ps = (__LA_TIME_T)sec;
}
return (ARCHIVE_OK);
}
@@ -2348,7 +2367,6 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
int64_t t;
long n;
const char *p;
- ssize_t bytes_read;
int err = ARCHIVE_OK;
switch (key[0]) {
@@ -2432,7 +2450,7 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
(unsigned long long)sparse_map_limit);
err = ARCHIVE_FAILED;
} else {
- p = __archive_read_ahead(a, value_length, &bytes_read);
+ p = __archive_read_ahead(a, value_length, NULL);
if (p == NULL) {
archive_set_error(&a->archive, EINVAL,
"Truncated archive"
@@ -2507,15 +2525,20 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
*/
if (key_length == 12 && memcmp(key, "creationtime", 12) == 0) {
/* LIBARCHIVE.creationtime */
- if ((err = pax_attribute_read_time(a, value_length, &t, &n, unconsumed)) == ARCHIVE_OK) {
- archive_entry_set_birthtime(entry, t, n);
+ __LA_TIME_T sec = 0;
+ if ((err = pax_attribute_read_time(a, value_length, &sec, &n, unconsumed)) == ARCHIVE_OK) {
+ archive_entry_set_birthtime(entry, sec, n);
+ } else {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Ignoring malformed pax creationtime");
}
return (err);
}
else if (key_length == 11 && memcmp(key, "symlinktype", 11) == 0) {
/* LIBARCHIVE.symlinktype */
if (value_length < 16) {
- p = __archive_read_ahead(a, value_length, &bytes_read);
+ p = __archive_read_ahead(a, value_length, NULL);
if (p == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated tar archive "
@@ -2549,7 +2572,7 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
if (value_length > xattr_limit) {
err = ARCHIVE_WARN;
} else {
- p = __archive_read_ahead(a, value_length, &bytes_read);
+ p = __archive_read_ahead(a, value_length, NULL);
if (p == NULL) {
archive_set_error(&a->archive, EINVAL,
"Truncated archive"
@@ -2579,7 +2602,7 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
/* TODO: Should this be FAILED instead? */
err = ARCHIVE_WARN;
} else {
- p = __archive_read_ahead(a, value_length, &bytes_read);
+ p = __archive_read_ahead(a, value_length, NULL);
if (p == NULL) {
archive_set_error(&a->archive, EINVAL,
"Truncated archive"
@@ -2632,7 +2655,7 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
}
else if (key_length == 6 && memcmp(key, "fflags", 6) == 0) {
if (value_length < fflags_limit) {
- p = __archive_read_ahead(a, value_length, &bytes_read);
+ p = __archive_read_ahead(a, value_length, NULL);
if (p == NULL) {
/* Truncated archive */
archive_set_error(&a->archive, EINVAL,
@@ -2679,7 +2702,7 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
key_length -= 6;
key += 6;
if (value_length < xattr_limit) {
- p = __archive_read_ahead(a, value_length, &bytes_read);
+ p = __archive_read_ahead(a, value_length, NULL);
if (p == NULL) {
archive_set_error(&a->archive, EINVAL,
"Truncated archive"
@@ -2709,7 +2732,7 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
if (key_length == 9 && memcmp(key, "holesdata", 9) == 0) {
/* SUN.holesdata */
if (value_length < sparse_map_limit) {
- p = __archive_read_ahead(a, value_length, &bytes_read);
+ p = __archive_read_ahead(a, value_length, NULL);
if (p == NULL) {
archive_set_error(&a->archive, EINVAL,
"Truncated archive"
@@ -2736,16 +2759,26 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
break;
case 'a':
if (key_length == 5 && memcmp(key, "atime", 5) == 0) {
- if ((err = pax_attribute_read_time(a, value_length, &t, &n, unconsumed)) == ARCHIVE_OK) {
- archive_entry_set_atime(entry, t, n);
+ __LA_TIME_T sec = 0;
+ if ((err = pax_attribute_read_time(a, value_length, &sec, &n, unconsumed)) == ARCHIVE_OK) {
+ archive_entry_set_atime(entry, sec, n);
+ } else {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Ignoring malformed pax atime");
}
return (err);
}
break;
case 'c':
if (key_length == 5 && memcmp(key, "ctime", 5) == 0) {
- if ((err = pax_attribute_read_time(a, value_length, &t, &n, unconsumed)) == ARCHIVE_OK) {
- archive_entry_set_ctime(entry, t, n);
+ __LA_TIME_T sec = 0;
+ if ((err = pax_attribute_read_time(a, value_length, &sec, &n, unconsumed)) == ARCHIVE_OK) {
+ archive_entry_set_ctime(entry, sec, n);
+ } else {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Ignoring malformed pax ctime");
}
return (err);
} else if (key_length == 7 && memcmp(key, "charset", 7) == 0) {
@@ -2773,7 +2806,7 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
case 'h':
if (key_length == 10 && memcmp(key, "hdrcharset", 10) == 0) {
if (value_length < 64) {
- p = __archive_read_ahead(a, value_length, &bytes_read);
+ p = __archive_read_ahead(a, value_length, NULL);
if (p == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated tar archive "
@@ -2817,8 +2850,13 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
break;
case 'm':
if (key_length == 5 && memcmp(key, "mtime", 5) == 0) {
- if ((err = pax_attribute_read_time(a, value_length, &t, &n, unconsumed)) == ARCHIVE_OK) {
- archive_entry_set_mtime(entry, t, n);
+ __LA_TIME_T sec;
+ if ((err = pax_attribute_read_time(a, value_length, &sec, &n, unconsumed)) == ARCHIVE_OK) {
+ archive_entry_set_mtime(entry, sec, n);
+ } else {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Ignoring malformed pax mtime");
}
return (err);
}
@@ -2885,7 +2923,8 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
/*
* Parse a decimal time value, which may include a fractional portion
*
- * Sets ps to INT64_MIN on error.
+ * Sets ps to INT64_MIN on error, including syntax issues such as non-digits,
+ * or a time value that's outside the range of time_t.
*/
static void
pax_time(const char *p, size_t length, int64_t *ps, long *pn)
@@ -2894,10 +2933,6 @@ pax_time(const char *p, size_t length, int64_t *ps, long *pn)
int64_t s;
unsigned long l;
int sign;
- int64_t limit, last_digit_limit;
-
- limit = INT64_MAX / 10;
- last_digit_limit = INT64_MAX % 10;
if (length <= 0) {
*ps = 0;
@@ -2913,34 +2948,73 @@ pax_time(const char *p, size_t length, int64_t *ps, long *pn)
}
while (length > 0 && *p >= '0' && *p <= '9') {
digit = *p - '0';
- if (s > limit ||
- (s == limit && digit > last_digit_limit)) {
+ if (archive_ckd_mul_i64(&s, s, 10) ||
+ archive_ckd_add_i64(&s, s, digit)) {
*ps = INT64_MIN;
*pn = 0;
return;
}
- s = (s * 10) + digit;
++p;
--length;
}
*ps = s * sign;
+#if ARCHIVE_VERSION_NUMBER < 4000000
+ /* Libarchive 4.0 will have __LA_TIME_T == int64_t, so
+ this will be unnecessary. */
+ /* Test whether it overflows __LA_TIME_T */
+ __LA_TIME_T sec = (__LA_TIME_T)*ps;
+ if ((int64_t)sec != *ps) {
+ *ps = INT64_MIN;
+ *pn = 0;
+ return;
+ }
+#endif
+
/* Calculate nanoseconds. */
*pn = 0;
- if (length <= 0 || *p != '.')
+ if (length <= 0) {
+ return;
+ }
+
+ /* Skip `.` */
+ if (*p != '.') {
+ *ps = INT64_MIN;
+ *pn = 0;
return;
+ }
+ ++p;
+ --length;
l = 100000000UL;
do {
+ if (length <= 0) {
+ return;
+ }
+ if (*p >= '0' && *p <= '9') {
+ *pn += (*p - '0') * l;
+ } else {
+ *ps = INT64_MIN;
+ *pn = 0;
+ return;
+ }
++p;
--length;
- if (length > 0 && *p >= '0' && *p <= '9')
- *pn += (*p - '0') * l;
- else
- break;
} while (l /= 10);
+
+ /* Ignore resolution beyond nanoseconds,
+ but verify it's all decimal digits. */
+ while (length > 0) {
+ if (*p < '0' || *p > '9') {
+ *ps = INT64_MIN;
+ *pn = 0;
+ return;
+ }
+ ++p;
+ --length;
+ }
}
/*
@@ -2950,6 +3024,7 @@ static int
header_gnutar(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, const void *h, int64_t *unconsumed)
{
+ struct archive_entry_header_gnutar header_copy;
const struct archive_entry_header_gnutar *header;
int64_t t;
int err = ARCHIVE_OK;
@@ -2960,8 +3035,14 @@ header_gnutar(struct archive_read *a, struct tar *tar,
* filename is stored as in old-style archives.
*/
+ /*
+ * Sparse extension reads can reuse the callback buffer containing h,
+ * so preserve the main header until common fields are parsed.
+ */
+ memcpy(&header_copy, h, sizeof(header_copy));
+ header = &header_copy;
+
/* Copy filename over (to ensure null termination). */
- header = (const struct archive_entry_header_gnutar *)h;
const char *existing_pathname = archive_entry_pathname(entry);
const wchar_t *existing_wcs_pathname = archive_entry_pathname_w(entry);
if ((existing_pathname == NULL || existing_pathname[0] == '\0')
@@ -3040,7 +3121,7 @@ header_gnutar(struct archive_read *a, struct tar *tar,
}
/* Grab fields common to all tar variants. */
- err = header_common(a, tar, entry, h);
+ err = header_common(a, tar, entry, header);
if (err == ARCHIVE_FATAL)
return (err);
@@ -3103,7 +3184,6 @@ static int
gnu_sparse_old_read(struct archive_read *a, struct tar *tar,
const struct archive_entry_header_gnutar *header, int64_t *unconsumed)
{
- ssize_t bytes_read;
const void *data;
struct extended {
struct gnu_sparse sparse[21];
@@ -3121,7 +3201,7 @@ gnu_sparse_old_read(struct archive_read *a, struct tar *tar,
if (tar_flush_unconsumed(a, unconsumed) != ARCHIVE_OK) {
return (ARCHIVE_FATAL);
}
- data = __archive_read_ahead(a, 512, &bytes_read);
+ data = __archive_read_ahead(a, 512, NULL);
if (data == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated tar archive "
@@ -3239,14 +3319,12 @@ static int64_t
gnu_sparse_10_atol(struct archive_read *a, struct tar *tar,
int64_t *remaining, int64_t *unconsumed)
{
- int64_t l, limit, last_digit_limit;
+ int64_t l;
const char *p;
ssize_t bytes_read;
int base, digit;
base = 10;
- limit = INT64_MAX / base;
- last_digit_limit = INT64_MAX % base;
/*
* Skip any lines starting with '#'; GNU tar specs
@@ -3267,10 +3345,10 @@ gnu_sparse_10_atol(struct archive_read *a, struct tar *tar,
if (*p < '0' || *p >= '0' + base)
return (ARCHIVE_WARN);
digit = *p - '0';
- if (l > limit || (l == limit && digit > last_digit_limit))
+ if (archive_ckd_mul_i64(&l, l, base) ||
+ archive_ckd_add_i64(&l, l, digit)) {
l = INT64_MAX; /* Truncate on overflow. */
- else
- l = (l * base) + digit;
+ }
p++;
bytes_read--;
}
@@ -3366,13 +3444,10 @@ pax_attribute_SUN_holesdata(struct archive_read *a, struct tar *tar,
return (ARCHIVE_FATAL);
tar->sparse_last->hole = hole;
}
- if (length == 0 || *e == '\n') {
- if (length == 0 && *e == '\n') {
- return (ARCHIVE_OK);
- } else {
- return (ARCHIVE_WARN);
- }
- }
+ if (length == 0)
+ return (ARCHIVE_OK);
+ if (*e == '\n')
+ return (ARCHIVE_WARN);
p = e + 1;
length--;
hole = hole == 0;
@@ -3416,13 +3491,9 @@ tar_atol(const char *p, size_t char_cnt)
static int64_t
tar_atol_base_n(const char *p, size_t char_cnt, int base)
{
- int64_t l, maxval, limit, last_digit_limit;
+ int64_t l;
int digit, sign;
- maxval = INT64_MAX;
- limit = INT64_MAX / base;
- last_digit_limit = INT64_MAX % base;
-
/* the pointer will not be dereferenced if char_cnt is zero
* due to the way the && operator is evaluated.
*/
@@ -3436,25 +3507,22 @@ tar_atol_base_n(const char *p, size_t char_cnt, int base)
sign = -1;
p++;
char_cnt--;
-
- maxval = INT64_MIN;
- limit = -(INT64_MIN / base);
- last_digit_limit = -(INT64_MIN % base);
}
l = 0;
- if (char_cnt != 0) {
+ while (char_cnt != 0) {
digit = *p - '0';
- while (digit >= 0 && digit < base && char_cnt != 0) {
- if (l>limit || (l == limit && digit >= last_digit_limit)) {
- return maxval; /* Truncate on overflow. */
- }
- l = (l * base) + digit;
- digit = *++p - '0';
- char_cnt--;
+ if (digit < 0 || digit >= base)
+ break;
+ if (archive_ckd_mul_i64(&l, l, base) ||
+ archive_ckd_add_i64(&l, l, sign * digit)) {
+ /* Truncate on overflow. */
+ return sign < 0 ? INT64_MIN : INT64_MAX;
}
+ p++;
+ char_cnt--;
}
- return (sign < 0) ? -l : l;
+ return l;
}
static int64_t
@@ -3534,9 +3602,8 @@ readline(struct archive_read *a, struct tar *tar, const char **start,
{
ssize_t bytes_read;
ssize_t total_size = 0;
- const void *t;
+ const void *p, *t;
const char *s;
- void *p;
if (tar_flush_unconsumed(a, unconsumed) != ARCHIVE_OK) {
return (ARCHIVE_FATAL);
@@ -3608,24 +3675,20 @@ readline(struct archive_read *a, struct tar *tar, const char **start,
static char *
base64_decode(const char *s, size_t len, size_t *out_len)
{
- static const unsigned char digits[64] = {
- 'A','B','C','D','E','F','G','H','I','J','K','L','M','N',
- 'O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b',
- 'c','d','e','f','g','h','i','j','k','l','m','n','o','p',
- 'q','r','s','t','u','v','w','x','y','z','0','1','2','3',
- '4','5','6','7','8','9','+','/' };
- static unsigned char decode_table[128];
+ static const unsigned char decode_table[128] = {
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255,
+ 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255,
+ 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 255, 255, 255, 255, 255 };
char *out, *d;
const unsigned char *src = (const unsigned char *)s;
- /* If the decode table is not yet initialized, prepare it. */
- if (decode_table[digits[1]] != 1) {
- unsigned i;
- memset(decode_table, 0xff, sizeof(decode_table));
- for (i = 0; i < sizeof(digits); i++)
- decode_table[digits[i]] = i;
- }
-
/* Allocate enough space to hold the entire output. */
/* Note that we may not use all of this... */
out = malloc(len - len / 4 + 1);
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_warc.c b/contrib/libarchive/libarchive/archive_read_support_format_warc.c
index d8f188cf0b44..d70c718320e1 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_warc.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_warc.c
@@ -25,28 +25,35 @@
#include "archive_platform.h"
-/**
- * WARC is standardised by ISO TC46/SC4/WG12 and currently available as
- * ISO 28500:2009.
- * For the purposes of this file we used the final draft from:
+/*
+ * An overview of WARC format:
+ *
+ * WARC files are laid out as a sequence of records. Each record has
+ * a text header followed by a content block whose size is given by
+ * Content-Length. This reader supports WARC/0.12 through WARC/1.0
+ * and was written using the final draft that became ISO 28500:2009:
* http://bibnum.bnf.fr/warc/WARC_ISO_28500_version1_latestdraft.pdf
*
- * Todo:
- * [ ] real-world warcs can contain resources at endpoints ending in /
- * e.g. http://bibnum.bnf.fr/warc/
- * if you're lucky their response contains a Content-Location: header
- * pointing to a unix-compliant filename, in the example above it's
- * Content-Location: http://bibnum.bnf.fr/warc/index.html
- * however, that's not mandated and github for example doesn't follow
- * this convention.
- * We need a set of archive options to control what to do with
- * entries like these, at the moment care is taken to skip them.
+ * This reader exposes resource and response records as regular files
+ * when they have a usable WARC-Target-URI. WARC-Date is exposed as
+ * ctime, and a Last-Modified record header is exposed as mtime when
+ * present.
*
- **/
+ * TODO: Real-world WARCs can contain resources at endpoints ending in
+ * a slash, for example http://bibnum.bnf.fr/warc/. Some responses
+ * include a Content-Location header that points to a Unix-compatible
+ * filename such as http://bibnum.bnf.fr/warc/index.html, but WARC does
+ * not require that convention and some sites do not follow it. Until
+ * archive options exist to control these entries, this reader skips
+ * them instead of creating directory endpoints as files.
+ */
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
@@ -56,40 +63,35 @@
#ifdef HAVE_STRING_H
#include <string.h>
#endif
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#endif
-#ifdef HAVE_CTYPE_H
-#include <ctype.h>
-#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#include "archive.h"
#include "archive_entry.h"
+#include "archive_integer.h"
#include "archive_private.h"
#include "archive_read_private.h"
typedef enum {
WT_NONE,
- /* warcinfo */
+ /* WARC info */
WT_INFO,
- /* metadata */
+ /* Metadata */
WT_META,
- /* resource */
+ /* Resource */
WT_RSRC,
- /* request, unsupported */
+ /* Request, unsupported */
WT_REQ,
- /* response, unsupported */
+ /* Response */
WT_RSP,
- /* revisit, unsupported */
+ /* Revisit, unsupported */
WT_RVIS,
- /* conversion, unsupported */
+ /* Conversion, unsupported */
WT_CONV,
- /* continuation, unsupported at the moment */
+ /* Continuation, currently unsupported */
WT_CONT,
- /* invalid type */
+ /* Invalid type */
LAST_WT
} warc_type_t;
@@ -103,82 +105,92 @@ typedef struct {
char *str;
} warc_strbuf_t;
-struct warc_s {
- /* content length ahead */
- size_t cntlen;
- /* and how much we've processed so far */
- size_t cntoff;
- /* and how much we need to consume between calls */
- size_t unconsumed;
+struct warc {
+ /* Content length of the current record */
+ int64_t cntlen;
+ /* Bytes processed from the current record */
+ int64_t cntoff;
+ /* Bytes to consume before the next read */
+ int64_t unconsumed;
- /* string pool */
+ /* String pool */
warc_strbuf_t pool;
- /* previous version */
+ /* Previous version */
unsigned int pver;
- /* stringified format name */
+ /* Stringified format name */
struct archive_string sver;
};
-static int _warc_bid(struct archive_read *a, int);
-static int _warc_cleanup(struct archive_read *a);
-static int _warc_read(struct archive_read*, const void**, size_t*, int64_t*);
-static int _warc_skip(struct archive_read *a);
-static int _warc_rdhdr(struct archive_read *a, struct archive_entry *e);
+static int archive_read_format_warc_bid(struct archive_read *, int);
+static int archive_read_format_warc_cleanup(struct archive_read *);
+static int archive_read_format_warc_read_data(struct archive_read *,
+ const void **, size_t *, int64_t *);
+static int archive_read_format_warc_skip(struct archive_read *);
+static int archive_read_format_warc_read_header(struct archive_read *,
+ struct archive_entry *);
-/* private routines */
-static unsigned int _warc_rdver(const char *buf, size_t bsz);
-static unsigned int _warc_rdtyp(const char *buf, size_t bsz);
-static warc_string_t _warc_rduri(const char *buf, size_t bsz);
-static ssize_t _warc_rdlen(const char *buf, size_t bsz);
-static time_t _warc_rdrtm(const char *buf, size_t bsz);
-static time_t _warc_rdmtm(const char *buf, size_t bsz);
-static const char *_warc_find_eoh(const char *buf, size_t bsz);
-static const char *_warc_find_eol(const char *buf, size_t bsz);
+/* Private routines */
+static unsigned int warc_read_version(const char *, size_t);
+static unsigned int warc_read_type(const char *, size_t);
+static warc_string_t warc_read_uri(const char *, size_t);
+static int64_t warc_read_length(const char *, size_t);
+static time_t warc_read_date(const char *, size_t);
+static time_t warc_read_last_modified(const char *, size_t);
+static const char *warc_find_eoh(const char *, size_t);
+static const char *warc_find_eol(const char *, size_t);
int
archive_read_support_format_warc(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
- struct warc_s *w;
+ struct warc *warc;
int r;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_format_warc");
- if ((w = calloc(1, sizeof(*w))) == NULL) {
+ if ((warc = calloc(1, sizeof(*warc))) == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate warc data");
return (ARCHIVE_FATAL);
}
- r = __archive_read_register_format(
- a, w, "warc",
- _warc_bid, NULL, _warc_rdhdr, _warc_read,
- _warc_skip, NULL, _warc_cleanup, NULL, NULL);
+ r = __archive_read_register_format(a,
+ warc,
+ "warc",
+ archive_read_format_warc_bid,
+ NULL,
+ archive_read_format_warc_read_header,
+ archive_read_format_warc_read_data,
+ archive_read_format_warc_skip,
+ NULL,
+ archive_read_format_warc_cleanup,
+ NULL,
+ NULL);
if (r != ARCHIVE_OK) {
- free(w);
+ free(warc);
return (r);
}
return (ARCHIVE_OK);
}
static int
-_warc_cleanup(struct archive_read *a)
+archive_read_format_warc_cleanup(struct archive_read *a)
{
- struct warc_s *w = a->format->data;
+ struct warc *warc = a->format->data;
- if (w->pool.len > 0U) {
- free(w->pool.str);
+ if (warc->pool.len > 0U) {
+ free(warc->pool.str);
}
- archive_string_free(&w->sver);
- free(w);
+ archive_string_free(&warc->sver);
+ free(warc);
a->format->data = NULL;
return (ARCHIVE_OK);
}
static int
-_warc_bid(struct archive_read *a, int best_bid)
+archive_read_format_warc_bid(struct archive_read *a, int best_bid)
{
const char *hdr;
ssize_t nrd;
@@ -186,55 +198,52 @@ _warc_bid(struct archive_read *a, int best_bid)
(void)best_bid; /* UNUSED */
- /* check first line of file, it should be a record already */
- if ((hdr = __archive_read_ahead(a, 12U, &nrd)) == NULL) {
- /* no idea what to do */
- return -1;
- } else if (nrd < 12) {
- /* nah, not for us, our magic cookie is at least 12 bytes */
+ /* Check the first line, which should already be a record header. */
+ if ((hdr = __archive_read_ahead(a, 12, &nrd)) == NULL) {
+ /* Not enough data to identify this format. */
return -1;
}
- /* otherwise snarf the record's version number */
- ver = _warc_rdver(hdr, nrd);
+ /* Parse the record version number. */
+ ver = warc_read_version(hdr, nrd);
if (ver < 1200U || ver > 10000U) {
- /* we only support WARC 0.12 to 1.0 */
+ /* Only WARC 0.12 through WARC 1.0 are supported. */
return -1;
}
- /* otherwise be confident */
+ /* WARC magic and version checks passed. */
return (64);
}
static int
-_warc_rdhdr(struct archive_read *a, struct archive_entry *entry)
+archive_read_format_warc_read_header(struct archive_read *a,
+ struct archive_entry *entry)
{
#define HDR_PROBE_LEN (12U)
- struct warc_s *w = a->format->data;
+ struct warc *warc = a->format->data;
unsigned int ver;
const char *buf;
ssize_t nrd;
const char *eoh;
char *tmp;
- /* for the file name, saves some strndup()'ing */
+ /* Reuse the header buffer while parsing the file name. */
warc_string_t fnam;
- /* warc record type, not that we really use it a lot */
+ /* WARC record type */
warc_type_t ftyp;
- /* content-length+error monad */
- ssize_t cntlen;
- /* record time is the WARC-Date time we reinterpret it as ctime */
+ /* Content length, or a negative error indicator */
+ int64_t cntlen;
+ /* WARC-Date is exposed as the entry ctime. */
time_t rtime;
- /* mtime is the Last-Modified time which will be the entry's mtime */
+ /* A Last-Modified record header is exposed as the entry mtime. */
time_t mtime;
start_over:
- /* just use read_ahead() they keep track of unconsumed
- * bits and bobs for us; no need to put an extra shift in
- * and reproduce that functionality here */
+ /* Use read_ahead(); it already tracks unconsumed bytes, so this
+ * reader does not need a separate shift buffer. */
buf = __archive_read_ahead(a, HDR_PROBE_LEN, &nrd);
if (nrd < 0) {
- /* no good */
+ /* I/O or stream error. */
archive_set_error(
&a->archive, ARCHIVE_ERRNO_MISC,
"Bad record header");
@@ -244,19 +253,17 @@ start_over:
* must be EOF therefore */
return (ARCHIVE_EOF);
}
- /* looks good so far, try and find the end of the header now */
- eoh = _warc_find_eoh(buf, nrd);
+ /* Locate the end of the record header. */
+ eoh = warc_find_eoh(buf, nrd);
if (eoh == NULL) {
- /* still no good, the header end might be beyond the
- * probe we've requested, but then again who'd cram
- * so much stuff into the header *and* be 28500-compliant */
+ /* The header terminator was not found in the probed data. */
archive_set_error(
&a->archive, ARCHIVE_ERRNO_MISC,
"Bad record header");
return (ARCHIVE_FATAL);
}
- ver = _warc_rdver(buf, eoh - buf);
- /* we currently support WARC 0.12 to 1.0 */
+ ver = warc_read_version(buf, eoh - buf);
+ /* Only WARC 0.12 through WARC 1.0 are supported. */
if (ver == 0U) {
archive_set_error(
&a->archive, ARCHIVE_ERRNO_MISC,
@@ -269,78 +276,73 @@ start_over:
ver / 10000, (ver % 10000) / 100);
return (ARCHIVE_FATAL);
}
- cntlen = _warc_rdlen(buf, eoh - buf);
+ cntlen = warc_read_length(buf, eoh - buf);
if (cntlen < 0) {
- /* nightmare! the specs say content-length is mandatory
- * so I don't feel overly bad stopping the reader here */
+ /* This reader requires Content-Length before processing a record. */
archive_set_error(
&a->archive, EINVAL,
"Bad content length");
return (ARCHIVE_FATAL);
}
- rtime = _warc_rdrtm(buf, eoh - buf);
+ rtime = warc_read_date(buf, eoh - buf);
if (rtime == (time_t)-1) {
- /* record time is mandatory as per WARC/1.0,
- * so just barf here, fast and loud */
+ /* This reader requires WARC-Date before processing a record. */
archive_set_error(
&a->archive, EINVAL,
"Bad record time");
return (ARCHIVE_FATAL);
}
- /* let the world know we're a WARC archive */
+ /* Report this archive as WARC. */
a->archive.archive_format = ARCHIVE_FORMAT_WARC;
- if (ver != w->pver) {
- /* stringify this entry's version */
- archive_string_sprintf(&w->sver,
+ if (ver != warc->pver) {
+ /* Format this entry's WARC version. */
+ archive_string_sprintf(&warc->sver,
"WARC/%u.%u", ver / 10000, (ver % 10000) / 100);
- /* remember the version */
- w->pver = ver;
+ /* Remember the version for later entries. */
+ warc->pver = ver;
}
- /* start off with the type */
- ftyp = _warc_rdtyp(buf, eoh - buf);
- /* and let future calls know about the content */
- w->cntlen = cntlen;
- w->cntoff = 0U;
- mtime = 0;/* Avoid compiling error on some platform. */
+ /* Parse the record type. */
+ ftyp = warc_read_type(buf, eoh - buf);
+ /* Save content state for subsequent read calls. */
+ warc->cntlen = cntlen;
+ warc->cntoff = 0;
+ mtime = 0;/* Avoid compiler warnings on some platforms. */
switch (ftyp) {
case WT_RSRC:
case WT_RSP:
- /* only try and read the filename in the cases that are
- * guaranteed to have one */
- fnam = _warc_rduri(buf, eoh - buf);
- /* check the last character in the URI to avoid creating
- * directory endpoints as files, see Todo above */
+ /* Read the filename only for record types that are expected to
+ * have a target URI. */
+ fnam = warc_read_uri(buf, eoh - buf);
+ /* Avoid creating directory endpoints as files. */
if (fnam.len == 0 || fnam.str[fnam.len - 1] == '/') {
- /* break here for now */
+ /* Skip this record. */
fnam.len = 0U;
fnam.str = NULL;
break;
}
- /* bang to our string pool, so we save a
- * malloc()+free() roundtrip */
- if (fnam.len + 1U > w->pool.len) {
- w->pool.len = ((fnam.len + 64U) / 64U) * 64U;
- tmp = realloc(w->pool.str, w->pool.len);
+ /* Copy the name into the reusable string pool to avoid a malloc/free
+ * roundtrip for each entry. */
+ if (fnam.len + 1U > warc->pool.len) {
+ warc->pool.len = ((fnam.len + 64U) / 64U) * 64U;
+ tmp = realloc(warc->pool.str, warc->pool.len);
if (tmp == NULL) {
archive_set_error(
&a->archive, ENOMEM,
"Out of memory");
return (ARCHIVE_FATAL);
}
- w->pool.str = tmp;
+ warc->pool.str = tmp;
}
- memcpy(w->pool.str, fnam.str, fnam.len);
- w->pool.str[fnam.len] = '\0';
- /* let no one else know about the pool, it's a secret, shhh */
- fnam.str = w->pool.str;
+ memcpy(warc->pool.str, fnam.str, fnam.len);
+ warc->pool.str[fnam.len] = '\0';
+ /* Hide the pool implementation behind the parsed string. */
+ fnam.str = warc->pool.str;
- /* snarf mtime or deduce from rtime
- * this is a custom header added by our writer, it's quite
- * hard to believe anyone else would go through with it
- * (apart from being part of some http responses of course) */
- if ((mtime = _warc_rdmtm(buf, eoh - buf)) == (time_t)-1) {
+ /* Use a Last-Modified record header when present; otherwise fall back
+ * to WARC-Date. */
+ if ((mtime = warc_read_last_modified(buf, eoh - buf)) == (time_t)-1) {
mtime = rtime;
}
break;
@@ -358,19 +360,19 @@ start_over:
break;
}
- /* now eat some of those delicious buffer bits */
+ /* Consume the record header. */
__archive_read_consume(a, eoh - buf);
switch (ftyp) {
case WT_RSRC:
case WT_RSP:
if (fnam.len > 0U) {
- /* populate entry object */
+ /* Populate the entry object. */
archive_entry_set_filetype(entry, AE_IFREG);
archive_entry_copy_pathname(entry, fnam.str);
archive_entry_set_size(entry, cntlen);
archive_entry_set_perm(entry, 0644);
- /* rtime is the new ctime, mtime stays mtime */
+ /* WARC-Date becomes ctime; mtime comes from Last-Modified or WARC-Date. */
archive_entry_set_ctime(entry, rtime, 0L);
archive_entry_set_mtime(entry, mtime, 0L);
break;
@@ -385,8 +387,8 @@ start_over:
case WT_CONT:
case LAST_WT:
default:
- /* consume the content and start over */
- if (_warc_skip(a) < 0)
+ /* Skip this record body and look for the next one. */
+ if (archive_read_format_warc_skip(a) < 0)
return (ARCHIVE_FATAL);
goto start_over;
}
@@ -394,62 +396,69 @@ start_over:
}
static int
-_warc_read(struct archive_read *a, const void **buf, size_t *bsz, int64_t *off)
+archive_read_format_warc_read_data(struct archive_read *a, const void **buf,
+ size_t *bsz, int64_t *off)
{
- struct warc_s *w = a->format->data;
+ struct warc *warc = a->format->data;
const char *rab;
ssize_t nrd;
- if (w->cntoff >= w->cntlen) {
- eof:
- /* it's our lucky day, no work, we can leave early */
+ if (warc->unconsumed) {
+ __archive_read_consume(a, warc->unconsumed);
+ warc->unconsumed = 0;
+ }
+
+ if (warc->cntoff >= warc->cntlen) {
+ /* No data is available to return for this entry. */
*buf = NULL;
*bsz = 0U;
- *off = w->cntoff;
- w->unconsumed = 0U;
+ *off = warc->cntoff;
return (ARCHIVE_EOF);
}
- if (w->unconsumed) {
- __archive_read_consume(a, w->unconsumed);
- w->unconsumed = 0U;
- }
-
rab = __archive_read_ahead(a, 1U, &nrd);
if (nrd < 0) {
*bsz = 0U;
- /* big catastrophe */
+ /* Propagate the read error. */
return (int)nrd;
} else if (nrd == 0) {
- goto eof;
- } else if ((size_t)nrd > w->cntlen - w->cntoff) {
- /* clamp to content-length */
- nrd = w->cntlen - w->cntoff;
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated WARC file data");
+ return (ARCHIVE_FATAL);
+ } else if ((int64_t)nrd > warc->cntlen - warc->cntoff) {
+ /* Clamp reads to Content-Length. */
+ nrd = warc->cntlen - warc->cntoff;
}
- *off = w->cntoff;
+ *off = warc->cntoff;
*bsz = nrd;
*buf = rab;
- w->cntoff += nrd;
- w->unconsumed = (size_t)nrd;
+ warc->cntoff += nrd;
+ warc->unconsumed = nrd;
return (ARCHIVE_OK);
}
static int
-_warc_skip(struct archive_read *a)
+archive_read_format_warc_skip(struct archive_read *a)
{
- struct warc_s *w = a->format->data;
+ struct warc *warc = a->format->data;
- if (__archive_read_consume(a, w->cntlen) < 0 ||
+ if (warc->cntoff > warc->cntlen)
+ return (ARCHIVE_FATAL);
+ if (warc->unconsumed) {
+ __archive_read_consume(a, warc->unconsumed);
+ warc->unconsumed = 0;
+ }
+ if (__archive_read_consume(a, warc->cntlen - warc->cntoff) < 0 ||
__archive_read_consume(a, 4U/*\r\n\r\n separator*/) < 0)
return (ARCHIVE_FATAL);
- w->cntlen = 0U;
- w->cntoff = 0U;
+ warc->cntlen = 0;
+ warc->cntoff = 0;
return (ARCHIVE_OK);
}
-/* private routines */
+/* Private routines */
static void*
deconst(const void *c)
{
@@ -469,44 +478,41 @@ xmemmem(const char *hay, const size_t haysize,
unsigned int nsum;
unsigned int eqp;
- /* trivial checks first
- * a 0-sized needle is defined to be found anywhere in haystack
- * then run strchr() to find a candidate in HAYSTACK (i.e. a portion
- * that happens to begin with *NEEDLE) */
+ /* Handle trivial cases first. A zero-sized needle is defined to be
+ * found anywhere in the haystack; otherwise find the first candidate
+ * that begins with *NEEDLE. */
if (needlesize == 0UL) {
return deconst(hay);
} else if ((hay = memchr(hay, *needle, haysize)) == NULL) {
- /* trivial */
+ /* No candidate match remains. */
return NULL;
}
- /* First characters of haystack and needle are the same now. Both are
- * guaranteed to be at least one character long. Now computes the sum
- * of characters values of needle together with the sum of the first
- * needle_len characters of haystack. */
+ /* The first characters of haystack and needle already match, and both
+ * strings are at least one character long. Compute the rolling XOR
+ * values for the needle and the first NEEDLESIZE characters of haystack. */
for (hp = hay + 1U, np = needle + 1U, hsum = *hay, nsum = *hay, eqp = 1U;
hp < eoh && np < eon;
hsum ^= *hp, nsum ^= *np, eqp &= *hp == *np, hp++, np++);
/* HP now references the (NEEDLESIZE + 1)-th character. */
if (np < eon) {
- /* haystack is smaller than needle, :O */
+ /* The haystack is smaller than the needle. */
return NULL;
} else if (eqp) {
- /* found a match */
+ /* Found a match. */
return deconst(hay);
}
- /* now loop through the rest of haystack,
- * updating the sum iteratively */
+ /* Loop through the rest of the haystack and update the rolling XOR
+ * iteratively. */
for (cand = hay; hp < eoh; hp++) {
hsum ^= *cand++;
hsum ^= *hp;
- /* Since the sum of the characters is already known to be
- * equal at that point, it is enough to check just NEEDLESIZE - 1
- * characters for equality,
- * also CAND is by design < HP, so no need for range checks */
+ /* When the rolling XOR values match, it is enough to check
+ * NEEDLESIZE - 1 characters for equality. CAND is always before
+ * HP by design, so no range check is needed. */
if (hsum == nsum && memcmp(cand, needle, needlesize - 1U) == 0) {
return deconst(cand);
}
@@ -519,7 +525,7 @@ strtoi_lim(const char *str, const char **ep, int llim, int ulim)
{
int res = 0;
const char *sp;
- /* we keep track of the number of digits via rulim */
+ /* Track the number of digits with rulim. */
int rulim;
for (sp = str, rulim = ulim > 10 ? ulim : 10;
@@ -546,11 +552,11 @@ time_from_tm(struct tm *t)
/* Use platform timegm() if available. */
return (timegm(t));
#else
- /* Else use direct calculation using POSIX assumptions. */
- /* First, fix up tm_yday based on the year/month/day. */
+ /* Otherwise, calculate directly using POSIX assumptions. */
+ /* First, fix up tm_yday based on the year, month, and day. */
if (mktime(t) == (time_t)-1)
return ((time_t)-1);
- /* Then we can compute timegm() from first principles. */
+ /* Then compute timegm() from first principles. */
return (t->tm_sec
+ t->tm_min * 60
+ t->tm_hour * 3600
@@ -565,48 +571,48 @@ time_from_tm(struct tm *t)
static time_t
xstrpisotime(const char *s, char **endptr)
{
-/** like strptime() but strictly for ISO 8601 Zulu strings */
+/* Like strptime(), but only for ISO 8601 Zulu strings. */
struct tm tm;
time_t res = (time_t)-1;
- /* make sure tm is clean */
+ /* Clear the tm structure. */
memset(&tm, 0, sizeof(tm));
- /* as a courtesy to our callers, and since this is a non-standard
- * routine, we skip leading whitespace */
+ /* This is a non-standard routine, so skip leading whitespace for
+ * caller convenience. */
while (*s == ' ' || *s == '\t')
++s;
- /* read year */
+ /* Read the year. */
if ((tm.tm_year = strtoi_lim(s, &s, 1583, 4095)) < 0 || *s++ != '-') {
goto out;
}
- /* read month */
+ /* Read the month. */
if ((tm.tm_mon = strtoi_lim(s, &s, 1, 12)) < 0 || *s++ != '-') {
goto out;
}
- /* read day-of-month */
+ /* Read the day of the month. */
if ((tm.tm_mday = strtoi_lim(s, &s, 1, 31)) < 0 || *s++ != 'T') {
goto out;
}
- /* read hour */
+ /* Read the hour. */
if ((tm.tm_hour = strtoi_lim(s, &s, 0, 23)) < 0 || *s++ != ':') {
goto out;
}
- /* read minute */
+ /* Read the minute. */
if ((tm.tm_min = strtoi_lim(s, &s, 0, 59)) < 0 || *s++ != ':') {
goto out;
}
- /* read second */
+ /* Read the second. */
if ((tm.tm_sec = strtoi_lim(s, &s, 0, 60)) < 0 || *s++ != 'Z') {
goto out;
}
- /* massage TM to fulfill some of POSIX' constraints */
+ /* Adjust tm fields to satisfy POSIX constraints. */
tm.tm_year -= 1900;
tm.tm_mon--;
- /* now convert our custom tm struct to a unix stamp using UTC */
+ /* Convert the tm structure to a Unix timestamp in UTC. */
res = time_from_tm(&tm);
out:
@@ -616,8 +622,14 @@ out:
return res;
}
+static int
+warc_isdigit(const char c)
+{
+ return c >= '0' && c <= '9';
+}
+
static unsigned int
-_warc_rdver(const char *buf, size_t bsz)
+warc_read_version(const char *buf, size_t bsz)
{
static const char magic[] = "WARC/";
const char *c;
@@ -625,35 +637,34 @@ _warc_rdver(const char *buf, size_t bsz)
unsigned int end = 0U;
if (bsz < 12 || memcmp(buf, magic, sizeof(magic) - 1U) != 0) {
- /* buffer too small or invalid magic */
+ /* Buffer too small or invalid magic. */
return ver;
}
- /* looks good so far, read the version number for a laugh */
+ /* Parse the version number. */
buf += sizeof(magic) - 1U;
- if (isdigit((unsigned char)buf[0U]) && (buf[1U] == '.') &&
- isdigit((unsigned char)buf[2U])) {
- /* we support a maximum of 2 digits in the minor version */
- if (isdigit((unsigned char)buf[3U]))
+ if (warc_isdigit(buf[0]) && buf[1] == '.' && warc_isdigit(buf[2])) {
+ /* Support at most two digits in the minor version. */
+ if (warc_isdigit(buf[3]))
end = 1U;
- /* set up major version */
+ /* Set up the major version. */
ver = (buf[0U] - '0') * 10000U;
- /* set up minor version */
+ /* Set up the minor version. */
if (end == 1U) {
ver += (buf[2U] - '0') * 1000U;
ver += (buf[3U] - '0') * 100U;
} else
ver += (buf[2U] - '0') * 100U;
/*
- * WARC below version 0.12 has a space-separated header
- * WARC 0.12 and above terminates the version with a CRLF
+ * WARC versions before 0.12 use a space-separated header.
+ * WARC 0.12 and later terminate the version with CRLF.
*/
c = buf + 3U + end;
if (ver >= 1200U) {
if (memcmp(c, "\r\n", 2U) != 0)
ver = 0U;
} else {
- /* ver < 1200U */
+ /* Version is below WARC 0.12. */
if (*c != ' ' && *c != '\t')
ver = 0U;
}
@@ -662,22 +673,22 @@ _warc_rdver(const char *buf, size_t bsz)
}
static unsigned int
-_warc_rdtyp(const char *buf, size_t bsz)
+warc_read_type(const char *buf, size_t bsz)
{
static const char _key[] = "\r\nWARC-Type:";
const char *val, *eol;
if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {
- /* no bother */
+ /* Header field is absent. */
return WT_NONE;
}
val += sizeof(_key) - 1U;
- if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) {
- /* no end of line */
+ if ((eol = warc_find_eol(val, buf + bsz - val)) == NULL) {
+ /* Header field has no end of line. */
return WT_NONE;
}
- /* overread whitespace */
+ /* Skip leading whitespace. */
while (val < eol && (*val == ' ' || *val == '\t'))
++val;
@@ -691,55 +702,55 @@ _warc_rdtyp(const char *buf, size_t bsz)
}
static warc_string_t
-_warc_rduri(const char *buf, size_t bsz)
+warc_read_uri(const char *buf, size_t bsz)
{
static const char _key[] = "\r\nWARC-Target-URI:";
const char *val, *uri, *eol, *p;
warc_string_t res = {0U, NULL};
if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {
- /* no bother */
+ /* Header field is absent. */
return res;
}
- /* overread whitespace */
+ /* Skip leading whitespace. */
val += sizeof(_key) - 1U;
- if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) {
- /* no end of line */
+ if ((eol = warc_find_eol(val, buf + bsz - val)) == NULL) {
+ /* Header field has no end of line. */
return res;
}
while (val < eol && (*val == ' ' || *val == '\t'))
++val;
- /* overread URL designators */
+ /* Locate the :// separator. */
if ((uri = xmemmem(val, eol - val, "://", 3U)) == NULL) {
- /* not touching that! */
+ /* Ignore values without a :// separator. */
return res;
}
- /* spaces inside uri are not allowed, CRLF should follow */
+ /* Spaces inside a URI are not allowed; CRLF should follow. */
for (p = val; p < eol; p++) {
if (isspace((unsigned char)*p))
return res;
}
- /* there must be at least space for ftp */
+ /* Require enough room for the shortest supported scheme. */
if (uri < (val + 3U))
return res;
- /* move uri to point to after :// */
+ /* Move uri past the :// separator. */
uri += 3U;
- /* now then, inspect the URI */
+ /* Inspect the scheme prefix. */
if (memcmp(val, "file", 4U) == 0) {
- /* perfect, nothing left to do here */
+ /* Keep file:// paths as-is. */
} else if (memcmp(val, "http", 4U) == 0 ||
memcmp(val, "ftp", 3U) == 0) {
- /* overread domain, and the first / */
+ /* Skip the domain and the first slash. */
while (uri < eol && *uri++ != '/');
} else {
- /* not sure what to do? best to bugger off */
+ /* Unsupported URI scheme. */
return res;
}
res.str = uri;
@@ -747,42 +758,49 @@ _warc_rduri(const char *buf, size_t bsz)
return res;
}
-static ssize_t
-_warc_rdlen(const char *buf, size_t bsz)
+static int64_t
+warc_read_length(const char *buf, size_t bsz)
{
static const char _key[] = "\r\nContent-Length:";
- const char *val, *eol;
- char *on = NULL;
- long int len;
+ const char *val, *eol, *p;
+ int64_t len;
if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {
- /* no bother */
+ /* Header field is absent. */
return -1;
}
val += sizeof(_key) - 1U;
- if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) {
- /* no end of line */
+
+ if ((eol = warc_find_eol(val, buf + bsz - val)) == NULL) {
+ /* Malformed field with no end of line. */
return -1;
}
- /* skip leading whitespace */
+ /* Skip leading whitespace. */
while (val < eol && (*val == ' ' || *val == '\t'))
val++;
- /* there must be at least one digit */
- if (!isdigit((unsigned char)*val))
- return -1;
- errno = 0;
- len = strtol(val, &on, 10);
- if (errno != 0 || on != eol) {
- /* line must end here */
+
+ /* Require at least one digit. */
+ if (val >= eol || *val < '0' || *val > '9')
return -1;
+
+ len = 0;
+ for (p = val; p < eol; p++) {
+ int64_t digit;
+
+ if (*p < '0' || *p > '9')
+ return -1;
+ digit = *p - '0';
+ if (archive_ckd_mul_i64(&len, len, 10) ||
+ archive_ckd_add_i64(&len, len, digit))
+ return -1;
}
- return (size_t)len;
+ return len;
}
static time_t
-_warc_rdrtm(const char *buf, size_t bsz)
+warc_read_date(const char *buf, size_t bsz)
{
static const char _key[] = "\r\nWARC-Date:";
const char *val, *eol;
@@ -790,26 +808,26 @@ _warc_rdrtm(const char *buf, size_t bsz)
time_t res;
if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {
- /* no bother */
+ /* Header field is absent. */
return (time_t)-1;
}
val += sizeof(_key) - 1U;
- if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL ) {
- /* no end of line */
+ if ((eol = warc_find_eol(val, buf + bsz - val)) == NULL ) {
+ /* Header field has no end of line. */
return -1;
}
- /* xstrpisotime() kindly overreads whitespace for us, so use that */
+ /* xstrpisotime() skips leading whitespace. */
res = xstrpisotime(val, &on);
if (on != eol) {
- /* line must end here */
+ /* The field must end here. */
return -1;
}
return res;
}
static time_t
-_warc_rdmtm(const char *buf, size_t bsz)
+warc_read_last_modified(const char *buf, size_t bsz)
{
static const char _key[] = "\r\nLast-Modified:";
const char *val, *eol;
@@ -817,26 +835,26 @@ _warc_rdmtm(const char *buf, size_t bsz)
time_t res;
if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {
- /* no bother */
+ /* Header field is absent. */
return (time_t)-1;
}
val += sizeof(_key) - 1U;
- if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL ) {
- /* no end of line */
+ if ((eol = warc_find_eol(val, buf + bsz - val)) == NULL ) {
+ /* Header field has no end of line. */
return -1;
}
- /* xstrpisotime() kindly overreads whitespace for us, so use that */
+ /* xstrpisotime() skips leading whitespace. */
res = xstrpisotime(val, &on);
if (on != eol) {
- /* line must end here */
+ /* The field must end here. */
return -1;
}
return res;
}
-static const char*
-_warc_find_eoh(const char *buf, size_t bsz)
+static const char *
+warc_find_eoh(const char *buf, size_t bsz)
{
static const char _marker[] = "\r\n\r\n";
const char *hit = xmemmem(buf, bsz, _marker, sizeof(_marker) - 1U);
@@ -847,12 +865,11 @@ _warc_find_eoh(const char *buf, size_t bsz)
return hit;
}
-static const char*
-_warc_find_eol(const char *buf, size_t bsz)
+static const char *
+warc_find_eol(const char *buf, size_t bsz)
{
static const char _marker[] = "\r\n";
const char *hit = xmemmem(buf, bsz, _marker, sizeof(_marker) - 1U);
return hit;
}
-/* archive_read_support_format_warc.c ends here */
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_xar.c b/contrib/libarchive/libarchive/archive_read_support_format_xar.c
index 874501fc0782..dbe2c25d93a1 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_xar.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_xar.c
@@ -56,6 +56,7 @@
#include "archive_endian.h"
#include "archive_entry.h"
#include "archive_entry_locale.h"
+#include "archive_integer.h"
#include "archive_private.h"
#include "archive_read_private.h"
@@ -107,10 +108,14 @@ archive_read_support_format_xar(struct archive *_a)
#define CKSUM_NONE 0
#define CKSUM_SHA1 1
#define CKSUM_MD5 2
+#define CKSUM_SHA256 3
+#define CKSUM_SHA512 4
#define MD5_SIZE 16
#define SHA1_SIZE 20
-#define MAX_SUM_SIZE 20
+#define SHA256_SIZE 32
+#define SHA512_SIZE 64
+#define MAX_SUM_SIZE 64
enum enctype {
NONE,
@@ -134,6 +139,12 @@ struct chksumwork {
#ifdef ARCHIVE_HAS_SHA1
archive_sha1_ctx sha1ctx;
#endif
+#ifdef ARCHIVE_HAS_SHA256
+ archive_sha256_ctx sha256ctx;
+#endif
+#ifdef ARCHIVE_HAS_SHA512
+ archive_sha512_ctx sha512ctx;
+#endif
};
struct xattr {
@@ -213,8 +224,8 @@ struct hdlink {
struct heap_queue {
struct xar_file **files;
- int allocated;
- int used;
+ size_t allocated;
+ size_t used;
};
enum xmlstatus {
@@ -387,8 +398,7 @@ static int rd_contents_init(struct archive_read *,
enum enctype, int, int);
static int rd_contents(struct archive_read *, const void **,
size_t *, size_t *, uint64_t);
-static uint64_t atol10(const char *, size_t);
-static int64_t atol8(const char *, size_t);
+static int atou64(const char *, size_t, int, uint64_t *);
static size_t atohex(unsigned char *, size_t, const char *, size_t);
static time_t parse_time(const char *p, size_t n);
static int heap_add_entry(struct archive_read *a,
@@ -396,7 +406,7 @@ static int heap_add_entry(struct archive_read *a,
static struct xar_file *heap_get_entry(struct heap_queue *);
static int add_link(struct archive_read *,
struct xar *, struct xar_file *);
-static void checksum_init(struct archive_read *, int, int);
+static int checksum_init(struct archive_read *, int, int);
static void checksum_update(struct archive_read *, const void *,
size_t, const void *, size_t);
static int checksum_final(struct archive_read *, const void *,
@@ -421,7 +431,7 @@ static void unknowntag_end(struct xar *, const char *);
static int xml_start(struct archive_read *,
const char *, struct xmlattr_list *);
static void xml_end(void *, const char *);
-static void xml_data(void *, const char *, size_t);
+static int xml_data(void *, const char *, size_t);
static int xml_parse_file_flags(struct xar *, const char *);
static int xml_parse_file_ext2(struct xar *, const char *);
#if defined(HAVE_LIBXML_XMLREADER_H)
@@ -524,6 +534,8 @@ xar_bid(struct archive_read *a, int best_bid)
case CKSUM_NONE:
case CKSUM_SHA1:
case CKSUM_MD5:
+ case CKSUM_SHA256:
+ case CKSUM_SHA512:
bid += 32;
break;
default:
@@ -536,7 +548,7 @@ xar_bid(struct archive_read *a, int best_bid)
static int
read_toc(struct archive_read *a)
{
- struct xar *xar;
+ struct xar *xar = a->format->data;
struct xar_file *file;
const unsigned char *b;
uint64_t toc_compressed_size;
@@ -545,8 +557,6 @@ read_toc(struct archive_read *a)
ssize_t bytes;
int r;
- xar = (struct xar *)(a->format->data);
-
/*
* Read xar header.
*/
@@ -674,12 +684,11 @@ read_toc(struct archive_read *a)
static int
xar_read_header(struct archive_read *a, struct archive_entry *entry)
{
- struct xar *xar;
+ struct xar *xar = a->format->data;
struct xar_file *file;
struct xattr *xattr;
int r;
- xar = (struct xar *)(a->format->data);
r = ARCHIVE_OK;
if (xar->offset == 0) {
@@ -729,6 +738,7 @@ xar_read_header(struct archive_read *a, struct archive_entry *entry)
if (errno == ENOMEM) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory for Gname");
+ file_free(file);
return (ARCHIVE_FATAL);
}
archive_set_error(&a->archive,
@@ -744,6 +754,7 @@ xar_read_header(struct archive_read *a, struct archive_entry *entry)
if (errno == ENOMEM) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory for Uname");
+ file_free(file);
return (ARCHIVE_FATAL);
}
archive_set_error(&a->archive,
@@ -758,6 +769,7 @@ xar_read_header(struct archive_read *a, struct archive_entry *entry)
if (errno == ENOMEM) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory for Pathname");
+ file_free(file);
return (ARCHIVE_FATAL);
}
archive_set_error(&a->archive,
@@ -774,6 +786,7 @@ xar_read_header(struct archive_read *a, struct archive_entry *entry)
if (errno == ENOMEM) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory for Linkname");
+ file_free(file);
return (ARCHIVE_FATAL);
}
archive_set_error(&a->archive,
@@ -874,12 +887,10 @@ static int
xar_read_data(struct archive_read *a,
const void **buff, size_t *size, int64_t *offset)
{
- struct xar *xar;
+ struct xar *xar = a->format->data;
size_t used = 0;
int r;
- xar = (struct xar *)(a->format->data);
-
if (xar->entry_unconsumed) {
__archive_read_consume(a, xar->entry_unconsumed);
xar->entry_unconsumed = 0;
@@ -937,10 +948,9 @@ abort_read_data:
static int
xar_read_data_skip(struct archive_read *a)
{
- struct xar *xar;
+ struct xar *xar = a->format->data;
int64_t bytes_skipped;
- xar = (struct xar *)(a->format->data);
if (xar->end_of_file)
return (ARCHIVE_EOF);
bytes_skipped = __archive_read_consume(a, xar->entry_remaining +
@@ -955,12 +965,11 @@ xar_read_data_skip(struct archive_read *a)
static int
xar_cleanup(struct archive_read *a)
{
- struct xar *xar;
+ struct xar *xar = a->format->data;
struct hdlink *hdlink;
- int i;
+ size_t i;
int r;
- xar = (struct xar *)(a->format->data);
checksum_cleanup(a);
r = decompression_cleanup(a);
hdlink = xar->hdlink_list;
@@ -990,9 +999,8 @@ xar_cleanup(struct archive_read *a)
static int
move_reading_point(struct archive_read *a, uint64_t offset)
{
- struct xar *xar;
+ struct xar *xar = a->format->data;
- xar = (struct xar *)(a->format->data);
if (xar->offset - xar->h_base != offset) {
/* Seek forward to the start of file contents. */
int64_t step;
@@ -1027,8 +1035,7 @@ rd_contents_init(struct archive_read *a, enum enctype encoding,
if ((r = decompression_init(a, encoding)) != ARCHIVE_OK)
return (r);
/* Init checksum library. */
- checksum_init(a, a_sum_alg, e_sum_alg);
- return (ARCHIVE_OK);
+ return (checksum_init(a, a_sum_alg, e_sum_alg));
}
static int
@@ -1071,44 +1078,24 @@ rd_contents(struct archive_read *a, const void **buff, size_t *size,
* it does obey locale.
*/
-static uint64_t
-atol10(const char *p, size_t char_cnt)
+static int
+atou64(const char *p, size_t char_cnt, int base, uint64_t *val)
{
uint64_t l;
- int digit;
-
- if (char_cnt == 0)
- return (0);
-
- l = 0;
- digit = *p - '0';
- while (digit >= 0 && digit < 10 && char_cnt-- > 0) {
- l = (l * 10) + digit;
- digit = *++p - '0';
- }
- return (l);
-}
-
-static int64_t
-atol8(const char *p, size_t char_cnt)
-{
- int64_t l;
- int digit;
-
- if (char_cnt == 0)
- return (0);
l = 0;
while (char_cnt-- > 0) {
- if (*p >= '0' && *p <= '7')
- digit = *p - '0';
- else
+ int digit = *p++ - '0';
+
+ if (digit < 0 || digit >= base)
break;
- p++;
- l <<= 3;
- l |= digit;
+ if (archive_ckd_mul_u64(&l, l, base) ||
+ archive_ckd_add_u64(&l, l, digit))
+ return (ARCHIVE_FATAL);
}
- return (l);
+
+ *val = l;
+ return (ARCHIVE_OK);
}
static size_t
@@ -1173,48 +1160,42 @@ parse_time(const char *p, size_t n)
{
struct tm tm;
time_t t = 0;
- int64_t data;
+ uint64_t data;
memset(&tm, 0, sizeof(tm));
if (n != 20)
return (t);
- data = atol10(p, 4);
- if (data < 1900)
+ if (atou64(p, 4, 10, &data) != ARCHIVE_OK || data < 1900)
return (t);
tm.tm_year = (int)data - 1900;
p += 4;
if (*p++ != '-')
return (t);
- data = atol10(p, 2);
- if (data < 1 || data > 12)
+ if (atou64(p, 2, 10, &data) != ARCHIVE_OK || data < 1 || data > 12)
return (t);
tm.tm_mon = (int)data -1;
p += 2;
if (*p++ != '-')
return (t);
- data = atol10(p, 2);
- if (data < 1 || data > 31)
+ if (atou64(p, 2, 10, &data) != ARCHIVE_OK || data < 1 || data > 31)
return (t);
tm.tm_mday = (int)data;
p += 2;
if (*p++ != 'T')
return (t);
- data = atol10(p, 2);
- if (data < 0 || data > 23)
+ if (atou64(p, 2, 10, &data) != ARCHIVE_OK || data > 23)
return (t);
tm.tm_hour = (int)data;
p += 2;
if (*p++ != ':')
return (t);
- data = atol10(p, 2);
- if (data < 0 || data > 59)
+ if (atou64(p, 2, 10, &data) != ARCHIVE_OK || data > 59)
return (t);
tm.tm_min = (int)data;
p += 2;
if (*p++ != ':')
return (t);
- data = atol10(p, 2);
- if (data < 0 || data > 60)
+ if (atou64(p, 2, 10, &data) != ARCHIVE_OK || data > 60)
return (t);
tm.tm_sec = (int)data;
#if 0
@@ -1233,19 +1214,17 @@ heap_add_entry(struct archive_read *a,
struct heap_queue *heap, struct xar_file *file)
{
uint64_t file_id, parent_id;
- int hole, parent;
+ size_t hole, parent;
/* Expand our pending files list as necessary. */
if (heap->used >= heap->allocated) {
struct xar_file **new_pending_files;
- int new_size;
+ size_t new_size;
if (heap->allocated < 1024)
new_size = 1024;
- else
- new_size = heap->allocated * 2;
- /* Overflow might keep us from growing the list. */
- if (new_size <= heap->allocated) {
+ else if (archive_ckd_mul_size(&new_size, heap->allocated, 2)) {
+ /* Overflow keeps us from growing the list. */
archive_set_error(&a->archive,
ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
@@ -1273,7 +1252,7 @@ heap_add_entry(struct archive_read *a,
*/
hole = heap->used++;
while (hole > 0) {
- parent = (hole - 1)/2;
+ parent = (hole - 1) / 2;
parent_id = heap->files[parent]->id;
if (file_id >= parent_id) {
heap->files[hole] = file;
@@ -1292,7 +1271,7 @@ static struct xar_file *
heap_get_entry(struct heap_queue *heap)
{
uint64_t a_id, b_id, c_id;
- int a, b, c;
+ size_t a, b, c;
struct xar_file *r, *tmp;
if (heap->used < 1)
@@ -1362,7 +1341,7 @@ add_link(struct archive_read *a, struct xar *xar, struct xar_file *file)
return (ARCHIVE_OK);
}
-static void
+static int
_checksum_init(struct chksumwork *sumwrk, int sum_alg)
{
sumwrk->alg = sum_alg;
@@ -1375,7 +1354,20 @@ _checksum_init(struct chksumwork *sumwrk, int sum_alg)
case CKSUM_MD5:
archive_md5_init(&(sumwrk->md5ctx));
break;
+#ifdef ARCHIVE_HAS_SHA256
+ case CKSUM_SHA256:
+ archive_sha256_init(&(sumwrk->sha256ctx));
+ break;
+#endif
+#ifdef ARCHIVE_HAS_SHA512
+ case CKSUM_SHA512:
+ archive_sha512_init(&(sumwrk->sha512ctx));
+ break;
+#endif
+ default:
+ return (ARCHIVE_FATAL);
}
+ return (ARCHIVE_OK);
}
static void
@@ -1391,6 +1383,16 @@ _checksum_update(struct chksumwork *sumwrk, const void *buff, size_t size)
case CKSUM_MD5:
archive_md5_update(&(sumwrk->md5ctx), buff, size);
break;
+#ifdef ARCHIVE_HAS_SHA256
+ case CKSUM_SHA256:
+ archive_sha256_update(&(sumwrk->sha256ctx), buff, size);
+ break;
+#endif
+#ifdef ARCHIVE_HAS_SHA512
+ case CKSUM_SHA512:
+ archive_sha512_update(&(sumwrk->sha512ctx), buff, size);
+ break;
+#endif
}
}
@@ -1415,27 +1417,48 @@ _checksum_final(struct chksumwork *sumwrk, const void *val, size_t len)
memcmp(val, sum, MD5_SIZE) != 0)
r = ARCHIVE_FAILED;
break;
+#ifdef ARCHIVE_HAS_SHA256
+ case CKSUM_SHA256:
+ archive_sha256_final(&(sumwrk->sha256ctx), sum);
+ if (len != SHA256_SIZE ||
+ memcmp(val, sum, SHA256_SIZE) != 0)
+ r = ARCHIVE_FAILED;
+ break;
+#endif
+#ifdef ARCHIVE_HAS_SHA512
+ case CKSUM_SHA512:
+ archive_sha512_final(&(sumwrk->sha512ctx), sum);
+ if (len != SHA512_SIZE ||
+ memcmp(val, sum, SHA512_SIZE) != 0)
+ r = ARCHIVE_FAILED;
+ break;
+#endif
+ default:
+ r = ARCHIVE_FAILED;
}
return (r);
}
-static void
+static int
checksum_init(struct archive_read *a, int a_sum_alg, int e_sum_alg)
{
- struct xar *xar;
+ struct xar *xar = a->format->data;
- xar = (struct xar *)(a->format->data);
- _checksum_init(&(xar->a_sumwrk), a_sum_alg);
- _checksum_init(&(xar->e_sumwrk), e_sum_alg);
+ if (_checksum_init(&(xar->a_sumwrk), a_sum_alg) != ARCHIVE_OK ||
+ _checksum_init(&(xar->e_sumwrk), e_sum_alg) != ARCHIVE_OK) {
+ archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
+ "Unsupported checksum");
+ return (ARCHIVE_FATAL);
+ }
+ return (ARCHIVE_OK);
}
static void
checksum_update(struct archive_read *a, const void *abuff, size_t asize,
const void *ebuff, size_t esize)
{
- struct xar *xar;
+ struct xar *xar = a->format->data;
- xar = (struct xar *)(a->format->data);
_checksum_update(&(xar->a_sumwrk), abuff, asize);
_checksum_update(&(xar->e_sumwrk), ebuff, esize);
}
@@ -1444,27 +1467,24 @@ static int
checksum_final(struct archive_read *a, const void *a_sum_val,
size_t a_sum_len, const void *e_sum_val, size_t e_sum_len)
{
- struct xar *xar;
- int r;
+ struct xar *xar = a->format->data;
- xar = (struct xar *)(a->format->data);
- r = _checksum_final(&(xar->a_sumwrk), a_sum_val, a_sum_len);
- if (r == ARCHIVE_OK)
- r = _checksum_final(&(xar->e_sumwrk), e_sum_val, e_sum_len);
- if (r != ARCHIVE_OK)
+ if (_checksum_final(&(xar->a_sumwrk), a_sum_val, a_sum_len) != ARCHIVE_OK ||
+ _checksum_final(&(xar->e_sumwrk), e_sum_val, e_sum_len) != ARCHIVE_OK) {
archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
- "Sumcheck error");
- return (r);
+ "Checksum error");
+ return (ARCHIVE_FATAL);
+ }
+ return (ARCHIVE_OK);
}
static int
decompression_init(struct archive_read *a, enum enctype encoding)
{
- struct xar *xar;
+ struct xar *xar = a->format->data;
const char *detail;
int r;
- xar = (struct xar *)(a->format->data);
xar->rd_encoding = encoding;
switch (encoding) {
case NONE:
@@ -1600,12 +1620,11 @@ static int
decompress(struct archive_read *a, const void **buff, size_t *outbytes,
const void *b, size_t *used)
{
- struct xar *xar;
+ struct xar *xar = a->format->data;
void *outbuff;
size_t avail_in, avail_out;
int r;
- xar = (struct xar *)(a->format->data);
avail_in = *used;
outbuff = (void *)(uintptr_t)*buff;
if (outbuff == NULL) {
@@ -1728,10 +1747,9 @@ decompress(struct archive_read *a, const void **buff, size_t *outbytes,
static int
decompression_cleanup(struct archive_read *a)
{
- struct xar *xar;
+ struct xar *xar = a->format->data;
int r;
- xar = (struct xar *)(a->format->data);
r = ARCHIVE_OK;
if (xar->stream_valid) {
if (inflateEnd(&(xar->stream)) != Z_OK) {
@@ -1760,9 +1778,7 @@ decompression_cleanup(struct archive_read *a)
static void
checksum_cleanup(struct archive_read *a) {
- struct xar *xar;
-
- xar = (struct xar *)(a->format->data);
+ struct xar *xar = a->format->data;
_checksum_final(&(xar->a_sumwrk), NULL, 0);
_checksum_final(&(xar->e_sumwrk), NULL, 0);
@@ -1800,15 +1816,26 @@ file_new(struct archive_read *a, struct xar *xar, struct xmlattr_list *list)
file->mode = 0777 | AE_IFREG;
file->atime = 0;
file->mtime = 0;
- xar->file = file;
xar->xattr = NULL;
for (attr = list->first; attr != NULL; attr = attr->next) {
- if (strcmp(attr->name, "id") == 0)
- file->id = atol10(attr->value, strlen(attr->value));
+ if (strcmp(attr->name, "id") == 0) {
+ int r;
+
+ r = atou64(attr->value, strlen(attr->value),
+ 10, &file->id);
+ if (r != ARCHIVE_OK) {
+ free(file);
+ return (r);
+ }
+ }
}
+ xar->file = file;
file->nlink = 1;
- if (heap_add_entry(a, &(xar->file_queue), file) != ARCHIVE_OK)
+ if (heap_add_entry(a, &(xar->file_queue), file) != ARCHIVE_OK) {
+ xar->file = file->parent;
+ file_free(file);
return (ARCHIVE_FATAL);
+ }
return (ARCHIVE_OK);
}
@@ -1822,6 +1849,7 @@ file_free(struct xar_file *file)
archive_string_free(&(file->uname));
archive_string_free(&(file->gname));
archive_string_free(&(file->hardlink));
+ archive_string_free(&(file->fflags_text));
xattr = file->xattr_list;
while (xattr != NULL) {
struct xattr *next;
@@ -1845,11 +1873,19 @@ xattr_new(struct archive_read *a, struct xar *xar, struct xmlattr_list *list)
archive_set_error(&a->archive, ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
- xar->xattr = xattr;
for (attr = list->first; attr != NULL; attr = attr->next) {
- if (strcmp(attr->name, "id") == 0)
- xattr->id = atol10(attr->value, strlen(attr->value));
+ if (strcmp(attr->name, "id") == 0) {
+ int r;
+
+ r = atou64(attr->value, strlen(attr->value),
+ 10, &xattr->id);
+ if (r != ARCHIVE_OK) {
+ free(xattr);
+ return (r);
+ }
+ }
}
+ xar->xattr = xattr;
/* Chain to xattr list. */
for (nx = &(xar->file->xattr_list);
*nx != NULL; nx = &((*nx)->next)) {
@@ -1866,6 +1902,7 @@ static void
xattr_free(struct xattr *xattr)
{
archive_string_free(&(xattr->name));
+ archive_string_free(&(xattr->fstype));
free(xattr);
}
@@ -1903,9 +1940,16 @@ getsumalgorithm(struct xmlattr_list *list)
const char *v = attr->value;
if ((v[0] == 'S' || v[0] == 's') &&
(v[1] == 'H' || v[1] == 'h') &&
- (v[2] == 'A' || v[2] == 'a') &&
- v[3] == '1' && v[4] == '\0')
- alg = CKSUM_SHA1;
+ (v[2] == 'A' || v[2] == 'a')) {
+ if (v[3] == '1' && v[4] == '\0')
+ alg = CKSUM_SHA1;
+ else if (v[3] == '2' && v[4] == '5' &&
+ v[5] == '6' && v[6] == '\0')
+ alg = CKSUM_SHA256;
+ else if (v[3] == '5' && v[4] == '1' &&
+ v[5] == '2' && v[6] == '\0')
+ alg = CKSUM_SHA512;
+ }
if ((v[0] == 'M' || v[0] == 'm') &&
(v[1] == 'D' || v[1] == 'd') &&
v[2] == '5' && v[3] == '\0')
@@ -1963,11 +2007,9 @@ unknowntag_end(struct xar *xar, const char *name)
static int
xml_start(struct archive_read *a, const char *name, struct xmlattr_list *list)
{
- struct xar *xar;
+ struct xar *xar = a->format->data;
struct xmlattr *attr;
- xar = (struct xar *)(a->format->data);
-
#if DEBUG
fprintf(stderr, "xml_sta:[%s]\n", name);
for (attr = list->first; attr != NULL; attr = attr->next)
@@ -2065,8 +2107,17 @@ xml_start(struct archive_read *a, const char *name, struct xmlattr_list *list)
xar->file->hdnext = xar->hdlink_orgs;
xar->hdlink_orgs = xar->file;
} else {
- xar->file->link = (unsigned)atol10(attr->value,
- strlen(attr->value));
+ uint64_t val;
+ int r;
+ r = atou64(attr->value,
+ strlen(attr->value), 10, &val);
+ if (r != ARCHIVE_OK) {
+ return (r);
+ }
+ if (val > UINT_MAX) {
+ return (ARCHIVE_FATAL);
+ }
+ xar->file->link = (unsigned)val;
if (xar->file->link > 0)
if (add_link(a, xar, xar->file) != ARCHIVE_OK) {
return (ARCHIVE_FATAL);
@@ -2250,11 +2301,8 @@ xml_start(struct archive_read *a, const char *name, struct xmlattr_list *list)
static void
xml_end(void *userData, const char *name)
{
- struct archive_read *a;
- struct xar *xar;
-
- a = (struct archive_read *)userData;
- xar = (struct xar *)(a->format->data);
+ struct archive_read *a = (struct archive_read *)userData;
+ struct xar *xar = a->format->data;
#if DEBUG
fprintf(stderr, "xml_end:[%s]\n", name);
@@ -2628,7 +2676,7 @@ strappend_base64(struct xar *xar,
len = 0;
out = buff;
b = (const unsigned char *)s;
- while (l > 0) {
+ while (l > 1) {
int n = 0;
if (base64[b[0]] < 0 || base64[b[1]] < 0)
@@ -2673,37 +2721,41 @@ is_string(const char *known, const char *data, size_t len)
return memcmp(data, known, len);
}
-static void
+static int
xml_data(void *userData, const char *s, size_t len)
{
- struct archive_read *a;
- struct xar *xar;
-
- a = (struct archive_read *)userData;
- xar = (struct xar *)(a->format->data);
+ struct archive_read *a = (struct archive_read *)userData;
+ struct xar *xar = a->format->data;
+ uint64_t val;
+ int r;
#if DEBUG
{
char buff[1024];
- if (len > (int)(sizeof(buff)-1))
- len = (int)(sizeof(buff)-1);
- strncpy(buff, s, len);
- buff[len] = 0;
- fprintf(stderr, "\tlen=%d:\"%s\"\n", len, buff);
+ size_t dlen = len;
+ if (dlen > sizeof(buff) - 1)
+ dlen = sizeof(buff) - 1;
+ strncpy(buff, s, dlen);
+ buff[dlen] = 0;
+ fprintf(stderr, "\tlen=%zu:\"%s\"\n", dlen, buff);
}
#endif
switch (xar->xmlsts) {
case TOC_CHECKSUM_OFFSET:
- xar->toc_chksum_offset = atol10(s, len);
+ r = atou64(s, len, 10, &xar->toc_chksum_offset);
+ if (r != ARCHIVE_OK)
+ return (r);
break;
case TOC_CHECKSUM_SIZE:
- xar->toc_chksum_size = atol10(s, len);
+ r = atou64(s, len, 10, &xar->toc_chksum_size);
+ if (r != ARCHIVE_OK)
+ return (r);
break;
default:
break;
}
if (xar->file == NULL)
- return;
+ return (ARCHIVE_OK);
switch (xar->xmlsts) {
case FILE_NAME:
@@ -2752,42 +2804,76 @@ xml_data(void *userData, const char *s, size_t len)
xar->file->has |= HAS_TYPE;
break;
case FILE_INODE:
+ r = atou64(s, len, 10, &val);
+ if (r != ARCHIVE_OK)
+ return (r);
+ if (val > (uint64_t)INT64_MAX)
+ return (ARCHIVE_FATAL);
xar->file->has |= HAS_INO;
- xar->file->ino64 = atol10(s, len);
+ xar->file->ino64 = (int64_t)val;
break;
case FILE_DEVICE_MAJOR:
+ r = atou64(s, len, 10, &val);
+ if (r != ARCHIVE_OK)
+ return (r);
+ if (val != (dev_t)val)
+ return (ARCHIVE_FATAL);
xar->file->has |= HAS_DEVMAJOR;
- xar->file->devmajor = (dev_t)atol10(s, len);
+ xar->file->devmajor = (dev_t)val;
break;
case FILE_DEVICE_MINOR:
+ r = atou64(s, len, 10, &val);
+ if (r != ARCHIVE_OK)
+ return (r);
+ if (val != (dev_t)val)
+ return (ARCHIVE_FATAL);
xar->file->has |= HAS_DEVMINOR;
- xar->file->devminor = (dev_t)atol10(s, len);
+ xar->file->devminor = (dev_t)val;
break;
case FILE_DEVICENO:
+ r = atou64(s, len, 10, &val);
+ if (r != ARCHIVE_OK)
+ return (r);
+ if (val != (dev_t)val)
+ return (ARCHIVE_FATAL);
xar->file->has |= HAS_DEV;
- xar->file->dev = (dev_t)atol10(s, len);
+ xar->file->dev = (dev_t)val;
break;
case FILE_MODE:
+ r = atou64(s, len, 8, &val);
+ if (r != ARCHIVE_OK)
+ return (r);
+ if (val != (mode_t)val)
+ return (ARCHIVE_FATAL);
xar->file->has |= HAS_MODE;
xar->file->mode =
- (xar->file->mode & AE_IFMT) |
- ((mode_t)(atol8(s, len)) & ~AE_IFMT);
+ (xar->file->mode & AE_IFMT) | ((mode_t)val & ~AE_IFMT);
break;
case FILE_GROUP:
xar->file->has |= HAS_GID;
archive_strncpy(&(xar->file->gname), s, len);
break;
case FILE_GID:
+ r = atou64(s, len, 10, &val);
+ if (r != ARCHIVE_OK)
+ return (r);
+ if (val > (uint64_t)INT64_MAX)
+ return (ARCHIVE_FATAL);
xar->file->has |= HAS_GID;
- xar->file->gid = atol10(s, len);
+ xar->file->gid = (int64_t)val;
break;
case FILE_USER:
xar->file->has |= HAS_UID;
archive_strncpy(&(xar->file->uname), s, len);
break;
case FILE_UID:
+ r = atou64(s, len, 10, &val);
+ if (r != ARCHIVE_OK)
+ return (r);
+ if (val > (uint64_t)INT64_MAX)
+ return (ARCHIVE_FATAL);
xar->file->has |= HAS_UID;
- xar->file->uid = atol10(s, len);
+ xar->file->uid = (int64_t)val;
break;
case FILE_CTIME:
xar->file->has |= HAS_TIME | HAS_CTIME;
@@ -2802,16 +2888,22 @@ xml_data(void *userData, const char *s, size_t len)
xar->file->atime = parse_time(s, len);
break;
case FILE_DATA_LENGTH:
+ r = atou64(s, len, 10, &xar->file->length);
+ if (r != ARCHIVE_OK)
+ return (r);
xar->file->has |= HAS_DATA;
- xar->file->length = atol10(s, len);
break;
case FILE_DATA_OFFSET:
+ r = atou64(s, len, 10, &xar->file->offset);
+ if (r != ARCHIVE_OK)
+ return (r);
xar->file->has |= HAS_DATA;
- xar->file->offset = atol10(s, len);
break;
case FILE_DATA_SIZE:
+ r = atou64(s, len, 10, &xar->file->size);
+ if (r != ARCHIVE_OK)
+ return (r);
xar->file->has |= HAS_DATA;
- xar->file->size = atol10(s, len);
break;
case FILE_DATA_A_CHECKSUM:
xar->file->a_sum.len = atohex(xar->file->a_sum.val,
@@ -2822,16 +2914,22 @@ xml_data(void *userData, const char *s, size_t len)
sizeof(xar->file->e_sum.val), s, len);
break;
case FILE_EA_LENGTH:
+ r = atou64(s, len, 10, &xar->xattr->length);
+ if (r != ARCHIVE_OK)
+ return (r);
xar->file->has |= HAS_XATTR;
- xar->xattr->length = atol10(s, len);
break;
case FILE_EA_OFFSET:
+ r = atou64(s, len, 10, &xar->xattr->offset);
+ if (r != ARCHIVE_OK)
+ return (r);
xar->file->has |= HAS_XATTR;
- xar->xattr->offset = atol10(s, len);
break;
case FILE_EA_SIZE:
+ r = atou64(s, len, 10, &xar->xattr->size);
+ if (r != ARCHIVE_OK)
+ return (r);
xar->file->has |= HAS_XATTR;
- xar->xattr->size = atol10(s, len);
break;
case FILE_EA_A_CHECKSUM:
xar->file->has |= HAS_XATTR;
@@ -2907,6 +3005,8 @@ xml_data(void *userData, const char *s, size_t len)
case UNKNOWN:
break;
}
+
+ return (ARCHIVE_OK);
}
/*
@@ -3108,16 +3208,13 @@ xml2_xmlattr_setup(struct archive_read *a,
static int
xml2_read_cb(void *context, char *buffer, int len)
{
- struct archive_read *a;
- struct xar *xar;
+ struct archive_read *a = (struct archive_read *)context;
+ struct xar *xar = a->format->data;
const void *d;
size_t outbytes;
size_t used = 0;
int r;
- a = (struct archive_read *)context;
- xar = (struct xar *)(a->format->data);
-
if (xar->toc_remaining <= 0)
return (0);
d = buffer;
@@ -3146,10 +3243,9 @@ static void
xml2_error_hdr(void *arg, const char *msg, xmlParserSeverities severity,
xmlTextReaderLocatorPtr locator)
{
- struct archive_read *a;
+ struct archive_read *a = (struct archive_read *)arg;
(void)locator; /* UNUSED */
- a = (struct archive_read *)arg;
switch (severity) {
case XML_PARSER_SEVERITY_VALIDITY_WARNING:
case XML_PARSER_SEVERITY_WARNING:
@@ -3205,7 +3301,12 @@ xml2_read_toc(struct archive_read *a)
break;
case XML_READER_TYPE_TEXT:
value = (const char *)xmlTextReaderConstValue(reader);
- xml_data(a, value, strlen(value));
+ r = xml_data(a, value, strlen(value));
+ if (r != ARCHIVE_OK) {
+ xmlFreeTextReader(reader);
+ xmlCleanupParser();
+ return (r);
+ }
break;
case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
default:
@@ -3285,21 +3386,22 @@ expat_data_cb(void *userData, const XML_Char *s, int len)
{
struct expat_userData *ud = (struct expat_userData *)userData;
- xml_data(ud->archive, s, (size_t)len);
+ if (ud->state != ARCHIVE_OK)
+ return;
+
+ ud->state = xml_data(ud->archive, s, (size_t)len);
}
static int
expat_read_toc(struct archive_read *a)
{
- struct xar *xar;
+ struct xar *xar = a->format->data;
XML_Parser parser;
struct expat_userData ud;
ud.state = ARCHIVE_OK;
ud.archive = a;
- xar = (struct xar *)(a->format->data);
-
/* Initialize XML Parser library. */
parser = XML_ParserCreate(NULL);
if (parser == NULL) {
@@ -3321,7 +3423,7 @@ expat_read_toc(struct archive_read *a)
d = NULL;
r = rd_contents(a, &d, &outbytes, &used, xar->toc_remaining);
- if (r != ARCHIVE_OK) {
+ if (r != ARCHIVE_OK || outbytes > INT_MAX) {
XML_ParserFree(parser);
return (r);
}
@@ -3383,16 +3485,13 @@ static HRESULT STDMETHODCALLTYPE
asaRead(ISequentialStream *this, void *pv, ULONG cb, ULONG *pcbRead)
{
struct ArchiveStreamAdapter *asa = (struct ArchiveStreamAdapter *)this;
- struct archive_read *a;
- struct xar *xar;
+ struct archive_read *a = asa->a;
+ struct xar *xar = a->format->data;
const void *d = pv;
size_t outbytes = cb;
size_t used = 0;
int r;
- a = asa->a;
- xar = (struct xar *)(a->format->data);
-
*pcbRead = 0;
if (xar->toc_remaining <= 0)
@@ -3638,7 +3737,11 @@ xmllite_read_toc(struct archive_read *a)
goto out;
}
- xml_data(a, as.s, (int)archive_strlen(&as));
+ r = xml_data(a, as.s, archive_strlen(&as));
+ if (r != ARCHIVE_OK) {
+ /* xml_data sets an appropriate error */
+ goto out;
+ }
archive_string_free(&as);
case XmlNodeType_None:
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_zip.c b/contrib/libarchive/libarchive/archive_read_support_format_zip.c
index 00796b288a48..4148c4c90412 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_zip.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_zip.c
@@ -152,8 +152,6 @@ struct zip {
struct archive_string format_name;
int64_t central_directory_offset;
int64_t central_directory_offset_adjusted;
- size_t central_directory_entries_total;
- size_t central_directory_entries_on_this_disk;
int has_encrypted_entries;
/* List of entries (seekable Zip only) */
@@ -261,6 +259,15 @@ struct zip {
/* Many systems define min or MIN, but not all. */
#define zipmin(a,b) ((a) < (b) ? (a) : (b))
+/* True if this entry has declared a specific uncompressed size. */
+static int
+zip_entry_size_is_set(const struct zip_entry *zip_entry)
+{
+ return (0 == (zip_entry->zip_flags & ZIP_LENGTH_AT_END)
+ || (zip_entry->uncompressed_size > 0
+ && zip_entry->uncompressed_size != 0xffffffff));
+}
+
#ifdef HAVE_ZLIB_H
static int
zip_read_data_deflate(struct archive_read *a, const void **buff,
@@ -272,6 +279,10 @@ zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
size_t *size, int64_t *offset);
#endif
+static void
+trad_enc_decrypt_update(struct trad_enc_ctx *, const uint8_t *, size_t,
+ uint8_t *, size_t);
+
/* This function is used by Ppmd8_DecodeSymbol during decompression of Ppmd8
* streams inside ZIP files. It has 2 purposes: one is to fetch the next
* compressed byte from the stream, second one is to increase the counter how
@@ -280,16 +291,33 @@ static Byte
ppmd_read(void* p) {
/* Get the handle to current decompression context. */
struct archive_read *a = ((IByteIn*)p)->a;
- struct zip *zip = (struct zip*) a->format->data;
- ssize_t bytes_avail = 0;
+ struct zip *zip = a->format->data;
/* Fetch next byte. */
- const uint8_t* data = __archive_read_ahead(a, 1, &bytes_avail);
- if(bytes_avail < 1) {
+ const uint8_t* data = __archive_read_ahead(a, 1, NULL);
+ if(data == NULL) {
zip->ppmd8_stream_failed = 1;
return 0;
}
+ if (zip->tctx_valid || zip->cctx_valid) {
+ uint8_t val;
+ if (zip->tctx_valid) {
+ trad_enc_decrypt_update(&zip->tctx,
+ data, 1, &val, 1);
+ } else {
+ size_t dsize = 1;
+ archive_decrypto_aes_ctr_update(&zip->cctx,
+ data, 1, &val, &dsize);
+ }
+ if (zip->hctx_valid)
+ archive_hmac_sha1_update(&zip->hctx, data, 1);
+
+ __archive_read_consume(a, 1);
+ ++zip->zipx_ppmd_read_compressed;
+ return val;
+ }
+
__archive_read_consume(a, 1);
/* Increment the counter. */
@@ -401,6 +429,153 @@ crypt_derive_key_sha1(const void *p, int size, unsigned char *key,
}
#endif
+/* Read and decrypt bytes for zipx init headers.
+ * Used by format-specific init functions (lzma, ppmd) that need to
+ * read a small header from the compressed stream. When encryption is
+ * active the bytes are decrypted in-place into the decryption buffer. */
+static int
+zipx_read_header_and_decrypt(struct archive_read *a, const void **buf, size_t in_len,
+ size_t *out_len, size_t *consumed)
+{
+ struct zip *zip = a->format->data;
+ const void *raw;
+ ssize_t bytes_avail;
+ size_t to_decrypt;
+
+ raw = __archive_read_ahead(a, in_len, &bytes_avail);
+ if (raw == NULL || bytes_avail < (ssize_t)in_len) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated ZIP file data");
+ return (ARCHIVE_FATAL);
+ }
+
+ if (zip->tctx_valid || zip->cctx_valid) {
+ to_decrypt = in_len;
+ if (to_decrypt > zip->decrypted_buffer_size)
+ to_decrypt = zip->decrypted_buffer_size;
+
+ if (zip->tctx_valid) {
+ trad_enc_decrypt_update(&zip->tctx,
+ raw, to_decrypt,
+ zip->decrypted_buffer, to_decrypt);
+ } else {
+ size_t dsize = to_decrypt;
+ archive_decrypto_aes_ctr_update(&zip->cctx,
+ raw, to_decrypt,
+ zip->decrypted_buffer, &dsize);
+ }
+ if (zip->hctx_valid)
+ archive_hmac_sha1_update(&zip->hctx,
+ raw, to_decrypt);
+
+ *buf = zip->decrypted_buffer;
+ *out_len = to_decrypt;
+ *consumed = to_decrypt;
+ } else {
+ *buf = raw;
+ *out_len = in_len;
+ *consumed = in_len;
+ }
+ return (ARCHIVE_OK);
+}
+
+/* Decrypt bulk compressed data for zipx decompression.
+ * Manages the decryption buffer, handles partial fills, and returns decrypted
+ * data pointer + length. `sp` is set to the raw pointer for HMAC accounting. */
+static void
+zip_read_decrypt(struct zip *zip, const void *compressed_buff,
+ ssize_t bytes_avail, const void **result_buff, ssize_t *result_avail,
+ const void **sp)
+{
+ *sp = compressed_buff;
+
+ /* Safety check to prevent potential OOB reads if something went wrong
+ * previously. We should not have a negative bytes_avail count here.
+ * If we do, set them to zero so that reading the ZIP will fail later,
+ * safely as corrupted instead of crashing. */
+ if (bytes_avail < 0)
+ bytes_avail = 0;
+
+ if (zip->tctx_valid || zip->cctx_valid) {
+ if (zip->decrypted_bytes_remaining < (size_t)bytes_avail) {
+ size_t buff_remaining =
+ (zip->decrypted_buffer +
+ zip->decrypted_buffer_size)
+ - (zip->decrypted_ptr +
+ zip->decrypted_bytes_remaining);
+ /* The new bytes to decrypt start after decrypted_bytes_remaining
+ * in the raw stream: those leading bytes were already
+ * decrypted on a previous call but have not yet been consumed. */
+ size_t new_bytes =
+ (size_t)bytes_avail
+ - zip->decrypted_bytes_remaining;
+
+ if (buff_remaining > new_bytes)
+ buff_remaining = new_bytes;
+
+ if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END) &&
+ zip->entry_bytes_remaining > 0) {
+ if ((int64_t)(zip->decrypted_bytes_remaining
+ + buff_remaining)
+ > zip->entry_bytes_remaining) {
+ if (zip->entry_bytes_remaining <
+ (int64_t)zip->decrypted_bytes_remaining)
+ buff_remaining = 0;
+ else
+ buff_remaining =
+ (size_t)zip->entry_bytes_remaining
+ - zip->decrypted_bytes_remaining;
+ }
+ }
+ if (buff_remaining > 0) {
+ if (zip->tctx_valid) {
+ trad_enc_decrypt_update(&zip->tctx,
+ (const uint8_t *)compressed_buff
+ + zip->decrypted_bytes_remaining,
+ buff_remaining,
+ zip->decrypted_ptr
+ + zip->decrypted_bytes_remaining,
+ buff_remaining);
+ } else {
+ size_t dsize = buff_remaining;
+ archive_decrypto_aes_ctr_update(
+ &zip->cctx,
+ (const uint8_t *)compressed_buff
+ + zip->decrypted_bytes_remaining,
+ buff_remaining,
+ zip->decrypted_ptr
+ + zip->decrypted_bytes_remaining,
+ &dsize);
+ }
+ zip->decrypted_bytes_remaining +=
+ buff_remaining;
+ }
+ }
+ *result_avail = zip->decrypted_bytes_remaining;
+ *result_buff = (const char *)zip->decrypted_ptr;
+ } else {
+ *result_buff = compressed_buff;
+ *result_avail = bytes_avail;
+ }
+}
+
+/* Post-decompression decrypt state update.
+ * Updates decrypt buffer pointers and HMAC after the decompressor
+ * has consumed `to_consume` bytes. */
+static void
+zip_read_decrypt_update(struct zip *zip, ssize_t to_consume, const void *sp)
+{
+ if (zip->tctx_valid || zip->cctx_valid) {
+ zip->decrypted_bytes_remaining -= to_consume;
+ if (zip->decrypted_bytes_remaining == 0)
+ zip->decrypted_ptr = zip->decrypted_buffer;
+ else
+ zip->decrypted_ptr += to_consume;
+ }
+ if (zip->hctx_valid)
+ archive_hmac_sha1_update(&zip->hctx, sp, to_consume);
+}
+
/*
* Common code for streaming or seeking modes.
*
@@ -481,8 +656,8 @@ static int
process_extra(struct archive_read *a, struct archive_entry *entry,
const char *p, size_t extra_length, struct zip_entry* zip_entry)
{
+ struct zip *zip = a->format->data;
unsigned offset = 0;
- struct zip *zip = (struct zip *)(a->format->data);
if (extra_length == 0) {
return ARCHIVE_OK;
@@ -581,6 +756,22 @@ process_extra(struct archive_read *a, struct archive_entry *entry,
* on which file starts, but we don't handle
* multi-volume Zip files. */
break;
+ case 0x000d:
+ /* PKWARE Unix Extra Field fixed metadata. */
+ if (datasize >= 12) {
+ zip_entry->atime = archive_le32dec(p + offset);
+ zip_entry->mtime =
+ archive_le32dec(p + offset + 4);
+ zip_entry->uid =
+ archive_le16dec(p + offset + 8);
+ zip_entry->gid =
+ archive_le16dec(p + offset + 10);
+ /*
+ * APPNOTE.TXT also defines additional data after
+ * this fixed metadata, depending on file type.
+ */
+ }
+ break;
#ifdef DEBUG
case 0x0017:
{
@@ -1269,10 +1460,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
"Read error skipping symlink target name");
return ARCHIVE_FATAL;
}
- } else if (0 == (zip_entry->zip_flags & ZIP_LENGTH_AT_END)
- || (zip_entry->uncompressed_size > 0
- && zip_entry->uncompressed_size != 0xffffffff)) {
- /* Set the size only if it's meaningful. */
+ } else if (zip_entry_size_is_set(zip_entry)) {
archive_entry_set_size(entry, zip_entry->uncompressed_size);
}
zip->entry_bytes_remaining = zip_entry->compressed_size;
@@ -1295,7 +1483,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
static int
check_authentication_code(struct archive_read *a, const void *_p)
{
- struct zip *zip = (struct zip *)(a->format->data);
+ struct zip *zip = a->format->data;
/* Check authentication code. */
if (zip->hctx_valid) {
@@ -1522,6 +1710,26 @@ consume_end_of_file_marker(struct archive_read *a, struct zip *zip)
return;
}
+ /* None of the exact patterns matched. If entry size was unknown
+ * (ZIP_LENGTH_AT_END flag), before treating this as
+ * corruption, check whether the next ZIP record follows the data
+ * immediately: a length-at-end entry whose compression format has
+ * its own end-of-stream marker (e.g. PPMd) may be written with no
+ * data descriptor at all. In that case the byte counts we measured
+ * during decompression are authoritative, so trust them and leave
+ * the stream untouched. */
+ if (zip->entry->zip_flags & ZIP_LENGTH_AT_END)
+ {
+ const uint32_t sig = archive_le32dec(p);
+ if (sig == 0x04034b50U /* Local file header */
+ || sig == 0x02014b50U /* Central directory record */
+ || sig == 0x06054b50U) /* End of central directory */ {
+ zip->entry->compressed_size = compressed_actual;
+ zip->entry->uncompressed_size = uncompressed_actual;
+ return;
+ }
+ }
+
/* If none of the above patterns gives us a full exact match,
* then there's something definitely amiss. The fallback code
* below will parse out some plausible values for error
@@ -1599,7 +1807,7 @@ static int
zip_read_data_none(struct archive_read *a, const void **_buff,
size_t *size, int64_t *offset)
{
- struct zip *zip;
+ struct zip *zip = a->format->data;
const char *buff;
ssize_t bytes_avail;
ssize_t trailing_extra;
@@ -1607,7 +1815,6 @@ zip_read_data_none(struct archive_read *a, const void **_buff,
(void)offset; /* UNUSED */
- zip = (struct zip *)(a->format->data);
trailing_extra = zip->hctx_valid ? AUTH_CODE_SIZE : 0;
if (zip->entry->zip_flags & ZIP_LENGTH_AT_END) {
@@ -1775,7 +1982,7 @@ zipx_lzma_alone_init(struct archive_read *a, struct zip *zip)
* "lzma alone" decoder from XZ Utils. */
memset(&zip->zipx_lzma_stream, 0, sizeof(zip->zipx_lzma_stream));
- r = lzma_alone_decoder(&zip->zipx_lzma_stream, UINT64_MAX);
+ r = lzma_alone_decoder(&zip->zipx_lzma_stream, 576 * ((uint64_t)1 << 20));
if (r != LZMA_OK) {
archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
"lzma initialization failed (%d)", r);
@@ -1825,12 +2032,38 @@ zipx_lzma_alone_init(struct archive_read *a, struct zip *zip)
*/
/* Read magic1,magic2,lzma_params from the ZIPX stream. */
- if(zip->entry_bytes_remaining < 9 || (p = __archive_read_ahead(a, 9, NULL)) == NULL) {
+ /* When the compressed size is unknown (e.g. ZIP_LENGTH_AT_END read
+ * from a non-seekable source), entry_bytes_remaining is 0 or negative
+ * here. We can still attempt to read the 9-byte header; if the data
+ * is truly truncated, the __archive_read_ahead calls below will catch
+ * it. */
+ if(zip->entry_bytes_remaining > 0
+ && zip->entry_bytes_remaining < 9) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated lzma data");
return (ARCHIVE_FATAL);
}
+ if (zip->tctx_valid || zip->cctx_valid) {
+ const void *decrypted;
+ size_t out_len;
+ size_t consumed;
+ int ret;
+
+ ret = zipx_read_header_and_decrypt(a, &decrypted, 9, &out_len, &consumed);
+ if (ret != ARCHIVE_OK)
+ return ret;
+ p = decrypted;
+ } else {
+ p = __archive_read_ahead(a, 9, NULL);
+ if (p == NULL) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated lzma data");
+ return (ARCHIVE_FATAL);
+ }
+ }
+
if(p[2] != 0x05 || p[3] != 0x00) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid lzma data");
@@ -1868,15 +2101,21 @@ zipx_lzma_alone_init(struct archive_read *a, struct zip *zip)
* output bytes yet. */
r = lzma_code(&zip->zipx_lzma_stream, LZMA_RUN);
if (r != LZMA_OK) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
- "lzma stream initialization error");
+ if (r == LZMA_MEMLIMIT_ERROR)
+ archive_set_error(&a->archive, ENOMEM,
+ "lzma stream requires too much memory");
+ else
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+ "lzma stream initialization error");
return ARCHIVE_FATAL;
}
/* We've already consumed some bytes, so take this into account. */
__archive_read_consume(a, 9);
- zip->entry_bytes_remaining -= 9;
zip->entry_compressed_bytes_read += 9;
+ if (zip->entry_bytes_remaining > 0) {
+ zip->entry_bytes_remaining -= 9;
+ }
zip->decompress_init = 1;
return (ARCHIVE_OK);
@@ -1886,11 +2125,12 @@ static int
zip_read_data_zipx_xz(struct archive_read *a, const void **buff,
size_t *size, int64_t *offset)
{
- struct zip* zip = (struct zip *)(a->format->data);
+ struct zip *zip = a->format->data;
int ret;
lzma_ret lz_ret;
const void* compressed_buf;
- ssize_t bytes_avail, in_bytes, to_consume = 0;
+ const void* sp;
+ ssize_t bytes_avail, to_consume = 0;
(void) offset; /* UNUSED */
@@ -1901,16 +2141,22 @@ zip_read_data_zipx_xz(struct archive_read *a, const void **buff,
return (ret);
}
- compressed_buf = __archive_read_ahead(a, 1, &bytes_avail);
+ compressed_buf = sp = __archive_read_ahead(a, 1, &bytes_avail);
+ if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)
+ && bytes_avail > zip->entry_bytes_remaining) {
+ bytes_avail = (ssize_t)zip->entry_bytes_remaining;
+ }
if (bytes_avail < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated xz file body");
return (ARCHIVE_FATAL);
}
- in_bytes = (ssize_t)zipmin(zip->entry_bytes_remaining, bytes_avail);
+ zip_read_decrypt(zip, compressed_buf, bytes_avail,
+ &compressed_buf, &bytes_avail, &sp);
+
zip->zipx_lzma_stream.next_in = compressed_buf;
- zip->zipx_lzma_stream.avail_in = in_bytes;
+ zip->zipx_lzma_stream.avail_in = bytes_avail;
zip->zipx_lzma_stream.total_in = 0;
zip->zipx_lzma_stream.next_out = zip->uncompressed_buffer;
zip->zipx_lzma_stream.avail_out = zip->uncompressed_buffer_size;
@@ -1937,8 +2183,10 @@ zip_read_data_zipx_xz(struct archive_read *a, const void **buff,
lzma_end(&zip->zipx_lzma_stream);
zip->zipx_lzma_valid = 0;
- if((int64_t) zip->zipx_lzma_stream.total_in !=
- zip->entry_bytes_remaining)
+ /* This assertion is only possible if the size of the compressed data
+ * stream is known -> !ZIP_LENGTH_AT_END */
+ if((int64_t) zip->zipx_lzma_stream.total_in != zip->entry_bytes_remaining
+ && !(zip->entry->zip_flags & ZIP_LENGTH_AT_END))
{
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
@@ -1957,6 +2205,16 @@ zip_read_data_zipx_xz(struct archive_read *a, const void **buff,
zip->entry_compressed_bytes_read += to_consume;
zip->entry_uncompressed_bytes_read += zip->zipx_lzma_stream.total_out;
+ zip_read_decrypt_update(zip, to_consume, sp);
+
+ if (zip->end_of_entry) {
+ if (zip->hctx_valid) {
+ ret = check_authentication_code(a, NULL);
+ if (ret != ARCHIVE_OK)
+ return ret;
+ }
+ }
+
*size = (size_t)zip->zipx_lzma_stream.total_out;
*buff = zip->uncompressed_buffer;
@@ -1967,11 +2225,12 @@ static int
zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
size_t *size, int64_t *offset)
{
- struct zip* zip = (struct zip *)(a->format->data);
+ struct zip *zip = a->format->data;
int ret;
lzma_ret lz_ret;
const void* compressed_buf;
- ssize_t bytes_avail, in_bytes, to_consume;
+ const void* sp;
+ ssize_t bytes_avail, to_consume;
(void) offset; /* UNUSED */
@@ -1991,26 +2250,38 @@ zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
* data.
*/
compressed_buf = __archive_read_ahead(a, 1, &bytes_avail);
+ if (zip->entry_bytes_remaining > 0
+ && bytes_avail > zip->entry_bytes_remaining) {
+ bytes_avail = (ssize_t)zip->entry_bytes_remaining;
+ }
if (bytes_avail < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated lzma file body");
return (ARCHIVE_FATAL);
}
- /* Set decompressor parameters. */
- in_bytes = (ssize_t)zipmin(zip->entry_bytes_remaining, bytes_avail);
+ zip_read_decrypt(zip, compressed_buf, bytes_avail,
+ &compressed_buf, &bytes_avail, &sp);
zip->zipx_lzma_stream.next_in = compressed_buf;
- zip->zipx_lzma_stream.avail_in = in_bytes;
+ zip->zipx_lzma_stream.avail_in = bytes_avail;
zip->zipx_lzma_stream.total_in = 0;
zip->zipx_lzma_stream.next_out = zip->uncompressed_buffer;
- zip->zipx_lzma_stream.avail_out =
- /* These lzma_alone streams lack end of stream marker, so let's
- * make sure the unpacker won't try to unpack more than it's
- * supposed to. */
- (size_t)zipmin((int64_t) zip->uncompressed_buffer_size,
- zip->entry->uncompressed_size -
- zip->entry_uncompressed_bytes_read);
+ /* These lzma_alone streams lack an end of stream marker in some
+ * cases, so when the uncompressed size is known we cap avail_out to
+ * make sure the unpacker won't try to unpack more than it's supposed
+ * to. When the compressed size is unknown (entry_bytes_remaining <= 0,
+ * e.g. ZIP_LENGTH_AT_END from a non-seekable source) we must use the
+ * full buffer and rely on the LZMA stream end marker to detect the end
+ * of the entry. */
+ if (zip->entry_bytes_remaining <= 0) {
+ zip->zipx_lzma_stream.avail_out = zip->uncompressed_buffer_size;
+ } else {
+ zip->zipx_lzma_stream.avail_out =
+ (size_t)zipmin((int64_t) zip->uncompressed_buffer_size,
+ zip->entry->uncompressed_size -
+ zip->entry_uncompressed_bytes_read);
+ }
zip->zipx_lzma_stream.total_out = 0;
/* Perform the decompression. */
@@ -2024,8 +2295,11 @@ zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
/* This case is optional in lzma alone format. It can happen,
* but most of the files don't have it. (GitHub #1257) */
case LZMA_STREAM_END:
+ /* This assertion is only possible if the size of the
+ * compressed data stream is known. */
if((int64_t) zip->zipx_lzma_stream.total_in !=
- zip->entry_bytes_remaining)
+ zip->entry_bytes_remaining
+ && zip->entry_bytes_remaining > 0)
{
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
@@ -2039,6 +2313,18 @@ zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
case LZMA_OK:
break;
+ case LZMA_BUF_ERROR:
+ if (zip->zipx_lzma_stream.avail_out == 0) {
+ /* The output buffer was filled exactly. When
+ * the uncompressed size is known this means we
+ * have decompressed all expected bytes. When
+ * the size is unknown a full buffer just means
+ * we need another iteration. */
+ if (zip->entry_bytes_remaining > 0)
+ zip->end_of_entry = 1;
+ break;
+ }
+ /* FALL THROUGH */
default:
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"lzma unknown error (%d)", (int) lz_ret);
@@ -2049,12 +2335,29 @@ zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
/* Update pointers. */
__archive_read_consume(a, to_consume);
- zip->entry_bytes_remaining -= to_consume;
zip->entry_compressed_bytes_read += to_consume;
zip->entry_uncompressed_bytes_read += zip->zipx_lzma_stream.total_out;
- if(zip->entry_bytes_remaining == 0) {
- zip->end_of_entry = 1;
+ zip_read_decrypt_update(zip, to_consume, sp);
+
+ if(zip->entry_bytes_remaining > 0) {
+ zip->entry_bytes_remaining -= to_consume;
+ if(zip->entry_bytes_remaining == 0) {
+ zip->end_of_entry = 1;
+ }
+ }
+
+ if(zip->end_of_entry && zip->entry_bytes_remaining > 0) {
+ ssize_t remaining = (ssize_t)zip->entry_bytes_remaining;
+ const void *p = __archive_read_ahead(a, remaining, NULL);
+ if (p != NULL) {
+ if (zip->hctx_valid)
+ archive_hmac_sha1_update(&zip->hctx,
+ p, remaining);
+ __archive_read_consume(a, remaining);
+ zip->entry_compressed_bytes_read += remaining;
+ zip->entry_bytes_remaining = 0;
+ }
}
/* Free lzma decoder handle because we'll no longer need it. */
@@ -2063,6 +2366,12 @@ zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
if(zip->end_of_entry) {
lzma_end(&zip->zipx_lzma_stream);
zip->zipx_lzma_valid = 0;
+
+ if (zip->hctx_valid) {
+ ret = check_authentication_code(a, NULL);
+ if (ret != ARCHIVE_OK)
+ return ret;
+ }
}
/* Return values. */
@@ -2104,11 +2413,22 @@ zipx_ppmd8_init(struct archive_read *a, struct zip *zip)
zip->zipx_ppmd_read_compressed = 0;
/* Read Ppmd8 header (2 bytes). */
- p = __archive_read_ahead(a, 2, NULL);
- if(!p) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated file data in PPMd8 stream");
- return (ARCHIVE_FATAL);
+ if (zip->tctx_valid || zip->cctx_valid) {
+ size_t out_len;
+ size_t consumed;
+ int ret;
+
+ ret = zipx_read_header_and_decrypt(a, &p, 2, &out_len, &consumed);
+ if (ret != ARCHIVE_OK)
+ return ret;
+ } else {
+ p = __archive_read_ahead(a, 2, NULL);
+ if(!p) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated file data in PPMd8 stream");
+ return (ARCHIVE_FATAL);
+ }
}
__archive_read_consume(a, 2);
@@ -2175,10 +2495,9 @@ static int
zip_read_data_zipx_ppmd(struct archive_read *a, const void **buff,
size_t *size, int64_t *offset)
{
- struct zip* zip = (struct zip *)(a->format->data);
+ struct zip *zip = a->format->data;
int ret;
size_t consumed_bytes = 0;
- ssize_t bytes_avail = 0;
(void) offset; /* UNUSED */
@@ -2192,8 +2511,7 @@ zip_read_data_zipx_ppmd(struct archive_read *a, const void **buff,
/* Fetch for more data. We're reading 1 byte here, but libarchive
* should prefetch more bytes. */
- (void) __archive_read_ahead(a, 1, &bytes_avail);
- if(bytes_avail < 0) {
+ if(__archive_read_ahead(a, 1, NULL) == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated PPMd8 file body");
return (ARCHIVE_FATAL);
@@ -2234,6 +2552,12 @@ zip_read_data_zipx_ppmd(struct archive_read *a, const void **buff,
if(zip->end_of_entry) {
__archive_ppmd8_functions.Ppmd8_Free(&zip->ppmd8);
zip->ppmd8_valid = 0;
+
+ if (zip->hctx_valid) {
+ int r = check_authentication_code(a, NULL);
+ if (r != ARCHIVE_OK)
+ return (r);
+ }
}
/* Update pointers for libarchive. */
@@ -2290,9 +2614,10 @@ static int
zip_read_data_zipx_bzip2(struct archive_read *a, const void **buff,
size_t *size, int64_t *offset)
{
- struct zip *zip = (struct zip *)(a->format->data);
- ssize_t bytes_avail = 0, in_bytes, to_consume;
+ struct zip *zip = a->format->data;
+ ssize_t bytes_avail = 0, to_consume;
const void *compressed_buff;
+ const void *sp;
int r;
uint64_t total_out;
@@ -2307,27 +2632,26 @@ zip_read_data_zipx_bzip2(struct archive_read *a, const void **buff,
/* Fetch more compressed bytes. */
compressed_buff = __archive_read_ahead(a, 1, &bytes_avail);
- if(bytes_avail < 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated bzip2 file body");
- return (ARCHIVE_FATAL);
+ if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)
+ && bytes_avail > zip->entry_bytes_remaining) {
+ bytes_avail = (ssize_t)zip->entry_bytes_remaining;
}
-
- in_bytes = (ssize_t)zipmin(zip->entry_bytes_remaining, bytes_avail);
- if(in_bytes < 1) {
+ if(bytes_avail < 1) {
/* libbz2 doesn't complain when caller feeds avail_in == 0.
* It will actually return success in this case, which is
* undesirable. This is why we need to make this check
* manually. */
-
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated bzip2 file body");
return (ARCHIVE_FATAL);
}
+ zip_read_decrypt(zip, compressed_buff, bytes_avail,
+ &compressed_buff, &bytes_avail, &sp);
+
/* Setup buffer boundaries. */
zip->bzstream.next_in = (char*)(uintptr_t) compressed_buff;
- zip->bzstream.avail_in = (uint32_t)in_bytes;
+ zip->bzstream.avail_in = (uint32_t)bytes_avail;
zip->bzstream.total_in_hi32 = 0;
zip->bzstream.total_in_lo32 = 0;
zip->bzstream.next_out = (char*) zip->uncompressed_buffer;
@@ -2375,6 +2699,14 @@ zip_read_data_zipx_bzip2(struct archive_read *a, const void **buff,
zip->entry_compressed_bytes_read += to_consume;
zip->entry_uncompressed_bytes_read += total_out;
+ zip_read_decrypt_update(zip, to_consume, sp);
+
+ if (zip->end_of_entry && zip->hctx_valid) {
+ r = check_authentication_code(a, NULL);
+ if (r != ARCHIVE_OK)
+ return r;
+ }
+
/* Give libarchive its due. */
*size = (size_t)total_out;
*buff = zip->uncompressed_buffer;
@@ -2433,9 +2765,10 @@ static int
zip_read_data_zipx_zstd(struct archive_read *a, const void **buff,
size_t *size, int64_t *offset)
{
- struct zip *zip = (struct zip *)(a->format->data);
- ssize_t bytes_avail = 0, in_bytes, to_consume;
+ struct zip *zip = a->format->data;
+ ssize_t bytes_avail = 0, to_consume;
const void *compressed_buff;
+ const void *sp;
int r;
size_t ret;
uint64_t total_out;
@@ -2452,15 +2785,12 @@ zip_read_data_zipx_zstd(struct archive_read *a, const void **buff,
}
/* Fetch more compressed bytes */
- compressed_buff = __archive_read_ahead(a, 1, &bytes_avail);
- if(bytes_avail < 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated zstd file body");
- return (ARCHIVE_FATAL);
+ compressed_buff = sp = __archive_read_ahead(a, 1, &bytes_avail);
+ if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)
+ && bytes_avail > zip->entry_bytes_remaining) {
+ bytes_avail = (ssize_t)zip->entry_bytes_remaining;
}
-
- in_bytes = (ssize_t)zipmin(zip->entry_bytes_remaining, bytes_avail);
- if(in_bytes < 1) {
+ if(bytes_avail < 1) {
/* zstd doesn't complain when caller feeds avail_in == 0.
* It will actually return success in this case, which is
* undesirable. This is why we need to make this check
@@ -2470,9 +2800,12 @@ zip_read_data_zipx_zstd(struct archive_read *a, const void **buff,
return (ARCHIVE_FATAL);
}
+ zip_read_decrypt(zip, compressed_buff, bytes_avail,
+ &compressed_buff, &bytes_avail, &sp);
+
/* Setup buffer boundaries */
in.src = compressed_buff;
- in.size = in_bytes;
+ in.size = bytes_avail;
in.pos = 0;
out = (ZSTD_outBuffer) { zip->uncompressed_buffer, zip->uncompressed_buffer_size, 0 };
@@ -2484,6 +2817,10 @@ zip_read_data_zipx_zstd(struct archive_read *a, const void **buff,
ZSTD_getErrorName(ret));
return (ARCHIVE_FATAL);
}
+ /* End of stream handling for zips with ZIP_LENGTH_AT_END flag */
+ if (ret == 0 && (zip->entry->zip_flags & ZIP_LENGTH_AT_END)) {
+ zip->end_of_entry = 1;
+ }
/* Check end of the stream. */
if (ret == 0) {
@@ -2504,6 +2841,14 @@ zip_read_data_zipx_zstd(struct archive_read *a, const void **buff,
zip->entry_compressed_bytes_read += to_consume;
zip->entry_uncompressed_bytes_read += total_out;
+ zip_read_decrypt_update(zip, to_consume, sp);
+
+ if (zip->end_of_entry && zip->hctx_valid) {
+ r = check_authentication_code(a, NULL);
+ if (r != ARCHIVE_OK)
+ return r;
+ }
+
/* Give libarchive its due. */
*size = (size_t)total_out;
*buff = zip->uncompressed_buffer;
@@ -2542,15 +2887,14 @@ static int
zip_read_data_deflate(struct archive_read *a, const void **buff,
size_t *size, int64_t *offset)
{
- struct zip *zip;
+ struct zip *zip = a->format->data;
ssize_t bytes_avail, to_consume = 0;
- const void *compressed_buff, *sp;
+ const void *compressed_buff;
+ const void *sp;
int r;
(void)offset; /* UNUSED */
- zip = (struct zip *)(a->format->data);
-
/* If the buffer hasn't been allocated, allocate it now. */
if (zip->uncompressed_buffer == NULL) {
zip->uncompressed_buffer_size = 256 * 1024;
@@ -2584,54 +2928,8 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
return (ARCHIVE_FATAL);
}
- if (zip->tctx_valid || zip->cctx_valid) {
- if (zip->decrypted_bytes_remaining < (size_t)bytes_avail) {
- size_t buff_remaining =
- (zip->decrypted_buffer +
- zip->decrypted_buffer_size)
- - (zip->decrypted_ptr +
- zip->decrypted_bytes_remaining);
-
- if (buff_remaining > (size_t)bytes_avail)
- buff_remaining = (size_t)bytes_avail;
-
- if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END) &&
- zip->entry_bytes_remaining > 0) {
- if ((int64_t)(zip->decrypted_bytes_remaining
- + buff_remaining)
- > zip->entry_bytes_remaining) {
- if (zip->entry_bytes_remaining <
- (int64_t)zip->decrypted_bytes_remaining)
- buff_remaining = 0;
- else
- buff_remaining =
- (size_t)zip->entry_bytes_remaining
- - zip->decrypted_bytes_remaining;
- }
- }
- if (buff_remaining > 0) {
- if (zip->tctx_valid) {
- trad_enc_decrypt_update(&zip->tctx,
- compressed_buff, buff_remaining,
- zip->decrypted_ptr
- + zip->decrypted_bytes_remaining,
- buff_remaining);
- } else {
- size_t dsize = buff_remaining;
- archive_decrypto_aes_ctr_update(
- &zip->cctx,
- compressed_buff, buff_remaining,
- zip->decrypted_ptr
- + zip->decrypted_bytes_remaining,
- &dsize);
- }
- zip->decrypted_bytes_remaining +=
- buff_remaining;
- }
- }
- bytes_avail = zip->decrypted_bytes_remaining;
- compressed_buff = (const char *)zip->decrypted_ptr;
- }
+ zip_read_decrypt(zip, compressed_buff, bytes_avail,
+ &compressed_buff, &bytes_avail, &sp);
/*
* A bug in zlib.h: stream.next_in should be marked 'const'
@@ -2670,22 +2968,12 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
zip->entry_compressed_bytes_read += to_consume;
zip->entry_uncompressed_bytes_read += zip->stream.total_out;
- if (zip->tctx_valid || zip->cctx_valid) {
- zip->decrypted_bytes_remaining -= to_consume;
- if (zip->decrypted_bytes_remaining == 0)
- zip->decrypted_ptr = zip->decrypted_buffer;
- else
- zip->decrypted_ptr += to_consume;
- }
- if (zip->hctx_valid)
- archive_hmac_sha1_update(&zip->hctx, sp, to_consume);
+ zip_read_decrypt_update(zip, to_consume, sp);
- if (zip->end_of_entry) {
- if (zip->hctx_valid) {
- r = check_authentication_code(a, NULL);
- if (r != ARCHIVE_OK) {
- return (r);
- }
+ if (zip->end_of_entry && zip->hctx_valid) {
+ r = check_authentication_code(a, NULL);
+ if (r != ARCHIVE_OK) {
+ return r;
}
}
@@ -2699,7 +2987,7 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
static int
read_decryption_header(struct archive_read *a)
{
- struct zip *zip = (struct zip *)(a->format->data);
+ struct zip *zip = a->format->data;
const char *p;
unsigned int remaining_size;
unsigned int ts;
@@ -2893,7 +3181,7 @@ nomem:
static int
zip_alloc_decryption_buffer(struct archive_read *a)
{
- struct zip *zip = (struct zip *)(a->format->data);
+ struct zip *zip = a->format->data;
size_t bs = 256 * 1024;
if (zip->decrypted_buffer == NULL) {
@@ -2912,7 +3200,7 @@ zip_alloc_decryption_buffer(struct archive_read *a)
static int
init_traditional_PKWARE_decryption(struct archive_read *a)
{
- struct zip *zip = (struct zip *)(a->format->data);
+ struct zip *zip = a->format->data;
const void *p;
int retry;
int r;
@@ -2984,7 +3272,7 @@ init_traditional_PKWARE_decryption(struct archive_read *a)
static int
init_WinZip_AES_decryption(struct archive_read *a)
{
- struct zip *zip = (struct zip *)(a->format->data);
+ struct zip *zip = a->format->data;
const void *p;
const uint8_t *pv;
size_t key_len, salt_len;
@@ -3078,8 +3366,8 @@ static int
archive_read_format_zip_read_data(struct archive_read *a,
const void **buff, size_t *size, int64_t *offset)
{
+ struct zip *zip = a->format->data;
int r;
- struct zip *zip = (struct zip *)(a->format->data);
if (zip->has_encrypted_entries ==
ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
@@ -3157,6 +3445,25 @@ archive_read_format_zip_read_data(struct archive_read *a,
}
if (r != ARCHIVE_OK)
return (r);
+
+ /*
+ * FAIL if there are more uncompressed bytes than were
+ * initially advertised. The end-of-entry check below also
+ * compares these values, but only once decoding reaches its
+ * own natural end. Fail the entry so a caller relying on
+ * archive_entry_size() as a hard boundary is never misled;
+ * later entries in the archive can still be read normally.
+ */
+ if (*size > 0 && zip_entry_size_is_set(zip->entry) &&
+ zip->entry_uncompressed_bytes_read > zip->entry->uncompressed_size) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "ZIP uncompressed data is larger than the declared "
+ "entry size (read at least %jd, expected %jd)",
+ (intmax_t)zip->entry_uncompressed_bytes_read,
+ (intmax_t)zip->entry->uncompressed_size);
+ return (ARCHIVE_FAILED);
+ }
+
if (*size > 0) {
zip->computed_crc32 = zip->crc32func(zip->computed_crc32, *buff,
(unsigned)*size);
@@ -3187,10 +3494,8 @@ archive_read_format_zip_read_data(struct archive_read *a,
(intmax_t)zip->entry->compressed_size);
return (ARCHIVE_FAILED);
}
- /* Size field only stores the lower 32 bits of the actual
- * size. */
- if ((zip->entry->uncompressed_size & UINT32_MAX)
- != (zip->entry_uncompressed_bytes_read & UINT32_MAX)) {
+ if (zip->entry->uncompressed_size !=
+ zip->entry_uncompressed_bytes_read) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"ZIP uncompressed data is wrong size "
"(read %jd, expected %jd)",
@@ -3206,11 +3511,9 @@ archive_read_format_zip_read_data(struct archive_read *a,
static int
archive_read_format_zip_cleanup(struct archive_read *a)
{
- struct zip *zip;
+ struct zip *zip = a->format->data;
struct zip_entry *zip_entry, *next_zip_entry;
- zip = (struct zip *)(a->format->data);
-
#ifdef HAVE_ZLIB_H
if (zip->stream_valid)
inflateEnd(&zip->stream);
@@ -3258,7 +3561,7 @@ archive_read_format_zip_cleanup(struct archive_read *a)
free(zip->v_data);
archive_string_free(&zip->format_name);
free(zip);
- (a->format->data) = NULL;
+ a->format->data = NULL;
return (ARCHIVE_OK);
}
@@ -3266,7 +3569,7 @@ static int
archive_read_format_zip_has_encrypted_entries(struct archive_read *_a)
{
if (_a && _a->format) {
- struct zip * zip = (struct zip *)_a->format->data;
+ struct zip *zip = _a->format->data;
if (zip) {
return zip->has_encrypted_entries;
}
@@ -3278,10 +3581,9 @@ static int
archive_read_format_zip_options(struct archive_read *a,
const char *key, const char *val)
{
- struct zip *zip;
+ struct zip *zip = a->format->data;
int ret = ARCHIVE_FAILED;
- zip = (struct zip *)(a->format->data);
if (strcmp(key, "compat-2x") == 0) {
/* Handle filenames as libarchive 2.x */
zip->init_default_conversion = (val != NULL) ? 1 : 0;
@@ -3388,14 +3690,12 @@ static int
archive_read_format_zip_streamable_read_header(struct archive_read *a,
struct archive_entry *entry)
{
- struct zip *zip;
+ struct zip *zip = a->format->data;
a->archive.archive_format = ARCHIVE_FORMAT_ZIP;
if (a->archive.archive_format_name == NULL)
a->archive.archive_format_name = "ZIP";
- zip = (struct zip *)(a->format->data);
-
/*
* It should be sufficient to call archive_read_next_header() for
* a reader to determine if an entry is encrypted or not. If the
@@ -3481,10 +3781,9 @@ archive_read_format_zip_streamable_read_header(struct archive_read *a,
static int
archive_read_format_zip_read_data_skip_streamable(struct archive_read *a)
{
- struct zip *zip;
+ struct zip *zip = a->format->data;
int64_t bytes_skipped;
- zip = (struct zip *)(a->format->data);
bytes_skipped = __archive_read_consume(a, zip->unconsumed);
zip->unconsumed = 0;
if (bytes_skipped < 0)
@@ -3726,7 +4025,7 @@ read_zip64_eocd(struct archive_read *a, struct zip *zip, const char *p)
static int
archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid)
{
- struct zip *zip = (struct zip *)a->format->data;
+ struct zip *zip = a->format->data;
int64_t file_size, current_offset;
const char *p;
int i, tail;
@@ -3932,7 +4231,6 @@ slurp_central_directory(struct archive_read *a, struct archive_entry* entry,
__archive_rb_tree_init(&zip->tree, &rb_ops);
__archive_rb_tree_init(&zip->tree_rsrc, &rb_rsrc_ops);
- zip->central_directory_entries_total = 0;
while (1) {
struct zip_entry *zip_entry;
size_t filename_length, extra_length, comment_length;
@@ -3961,7 +4259,6 @@ slurp_central_directory(struct archive_read *a, struct archive_entry* entry,
zip_entry->next = zip->zip_entries;
zip_entry->flags |= LA_FROM_CENTRAL_DIRECTORY;
zip->zip_entries = zip_entry;
- zip->central_directory_entries_total++;
/* version = p[4]; */
zip_entry->system = p[5];
@@ -4041,12 +4338,14 @@ slurp_central_directory(struct archive_read *a, struct archive_entry* entry,
r = rsrc_basename(name, filename_length);
if (filename_length >= 9 &&
strncmp("__MACOSX/", name, 9) == 0) {
+ const char *name_end;
+
+ name_end = name + filename_length;
/* If this file is not a resource fork nor
* a directory. We should treat it as a non
* resource fork file to expose it. */
if (name[filename_length-1] != '/' &&
- (r - name < 3 || r[0] != '.' ||
- r[1] != '_')) {
+ (name_end - r < 2 || r[0] != '.' || r[1] != '_')) {
__archive_rb_tree_insert_node(
&zip->tree, &zip_entry->node);
/* Expose its parent directories. */
@@ -4124,7 +4423,7 @@ static int
zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry,
struct zip_entry *rsrc)
{
- struct zip *zip = (struct zip *)a->format->data;
+ struct zip *zip = a->format->data;
unsigned char *metadata, *mp;
int64_t offset = archive_filter_bytes(&a->archive, 0);
size_t remaining_bytes, metadata_bytes;
@@ -4275,7 +4574,7 @@ static int
archive_read_format_zip_seekable_read_header(struct archive_read *a,
struct archive_entry *entry)
{
- struct zip *zip = (struct zip *)a->format->data;
+ struct zip *zip = a->format->data;
struct zip_entry *rsrc;
int64_t offset;
int r, ret = ARCHIVE_OK;
@@ -4355,8 +4654,7 @@ archive_read_format_zip_seekable_read_header(struct archive_read *a,
static int
archive_read_format_zip_read_data_skip_seekable(struct archive_read *a)
{
- struct zip *zip;
- zip = (struct zip *)(a->format->data);
+ struct zip *zip = a->format->data;
zip->unconsumed = 0;
return (ARCHIVE_OK);
diff --git a/contrib/libarchive/libarchive/archive_string.c b/contrib/libarchive/libarchive/archive_string.c
index 4fb96a9fa178..87e21c8d7f2e 100644
--- a/contrib/libarchive/libarchive/archive_string.c
+++ b/contrib/libarchive/libarchive/archive_string.c
@@ -450,6 +450,8 @@ default_iconv_charset(const char *charset) {
return locale_charset();
#elif HAVE_NL_LANGINFO
return nl_langinfo(CODESET);
+#elif defined(__BIONIC__)
+ return "UTF-8";
#else
return "";
#endif
@@ -1372,7 +1374,7 @@ free_sconv_object(struct archive_string_conv *sc)
}
#if defined(_WIN32) && !defined(__CYGWIN__)
-# if defined(WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+# if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
# define GetOEMCP() CP_OEMCP
# endif
@@ -2325,7 +2327,7 @@ best_effort_strncat_in_locale(struct archive_string *as, const void *_p,
remaining = length;
itp = (const uint8_t *)_p;
- while (*itp && remaining > 0) {
+ while (remaining > 0 && *itp) {
if (*itp > 127) {
// Non-ASCII: Substitute with suitable replacement
if (sc->flag & SCONV_TO_UTF8) {
@@ -2340,6 +2342,7 @@ best_effort_strncat_in_locale(struct archive_string *as, const void *_p,
archive_strappend_char(as, *itp);
}
++itp;
+ --remaining;
}
return (return_value);
}
diff --git a/contrib/libarchive/libarchive/archive_time.c b/contrib/libarchive/libarchive/archive_time.c
index 3352c809bd11..bc7708288976 100644
--- a/contrib/libarchive/libarchive/archive_time.c
+++ b/contrib/libarchive/libarchive/archive_time.c
@@ -24,11 +24,20 @@
*/
#include "archive_platform.h"
-#include "archive_private.h"
-#include "archive_time_private.h"
+
+#ifdef HAVE_LIMITS_H
#include <limits.h>
+#endif
+#ifdef HAVE_STDLIB_H
#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
#include <string.h>
+#endif
+
+#include "archive_integer.h"
+#include "archive_private.h"
+#include "archive_time_private.h"
#define NTFS_EPOC_TIME ARCHIVE_LITERAL_ULL(11644473600)
#define NTFS_TICKS ARCHIVE_LITERAL_ULL(10000000)
@@ -149,15 +158,11 @@ unix_to_ntfs(int64_t secs, uint32_t nsecs)
if (secs < -(int64_t)NTFS_EPOC_TIME)
return 0;
- ntfs = secs + NTFS_EPOC_TIME;
-
- if (ntfs > UINT64_MAX / NTFS_TICKS)
- return UINT64_MAX;
-
- ntfs *= NTFS_TICKS;
-
- if (ntfs > UINT64_MAX - nsecs/100)
+ /* (secs + NTFS_EPOC_TIME) * NTFS_TICKS + nsecs / 100 */
+ if (archive_ckd_add_u64(&ntfs, secs, NTFS_EPOC_TIME) ||
+ archive_ckd_mul_u64(&ntfs, ntfs, NTFS_TICKS) ||
+ archive_ckd_add_u64(&ntfs, ntfs, nsecs / 100))
return UINT64_MAX;
- return ntfs + nsecs/100;
+ return ntfs;
}
diff --git a/contrib/libarchive/libarchive/archive_util.3 b/contrib/libarchive/libarchive/archive_util.3
index 3aa508f25aa2..26026d432302 100644
--- a/contrib/libarchive/libarchive/archive_util.3
+++ b/contrib/libarchive/libarchive/archive_util.3
@@ -33,12 +33,15 @@
.Nm archive_errno ,
.Nm archive_error_string ,
.Nm archive_file_count ,
+.Nm archive_filter_bytes ,
.Nm archive_filter_code ,
.Nm archive_filter_count ,
.Nm archive_filter_name ,
.Nm archive_format ,
.Nm archive_format_name ,
-.Nm archive_position ,
+.Nm archive_free ,
+.Nm archive_position_compressed ,
+.Nm archive_position_uncompressed ,
.Nm archive_set_error
.Nd libarchive utility functions
.Sh LIBRARY
@@ -59,6 +62,8 @@ Streaming Archive Library (libarchive, -larchive)
.Fn archive_error_string "struct archive *"
.Ft int
.Fn archive_file_count "struct archive *"
+.Ft int64_t
+.Fn archive_filter_bytes "struct archive *" "int"
.Ft int
.Fn archive_filter_code "struct archive *" "int"
.Ft int
@@ -69,8 +74,12 @@ Streaming Archive Library (libarchive, -larchive)
.Fn archive_format "struct archive *"
.Ft const char *
.Fn archive_format_name "struct archive *"
+.Ft int
+.Fn archive_free "struct archive *"
+.Ft int64_t
+.Fn archive_position_compressed "struct archive *"
.Ft int64_t
-.Fn archive_position "struct archive *" "int"
+.Fn archive_position_uncompressed "struct archive *"
.Ft void
.Fo archive_set_error
.Fa "struct archive *"
@@ -140,13 +149,13 @@ filter 0 is the gunzip filter,
filter 1 is the uudecode filter,
and filter 2 is the pseudo-filter that wraps the archive read functions.
In this case, requesting
-.Fn archive_position a -1
+.Fn archive_filter_bytes a -1
would be a synonym for
-.Fn archive_position a 2
+.Fn archive_filter_bytes a 2
which would return the number of bytes currently read from the archive, while
-.Fn archive_position a 1
+.Fn archive_filter_bytes a 1
would return the number of bytes after uudecoding, and
-.Fn archive_position a 0
+.Fn archive_filter_bytes a 0
would return the number of bytes after decompression.
.It Fn archive_filter_name
Returns a textual name identifying the indicated filter.
@@ -165,16 +174,24 @@ utilize GNU tar extensions and several entries that do not.
These entries will have different format codes.
.It Fn archive_format_name
A textual description of the format of the current entry.
-.It Fn archive_position
+.It Fn archive_free
+Closes the archive if necessary, then releases all resources.
+.It Fn archive_filter_bytes
Returns the number of bytes read from or written to the indicated filter.
In particular,
-.Fn archive_position a 0
+.Fn archive_filter_bytes a 0
returns the number of bytes read or written by the format handler, while
-.Fn archive_position a -1
+.Fn archive_filter_bytes a -1
returns the number of bytes read or written to the archive.
See
.Fn archive_filter_count
for details of the numbering here.
+.It Fn archive_position_compressed
+Synonym for
+.Fn archive_filter_bytes a -1 .
+.It Fn archive_position_uncompressed
+Synonym for
+.Fn archive_filter_bytes a 0 .
.It Fn archive_set_error
Sets the numeric error code and error description that will be returned
by
diff --git a/contrib/libarchive/libarchive/archive_util.c b/contrib/libarchive/libarchive/archive_util.c
index 0d1de1ef2091..5e0b916de432 100644
--- a/contrib/libarchive/libarchive/archive_util.c
+++ b/contrib/libarchive/libarchive/archive_util.c
@@ -42,18 +42,12 @@
#include <string.h>
#endif
#if defined(_WIN32) && !defined(__CYGWIN__)
-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
-/* don't use bcrypt when XP needs to be supported */
#include <bcrypt.h>
/* Common in other bcrypt implementations, but missing from VS2008. */
#ifndef BCRYPT_SUCCESS
#define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS)
#endif
-
-#elif defined(HAVE_WINCRYPT_H)
-#include <wincrypt.h>
-#endif
#endif
#ifdef HAVE_ZLIB_H
#include <zlib.h>
@@ -110,8 +104,7 @@ archive_errno(struct archive *a)
const char *
archive_error_string(struct archive *a)
{
-
- if (a->error != NULL && *a->error != '\0')
+ if (a->error != NULL && *a->error != '\0')
return (a->error);
else
return (NULL);
@@ -250,11 +243,7 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
DWORD attr;
wchar_t *xp, *ep;
int fd;
-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
BCRYPT_ALG_HANDLE hAlg = NULL;
-#else
- HCRYPTPROV hProv = (HCRYPTPROV)NULL;
-#endif
fd = -1;
ws = NULL;
archive_string_init(&temp_name);
@@ -262,22 +251,36 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
if (template == NULL) {
/* Get a temporary directory. */
if (tmpdir == NULL) {
- size_t l;
- wchar_t *tmp;
+ wchar_t buf[MAX_PATH + 1];
+ wchar_t *p = buf, *buf2 = NULL;
+ size_t l, s;
- l = GetTempPathW(0, NULL);
+ s = MAX_PATH + 1;
+ l = GetTempPathW((DWORD)s, buf);
if (l == 0) {
la_dosmaperr(GetLastError());
goto exit_tmpfile;
}
- tmp = malloc(l*sizeof(wchar_t));
- if (tmp == NULL) {
- errno = ENOMEM;
- goto exit_tmpfile;
+ while (l > s) {
+ wchar_t *tmp;
+
+ s = l;
+ tmp = realloc(buf2, s * sizeof(wchar_t));
+ if (tmp == NULL) {
+ free(buf2);
+ errno = ENOMEM;
+ goto exit_tmpfile;
+ }
+ p = buf2 = tmp;
+ l = GetTempPathW((DWORD)s, buf2);
+ if (l == 0) {
+ free(buf2);
+ la_dosmaperr(GetLastError());
+ goto exit_tmpfile;
+ }
}
- GetTempPathW((DWORD)l, tmp);
- archive_wstrcpy(&temp_name, tmp);
- free(tmp);
+ archive_wstrcpy(&temp_name, p);
+ free(buf2);
} else {
if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
strlen(tmpdir)) < 0)
@@ -328,19 +331,11 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
abort();
}
-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM,
NULL, 0))) {
la_dosmaperr(GetLastError());
goto exit_tmpfile;
}
-#else
- if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
- CRYPT_VERIFYCONTEXT)) {
- la_dosmaperr(GetLastError());
- goto exit_tmpfile;
- }
-#endif
for (;;) {
wchar_t *p;
@@ -351,19 +346,11 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
/* Generate a random file name through CryptGenRandom(). */
p = xp;
-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
if (!BCRYPT_SUCCESS(BCryptGenRandom(hAlg, (PUCHAR)p,
(DWORD)(ep - p)*sizeof(wchar_t), 0))) {
la_dosmaperr(GetLastError());
goto exit_tmpfile;
}
-#else
- if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t),
- (BYTE*)p)) {
- la_dosmaperr(GetLastError());
- goto exit_tmpfile;
- }
-#endif
for (; p < ep; p++)
*p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
@@ -417,13 +404,8 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
break;/* success! */
}
exit_tmpfile:
-#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
if (hAlg != NULL)
BCryptCloseAlgorithmProvider(hAlg, 0);
-#else
- if (hProv != (HCRYPTPROV)NULL)
- CryptReleaseContext(hProv, 0);
-#endif
free(ws);
if (template == temp_name.s)
archive_wstring_free(&temp_name);
diff --git a/contrib/libarchive/libarchive/archive_version_details.c b/contrib/libarchive/libarchive/archive_version_details.c
index 9063faa79426..be11aad67e2e 100644
--- a/contrib/libarchive/libarchive/archive_version_details.c
+++ b/contrib/libarchive/libarchive/archive_version_details.c
@@ -158,10 +158,6 @@ archive_crypto_version(struct archive_string* str)
archive_strcat(str, " libmd/");
archive_strcat(str, archive_libmd_version());
#endif
-#if defined(ARCHIVE_CRYPTOR_USE_WINCRYPT)
- archive_strcat(str, " WinCrypt/");
- archive_strcat(str, archive_wincrypt_version());
-#endif
// Just in case
(void)str; /* UNUSED */
}
@@ -180,7 +176,7 @@ archive_version_details(void)
const char *libiconv = archive_libiconv_version();
const char *libacl = archive_libacl_version();
const char *librichacl = archive_librichacl_version();
- const char *libattr = archive_libacl_version();
+ const char *libattr = archive_libattr_version();
if (!init) {
archive_string_init(&str);
@@ -234,6 +230,7 @@ archive_version_details(void)
archive_strcat(&str, " libiconv/");
archive_strcat(&str, libiconv);
}
+ init = 1;
}
return str.s;
}
@@ -431,27 +428,7 @@ archive_cng_version(void)
const char *
archive_wincrypt_version(void)
{
-#if defined(ARCHIVE_CRYPTOR_USE_WINCRYPT) || defined(ARCHIVE_CRYPTO_WINCRYPT)
- HCRYPTPROV prov;
- if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
- if (GetLastError() != (DWORD)NTE_BAD_KEYSET)
- return NULL;
- if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET))
- return NULL;
- }
- DWORD version, length = sizeof(version);
- if (!CryptGetProvParam(prov, PP_VERSION, (BYTE *)&version, &length, 0)) {
- return NULL;
- } else {
- char major = (version >> 8) & 0xFF;
- char minor = version & 0xFF;
- static char wincrypt_version[6];
- snprintf(wincrypt_version, 6, "%hhd.%hhd", major, minor);
- return wincrypt_version;
- }
-#else
return NULL;
-#endif
}
const char *
diff --git a/contrib/libarchive/libarchive/archive_write.c b/contrib/libarchive/libarchive/archive_write.c
index 14dc7339ec5a..e1a3ffebb1ea 100644
--- a/contrib/libarchive/libarchive/archive_write.c
+++ b/contrib/libarchive/libarchive/archive_write.c
@@ -69,7 +69,7 @@ static int _archive_write_header(struct archive *, struct archive_entry *);
static int _archive_write_finish_entry(struct archive *);
static ssize_t _archive_write_data(struct archive *, const void *, size_t);
-struct archive_none {
+struct client {
size_t buffer_size;
size_t avail;
char *buffer;
@@ -135,7 +135,7 @@ archive_write_set_bytes_per_block(struct archive *_a, int bytes_per_block)
if (bytes_per_block < 0) {
// Do nothing if the bytes_per_block is negative
- return 0;
+ return ARCHIVE_OK;
}
a->bytes_per_block = bytes_per_block;
return (ARCHIVE_OK);
@@ -240,8 +240,10 @@ __archive_write_filter(struct archive_write_filter *f,
/* If unset, a fatal error has already occurred, so this filter
* didn't open. We cannot write anything. */
return(ARCHIVE_FATAL);
+ if (length > (uint64_t)(INT64_MAX - f->bytes_written))
+ return(ARCHIVE_FATAL);
r = (f->write)(f, buff, length);
- f->bytes_written += length;
+ f->bytes_written += (int64_t)length;
return (r);
}
@@ -338,7 +340,7 @@ __archive_write_filters_flush(struct archive_write *a)
}
int
-__archive_write_nulls(struct archive_write *a, size_t length)
+__archive_write_nulls(struct archive_write *a, uint64_t length)
{
if (length == 0)
return (ARCHIVE_OK);
@@ -357,7 +359,7 @@ static int
archive_write_client_open(struct archive_write_filter *f)
{
struct archive_write *a = (struct archive_write *)f->archive;
- struct archive_none *state;
+ struct client *client;
void *buffer;
size_t buffer_size;
@@ -366,21 +368,21 @@ archive_write_client_open(struct archive_write_filter *f)
archive_write_get_bytes_in_last_block(f->archive);
buffer_size = f->bytes_per_block;
- state = calloc(1, sizeof(*state));
+ client = calloc(1, sizeof(*client));
buffer = malloc(buffer_size);
- if (state == NULL || buffer == NULL) {
- free(state);
+ if (client == NULL || buffer == NULL) {
+ free(client);
free(buffer);
archive_set_error(f->archive, ENOMEM,
"Can't allocate data for output buffering");
return (ARCHIVE_FATAL);
}
- state->buffer_size = buffer_size;
- state->buffer = buffer;
- state->next = state->buffer;
- state->avail = state->buffer_size;
- f->data = state;
+ client->buffer_size = buffer_size;
+ client->buffer = buffer;
+ client->next = client->buffer;
+ client->avail = client->buffer_size;
+ f->data = client;
if (a->client_opener == NULL)
return (ARCHIVE_OK);
@@ -392,7 +394,7 @@ archive_write_client_write(struct archive_write_filter *f,
const void *_buff, size_t length)
{
struct archive_write *a = (struct archive_write *)f->archive;
- struct archive_none *state = (struct archive_none *)f->data;
+ struct client *client = f->data;
const char *buff = (const char *)_buff;
ssize_t remaining, to_copy;
ssize_t bytes_written;
@@ -405,7 +407,7 @@ archive_write_client_write(struct archive_write_filter *f,
* particular, this supports "no write delay" operation for
* special applications. Just set the block size to zero.
*/
- if (state->buffer_size == 0) {
+ if (client->buffer_size == 0) {
while (remaining > 0) {
bytes_written = (a->client_writer)(&a->archive,
a->client_data, buff, remaining);
@@ -418,20 +420,20 @@ archive_write_client_write(struct archive_write_filter *f,
}
/* If the copy buffer isn't empty, try to fill it. */
- if (state->avail < state->buffer_size) {
+ if (client->avail < client->buffer_size) {
/* If buffer is not empty... */
/* ... copy data into buffer ... */
- to_copy = ((size_t)remaining > state->avail) ?
- state->avail : (size_t)remaining;
- memcpy(state->next, buff, to_copy);
- state->next += to_copy;
- state->avail -= to_copy;
+ to_copy = ((size_t)remaining > client->avail) ?
+ client->avail : (size_t)remaining;
+ memcpy(client->next, buff, to_copy);
+ client->next += to_copy;
+ client->avail -= to_copy;
buff += to_copy;
remaining -= to_copy;
/* ... if it's full, write it out. */
- if (state->avail == 0) {
- char *p = state->buffer;
- size_t to_write = state->buffer_size;
+ if (client->avail == 0) {
+ char *p = client->buffer;
+ size_t to_write = client->buffer_size;
while (to_write > 0) {
bytes_written = (a->client_writer)(&a->archive,
a->client_data, p, to_write);
@@ -445,15 +447,15 @@ archive_write_client_write(struct archive_write_filter *f,
p += bytes_written;
to_write -= bytes_written;
}
- state->next = state->buffer;
- state->avail = state->buffer_size;
+ client->next = client->buffer;
+ client->avail = client->buffer_size;
}
}
- while ((size_t)remaining >= state->buffer_size) {
+ while ((size_t)remaining >= client->buffer_size) {
/* Write out full blocks directly to client. */
bytes_written = (a->client_writer)(&a->archive,
- a->client_data, buff, state->buffer_size);
+ a->client_data, buff, client->buffer_size);
if (bytes_written <= 0)
return (ARCHIVE_FATAL);
buff += bytes_written;
@@ -462,9 +464,9 @@ archive_write_client_write(struct archive_write_filter *f,
if (remaining > 0) {
/* Copy last bit into copy buffer. */
- memcpy(state->next, buff, remaining);
- state->next += remaining;
- state->avail -= remaining;
+ memcpy(client->next, buff, remaining);
+ client->next += remaining;
+ client->avail -= remaining;
}
return (ARCHIVE_OK);
}
@@ -473,7 +475,7 @@ static int
archive_write_client_free(struct archive_write_filter *f)
{
struct archive_write *a = (struct archive_write *)f->archive;
- struct archive_none *state = (struct archive_none *)f->data;
+ struct client *client = f->data;
if (a->client_freer)
(*a->client_freer)(&a->archive, a->client_data);
@@ -487,9 +489,9 @@ archive_write_client_free(struct archive_write_filter *f)
}
/* Free state. */
- if (state != NULL) {
- free(state->buffer);
- free(state);
+ if (client != NULL) {
+ free(client->buffer);
+ free(client);
f->data = NULL;
}
@@ -500,7 +502,7 @@ static int
archive_write_client_close(struct archive_write_filter *f)
{
struct archive_write *a = (struct archive_write *)f->archive;
- struct archive_none *state = (struct archive_none *)f->data;
+ struct client *client = f->data;
ssize_t block_length;
ssize_t target_block_length;
ssize_t bytes_written;
@@ -509,8 +511,8 @@ archive_write_client_close(struct archive_write_filter *f)
int ret = ARCHIVE_OK;
/* If there's pending data, pad and write the last block */
- if (state->next != state->buffer) {
- block_length = state->buffer_size - state->avail;
+ if (client->next != client->buffer) {
+ block_length = client->buffer_size - client->avail;
/* Tricky calculation to determine size of last block */
if (a->bytes_in_last_block <= 0)
@@ -524,11 +526,11 @@ archive_write_client_close(struct archive_write_filter *f)
if (target_block_length > a->bytes_per_block)
target_block_length = a->bytes_per_block;
if (block_length < target_block_length) {
- memset(state->next, 0,
+ memset(client->next, 0,
target_block_length - block_length);
block_length = target_block_length;
}
- p = state->buffer;
+ p = client->buffer;
to_write = block_length;
while (to_write > 0) {
bytes_written = (a->client_writer)(&a->archive,
@@ -683,6 +685,29 @@ __archive_write_filters_free(struct archive *_a)
a->filter_last = NULL;
}
+int
+__archive_write_unregister_format(struct archive_write *a)
+{
+ int r = ARCHIVE_OK;
+
+ if (a->format_free != NULL)
+ r = (a->format_free)(a);
+
+ a->format_data = NULL;
+ a->format_name = NULL;
+ a->format_init = NULL;
+ a->format_options = NULL;
+ a->format_finish_entry = NULL;
+ a->format_write_header = NULL;
+ a->format_write_data = NULL;
+ a->format_close = NULL;
+ a->format_free = NULL;
+ a->archive.archive_format = 0;
+ a->archive.archive_format_name = NULL;
+
+ return (r);
+}
+
/*
* Destroy the archive structure.
*
@@ -705,11 +730,9 @@ _archive_write_free(struct archive *_a)
r = archive_write_close(&a->archive);
/* Release format resources. */
- if (a->format_free != NULL) {
- r1 = (a->format_free)(a);
- if (r1 < r)
- r = r1;
- }
+ r1 = __archive_write_unregister_format(a);
+ if (r1 < r)
+ r = r1;
__archive_write_filters_free(_a);
@@ -761,7 +784,7 @@ _archive_write_header(struct archive *_a, struct archive_entry *entry)
archive_entry_ino_is_set(entry) &&
archive_entry_dev(entry) == (dev_t)a->skip_file_dev &&
archive_entry_ino64(entry) == a->skip_file_ino) {
- archive_set_error(&a->archive, 0,
+ archive_set_error(&a->archive, EIO,
"Can't add archive to itself");
return (ARCHIVE_FAILED);
}
diff --git a/contrib/libarchive/libarchive/archive_write_add_filter.c b/contrib/libarchive/libarchive/archive_write_add_filter.c
index aa962515a044..ddcf2825385a 100644
--- a/contrib/libarchive/libarchive/archive_write_add_filter.c
+++ b/contrib/libarchive/libarchive/archive_write_add_filter.c
@@ -49,7 +49,7 @@ struct { int code; int (*setter)(struct archive *); } codes[] =
{ ARCHIVE_FILTER_LZ4, archive_write_add_filter_lz4 },
{ ARCHIVE_FILTER_LZIP, archive_write_add_filter_lzip },
{ ARCHIVE_FILTER_LZMA, archive_write_add_filter_lzma },
- { ARCHIVE_FILTER_LZOP, archive_write_add_filter_lzip },
+ { ARCHIVE_FILTER_LZOP, archive_write_add_filter_lzop },
{ ARCHIVE_FILTER_UU, archive_write_add_filter_uuencode },
{ ARCHIVE_FILTER_XZ, archive_write_add_filter_xz },
{ ARCHIVE_FILTER_ZSTD, archive_write_add_filter_zstd },
diff --git a/contrib/libarchive/libarchive/archive_write_add_filter_b64encode.c b/contrib/libarchive/libarchive/archive_write_add_filter_b64encode.c
index d2c4742d2ef6..a285a54d48eb 100644
--- a/contrib/libarchive/libarchive/archive_write_add_filter_b64encode.c
+++ b/contrib/libarchive/libarchive/archive_write_add_filter_b64encode.c
@@ -39,13 +39,14 @@
#endif
#include "archive.h"
+#include "archive_integer.h"
#include "archive_private.h"
#include "archive_string.h"
#include "archive_write_private.h"
#define LBYTES 57
-struct private_b64encode {
+struct b64encode {
int mode;
struct archive_string name;
struct archive_string encoded_buff;
@@ -63,6 +64,7 @@ static int archive_filter_b64encode_close(struct archive_write_filter *);
static int archive_filter_b64encode_free(struct archive_write_filter *);
static void la_b64_encode(struct archive_string *, const unsigned char *, size_t);
static int64_t atol8(const char *, size_t);
+static void free_data(struct b64encode *);
static const char base64[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
@@ -79,34 +81,38 @@ static const char base64[] = {
* Add a compress filter to this write handle.
*/
int
-archive_write_add_filter_b64encode(struct archive *_a)
+archive_write_add_filter_b64encode(struct archive *a)
{
- struct archive_write *a = (struct archive_write *)_a;
- struct archive_write_filter *f = __archive_write_allocate_filter(_a);
- struct private_b64encode *state;
+ struct archive_write_filter *f;
+ struct b64encode *b64encode;
- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_add_filter_b64encode");
- state = calloc(1, sizeof(*state));
- if (state == NULL) {
- archive_set_error(f->archive, ENOMEM,
- "Can't allocate data for b64encode filter");
- return (ARCHIVE_FATAL);
- }
- archive_strcpy(&state->name, "-");
- state->mode = 0644;
+ b64encode = calloc(1, sizeof(*b64encode));
+ if (b64encode == NULL)
+ goto memerr;
+ archive_strcpy(&b64encode->name, "-");
+ b64encode->mode = 0644;
- f->data = state;
+ f = __archive_write_allocate_filter(a);
+ if (f == NULL)
+ goto memerr;
f->name = "b64encode";
f->code = ARCHIVE_FILTER_UU;
- f->open = archive_filter_b64encode_open;
+ f->data = b64encode;
f->options = archive_filter_b64encode_options;
+ f->open = archive_filter_b64encode_open;
f->write = archive_filter_b64encode_write;
f->close = archive_filter_b64encode_close;
f->free = archive_filter_b64encode_free;
return (ARCHIVE_OK);
+memerr:
+ free_data(b64encode);
+ archive_set_error(a, ENOMEM,
+ "Can't allocate data for b64encode filter");
+ return (ARCHIVE_FATAL);
}
/*
@@ -116,7 +122,7 @@ static int
archive_filter_b64encode_options(struct archive_write_filter *f, const char *key,
const char *value)
{
- struct private_b64encode *state = (struct private_b64encode *)f->data;
+ struct b64encode *b64encode = f->data;
if (strcmp(key, "mode") == 0) {
int64_t val;
@@ -132,7 +138,7 @@ archive_filter_b64encode_options(struct archive_write_filter *f, const char *key
"invalid mode option");
return (ARCHIVE_FAILED);
}
- state->mode = (int)val & 0777;
+ b64encode->mode = (int)val & 0777;
return (ARCHIVE_OK);
} else if (strcmp(key, "name") == 0) {
if (value == NULL) {
@@ -140,7 +146,7 @@ archive_filter_b64encode_options(struct archive_write_filter *f, const char *key
"name option requires a string");
return (ARCHIVE_FAILED);
}
- archive_strcpy(&state->name, value);
+ archive_strcpy(&b64encode->name, value);
return (ARCHIVE_OK);
}
@@ -156,7 +162,7 @@ archive_filter_b64encode_options(struct archive_write_filter *f, const char *key
static int
archive_filter_b64encode_open(struct archive_write_filter *f)
{
- struct private_b64encode *state = (struct private_b64encode *)f->data;
+ struct b64encode *b64encode = f->data;
size_t bs = 65536, bpb;
if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
@@ -169,18 +175,17 @@ archive_filter_b64encode_open(struct archive_write_filter *f)
bs -= bs % bpb;
}
- state->bs = bs;
- if (archive_string_ensure(&state->encoded_buff, bs + 512) == NULL) {
+ b64encode->bs = bs;
+ if (archive_string_ensure(&b64encode->encoded_buff, bs + 512) == NULL) {
archive_set_error(f->archive, ENOMEM,
"Can't allocate data for b64encode buffer");
return (ARCHIVE_FATAL);
}
- archive_string_sprintf(&state->encoded_buff, "begin-base64 %o %s\n",
- (unsigned int)state->mode, state->name.s);
+ archive_string_sprintf(&b64encode->encoded_buff, "begin-base64 %o %s\n",
+ (unsigned int)b64encode->mode, b64encode->name.s);
- f->data = state;
- return (0);
+ return (ARCHIVE_OK);
}
static void
@@ -224,39 +229,39 @@ static int
archive_filter_b64encode_write(struct archive_write_filter *f, const void *buff,
size_t length)
{
- struct private_b64encode *state = (struct private_b64encode *)f->data;
+ struct b64encode *b64encode = f->data;
const unsigned char *p = buff;
int ret = ARCHIVE_OK;
if (length == 0)
return (ret);
- if (state->hold_len) {
- while (state->hold_len < LBYTES && length > 0) {
- state->hold[state->hold_len++] = *p++;
+ if (b64encode->hold_len) {
+ while (b64encode->hold_len < LBYTES && length > 0) {
+ b64encode->hold[b64encode->hold_len++] = *p++;
length--;
}
- if (state->hold_len < LBYTES)
+ if (b64encode->hold_len < LBYTES)
return (ret);
- la_b64_encode(&state->encoded_buff, state->hold, LBYTES);
- state->hold_len = 0;
+ la_b64_encode(&b64encode->encoded_buff, b64encode->hold, LBYTES);
+ b64encode->hold_len = 0;
}
for (; length >= LBYTES; length -= LBYTES, p += LBYTES)
- la_b64_encode(&state->encoded_buff, p, LBYTES);
+ la_b64_encode(&b64encode->encoded_buff, p, LBYTES);
/* Save remaining bytes. */
if (length > 0) {
- memcpy(state->hold, p, length);
- state->hold_len = length;
+ memcpy(b64encode->hold, p, length);
+ b64encode->hold_len = length;
}
- while (archive_strlen(&state->encoded_buff) >= state->bs) {
+ while (archive_strlen(&b64encode->encoded_buff) >= b64encode->bs) {
ret = __archive_write_filter(f->next_filter,
- state->encoded_buff.s, state->bs);
- memmove(state->encoded_buff.s,
- state->encoded_buff.s + state->bs,
- state->encoded_buff.length - state->bs);
- state->encoded_buff.length -= state->bs;
+ b64encode->encoded_buff.s, b64encode->bs);
+ memmove(b64encode->encoded_buff.s,
+ b64encode->encoded_buff.s + b64encode->bs,
+ b64encode->encoded_buff.length - b64encode->bs);
+ b64encode->encoded_buff.length -= b64encode->bs;
}
return (ret);
@@ -269,26 +274,24 @@ archive_filter_b64encode_write(struct archive_write_filter *f, const void *buff,
static int
archive_filter_b64encode_close(struct archive_write_filter *f)
{
- struct private_b64encode *state = (struct private_b64encode *)f->data;
+ struct b64encode *b64encode = f->data;
/* Flush remaining bytes. */
- if (state->hold_len != 0)
- la_b64_encode(&state->encoded_buff, state->hold, state->hold_len);
- archive_string_sprintf(&state->encoded_buff, "====\n");
+ if (b64encode->hold_len != 0)
+ la_b64_encode(&b64encode->encoded_buff, b64encode->hold,
+ b64encode->hold_len);
+ archive_string_sprintf(&b64encode->encoded_buff, "====\n");
/* Write the last block */
archive_write_set_bytes_in_last_block(f->archive, 1);
return __archive_write_filter(f->next_filter,
- state->encoded_buff.s, archive_strlen(&state->encoded_buff));
+ b64encode->encoded_buff.s, archive_strlen(&b64encode->encoded_buff));
}
static int
archive_filter_b64encode_free(struct archive_write_filter *f)
{
- struct private_b64encode *state = (struct private_b64encode *)f->data;
-
- archive_string_free(&state->name);
- archive_string_free(&state->encoded_buff);
- free(state);
+ free_data(f->data);
+ f->data = NULL;
return (ARCHIVE_OK);
}
@@ -308,11 +311,19 @@ atol8(const char *p, size_t char_cnt)
else
return (-1);
p++;
- if (l > (INT64_MAX >> 3))
+ if (archive_ckd_mul_i64(&l, l, 8) ||
+ archive_ckd_add_i64(&l, l, digit))
return (-1);
- l <<= 3;
- l |= digit;
}
return (l);
}
+static void
+free_data(struct b64encode *b64encode)
+{
+ if (b64encode != NULL) {
+ archive_string_free(&b64encode->name);
+ archive_string_free(&b64encode->encoded_buff);
+ free(b64encode);
+ }
+}
diff --git a/contrib/libarchive/libarchive/archive_write_add_filter_bzip2.c b/contrib/libarchive/libarchive/archive_write_add_filter_bzip2.c
index 94b342d41b74..53908783a363 100644
--- a/contrib/libarchive/libarchive/archive_write_add_filter_bzip2.c
+++ b/contrib/libarchive/libarchive/archive_write_add_filter_bzip2.c
@@ -53,11 +53,10 @@ archive_write_set_compression_bzip2(struct archive *a)
}
#endif
-struct private_data {
+struct bzip2 {
int compression_level;
#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
bz_stream stream;
- int64_t total_in;
char *compressed;
size_t compressed_buffer_size;
#else
@@ -72,48 +71,64 @@ static int archive_compressor_bzip2_options(struct archive_write_filter *,
const char *, const char *);
static int archive_compressor_bzip2_write(struct archive_write_filter *,
const void *, size_t);
+static void free_data(struct bzip2 *);
/*
* Add a bzip2 compression filter to this write handle.
*/
int
-archive_write_add_filter_bzip2(struct archive *_a)
+archive_write_add_filter_bzip2(struct archive *a)
{
- struct archive_write *a = (struct archive_write *)_a;
- struct archive_write_filter *f = __archive_write_allocate_filter(_a);
- struct private_data *data;
+ struct archive_write_filter *f;
+ struct bzip2 *bzip2;
+ int r;
- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_add_filter_bzip2");
- data = calloc(1, sizeof(*data));
- if (data == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- data->compression_level = 9; /* default */
-
- f->data = data;
- f->options = &archive_compressor_bzip2_options;
- f->close = &archive_compressor_bzip2_close;
- f->free = &archive_compressor_bzip2_free;
- f->open = &archive_compressor_bzip2_open;
- f->code = ARCHIVE_FILTER_BZIP2;
- f->name = "bzip2";
+ bzip2 = calloc(1, sizeof(*bzip2));
+ if (bzip2 == NULL)
+ goto memerr;
#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
- return (ARCHIVE_OK);
+ bzip2->compression_level = 9;
+
+ r = ARCHIVE_OK;
#else
- data->pdata = __archive_write_program_allocate("bzip2");
- if (data->pdata == NULL) {
- free(data);
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- data->compression_level = 0;
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ bzip2->pdata = __archive_write_program_allocate("bzip2");
+ if (bzip2->pdata == NULL)
+ goto memerr;
+ bzip2->compression_level = 0;
+
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
"Using external bzip2 program");
- return (ARCHIVE_WARN);
+ r = ARCHIVE_WARN;
#endif
+
+ f = __archive_write_allocate_filter(a);
+ if (f == NULL)
+ goto memerr;
+ f->name = "bzip2";
+ f->code = ARCHIVE_FILTER_BZIP2;
+ f->data = bzip2;
+ f->options = archive_compressor_bzip2_options;
+ f->open = archive_compressor_bzip2_open;
+ f->write = archive_compressor_bzip2_write;
+ f->close = archive_compressor_bzip2_close;
+ f->free = archive_compressor_bzip2_free;
+
+ return (r);
+memerr:
+ free_data(bzip2);
+ archive_set_error(a, ENOMEM, "Out of memory");
+ return (ARCHIVE_FATAL);
+}
+
+static int
+archive_compressor_bzip2_free(struct archive_write_filter *f)
+{
+ free_data(f->data);
+ f->data = NULL;
+ return (ARCHIVE_OK);
}
/*
@@ -123,7 +138,7 @@ static int
archive_compressor_bzip2_options(struct archive_write_filter *f,
const char *key, const char *value)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct bzip2 *bzip2 = f->data;
if (strcmp(key, "compression-level") == 0) {
if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
@@ -132,12 +147,12 @@ archive_compressor_bzip2_options(struct archive_write_filter *f,
"compression-level invalid");
return (ARCHIVE_FAILED);
}
- data->compression_level = value[0] - '0';
+ bzip2->compression_level = value[0] - '0';
/* Make '0' be a synonym for '1'. */
/* This way, bzip2 compressor supports the same 0..9
* range of levels as gzip. */
- if (data->compression_level < 1)
- data->compression_level = 1;
+ if (bzip2->compression_level < 1)
+ bzip2->compression_level = 1;
return (ARCHIVE_OK);
}
@@ -157,7 +172,7 @@ archive_compressor_bzip2_options(struct archive_write_filter *f,
#define SET_NEXT_IN(st,src) \
(st)->stream.next_in = (char *)(uintptr_t)(const void *)(src)
static int drive_compressor(struct archive_write_filter *,
- struct private_data *, int finishing);
+ struct bzip2 *, int finishing);
/*
* Setup callback.
@@ -165,10 +180,10 @@ static int drive_compressor(struct archive_write_filter *,
static int
archive_compressor_bzip2_open(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct bzip2 *bzip2 = f->data;
int ret;
- if (data->compressed == NULL) {
+ if (bzip2->compressed == NULL) {
size_t bs = 65536, bpb;
if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
/* Buffer size should be a multiple number of the bytes
@@ -179,25 +194,23 @@ archive_compressor_bzip2_open(struct archive_write_filter *f)
else if (bpb != 0)
bs -= bs % bpb;
}
- data->compressed_buffer_size = bs;
- data->compressed = malloc(data->compressed_buffer_size);
- if (data->compressed == NULL) {
+ bzip2->compressed_buffer_size = bs;
+ bzip2->compressed = malloc(bzip2->compressed_buffer_size);
+ if (bzip2->compressed == NULL) {
archive_set_error(f->archive, ENOMEM,
"Can't allocate data for compression buffer");
return (ARCHIVE_FATAL);
}
}
- memset(&data->stream, 0, sizeof(data->stream));
- data->stream.next_out = data->compressed;
- data->stream.avail_out = (uint32_t)data->compressed_buffer_size;
- f->write = archive_compressor_bzip2_write;
+ memset(&bzip2->stream, 0, sizeof(bzip2->stream));
+ bzip2->stream.next_out = bzip2->compressed;
+ bzip2->stream.avail_out = (uint32_t)bzip2->compressed_buffer_size;
/* Initialize compression library */
- ret = BZ2_bzCompressInit(&(data->stream),
- data->compression_level, 0, 30);
+ ret = BZ2_bzCompressInit(&(bzip2->stream),
+ bzip2->compression_level, 0, 30);
if (ret == BZ_OK) {
- f->data = data;
return (ARCHIVE_OK);
}
@@ -237,15 +250,12 @@ static int
archive_compressor_bzip2_write(struct archive_write_filter *f,
const void *buff, size_t length)
{
- struct private_data *data = (struct private_data *)f->data;
-
- /* Update statistics */
- data->total_in += length;
+ struct bzip2 *bzip2 = f->data;
/* Compress input data to output buffer */
- SET_NEXT_IN(data, buff);
- data->stream.avail_in = (uint32_t)length;
- if (drive_compressor(f, data, 0))
+ SET_NEXT_IN(bzip2, buff);
+ bzip2->stream.avail_in = (uint32_t)length;
+ if (drive_compressor(f, bzip2, 0))
return (ARCHIVE_FATAL);
return (ARCHIVE_OK);
}
@@ -257,19 +267,19 @@ archive_compressor_bzip2_write(struct archive_write_filter *f,
static int
archive_compressor_bzip2_close(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct bzip2 *bzip2 = f->data;
int ret;
/* Finish compression cycle. */
- ret = drive_compressor(f, data, 1);
+ ret = drive_compressor(f, bzip2, 1);
if (ret == ARCHIVE_OK) {
/* Write the last block */
ret = __archive_write_filter(f->next_filter,
- data->compressed,
- data->compressed_buffer_size - data->stream.avail_out);
+ bzip2->compressed,
+ bzip2->compressed_buffer_size - bzip2->stream.avail_out);
}
- switch (BZ2_bzCompressEnd(&(data->stream))) {
+ switch (BZ2_bzCompressEnd(&(bzip2->stream))) {
case BZ_OK:
break;
default:
@@ -280,20 +290,6 @@ archive_compressor_bzip2_close(struct archive_write_filter *f)
return ret;
}
-static int
-archive_compressor_bzip2_free(struct archive_write_filter *f)
-{
- struct private_data *data = (struct private_data *)f->data;
-
- /* May already have been called, but not necessarily. */
- (void)BZ2_bzCompressEnd(&(data->stream));
-
- free(data->compressed);
- free(data);
- f->data = NULL;
- return (ARCHIVE_OK);
-}
-
/*
* Utility function to push input data through compressor, writing
* full output blocks as necessary.
@@ -303,35 +299,35 @@ archive_compressor_bzip2_free(struct archive_write_filter *f)
*/
static int
drive_compressor(struct archive_write_filter *f,
- struct private_data *data, int finishing)
+ struct bzip2 *bzip2, int finishing)
{
int ret;
for (;;) {
- if (data->stream.avail_out == 0) {
+ if (bzip2->stream.avail_out == 0) {
ret = __archive_write_filter(f->next_filter,
- data->compressed,
- data->compressed_buffer_size);
+ bzip2->compressed,
+ bzip2->compressed_buffer_size);
if (ret != ARCHIVE_OK) {
/* TODO: Handle this write failure */
return (ARCHIVE_FATAL);
}
- data->stream.next_out = data->compressed;
- data->stream.avail_out = (uint32_t)data->compressed_buffer_size;
+ bzip2->stream.next_out = bzip2->compressed;
+ bzip2->stream.avail_out = (uint32_t)bzip2->compressed_buffer_size;
}
/* If there's nothing to do, we're done. */
- if (!finishing && data->stream.avail_in == 0)
+ if (!finishing && bzip2->stream.avail_in == 0)
return (ARCHIVE_OK);
- ret = BZ2_bzCompress(&(data->stream),
+ ret = BZ2_bzCompress(&(bzip2->stream),
finishing ? BZ_FINISH : BZ_RUN);
switch (ret) {
case BZ_RUN_OK:
/* In non-finishing case, did compressor
* consume everything? */
- if (!finishing && data->stream.avail_in == 0)
+ if (!finishing && bzip2->stream.avail_in == 0)
return (ARCHIVE_OK);
break;
case BZ_FINISH_OK: /* Finishing: There's more work to do */
@@ -351,12 +347,24 @@ drive_compressor(struct archive_write_filter *f,
}
}
+static void
+free_data(struct bzip2 *bzip2)
+{
+ if (bzip2 != NULL) {
+ /* May already have been called, but not necessarily. */
+ (void)BZ2_bzCompressEnd(&(bzip2->stream));
+
+ free(bzip2->compressed);
+ free(bzip2);
+ }
+}
+
#else /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */
static int
archive_compressor_bzip2_open(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct bzip2 *bzip2 = f->data;
struct archive_string as;
int r;
@@ -364,13 +372,12 @@ archive_compressor_bzip2_open(struct archive_write_filter *f)
archive_strcpy(&as, "bzip2");
/* Specify compression level. */
- if (data->compression_level > 0) {
+ if (bzip2->compression_level > 0) {
archive_strcat(&as, " -");
- archive_strappend_char(&as, '0' + data->compression_level);
+ archive_strappend_char(&as, '0' + bzip2->compression_level);
}
- f->write = archive_compressor_bzip2_write;
- r = __archive_write_program_open(f, data->pdata, as.s);
+ r = __archive_write_program_open(f, bzip2->pdata, as.s);
archive_string_free(&as);
return (r);
}
@@ -379,27 +386,26 @@ static int
archive_compressor_bzip2_write(struct archive_write_filter *f, const void *buff,
size_t length)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct bzip2 *bzip2 = f->data;
- return __archive_write_program_write(f, data->pdata, buff, length);
+ return __archive_write_program_write(f, bzip2->pdata, buff, length);
}
static int
archive_compressor_bzip2_close(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct bzip2 *bzip2 = f->data;
- return __archive_write_program_close(f, data->pdata);
+ return __archive_write_program_close(f, bzip2->pdata);
}
-static int
-archive_compressor_bzip2_free(struct archive_write_filter *f)
+static void
+free_data(struct bzip2 *bzip2)
{
- struct private_data *data = (struct private_data *)f->data;
-
- __archive_write_program_free(data->pdata);
- free(data);
- return (ARCHIVE_OK);
+ if (bzip2 != NULL) {
+ __archive_write_program_free(bzip2->pdata);
+ free(bzip2);
+ }
}
#endif /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */
diff --git a/contrib/libarchive/libarchive/archive_write_add_filter_compress.c b/contrib/libarchive/libarchive/archive_write_add_filter_compress.c
index a54a85754293..f8824204933c 100644
--- a/contrib/libarchive/libarchive/archive_write_add_filter_compress.c
+++ b/contrib/libarchive/libarchive/archive_write_add_filter_compress.c
@@ -85,7 +85,7 @@
#define FIRST 257 /* First free entry. */
#define CLEAR 256 /* Table clear output code. */
-struct private_data {
+struct compress {
int64_t in_count, out_count, checkpoint;
int code_len; /* Number of bits/code. */
@@ -111,6 +111,7 @@ static int archive_compressor_compress_write(struct archive_write_filter *,
const void *, size_t);
static int archive_compressor_compress_close(struct archive_write_filter *);
static int archive_compressor_compress_free(struct archive_write_filter *);
+static void free_data(struct compress *);
#if ARCHIVE_VERSION_NUMBER < 4000000
int
@@ -125,17 +126,35 @@ archive_write_set_compression_compress(struct archive *a)
* Add a compress filter to this write handle.
*/
int
-archive_write_add_filter_compress(struct archive *_a)
+archive_write_add_filter_compress(struct archive *a)
{
- struct archive_write *a = (struct archive_write *)_a;
- struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+ struct archive_write_filter *f;
+ struct compress *compress;
- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_add_filter_compress");
- f->open = &archive_compressor_compress_open;
- f->code = ARCHIVE_FILTER_COMPRESS;
+
+ compress = calloc(1, sizeof(*compress));
+ if (compress == NULL)
+ goto memerr;
+
+ f = __archive_write_allocate_filter(a);
+ if (f == NULL)
+ goto memerr;
f->name = "compress";
+ f->code = ARCHIVE_FILTER_COMPRESS;
+ f->data = compress;
+ f->open = archive_compressor_compress_open;
+ f->write = archive_compressor_compress_write;
+ f->close = archive_compressor_compress_close;
+ f->free = archive_compressor_compress_free;
+
return (ARCHIVE_OK);
+memerr:
+ free_data(compress);
+ archive_set_error(a, ENOMEM,
+ "Can't allocate data for compression");
+ return (ARCHIVE_FATAL);
}
/*
@@ -144,19 +163,9 @@ archive_write_add_filter_compress(struct archive *_a)
static int
archive_compressor_compress_open(struct archive_write_filter *f)
{
- struct private_data *state;
+ struct compress *compress = f->data;
size_t bs = 65536, bpb;
- f->code = ARCHIVE_FILTER_COMPRESS;
- f->name = "compress";
-
- state = calloc(1, sizeof(*state));
- if (state == NULL) {
- archive_set_error(f->archive, ENOMEM,
- "Can't allocate data for compression");
- return (ARCHIVE_FATAL);
- }
-
if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
/* Buffer size should be a multiple number of the bytes
* per block for performance. */
@@ -166,41 +175,38 @@ archive_compressor_compress_open(struct archive_write_filter *f)
else if (bpb != 0)
bs -= bs % bpb;
}
- state->compressed_buffer_size = bs;
- state->compressed = malloc(state->compressed_buffer_size);
+ compress->compressed_buffer_size = bs;
+ compress->compressed = malloc(compress->compressed_buffer_size);
- if (state->compressed == NULL) {
+ if (compress->compressed == NULL) {
archive_set_error(f->archive, ENOMEM,
"Can't allocate data for compression buffer");
- free(state);
return (ARCHIVE_FATAL);
}
- f->write = archive_compressor_compress_write;
- f->close = archive_compressor_compress_close;
- f->free = archive_compressor_compress_free;
-
- state->max_maxcode = 0x10000; /* Should NEVER generate this code. */
- state->in_count = 0; /* Length of input. */
- state->bit_buf = 0;
- state->bit_offset = 0;
- state->out_count = 3; /* Includes 3-byte header mojo. */
- state->compress_ratio = 0;
- state->checkpoint = CHECK_GAP;
- state->code_len = 9;
- state->cur_maxcode = MAXCODE(state->code_len);
- state->first_free = FIRST;
+ /* Should NEVER generate this code. */
+ compress->max_maxcode = 0x10000;
+ /* Length of input. */
+ compress->in_count = 0;
+ compress->bit_buf = 0;
+ compress->bit_offset = 0;
+ /* Includes 3-byte header mojo. */
+ compress->out_count = 3;
+ compress->compress_ratio = 0;
+ compress->checkpoint = CHECK_GAP;
+ compress->code_len = 9;
+ compress->cur_maxcode = MAXCODE(compress->code_len);
+ compress->first_free = FIRST;
- memset(state->hashtab, 0xff, sizeof(state->hashtab));
+ memset(compress->hashtab, 0xff, sizeof(compress->hashtab));
/* Prime output buffer with a gzip header. */
- state->compressed[0] = 0x1f; /* Compress */
- state->compressed[1] = 0x9d;
- state->compressed[2] = 0x90; /* Block mode, 16bit max */
- state->compressed_offset = 3;
+ compress->compressed[0] = 0x1f; /* Compress */
+ compress->compressed[1] = 0x9d;
+ compress->compressed[2] = 0x90; /* Block mode, 16bit max */
+ compress->compressed_offset = 3;
- f->data = state;
- return (0);
+ return (ARCHIVE_OK);
}
/*-
@@ -224,17 +230,17 @@ static const unsigned char rmask[9] =
static int
output_byte(struct archive_write_filter *f, unsigned char c)
{
- struct private_data *state = f->data;
+ struct compress *compress = f->data;
- state->compressed[state->compressed_offset++] = c;
- ++state->out_count;
+ compress->compressed[compress->compressed_offset++] = c;
+ ++compress->out_count;
- if (state->compressed_buffer_size == state->compressed_offset) {
+ if (compress->compressed_buffer_size == compress->compressed_offset) {
int ret = __archive_write_filter(f->next_filter,
- state->compressed, state->compressed_buffer_size);
+ compress->compressed, compress->compressed_buffer_size);
if (ret != ARCHIVE_OK)
return ARCHIVE_FATAL;
- state->compressed_offset = 0;
+ compress->compressed_offset = 0;
}
return ARCHIVE_OK;
@@ -243,7 +249,7 @@ output_byte(struct archive_write_filter *f, unsigned char c)
static int
output_code(struct archive_write_filter *f, int ocode)
{
- struct private_data *state = f->data;
+ struct compress *compress = f->data;
int bits, ret, clear_flg, bit_offset;
clear_flg = ocode == CLEAR;
@@ -252,11 +258,11 @@ output_code(struct archive_write_filter *f, int ocode)
* Since ocode is always >= 8 bits, only need to mask the first
* hunk on the left.
*/
- bit_offset = state->bit_offset % 8;
- state->bit_buf |= (ocode << bit_offset) & 0xff;
- output_byte(f, state->bit_buf);
+ bit_offset = compress->bit_offset % 8;
+ compress->bit_buf |= (ocode << bit_offset) & 0xff;
+ output_byte(f, compress->bit_buf);
- bits = state->code_len - (8 - bit_offset);
+ bits = compress->code_len - (8 - bit_offset);
ocode >>= 8 - bit_offset;
/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
if (bits >= 8) {
@@ -265,41 +271,41 @@ output_code(struct archive_write_filter *f, int ocode)
bits -= 8;
}
/* Last bits. */
- state->bit_offset += state->code_len;
- state->bit_buf = ocode & rmask[bits];
- if (state->bit_offset == state->code_len * 8)
- state->bit_offset = 0;
+ compress->bit_offset += compress->code_len;
+ compress->bit_buf = ocode & rmask[bits];
+ if (compress->bit_offset == compress->code_len * 8)
+ compress->bit_offset = 0;
/*
* If the next entry is going to be too big for the ocode size,
* then increase it, if possible.
*/
- if (clear_flg || state->first_free > state->cur_maxcode) {
+ if (clear_flg || compress->first_free > compress->cur_maxcode) {
/*
* Write the whole buffer, because the input side won't
* discover the size increase until after it has read it.
*/
- if (state->bit_offset > 0) {
- while (state->bit_offset < state->code_len * 8) {
- ret = output_byte(f, state->bit_buf);
+ if (compress->bit_offset > 0) {
+ while (compress->bit_offset < compress->code_len * 8) {
+ ret = output_byte(f, compress->bit_buf);
if (ret != ARCHIVE_OK)
return ret;
- state->bit_offset += 8;
- state->bit_buf = 0;
+ compress->bit_offset += 8;
+ compress->bit_buf = 0;
}
}
- state->bit_buf = 0;
- state->bit_offset = 0;
+ compress->bit_buf = 0;
+ compress->bit_offset = 0;
if (clear_flg) {
- state->code_len = 9;
- state->cur_maxcode = MAXCODE(state->code_len);
+ compress->code_len = 9;
+ compress->cur_maxcode = MAXCODE(compress->code_len);
} else {
- state->code_len++;
- if (state->code_len == 16)
- state->cur_maxcode = state->max_maxcode;
+ compress->code_len++;
+ if (compress->code_len == 16)
+ compress->cur_maxcode = compress->max_maxcode;
else
- state->cur_maxcode = MAXCODE(state->code_len);
+ compress->cur_maxcode = MAXCODE(compress->code_len);
}
}
@@ -309,13 +315,13 @@ output_code(struct archive_write_filter *f, int ocode)
static int
output_flush(struct archive_write_filter *f)
{
- struct private_data *state = f->data;
+ struct compress *compress = f->data;
int ret;
/* At EOF, write the rest of the buffer. */
- if (state->bit_offset % 8) {
- state->code_len = (state->bit_offset % 8 + 7) / 8;
- ret = output_byte(f, state->bit_buf);
+ if (compress->bit_offset % 8) {
+ compress->code_len = (compress->bit_offset % 8 + 7) / 8;
+ ret = output_byte(f, compress->bit_buf);
if (ret != ARCHIVE_OK)
return ret;
}
@@ -330,7 +336,7 @@ static int
archive_compressor_compress_write(struct archive_write_filter *f,
const void *buff, size_t length)
{
- struct private_data *state = (struct private_data *)f->data;
+ struct compress *compress = f->data;
int i;
int ratio;
int c, disp, ret;
@@ -341,23 +347,24 @@ archive_compressor_compress_write(struct archive_write_filter *f,
bp = buff;
- if (state->in_count == 0) {
- state->cur_code = *bp++;
- ++state->in_count;
+ if (compress->in_count == 0) {
+ compress->cur_code = *bp++;
+ ++compress->in_count;
--length;
}
while (length--) {
c = *bp++;
- state->in_count++;
- state->cur_fcode = (c << 16) | state->cur_code;
- i = ((c << HSHIFT) ^ state->cur_code); /* Xor hashing. */
+ compress->in_count++;
+ compress->cur_fcode = (c << 16) | compress->cur_code;
+ /* Xor hashing. */
+ i = ((c << HSHIFT) ^ compress->cur_code);
- if (state->hashtab[i] == state->cur_fcode) {
- state->cur_code = state->codetab[i];
+ if (compress->hashtab[i] == compress->cur_fcode) {
+ compress->cur_code = compress->codetab[i];
continue;
}
- if (state->hashtab[i] < 0) /* Empty slot. */
+ if (compress->hashtab[i] < 0) /* Empty slot. */
goto nomatch;
/* Secondary hash (after G. Knott). */
if (i == 0)
@@ -368,40 +375,40 @@ archive_compressor_compress_write(struct archive_write_filter *f,
if ((i -= disp) < 0)
i += HSIZE;
- if (state->hashtab[i] == state->cur_fcode) {
- state->cur_code = state->codetab[i];
+ if (compress->hashtab[i] == compress->cur_fcode) {
+ compress->cur_code = compress->codetab[i];
continue;
}
- if (state->hashtab[i] >= 0)
+ if (compress->hashtab[i] >= 0)
goto probe;
nomatch:
- ret = output_code(f, state->cur_code);
+ ret = output_code(f, compress->cur_code);
if (ret != ARCHIVE_OK)
return ret;
- state->cur_code = c;
- if (state->first_free < state->max_maxcode) {
- state->codetab[i] = state->first_free++; /* code -> hashtable */
- state->hashtab[i] = state->cur_fcode;
+ compress->cur_code = c;
+ if (compress->first_free < compress->max_maxcode) {
+ compress->codetab[i] = compress->first_free++; /* code -> hashtable */
+ compress->hashtab[i] = compress->cur_fcode;
continue;
}
- if (state->in_count < state->checkpoint)
+ if (compress->in_count < compress->checkpoint)
continue;
- state->checkpoint = state->in_count + CHECK_GAP;
+ compress->checkpoint = compress->in_count + CHECK_GAP;
- if (state->in_count <= 0x007fffff && state->out_count != 0)
- ratio = (int)(state->in_count * 256 / state->out_count);
- else if ((ratio = (int)(state->out_count / 256)) == 0)
+ if (compress->in_count <= 0x007fffff && compress->out_count != 0)
+ ratio = (int)(compress->in_count * 256 / compress->out_count);
+ else if ((ratio = (int)(compress->out_count / 256)) == 0)
ratio = 0x7fffffff;
else
- ratio = (int)(state->in_count / ratio);
+ ratio = (int)(compress->in_count / ratio);
- if (ratio > state->compress_ratio)
- state->compress_ratio = ratio;
+ if (ratio > compress->compress_ratio)
+ compress->compress_ratio = ratio;
else {
- state->compress_ratio = 0;
- memset(state->hashtab, 0xff, sizeof(state->hashtab));
- state->first_free = FIRST;
+ compress->compress_ratio = 0;
+ memset(compress->hashtab, 0xff, sizeof(compress->hashtab));
+ compress->first_free = FIRST;
ret = output_code(f, CLEAR);
if (ret != ARCHIVE_OK)
return ret;
@@ -418,10 +425,10 @@ archive_compressor_compress_write(struct archive_write_filter *f,
static int
archive_compressor_compress_close(struct archive_write_filter *f)
{
- struct private_data *state = (struct private_data *)f->data;
+ struct compress *compress = f->data;
int ret;
- ret = output_code(f, state->cur_code);
+ ret = output_code(f, compress->cur_code);
if (ret != ARCHIVE_OK)
return ret;
ret = output_flush(f);
@@ -430,16 +437,23 @@ archive_compressor_compress_close(struct archive_write_filter *f)
/* Write the last block */
ret = __archive_write_filter(f->next_filter,
- state->compressed, state->compressed_offset);
+ compress->compressed, compress->compressed_offset);
return (ret);
}
static int
archive_compressor_compress_free(struct archive_write_filter *f)
{
- struct private_data *state = (struct private_data *)f->data;
-
- free(state->compressed);
- free(state);
+ free_data(f->data);
+ f->data = NULL;
return (ARCHIVE_OK);
}
+
+static void
+free_data(struct compress *compress)
+{
+ if (compress != NULL) {
+ free(compress->compressed);
+ free(compress);
+ }
+}
diff --git a/contrib/libarchive/libarchive/archive_write_add_filter_grzip.c b/contrib/libarchive/libarchive/archive_write_add_filter_grzip.c
index f8bb886061e5..be686c6176ea 100644
--- a/contrib/libarchive/libarchive/archive_write_add_filter_grzip.c
+++ b/contrib/libarchive/libarchive/archive_write_add_filter_grzip.c
@@ -35,7 +35,7 @@
#include "archive.h"
#include "archive_write_private.h"
-struct write_grzip {
+struct grzip {
struct archive_write_program_data *pdata;
};
@@ -46,42 +46,45 @@ static int archive_write_grzip_write(struct archive_write_filter *,
const void *, size_t);
static int archive_write_grzip_close(struct archive_write_filter *);
static int archive_write_grzip_free(struct archive_write_filter *);
+static void free_data(struct grzip *);
int
-archive_write_add_filter_grzip(struct archive *_a)
+archive_write_add_filter_grzip(struct archive *a)
{
- struct archive_write_filter *f = __archive_write_allocate_filter(_a);
- struct write_grzip *data;
+ struct archive_write_filter *f;
+ struct grzip *grzip;
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_add_filter_grzip");
- data = calloc(1, sizeof(*data));
- if (data == NULL) {
- archive_set_error(_a, ENOMEM, "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- data->pdata = __archive_write_program_allocate("grzip");
- if (data->pdata == NULL) {
- free(data);
- archive_set_error(_a, ENOMEM, "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
+ grzip = calloc(1, sizeof(*grzip));
+ if (grzip == NULL)
+ goto memerr;
+ grzip->pdata = __archive_write_program_allocate("grzip");
+ if (grzip->pdata == NULL)
+ goto memerr;
+ f = __archive_write_allocate_filter(a);
+ if (f == NULL)
+ goto memerr;
f->name = "grzip";
f->code = ARCHIVE_FILTER_GRZIP;
- f->data = data;
- f->open = archive_write_grzip_open;
+ f->data = grzip;
f->options = archive_write_grzip_options;
+ f->open = archive_write_grzip_open;
f->write = archive_write_grzip_write;
f->close = archive_write_grzip_close;
f->free = archive_write_grzip_free;
/* Note: This filter always uses an external program, so we
* return "warn" to inform of the fact. */
- archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
"Using external grzip program for grzip compression");
return (ARCHIVE_WARN);
+memerr:
+ free_data(grzip);
+ archive_set_error(a, ENOMEM, "Can't allocate memory");
+ return (ARCHIVE_FATAL);
}
static int
@@ -100,34 +103,41 @@ archive_write_grzip_options(struct archive_write_filter *f, const char *key,
static int
archive_write_grzip_open(struct archive_write_filter *f)
{
- struct write_grzip *data = (struct write_grzip *)f->data;
+ struct grzip *grzip = f->data;
- return __archive_write_program_open(f, data->pdata, "grzip");
+ return __archive_write_program_open(f, grzip->pdata, "grzip");
}
static int
archive_write_grzip_write(struct archive_write_filter *f,
const void *buff, size_t length)
{
- struct write_grzip *data = (struct write_grzip *)f->data;
+ struct grzip *grzip = f->data;
- return __archive_write_program_write(f, data->pdata, buff, length);
+ return __archive_write_program_write(f, grzip->pdata, buff, length);
}
static int
archive_write_grzip_close(struct archive_write_filter *f)
{
- struct write_grzip *data = (struct write_grzip *)f->data;
+ struct grzip *grzip = f->data;
- return __archive_write_program_close(f, data->pdata);
+ return __archive_write_program_close(f, grzip->pdata);
}
static int
archive_write_grzip_free(struct archive_write_filter *f)
{
- struct write_grzip *data = (struct write_grzip *)f->data;
-
- __archive_write_program_free(data->pdata);
- free(data);
+ free_data(f->data);
+ f->data = NULL;
return (ARCHIVE_OK);
}
+
+static void
+free_data(struct grzip *grzip)
+{
+ if (grzip != NULL) {
+ __archive_write_program_free(grzip->pdata);
+ free(grzip);
+ }
+}
diff --git a/contrib/libarchive/libarchive/archive_write_add_filter_gzip.c b/contrib/libarchive/libarchive/archive_write_add_filter_gzip.c
index 0a2f22408bad..a7679a728f4a 100644
--- a/contrib/libarchive/libarchive/archive_write_add_filter_gzip.c
+++ b/contrib/libarchive/libarchive/archive_write_add_filter_gzip.c
@@ -40,6 +40,7 @@
#endif
#include "archive.h"
+#include "archive_endian.h"
#include "archive_private.h"
#include "archive_string.h"
#include "archive_write_private.h"
@@ -55,13 +56,13 @@ archive_write_set_compression_gzip(struct archive *a)
/* Don't compile this if we don't have zlib. */
-struct private_data {
+struct gzip {
int compression_level;
int timestamp;
char *original_filename;
#ifdef HAVE_ZLIB_H
z_stream stream;
- int64_t total_in;
+ uint64_t total_in;
unsigned char *compressed;
size_t compressed_buffer_size;
unsigned long crc;
@@ -86,65 +87,66 @@ static int archive_compressor_gzip_close(struct archive_write_filter *);
static int archive_compressor_gzip_free(struct archive_write_filter *);
#ifdef HAVE_ZLIB_H
static int drive_compressor(struct archive_write_filter *,
- struct private_data *, int finishing);
+ struct gzip *, int finishing);
#endif
+static void free_data(struct gzip *);
/*
* Add a gzip compression filter to this write handle.
*/
int
-archive_write_add_filter_gzip(struct archive *_a)
+archive_write_add_filter_gzip(struct archive *a)
{
- struct archive_write *a = (struct archive_write *)_a;
- struct archive_write_filter *f = __archive_write_allocate_filter(_a);
- struct private_data *data;
- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_add_filter_gzip");
+ struct archive_write_filter *f;
+ struct gzip *gzip;
+ int r;
- data = calloc(1, sizeof(*data));
- if (data == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- f->data = data;
- f->open = &archive_compressor_gzip_open;
- f->options = &archive_compressor_gzip_options;
- f->close = &archive_compressor_gzip_close;
- f->free = &archive_compressor_gzip_free;
- f->code = ARCHIVE_FILTER_GZIP;
- f->name = "gzip";
+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_write_add_filter_gzip");
- data->original_filename = NULL;
+ gzip = calloc(1, sizeof(*gzip));
+ if (gzip == NULL)
+ goto memerr;
+ gzip->original_filename = NULL;
#ifdef HAVE_ZLIB_H
- data->compression_level = Z_DEFAULT_COMPRESSION;
- return (ARCHIVE_OK);
+ gzip->compression_level = Z_DEFAULT_COMPRESSION;
+
+ r = ARCHIVE_OK;
#else
- data->pdata = __archive_write_program_allocate("gzip");
- if (data->pdata == NULL) {
- free(data);
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- data->compression_level = 0;
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ gzip->pdata = __archive_write_program_allocate("gzip");
+ if (gzip->pdata == NULL)
+ goto memerr;
+ gzip->compression_level = 0;
+
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
"Using external gzip program");
- return (ARCHIVE_WARN);
+ r = ARCHIVE_WARN;
#endif
+
+ f = __archive_write_allocate_filter(a);
+ if (f == NULL)
+ goto memerr;
+ f->name = "gzip";
+ f->code = ARCHIVE_FILTER_GZIP;
+ f->data = gzip;
+ f->options = archive_compressor_gzip_options;
+ f->open = archive_compressor_gzip_open;
+ f->write = archive_compressor_gzip_write;
+ f->close = archive_compressor_gzip_close;
+ f->free = archive_compressor_gzip_free;
+
+ return (r);
+memerr:
+ free_data(gzip);
+ archive_set_error(a, ENOMEM, "Out of memory");
+ return (ARCHIVE_FATAL);
}
static int
archive_compressor_gzip_free(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
-
-#ifdef HAVE_ZLIB_H
- free(data->compressed);
-#else
- __archive_write_program_free(data->pdata);
-#endif
- free((void*)data->original_filename);
- free(data);
+ free_data(f->data);
f->data = NULL;
return (ARCHIVE_OK);
}
@@ -156,7 +158,7 @@ static int
archive_compressor_gzip_options(struct archive_write_filter *f, const char *key,
const char *value)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct gzip *gzip = f->data;
if (strcmp(key, "compression-level") == 0) {
if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
@@ -165,20 +167,20 @@ archive_compressor_gzip_options(struct archive_write_filter *f, const char *key,
"compression-level invalid");
return (ARCHIVE_FAILED);
}
- data->compression_level = value[0] - '0';
+ gzip->compression_level = value[0] - '0';
return (ARCHIVE_OK);
}
if (strcmp(key, "timestamp") == 0) {
- data->timestamp = (value == NULL)?-1:1;
+ gzip->timestamp = (value == NULL)?-1:1;
return (ARCHIVE_OK);
}
if (strcmp(key, "original-filename") == 0) {
- free((void*)data->original_filename);
- data->original_filename = NULL;
+ free((void*)gzip->original_filename);
+ gzip->original_filename = NULL;
if (value) {
- data->original_filename = strdup(value);
- if (data->original_filename == NULL)
- return (ARCHIVE_WARN);
+ gzip->original_filename = strdup(value);
+ if (gzip->original_filename == NULL)
+ return (ARCHIVE_FAILED);
}
return (ARCHIVE_OK);
}
@@ -196,11 +198,11 @@ archive_compressor_gzip_options(struct archive_write_filter *f, const char *key,
static int
archive_compressor_gzip_open(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct gzip *gzip = f->data;
int ret = ARCHIVE_OK;
int init_success;
- if (data->compressed == NULL) {
+ if (gzip->compressed == NULL) {
size_t bs = 65536, bpb;
if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
/* Buffer size should be a multiple number of
@@ -211,63 +213,60 @@ archive_compressor_gzip_open(struct archive_write_filter *f)
else if (bpb != 0)
bs -= bs % bpb;
}
- data->compressed_buffer_size = bs;
- data->compressed = malloc(data->compressed_buffer_size);
- if (data->compressed == NULL) {
+ gzip->compressed_buffer_size = bs;
+ gzip->compressed = malloc(gzip->compressed_buffer_size);
+ if (gzip->compressed == NULL) {
archive_set_error(f->archive, ENOMEM,
"Can't allocate data for compression buffer");
return (ARCHIVE_FATAL);
}
}
- data->crc = crc32(0L, NULL, 0);
- data->stream.next_out = data->compressed;
- data->stream.avail_out = (uInt)data->compressed_buffer_size;
+ gzip->crc = crc32(0L, NULL, 0);
+ gzip->stream.next_out = gzip->compressed;
+ gzip->stream.avail_out = (uInt)gzip->compressed_buffer_size;
/* Prime output buffer with a gzip header. */
- data->compressed[0] = 0x1f; /* GZip signature bytes */
- data->compressed[1] = 0x8b;
- data->compressed[2] = 0x08; /* "Deflate" compression */
- data->compressed[3] = 0x00; /* Flags */
- if (data->timestamp >= 0) {
- time_t t = time(NULL);
- data->compressed[4] = (uint8_t)(t)&0xff; /* Timestamp */
- data->compressed[5] = (uint8_t)(t>>8)&0xff;
- data->compressed[6] = (uint8_t)(t>>16)&0xff;
- data->compressed[7] = (uint8_t)(t>>24)&0xff;
+ gzip->compressed[0] = 0x1f; /* GZip signature bytes */
+ gzip->compressed[1] = 0x8b;
+ gzip->compressed[2] = 0x08; /* "Deflate" compression */
+ gzip->compressed[3] = 0x00; /* Flags */
+ if (gzip->timestamp >= 0) {
+ uint32_t t = (uint32_t)time(NULL);
+ archive_le32enc(gzip->compressed + 4, t); /* Timestamp */
} else {
- memset(&data->compressed[4], 0, 4);
+ memset(&gzip->compressed[4], 0, 4);
}
- if (data->compression_level == 9) {
- data->compressed[8] = 2;
- } else if(data->compression_level == 1) {
- data->compressed[8] = 4;
+ if (gzip->compression_level == 9) {
+ gzip->compressed[8] = 2;
+ } else if(gzip->compression_level == 1) {
+ gzip->compressed[8] = 4;
} else {
- data->compressed[8] = 0;
+ gzip->compressed[8] = 0;
}
- data->compressed[9] = 3; /* OS=Unix */
- data->stream.next_out += 10;
- data->stream.avail_out -= 10;
+ gzip->compressed[9] = 3; /* OS=Unix */
+ gzip->stream.next_out += 10;
+ gzip->stream.avail_out -= 10;
- if (data->original_filename != NULL) {
+ if (gzip->original_filename != NULL) {
/* Limit "original filename" to 32k or the
* remaining space in the buffer, whichever is smaller.
*/
- int ofn_length = strlen(data->original_filename);
- int ofn_max_length = 32768;
- int ofn_space_available = data->compressed
- + data->compressed_buffer_size
- - data->stream.next_out
+ size_t ofn_length = strlen(gzip->original_filename);
+ size_t ofn_max_length = 32768;
+ size_t ofn_space_available = gzip->compressed
+ + gzip->compressed_buffer_size
+ - gzip->stream.next_out
- 1;
if (ofn_max_length > ofn_space_available) {
ofn_max_length = ofn_space_available;
}
if (ofn_length < ofn_max_length) {
- data->compressed[3] |= 0x8;
- strcpy((char*)data->compressed + 10,
- data->original_filename);
- data->stream.next_out += ofn_length + 1;
- data->stream.avail_out -= ofn_length + 1;
+ gzip->compressed[3] |= 0x8;
+ strcpy((char*)gzip->compressed + 10,
+ gzip->original_filename);
+ gzip->stream.next_out += ofn_length + 1;
+ gzip->stream.avail_out -= ofn_length + 1;
} else {
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
"Gzip 'Original Filename' ignored because it is too long");
@@ -275,18 +274,15 @@ archive_compressor_gzip_open(struct archive_write_filter *f)
}
}
- f->write = archive_compressor_gzip_write;
-
/* Initialize compression library. */
- init_success = deflateInit2(&(data->stream),
- data->compression_level,
+ init_success = deflateInit2(&(gzip->stream),
+ gzip->compression_level,
Z_DEFLATED,
-15 /* < 0 to suppress zlib header */,
8,
Z_DEFAULT_STRATEGY);
if (init_success == Z_OK) {
- f->data = data;
return (ret);
}
@@ -322,17 +318,17 @@ static int
archive_compressor_gzip_write(struct archive_write_filter *f, const void *buff,
size_t length)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct gzip *gzip = f->data;
int ret;
/* Update statistics */
- data->crc = crc32(data->crc, (const Bytef *)buff, (uInt)length);
- data->total_in += length;
+ gzip->crc = crc32(gzip->crc, (const Bytef *)buff, (uInt)length);
+ gzip->total_in += length;
/* Compress input data to output buffer */
- SET_NEXT_IN(data, buff);
- data->stream.avail_in = (uInt)length;
- if ((ret = drive_compressor(f, data, 0)) != ARCHIVE_OK)
+ SET_NEXT_IN(gzip, buff);
+ gzip->stream.avail_in = (uInt)length;
+ if ((ret = drive_compressor(f, gzip, 0)) != ARCHIVE_OK)
return (ret);
return (ARCHIVE_OK);
@@ -344,32 +340,26 @@ archive_compressor_gzip_write(struct archive_write_filter *f, const void *buff,
static int
archive_compressor_gzip_close(struct archive_write_filter *f)
{
+ struct gzip *gzip = f->data;
unsigned char trailer[8];
- struct private_data *data = (struct private_data *)f->data;
int ret;
/* Finish compression cycle */
- ret = drive_compressor(f, data, 1);
+ ret = drive_compressor(f, gzip, 1);
if (ret == ARCHIVE_OK) {
/* Write the last compressed data. */
ret = __archive_write_filter(f->next_filter,
- data->compressed,
- data->compressed_buffer_size - data->stream.avail_out);
+ gzip->compressed,
+ gzip->compressed_buffer_size - gzip->stream.avail_out);
}
if (ret == ARCHIVE_OK) {
/* Build and write out 8-byte trailer. */
- trailer[0] = (uint8_t)(data->crc)&0xff;
- trailer[1] = (uint8_t)(data->crc >> 8)&0xff;
- trailer[2] = (uint8_t)(data->crc >> 16)&0xff;
- trailer[3] = (uint8_t)(data->crc >> 24)&0xff;
- trailer[4] = (uint8_t)(data->total_in)&0xff;
- trailer[5] = (uint8_t)(data->total_in >> 8)&0xff;
- trailer[6] = (uint8_t)(data->total_in >> 16)&0xff;
- trailer[7] = (uint8_t)(data->total_in >> 24)&0xff;
+ archive_le32enc(trailer, gzip->crc);
+ archive_le32enc(trailer + 4, gzip->total_in);
ret = __archive_write_filter(f->next_filter, trailer, 8);
}
- switch (deflateEnd(&(data->stream))) {
+ switch (deflateEnd(&(gzip->stream))) {
case Z_OK:
break;
default:
@@ -389,34 +379,34 @@ archive_compressor_gzip_close(struct archive_write_filter *f)
*/
static int
drive_compressor(struct archive_write_filter *f,
- struct private_data *data, int finishing)
+ struct gzip *gzip, int finishing)
{
int ret;
for (;;) {
- if (data->stream.avail_out == 0) {
+ if (gzip->stream.avail_out == 0) {
ret = __archive_write_filter(f->next_filter,
- data->compressed,
- data->compressed_buffer_size);
+ gzip->compressed,
+ gzip->compressed_buffer_size);
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
- data->stream.next_out = data->compressed;
- data->stream.avail_out =
- (uInt)data->compressed_buffer_size;
+ gzip->stream.next_out = gzip->compressed;
+ gzip->stream.avail_out =
+ (uInt)gzip->compressed_buffer_size;
}
/* If there's nothing to do, we're done. */
- if (!finishing && data->stream.avail_in == 0)
+ if (!finishing && gzip->stream.avail_in == 0)
return (ARCHIVE_OK);
- ret = deflate(&(data->stream),
+ ret = deflate(&(gzip->stream),
finishing ? Z_FINISH : Z_NO_FLUSH );
switch (ret) {
case Z_OK:
/* In non-finishing case, check if compressor
* consumed everything */
- if (!finishing && data->stream.avail_in == 0)
+ if (!finishing && gzip->stream.avail_in == 0)
return (ARCHIVE_OK);
/* In finishing case, this return always means
* there's more work */
@@ -435,12 +425,22 @@ drive_compressor(struct archive_write_filter *f,
}
}
+static void
+free_data(struct gzip *gzip)
+{
+ if (gzip != NULL) {
+ free(gzip->compressed);
+ free(gzip->original_filename);
+ free(gzip);
+ }
+}
+
#else /* HAVE_ZLIB_H */
static int
archive_compressor_gzip_open(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct gzip *gzip = f->data;
struct archive_string as;
int r;
@@ -448,19 +448,18 @@ archive_compressor_gzip_open(struct archive_write_filter *f)
archive_strcpy(&as, "gzip");
/* Specify compression level. */
- if (data->compression_level > 0) {
+ if (gzip->compression_level > 0) {
archive_strcat(&as, " -");
- archive_strappend_char(&as, '0' + data->compression_level);
+ archive_strappend_char(&as, '0' + gzip->compression_level);
}
- if (data->timestamp < 0)
+ if (gzip->timestamp < 0)
/* Do not save timestamp. */
archive_strcat(&as, " -n");
- else if (data->timestamp > 0)
+ else if (gzip->timestamp > 0)
/* Save timestamp. */
archive_strcat(&as, " -N");
- f->write = archive_compressor_gzip_write;
- r = __archive_write_program_open(f, data->pdata, as.s);
+ r = __archive_write_program_open(f, gzip->pdata, as.s);
archive_string_free(&as);
return (r);
}
@@ -469,17 +468,26 @@ static int
archive_compressor_gzip_write(struct archive_write_filter *f, const void *buff,
size_t length)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct gzip *gzip = f->data;
- return __archive_write_program_write(f, data->pdata, buff, length);
+ return __archive_write_program_write(f, gzip->pdata, buff, length);
}
static int
archive_compressor_gzip_close(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct gzip *gzip = f->data;
- return __archive_write_program_close(f, data->pdata);
+ return __archive_write_program_close(f, gzip->pdata);
}
+static void
+free_data(struct gzip *gzip)
+{
+ if (gzip != NULL) {
+ __archive_write_program_free(gzip->pdata);
+ free(gzip->original_filename);
+ free(gzip);
+ }
+}
#endif /* HAVE_ZLIB_H */
diff --git a/contrib/libarchive/libarchive/archive_write_add_filter_lrzip.c b/contrib/libarchive/libarchive/archive_write_add_filter_lrzip.c
index cda34dc738d3..3bd5bc64257b 100644
--- a/contrib/libarchive/libarchive/archive_write_add_filter_lrzip.c
+++ b/contrib/libarchive/libarchive/archive_write_add_filter_lrzip.c
@@ -39,7 +39,7 @@
#include "archive_string.h"
#include "archive_write_private.h"
-struct write_lrzip {
+struct lrzip {
struct archive_write_program_data *pdata;
int compression_level;
enum { lzma = 0, bzip2, gzip, lzo, none, zpaq } compression;
@@ -52,49 +52,52 @@ static int archive_write_lrzip_write(struct archive_write_filter *,
const void *, size_t);
static int archive_write_lrzip_close(struct archive_write_filter *);
static int archive_write_lrzip_free(struct archive_write_filter *);
+static void free_data(struct lrzip *);
int
-archive_write_add_filter_lrzip(struct archive *_a)
+archive_write_add_filter_lrzip(struct archive *a)
{
- struct archive_write_filter *f = __archive_write_allocate_filter(_a);
- struct write_lrzip *data;
+ struct archive_write_filter *f;
+ struct lrzip *lrzip;
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_add_filter_lrzip");
- data = calloc(1, sizeof(*data));
- if (data == NULL) {
- archive_set_error(_a, ENOMEM, "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- data->pdata = __archive_write_program_allocate("lrzip");
- if (data->pdata == NULL) {
- free(data);
- archive_set_error(_a, ENOMEM, "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
+ lrzip = calloc(1, sizeof(*lrzip));
+ if (lrzip == NULL)
+ goto memerr;
+ lrzip->pdata = __archive_write_program_allocate("lrzip");
+ if (lrzip->pdata == NULL)
+ goto memerr;
+ f = __archive_write_allocate_filter(a);
+ if (f == NULL)
+ goto memerr;
f->name = "lrzip";
f->code = ARCHIVE_FILTER_LRZIP;
- f->data = data;
- f->open = archive_write_lrzip_open;
+ f->data = lrzip;
f->options = archive_write_lrzip_options;
+ f->open = archive_write_lrzip_open;
f->write = archive_write_lrzip_write;
f->close = archive_write_lrzip_close;
f->free = archive_write_lrzip_free;
/* Note: This filter always uses an external program, so we
* return "warn" to inform of the fact. */
- archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
"Using external lrzip program for lrzip compression");
return (ARCHIVE_WARN);
+memerr:
+ free_data(lrzip);
+ archive_set_error(a, ENOMEM, "Can't allocate memory");
+ return (ARCHIVE_FATAL);
}
static int
archive_write_lrzip_options(struct archive_write_filter *f, const char *key,
const char *value)
{
- struct write_lrzip *data = (struct write_lrzip *)f->data;
+ struct lrzip *lrzip = f->data;
if (strcmp(key, "compression") == 0) {
if (value == NULL) {
@@ -103,15 +106,15 @@ archive_write_lrzip_options(struct archive_write_filter *f, const char *key,
return (ARCHIVE_FAILED);
}
else if (strcmp(value, "bzip2") == 0)
- data->compression = bzip2;
+ lrzip->compression = bzip2;
else if (strcmp(value, "gzip") == 0)
- data->compression = gzip;
+ lrzip->compression = gzip;
else if (strcmp(value, "lzo") == 0)
- data->compression = lzo;
+ lrzip->compression = lzo;
else if (strcmp(value, "none") == 0)
- data->compression = none;
+ lrzip->compression = none;
else if (strcmp(value, "zpaq") == 0)
- data->compression = zpaq;
+ lrzip->compression = zpaq;
else {
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
"compression invalid");
@@ -125,7 +128,7 @@ archive_write_lrzip_options(struct archive_write_filter *f, const char *key,
"compression-level invalid");
return (ARCHIVE_FAILED);
}
- data->compression_level = value[0] - '0';
+ lrzip->compression_level = value[0] - '0';
return (ARCHIVE_OK);
}
/* Note: The "warn" return is just to inform the options
@@ -137,7 +140,7 @@ archive_write_lrzip_options(struct archive_write_filter *f, const char *key,
static int
archive_write_lrzip_open(struct archive_write_filter *f)
{
- struct write_lrzip *data = (struct write_lrzip *)f->data;
+ struct lrzip *lrzip = f->data;
struct archive_string as;
int r;
@@ -145,7 +148,7 @@ archive_write_lrzip_open(struct archive_write_filter *f)
archive_strcpy(&as, "lrzip -q");
/* Specify compression type. */
- switch (data->compression) {
+ switch (lrzip->compression) {
case lzma:/* default compression */
break;
case bzip2:
@@ -166,12 +169,12 @@ archive_write_lrzip_open(struct archive_write_filter *f)
}
/* Specify compression level. */
- if (data->compression_level > 0) {
+ if (lrzip->compression_level > 0) {
archive_strcat(&as, " -L ");
- archive_strappend_char(&as, '0' + data->compression_level);
+ archive_strappend_char(&as, '0' + lrzip->compression_level);
}
- r = __archive_write_program_open(f, data->pdata, as.s);
+ r = __archive_write_program_open(f, lrzip->pdata, as.s);
archive_string_free(&as);
return (r);
}
@@ -180,25 +183,32 @@ static int
archive_write_lrzip_write(struct archive_write_filter *f,
const void *buff, size_t length)
{
- struct write_lrzip *data = (struct write_lrzip *)f->data;
+ struct lrzip *lrzip = f->data;
- return __archive_write_program_write(f, data->pdata, buff, length);
+ return __archive_write_program_write(f, lrzip->pdata, buff, length);
}
static int
archive_write_lrzip_close(struct archive_write_filter *f)
{
- struct write_lrzip *data = (struct write_lrzip *)f->data;
+ struct lrzip *lrzip = f->data;
- return __archive_write_program_close(f, data->pdata);
+ return __archive_write_program_close(f, lrzip->pdata);
}
static int
archive_write_lrzip_free(struct archive_write_filter *f)
{
- struct write_lrzip *data = (struct write_lrzip *)f->data;
-
- __archive_write_program_free(data->pdata);
- free(data);
+ free_data(f->data);
+ f->data = NULL;
return (ARCHIVE_OK);
}
+
+static void
+free_data(struct lrzip *lrzip)
+{
+ if (lrzip != NULL) {
+ __archive_write_program_free(lrzip->pdata);
+ free(lrzip);
+ }
+}
diff --git a/contrib/libarchive/libarchive/archive_write_add_filter_lz4.c b/contrib/libarchive/libarchive/archive_write_add_filter_lz4.c
index efc408e2a3f8..8b3b575fae4d 100644
--- a/contrib/libarchive/libarchive/archive_write_add_filter_lz4.c
+++ b/contrib/libarchive/libarchive/archive_write_add_filter_lz4.c
@@ -50,7 +50,7 @@
#define LZ4_MAGICNUMBER 0x184d2204
-struct private_data {
+struct lz4 {
int compression_level;
unsigned header_written:1;
unsigned version_number:1;
@@ -61,7 +61,6 @@ struct private_data {
unsigned preset_dictionary:1;
unsigned block_maximum_size:3;
#if defined(HAVE_LIBLZ4) && LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 2
- int64_t total_in;
char *out;
char *out_buffer;
size_t out_buffer_size;
@@ -86,66 +85,81 @@ static int archive_filter_lz4_options(struct archive_write_filter *,
const char *, const char *);
static int archive_filter_lz4_write(struct archive_write_filter *,
const void *, size_t);
+static void free_data(struct lz4 *);
/*
- * Add a lz4 compression filter to this write handle.
+ * Add an lz4 compression filter to this write handle.
*/
int
-archive_write_add_filter_lz4(struct archive *_a)
+archive_write_add_filter_lz4(struct archive *a)
{
- struct archive_write *a = (struct archive_write *)_a;
- struct archive_write_filter *f = __archive_write_allocate_filter(_a);
- struct private_data *data;
+ struct archive_write_filter *f;
+ struct lz4 *lz4;
+ int r;
- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_add_filter_lz4");
- data = calloc(1, sizeof(*data));
- if (data == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
-
+ lz4 = calloc(1, sizeof(*lz4));
+ if (lz4 == NULL)
+ goto memerr;
/*
* Setup default settings.
*/
- data->compression_level = 1;
- data->version_number = 0x01;
- data->block_independence = 1;
- data->block_checksum = 0;
- data->stream_size = 0;
- data->stream_checksum = 1;
- data->preset_dictionary = 0;
- data->block_maximum_size = 7;
-
- /*
- * Setup a filter setting.
- */
- f->data = data;
- f->options = &archive_filter_lz4_options;
- f->close = &archive_filter_lz4_close;
- f->free = &archive_filter_lz4_free;
- f->open = &archive_filter_lz4_open;
- f->code = ARCHIVE_FILTER_LZ4;
- f->name = "lz4";
+ lz4->version_number = 0x01;
+ lz4->block_independence = 1;
+ lz4->block_checksum = 0;
+ lz4->stream_size = 0;
+ lz4->stream_checksum = 1;
+ lz4->preset_dictionary = 0;
+ lz4->block_maximum_size = 7;
#if defined(HAVE_LIBLZ4) && LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 2
- return (ARCHIVE_OK);
+ lz4->compression_level = 1;
+
+ r = ARCHIVE_OK;
#else
/*
* We don't have lz4 library, and execute external lz4 program
* instead.
*/
- data->pdata = __archive_write_program_allocate("lz4");
- if (data->pdata == NULL) {
- free(data);
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- data->compression_level = 0;
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ lz4->pdata = __archive_write_program_allocate("lz4");
+ if (lz4->pdata == NULL)
+ goto memerr;
+ lz4->compression_level = 0;
+
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
"Using external lz4 program");
- return (ARCHIVE_WARN);
+ r = ARCHIVE_WARN;
#endif
+
+ /*
+ * Setup a filter setting.
+ */
+ f = __archive_write_allocate_filter(a);
+ if (f == NULL)
+ goto memerr;
+ f->name = "lz4";
+ f->code = ARCHIVE_FILTER_LZ4;
+ f->data = lz4;
+ f->options = archive_filter_lz4_options;
+ f->open = archive_filter_lz4_open;
+ f->write = archive_filter_lz4_write;
+ f->close = archive_filter_lz4_close;
+ f->free = archive_filter_lz4_free;
+
+ return (r);
+memerr:
+ free_data(lz4);
+ archive_set_error(a, ENOMEM, "Out of memory");
+ return (ARCHIVE_FATAL);
+}
+
+static int
+archive_filter_lz4_free(struct archive_write_filter *f)
+{
+ free_data(f->data);
+ f->data = NULL;
+ return (ARCHIVE_OK);
}
/*
@@ -155,7 +169,7 @@ static int
archive_filter_lz4_options(struct archive_write_filter *f,
const char *key, const char *value)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct lz4 *lz4 = f->data;
if (strcmp(key, "compression-level") == 0) {
int val;
@@ -174,15 +188,15 @@ archive_filter_lz4_options(struct archive_write_filter *f,
return (ARCHIVE_FATAL);
}
#endif
- data->compression_level = val;
+ lz4->compression_level = val;
return (ARCHIVE_OK);
}
if (strcmp(key, "stream-checksum") == 0) {
- data->stream_checksum = value != NULL;
+ lz4->stream_checksum = value != NULL;
return (ARCHIVE_OK);
}
if (strcmp(key, "block-checksum") == 0) {
- data->block_checksum = value != NULL;
+ lz4->block_checksum = value != NULL;
return (ARCHIVE_OK);
}
if (strcmp(key, "block-size") == 0) {
@@ -192,11 +206,11 @@ archive_filter_lz4_options(struct archive_write_filter *f,
"block-size invalid");
return (ARCHIVE_FAILED);
}
- data->block_maximum_size = value[0] - '0';
+ lz4->block_maximum_size = value[0] - '0';
return (ARCHIVE_OK);
}
if (strcmp(key, "block-dependence") == 0) {
- data->block_independence = value == NULL;
+ lz4->block_independence = value == NULL;
return (ARCHIVE_OK);
}
@@ -226,24 +240,24 @@ static ssize_t lz4_write_one_block(struct archive_write_filter *, const char *,
static int
archive_filter_lz4_open(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct lz4 *lz4 = f->data;
size_t required_size;
- static size_t const bkmap[] = { 64 * 1024, 256 * 1024, 1 * 1024 * 1024,
+ static const size_t bkmap[] = { 64 * 1024, 256 * 1024, 1 * 1024 * 1024,
4 * 1024 * 1024 };
size_t pre_block_size;
- if (data->block_maximum_size < 4)
- data->block_size = bkmap[0];
+ if (lz4->block_maximum_size < 4)
+ lz4->block_size = bkmap[0];
else
- data->block_size = bkmap[data->block_maximum_size - 4];
+ lz4->block_size = bkmap[lz4->block_maximum_size - 4];
- required_size = 4 + 15 + 4 + data->block_size + 4 + 4;
- if (data->out_buffer_size < required_size) {
+ required_size = 4 + 15 + 4 + lz4->block_size + 4 + 4;
+ if (lz4->out_buffer_size < required_size) {
size_t bs = required_size, bpb;
- free(data->out_buffer);
+ free(lz4->out_buffer);
if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
/* Buffer size should be a multiple number of
- * the of bytes per block for performance. */
+ * the bytes per block for performance. */
bpb = archive_write_get_bytes_per_block(f->archive);
if (bpb > bs)
bs = bpb;
@@ -252,34 +266,32 @@ archive_filter_lz4_open(struct archive_write_filter *f)
bs -= bs % bpb;
}
}
- data->out_block_size = bs;
+ lz4->out_block_size = bs;
bs += required_size;
- data->out_buffer = malloc(bs);
- data->out = data->out_buffer;
- data->out_buffer_size = bs;
+ lz4->out_buffer = malloc(bs);
+ lz4->out = lz4->out_buffer;
+ lz4->out_buffer_size = bs;
}
- pre_block_size = (data->block_independence)? 0: 64 * 1024;
- if (data->in_buffer_size < data->block_size + pre_block_size) {
- free(data->in_buffer_allocated);
- data->in_buffer_size = data->block_size;
- data->in_buffer_allocated =
- malloc(data->in_buffer_size + pre_block_size);
- data->in_buffer = data->in_buffer_allocated + pre_block_size;
- if (!data->block_independence && data->compression_level >= 3)
- data->in_buffer = data->in_buffer_allocated;
- data->in = data->in_buffer;
- data->in_buffer_size = data->block_size;
+ pre_block_size = (lz4->block_independence)? 0: 64 * 1024;
+ if (lz4->in_buffer_size < lz4->block_size + pre_block_size) {
+ free(lz4->in_buffer_allocated);
+ lz4->in_buffer_size = lz4->block_size;
+ lz4->in_buffer_allocated =
+ malloc(lz4->in_buffer_size + pre_block_size);
+ lz4->in_buffer = lz4->in_buffer_allocated + pre_block_size;
+ if (!lz4->block_independence && lz4->compression_level >= 3)
+ lz4->in_buffer = lz4->in_buffer_allocated;
+ lz4->in = lz4->in_buffer;
+ lz4->in_buffer_size = lz4->block_size;
}
- if (data->out_buffer == NULL || data->in_buffer_allocated == NULL) {
+ if (lz4->out_buffer == NULL || lz4->in_buffer_allocated == NULL) {
archive_set_error(f->archive, ENOMEM,
"Can't allocate data for compression buffer");
return (ARCHIVE_FATAL);
}
- f->write = archive_filter_lz4_write;
-
return (ARCHIVE_OK);
}
@@ -292,23 +304,20 @@ static int
archive_filter_lz4_write(struct archive_write_filter *f,
const void *buff, size_t length)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct lz4 *lz4 = f->data;
int ret = ARCHIVE_OK;
const char *p;
size_t remaining;
ssize_t size;
/* If we haven't written a stream descriptor, we have to do it first. */
- if (!data->header_written) {
+ if (!lz4->header_written) {
ret = lz4_write_stream_descriptor(f);
if (ret != ARCHIVE_OK)
return (ret);
- data->header_written = 1;
+ lz4->header_written = 1;
}
- /* Update statistics */
- data->total_in += length;
-
p = (const char *)buff;
remaining = length;
while (remaining) {
@@ -317,14 +326,14 @@ archive_filter_lz4_write(struct archive_write_filter *f,
size = lz4_write_one_block(f, p, remaining);
if (size < ARCHIVE_OK)
return (ARCHIVE_FATAL);
- l = data->out - data->out_buffer;
- if (l >= data->out_block_size) {
+ l = lz4->out - lz4->out_buffer;
+ if (l >= lz4->out_block_size) {
ret = __archive_write_filter(f->next_filter,
- data->out_buffer, data->out_block_size);
- l -= data->out_block_size;
- memcpy(data->out_buffer,
- data->out_buffer + data->out_block_size, l);
- data->out = data->out_buffer + l;
+ lz4->out_buffer, lz4->out_block_size);
+ l -= lz4->out_block_size;
+ memcpy(lz4->out_buffer,
+ lz4->out_buffer + lz4->out_block_size, l);
+ lz4->out = lz4->out_buffer + l;
if (ret < ARCHIVE_WARN)
break;
}
@@ -341,7 +350,7 @@ archive_filter_lz4_write(struct archive_write_filter *f,
static int
archive_filter_lz4_close(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct lz4 *lz4 = f->data;
int ret;
/* Finish compression cycle. */
@@ -352,75 +361,48 @@ archive_filter_lz4_close(struct archive_write_filter *f)
*/
/* Write End Of Stream. */
- memset(data->out, 0, 4); data->out += 4;
+ memset(lz4->out, 0, 4); lz4->out += 4;
/* Write Stream checksum if needed. */
- if (data->stream_checksum) {
+ if (lz4->stream_checksum) {
unsigned int checksum;
checksum = __archive_xxhash.XXH32_digest(
- data->xxh32_state);
- data->xxh32_state = NULL;
- archive_le32enc(data->out, checksum);
- data->out += 4;
+ lz4->xxh32_state);
+ lz4->xxh32_state = NULL;
+ archive_le32enc(lz4->out, checksum);
+ lz4->out += 4;
}
ret = __archive_write_filter(f->next_filter,
- data->out_buffer, data->out - data->out_buffer);
+ lz4->out_buffer, lz4->out - lz4->out_buffer);
}
return ret;
}
static int
-archive_filter_lz4_free(struct archive_write_filter *f)
-{
- struct private_data *data = (struct private_data *)f->data;
-
- if (data->lz4_stream != NULL) {
-#ifdef HAVE_LZ4HC_H
- if (data->compression_level >= 3)
-#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
- LZ4_freeStreamHC(data->lz4_stream);
-#else
- LZ4_freeHC(data->lz4_stream);
-#endif
- else
-#endif
-#if LZ4_VERSION_MINOR >= 3
- LZ4_freeStream(data->lz4_stream);
-#else
- LZ4_free(data->lz4_stream);
-#endif
- }
- free(data->out_buffer);
- free(data->in_buffer_allocated);
- free(data->xxh32_state);
- free(data);
- f->data = NULL;
- return (ARCHIVE_OK);
-}
-
-static int
lz4_write_stream_descriptor(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct lz4 *lz4 = f->data;
uint8_t *sd;
- sd = (uint8_t *)data->out;
+ sd = (uint8_t *)lz4->out;
/* Write Magic Number. */
archive_le32enc(&sd[0], LZ4_MAGICNUMBER);
/* FLG */
- sd[4] = (data->version_number << 6)
- | (data->block_independence << 5)
- | (data->block_checksum << 4)
- | (data->stream_size << 3)
- | (data->stream_checksum << 2)
- | (data->preset_dictionary << 0);
+ sd[4] = (lz4->version_number << 6)
+ | (lz4->block_independence << 5)
+ | (lz4->block_checksum << 4)
+ | (lz4->stream_size << 3)
+ | (lz4->stream_checksum << 2)
+ | (lz4->preset_dictionary << 0);
/* BD */
- sd[5] = (data->block_maximum_size << 4);
+ sd[5] = (lz4->block_maximum_size << 4);
sd[6] = (__archive_xxhash.XXH32(&sd[4], 2, 0) >> 8) & 0xff;
- data->out += 7;
- if (data->stream_checksum)
- data->xxh32_state = __archive_xxhash.XXH32_init(0);
- else
- data->xxh32_state = NULL;
+ lz4->out += 7;
+ if (lz4->stream_checksum) {
+ lz4->xxh32_state = __archive_xxhash.XXH32_init(0);
+ if (lz4->xxh32_state == NULL)
+ return (ARCHIVE_FATAL);
+ } else
+ lz4->xxh32_state = NULL;
return (ARCHIVE_OK);
}
@@ -428,36 +410,36 @@ static ssize_t
lz4_write_one_block(struct archive_write_filter *f, const char *p,
size_t length)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct lz4 *lz4 = f->data;
ssize_t r;
if (p == NULL) {
/* Compress remaining uncompressed data. */
- if (data->in_buffer == data->in)
+ if (lz4->in_buffer == lz4->in)
return 0;
else {
- size_t l = data->in - data->in_buffer;
- r = drive_compressor(f, data->in_buffer, l);
+ size_t l = lz4->in - lz4->in_buffer;
+ r = drive_compressor(f, lz4->in_buffer, l);
if (r == ARCHIVE_OK)
r = (ssize_t)l;
}
- } else if ((data->block_independence || data->compression_level < 3) &&
- data->in_buffer == data->in && length >= data->block_size) {
- r = drive_compressor(f, p, data->block_size);
+ } else if ((lz4->block_independence || lz4->compression_level < 3) &&
+ lz4->in_buffer == lz4->in && length >= lz4->block_size) {
+ r = drive_compressor(f, p, lz4->block_size);
if (r == ARCHIVE_OK)
- r = (ssize_t)data->block_size;
+ r = (ssize_t)lz4->block_size;
} else {
- size_t remaining_size = data->in_buffer_size -
- (data->in - data->in_buffer);
+ size_t remaining_size = lz4->in_buffer_size -
+ (lz4->in - lz4->in_buffer);
size_t l = (remaining_size > length)? length: remaining_size;
- memcpy(data->in, p, l);
- data->in += l;
+ memcpy(lz4->in, p, l);
+ lz4->in += l;
if (l == remaining_size) {
- r = drive_compressor(f, data->in_buffer,
- data->block_size);
+ r = drive_compressor(f, lz4->in_buffer,
+ lz4->block_size);
if (r == ARCHIVE_OK)
r = (ssize_t)l;
- data->in = data->in_buffer;
+ lz4->in = lz4->in_buffer;
} else
r = (ssize_t)l;
}
@@ -476,12 +458,12 @@ lz4_write_one_block(struct archive_write_filter *f, const char *p,
static int
drive_compressor(struct archive_write_filter *f, const char *p, size_t length)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct lz4 *lz4 = f->data;
- if (data->stream_checksum)
- __archive_xxhash.XXH32_update(data->xxh32_state,
+ if (lz4->stream_checksum)
+ __archive_xxhash.XXH32_update(lz4->xxh32_state,
p, (int)length);
- if (data->block_independence)
+ if (lz4->block_independence)
return drive_compressor_independence(f, p, length);
else
return drive_compressor_dependence(f, p, length);
@@ -491,48 +473,48 @@ static int
drive_compressor_independence(struct archive_write_filter *f, const char *p,
size_t length)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct lz4 *lz4 = f->data;
unsigned int outsize;
#ifdef HAVE_LZ4HC_H
- if (data->compression_level >= 3)
+ if (lz4->compression_level >= 3)
#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
- outsize = LZ4_compress_HC(p, data->out + 4,
- (int)length, (int)data->block_size,
- data->compression_level);
+ outsize = LZ4_compress_HC(p, lz4->out + 4,
+ (int)length, (int)lz4->block_size,
+ lz4->compression_level);
#else
- outsize = LZ4_compressHC2_limitedOutput(p, data->out + 4,
- (int)length, (int)data->block_size,
- data->compression_level);
+ outsize = LZ4_compressHC2_limitedOutput(p, lz4->out + 4,
+ (int)length, (int)lz4->block_size,
+ lz4->compression_level);
#endif
else
#endif
#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
- outsize = LZ4_compress_default(p, data->out + 4,
- (int)length, (int)data->block_size);
+ outsize = LZ4_compress_default(p, lz4->out + 4,
+ (int)length, (int)lz4->block_size);
#else
- outsize = LZ4_compress_limitedOutput(p, data->out + 4,
- (int)length, (int)data->block_size);
+ outsize = LZ4_compress_limitedOutput(p, lz4->out + 4,
+ (int)length, (int)lz4->block_size);
#endif
if (outsize) {
/* The buffer is compressed. */
- archive_le32enc(data->out, outsize);
- data->out += 4;
+ archive_le32enc(lz4->out, outsize);
+ lz4->out += 4;
} else {
/* The buffer is not compressed. The compressed size was
* bigger than its uncompressed size. */
- archive_le32enc(data->out, (uint32_t)(length | 0x80000000));
- data->out += 4;
- memcpy(data->out, p, length);
+ archive_le32enc(lz4->out, (uint32_t)(length | 0x80000000));
+ lz4->out += 4;
+ memcpy(lz4->out, p, length);
outsize = (uint32_t)length;
}
- data->out += outsize;
- if (data->block_checksum) {
+ lz4->out += outsize;
+ if (lz4->block_checksum) {
unsigned int checksum =
- __archive_xxhash.XXH32(data->out - outsize, outsize, 0);
- archive_le32enc(data->out, checksum);
- data->out += 4;
+ __archive_xxhash.XXH32(lz4->out - outsize, outsize, 0);
+ archive_le32enc(lz4->out, checksum);
+ lz4->out += 4;
}
return (ARCHIVE_OK);
}
@@ -541,21 +523,21 @@ static int
drive_compressor_dependence(struct archive_write_filter *f, const char *p,
size_t length)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct lz4 *lz4 = f->data;
int outsize;
#define DICT_SIZE (64 * 1024)
#ifdef HAVE_LZ4HC_H
- if (data->compression_level >= 3) {
- if (data->lz4_stream == NULL) {
+ if (lz4->compression_level >= 3) {
+ if (lz4->lz4_stream == NULL) {
#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
- data->lz4_stream = LZ4_createStreamHC();
- LZ4_resetStreamHC(data->lz4_stream, data->compression_level);
+ lz4->lz4_stream = LZ4_createStreamHC();
+ LZ4_resetStreamHC(lz4->lz4_stream, lz4->compression_level);
#else
- data->lz4_stream =
- LZ4_createHC(data->in_buffer_allocated);
+ lz4->lz4_stream =
+ LZ4_createHC(lz4->in_buffer_allocated);
#endif
- if (data->lz4_stream == NULL) {
+ if (lz4->lz4_stream == NULL) {
archive_set_error(f->archive, ENOMEM,
"Can't allocate data for compression"
" buffer");
@@ -563,23 +545,23 @@ drive_compressor_dependence(struct archive_write_filter *f, const char *p,
}
}
else
- LZ4_loadDictHC(data->lz4_stream, data->in_buffer_allocated, DICT_SIZE);
+ LZ4_loadDictHC(lz4->lz4_stream, lz4->in_buffer_allocated, DICT_SIZE);
#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
outsize = LZ4_compress_HC_continue(
- data->lz4_stream, p, data->out + 4, (int)length,
- (int)data->block_size);
+ lz4->lz4_stream, p, lz4->out + 4, (int)length,
+ (int)lz4->block_size);
#else
outsize = LZ4_compressHC2_limitedOutput_continue(
- data->lz4_stream, p, data->out + 4, (int)length,
- (int)data->block_size, data->compression_level);
+ lz4->lz4_stream, p, lz4->out + 4, (int)length,
+ (int)lz4->block_size, lz4->compression_level);
#endif
} else
#endif
{
- if (data->lz4_stream == NULL) {
- data->lz4_stream = LZ4_createStream();
- if (data->lz4_stream == NULL) {
+ if (lz4->lz4_stream == NULL) {
+ lz4->lz4_stream = LZ4_createStream();
+ if (lz4->lz4_stream == NULL) {
archive_set_error(f->archive, ENOMEM,
"Can't allocate data for compression"
" buffer");
@@ -587,64 +569,91 @@ drive_compressor_dependence(struct archive_write_filter *f, const char *p,
}
}
else
- LZ4_loadDict(data->lz4_stream, data->in_buffer_allocated, DICT_SIZE);
+ LZ4_loadDict(lz4->lz4_stream, lz4->in_buffer_allocated, DICT_SIZE);
#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
outsize = LZ4_compress_fast_continue(
- data->lz4_stream, p, data->out + 4, (int)length,
- (int)data->block_size, 1);
+ lz4->lz4_stream, p, lz4->out + 4, (int)length,
+ (int)lz4->block_size, 1);
#else
outsize = LZ4_compress_limitedOutput_continue(
- data->lz4_stream, p, data->out + 4, (int)length,
- (int)data->block_size);
+ lz4->lz4_stream, p, lz4->out + 4, (int)length,
+ (int)lz4->block_size);
#endif
}
if (outsize) {
/* The buffer is compressed. */
- archive_le32enc(data->out, outsize);
- data->out += 4;
+ archive_le32enc(lz4->out, outsize);
+ lz4->out += 4;
} else {
/* The buffer is not compressed. The compressed size was
* bigger than its uncompressed size. */
- archive_le32enc(data->out, (uint32_t)(length | 0x80000000));
- data->out += 4;
- memcpy(data->out, p, length);
+ archive_le32enc(lz4->out, (uint32_t)(length | 0x80000000));
+ lz4->out += 4;
+ memcpy(lz4->out, p, length);
outsize = (uint32_t)length;
}
- data->out += outsize;
- if (data->block_checksum) {
+ lz4->out += outsize;
+ if (lz4->block_checksum) {
unsigned int checksum =
- __archive_xxhash.XXH32(data->out - outsize, outsize, 0);
- archive_le32enc(data->out, checksum);
- data->out += 4;
+ __archive_xxhash.XXH32(lz4->out - outsize, outsize, 0);
+ archive_le32enc(lz4->out, checksum);
+ lz4->out += 4;
}
- if (length == data->block_size) {
+ if (length == lz4->block_size) {
#ifdef HAVE_LZ4HC_H
- if (data->compression_level >= 3) {
+ if (lz4->compression_level >= 3) {
#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
- LZ4_saveDictHC(data->lz4_stream, data->in_buffer_allocated, DICT_SIZE);
+ LZ4_saveDictHC(lz4->lz4_stream, lz4->in_buffer_allocated, DICT_SIZE);
#else
- LZ4_slideInputBufferHC(data->lz4_stream);
+ LZ4_slideInputBufferHC(lz4->lz4_stream);
#endif
- data->in_buffer = data->in_buffer_allocated + DICT_SIZE;
+ lz4->in_buffer = lz4->in_buffer_allocated + DICT_SIZE;
}
else
#endif
- LZ4_saveDict(data->lz4_stream,
- data->in_buffer_allocated, DICT_SIZE);
+ LZ4_saveDict(lz4->lz4_stream,
+ lz4->in_buffer_allocated, DICT_SIZE);
#undef DICT_SIZE
}
return (ARCHIVE_OK);
}
+static void
+free_data(struct lz4 *lz4)
+{
+ if (lz4 != NULL) {
+ if (lz4->lz4_stream != NULL) {
+#ifdef HAVE_LZ4HC_H
+ if (lz4->compression_level >= 3)
+#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
+ LZ4_freeStreamHC(lz4->lz4_stream);
+#else
+ LZ4_freeHC(lz4->lz4_stream);
+#endif
+ else
+#endif
+#if LZ4_VERSION_MINOR >= 3
+ LZ4_freeStream(lz4->lz4_stream);
+#else
+ LZ4_free(lz4->lz4_stream);
+#endif
+ }
+ free(lz4->out_buffer);
+ free(lz4->in_buffer_allocated);
+ free(lz4->xxh32_state);
+ free(lz4);
+ }
+}
+
#else /* HAVE_LIBLZ4 */
static int
archive_filter_lz4_open(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct lz4 *lz4 = f->data;
struct archive_string as;
int r;
@@ -652,24 +661,22 @@ archive_filter_lz4_open(struct archive_write_filter *f)
archive_strcpy(&as, "lz4 -z -q -q");
/* Specify a compression level. */
- if (data->compression_level > 0) {
+ if (lz4->compression_level > 0) {
archive_strcat(&as, " -");
- archive_strappend_char(&as, '0' + data->compression_level);
+ archive_strappend_char(&as, '0' + lz4->compression_level);
}
/* Specify a block size. */
archive_strcat(&as, " -B");
- archive_strappend_char(&as, '0' + data->block_maximum_size);
+ archive_strappend_char(&as, '0' + lz4->block_maximum_size);
- if (data->block_checksum)
+ if (lz4->block_checksum)
archive_strcat(&as, " -BX");
- if (data->stream_checksum == 0)
+ if (lz4->stream_checksum == 0)
archive_strcat(&as, " --no-frame-crc");
- if (data->block_independence == 0)
+ if (lz4->block_independence == 0)
archive_strcat(&as, " -BD");
- f->write = archive_filter_lz4_write;
-
- r = __archive_write_program_open(f, data->pdata, as.s);
+ r = __archive_write_program_open(f, lz4->pdata, as.s);
archive_string_free(&as);
return (r);
}
@@ -678,27 +685,26 @@ static int
archive_filter_lz4_write(struct archive_write_filter *f, const void *buff,
size_t length)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct lz4 *lz4 = f->data;
- return __archive_write_program_write(f, data->pdata, buff, length);
+ return __archive_write_program_write(f, lz4->pdata, buff, length);
}
static int
archive_filter_lz4_close(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct lz4 *lz4 = f->data;
- return __archive_write_program_close(f, data->pdata);
+ return __archive_write_program_close(f, lz4->pdata);
}
-static int
-archive_filter_lz4_free(struct archive_write_filter *f)
+static void
+free_data(struct lz4 *lz4)
{
- struct private_data *data = (struct private_data *)f->data;
-
- __archive_write_program_free(data->pdata);
- free(data);
- return (ARCHIVE_OK);
+ if (lz4 != NULL) {
+ __archive_write_program_free(lz4->pdata);
+ free(lz4);
+ }
}
#endif /* HAVE_LIBLZ4 */
diff --git a/contrib/libarchive/libarchive/archive_write_add_filter_lzop.c b/contrib/libarchive/libarchive/archive_write_add_filter_lzop.c
index 42d62db63a13..3ed721e1ea1b 100644
--- a/contrib/libarchive/libarchive/archive_write_add_filter_lzop.c
+++ b/contrib/libarchive/libarchive/archive_write_add_filter_lzop.c
@@ -55,7 +55,7 @@ enum lzo_method {
METHOD_LZO1X_1_15 = 2,
METHOD_LZO1X_999 = 3
};
-struct write_lzop {
+struct lzop {
int compression_level;
#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
unsigned char *uncompressed;
@@ -80,6 +80,7 @@ static int archive_write_lzop_write(struct archive_write_filter *,
const void *, size_t);
static int archive_write_lzop_close(struct archive_write_filter *);
static int archive_write_lzop_free(struct archive_write_filter *);
+static void free_data(struct lzop *);
#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
/* Maximum block size. */
@@ -133,73 +134,72 @@ static const unsigned char header[] = {
#endif
int
-archive_write_add_filter_lzop(struct archive *_a)
+archive_write_add_filter_lzop(struct archive *a)
{
- struct archive_write_filter *f = __archive_write_allocate_filter(_a);
- struct write_lzop *data;
+ struct archive_write_filter *f;
+ struct lzop *lzop;
+ int r;
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_add_filter_lzop");
- data = calloc(1, sizeof(*data));
- if (data == NULL) {
- archive_set_error(_a, ENOMEM, "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
-
- f->name = "lzop";
- f->code = ARCHIVE_FILTER_LZOP;
- f->data = data;
- f->open = archive_write_lzop_open;
- f->options = archive_write_lzop_options;
- f->write = archive_write_lzop_write;
- f->close = archive_write_lzop_close;
- f->free = archive_write_lzop_free;
+ lzop = calloc(1, sizeof(*lzop));
+ if (lzop == NULL)
+ goto memerr;
#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
if (lzo_init() != LZO_E_OK) {
- free(data);
- archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+ free_data(lzop);
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
"lzo_init(type check) failed");
return (ARCHIVE_FATAL);
}
if (lzo_version() < 0x940) {
- free(data);
- archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+ free_data(lzop);
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
"liblzo library is too old(%s < 0.940)",
lzo_version_string());
return (ARCHIVE_FATAL);
}
- data->compression_level = 5;
- return (ARCHIVE_OK);
+ lzop->compression_level = 5;
+
+ r = ARCHIVE_OK;
#else
- data->pdata = __archive_write_program_allocate("lzop");
- if (data->pdata == NULL) {
- free(data);
- archive_set_error(_a, ENOMEM, "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- data->compression_level = 0;
+ lzop->pdata = __archive_write_program_allocate("lzop");
+ if (lzop->pdata == NULL)
+ goto memerr;
+ lzop->compression_level = 0;
+
/* Note: We return "warn" to inform of using an external lzop
* program. */
- archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
"Using external lzop program for lzop compression");
- return (ARCHIVE_WARN);
+ r = ARCHIVE_WARN;
#endif
+
+ f = __archive_write_allocate_filter(a);
+ if (f == NULL)
+ goto memerr;
+ f->name = "lzop";
+ f->code = ARCHIVE_FILTER_LZOP;
+ f->data = lzop;
+ f->options = archive_write_lzop_options;
+ f->open = archive_write_lzop_open;
+ f->write = archive_write_lzop_write;
+ f->close = archive_write_lzop_close;
+ f->free = archive_write_lzop_free;
+
+ return (r);
+memerr:
+ free_data(lzop);
+ archive_set_error(a, ENOMEM, "Can't allocate memory");
+ return (ARCHIVE_FATAL);
}
static int
archive_write_lzop_free(struct archive_write_filter *f)
{
- struct write_lzop *data = (struct write_lzop *)f->data;
-
-#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
- free(data->uncompressed);
- free(data->compressed);
- free(data->work_buffer);
-#else
- __archive_write_program_free(data->pdata);
-#endif
- free(data);
+ free_data(f->data);
+ f->data = NULL;
return (ARCHIVE_OK);
}
@@ -207,7 +207,7 @@ static int
archive_write_lzop_options(struct archive_write_filter *f, const char *key,
const char *value)
{
- struct write_lzop *data = (struct write_lzop *)f->data;
+ struct lzop *lzop = f->data;
if (strcmp(key, "compression-level") == 0) {
if (value == NULL || !(value[0] >= '1' && value[0] <= '9') ||
@@ -216,7 +216,7 @@ archive_write_lzop_options(struct archive_write_filter *f, const char *key,
"compression-level invalid");
return (ARCHIVE_FAILED);
}
- data->compression_level = value[0] - '0';
+ lzop->compression_level = value[0] - '0';
return (ARCHIVE_OK);
}
/* Note: The "warn" return is just to inform the options
@@ -229,58 +229,58 @@ archive_write_lzop_options(struct archive_write_filter *f, const char *key,
static int
archive_write_lzop_open(struct archive_write_filter *f)
{
- struct write_lzop *data = (struct write_lzop *)f->data;
+ struct lzop *lzop = f->data;
- switch (data->compression_level) {
+ switch (lzop->compression_level) {
case 1:
- data->method = METHOD_LZO1X_1_15; data->level = 1; break;
+ lzop->method = METHOD_LZO1X_1_15; lzop->level = 1; break;
default:
case 2: case 3: case 4: case 5: case 6:
- data->method = METHOD_LZO1X_1; data->level = 5; break;
+ lzop->method = METHOD_LZO1X_1; lzop->level = 5; break;
case 7:
- data->method = METHOD_LZO1X_999; data->level = 7; break;
+ lzop->method = METHOD_LZO1X_999; lzop->level = 7; break;
case 8:
- data->method = METHOD_LZO1X_999; data->level = 8; break;
+ lzop->method = METHOD_LZO1X_999; lzop->level = 8; break;
case 9:
- data->method = METHOD_LZO1X_999; data->level = 9; break;
+ lzop->method = METHOD_LZO1X_999; lzop->level = 9; break;
}
- switch (data->method) {
+ switch (lzop->method) {
case METHOD_LZO1X_1:
- data->work_buffer_size = LZO1X_1_MEM_COMPRESS; break;
+ lzop->work_buffer_size = LZO1X_1_MEM_COMPRESS; break;
case METHOD_LZO1X_1_15:
- data->work_buffer_size = LZO1X_1_15_MEM_COMPRESS; break;
+ lzop->work_buffer_size = LZO1X_1_15_MEM_COMPRESS; break;
case METHOD_LZO1X_999:
- data->work_buffer_size = LZO1X_999_MEM_COMPRESS; break;
+ lzop->work_buffer_size = LZO1X_999_MEM_COMPRESS; break;
}
- if (data->work_buffer == NULL) {
- data->work_buffer = (lzo_voidp)malloc(data->work_buffer_size);
- if (data->work_buffer == NULL) {
+ if (lzop->work_buffer == NULL) {
+ lzop->work_buffer = (lzo_voidp)malloc(lzop->work_buffer_size);
+ if (lzop->work_buffer == NULL) {
archive_set_error(f->archive, ENOMEM,
"Can't allocate data for compression buffer");
return (ARCHIVE_FATAL);
}
}
- if (data->compressed == NULL) {
- data->compressed_buffer_size = sizeof(header) +
+ if (lzop->compressed == NULL) {
+ lzop->compressed_buffer_size = sizeof(header) +
BLOCK_SIZE + (BLOCK_SIZE >> 4) + 64 + 3;
- data->compressed = (unsigned char *)
- malloc(data->compressed_buffer_size);
- if (data->compressed == NULL) {
+ lzop->compressed = (unsigned char *)
+ malloc(lzop->compressed_buffer_size);
+ if (lzop->compressed == NULL) {
archive_set_error(f->archive, ENOMEM,
"Can't allocate data for compression buffer");
return (ARCHIVE_FATAL);
}
}
- if (data->uncompressed == NULL) {
- data->uncompressed_buffer_size = BLOCK_SIZE;
- data->uncompressed = (unsigned char *)
- malloc(data->uncompressed_buffer_size);
- if (data->uncompressed == NULL) {
+ if (lzop->uncompressed == NULL) {
+ lzop->uncompressed_buffer_size = BLOCK_SIZE;
+ lzop->uncompressed = (unsigned char *)
+ malloc(lzop->uncompressed_buffer_size);
+ if (lzop->uncompressed == NULL) {
archive_set_error(f->archive, ENOMEM,
"Can't allocate data for compression buffer");
return (ARCHIVE_FATAL);
}
- data->uncompressed_avail_bytes = BLOCK_SIZE;
+ lzop->uncompressed_avail_bytes = BLOCK_SIZE;
}
return (ARCHIVE_OK);
}
@@ -288,68 +288,68 @@ archive_write_lzop_open(struct archive_write_filter *f)
static int
make_header(struct archive_write_filter *f)
{
- struct write_lzop *data = (struct write_lzop *)f->data;
+ struct lzop *lzop = f->data;
int64_t t;
uint32_t checksum;
- memcpy(data->compressed, header, sizeof(header));
+ memcpy(lzop->compressed, header, sizeof(header));
/* Overwrite library version. */
- data->compressed[HEADER_LIBVERSION] = (unsigned char )
+ lzop->compressed[HEADER_LIBVERSION] = (unsigned char )
(lzo_version() >> 8) & 0xff;
- data->compressed[HEADER_LIBVERSION + 1] = (unsigned char )
+ lzop->compressed[HEADER_LIBVERSION + 1] = (unsigned char )
lzo_version() & 0xff;
/* Overwrite method and level. */
- data->compressed[HEADER_METHOD] = (unsigned char)data->method;
- data->compressed[HEADER_LEVEL] = data->level;
+ lzop->compressed[HEADER_METHOD] = (unsigned char)lzop->method;
+ lzop->compressed[HEADER_LEVEL] = lzop->level;
/* Overwrite mtime with current time. */
t = (int64_t)time(NULL);
- archive_be32enc(&data->compressed[HEADER_MTIME_LOW],
+ archive_be32enc(&lzop->compressed[HEADER_MTIME_LOW],
(uint32_t)(t & 0xffffffff));
- archive_be32enc(&data->compressed[HEADER_MTIME_HIGH],
+ archive_be32enc(&lzop->compressed[HEADER_MTIME_HIGH],
(uint32_t)((t >> 32) & 0xffffffff));
/* Overwrite header checksum with calculated value. */
- checksum = lzo_adler32(1, data->compressed + HEADER_VERSION,
+ checksum = lzo_adler32(1, lzop->compressed + HEADER_VERSION,
(lzo_uint)(HEADER_H_CHECKSUM - HEADER_VERSION));
- archive_be32enc(&data->compressed[HEADER_H_CHECKSUM], checksum);
+ archive_be32enc(&lzop->compressed[HEADER_H_CHECKSUM], checksum);
return (sizeof(header));
}
static int
drive_compressor(struct archive_write_filter *f)
{
- struct write_lzop *data = (struct write_lzop *)f->data;
+ struct lzop *lzop = f->data;
unsigned char *p;
const int block_info_bytes = 12;
int header_bytes, r;
lzo_uint usize, csize;
uint32_t checksum;
- if (!data->header_written) {
+ if (!lzop->header_written) {
header_bytes = make_header(f);
- data->header_written = 1;
+ lzop->header_written = 1;
} else
header_bytes = 0;
- p = data->compressed;
+ p = lzop->compressed;
usize = (lzo_uint)
- (data->uncompressed_buffer_size - data->uncompressed_avail_bytes);
+ (lzop->uncompressed_buffer_size - lzop->uncompressed_avail_bytes);
csize = 0;
- switch (data->method) {
+ switch (lzop->method) {
default:
case METHOD_LZO1X_1:
- r = lzo1x_1_compress(data->uncompressed, usize,
+ r = lzo1x_1_compress(lzop->uncompressed, usize,
p + header_bytes + block_info_bytes, &csize,
- data->work_buffer);
+ lzop->work_buffer);
break;
case METHOD_LZO1X_1_15:
- r = lzo1x_1_15_compress(data->uncompressed, usize,
+ r = lzo1x_1_15_compress(lzop->uncompressed, usize,
p + header_bytes + block_info_bytes, &csize,
- data->work_buffer);
+ lzop->work_buffer);
break;
case METHOD_LZO1X_999:
- r = lzo1x_999_compress_level(data->uncompressed, usize,
+ r = lzo1x_999_compress_level(lzop->uncompressed, usize,
p + header_bytes + block_info_bytes, &csize,
- data->work_buffer, NULL, 0, 0, data->level);
+ lzop->work_buffer, NULL, 0, 0, lzop->level);
break;
}
if (r != LZO_E_OK) {
@@ -361,13 +361,13 @@ drive_compressor(struct archive_write_filter *f)
/* Store uncompressed size. */
archive_be32enc(p + header_bytes, (uint32_t)usize);
/* Store the checksum of the uncompressed data. */
- checksum = lzo_adler32(1, data->uncompressed, usize);
+ checksum = lzo_adler32(1, lzop->uncompressed, usize);
archive_be32enc(p + header_bytes + 8, checksum);
if (csize < usize) {
/* Store compressed size. */
archive_be32enc(p + header_bytes + 4, (uint32_t)csize);
- r = __archive_write_filter(f->next_filter, data->compressed,
+ r = __archive_write_filter(f->next_filter, lzop->compressed,
header_bytes + block_info_bytes + csize);
} else {
/*
@@ -375,11 +375,11 @@ drive_compressor(struct archive_write_filter *f)
*/
/* Store uncompressed size as compressed size. */
archive_be32enc(p + header_bytes + 4, (uint32_t)usize);
- r = __archive_write_filter(f->next_filter, data->compressed,
+ r = __archive_write_filter(f->next_filter, lzop->compressed,
header_bytes + block_info_bytes);
if (r != ARCHIVE_OK)
return (ARCHIVE_FATAL);
- r = __archive_write_filter(f->next_filter, data->uncompressed,
+ r = __archive_write_filter(f->next_filter, lzop->uncompressed,
usize);
}
@@ -392,30 +392,30 @@ static int
archive_write_lzop_write(struct archive_write_filter *f,
const void *buff, size_t length)
{
- struct write_lzop *data = (struct write_lzop *)f->data;
+ struct lzop *lzop = f->data;
const char *p = buff;
int r;
do {
- if (data->uncompressed_avail_bytes > length) {
- memcpy(data->uncompressed
- + data->uncompressed_buffer_size
- - data->uncompressed_avail_bytes,
+ if (lzop->uncompressed_avail_bytes > length) {
+ memcpy(lzop->uncompressed
+ + lzop->uncompressed_buffer_size
+ - lzop->uncompressed_avail_bytes,
p, length);
- data->uncompressed_avail_bytes -= length;
+ lzop->uncompressed_avail_bytes -= length;
return (ARCHIVE_OK);
}
- memcpy(data->uncompressed + data->uncompressed_buffer_size
- - data->uncompressed_avail_bytes,
- p, data->uncompressed_avail_bytes);
- length -= data->uncompressed_avail_bytes;
- p += data->uncompressed_avail_bytes;
- data->uncompressed_avail_bytes = 0;
+ memcpy(lzop->uncompressed + lzop->uncompressed_buffer_size
+ - lzop->uncompressed_avail_bytes,
+ p, lzop->uncompressed_avail_bytes);
+ length -= lzop->uncompressed_avail_bytes;
+ p += lzop->uncompressed_avail_bytes;
+ lzop->uncompressed_avail_bytes = 0;
r = drive_compressor(f);
if (r != ARCHIVE_OK) return (r);
- data->uncompressed_avail_bytes = BLOCK_SIZE;
+ lzop->uncompressed_avail_bytes = BLOCK_SIZE;
} while (length);
return (ARCHIVE_OK);
@@ -424,11 +424,11 @@ archive_write_lzop_write(struct archive_write_filter *f,
static int
archive_write_lzop_close(struct archive_write_filter *f)
{
- struct write_lzop *data = (struct write_lzop *)f->data;
+ struct lzop *lzop = f->data;
const uint32_t endmark = 0;
int r;
- if (data->uncompressed_avail_bytes < BLOCK_SIZE) {
+ if (lzop->uncompressed_avail_bytes < BLOCK_SIZE) {
/* Compress and output remaining data. */
r = drive_compressor(f);
if (r != ARCHIVE_OK)
@@ -439,24 +439,35 @@ archive_write_lzop_close(struct archive_write_filter *f)
return __archive_write_filter(f->next_filter, &endmark, sizeof(endmark));
}
+static void
+free_data(struct lzop *lzop)
+{
+ if (lzop != NULL) {
+ free(lzop->uncompressed);
+ free(lzop->compressed);
+ free(lzop->work_buffer);
+ free(lzop);
+ }
+}
+
#else
static int
archive_write_lzop_open(struct archive_write_filter *f)
{
- struct write_lzop *data = (struct write_lzop *)f->data;
+ struct lzop *lzop = f->data;
struct archive_string as;
int r;
archive_string_init(&as);
archive_strcpy(&as, "lzop");
/* Specify compression level. */
- if (data->compression_level > 0) {
+ if (lzop->compression_level > 0) {
archive_strappend_char(&as, ' ');
archive_strappend_char(&as, '-');
- archive_strappend_char(&as, '0' + data->compression_level);
+ archive_strappend_char(&as, '0' + lzop->compression_level);
}
- r = __archive_write_program_open(f, data->pdata, as.s);
+ r = __archive_write_program_open(f, lzop->pdata, as.s);
archive_string_free(&as);
return (r);
}
@@ -465,16 +476,25 @@ static int
archive_write_lzop_write(struct archive_write_filter *f,
const void *buff, size_t length)
{
- struct write_lzop *data = (struct write_lzop *)f->data;
+ struct lzop *lzop = f->data;
- return __archive_write_program_write(f, data->pdata, buff, length);
+ return __archive_write_program_write(f, lzop->pdata, buff, length);
}
static int
archive_write_lzop_close(struct archive_write_filter *f)
{
- struct write_lzop *data = (struct write_lzop *)f->data;
+ struct lzop *lzop = f->data;
- return __archive_write_program_close(f, data->pdata);
+ return __archive_write_program_close(f, lzop->pdata);
+}
+
+static void
+free_data(struct lzop *lzop)
+{
+ if (lzop != NULL) {
+ __archive_write_program_free(lzop->pdata);
+ free(lzop);
+ }
}
#endif
diff --git a/contrib/libarchive/libarchive/archive_write_add_filter_program.c b/contrib/libarchive/libarchive/archive_write_add_filter_program.c
index f12db3373883..ee0869717e95 100644
--- a/contrib/libarchive/libarchive/archive_write_add_filter_program.c
+++ b/contrib/libarchive/libarchive/archive_write_add_filter_program.c
@@ -70,7 +70,7 @@ struct archive_write_program_data {
char *program_name;
};
-struct private_data {
+struct program {
struct archive_write_program_data *pdata;
struct archive_string description;
char *cmd;
@@ -81,51 +81,53 @@ static int archive_compressor_program_write(struct archive_write_filter *,
const void *, size_t);
static int archive_compressor_program_close(struct archive_write_filter *);
static int archive_compressor_program_free(struct archive_write_filter *);
+static void free_data(struct program *);
/*
* Add a filter to this write handle that passes all data through an
* external program.
*/
int
-archive_write_add_filter_program(struct archive *_a, const char *cmd)
+archive_write_add_filter_program(struct archive *a, const char *cmd)
{
- struct archive_write_filter *f = __archive_write_allocate_filter(_a);
- struct private_data *data;
+ struct archive_write_filter *f;
+ struct program *program;
static const char prefix[] = "Program: ";
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_add_filter_program");
- f->data = calloc(1, sizeof(*data));
- if (f->data == NULL)
+ program = calloc(1, sizeof(*program));
+ if (program == NULL)
goto memerr;
- data = (struct private_data *)f->data;
-
- data->cmd = strdup(cmd);
- if (data->cmd == NULL)
+ program->cmd = strdup(cmd);
+ if (program->cmd == NULL)
goto memerr;
-
- data->pdata = __archive_write_program_allocate(cmd);
- if (data->pdata == NULL)
+ program->pdata = __archive_write_program_allocate(cmd);
+ if (program->pdata == NULL)
goto memerr;
-
/* Make up a description string. */
- if (archive_string_ensure(&data->description,
+ if (archive_string_ensure(&program->description,
strlen(prefix) + strlen(cmd) + 1) == NULL)
goto memerr;
- archive_strcpy(&data->description, prefix);
- archive_strcat(&data->description, cmd);
+ archive_strcpy(&program->description, prefix);
+ archive_strcat(&program->description, cmd);
- f->name = data->description.s;
+ f = __archive_write_allocate_filter(a);
+ if (f == NULL)
+ goto memerr;
+ f->name = program->description.s;
f->code = ARCHIVE_FILTER_PROGRAM;
+ f->data = program;
f->open = archive_compressor_program_open;
f->write = archive_compressor_program_write;
f->close = archive_compressor_program_close;
f->free = archive_compressor_program_free;
+
return (ARCHIVE_OK);
memerr:
- archive_compressor_program_free(f);
- archive_set_error(_a, ENOMEM,
+ free_data(program);
+ archive_set_error(a, ENOMEM,
"Can't allocate memory for filter program");
return (ARCHIVE_FATAL);
}
@@ -133,40 +135,33 @@ memerr:
static int
archive_compressor_program_open(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct program *program = f->data;
- return __archive_write_program_open(f, data->pdata, data->cmd);
+ return __archive_write_program_open(f, program->pdata, program->cmd);
}
static int
archive_compressor_program_write(struct archive_write_filter *f,
const void *buff, size_t length)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct program *program = f->data;
- return __archive_write_program_write(f, data->pdata, buff, length);
+ return __archive_write_program_write(f, program->pdata, buff, length);
}
static int
archive_compressor_program_close(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct program *program = f->data;
- return __archive_write_program_close(f, data->pdata);
+ return __archive_write_program_close(f, program->pdata);
}
static int
archive_compressor_program_free(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
-
- if (data) {
- free(data->cmd);
- archive_string_free(&data->description);
- __archive_write_program_free(data->pdata);
- free(data);
- f->data = NULL;
- }
+ free_data(f->data);
+ f->data = NULL;
return (ARCHIVE_OK);
}
@@ -184,6 +179,10 @@ __archive_write_program_allocate(const char *program)
data->child_stdin = -1;
data->child_stdout = -1;
data->program_name = strdup(program);
+ if (data->program_name == NULL) {
+ free(data);
+ return (NULL);
+ }
return (data);
}
@@ -387,3 +386,13 @@ cleanup:
return ret;
}
+static void
+free_data(struct program *program)
+{
+ if (program) {
+ free(program->cmd);
+ archive_string_free(&program->description);
+ __archive_write_program_free(program->pdata);
+ free(program);
+ }
+}
diff --git a/contrib/libarchive/libarchive/archive_write_add_filter_uuencode.c b/contrib/libarchive/libarchive/archive_write_add_filter_uuencode.c
index d25236fa9b26..83ec2ebffb9f 100644
--- a/contrib/libarchive/libarchive/archive_write_add_filter_uuencode.c
+++ b/contrib/libarchive/libarchive/archive_write_add_filter_uuencode.c
@@ -39,13 +39,14 @@
#endif
#include "archive.h"
+#include "archive_integer.h"
#include "archive_private.h"
#include "archive_string.h"
#include "archive_write_private.h"
#define LBYTES 45
-struct private_uuencode {
+struct uuencode {
int mode;
struct archive_string name;
struct archive_string encoded_buff;
@@ -63,39 +64,44 @@ static int archive_filter_uuencode_close(struct archive_write_filter *);
static int archive_filter_uuencode_free(struct archive_write_filter *);
static void uu_encode(struct archive_string *, const unsigned char *, size_t);
static int64_t atol8(const char *, size_t);
+static void free_data(struct uuencode *);
/*
* Add a compress filter to this write handle.
*/
int
-archive_write_add_filter_uuencode(struct archive *_a)
+archive_write_add_filter_uuencode(struct archive *a)
{
- struct archive_write *a = (struct archive_write *)_a;
- struct archive_write_filter *f = __archive_write_allocate_filter(_a);
- struct private_uuencode *state;
+ struct archive_write_filter *f;
+ struct uuencode *uuencode;
- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_add_filter_uu");
+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_write_add_filter_uuencode");
- state = calloc(1, sizeof(*state));
- if (state == NULL) {
- archive_set_error(f->archive, ENOMEM,
- "Can't allocate data for uuencode filter");
- return (ARCHIVE_FATAL);
- }
- archive_strcpy(&state->name, "-");
- state->mode = 0644;
+ uuencode = calloc(1, sizeof(*uuencode));
+ if (uuencode == NULL)
+ goto memerr;
+ archive_strcpy(&uuencode->name, "-");
+ uuencode->mode = 0644;
- f->data = state;
+ f = __archive_write_allocate_filter(a);
+ if (f == NULL)
+ goto memerr;
f->name = "uuencode";
f->code = ARCHIVE_FILTER_UU;
- f->open = archive_filter_uuencode_open;
+ f->data = uuencode;
f->options = archive_filter_uuencode_options;
+ f->open = archive_filter_uuencode_open;
f->write = archive_filter_uuencode_write;
f->close = archive_filter_uuencode_close;
f->free = archive_filter_uuencode_free;
return (ARCHIVE_OK);
+memerr:
+ free_data(uuencode);
+ archive_set_error(a, ENOMEM,
+ "Can't allocate data for uuencode filter");
+ return (ARCHIVE_FATAL);
}
/*
@@ -105,7 +111,7 @@ static int
archive_filter_uuencode_options(struct archive_write_filter *f, const char *key,
const char *value)
{
- struct private_uuencode *state = (struct private_uuencode *)f->data;
+ struct uuencode *uuencode = f->data;
if (strcmp(key, "mode") == 0) {
int64_t val;
@@ -121,7 +127,7 @@ archive_filter_uuencode_options(struct archive_write_filter *f, const char *key,
"invalid mode option");
return (ARCHIVE_FAILED);
}
- state->mode = (int)val & 0777;
+ uuencode->mode = (int)val & 0777;
return (ARCHIVE_OK);
} else if (strcmp(key, "name") == 0) {
if (value == NULL) {
@@ -129,7 +135,7 @@ archive_filter_uuencode_options(struct archive_write_filter *f, const char *key,
"name option requires a string");
return (ARCHIVE_FAILED);
}
- archive_strcpy(&state->name, value);
+ archive_strcpy(&uuencode->name, value);
return (ARCHIVE_OK);
}
@@ -145,7 +151,7 @@ archive_filter_uuencode_options(struct archive_write_filter *f, const char *key,
static int
archive_filter_uuencode_open(struct archive_write_filter *f)
{
- struct private_uuencode *state = (struct private_uuencode *)f->data;
+ struct uuencode *uuencode = f->data;
size_t bs = 65536, bpb;
if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
@@ -158,18 +164,17 @@ archive_filter_uuencode_open(struct archive_write_filter *f)
bs -= bs % bpb;
}
- state->bs = bs;
- if (archive_string_ensure(&state->encoded_buff, bs + 512) == NULL) {
+ uuencode->bs = bs;
+ if (archive_string_ensure(&uuencode->encoded_buff, bs + 512) == NULL) {
archive_set_error(f->archive, ENOMEM,
"Can't allocate data for uuencode buffer");
return (ARCHIVE_FATAL);
}
- archive_string_sprintf(&state->encoded_buff, "begin %o %s\n",
- (unsigned int)state->mode, state->name.s);
+ archive_string_sprintf(&uuencode->encoded_buff, "begin %o %s\n",
+ (unsigned int)uuencode->mode, uuencode->name.s);
- f->data = state;
- return (0);
+ return (ARCHIVE_OK);
}
static void
@@ -215,39 +220,39 @@ static int
archive_filter_uuencode_write(struct archive_write_filter *f, const void *buff,
size_t length)
{
- struct private_uuencode *state = (struct private_uuencode *)f->data;
+ struct uuencode *uuencode = f->data;
const unsigned char *p = buff;
int ret = ARCHIVE_OK;
if (length == 0)
return (ret);
- if (state->hold_len) {
- while (state->hold_len < LBYTES && length > 0) {
- state->hold[state->hold_len++] = *p++;
+ if (uuencode->hold_len) {
+ while (uuencode->hold_len < LBYTES && length > 0) {
+ uuencode->hold[uuencode->hold_len++] = *p++;
length--;
}
- if (state->hold_len < LBYTES)
+ if (uuencode->hold_len < LBYTES)
return (ret);
- uu_encode(&state->encoded_buff, state->hold, LBYTES);
- state->hold_len = 0;
+ uu_encode(&uuencode->encoded_buff, uuencode->hold, LBYTES);
+ uuencode->hold_len = 0;
}
for (; length >= LBYTES; length -= LBYTES, p += LBYTES)
- uu_encode(&state->encoded_buff, p, LBYTES);
+ uu_encode(&uuencode->encoded_buff, p, LBYTES);
/* Save remaining bytes. */
if (length > 0) {
- memcpy(state->hold, p, length);
- state->hold_len = length;
+ memcpy(uuencode->hold, p, length);
+ uuencode->hold_len = length;
}
- while (archive_strlen(&state->encoded_buff) >= state->bs) {
+ while (archive_strlen(&uuencode->encoded_buff) >= uuencode->bs) {
ret = __archive_write_filter(f->next_filter,
- state->encoded_buff.s, state->bs);
- memmove(state->encoded_buff.s,
- state->encoded_buff.s + state->bs,
- state->encoded_buff.length - state->bs);
- state->encoded_buff.length -= state->bs;
+ uuencode->encoded_buff.s, uuencode->bs);
+ memmove(uuencode->encoded_buff.s,
+ uuencode->encoded_buff.s + uuencode->bs,
+ uuencode->encoded_buff.length - uuencode->bs);
+ uuencode->encoded_buff.length -= uuencode->bs;
}
return (ret);
@@ -260,26 +265,24 @@ archive_filter_uuencode_write(struct archive_write_filter *f, const void *buff,
static int
archive_filter_uuencode_close(struct archive_write_filter *f)
{
- struct private_uuencode *state = (struct private_uuencode *)f->data;
+ struct uuencode *uuencode = f->data;
/* Flush remaining bytes. */
- if (state->hold_len != 0)
- uu_encode(&state->encoded_buff, state->hold, state->hold_len);
- archive_string_sprintf(&state->encoded_buff, "`\nend\n");
+ if (uuencode->hold_len != 0)
+ uu_encode(&uuencode->encoded_buff, uuencode->hold,
+ uuencode->hold_len);
+ archive_string_sprintf(&uuencode->encoded_buff, "`\nend\n");
/* Write the last block */
archive_write_set_bytes_in_last_block(f->archive, 1);
return __archive_write_filter(f->next_filter,
- state->encoded_buff.s, archive_strlen(&state->encoded_buff));
+ uuencode->encoded_buff.s, archive_strlen(&uuencode->encoded_buff));
}
static int
archive_filter_uuencode_free(struct archive_write_filter *f)
{
- struct private_uuencode *state = (struct private_uuencode *)f->data;
-
- archive_string_free(&state->name);
- archive_string_free(&state->encoded_buff);
- free(state);
+ free_data(f->data);
+ f->data = NULL;
return (ARCHIVE_OK);
}
@@ -299,11 +302,19 @@ atol8(const char *p, size_t char_cnt)
else
return (-1);
p++;
- if (l > (INT64_MAX >> 3))
+ if (archive_ckd_mul_i64(&l, l, 8) ||
+ archive_ckd_add_i64(&l, l, digit))
return (-1);
- l <<= 3;
- l |= digit;
}
return (l);
}
+static void
+free_data(struct uuencode *uuencode)
+{
+ if (uuencode != NULL) {
+ archive_string_free(&uuencode->name);
+ archive_string_free(&uuencode->encoded_buff);
+ free(uuencode);
+ }
+}
diff --git a/contrib/libarchive/libarchive/archive_write_add_filter_xz.c b/contrib/libarchive/libarchive/archive_write_add_filter_xz.c
index 56cf02070754..599ee413b0e1 100644
--- a/contrib/libarchive/libarchive/archive_write_add_filter_xz.c
+++ b/contrib/libarchive/libarchive/archive_write_add_filter_xz.c
@@ -99,7 +99,7 @@ archive_write_add_filter_lzip(struct archive *a)
#else
/* Don't compile this if we don't have liblzma. */
-struct private_data {
+struct xz {
int compression_level;
uint32_t threads;
lzma_stream stream;
@@ -121,7 +121,8 @@ static int archive_compressor_xz_write(struct archive_write_filter *,
static int archive_compressor_xz_close(struct archive_write_filter *);
static int archive_compressor_xz_free(struct archive_write_filter *);
static int drive_compressor(struct archive_write_filter *,
- struct private_data *, int finishing);
+ struct xz *, int finishing);
+static void free_data(struct xz *);
struct option_value {
uint32_t dict_size;
@@ -142,85 +143,72 @@ static const struct option_value option_values[] = {
};
static int
-common_setup(struct archive_write_filter *f)
+common_setup(struct archive *a, const char *name, int code)
{
- struct private_data *data;
- struct archive_write *a = (struct archive_write *)f->archive;
- data = calloc(1, sizeof(*data));
- if (data == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- f->data = data;
- data->compression_level = LZMA_PRESET_DEFAULT;
- data->threads = 1;
- f->open = &archive_compressor_xz_open;
+ struct xz *xz;
+ struct archive_write_filter *f;
+
+ xz = calloc(1, sizeof(*xz));
+ if (xz == NULL)
+ goto memerr;
+ xz->compression_level = LZMA_PRESET_DEFAULT;
+ xz->threads = 1;
+
+ f = __archive_write_allocate_filter(a);
+ if (f == NULL)
+ goto memerr;
+ f->name = name;
+ f->code = code;
+ f->data = xz;
+ f->options = archive_compressor_xz_options;
+ f->open = archive_compressor_xz_open;
+ f->write = archive_compressor_xz_write;
f->close = archive_compressor_xz_close;
f->free = archive_compressor_xz_free;
- f->options = &archive_compressor_xz_options;
+
return (ARCHIVE_OK);
+memerr:
+ free_data(xz);
+ archive_set_error(a, ENOMEM, "Out of memory");
+ return (ARCHIVE_FATAL);
}
/*
* Add an xz compression filter to this write handle.
*/
int
-archive_write_add_filter_xz(struct archive *_a)
+archive_write_add_filter_xz(struct archive *a)
{
- struct archive_write_filter *f;
- int r;
-
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_add_filter_xz");
- f = __archive_write_allocate_filter(_a);
- r = common_setup(f);
- if (r == ARCHIVE_OK) {
- f->code = ARCHIVE_FILTER_XZ;
- f->name = "xz";
- }
- return (r);
+
+ return common_setup(a, "xz", ARCHIVE_FILTER_XZ);
}
/* LZMA is handled identically, we just need a different compression
* code set. (The liblzma setup looks at the code to determine
* the one place that XZ and LZMA require different handling.) */
int
-archive_write_add_filter_lzma(struct archive *_a)
+archive_write_add_filter_lzma(struct archive *a)
{
- struct archive_write_filter *f;
- int r;
-
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_add_filter_lzma");
- f = __archive_write_allocate_filter(_a);
- r = common_setup(f);
- if (r == ARCHIVE_OK) {
- f->code = ARCHIVE_FILTER_LZMA;
- f->name = "lzma";
- }
- return (r);
+
+ return common_setup(a, "lzma", ARCHIVE_FILTER_LZMA);
}
int
-archive_write_add_filter_lzip(struct archive *_a)
+archive_write_add_filter_lzip(struct archive *a)
{
- struct archive_write_filter *f;
- int r;
-
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_add_filter_lzip");
- f = __archive_write_allocate_filter(_a);
- r = common_setup(f);
- if (r == ARCHIVE_OK) {
- f->code = ARCHIVE_FILTER_LZIP;
- f->name = "lzip";
- }
- return (r);
+
+ return common_setup(a, "lzip", ARCHIVE_FILTER_LZIP);
}
static int
archive_compressor_xz_init_stream(struct archive_write_filter *f,
- struct private_data *data)
+ struct xz *xz)
{
static const lzma_stream lzma_stream_init_data = LZMA_STREAM_INIT;
int ret;
@@ -228,27 +216,27 @@ archive_compressor_xz_init_stream(struct archive_write_filter *f,
lzma_mt mt_options;
#endif
- data->stream = lzma_stream_init_data;
- data->stream.next_out = data->compressed;
- data->stream.avail_out = data->compressed_buffer_size;
+ xz->stream = lzma_stream_init_data;
+ xz->stream.next_out = xz->compressed;
+ xz->stream.avail_out = xz->compressed_buffer_size;
if (f->code == ARCHIVE_FILTER_XZ) {
#ifdef HAVE_LZMA_STREAM_ENCODER_MT
- if (data->threads != 1) {
+ if (xz->threads != 1) {
memset(&mt_options, 0, sizeof(mt_options));
- mt_options.threads = data->threads;
+ mt_options.threads = xz->threads;
mt_options.timeout = 300;
- mt_options.filters = data->lzmafilters;
+ mt_options.filters = xz->lzmafilters;
mt_options.check = LZMA_CHECK_CRC64;
- ret = lzma_stream_encoder_mt(&(data->stream),
+ ret = lzma_stream_encoder_mt(&(xz->stream),
&mt_options);
} else
#endif
- ret = lzma_stream_encoder(&(data->stream),
- data->lzmafilters, LZMA_CHECK_CRC64);
+ ret = lzma_stream_encoder(&(xz->stream),
+ xz->lzmafilters, LZMA_CHECK_CRC64);
} else if (f->code == ARCHIVE_FILTER_LZMA) {
- ret = lzma_alone_encoder(&(data->stream), &data->lzma_opt);
+ ret = lzma_alone_encoder(&(xz->stream), &xz->lzma_opt);
} else { /* ARCHIVE_FILTER_LZIP */
- int dict_size = data->lzma_opt.dict_size;
+ int dict_size = xz->lzma_opt.dict_size;
int ds, log2dic, wedges;
/* Calculate a coded dictionary size */
@@ -270,18 +258,18 @@ archive_compressor_xz_init_stream(struct archive_write_filter *f,
wedges = 0;
ds = ((wedges << 5) & 0xe0) | (log2dic & 0x1f);
- data->crc32 = 0;
+ xz->crc32 = 0;
/* Make a header */
- data->compressed[0] = 0x4C;
- data->compressed[1] = 0x5A;
- data->compressed[2] = 0x49;
- data->compressed[3] = 0x50;
- data->compressed[4] = 1;/* Version */
- data->compressed[5] = (unsigned char)ds;
- data->stream.next_out += 6;
- data->stream.avail_out -= 6;
+ xz->compressed[0] = 0x4C;
+ xz->compressed[1] = 0x5A;
+ xz->compressed[2] = 0x49;
+ xz->compressed[3] = 0x50;
+ xz->compressed[4] = 1;/* Version */
+ xz->compressed[5] = (unsigned char)ds;
+ xz->stream.next_out += 6;
+ xz->stream.avail_out -= 6;
- ret = lzma_raw_encoder(&(data->stream), data->lzmafilters);
+ ret = lzma_raw_encoder(&(xz->stream), xz->lzmafilters);
}
if (ret == LZMA_OK)
return (ARCHIVE_OK);
@@ -307,10 +295,10 @@ archive_compressor_xz_init_stream(struct archive_write_filter *f,
static int
archive_compressor_xz_open(struct archive_write_filter *f)
{
- struct private_data *data = f->data;
+ struct xz *xz = f->data;
int ret;
- if (data->compressed == NULL) {
+ if (xz->compressed == NULL) {
size_t bs = 65536, bpb;
if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
/* Buffer size should be a multiple number of the bytes
@@ -321,49 +309,46 @@ archive_compressor_xz_open(struct archive_write_filter *f)
else if (bpb != 0)
bs -= bs % bpb;
}
- data->compressed_buffer_size = bs;
- data->compressed = malloc(data->compressed_buffer_size);
- if (data->compressed == NULL) {
+ xz->compressed_buffer_size = bs;
+ xz->compressed = malloc(xz->compressed_buffer_size);
+ if (xz->compressed == NULL) {
archive_set_error(f->archive, ENOMEM,
"Can't allocate data for compression buffer");
return (ARCHIVE_FATAL);
}
}
- f->write = archive_compressor_xz_write;
-
/* Initialize compression library. */
if (f->code == ARCHIVE_FILTER_LZIP) {
const struct option_value *val =
- &option_values[data->compression_level];
+ &option_values[xz->compression_level];
- data->lzma_opt.dict_size = val->dict_size;
- data->lzma_opt.preset_dict = NULL;
- data->lzma_opt.preset_dict_size = 0;
- data->lzma_opt.lc = LZMA_LC_DEFAULT;
- data->lzma_opt.lp = LZMA_LP_DEFAULT;
- data->lzma_opt.pb = LZMA_PB_DEFAULT;
- data->lzma_opt.mode =
- data->compression_level<= 2? LZMA_MODE_FAST:LZMA_MODE_NORMAL;
- data->lzma_opt.nice_len = val->nice_len;
- data->lzma_opt.mf = val->mf;
- data->lzma_opt.depth = 0;
- data->lzmafilters[0].id = LZMA_FILTER_LZMA1;
- data->lzmafilters[0].options = &data->lzma_opt;
- data->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
+ xz->lzma_opt.dict_size = val->dict_size;
+ xz->lzma_opt.preset_dict = NULL;
+ xz->lzma_opt.preset_dict_size = 0;
+ xz->lzma_opt.lc = LZMA_LC_DEFAULT;
+ xz->lzma_opt.lp = LZMA_LP_DEFAULT;
+ xz->lzma_opt.pb = LZMA_PB_DEFAULT;
+ xz->lzma_opt.mode =
+ xz->compression_level<= 2? LZMA_MODE_FAST:LZMA_MODE_NORMAL;
+ xz->lzma_opt.nice_len = val->nice_len;
+ xz->lzma_opt.mf = val->mf;
+ xz->lzma_opt.depth = 0;
+ xz->lzmafilters[0].id = LZMA_FILTER_LZMA1;
+ xz->lzmafilters[0].options = &xz->lzma_opt;
+ xz->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
} else {
- if (lzma_lzma_preset(&data->lzma_opt, data->compression_level)) {
+ if (lzma_lzma_preset(&xz->lzma_opt, xz->compression_level)) {
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library");
}
- data->lzmafilters[0].id = LZMA_FILTER_LZMA2;
- data->lzmafilters[0].options = &data->lzma_opt;
- data->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
+ xz->lzmafilters[0].id = LZMA_FILTER_LZMA2;
+ xz->lzmafilters[0].options = &xz->lzma_opt;
+ xz->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
}
- ret = archive_compressor_xz_init_stream(f, data);
+ ret = archive_compressor_xz_init_stream(f, xz);
if (ret == LZMA_OK) {
- f->data = data;
- return (0);
+ return (ARCHIVE_OK);
}
return (ARCHIVE_FATAL);
}
@@ -375,7 +360,7 @@ static int
archive_compressor_xz_options(struct archive_write_filter *f,
const char *key, const char *value)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct xz *xz = f->data;
if (strcmp(key, "compression-level") == 0) {
if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
@@ -384,9 +369,9 @@ archive_compressor_xz_options(struct archive_write_filter *f,
"compression-level invalid");
return (ARCHIVE_FAILED);
}
- data->compression_level = value[0] - '0';
- if (data->compression_level > 9)
- data->compression_level = 9;
+ xz->compression_level = value[0] - '0';
+ if (xz->compression_level > 9)
+ xz->compression_level = 9;
return (ARCHIVE_OK);
} else if (strcmp(key, "threads") == 0) {
char *endptr;
@@ -400,17 +385,17 @@ archive_compressor_xz_options(struct archive_write_filter *f,
errno = 0;
val = strtoul(value, &endptr, 10);
if (errno != 0 || *endptr != '\0' || val > (unsigned)INT_MAX) {
- data->threads = 1;
+ xz->threads = 1;
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
"threads invalid");
return (ARCHIVE_FAILED);
}
- data->threads = (int)val;
- if (data->threads == 0) {
+ xz->threads = (int)val;
+ if (xz->threads == 0) {
#ifdef HAVE_LZMA_STREAM_ENCODER_MT
- data->threads = lzma_cputhreads();
+ xz->threads = lzma_cputhreads();
#else
- data->threads = 1;
+ xz->threads = 1;
#endif
}
return (ARCHIVE_OK);
@@ -429,18 +414,18 @@ static int
archive_compressor_xz_write(struct archive_write_filter *f,
const void *buff, size_t length)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct xz *xz = f->data;
int ret;
/* Update statistics */
- data->total_in += length;
+ xz->total_in += length;
if (f->code == ARCHIVE_FILTER_LZIP)
- data->crc32 = lzma_crc32(buff, length, data->crc32);
+ xz->crc32 = lzma_crc32(buff, length, xz->crc32);
/* Compress input data to output buffer */
- data->stream.next_in = buff;
- data->stream.avail_in = length;
- if ((ret = drive_compressor(f, data, 0)) != ARCHIVE_OK)
+ xz->stream.next_in = buff;
+ xz->stream.avail_in = length;
+ if ((ret = drive_compressor(f, xz, 0)) != ARCHIVE_OK)
return (ret);
return (ARCHIVE_OK);
@@ -453,34 +438,32 @@ archive_compressor_xz_write(struct archive_write_filter *f,
static int
archive_compressor_xz_close(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct xz *xz = f->data;
int ret;
- ret = drive_compressor(f, data, 1);
+ ret = drive_compressor(f, xz, 1);
if (ret == ARCHIVE_OK) {
- data->total_out +=
- data->compressed_buffer_size - data->stream.avail_out;
+ xz->total_out +=
+ xz->compressed_buffer_size - xz->stream.avail_out;
ret = __archive_write_filter(f->next_filter,
- data->compressed,
- data->compressed_buffer_size - data->stream.avail_out);
+ xz->compressed,
+ xz->compressed_buffer_size - xz->stream.avail_out);
if (f->code == ARCHIVE_FILTER_LZIP && ret == ARCHIVE_OK) {
- archive_le32enc(data->compressed, data->crc32);
- archive_le64enc(data->compressed+4, data->total_in);
- archive_le64enc(data->compressed+12, data->total_out + 20);
+ archive_le32enc(xz->compressed, xz->crc32);
+ archive_le64enc(xz->compressed+4, xz->total_in);
+ archive_le64enc(xz->compressed+12, xz->total_out + 20);
ret = __archive_write_filter(f->next_filter,
- data->compressed, 20);
+ xz->compressed, 20);
}
}
- lzma_end(&(data->stream));
+ lzma_end(&(xz->stream));
return ret;
}
static int
archive_compressor_xz_free(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
- free(data->compressed);
- free(data);
+ free_data(f->data);
f->data = NULL;
return (ARCHIVE_OK);
}
@@ -494,34 +477,34 @@ archive_compressor_xz_free(struct archive_write_filter *f)
*/
static int
drive_compressor(struct archive_write_filter *f,
- struct private_data *data, int finishing)
+ struct xz *xz, int finishing)
{
int ret;
for (;;) {
- if (data->stream.avail_out == 0) {
- data->total_out += data->compressed_buffer_size;
+ if (xz->stream.avail_out == 0) {
+ xz->total_out += xz->compressed_buffer_size;
ret = __archive_write_filter(f->next_filter,
- data->compressed,
- data->compressed_buffer_size);
+ xz->compressed,
+ xz->compressed_buffer_size);
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
- data->stream.next_out = data->compressed;
- data->stream.avail_out = data->compressed_buffer_size;
+ xz->stream.next_out = xz->compressed;
+ xz->stream.avail_out = xz->compressed_buffer_size;
}
/* If there's nothing to do, we're done. */
- if (!finishing && data->stream.avail_in == 0)
+ if (!finishing && xz->stream.avail_in == 0)
return (ARCHIVE_OK);
- ret = lzma_code(&(data->stream),
+ ret = lzma_code(&(xz->stream),
finishing ? LZMA_FINISH : LZMA_RUN );
switch (ret) {
case LZMA_OK:
/* In non-finishing case, check if compressor
* consumed everything */
- if (!finishing && data->stream.avail_in == 0)
+ if (!finishing && xz->stream.avail_in == 0)
return (ARCHIVE_OK);
/* In finishing case, this return always means
* there's more work */
@@ -537,7 +520,7 @@ drive_compressor(struct archive_write_filter *f,
archive_set_error(f->archive, ENOMEM,
"lzma compression error: "
"%ju MiB would have been needed",
- (uintmax_t)((lzma_memusage(&(data->stream))
+ (uintmax_t)((lzma_memusage(&(xz->stream))
+ 1024 * 1024 -1)
/ (1024 * 1024)));
return (ARCHIVE_FATAL);
@@ -552,4 +535,13 @@ drive_compressor(struct archive_write_filter *f,
}
}
+static void
+free_data(struct xz *xz)
+{
+ if (xz != NULL) {
+ free(xz->compressed);
+ free(xz);
+ }
+}
+
#endif /* HAVE_LZMA_H */
diff --git a/contrib/libarchive/libarchive/archive_write_add_filter_zstd.c b/contrib/libarchive/libarchive/archive_write_add_filter_zstd.c
index 7149abb2b8a8..826227fd4764 100644
--- a/contrib/libarchive/libarchive/archive_write_add_filter_zstd.c
+++ b/contrib/libarchive/libarchive/archive_write_add_filter_zstd.c
@@ -55,7 +55,7 @@
/* Don't compile this if we don't have zstd.h */
-struct private_data {
+struct zstd {
int compression_level;
int threads;
int long_distance;
@@ -73,7 +73,6 @@ struct private_data {
size_t cur_frame;
size_t cur_frame_in;
size_t cur_frame_out;
- size_t total_in;
ZSTD_CStream *cstream;
ZSTD_outBuffer out;
#else
@@ -104,79 +103,77 @@ static int archive_compressor_zstd_close(struct archive_write_filter *);
static int archive_compressor_zstd_free(struct archive_write_filter *);
#if HAVE_ZSTD_H && HAVE_ZSTD_compressStream
static int drive_compressor(struct archive_write_filter *,
- struct private_data *, int, const void *, size_t);
+ struct zstd *, int, const void *, size_t);
#endif
+static void free_data(struct zstd *);
/*
* Add a zstd compression filter to this write handle.
*/
int
-archive_write_add_filter_zstd(struct archive *_a)
+archive_write_add_filter_zstd(struct archive *a)
{
- struct archive_write *a = (struct archive_write *)_a;
- struct archive_write_filter *f = __archive_write_allocate_filter(_a);
- struct private_data *data;
- archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ struct archive_write_filter *f;
+ struct zstd *zstd;
+ int r;
+
+ archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_add_filter_zstd");
- data = calloc(1, sizeof(*data));
- if (data == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- f->data = data;
- f->open = &archive_compressor_zstd_open;
- f->options = &archive_compressor_zstd_options;
- f->flush = &archive_compressor_zstd_flush;
- f->close = &archive_compressor_zstd_close;
- f->free = &archive_compressor_zstd_free;
- f->code = ARCHIVE_FILTER_ZSTD;
- f->name = "zstd";
- data->compression_level = CLEVEL_DEFAULT;
- data->threads = 0;
- data->long_distance = 0;
+ zstd = calloc(1, sizeof(*zstd));
+ if (zstd == NULL)
+ goto memerr;
+ zstd->compression_level = CLEVEL_DEFAULT;
+ zstd->threads = 0;
+ zstd->long_distance = 0;
#if HAVE_ZSTD_H && HAVE_ZSTD_compressStream
- data->frame_per_file = 0;
- data->min_frame_in = 0;
- data->max_frame_in = SIZE_MAX;
- data->min_frame_out = 0;
- data->max_frame_out = SIZE_MAX;
- data->cur_frame_in = 0;
- data->cur_frame_out = 0;
- data->cstream = ZSTD_createCStream();
- if (data->cstream == NULL) {
- free(data);
- archive_set_error(&a->archive, ENOMEM,
- "Failed to allocate zstd compressor object");
- return (ARCHIVE_FATAL);
- }
+ zstd->frame_per_file = 0;
+ zstd->min_frame_in = 0;
+ zstd->max_frame_in = SIZE_MAX;
+ zstd->min_frame_out = 0;
+ zstd->max_frame_out = SIZE_MAX;
+ zstd->cur_frame_in = 0;
+ zstd->cur_frame_out = 0;
+ zstd->cstream = ZSTD_createCStream();
+ if (zstd->cstream == NULL)
+ goto memerr;
- return (ARCHIVE_OK);
+ r = ARCHIVE_OK;
#else
- data->pdata = __archive_write_program_allocate("zstd");
- if (data->pdata == NULL) {
- free(data);
- archive_set_error(&a->archive, ENOMEM, "Out of memory");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ zstd->pdata = __archive_write_program_allocate("zstd");
+ if (zstd->pdata == NULL)
+ goto memerr;
+
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
"Using external zstd program");
- return (ARCHIVE_WARN);
+ r = ARCHIVE_WARN;
#endif
+
+ f = __archive_write_allocate_filter(a);
+ if (f == NULL)
+ goto memerr;
+ f->name = "zstd";
+ f->code = ARCHIVE_FILTER_ZSTD;
+ f->data = zstd;
+ f->options = archive_compressor_zstd_options;
+ f->open = archive_compressor_zstd_open;
+ f->write = archive_compressor_zstd_write;
+ f->flush = archive_compressor_zstd_flush;
+ f->close = archive_compressor_zstd_close;
+ f->free = archive_compressor_zstd_free;
+
+ return (r);
+memerr:
+ free_data(zstd);
+ archive_set_error(a, ENOMEM, "Out of memory");
+ return (ARCHIVE_FATAL);
}
static int
archive_compressor_zstd_free(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
-#if HAVE_ZSTD_H && HAVE_ZSTD_compressStream
- ZSTD_freeCStream(data->cstream);
- free(data->out.dst);
-#else
- __archive_write_program_free(data->pdata);
-#endif
- free(data);
+ free_data(f->data);
f->data = NULL;
return (ARCHIVE_OK);
}
@@ -240,7 +237,7 @@ static int
archive_compressor_zstd_options(struct archive_write_filter *f, const char *key,
const char *value)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct zstd *zstd = f->data;
if (strcmp(key, "compression-level") == 0) {
intmax_t level;
@@ -269,7 +266,7 @@ archive_compressor_zstd_options(struct archive_write_filter *f, const char *key,
"compression-level out of range");
return (ARCHIVE_FAILED);
}
- data->compression_level = (int)level;
+ zstd->compression_level = (int)level;
return (ARCHIVE_OK);
} else if (strcmp(key, "threads") == 0) {
intmax_t threads;
@@ -296,14 +293,14 @@ archive_compressor_zstd_options(struct archive_write_filter *f, const char *key,
"threads out of rnage");
return (ARCHIVE_FAILED);
}
- data->threads = (int)threads;
+ zstd->threads = (int)threads;
return (ARCHIVE_OK);
#if HAVE_ZSTD_H && HAVE_ZSTD_compressStream
} else if (strcmp(key, "frame-per-file") == 0) {
- data->frame_per_file = 1;
+ zstd->frame_per_file = 1;
return (ARCHIVE_OK);
} else if (strcmp(key, "min-frame-in") == 0) {
- if (string_to_size(value, &data->min_frame_in) != ARCHIVE_OK) {
+ if (string_to_size(value, &zstd->min_frame_in) != ARCHIVE_OK) {
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
"min-frame-in invalid");
return (ARCHIVE_FAILED);
@@ -311,7 +308,7 @@ archive_compressor_zstd_options(struct archive_write_filter *f, const char *key,
return (ARCHIVE_OK);
} else if (strcmp(key, "min-frame-out") == 0 ||
strcmp(key, "min-frame-size") == 0) {
- if (string_to_size(value, &data->min_frame_out) != ARCHIVE_OK) {
+ if (string_to_size(value, &zstd->min_frame_out) != ARCHIVE_OK) {
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
"min-frame-out invalid");
return (ARCHIVE_FAILED);
@@ -319,16 +316,16 @@ archive_compressor_zstd_options(struct archive_write_filter *f, const char *key,
return (ARCHIVE_OK);
} else if (strcmp(key, "max-frame-in") == 0 ||
strcmp(key, "max-frame-size") == 0) {
- if (string_to_size(value, &data->max_frame_in) != ARCHIVE_OK ||
- data->max_frame_in < 1024) {
+ if (string_to_size(value, &zstd->max_frame_in) != ARCHIVE_OK ||
+ zstd->max_frame_in < 1024) {
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
"max-frame-size invalid");
return (ARCHIVE_FAILED);
}
return (ARCHIVE_OK);
} else if (strcmp(key, "max-frame-out") == 0) {
- if (string_to_size(value, &data->max_frame_out) != ARCHIVE_OK ||
- data->max_frame_out < 1024) {
+ if (string_to_size(value, &zstd->max_frame_out) != ARCHIVE_OK ||
+ zstd->max_frame_out < 1024) {
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
"max-frame-out invalid");
return (ARCHIVE_FAILED);
@@ -364,7 +361,7 @@ archive_compressor_zstd_options(struct archive_write_filter *f, const char *key,
if (((int)long_distance) < 10 || (int)long_distance > max_distance)
return (ARCHIVE_FAILED);
#endif
- data->long_distance = (int)long_distance;
+ zstd->long_distance = (int)long_distance;
return (ARCHIVE_OK);
}
@@ -381,9 +378,9 @@ archive_compressor_zstd_options(struct archive_write_filter *f, const char *key,
static int
archive_compressor_zstd_open(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct zstd *zstd = f->data;
- if (data->out.dst == NULL) {
+ if (zstd->out.dst == NULL) {
size_t bs = ZSTD_CStreamOutSize(), bpb;
if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
/* Buffer size should be a multiple number of
@@ -394,31 +391,29 @@ archive_compressor_zstd_open(struct archive_write_filter *f)
else if (bpb != 0)
bs -= bs % bpb;
}
- data->out.size = bs;
- data->out.pos = 0;
- data->out.dst = malloc(data->out.size);
- if (data->out.dst == NULL) {
+ zstd->out.size = bs;
+ zstd->out.pos = 0;
+ zstd->out.dst = malloc(zstd->out.size);
+ if (zstd->out.dst == NULL) {
archive_set_error(f->archive, ENOMEM,
"Can't allocate data for compression buffer");
return (ARCHIVE_FATAL);
}
}
- f->write = archive_compressor_zstd_write;
-
- if (ZSTD_isError(ZSTD_initCStream(data->cstream,
- data->compression_level))) {
+ if (ZSTD_isError(ZSTD_initCStream(zstd->cstream,
+ zstd->compression_level))) {
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing zstd compressor object");
return (ARCHIVE_FATAL);
}
- ZSTD_CCtx_setParameter(data->cstream, ZSTD_c_nbWorkers, data->threads);
+ ZSTD_CCtx_setParameter(zstd->cstream, ZSTD_c_nbWorkers, zstd->threads);
- ZSTD_CCtx_setParameter(data->cstream, ZSTD_c_checksumFlag, 1);
+ ZSTD_CCtx_setParameter(zstd->cstream, ZSTD_c_checksumFlag, 1);
#if ZSTD_VERSION_NUMBER >= MINVER_LONG
- ZSTD_CCtx_setParameter(data->cstream, ZSTD_c_windowLog, data->long_distance);
+ ZSTD_CCtx_setParameter(zstd->cstream, ZSTD_c_windowLog, zstd->long_distance);
#endif
return (ARCHIVE_OK);
@@ -431,9 +426,9 @@ static int
archive_compressor_zstd_write(struct archive_write_filter *f, const void *buff,
size_t length)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct zstd *zstd = f->data;
- return (drive_compressor(f, data, 0, buff, length));
+ return (drive_compressor(f, zstd, 0, buff, length));
}
/*
@@ -442,15 +437,15 @@ archive_compressor_zstd_write(struct archive_write_filter *f, const void *buff,
static int
archive_compressor_zstd_flush(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct zstd *zstd = f->data;
- if (data->frame_per_file && data->state == running) {
- if (data->cur_frame_in > data->min_frame_in &&
- data->cur_frame_out > data->min_frame_out) {
- data->state = finishing;
+ if (zstd->frame_per_file && zstd->state == running) {
+ if (zstd->cur_frame_in > zstd->min_frame_in &&
+ zstd->cur_frame_out > zstd->min_frame_out) {
+ zstd->state = finishing;
}
}
- return (drive_compressor(f, data, 1, NULL, 0));
+ return (drive_compressor(f, zstd, 1, NULL, 0));
}
/*
@@ -459,11 +454,11 @@ archive_compressor_zstd_flush(struct archive_write_filter *f)
static int
archive_compressor_zstd_close(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct zstd *zstd = f->data;
- if (data->state == running)
- data->state = finishing;
- return (drive_compressor(f, data, 1, NULL, 0));
+ if (zstd->state == running)
+ zstd->state = finishing;
+ return (drive_compressor(f, zstd, 1, NULL, 0));
}
/*
@@ -472,7 +467,7 @@ archive_compressor_zstd_close(struct archive_write_filter *f)
*/
static int
drive_compressor(struct archive_write_filter *f,
- struct private_data *data, int flush, const void *src, size_t length)
+ struct zstd *zstd, int flush, const void *src, size_t length)
{
ZSTD_inBuffer in = { .src = src, .size = length, .pos = 0 };
size_t ipos, opos, zstdret = 0;
@@ -480,47 +475,46 @@ drive_compressor(struct archive_write_filter *f,
for (;;) {
ipos = in.pos;
- opos = data->out.pos;
- switch (data->state) {
+ opos = zstd->out.pos;
+ switch (zstd->state) {
case running:
if (in.pos == in.size)
return (ARCHIVE_OK);
- zstdret = ZSTD_compressStream(data->cstream,
- &data->out, &in);
+ zstdret = ZSTD_compressStream(zstd->cstream,
+ &zstd->out, &in);
if (ZSTD_isError(zstdret))
goto zstd_fatal;
break;
case finishing:
- zstdret = ZSTD_endStream(data->cstream, &data->out);
+ zstdret = ZSTD_endStream(zstd->cstream, &zstd->out);
if (ZSTD_isError(zstdret))
goto zstd_fatal;
if (zstdret == 0)
- data->state = resetting;
+ zstd->state = resetting;
break;
case resetting:
- ZSTD_CCtx_reset(data->cstream, ZSTD_reset_session_only);
- data->cur_frame++;
- data->cur_frame_in = 0;
- data->cur_frame_out = 0;
- data->state = running;
+ ZSTD_CCtx_reset(zstd->cstream, ZSTD_reset_session_only);
+ zstd->cur_frame++;
+ zstd->cur_frame_in = 0;
+ zstd->cur_frame_out = 0;
+ zstd->state = running;
break;
}
- data->total_in += in.pos - ipos;
- data->cur_frame_in += in.pos - ipos;
- data->cur_frame_out += data->out.pos - opos;
- if (data->state == running) {
- if (data->cur_frame_in >= data->max_frame_in ||
- data->cur_frame_out >= data->max_frame_out) {
- data->state = finishing;
+ zstd->cur_frame_in += in.pos - ipos;
+ zstd->cur_frame_out += zstd->out.pos - opos;
+ if (zstd->state == running) {
+ if (zstd->cur_frame_in >= zstd->max_frame_in ||
+ zstd->cur_frame_out >= zstd->max_frame_out) {
+ zstd->state = finishing;
}
}
- if (data->out.pos == data->out.size ||
- (flush && data->out.pos > 0)) {
+ if (zstd->out.pos == zstd->out.size ||
+ (flush && zstd->out.pos > 0)) {
ret = __archive_write_filter(f->next_filter,
- data->out.dst, data->out.pos);
+ zstd->out.dst, zstd->out.pos);
if (ret != ARCHIVE_OK)
goto fatal;
- data->out.pos = 0;
+ zstd->out.pos = 0;
}
}
zstd_fatal:
@@ -531,12 +525,22 @@ fatal:
return (ARCHIVE_FATAL);
}
+static void
+free_data(struct zstd *zstd)
+{
+ if (zstd != NULL) {
+ ZSTD_freeCStream(zstd->cstream);
+ free(zstd->out.dst);
+ free(zstd);
+ }
+}
+
#else /* HAVE_ZSTD_H && HAVE_ZSTD_compressStream */
static int
archive_compressor_zstd_open(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct zstd *zstd = f->data;
struct archive_string as;
int r;
@@ -544,26 +548,25 @@ archive_compressor_zstd_open(struct archive_write_filter *f)
/* --no-check matches library default */
archive_strcpy(&as, "zstd --no-check");
- if (data->compression_level < CLEVEL_STD_MIN) {
- archive_string_sprintf(&as, " --fast=%d", -data->compression_level);
+ if (zstd->compression_level < CLEVEL_STD_MIN) {
+ archive_string_sprintf(&as, " --fast=%d", -zstd->compression_level);
} else {
- archive_string_sprintf(&as, " -%d", data->compression_level);
+ archive_string_sprintf(&as, " -%d", zstd->compression_level);
}
- if (data->compression_level > CLEVEL_STD_MAX) {
+ if (zstd->compression_level > CLEVEL_STD_MAX) {
archive_strcat(&as, " --ultra");
}
- if (data->threads != 0) {
- archive_string_sprintf(&as, " --threads=%d", data->threads);
+ if (zstd->threads != 0) {
+ archive_string_sprintf(&as, " --threads=%d", zstd->threads);
}
- if (data->long_distance != 0) {
- archive_string_sprintf(&as, " --long=%d", data->long_distance);
+ if (zstd->long_distance != 0) {
+ archive_string_sprintf(&as, " --long=%d", zstd->long_distance);
}
- f->write = archive_compressor_zstd_write;
- r = __archive_write_program_open(f, data->pdata, as.s);
+ r = __archive_write_program_open(f, zstd->pdata, as.s);
archive_string_free(&as);
return (r);
}
@@ -572,9 +575,9 @@ static int
archive_compressor_zstd_write(struct archive_write_filter *f, const void *buff,
size_t length)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct zstd *zstd = f->data;
- return __archive_write_program_write(f, data->pdata, buff, length);
+ return __archive_write_program_write(f, zstd->pdata, buff, length);
}
static int
@@ -588,9 +591,18 @@ archive_compressor_zstd_flush(struct archive_write_filter *f)
static int
archive_compressor_zstd_close(struct archive_write_filter *f)
{
- struct private_data *data = (struct private_data *)f->data;
+ struct zstd *zstd = f->data;
- return __archive_write_program_close(f, data->pdata);
+ return __archive_write_program_close(f, zstd->pdata);
+}
+
+static void
+free_data(struct zstd *zstd)
+{
+ if (zstd != NULL) {
+ __archive_write_program_free(zstd->pdata);
+ free(zstd);
+ }
}
#endif /* HAVE_ZSTD_H && HAVE_ZSTD_compressStream */
diff --git a/contrib/libarchive/libarchive/archive_write_disk_posix.c b/contrib/libarchive/libarchive/archive_write_disk_posix.c
index 5ee36888ef48..58df09e4bf7d 100644
--- a/contrib/libarchive/libarchive/archive_write_disk_posix.c
+++ b/contrib/libarchive/libarchive/archive_write_disk_posix.c
@@ -300,7 +300,7 @@ struct archive_write_disk {
uint32_t compressed_rsrc_position;
uint32_t compressed_rsrc_position_v;
/* Buffer for uncompressed data. */
- char *uncompressed_buffer;
+ unsigned char *uncompressed_buffer;
size_t block_remaining_bytes;
size_t file_remaining_bytes;
#ifdef HAVE_ZLIB_H
@@ -308,6 +308,10 @@ struct archive_write_disk {
int stream_valid;
int decmpfs_compression_level;
#endif
+#if !(ARCHIVE_XATTR_LINUX || ARCHIVE_XATTR_DARWIN || ARCHIVE_XATTR_AIX ||\
+ ARCHIVE_XATTR_FREEBSD)
+ int warning_done;
+#endif
};
/*
@@ -596,11 +600,12 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
a->pst = NULL;
a->current_fixup = NULL;
a->deferred = 0;
- if (a->entry) {
- archive_entry_free(a->entry);
- a->entry = NULL;
- }
+ archive_entry_free(a->entry);
a->entry = archive_entry_clone(entry);
+ if (a->entry == NULL) {
+ archive_set_error(&a->archive, ENOMEM, "Out of memory");
+ return (ARCHIVE_FATAL);
+ }
a->fd = -1;
a->fd_offset = 0;
a->offset = 0;
@@ -971,7 +976,7 @@ write_data_block(struct archive_write_disk *a, const char *buff, size_t size)
return (ARCHIVE_OK);
if (a->filesize == 0 || a->fd < 0) {
- archive_set_error(&a->archive, 0,
+ archive_set_error(&a->archive, EIO,
"Attempt to write to an empty file");
return (ARCHIVE_WARN);
}
@@ -1249,7 +1254,7 @@ static int
hfs_decompress(struct archive_write_disk *a)
{
uint32_t *block_info;
- unsigned int block_count;
+ uint32_t block_count;
uint32_t data_pos, data_size;
ssize_t r;
ssize_t bytes_written, bytes_to_write;
@@ -1272,10 +1277,10 @@ hfs_decompress(struct archive_write_disk *a)
bytes_to_write = data_size -1;
b = a->compressed_buffer + 1;
} else {
- uLong dest_len = MAX_DECMPFS_BLOCK_SIZE;
+ size_t dest_len = MAX_DECMPFS_BLOCK_SIZE;
int zr;
- zr = uncompress((Bytef *)a->uncompressed_buffer,
+ zr = uncompress(a->uncompressed_buffer,
&dest_len, a->compressed_buffer, data_size);
if (zr != Z_OK) {
archive_set_error(&a->archive,
@@ -1284,7 +1289,7 @@ hfs_decompress(struct archive_write_disk *a)
return (ARCHIVE_WARN);
}
bytes_to_write = dest_len;
- b = (unsigned char *)a->uncompressed_buffer;
+ b = a->uncompressed_buffer;
}
do {
bytes_written = write(a->fd, b, bytes_to_write);
@@ -1467,8 +1472,7 @@ hfs_write_decmpfs_block(struct archive_write_disk *a, const char *buff,
if (a->decmpfs_block_count == (unsigned)-1) {
void *new_block;
- size_t new_size;
- unsigned int block_count;
+ size_t block_count, new_size;
if (a->decmpfs_header_p == NULL) {
new_block = malloc(MAX_DECMPFS_XATTR_SIZE
@@ -1488,13 +1492,20 @@ hfs_write_decmpfs_block(struct archive_write_disk *a, const char *buff,
archive_le64enc(&a->decmpfs_header_p[DECMPFS_UNCOMPRESSED_SIZE],
a->filesize);
- /* Calculate a block count of the file. */
- block_count =
- (a->filesize + MAX_DECMPFS_BLOCK_SIZE -1) /
- MAX_DECMPFS_BLOCK_SIZE;
+ /*
+ * Calculate block count for the file.
+ */
+ block_count = (a->filesize + MAX_DECMPFS_BLOCK_SIZE - 1) /
+ MAX_DECMPFS_BLOCK_SIZE;
+ if (block_count > (SIZE_MAX - RSRC_H_SIZE - 4 - RSRC_F_SIZE) /
+ (sizeof(uint32_t) * 2) || block_count > UINT32_MAX) {
+ archive_set_error(&a->archive, EFBIG, "File too big");
+ return (ARCHIVE_FATAL);
+ }
+
/*
* Allocate buffer for resource fork.
- * Set up related pointers;
+ * Set up related pointers.
*/
new_size =
RSRC_H_SIZE + /* header */
@@ -1535,7 +1546,7 @@ hfs_write_decmpfs_block(struct archive_write_disk *a, const char *buff,
a->decmpfs_block_info =
(uint32_t *)(a->resource_fork + RSRC_H_SIZE);
/* Set the block count to the resource fork. */
- archive_le32enc(a->decmpfs_block_info++, block_count);
+ archive_le32enc(a->decmpfs_block_info++, (uint32_t)block_count);
/* Get the position where we are going to set compressed
* data. */
a->compressed_rsrc_position =
@@ -1595,7 +1606,7 @@ hfs_write_data_block(struct archive_write_disk *a, const char *buff,
return (ARCHIVE_OK);
if (a->filesize == 0 || a->fd < 0) {
- archive_set_error(&a->archive, 0,
+ archive_set_error(&a->archive, EIO,
"Attempt to write to an empty file");
return (ARCHIVE_WARN);
}
@@ -1674,7 +1685,7 @@ _archive_write_disk_data_block(struct archive *_a,
if (r < ARCHIVE_OK)
return (r);
if ((size_t)r < size) {
- archive_set_error(&a->archive, 0,
+ archive_set_error(&a->archive, EOVERFLOW,
"Too much data: Truncating file at %ju bytes",
(uintmax_t)a->filesize);
return (ARCHIVE_WARN);
@@ -2196,7 +2207,7 @@ restore_entry(struct archive_write_disk *a)
if (a->skip_file_set &&
a->st.st_dev == (dev_t)a->skip_file_dev &&
a->st.st_ino == (ino_t)a->skip_file_ino) {
- archive_set_error(&a->archive, 0,
+ archive_set_error(&a->archive, EIO,
"Refusing to overwrite archive");
return (ARCHIVE_FAILED);
}
@@ -2364,7 +2375,7 @@ create_filesystem_object(struct archive_write_disk *a)
#endif
if (r != 0)
r = errno;
- else if ((st.st_mode & AE_IFMT) == AE_IFREG) {
+ else if (S_ISREG(st.st_mode)) {
a->fd = open(a->name, O_WRONLY | O_TRUNC |
O_BINARY | O_CLOEXEC | O_NOFOLLOW);
__archive_ensure_cloexec_flag(a->fd);
@@ -2996,7 +3007,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
*/
/*
if (!S_ISLNK(path)) {
- fsobj_error(a_eno, a_estr, 0,
+ fsobj_error(a_eno, a_estr, -1,
"Removing symlink ", path);
}
*/
@@ -3012,7 +3023,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
#endif
if (r != 0) {
tail[0] = c;
- fsobj_error(a_eno, a_estr, 0,
+ fsobj_error(a_eno, a_estr, EIO,
"Cannot remove intervening "
"symlink ", path);
res = ARCHIVE_FAILED;
@@ -3072,7 +3083,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
head = tail + 1;
} else {
tail[0] = c;
- fsobj_error(a_eno, a_estr, 0,
+ fsobj_error(a_eno, a_estr, ELOOP,
"Cannot extract through "
"symlink ", path);
res = ARCHIVE_FAILED;
@@ -3080,7 +3091,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
}
} else {
tail[0] = c;
- fsobj_error(a_eno, a_estr, 0,
+ fsobj_error(a_eno, a_estr, ELOOP,
"Cannot extract through symlink ", path);
res = ARCHIVE_FAILED;
break;
@@ -4339,7 +4350,7 @@ copy_metadata(struct archive_write_disk *a, const char *metadata,
* with at least a writing mode(O_RDWR or O_WRONLY). it
* makes the data fork uncompressed.
*/
- dffd = open(datafork, 0);
+ dffd = open(datafork, O_SYMLINK);
if (dffd == -1) {
archive_set_error(&a->archive, errno,
"Failed to open the data fork for metadata");
@@ -4441,14 +4452,16 @@ fixup_appledouble(struct archive_write_disk *a, const char *pathname)
*/
archive_strncpy(&datafork, pathname, p - pathname);
archive_strcat(&datafork, p + 2);
- if (
#ifdef HAVE_LSTAT
- lstat(datafork.s, &st) == -1 ||
+ if (lstat(datafork.s, &st) == -1)
+ goto skip_appledouble;
#else
- la_stat(datafork.s, &st) == -1 ||
+ if (la_stat(datafork.s, &st) == -1)
+ goto skip_appledouble;
#endif
- (((st.st_mode & AE_IFMT) != AE_IFREG) &&
- ((st.st_mode & AE_IFMT) != AE_IFDIR)))
+ if (!S_ISREG(st.st_mode) &&
+ !S_ISDIR(st.st_mode) &&
+ !S_ISLNK(st.st_mode))
goto skip_appledouble;
/*
@@ -4693,12 +4706,10 @@ set_xattrs(struct archive_write_disk *a)
static int
set_xattrs(struct archive_write_disk *a)
{
- static int warning_done = 0;
-
/* If there aren't any extended attributes, then it's okay not
* to extract them, otherwise, issue a single warning. */
- if (archive_entry_xattr_count(a->entry) != 0 && !warning_done) {
- warning_done = 1;
+ if (archive_entry_xattr_count(a->entry) != 0 && !a->warning_done) {
+ a->warning_done = 1;
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Cannot restore extended attributes on this system");
return (ARCHIVE_WARN);
diff --git a/contrib/libarchive/libarchive/archive_write_disk_set_standard_lookup.c b/contrib/libarchive/libarchive/archive_write_disk_set_standard_lookup.c
index 964169898e45..5705a978f979 100644
--- a/contrib/libarchive/libarchive/archive_write_disk_set_standard_lookup.c
+++ b/contrib/libarchive/libarchive/archive_write_disk_set_standard_lookup.c
@@ -45,6 +45,7 @@
#endif
#include "archive.h"
+#include "archive_integer.h"
#include "archive_private.h"
#include "archive_read_private.h"
#include "archive_write_disk_private.h"
@@ -134,7 +135,8 @@ lookup_gid(void *private_data, const char *gname, int64_t gid)
break;
if (r != ERANGE)
break;
- bufsize *= 2;
+ if (archive_ckd_mul_size(&bufsize, bufsize, 2))
+ break;
free(allocated);
allocated = malloc(bufsize);
if (allocated == NULL)
@@ -203,7 +205,8 @@ lookup_uid(void *private_data, const char *uname, int64_t uid)
break;
if (r != ERANGE)
break;
- bufsize *= 2;
+ if (archive_ckd_mul_size(&bufsize, bufsize, 2))
+ break;
free(allocated);
allocated = malloc(bufsize);
if (allocated == NULL)
diff --git a/contrib/libarchive/libarchive/archive_write_filter.3 b/contrib/libarchive/libarchive/archive_write_filter.3
index b39cabe04782..9939de414bba 100644
--- a/contrib/libarchive/libarchive/archive_write_filter.3
+++ b/contrib/libarchive/libarchive/archive_write_filter.3
@@ -50,6 +50,8 @@ Streaming Archive Library (libarchive, -larchive)
.Ft int
.Fn archive_write_add_filter_b64encode "struct archive *"
.Ft int
+.Fn archive_write_add_filter_by_name "struct archive *" "const char *name"
+.Ft int
.Fn archive_write_add_filter_bzip2 "struct archive *"
.Ft int
.Fn archive_write_add_filter_compress "struct archive *"
@@ -100,6 +102,8 @@ Note that the compressed output is always properly blocked.
.Xc
The output will be encoded as specified.
The encoded output is always properly blocked.
+.It Fn archive_write_add_filter_by_name
+Sets the corresponding filter based on the common name.
.It Fn archive_write_add_filter_none
This is never necessary.
It is provided only for backwards compatibility.
@@ -111,6 +115,10 @@ write callbacks.
.Sh RETURN VALUES
These functions return
.Cm ARCHIVE_OK
+.Po or
+.Cm ARCHIVE_WARN
+if an external program had to be executed to handle the filter
+.Pc
on success, or
.Cm ARCHIVE_FATAL .
.\"
diff --git a/contrib/libarchive/libarchive/archive_write_format.3 b/contrib/libarchive/libarchive/archive_write_format.3
index 9e331368aeef..1b26c1c4640c 100644
--- a/contrib/libarchive/libarchive/archive_write_format.3
+++ b/contrib/libarchive/libarchive/archive_write_format.3
@@ -129,7 +129,9 @@ Sets the corresponding format based on the common name.
.Fn archive_write_set_format_filter_by_ext
.Fn archive_write_set_format_filter_by_ext_def
.Xc
-Sets both filters and format based on the output filename.
+Sets both filters and format based on the output filename, optionally
+referring to a default extension if the supplied filename does not have a
+known one.
Supported extensions: .7z, .zip, .jar, .cpio, .iso, .a, .ar, .tar, .tgz, .tar.gz, .tar.bz2, .tar.xz
.It Xo
.Fn archive_write_set_format_7zip
diff --git a/contrib/libarchive/libarchive/archive_write_private.h b/contrib/libarchive/libarchive/archive_write_private.h
index f259ccb16546..ca9393fb8ea0 100644
--- a/contrib/libarchive/libarchive/archive_write_private.h
+++ b/contrib/libarchive/libarchive/archive_write_private.h
@@ -69,7 +69,7 @@ void __archive_write_filters_free(struct archive *);
struct archive_write_filter *__archive_write_allocate_filter(struct archive *);
int __archive_write_output(struct archive_write *, const void *, size_t);
-int __archive_write_nulls(struct archive_write *, size_t);
+int __archive_write_nulls(struct archive_write *, uint64_t);
int __archive_write_filter(struct archive_write_filter *, const void *, size_t);
struct archive_write {
@@ -132,6 +132,8 @@ struct archive_write {
void *passphrase_client_data;
};
+int __archive_write_unregister_format(struct archive_write *);
+
/*
* Utility function to format a USTAR header into a buffer. If
* "strict" is set, this tries to create the absolutely most portable
diff --git a/contrib/libarchive/libarchive/archive_write_set_format_7zip.c b/contrib/libarchive/libarchive/archive_write_set_format_7zip.c
index 92ad810635ab..9e2e437dbe87 100644
--- a/contrib/libarchive/libarchive/archive_write_set_format_7zip.c
+++ b/contrib/libarchive/libarchive/archive_write_set_format_7zip.c
@@ -215,8 +215,6 @@ struct _7zip {
size_t total_number_dir_entry;
size_t total_bytes_entry_name;
size_t total_number_time_defined[3];
- uint64_t total_bytes_compressed;
- uint64_t total_bytes_uncompressed;
uint64_t entry_bytes_remaining;
uint32_t entry_crc32;
uint32_t precode_crc32;
@@ -314,7 +312,7 @@ static int _7z_compression_init_encoder(struct archive_write *, unsigned,
int);
static int compression_init_encoder_zstd(struct archive *,
struct la_zstream *, int, int);
-#if defined(HAVE_ZSTD_H)
+#if HAVE_ZSTD_H && HAVE_ZSTD_compressStream
static int compression_code_zstd(struct archive *,
struct la_zstream *, enum la_zaction);
static int compression_end_zstd(struct archive *, struct la_zstream *);
@@ -358,8 +356,7 @@ archive_write_set_format_7zip(struct archive *_a)
ARCHIVE_STATE_NEW, "archive_write_set_format_7zip");
/* If another format was already registered, unregister it. */
- if (a->format_free != NULL)
- (a->format_free)(a);
+ (void)__archive_write_unregister_format(a);
zip = calloc(1, sizeof(*zip));
if (zip == NULL) {
@@ -379,7 +376,7 @@ archive_write_set_format_7zip(struct archive *_a)
zip->opt_compression = _7Z_BZIP2;
#elif defined(HAVE_ZLIB_H)
zip->opt_compression = _7Z_DEFLATE;
-#elif HAVE_ZSTD_H
+#elif HAVE_ZSTD_H && HAVE_ZSTD_compressStream
zip->opt_compression = _7Z_ZSTD;
#else
zip->opt_compression = _7Z_COPY;
@@ -415,9 +412,7 @@ archive_write_set_format_7zip(struct archive *_a)
static int
_7z_options(struct archive_write *a, const char *key, const char *value)
{
- struct _7zip *zip;
-
- zip = (struct _7zip *)a->format_data;
+ struct _7zip *zip = a->format_data;
if (strcmp(key, "compression") == 0) {
const char *name = NULL;
@@ -559,11 +554,10 @@ _7z_options(struct archive_write *a, const char *key, const char *value)
static int
_7z_write_header(struct archive_write *a, struct archive_entry *entry)
{
- struct _7zip *zip;
+ struct _7zip *zip = a->format_data;
struct file *file;
int r;
- zip = (struct _7zip *)a->format_data;
zip->cur_file = NULL;
zip->entry_bytes_remaining = 0;
@@ -667,12 +661,10 @@ _7z_write_header(struct archive_write *a, struct archive_entry *entry)
static int
write_to_temp(struct archive_write *a, const void *buff, size_t s)
{
- struct _7zip *zip;
+ struct _7zip *zip = a->format_data;
const unsigned char *p;
ssize_t ws;
- zip = (struct _7zip *)a->format_data;
-
/*
* Open a temporary file.
*/
@@ -705,7 +697,7 @@ static ssize_t
compress_out(struct archive_write *a, const void *buff, size_t s,
enum la_zaction run)
{
- struct _7zip *zip = (struct _7zip *)a->format_data;
+ struct _7zip *zip = a->format_data;
int r;
if (run == ARCHIVE_Z_FINISH && zip->stream.total_in == 0 && s == 0)
@@ -751,11 +743,9 @@ compress_out(struct archive_write *a, const void *buff, size_t s,
static ssize_t
_7z_write_data(struct archive_write *a, const void *buff, size_t s)
{
- struct _7zip *zip;
+ struct _7zip *zip = a->format_data;
ssize_t bytes;
- zip = (struct _7zip *)a->format_data;
-
if (s > zip->entry_bytes_remaining)
s = (size_t)zip->entry_bytes_remaining;
if (s == 0 || zip->cur_file == NULL)
@@ -771,11 +761,10 @@ _7z_write_data(struct archive_write *a, const void *buff, size_t s)
static int
_7z_finish_entry(struct archive_write *a)
{
- struct _7zip *zip;
+ struct _7zip *zip = a->format_data;
size_t s;
ssize_t r;
- zip = (struct _7zip *)a->format_data;
if (zip->cur_file == NULL)
return (ARCHIVE_OK);
@@ -787,8 +776,6 @@ _7z_finish_entry(struct archive_write *a)
if (r < 0)
return ((int)r);
}
- zip->total_bytes_compressed += zip->stream.total_in;
- zip->total_bytes_uncompressed += zip->stream.total_out;
zip->cur_file->crc32 = zip->entry_crc32;
zip->cur_file = NULL;
@@ -798,11 +785,10 @@ _7z_finish_entry(struct archive_write *a)
static int
flush_wbuff(struct archive_write *a)
{
- struct _7zip *zip;
+ struct _7zip *zip = a->format_data;
int r;
size_t s;
- zip = (struct _7zip *)a->format_data;
s = sizeof(zip->wbuff) - zip->wbuff_remaining;
r = __archive_write_output(a, zip->wbuff, s);
if (r != ARCHIVE_OK)
@@ -814,10 +800,9 @@ flush_wbuff(struct archive_write *a)
static int
copy_out(struct archive_write *a, uint64_t offset, uint64_t length)
{
- struct _7zip *zip;
+ struct _7zip *zip = a->format_data;
int r;
- zip = (struct _7zip *)a->format_data;
if (zip->temp_offset > 0 &&
lseek(zip->temp_fd, offset, SEEK_SET) < 0) {
archive_set_error(&(a->archive), errno, "lseek failed");
@@ -841,7 +826,8 @@ copy_out(struct archive_write *a, uint64_t offset, uint64_t length)
return (ARCHIVE_FATAL);
}
if (rs == 0) {
- archive_set_error(&(a->archive), 0,
+ archive_set_error(&(a->archive),
+ ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated 7-Zip archive");
return (ARCHIVE_FATAL);
}
@@ -859,15 +845,13 @@ copy_out(struct archive_write *a, uint64_t offset, uint64_t length)
static int
_7z_close(struct archive_write *a)
{
- struct _7zip *zip;
+ struct _7zip *zip = a->format_data;
unsigned char *wb;
uint64_t header_offset, header_size, header_unpacksize;
uint64_t length;
uint32_t header_crc32;
int r;
- zip = (struct _7zip *)a->format_data;
-
if (zip->total_number_entry > 0) {
struct archive_rb_node *n;
uint64_t data_offset, data_size, data_unpacksize;
@@ -1032,7 +1016,7 @@ enc_uint64(struct archive_write *a, uint64_t val)
static int
make_substreamsInfo(struct archive_write *a, struct coder *coders)
{
- struct _7zip *zip = (struct _7zip *)a->format_data;
+ struct _7zip *zip = a->format_data;
struct file *file;
int r;
@@ -1108,7 +1092,7 @@ make_streamsInfo(struct archive_write *a, uint64_t offset, uint64_t pack_size,
uint64_t unpack_size, int num_coder, struct coder *coders, int substrm,
uint32_t header_crc)
{
- struct _7zip *zip = (struct _7zip *)a->format_data;
+ struct _7zip *zip = a->format_data;
uint8_t codec_buff[8];
int numFolders, fi;
int codec_size;
@@ -1300,8 +1284,8 @@ make_streamsInfo(struct archive_write *a, uint64_t offset, uint64_t pack_size,
static int
make_time(struct archive_write *a, uint8_t type, unsigned flg, int ti)
{
+ struct _7zip *zip = a->format_data;
uint8_t filetime[8];
- struct _7zip *zip = (struct _7zip *)a->format_data;
struct file *file;
int r;
uint8_t b, mask;
@@ -1389,7 +1373,7 @@ static int
make_header(struct archive_write *a, uint64_t offset, uint64_t pack_size,
uint64_t unpack_size, int codernum, struct coder *coders)
{
- struct _7zip *zip = (struct _7zip *)a->format_data;
+ struct _7zip *zip = a->format_data;
struct file *file;
int r;
uint8_t b, mask;
@@ -1597,7 +1581,7 @@ make_header(struct archive_write *a, uint64_t offset, uint64_t pack_size,
static int
_7z_free(struct archive_write *a)
{
- struct _7zip *zip = (struct _7zip *)a->format_data;
+ struct _7zip *zip = a->format_data;
/* Close the temporary file. */
if (zip->temp_fd >= 0)
@@ -1635,13 +1619,12 @@ static int
file_new(struct archive_write *a, struct archive_entry *entry,
struct file **newfile)
{
- struct _7zip *zip;
+ struct _7zip *zip = a->format_data;
struct file *file;
const char *u16;
size_t u16len;
int ret = ARCHIVE_OK;
- zip = (struct _7zip *)a->format_data;
*newfile = NULL;
file = calloc(1, sizeof(*file));
@@ -1685,7 +1668,7 @@ file_new(struct archive_write *a, struct archive_entry *entry,
const char* linkpath;
linkpath = archive_entry_symlink_utf8(entry);
if (linkpath == NULL) {
- free(file);
+ file_free(file);
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"symlink path could not be converted to UTF-8");
return (ARCHIVE_FAILED);
@@ -2259,7 +2242,7 @@ static void
ppmd_write(void *p, Byte b)
{
struct archive_write *a = ((IByteOut *)p)->a;
- struct _7zip *zip = (struct _7zip *)(a->format_data);
+ struct _7zip *zip = a->format_data;
struct la_zstream *lastrm = &(zip->stream);
struct ppmd_stream *strm;
@@ -2516,10 +2499,9 @@ static int
_7z_compression_init_encoder(struct archive_write *a, unsigned compression,
int compression_level)
{
- struct _7zip *zip;
+ struct _7zip *zip = a->format_data;
int r;
- zip = (struct _7zip *)a->format_data;
switch (compression) {
case _7Z_DEFLATE:
r = compression_init_encoder_deflate(
diff --git a/contrib/libarchive/libarchive/archive_write_set_format_ar.c b/contrib/libarchive/libarchive/archive_write_set_format_ar.c
index e5e9c806b639..57572ea38bd3 100644
--- a/contrib/libarchive/libarchive/archive_write_set_format_ar.c
+++ b/contrib/libarchive/libarchive/archive_write_set_format_ar.c
@@ -40,10 +40,11 @@
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
+#include "archive_string.h"
#include "archive_write_private.h"
#include "archive_write_set_format_private.h"
-struct ar_w {
+struct ar {
uint64_t entry_bytes_remaining;
uint64_t entry_padding;
int is_strtab;
@@ -78,7 +79,6 @@ static ssize_t archive_write_ar_data(struct archive_write *,
static int archive_write_ar_free(struct archive_write *);
static int archive_write_ar_close(struct archive_write *);
static int archive_write_ar_finish_entry(struct archive_write *);
-static const char *ar_basename(const char *path);
static int format_octal(int64_t v, char *p, int s);
static int format_decimal(int64_t v, char *p, int s);
@@ -120,11 +120,10 @@ archive_write_set_format_ar_svr4(struct archive *_a)
static int
archive_write_set_format_ar(struct archive_write *a)
{
- struct ar_w *ar;
+ struct ar *ar;
/* If someone else was already registered, unregister them. */
- if (a->format_free != NULL)
- (a->format_free)(a);
+ (void)__archive_write_unregister_format(a);
ar = calloc(1, sizeof(*ar));
if (ar == NULL) {
@@ -147,16 +146,18 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
{
int ret, append_fn;
char buff[60];
- char *ss, *se;
- struct ar_w *ar;
+ char *ss;
+ struct ar *ar = a->format_data;
+ struct archive_string se;
const char *pathname;
const char *filename;
+ size_t filename_length;
int64_t size;
append_fn = 0;
- ar = (struct ar_w *)a->format_data;
ar->is_strtab = 0;
filename = NULL;
+ filename_length = 0;
size = archive_entry_size(entry);
@@ -172,7 +173,7 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
/*
* If we are now at the beginning of the archive,
- * we need first write the ar global header.
+ * we have to write the ar global header first.
*/
if (!ar->wrote_global_header) {
__archive_write_output(a, "!<arch>\n", 8);
@@ -215,12 +216,17 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
* Otherwise, entry is a normal archive member.
* Strip leading paths from filenames, if any.
*/
- if ((filename = ar_basename(pathname)) == NULL) {
+ filename = strrchr(pathname, '/');
+ if (filename == NULL)
+ filename = pathname;
+ else if (filename[1] == '\0') {
/* Reject filenames with trailing "/" */
archive_set_error(&a->archive, EINVAL,
"Invalid filename");
return (ARCHIVE_WARN);
- }
+ } else
+ filename++;
+ filename_length = strlen(filename);
if (a->archive.archive_format == ARCHIVE_FORMAT_AR_GNU) {
/*
@@ -229,10 +235,10 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
* So, the longest filename here (without extension) is
* actually 15 bytes.
*/
- if (strlen(filename) <= 15) {
+ if (filename_length <= 15) {
memcpy(&buff[AR_name_offset],
- filename, strlen(filename));
- buff[AR_name_offset + strlen(filename)] = '/';
+ filename, filename_length);
+ buff[AR_name_offset + filename_length] = '/';
} else {
/*
* For filename longer than 15 bytes, GNU variant
@@ -246,18 +252,10 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
return (ARCHIVE_WARN);
}
- se = malloc(strlen(filename) + 3);
- if (se == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate filename buffer");
- return (ARCHIVE_FATAL);
- }
-
- memcpy(se, filename, strlen(filename));
- strcpy(se + strlen(filename), "/\n");
-
- ss = strstr(ar->strtab, se);
- free(se);
+ archive_string_init(&se);
+ archive_string_sprintf(&se, "%s/\n", filename);
+ ss = strstr(ar->strtab, se.s);
+ archive_string_free(&se);
if (ss == NULL) {
archive_set_error(&a->archive, EINVAL,
@@ -289,13 +287,13 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
* The name is then written immediately following the
* archive header.
*/
- if (strlen(filename) <= 16 && strchr(filename, ' ') == NULL) {
- memcpy(&buff[AR_name_offset], filename, strlen(filename));
- buff[AR_name_offset + strlen(filename)] = ' ';
+ if (filename_length <= 16 && strchr(filename, ' ') == NULL) {
+ memcpy(&buff[AR_name_offset], filename, filename_length);
+ buff[AR_name_offset + filename_length] = ' ';
}
else {
memcpy(buff + AR_name_offset, "#1/", 3);
- if (format_decimal(strlen(filename),
+ if (format_decimal(filename_length,
buff + AR_name_offset + 3,
AR_name_size - 3)) {
archive_set_error(&a->archive, ERANGE,
@@ -303,7 +301,7 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
return (ARCHIVE_WARN);
}
append_fn = 1;
- size += strlen(filename);
+ size += filename_length;
}
}
@@ -353,10 +351,10 @@ size:
ar->entry_padding = ar->entry_bytes_remaining % 2;
if (append_fn > 0) {
- ret = __archive_write_output(a, filename, strlen(filename));
+ ret = __archive_write_output(a, filename, filename_length);
if (ret != ARCHIVE_OK)
return (ret);
- ar->entry_bytes_remaining -= strlen(filename);
+ ar->entry_bytes_remaining -= filename_length;
}
return (ARCHIVE_OK);
@@ -365,10 +363,9 @@ size:
static ssize_t
archive_write_ar_data(struct archive_write *a, const void *buff, size_t s)
{
- struct ar_w *ar;
+ struct ar *ar = a->format_data;
int ret;
- ar = (struct ar_w *)a->format_data;
if (s > ar->entry_bytes_remaining)
s = (size_t)ar->entry_bytes_remaining;
@@ -401,9 +398,7 @@ archive_write_ar_data(struct archive_write *a, const void *buff, size_t s)
static int
archive_write_ar_free(struct archive_write *a)
{
- struct ar_w *ar;
-
- ar = (struct ar_w *)a->format_data;
+ struct ar *ar = a->format_data;
if (ar == NULL)
return (ARCHIVE_OK);
@@ -421,14 +416,13 @@ archive_write_ar_free(struct archive_write *a)
static int
archive_write_ar_close(struct archive_write *a)
{
- struct ar_w *ar;
+ struct ar *ar = a->format_data;
int ret;
/*
* If we haven't written anything yet, we need to write
* the ar global header now to make it a valid ar archive.
*/
- ar = (struct ar_w *)a->format_data;
if (!ar->wrote_global_header) {
ar->wrote_global_header = 1;
ret = __archive_write_output(a, "!<arch>\n", 8);
@@ -441,11 +435,9 @@ archive_write_ar_close(struct archive_write *a)
static int
archive_write_ar_finish_entry(struct archive_write *a)
{
- struct ar_w *ar;
+ struct ar *ar = a->format_data;
int ret;
- ar = (struct ar_w *)a->format_data;
-
if (ar->entry_bytes_remaining != 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Entry remaining bytes larger than 0");
@@ -546,24 +538,3 @@ format_decimal(int64_t v, char *p, int s)
return (-1);
}
-
-static const char *
-ar_basename(const char *path)
-{
- const char *endp, *startp;
-
- endp = path + strlen(path) - 1;
- /*
- * For filename with trailing slash(es), we return
- * NULL indicating an error.
- */
- if (*endp == '/')
- return (NULL);
-
- /* Find the start of the base */
- startp = endp;
- while (startp > path && *(startp - 1) != '/')
- startp--;
-
- return (startp);
-}
diff --git a/contrib/libarchive/libarchive/archive_write_set_format_cpio_binary.c b/contrib/libarchive/libarchive/archive_write_set_format_cpio_binary.c
index 4777e75f2912..6648b18d90ac 100644
--- a/contrib/libarchive/libarchive/archive_write_set_format_cpio_binary.c
+++ b/contrib/libarchive/libarchive/archive_write_set_format_cpio_binary.c
@@ -40,6 +40,7 @@
#include "archive.h"
#include "archive_entry.h"
#include "archive_entry_locale.h"
+#include "archive_integer.h"
#include "archive_private.h"
#include "archive_write_private.h"
#include "archive_write_set_format_private.h"
@@ -182,8 +183,7 @@ archive_write_set_format_cpio_binary(struct archive *_a, int format)
ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_binary");
/* If someone else was already registered, unregister them. */
- if (a->format_free != NULL)
- (a->format_free)(a);
+ (void)__archive_write_unregister_format(a);
cpio = calloc(1, sizeof(*cpio));
if (cpio == NULL) {
@@ -235,7 +235,7 @@ static int
archive_write_binary_options(struct archive_write *a, const char *key,
const char *val)
{
- struct cpio *cpio = (struct cpio *)a->format_data;
+ struct cpio *cpio = a->format_data;
int ret = ARCHIVE_FAILED;
if (strcmp(key, "hdrcharset") == 0) {
@@ -307,10 +307,16 @@ synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry)
/* Ensure space for the new mapping. */
if (cpio->ino_list_size <= cpio->ino_list_next) {
- size_t newsize = cpio->ino_list_size < 512
- ? 512 : cpio->ino_list_size * 2;
- void *newlist = realloc(cpio->ino_list,
- sizeof(cpio->ino_list[0]) * newsize);
+ size_t newsize, size;
+ if (cpio->ino_list_size < 512)
+ newsize = 512;
+ else if (archive_ckd_mul_size(&newsize,
+ cpio->ino_list_size, 2))
+ return (-1);
+ if (archive_ckd_mul_size(&size,
+ newsize, sizeof(cpio->ino_list[0])))
+ return (-1);
+ void *newlist = realloc(cpio->ino_list, size);
if (newlist == NULL)
return (-1);
@@ -329,10 +335,9 @@ synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry)
static struct archive_string_conv *
get_sconv(struct archive_write *a)
{
- struct cpio *cpio;
+ struct cpio *cpio = a->format_data;
struct archive_string_conv *sconv;
- cpio = (struct cpio *)a->format_data;
sconv = cpio->opt_sconv;
if (sconv == NULL) {
if (!cpio->init_default_conversion) {
@@ -378,16 +383,15 @@ archive_write_binary_header(struct archive_write *a, struct archive_entry *entry
static int
write_header(struct archive_write *a, struct archive_entry *entry)
{
- struct cpio *cpio;
+ struct cpio *cpio = a->format_data;
const char *p, *path;
- int pathlength, ret, ret_final;
+ int ret, ret_final;
int64_t ino;
struct cpio_binary_header h;
struct archive_string_conv *sconv;
struct archive_entry *entry_main;
- size_t len;
+ size_t len, pathlength;
- cpio = (struct cpio *)a->format_data;
ret_final = ARCHIVE_OK;
sconv = get_sconv(a);
@@ -423,7 +427,7 @@ write_header(struct archive_write *a, struct archive_entry *entry)
ret_final = ARCHIVE_WARN;
}
/* Include trailing null */
- pathlength = (int)len + 1;
+ pathlength = len + 1;
h.h_magic = la_swap16(070707);
h.h_dev = la_swap16(archive_entry_dev(entry));
@@ -472,7 +476,13 @@ write_header(struct archive_write *a, struct archive_entry *entry)
h.h_majmin = 0;
h.h_mtime = la_swap32((uint32_t)archive_entry_mtime(entry));
- h.h_namesize = la_swap16(pathlength);
+ if (pathlength > 0xffff) {
+ archive_set_error(&a->archive, ERANGE,
+ "Filename is too long for cpio format");
+ ret_final = ARCHIVE_FAILED;
+ goto exit_write_header;
+ }
+ h.h_namesize = la_swap16((uint16_t)pathlength);
/* Non-regular files don't store bodies. */
if (archive_entry_filetype(entry) != AE_IFREG)
@@ -555,10 +565,9 @@ exit_write_header:
static ssize_t
archive_write_binary_data(struct archive_write *a, const void *buff, size_t s)
{
- struct cpio *cpio;
+ struct cpio *cpio = a->format_data;
int ret;
- cpio = (struct cpio *)a->format_data;
if (s > cpio->entry_bytes_remaining)
s = (size_t)cpio->entry_bytes_remaining;
@@ -592,9 +601,8 @@ archive_write_binary_close(struct archive_write *a)
static int
archive_write_binary_free(struct archive_write *a)
{
- struct cpio *cpio;
+ struct cpio *cpio = a->format_data;
- cpio = (struct cpio *)a->format_data;
free(cpio->ino_list);
free(cpio);
a->format_data = NULL;
@@ -604,9 +612,7 @@ archive_write_binary_free(struct archive_write *a)
static int
archive_write_binary_finish_entry(struct archive_write *a)
{
- struct cpio *cpio;
+ struct cpio *cpio = a->format_data;
- cpio = (struct cpio *)a->format_data;
- return (__archive_write_nulls(a,
- (size_t)cpio->entry_bytes_remaining));
+ return (__archive_write_nulls(a, cpio->entry_bytes_remaining));
}
diff --git a/contrib/libarchive/libarchive/archive_write_set_format_cpio_newc.c b/contrib/libarchive/libarchive/archive_write_set_format_cpio_newc.c
index d72434d8ae88..b9de7d362e22 100644
--- a/contrib/libarchive/libarchive/archive_write_set_format_cpio_newc.c
+++ b/contrib/libarchive/libarchive/archive_write_set_format_cpio_newc.c
@@ -113,8 +113,7 @@ archive_write_set_format_cpio_newc(struct archive *_a)
ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_newc");
/* If someone else was already registered, unregister them. */
- if (a->format_free != NULL)
- (a->format_free)(a);
+ (void)__archive_write_unregister_format(a);
cpio = calloc(1, sizeof(*cpio));
if (cpio == NULL) {
@@ -138,7 +137,7 @@ static int
archive_write_newc_options(struct archive_write *a, const char *key,
const char *val)
{
- struct cpio *cpio = (struct cpio *)a->format_data;
+ struct cpio *cpio = a->format_data;
int ret = ARCHIVE_FAILED;
if (strcmp(key, "hdrcharset") == 0) {
@@ -166,10 +165,9 @@ archive_write_newc_options(struct archive_write *a, const char *key,
static struct archive_string_conv *
get_sconv(struct archive_write *a)
{
- struct cpio *cpio;
+ struct cpio *cpio = a->format_data;
struct archive_string_conv *sconv;
- cpio = (struct cpio *)a->format_data;
sconv = cpio->opt_sconv;
if (sconv == NULL) {
if (!cpio->init_default_conversion) {
@@ -216,17 +214,16 @@ archive_write_newc_header(struct archive_write *a, struct archive_entry *entry)
static int
write_header(struct archive_write *a, struct archive_entry *entry)
{
+ struct cpio *cpio = a->format_data;
int64_t ino;
- struct cpio *cpio;
const char *p, *path;
- int pathlength, ret, ret_final;
+ int ret, ret_final;
char h[c_header_size];
struct archive_string_conv *sconv;
struct archive_entry *entry_main;
- size_t len;
+ size_t len, pathlength;
int pad;
- cpio = (struct cpio *)a->format_data;
ret_final = ARCHIVE_OK;
sconv = get_sconv(a);
@@ -261,7 +258,7 @@ write_header(struct archive_write *a, struct archive_entry *entry)
archive_string_conversion_charset_name(sconv));
ret_final = ARCHIVE_WARN;
}
- pathlength = (int)len + 1; /* Include trailing null. */
+ pathlength = len + 1; /* Include trailing null. */
memset(h, 0, c_header_size);
format_hex(0x070701, h + c_magic_offset, c_magic_size);
@@ -292,7 +289,12 @@ write_header(struct archive_write *a, struct archive_entry *entry)
format_hex(0, h + c_rdevminor_offset, c_rdevminor_size);
}
format_hex(archive_entry_mtime(entry), h + c_mtime_offset, c_mtime_size);
- format_hex(pathlength, h + c_namesize_offset, c_namesize_size);
+ if (format_hex(pathlength, h + c_namesize_offset, c_namesize_size)) {
+ archive_set_error(&a->archive, ERANGE,
+ "Filename is too long for cpio format");
+ ret_final = ARCHIVE_FAILED;
+ goto exit_write_header;
+ }
format_hex(0, h + c_checksum_offset, c_checksum_size);
/* Non-regular files don't store bodies. */
@@ -373,10 +375,9 @@ exit_write_header:
static ssize_t
archive_write_newc_data(struct archive_write *a, const void *buff, size_t s)
{
- struct cpio *cpio;
+ struct cpio *cpio = a->format_data;
int ret;
- cpio = (struct cpio *)a->format_data;
if (s > cpio->entry_bytes_remaining)
s = (size_t)cpio->entry_bytes_remaining;
@@ -425,6 +426,8 @@ archive_write_newc_close(struct archive_write *a)
struct archive_entry *trailer;
trailer = archive_entry_new();
+ if (trailer == NULL)
+ return ARCHIVE_FATAL;
archive_entry_set_nlink(trailer, 1);
archive_entry_set_size(trailer, 0);
archive_entry_set_pathname(trailer, "TRAILER!!!");
@@ -437,9 +440,8 @@ archive_write_newc_close(struct archive_write *a)
static int
archive_write_newc_free(struct archive_write *a)
{
- struct cpio *cpio;
+ struct cpio *cpio = a->format_data;
- cpio = (struct cpio *)a->format_data;
free(cpio);
a->format_data = NULL;
return (ARCHIVE_OK);
@@ -448,9 +450,8 @@ archive_write_newc_free(struct archive_write *a)
static int
archive_write_newc_finish_entry(struct archive_write *a)
{
- struct cpio *cpio;
+ struct cpio *cpio = a->format_data;
- cpio = (struct cpio *)a->format_data;
return (__archive_write_nulls(a,
- (size_t)cpio->entry_bytes_remaining + cpio->padding));
+ cpio->entry_bytes_remaining + cpio->padding));
}
diff --git a/contrib/libarchive/libarchive/archive_write_set_format_cpio_odc.c b/contrib/libarchive/libarchive/archive_write_set_format_cpio_odc.c
index ffac716b8e75..c384d4827288 100644
--- a/contrib/libarchive/libarchive/archive_write_set_format_cpio_odc.c
+++ b/contrib/libarchive/libarchive/archive_write_set_format_cpio_odc.c
@@ -40,6 +40,7 @@
#include "archive.h"
#include "archive_entry.h"
#include "archive_entry_locale.h"
+#include "archive_integer.h"
#include "archive_private.h"
#include "archive_write_private.h"
#include "archive_write_set_format_private.h"
@@ -107,8 +108,7 @@ archive_write_set_format_cpio_odc(struct archive *_a)
ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_odc");
/* If someone else was already registered, unregister them. */
- if (a->format_free != NULL)
- (a->format_free)(a);
+ (void)__archive_write_unregister_format(a);
cpio = calloc(1, sizeof(*cpio));
if (cpio == NULL) {
@@ -132,7 +132,7 @@ static int
archive_write_odc_options(struct archive_write *a, const char *key,
const char *val)
{
- struct cpio *cpio = (struct cpio *)a->format_data;
+ struct cpio *cpio = a->format_data;
int ret = ARCHIVE_FAILED;
if (strcmp(key, "hdrcharset") == 0) {
@@ -204,10 +204,16 @@ synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry)
/* Ensure space for the new mapping. */
if (cpio->ino_list_size <= cpio->ino_list_next) {
- size_t newsize = cpio->ino_list_size < 512
- ? 512 : cpio->ino_list_size * 2;
- void *newlist = realloc(cpio->ino_list,
- sizeof(cpio->ino_list[0]) * newsize);
+ size_t newsize, size;
+ if (cpio->ino_list_size < 512)
+ newsize = 512;
+ else if (archive_ckd_mul_size(&newsize,
+ cpio->ino_list_size, 2))
+ return (-1);
+ if (archive_ckd_mul_size(&size,
+ newsize, sizeof(cpio->ino_list[0])))
+ return (-1);
+ void *newlist = realloc(cpio->ino_list, size);
if (newlist == NULL)
return (-1);
@@ -226,10 +232,9 @@ synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry)
static struct archive_string_conv *
get_sconv(struct archive_write *a)
{
- struct cpio *cpio;
+ struct cpio *cpio = a->format_data;
struct archive_string_conv *sconv;
- cpio = (struct cpio *)a->format_data;
sconv = cpio->opt_sconv;
if (sconv == NULL) {
if (!cpio->init_default_conversion) {
@@ -275,16 +280,15 @@ archive_write_odc_header(struct archive_write *a, struct archive_entry *entry)
static int
write_header(struct archive_write *a, struct archive_entry *entry)
{
- struct cpio *cpio;
+ struct cpio *cpio = a->format_data;
const char *p, *path;
- int pathlength, ret, ret_final;
+ int ret, ret_final;
int64_t ino;
char h[76];
struct archive_string_conv *sconv;
struct archive_entry *entry_main;
- size_t len;
+ size_t len, pathlength;
- cpio = (struct cpio *)a->format_data;
ret_final = ARCHIVE_OK;
sconv = get_sconv(a);
@@ -320,7 +324,7 @@ write_header(struct archive_write *a, struct archive_entry *entry)
ret_final = ARCHIVE_WARN;
}
/* Include trailing null. */
- pathlength = (int)len + 1;
+ pathlength = len + 1;
memset(h, 0, sizeof(h));
format_octal(070707, h + c_magic_offset, c_magic_size);
@@ -351,7 +355,12 @@ write_header(struct archive_write *a, struct archive_entry *entry)
else
format_octal(0, h + c_rdev_offset, c_rdev_size);
format_octal(archive_entry_mtime(entry), h + c_mtime_offset, c_mtime_size);
- format_octal(pathlength, h + c_namesize_offset, c_namesize_size);
+ if (format_octal((int64_t)pathlength, h + c_namesize_offset, c_namesize_size)) {
+ archive_set_error(&a->archive, ERANGE,
+ "Filename is too long for cpio format");
+ ret_final = ARCHIVE_FAILED;
+ goto exit_write_header;
+ }
/* Non-regular files don't store bodies. */
if (archive_entry_filetype(entry) != AE_IFREG)
@@ -415,10 +424,9 @@ exit_write_header:
static ssize_t
archive_write_odc_data(struct archive_write *a, const void *buff, size_t s)
{
- struct cpio *cpio;
+ struct cpio *cpio = a->format_data;
int ret;
- cpio = (struct cpio *)a->format_data;
if (s > cpio->entry_bytes_remaining)
s = (size_t)cpio->entry_bytes_remaining;
@@ -482,9 +490,8 @@ archive_write_odc_close(struct archive_write *a)
static int
archive_write_odc_free(struct archive_write *a)
{
- struct cpio *cpio;
+ struct cpio *cpio = a->format_data;
- cpio = (struct cpio *)a->format_data;
free(cpio->ino_list);
free(cpio);
a->format_data = NULL;
@@ -494,9 +501,8 @@ archive_write_odc_free(struct archive_write *a)
static int
archive_write_odc_finish_entry(struct archive_write *a)
{
- struct cpio *cpio;
+ struct cpio *cpio = a->format_data;
- cpio = (struct cpio *)a->format_data;
- return (__archive_write_nulls(a,
- (size_t)cpio->entry_bytes_remaining));
+ return (__archive_write_nulls(a,
+ cpio->entry_bytes_remaining));
}
diff --git a/contrib/libarchive/libarchive/archive_write_set_format_gnutar.c b/contrib/libarchive/libarchive/archive_write_set_format_gnutar.c
index b67007a631c0..5a767e1bd72b 100644
--- a/contrib/libarchive/libarchive/archive_write_set_format_gnutar.c
+++ b/contrib/libarchive/libarchive/archive_write_set_format_gnutar.c
@@ -174,6 +174,11 @@ archive_write_set_format_gnutar(struct archive *_a)
struct archive_write *a = (struct archive_write *)_a;
struct gnutar *gnutar;
+ archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_write_set_format_gnutar");
+
+ (void)__archive_write_unregister_format(a);
+
gnutar = calloc(1, sizeof(*gnutar));
if (gnutar == NULL) {
archive_set_error(&a->archive, ENOMEM,
@@ -197,7 +202,7 @@ static int
archive_write_gnutar_options(struct archive_write *a, const char *key,
const char *val)
{
- struct gnutar *gnutar = (struct gnutar *)a->format_data;
+ struct gnutar *gnutar = a->format_data;
int ret = ARCHIVE_FAILED;
if (strcmp(key, "hdrcharset") == 0) {
@@ -231,9 +236,8 @@ archive_write_gnutar_close(struct archive_write *a)
static int
archive_write_gnutar_free(struct archive_write *a)
{
- struct gnutar *gnutar;
+ struct gnutar *gnutar = a->format_data;
- gnutar = (struct gnutar *)a->format_data;
free(gnutar);
a->format_data = NULL;
return (ARCHIVE_OK);
@@ -242,12 +246,11 @@ archive_write_gnutar_free(struct archive_write *a)
static int
archive_write_gnutar_finish_entry(struct archive_write *a)
{
- struct gnutar *gnutar;
+ struct gnutar *gnutar = a->format_data;
int ret;
- gnutar = (struct gnutar *)a->format_data;
- ret = __archive_write_nulls(a, (size_t)
- (gnutar->entry_bytes_remaining + gnutar->entry_padding));
+ ret = __archive_write_nulls(a,
+ gnutar->entry_bytes_remaining + gnutar->entry_padding);
gnutar->entry_bytes_remaining = gnutar->entry_padding = 0;
return (ret);
}
@@ -255,10 +258,9 @@ archive_write_gnutar_finish_entry(struct archive_write *a)
static ssize_t
archive_write_gnutar_data(struct archive_write *a, const void *buff, size_t s)
{
- struct gnutar *gnutar;
+ struct gnutar *gnutar = a->format_data;
int ret;
- gnutar = (struct gnutar *)a->format_data;
if (s > gnutar->entry_bytes_remaining)
s = (size_t)gnutar->entry_bytes_remaining;
ret = __archive_write_output(a, buff, s);
@@ -272,15 +274,13 @@ static int
archive_write_gnutar_header(struct archive_write *a,
struct archive_entry *entry)
{
+ struct gnutar *gnutar = a->format_data;
char buff[512];
int r, ret, ret2 = ARCHIVE_OK;
char tartype;
- struct gnutar *gnutar;
struct archive_string_conv *sconv;
struct archive_entry *entry_main;
- gnutar = (struct gnutar *)a->format_data;
-
/* Setup default string conversion. */
if (gnutar->opt_sconv == NULL) {
if (!gnutar->init_default_conversion) {
@@ -321,7 +321,8 @@ archive_write_gnutar_header(struct archive_write *a,
const wchar_t *wp;
wp = archive_entry_pathname_w(entry);
- if (wp != NULL && wp[wcslen(wp) -1] != L'/') {
+ if (wp != NULL && wp[0] != L'\0' &&
+ wp[wcslen(wp) - 1] != L'/') {
struct archive_wstring ws;
archive_string_init(&ws);
@@ -493,6 +494,13 @@ archive_write_gnutar_header(struct archive_write *a,
size_t length = gnutar->linkname_length + 1;
struct archive_entry *temp = archive_entry_new2(&a->archive);
+ if (temp == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate memory for Linkname");
+ ret = ARCHIVE_FATAL;
+ goto exit_write_header;
+ }
+
/* Uname/gname here don't really matter since no one reads them;
* these are the values that GNU tar happens to use on FreeBSD. */
archive_entry_set_uname(temp, "root");
@@ -523,6 +531,13 @@ archive_write_gnutar_header(struct archive_write *a,
size_t length = gnutar->pathname_length + 1;
struct archive_entry *temp = archive_entry_new2(&a->archive);
+ if (temp == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate memory for Linkname");
+ ret = ARCHIVE_FATAL;
+ goto exit_write_header;
+ }
+
/* Uname/gname here don't really matter since no one reads them;
* these are the values that GNU tar happens to use on FreeBSD. */
archive_entry_set_uname(temp, "root");
@@ -588,13 +603,11 @@ static int
archive_format_gnutar_header(struct archive_write *a, char h[512],
struct archive_entry *entry, char tartype)
{
+ struct gnutar *gnutar = a->format_data;
unsigned int checksum;
int i, ret;
size_t copy_length;
const char *p;
- struct gnutar *gnutar;
-
- gnutar = (struct gnutar *)a->format_data;
ret = 0;
@@ -651,7 +664,7 @@ archive_format_gnutar_header(struct archive_write *a, char h[512],
copy_length = gnutar->gname_length;
}
if (copy_length > 0) {
- if (strlen(p) > GNUTAR_gname_size)
+ if (copy_length > GNUTAR_gname_size)
copy_length = GNUTAR_gname_size;
memcpy(h + GNUTAR_gname_offset, p, copy_length);
}
diff --git a/contrib/libarchive/libarchive/archive_write_set_format_iso9660.c b/contrib/libarchive/libarchive/archive_write_set_format_iso9660.c
index 359a2737365f..ee50f7c0842b 100644
--- a/contrib/libarchive/libarchive/archive_write_set_format_iso9660.c
+++ b/contrib/libarchive/libarchive/archive_write_set_format_iso9660.c
@@ -119,6 +119,8 @@ static const unsigned char zisofs_magic[8] = {
#define ZF_LOG2_BS 15 /* log2 block size; 32K bytes. */
#define ZF_BLOCK_SIZE (1UL << ZF_LOG2_BS)
+#define MAX_JOLIET_ID_NUM 46656 /* 3 base 36 digits */
+
/*
* Manage extra records.
*/
@@ -764,7 +766,7 @@ struct iso9660 {
#ifdef HAVE_ZLIB_H
/*
* Copy a compressed file to iso9660.zisofs.temp_fd
- * and also copy a uncompressed file(original file) to
+ * and also copy an uncompressed file(original file) to
* iso9660.temp_fd . If the number of logical block
* of the compressed file is less than the number of
* logical block of the uncompressed file, use it and
@@ -1008,7 +1010,7 @@ static int idr_start(struct archive_write *, struct idr *,
static void idr_register(struct idr *, struct isoent *, int,
int);
static void idr_extend_identifier(struct idrent *, int, int);
-static void idr_resolve(struct idr *, void (*)(unsigned char *, int));
+static int idr_resolve(struct idr *, void (*)(unsigned char *, int));
static void idr_set_num(unsigned char *, int);
static void idr_set_num_beutf16(unsigned char *, int);
static int isoent_gen_iso9660_identifier(struct archive_write *,
@@ -1057,8 +1059,7 @@ archive_write_set_format_iso9660(struct archive *_a)
ARCHIVE_STATE_NEW, "archive_write_set_format_iso9660");
/* If another format was already registered, unregister it. */
- if (a->format_free != NULL)
- (a->format_free)(a);
+ (void)__archive_write_unregister_format(a);
iso9660 = calloc(1, sizeof(*iso9660));
if (iso9660 == NULL) {
@@ -1168,6 +1169,7 @@ archive_write_set_format_iso9660(struct archive *_a)
iso9660->cur_dirent = iso9660->primary.rootent;
archive_string_init(&(iso9660->cur_dirstr));
if (archive_string_ensure(&(iso9660->cur_dirstr), 1) == NULL) {
+ free(iso9660->cur_dirent);
free(iso9660);
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory");
@@ -1424,8 +1426,8 @@ iso9660_options(struct archive_write *a, const char *key, const char *value)
break;
case 'i':
if (strcmp(key, "iso-level") == 0) {
- if (value != NULL && value[1] == '\0' &&
- (value[0] >= '1' && value[0] <= '4')) {
+ if (value != NULL && value[0] >= '1' &&
+ value[0] <= '4' && value[1] == '\0') {
iso9660->opt.iso_level = value[0]-'0';
return (ARCHIVE_OK);
}
@@ -1526,13 +1528,11 @@ invalid_value:
static int
iso9660_write_header(struct archive_write *a, struct archive_entry *entry)
{
- struct iso9660 *iso9660;
+ struct iso9660 *iso9660 = a->format_data;
struct isofile *file;
struct isoent *isoent;
int r, ret = ARCHIVE_OK;
- iso9660 = a->format_data;
-
iso9660->cur_file = NULL;
iso9660->bytes_remaining = 0;
iso9660->need_multi_extent = 0;
@@ -1674,7 +1674,7 @@ wb_write_to_temp(struct archive_write *a, const void *buff, size_t s)
* order to reduce a extra memory copy.
*/
if (wb_remaining(a) == wb_buffmax() && s > (1024 * 16)) {
- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
+ struct iso9660 *iso9660 = a->format_data;
xs = s % LOGICAL_BLOCK_SIZE;
iso9660->wbuff_offset += s - xs;
if (write_to_temp(a, buff, s - xs) != ARCHIVE_OK)
@@ -1856,11 +1856,9 @@ iso9660_finish_entry(struct archive_write *a)
static int
iso9660_close(struct archive_write *a)
{
- struct iso9660 *iso9660;
+ struct iso9660 *iso9660 = a->format_data;
int ret, blocks;
- iso9660 = a->format_data;
-
/*
* Write remaining data out to the temporary file.
*/
@@ -2118,11 +2116,9 @@ iso9660_close(struct archive_write *a)
static int
iso9660_free(struct archive_write *a)
{
- struct iso9660 *iso9660;
+ struct iso9660 *iso9660 = a->format_data;
int i, ret;
- iso9660 = a->format_data;
-
/* Close the temporary file. */
if (iso9660->temp_fd >= 0)
close(iso9660->temp_fd);
@@ -2918,10 +2914,10 @@ set_directory_record_rr(unsigned char *bp, int dr_len,
extra_tell_used_size(&ctl, length);
if (extra_space(&ctl) < 6) {
bp = extra_next_record(&ctl, 6);
- nmmax = extra_space(&ctl);
- if (nmmax > 0xff)
- nmmax = 0xff;
}
+ nmmax = extra_space(&ctl);
+ if (nmmax > 0xff)
+ nmmax = 0xff;
if (bp != NULL) {
bp[1] = 'N';
bp[2] = 'M';
@@ -3036,8 +3032,8 @@ set_directory_record_rr(unsigned char *bp, int dr_len,
const char *sl;
char sl_last;
- if (extra_space(&ctl) < 7)
- bp = extra_next_record(&ctl, 7);
+ if (extra_space(&ctl) < 12)
+ bp = extra_next_record(&ctl, 12);
sl = file->symlink.s;
sl_last = '\0';
if (bp != NULL) {
@@ -3616,7 +3612,7 @@ get_dir_rec_size(struct iso9660 *iso9660, struct isoent *isoent,
static inline unsigned char *
wb_buffptr(struct archive_write *a)
{
- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
+ struct iso9660 *iso9660 = a->format_data;
return (&(iso9660->wbuff[sizeof(iso9660->wbuff)
- iso9660->wbuff_remaining]));
@@ -3625,7 +3621,7 @@ wb_buffptr(struct archive_write *a)
static int
wb_write_out(struct archive_write *a)
{
- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
+ struct iso9660 *iso9660 = a->format_data;
size_t wsize, nw;
int r;
@@ -3650,7 +3646,7 @@ wb_write_out(struct archive_write *a)
static int
wb_consume(struct archive_write *a, size_t size)
{
- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
+ struct iso9660 *iso9660 = a->format_data;
if (size > iso9660->wbuff_remaining ||
iso9660->wbuff_remaining == 0) {
@@ -3671,7 +3667,7 @@ wb_consume(struct archive_write *a, size_t size)
static int
wb_set_offset(struct archive_write *a, int64_t off)
{
- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
+ struct iso9660 *iso9660 = a->format_data;
int64_t used, ext_bytes;
if (iso9660->wbuff_type != WB_TO_TEMP) {
@@ -3838,7 +3834,7 @@ set_file_identifier(unsigned char *bp, int from, int to, enum vdc vdc,
static int
write_VD(struct archive_write *a, struct vdd *vdd)
{
- struct iso9660 *iso9660;
+ struct iso9660 *iso9660 = a->format_data;
unsigned char *bp;
uint16_t volume_set_size = 1;
char identifier[256];
@@ -3847,7 +3843,6 @@ write_VD(struct archive_write *a, struct vdd *vdd)
unsigned char vd_ver, fst_ver;
int r;
- iso9660 = a->format_data;
switch (vdd->vdd_type) {
case VDD_JOLIET:
vdt = VDT_SUPPLEMENTARY;
@@ -3985,10 +3980,9 @@ write_VD(struct archive_write *a, struct vdd *vdd)
static int
write_VD_boot_record(struct archive_write *a)
{
- struct iso9660 *iso9660;
+ struct iso9660 *iso9660 = a->format_data;
unsigned char *bp;
- iso9660 = a->format_data;
bp = wb_buffptr(a) -1;
/* Volume Descriptor Type */
set_VD_bp(bp, VDT_BOOT_RECORD, 1);
@@ -4056,7 +4050,7 @@ set_option_info(struct archive_string *info, int *opt, const char *key,
static int
write_information_block(struct archive_write *a)
{
- struct iso9660 *iso9660;
+ struct iso9660 *iso9660 = a->format_data;
char buf[128];
const char *v;
int opt, r;
@@ -4064,7 +4058,6 @@ write_information_block(struct archive_write *a)
size_t info_size = LOGICAL_BLOCK_SIZE *
NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK;
- iso9660 = (struct iso9660 *)a->format_data;
if (info_size > wb_remaining(a)) {
r = wb_write_out(a);
if (r != ARCHIVE_OK)
@@ -4281,9 +4274,11 @@ _write_path_table(struct archive_write *a, int type_m, int depth,
set_num_731(bp+3, np->dir_location);
/* Parent Directory Number */
if (type_m)
- set_num_722(bp+7, np->parent->dir_number);
+ set_num_722(bp+7,
+ np->parent != NULL ? np->parent->dir_number : 0);
else
- set_num_721(bp+7, np->parent->dir_number);
+ set_num_721(bp+7,
+ np->parent != NULL ? np->parent->dir_number : 0);
/* Directory Identifier */
if (np->identifier == NULL)
bp[9] = 0;
@@ -4712,14 +4707,12 @@ cleanup_backslash_2(wchar_t *p)
static int
isofile_gen_utility_names(struct archive_write *a, struct isofile *file)
{
- struct iso9660 *iso9660;
+ struct iso9660 *iso9660 = a->format_data;
const char *pathname;
char *p, *dirname, *slash;
size_t len;
int ret = ARCHIVE_OK;
- iso9660 = a->format_data;
-
archive_string_empty(&(file->parentdir));
archive_string_empty(&(file->basename));
archive_string_empty(&(file->basename_utf16));
@@ -4910,20 +4903,29 @@ isofile_gen_utility_names(struct archive_write *a, struct isofile *file)
* --> 'dir/dir2/'
*/
char *rp = p -1;
+ size_t off;
+ for (off = 4; p[off] == '/'; off++)
+ ;
while (rp >= dirname) {
if (*rp == '/')
break;
--rp;
}
if (rp > dirname) {
- strcpy(rp, p+3);
+ memmove(rp + 1, p + off, strlen(p + off) + 1);
p = rp;
} else {
- strcpy(dirname, p+4);
+ memmove(dirname, p + off, strlen(p + off) + 1);
p = dirname;
}
} else
p++;
+ } else if (p == dirname && p[0] == '.' && p[1] == '.' && p[2] == '/') {
+ size_t off;
+ for (off = 3; p[off] == '/'; off++)
+ ;
+ memmove(dirname, p + off, strlen(p + off) + 1);
+ p = dirname;
} else
p++;
}
@@ -5526,7 +5528,7 @@ isoent_setup_file_location(struct iso9660 *iso9660, int location)
static int
get_path_component(char *name, size_t n, const char *fn)
{
- char *p;
+ const char *p;
size_t l;
p = strchr(fn, '/');
@@ -5549,6 +5551,7 @@ get_path_component(char *name, size_t n, const char *fn)
static int
isoent_tree(struct archive_write *a, struct isoent **isoentpp)
{
+ struct iso9660 *iso9660 = a->format_data;
#if defined(_WIN32) && !defined(__CYGWIN__)
char name[_MAX_FNAME];/* Included null terminator size. */
#elif defined(NAME_MAX) && NAME_MAX >= 255
@@ -5556,7 +5559,6 @@ isoent_tree(struct archive_write *a, struct isoent **isoentpp)
#else
char name[256];
#endif
- struct iso9660 *iso9660 = a->format_data;
struct isoent *dent, *isoent, *np;
struct isofile *f1, *f2;
const char *fn, *p;
@@ -5903,21 +5905,22 @@ idr_register(struct idr *idr, struct isoent *isoent, int weight, int noff)
static void
idr_extend_identifier(struct idrent *wnp, int numsize, int nullsize)
{
- unsigned char *p;
- int wnp_ext_off;
-
- wnp_ext_off = wnp->isoent->ext_off;
- if (wnp->noff + numsize != wnp_ext_off) {
- p = (unsigned char *)wnp->isoent->identifier;
- /* Extend the filename; foo.c --> foo___.c */
- memmove(p + wnp->noff + numsize, p + wnp_ext_off,
+ if (wnp->noff + numsize != wnp->isoent->ext_off) {
+ /*
+ * Extend the filename; foo.c --> foo___.c
+ *
+ * The caller must verify that enough memory is available.
+ */
+ memmove(wnp->isoent->identifier + wnp->noff + numsize,
+ wnp->isoent->identifier + wnp->isoent->ext_off,
wnp->isoent->ext_len + nullsize);
- wnp->isoent->ext_off = wnp_ext_off = wnp->noff + numsize;
- wnp->isoent->id_len = wnp_ext_off + wnp->isoent->ext_len;
+ wnp->isoent->ext_off = wnp->noff + numsize;
+ wnp->isoent->id_len =
+ wnp->isoent->ext_off + wnp->isoent->ext_len;
}
}
-static void
+static int
idr_resolve(struct idr *idr, void (*fsetnum)(unsigned char *p, int num))
{
struct idrent *n;
@@ -5927,10 +5930,13 @@ idr_resolve(struct idr *idr, void (*fsetnum)(unsigned char *p, int num))
idr_extend_identifier(n, idr->num_size, idr->null_size);
p = (unsigned char *)n->isoent->identifier + n->noff;
do {
+ if (n->avail->rename_num >= MAX_JOLIET_ID_NUM)
+ return (-ERANGE);
fsetnum(p, n->avail->rename_num++);
} while (!__archive_rb_tree_insert_node(
&(idr->rbtree), &(n->rbnode)));
}
+ return (0);
}
static void
@@ -5980,7 +5986,7 @@ static int
isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent,
struct idr *idr)
{
- struct iso9660 *iso9660;
+ struct iso9660 *iso9660 = a->format_data;
struct isoent *np;
char *p;
int l, r;
@@ -5990,11 +5996,14 @@ isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent,
static const struct archive_rb_tree_ops rb_ops = {
isoent_cmp_node_iso9660, isoent_cmp_key_iso9660
};
+ const int num_size = 3;
+ const int dot_size = 1;
+ const int version_size = 2;
+ const int null_size = 1;
if (isoent->children.cnt == 0)
- return (0);
+ return (ARCHIVE_OK);
- iso9660 = a->format_data;
char_map = idr->char_map;
if (iso9660->opt.iso_level <= 3) {
allow_ldots = 0;
@@ -6030,7 +6039,7 @@ isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent,
fnmax = ffmax = dnmax = 207;
}
- r = idr_start(a, idr, isoent->children.cnt, ffmax, 3, 1, &rb_ops);
+ r = idr_start(a, idr, isoent->children.cnt, ffmax, num_size, null_size, &rb_ops);
if (r < 0)
return (r);
@@ -6039,7 +6048,7 @@ isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent,
int ext_off, noff, weight;
l = (int)np->file->basename.length;
- p = malloc(l+31+2+1);
+ p = malloc(l + num_size + dot_size + version_size + null_size);
if (p == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory");
@@ -6189,13 +6198,19 @@ isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent,
noff = ext_off - 1;
else
noff = ext_off;
+ if (noff < 0)
+ noff = 0;
}
/* Register entry to the identifier resolver. */
idr_register(idr, np, weight, noff);
}
/* Resolve duplicate identifier. */
- idr_resolve(idr, idr_set_num);
+ r = idr_resolve(idr, idr_set_num);
+ if (r < 0) {
+ archive_set_error(&a->archive, -r, "Too many duplicated identifiers");
+ return (ARCHIVE_FATAL);
+ }
/* Add a period and a version number to identifiers. */
for (np = isoent->children.first; np != NULL; np = np->chnext) {
@@ -6230,7 +6245,7 @@ static int
isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
struct idr *idr)
{
- struct iso9660 *iso9660;
+ struct iso9660 *iso9660 = a->format_data;
struct isoent *np;
unsigned char *p;
size_t l;
@@ -6239,17 +6254,18 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
static const struct archive_rb_tree_ops rb_ops = {
isoent_cmp_node_joliet, isoent_cmp_key_joliet
};
+ const int num_size = 6;
+ const int null_size = 2;
if (isoent->children.cnt == 0)
- return (0);
+ return (ARCHIVE_OK);
- iso9660 = a->format_data;
if (iso9660->opt.joliet == OPT_JOLIET_LONGNAME)
ffmax = 206;
else
ffmax = 128;
- r = idr_start(a, idr, isoent->children.cnt, (int)ffmax, 6, 2, &rb_ops);
+ r = idr_start(a, idr, isoent->children.cnt, (int)ffmax, num_size, null_size, &rb_ops);
if (r < 0)
return (r);
@@ -6265,7 +6281,7 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
if ((l = np->file->basename_utf16.length) > ffmax)
l = ffmax;
- p = malloc((l+1)*2);
+ p = malloc(l + num_size + null_size);
if (p == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory");
@@ -6334,12 +6350,18 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
noff = ext_off - 2;
else
noff = ext_off;
+ if (noff < 0)
+ noff = 0;
/* Register entry to the identifier resolver. */
idr_register(idr, np, weight, noff);
}
/* Resolve duplicate identifier with Joliet Volume. */
- idr_resolve(idr, idr_set_num_beutf16);
+ r = idr_resolve(idr, idr_set_num_beutf16);
+ if (r < 0) {
+ archive_set_error(&a->archive, -r, "Too many duplicated identifiers");
+ return (ARCHIVE_FATAL);
+ }
return (ARCHIVE_OK);
}
@@ -6727,7 +6749,12 @@ isoent_rr_move_dir(struct archive_write *a, struct isoent **rr_moved,
/*
* The mvent becomes a child of the rr_moved entry.
*/
- isoent_add_child_tail(rrmoved, mvent);
+ if (!isoent_add_child_tail(rrmoved, mvent)) {
+ _isoent_free(mvent);
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Unable to insert rr_moved entry");
+ return (ARCHIVE_FATAL);
+ }
archive_entry_set_nlink(rrmoved->file->entry,
archive_entry_nlink(rrmoved->file->entry) + 1);
/*
@@ -6820,7 +6847,15 @@ _compare_path_table(const void *v1, const void *v2)
p2 = *((const struct isoent **)(uintptr_t)v2);
/* Compare parent directory number */
- cmp = p1->parent->dir_number - p2->parent->dir_number;
+ if (p1->parent == NULL || p2->parent == NULL) {
+ if (p1->parent == p2->parent)
+ cmp = 0;
+ else if (p1->parent == NULL)
+ return (-1);
+ else
+ return (1);
+ } else
+ cmp = p1->parent->dir_number - p2->parent->dir_number;
if (cmp != 0)
return (cmp);
@@ -6863,7 +6898,15 @@ _compare_path_table_joliet(const void *v1, const void *v2)
p2 = *((const struct isoent **)(uintptr_t)v2);
/* Compare parent directory number */
- cmp = p1->parent->dir_number - p2->parent->dir_number;
+ if (p1->parent == NULL || p2->parent == NULL) {
+ if (p1->parent == p2->parent)
+ cmp = 0;
+ else if (p1->parent == NULL)
+ return (-1);
+ else
+ return (1);
+ } else
+ cmp = p1->parent->dir_number - p2->parent->dir_number;
if (cmp != 0)
return (cmp);
@@ -7465,8 +7508,9 @@ zisofs_init(struct archive_write *a, struct isofile *file)
(uint32_t)archive_entry_size(file->entry);
/* Calculate a size of Block Pointers of zisofs. */
- _ceil = (file->zisofs.uncompressed_size + ZF_BLOCK_SIZE -1)
- >> file->zisofs.log2_bs;
+ _ceil = (size_t)(((uint64_t)file->zisofs.uncompressed_size +
+ (ZF_BLOCK_SIZE - 1))
+ >> file->zisofs.log2_bs);
iso9660->zisofs.block_pointers_cnt = (int)_ceil + 1;
iso9660->zisofs.block_pointers_idx = 0;
diff --git a/contrib/libarchive/libarchive/archive_write_set_format_mtree.c b/contrib/libarchive/libarchive/archive_write_set_format_mtree.c
index a4ffec8954d9..b3433507e91a 100644
--- a/contrib/libarchive/libarchive/archive_write_set_format_mtree.c
+++ b/contrib/libarchive/libarchive/archive_write_set_format_mtree.c
@@ -117,7 +117,7 @@ struct mtree_entry {
int64_t ino;
};
-struct mtree_writer {
+struct mtree {
struct mtree_entry *mtree_entry;
struct mtree_entry *root;
struct mtree_entry *cur_dirent;
@@ -220,10 +220,10 @@ static int attr_counter_inc(struct attr_counter **, struct attr_counter *,
struct attr_counter *, struct mtree_entry *);
static struct attr_counter * attr_counter_new(struct mtree_entry *,
struct attr_counter *);
-static int attr_counter_set_collect(struct mtree_writer *,
+static int attr_counter_set_collect(struct mtree *,
struct mtree_entry *);
-static void attr_counter_set_free(struct mtree_writer *);
-static int get_global_set_keys(struct mtree_writer *, struct mtree_entry *);
+static void attr_counter_set_free(struct mtree *);
+static int get_global_set_keys(struct mtree *, struct mtree_entry *);
static int mtree_entry_add_child_tail(struct mtree_entry *,
struct mtree_entry *);
static int mtree_entry_create_virtual_dir(struct archive_write *, const char *,
@@ -236,14 +236,14 @@ static int mtree_entry_exchange_same_entry(struct archive_write *,
static void mtree_entry_free(struct mtree_entry *);
static int mtree_entry_new(struct archive_write *, struct archive_entry *,
struct mtree_entry **);
-static void mtree_entry_register_free(struct mtree_writer *);
-static void mtree_entry_register_init(struct mtree_writer *);
+static void mtree_entry_register_free(struct mtree *);
+static void mtree_entry_register_init(struct mtree *);
static int mtree_entry_setup_filenames(struct archive_write *,
struct mtree_entry *, struct archive_entry *);
static int mtree_entry_tree_add(struct archive_write *, struct mtree_entry **);
-static void sum_init(struct mtree_writer *);
-static void sum_update(struct mtree_writer *, const void *, size_t);
-static void sum_final(struct mtree_writer *, struct reg_info *);
+static void sum_init(struct mtree *);
+static void sum_update(struct mtree *, const void *, size_t);
+static void sum_final(struct mtree *, struct reg_info *);
static void sum_write(struct archive_string *, struct reg_info *);
static int write_mtree_entry(struct archive_write *, struct mtree_entry *);
static int write_dot_dot_entry(struct archive_write *, struct mtree_entry *);
@@ -307,14 +307,14 @@ static const uint32_t crctab[] = {
static const unsigned char safe_char[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
- /* !"$%&'()*+,-./ EXCLUSION:0x20( ) 0x23(#) */
- 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
- /* 0123456789:;<>? EXCLUSION:0x3d(=) */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, /* 30 - 3F */
+ /* !"$%&'()+,-./ EXCLUSION:0x20( ) 0x23(#) 0x2a(*) */
+ 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* 20 - 2F */
+ /* 0123456789:;<> EXCLUSION:0x3d(=) 0x3f(?) */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, /* 30 - 3F */
/* @ABCDEFGHIJKLMNO */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
- /* PQRSTUVWXYZ[]^_ EXCLUSION:0x5c(\) */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, /* 50 - 5F */
+ /* PQRSTUVWXYZ]^_ EXCLUSION:0x5b([) 0x5c(\) */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, /* 50 - 5F */
/* `abcdefghijklmno */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
/* pqrstuvwxyz{|}~ */
@@ -358,7 +358,7 @@ mtree_quote(struct archive_string *s, const char *str)
* Indent a line as the mtree utility does so it is readable for people.
*/
static void
-mtree_indent(struct mtree_writer *mtree)
+mtree_indent(struct mtree *mtree)
{
int i, fn, nd, pd;
const char *r, *s, *x;
@@ -434,7 +434,7 @@ mtree_indent(struct mtree_writer *mtree)
* collected by the attr_counter_set_collect() function.
*/
static void
-write_global(struct mtree_writer *mtree)
+write_global(struct mtree *mtree)
{
struct archive_string setstr;
struct archive_string unsetstr;
@@ -636,7 +636,7 @@ attr_counter_inc(struct attr_counter **top, struct attr_counter *ac,
* Tabulate uid, gid, mode and fflags of a entry in order to be used for /set.
*/
static int
-attr_counter_set_collect(struct mtree_writer *mtree, struct mtree_entry *me)
+attr_counter_set_collect(struct mtree *mtree, struct mtree_entry *me)
{
struct attr_counter *ac, *last;
struct attr_counter_set *acs = &mtree->acs;
@@ -713,7 +713,7 @@ attr_counter_set_collect(struct mtree_writer *mtree, struct mtree_entry *me)
}
static void
-attr_counter_set_free(struct mtree_writer *mtree)
+attr_counter_set_free(struct mtree *mtree)
{
struct attr_counter_set *acs = &mtree->acs;
@@ -724,7 +724,7 @@ attr_counter_set_free(struct mtree_writer *mtree)
}
static int
-get_global_set_keys(struct mtree_writer *mtree, struct mtree_entry *me)
+get_global_set_keys(struct mtree *mtree, struct mtree_entry *me)
{
int keys;
@@ -801,6 +801,8 @@ mtree_entry_new(struct archive_write *a, struct archive_entry *entry,
archive_strcpy(&me->symlink, s);
me->nlink = archive_entry_nlink(entry);
me->filetype = archive_entry_filetype(entry);
+ if (me->filetype == AE_IFLNK && me->symlink.s == NULL)
+ archive_strcpy(&me->symlink, "");
me->mode = archive_entry_mode(entry) & 07777;
me->uid = archive_entry_uid(entry);
me->gid = archive_entry_gid(entry);
@@ -911,7 +913,7 @@ static int
archive_write_mtree_header(struct archive_write *a,
struct archive_entry *entry)
{
- struct mtree_writer *mtree= a->format_data;
+ struct mtree *mtree = a->format_data;
struct mtree_entry *mtree_entry;
int r, r2;
@@ -954,7 +956,7 @@ archive_write_mtree_header(struct archive_write *a,
static int
write_mtree_entry(struct archive_write *a, struct mtree_entry *me)
{
- struct mtree_writer *mtree = a->format_data;
+ struct mtree *mtree = a->format_data;
struct archive_string *str;
int keys, ret;
@@ -988,7 +990,8 @@ write_mtree_entry(struct archive_write *a, struct mtree_entry *me)
* a full pathname.
*/
mtree_quote(str, me->parentdir.s);
- archive_strappend_char(str, '/');
+ if (strcmp(me->basename.s, ".") != 0)
+ archive_strappend_char(str, '/');
}
mtree_quote(str, me->basename.s);
@@ -1104,7 +1107,7 @@ write_mtree_entry(struct archive_write *a, struct mtree_entry *me)
static int
write_dot_dot_entry(struct archive_write *a, struct mtree_entry *n)
{
- struct mtree_writer *mtree = a->format_data;
+ struct mtree *mtree = a->format_data;
int ret;
if (n->parentdir.s) {
@@ -1139,12 +1142,14 @@ write_dot_dot_entry(struct archive_write *a, struct mtree_entry *n)
static int
write_mtree_entry_tree(struct archive_write *a)
{
- struct mtree_writer *mtree = a->format_data;
+ struct mtree *mtree = a->format_data;
struct mtree_entry *np = mtree->root;
struct archive_rb_node *n;
int ret;
do {
+ if (np->dir_info == NULL)
+ break;
if (mtree->output_global_set) {
/*
* Collect attribute information to know which value
@@ -1240,7 +1245,7 @@ write_mtree_entry_tree(struct archive_write *a)
static int
archive_write_mtree_finish_entry(struct archive_write *a)
{
- struct mtree_writer *mtree = a->format_data;
+ struct mtree *mtree = a->format_data;
struct mtree_entry *me;
if ((me = mtree->mtree_entry) == NULL)
@@ -1256,7 +1261,7 @@ archive_write_mtree_finish_entry(struct archive_write *a)
static int
archive_write_mtree_close(struct archive_write *a)
{
- struct mtree_writer *mtree= a->format_data;
+ struct mtree *mtree = a->format_data;
int ret;
if (mtree->root != NULL) {
@@ -1273,7 +1278,7 @@ archive_write_mtree_close(struct archive_write *a)
static ssize_t
archive_write_mtree_data(struct archive_write *a, const void *buff, size_t n)
{
- struct mtree_writer *mtree= a->format_data;
+ struct mtree *mtree = a->format_data;
if (n > mtree->entry_bytes_remaining)
n = (size_t)mtree->entry_bytes_remaining;
@@ -1292,7 +1297,7 @@ archive_write_mtree_data(struct archive_write *a, const void *buff, size_t n)
static int
archive_write_mtree_free(struct archive_write *a)
{
- struct mtree_writer *mtree= a->format_data;
+ struct mtree *mtree = a->format_data;
if (mtree == NULL)
return (ARCHIVE_OK);
@@ -1312,7 +1317,7 @@ static int
archive_write_mtree_options(struct archive_write *a, const char *key,
const char *value)
{
- struct mtree_writer *mtree= a->format_data;
+ struct mtree *mtree = a->format_data;
int keybit = 0;
switch (key[0]) {
@@ -1424,12 +1429,11 @@ static int
archive_write_set_format_mtree_default(struct archive *_a, const char *fn)
{
struct archive_write *a = (struct archive_write *)_a;
- struct mtree_writer *mtree;
+ struct mtree *mtree;
archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, fn);
- if (a->format_free != NULL)
- (a->format_free)(a);
+ (void)__archive_write_unregister_format(a);
if ((mtree = calloc(1, sizeof(*mtree))) == NULL) {
archive_set_error(&a->archive, ENOMEM,
@@ -1476,9 +1480,7 @@ archive_write_set_format_mtree_classic(struct archive *_a)
"archive_write_set_format_mtree_classic");
if (r == ARCHIVE_OK) {
struct archive_write *a = (struct archive_write *)_a;
- struct mtree_writer *mtree;
-
- mtree = (struct mtree_writer *)a->format_data;
+ struct mtree *mtree = a->format_data;
/* Set to output a mtree archive in classic format. */
mtree->classic = 1;
@@ -1490,7 +1492,7 @@ archive_write_set_format_mtree_classic(struct archive *_a)
}
static void
-sum_init(struct mtree_writer *mtree)
+sum_init(struct mtree *mtree)
{
mtree->compute_sum = 0;
@@ -1551,7 +1553,7 @@ sum_init(struct mtree_writer *mtree)
}
static void
-sum_update(struct mtree_writer *mtree, const void *buff, size_t n)
+sum_update(struct mtree *mtree, const void *buff, size_t n)
{
if (mtree->compute_sum & F_CKSUM) {
/*
@@ -1609,8 +1611,9 @@ sum_update(struct mtree_writer *mtree, const void *buff, size_t n)
}
static void
-sum_final(struct mtree_writer *mtree, struct reg_info *reg)
+sum_final(struct mtree *mtree, struct reg_info *reg)
{
+ struct ae_digest digest;
if (mtree->compute_sum & F_CKSUM) {
uint64_t len;
@@ -1620,40 +1623,34 @@ sum_final(struct mtree_writer *mtree, struct reg_info *reg)
reg->crc = ~mtree->crc;
}
#ifdef ARCHIVE_HAS_MD5
- if ((mtree->compute_sum & F_MD5)
- && !(reg->mset_digest & AE_MSET_DIGEST_MD5))
+ if (mtree->compute_sum & F_MD5)
- archive_md5_final(&mtree->md5ctx, reg->digest.md5);
+ archive_md5_final(&mtree->md5ctx, (reg->mset_digest & AE_MSET_DIGEST_MD5) ? digest.md5 : reg->digest.md5);
#endif
#ifdef ARCHIVE_HAS_RMD160
- if ((mtree->compute_sum & F_RMD160)
- && !(reg->mset_digest & AE_MSET_DIGEST_RMD160))
+ if (mtree->compute_sum & F_RMD160)
- archive_rmd160_final(&mtree->rmd160ctx, reg->digest.rmd160);
+ archive_rmd160_final(&mtree->rmd160ctx, (reg->mset_digest & AE_MSET_DIGEST_RMD160) ? digest.rmd160 : reg->digest.rmd160);
#endif
#ifdef ARCHIVE_HAS_SHA1
- if ((mtree->compute_sum & F_SHA1)
- && !(reg->mset_digest & AE_MSET_DIGEST_SHA1))
+ if (mtree->compute_sum & F_SHA1)
- archive_sha1_final(&mtree->sha1ctx, reg->digest.sha1);
+ archive_sha1_final(&mtree->sha1ctx, (reg->mset_digest & AE_MSET_DIGEST_SHA1) ? digest.sha1 : reg->digest.sha1);
#endif
#ifdef ARCHIVE_HAS_SHA256
- if ((mtree->compute_sum & F_SHA256)
- && !(reg->mset_digest & AE_MSET_DIGEST_SHA256))
+ if (mtree->compute_sum & F_SHA256)
- archive_sha256_final(&mtree->sha256ctx, reg->digest.sha256);
+ archive_sha256_final(&mtree->sha256ctx, (reg->mset_digest & AE_MSET_DIGEST_SHA256) ? digest.sha256 : reg->digest.sha256);
#endif
#ifdef ARCHIVE_HAS_SHA384
- if ((mtree->compute_sum & F_SHA384)
- && !(reg->mset_digest & AE_MSET_DIGEST_SHA384))
+ if (mtree->compute_sum & F_SHA384)
- archive_sha384_final(&mtree->sha384ctx, reg->digest.sha384);
+ archive_sha384_final(&mtree->sha384ctx, (reg->mset_digest & AE_MSET_DIGEST_SHA384) ? digest.sha384 : reg->digest.sha384);
#endif
#ifdef ARCHIVE_HAS_SHA512
- if ((mtree->compute_sum & F_SHA512)
- && !(reg->mset_digest & AE_MSET_DIGEST_SHA512))
+ if (mtree->compute_sum & F_SHA512)
- archive_sha512_final(&mtree->sha512ctx, reg->digest.sha512);
+ archive_sha512_final(&mtree->sha512ctx, (reg->mset_digest & AE_MSET_DIGEST_SHA512) ? digest.sha512 : reg->digest.sha512);
#endif
/* Save what types of sum are computed. */
reg->compute_sum = mtree->compute_sum;
@@ -1886,20 +1883,29 @@ mtree_entry_setup_filenames(struct archive_write *a, struct mtree_entry *file,
* --> 'dir/dir2/'
*/
char *rp = p -1;
+ size_t off;
+ for (off = 4; p[off] == '/'; off++)
+ ;
while (rp >= dirname) {
if (*rp == '/')
break;
--rp;
}
if (rp > dirname) {
- strcpy(rp, p+3);
+ memmove(rp + 1, p + off, strlen(p + off) + 1);
p = rp;
} else {
- strcpy(dirname, p+4);
+ memmove(dirname, p + off, strlen(p + off) + 1);
p = dirname;
}
} else
p++;
+ } else if (p == dirname && p[0] == '.' && p[1] == '.' && p[2] == '/') {
+ size_t off;
+ for (off = 3; p[off] == '/'; off++)
+ ;
+ memmove(dirname, p + off, strlen(p + off) + 1);
+ p = dirname;
} else
p++;
}
@@ -1986,7 +1992,7 @@ mtree_entry_create_virtual_dir(struct archive_write *a, const char *pathname,
}
static void
-mtree_entry_register_add(struct mtree_writer *mtree, struct mtree_entry *file)
+mtree_entry_register_add(struct mtree *mtree, struct mtree_entry *file)
{
file->next = NULL;
*mtree->file_list.last = file;
@@ -1994,14 +2000,14 @@ mtree_entry_register_add(struct mtree_writer *mtree, struct mtree_entry *file)
}
static void
-mtree_entry_register_init(struct mtree_writer *mtree)
+mtree_entry_register_init(struct mtree *mtree)
{
mtree->file_list.first = NULL;
mtree->file_list.last = &(mtree->file_list.first);
}
static void
-mtree_entry_register_free(struct mtree_writer *mtree)
+mtree_entry_register_free(struct mtree *mtree)
{
struct mtree_entry *file, *file_next;
@@ -2041,7 +2047,7 @@ mtree_entry_find_child(struct mtree_entry *parent, const char *child_name)
static int
get_path_component(char *name, size_t n, const char *fn)
{
- char *p;
+ const char *p;
size_t l;
p = strchr(fn, '/');
@@ -2064,6 +2070,7 @@ get_path_component(char *name, size_t n, const char *fn)
static int
mtree_entry_tree_add(struct archive_write *a, struct mtree_entry **filep)
{
+ struct mtree *mtree = a->format_data;
#if defined(_WIN32) && !defined(__CYGWIN__)
char name[_MAX_FNAME];/* Included null terminator size. */
#elif defined(NAME_MAX) && NAME_MAX >= 255
@@ -2071,7 +2078,6 @@ mtree_entry_tree_add(struct archive_write *a, struct mtree_entry **filep)
#else
char name[256];
#endif
- struct mtree_writer *mtree = (struct mtree_writer *)a->format_data;
struct mtree_entry *dent, *file, *np;
const char *fn, *p;
int l, r;
@@ -2079,6 +2085,11 @@ mtree_entry_tree_add(struct archive_write *a, struct mtree_entry **filep)
file = *filep;
if (file->parentdir.length == 0 && file->basename.length == 1 &&
file->basename.s[0] == '.') {
+ if (file->filetype != AE_IFDIR) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Root entry '.' must be a directory");
+ return (ARCHIVE_FAILED);
+ }
file->parent = file;
if (mtree->root != NULL) {
np = mtree->root;
diff --git a/contrib/libarchive/libarchive/archive_write_set_format_pax.c b/contrib/libarchive/libarchive/archive_write_set_format_pax.c
index f3589d6859e3..1e27260501ba 100644
--- a/contrib/libarchive/libarchive/archive_write_set_format_pax.c
+++ b/contrib/libarchive/libarchive/archive_write_set_format_pax.c
@@ -40,10 +40,13 @@
#include "archive.h"
#include "archive_entry.h"
#include "archive_entry_locale.h"
+#include "archive_integer.h"
#include "archive_private.h"
#include "archive_write_private.h"
#include "archive_write_set_format_private.h"
+#define PAX_MAX_ALIGN (1U << 20)
+
struct sparse_block {
struct sparse_block *next;
int is_hole;
@@ -63,6 +66,10 @@ struct pax {
struct archive_string_conv *sconv_utf8;
int opt_binary;
+ /* If non-zero, align regular file data to this many bytes in the
+ * uncompressed stream (power of two, multiple of 512). */
+ size_t align;
+
unsigned flags;
#define WRITE_SCHILY_XATTR (1 << 0)
#define WRITE_LIBARCHIVE_XATTR (1 << 1)
@@ -78,6 +85,8 @@ static void add_pax_attr_int(struct archive_string *,
static void add_pax_attr_time(struct archive_string *,
const char *key, int64_t sec,
unsigned long nanos);
+static size_t add_pax_padding_prefix(struct archive_string *,
+ size_t cur_len, size_t target_len);
static int add_pax_acl(struct archive_write *,
struct archive_entry *, struct pax *, int);
static ssize_t archive_write_pax_data(struct archive_write *,
@@ -89,6 +98,7 @@ static int archive_write_pax_header(struct archive_write *,
struct archive_entry *);
static int archive_write_pax_options(struct archive_write *,
const char *, const char *);
+static int write_pax_padding(struct archive_write *, size_t);
static char *base64_encode(const char *src, size_t len);
static char *build_gnu_sparse_name(char *dest, const char *src);
static char *build_pax_attribute_name(char *dest, const char *src);
@@ -135,8 +145,7 @@ archive_write_set_format_pax(struct archive *_a)
archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_set_format_pax");
- if (a->format_free != NULL)
- (a->format_free)(a);
+ (void)__archive_write_unregister_format(a);
pax = calloc(1, sizeof(*pax));
if (pax == NULL) {
@@ -163,7 +172,7 @@ static int
archive_write_pax_options(struct archive_write *a, const char *key,
const char *val)
{
- struct pax *pax = (struct pax *)a->format_data;
+ struct pax *pax = a->format_data;
int ret = ARCHIVE_FAILED;
if (strcmp(key, "hdrcharset") == 0) {
@@ -222,6 +231,25 @@ archive_write_pax_options(struct archive_write *a, const char *key,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"pax: invalid xattr header name");
return (ret);
+ } else if (strcmp(key, "align") == 0) {
+ unsigned long v;
+ char *end;
+
+ if (val == NULL || val[0] == 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "pax: align option needs a value");
+ return (ARCHIVE_FAILED);
+ }
+ v = strtoul(val, &end, 10);
+ if (*end != '\0' || v == 0 || (v % 512) != 0 ||
+ (v & (v - 1)) != 0 || v > PAX_MAX_ALIGN) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "pax: align must be a power of two, a multiple "
+ "of 512, and no larger than 1 MiB");
+ return (ARCHIVE_FAILED);
+ }
+ pax->align = (size_t)v;
+ return (ARCHIVE_OK);
}
/* Note: The "warn" return is just to inform the options
@@ -360,6 +388,81 @@ add_pax_attr_binary(struct archive_string *as, const char *key,
archive_strappend_char(as, '\n');
}
+/*
+ * Append the length/key prefix of an ignorable "LIBARCHIVE.pad" record whose
+ * full length rounds the pax body up to 'target_len'. Return the number of
+ * value/newline bytes that must be emitted after the in-memory header.
+ */
+static size_t
+add_pax_padding_prefix(struct archive_string *as, size_t cur_len,
+ size_t target_len)
+{
+ static const char key[] = "LIBARCHIVE.pad";
+ char tmp[1 + 3 * sizeof(int64_t)];
+ char *length;
+ size_t prefix_len, record_len;
+
+ if (target_len <= cur_len)
+ return (0);
+ record_len = target_len - cur_len;
+ tmp[sizeof(tmp) - 1] = 0;
+ length = format_int(tmp + sizeof(tmp) - 1, (int64_t)record_len);
+ prefix_len = strlen(length) + 1 + sizeof(key) - 1 + 1;
+ if (record_len <= prefix_len)
+ return (0); /* not enough room; leave unaligned */
+
+ archive_strcat(as, length);
+ archive_strappend_char(as, ' ');
+ archive_strcat(as, key);
+ archive_strappend_char(as, '=');
+ return (record_len - prefix_len);
+}
+
+/* Emit a deferred pax padding value followed by its record newline. */
+static int
+write_pax_padding(struct archive_write *a, size_t length)
+{
+ char padding[1024];
+
+ if (length == 0)
+ return (ARCHIVE_OK);
+ memset(padding, 'X', sizeof(padding));
+ while (length > 1) {
+ size_t to_write = length - 1;
+ int r;
+
+ if (to_write > sizeof(padding))
+ to_write = sizeof(padding);
+ r = __archive_write_output(a, padding, to_write);
+ if (r != ARCHIVE_OK)
+ return (r);
+ length -= to_write;
+ }
+ return (__archive_write_output(a, "\n", 1));
+}
+
+/*
+ * For the pax "align" option: given entry offset 'off' (a multiple of 512) and
+ * current extended-header body length 'l0', return the body length needed so
+ * the file data (after the x header) lands on 'align', or 'l0' if already
+ * aligned.
+ */
+static size_t
+pax_align_body_len(uint64_t off, size_t l0, size_t align)
+{
+ uint64_t amask = (uint64_t)align - 1;
+ /* Data offset with no extra padding (no x header when l0 == 0). */
+ uint64_t natural_off = (l0 == 0) ? off + 512
+ : off + 1024 + (((uint64_t)l0 + 511) & ~(uint64_t)511);
+
+ if ((natural_off & amask) == 0)
+ return (l0);
+
+ /* Grow the body (past l0 plus pad-record room) to land data on align. */
+ uint64_t base = off + 1024;
+ return ((size_t)(((base + l0 + 64 + amask) & ~amask) - base));
+}
+
static void
archive_write_pax_header_xattr(struct pax *pax, const char *encoded_name,
const void *value, size_t value_len)
@@ -577,6 +680,7 @@ static int
archive_write_pax_header(struct archive_write *a,
struct archive_entry *entry_original)
{
+ struct pax *pax = a->format_data;
struct archive_entry *entry_main;
const char *p;
const char *suffix;
@@ -584,7 +688,6 @@ archive_write_pax_header(struct archive_write *a,
int acl_types;
int sparse_count;
uint64_t sparse_total, real_size;
- struct pax *pax;
const char *hardlink;
const char *path = NULL, *linkpath = NULL;
const char *uname = NULL, *gname = NULL;
@@ -592,6 +695,7 @@ archive_write_pax_header(struct archive_write *a,
size_t mac_metadata_size;
struct archive_string_conv *sconv;
size_t hardlink_length, path_length, linkpath_length;
+ size_t pax_header_padding = 0;
size_t uname_length, gname_length;
char paxbuff[512];
@@ -603,7 +707,6 @@ archive_write_pax_header(struct archive_write *a,
ret = ARCHIVE_OK;
need_extension = 0;
- pax = (struct pax *)a->format_data;
const time_t ustar_max_mtime = get_ustar_max_mtime();
@@ -676,7 +779,8 @@ archive_write_pax_header(struct archive_write *a,
const wchar_t *wp;
wp = archive_entry_pathname_w(entry_original);
- if (wp != NULL && wp[wcslen(wp) -1] != L'/') {
+ if (wp != NULL && wp[0] != L'\0' &&
+ wp[wcslen(wp) - 1] != L'/') {
struct archive_wstring ws;
archive_string_init(&ws);
@@ -1336,14 +1440,6 @@ archive_write_pax_header(struct archive_write *a,
archive_entry_set_size(entry_main, 0);
/*
- * Pax-restricted does not store data for hardlinks, in order
- * to improve compatibility with ustar.
- */
- if (a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE &&
- hardlink != NULL)
- archive_entry_set_size(entry_main, 0);
-
- /*
* XXX Full pax interchange format does permit a hardlink
* entry to have data associated with it. I'm not supporting
* that here because the client expects me to tell them whether
@@ -1409,6 +1505,21 @@ archive_write_pax_header(struct archive_write *a,
return (ARCHIVE_FATAL);
}
+ /* Pad the extended header so contiguous file data starts on a pax->align
+ * boundary (for reflinking); short and sparse files are left alone. */
+ if (pax->align > 0
+ && archive_entry_filetype(entry_main) == AE_IFREG
+ && hardlink == NULL
+ && sparse_count == 0
+ && real_size >= (uint64_t)pax->align) {
+ size_t l0 = archive_strlen(&(pax->pax_header));
+ size_t needed = pax_align_body_len(
+ (uint64_t)a->filter_first->bytes_written, l0, pax->align);
+ if (needed != l0)
+ pax_header_padding = add_pax_padding_prefix(
+ &(pax->pax_header), l0, needed);
+ }
+
/* If we built any extended attributes, write that entry first. */
if (archive_strlen(&(pax->pax_header)) > 0) {
struct archive_entry *pax_attr_entry;
@@ -1417,11 +1528,20 @@ archive_write_pax_header(struct archive_write *a,
__LA_MODE_T mode;
pax_attr_entry = archive_entry_new2(&a->archive);
+ if (pax_attr_entry == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Out of memory");
+ archive_entry_free(entry_main);
+ archive_string_free(&entry_name);
+ return (ARCHIVE_FATAL);
+ }
+
p = entry_name.s;
archive_entry_set_pathname(pax_attr_entry,
build_pax_attribute_name(pax_entry_name, p));
archive_entry_set_size(pax_attr_entry,
- archive_strlen(&(pax->pax_header)));
+ archive_strlen(&(pax->pax_header)) +
+ pax_header_padding);
/* Copy uid/gid (but clip to ustar limits). */
uid = archive_entry_uid(entry_main);
if (uid >= 1 << 18)
@@ -1487,7 +1607,8 @@ archive_write_pax_header(struct archive_write *a,
return (ARCHIVE_FATAL);
}
- pax->entry_bytes_remaining = archive_strlen(&(pax->pax_header));
+ pax->entry_bytes_remaining = archive_strlen(&(pax->pax_header)) +
+ pax_header_padding;
pax->entry_padding =
0x1ff & (-(int64_t)pax->entry_bytes_remaining);
@@ -1499,8 +1620,14 @@ archive_write_pax_header(struct archive_write *a,
archive_string_free(&entry_name);
return (ARCHIVE_FATAL);
}
+ r = write_pax_padding(a, pax_header_padding);
+ if (r != ARCHIVE_OK) {
+ archive_entry_free(entry_main);
+ archive_string_free(&entry_name);
+ return (ARCHIVE_FATAL);
+ }
/* Pad out the end of the entry. */
- r = __archive_write_nulls(a, (size_t)pax->entry_padding);
+ r = __archive_write_nulls(a, pax->entry_padding);
if (r != ARCHIVE_OK) {
/* If a write fails, we're pretty much toast. */
archive_entry_free(entry_main);
@@ -1572,18 +1699,21 @@ build_ustar_entry_name(char *dest, const char *src, size_t src_length,
char *p;
int need_slash = 0; /* Was there a trailing slash? */
size_t suffix_length = 98; /* 99 - 1 for trailing slash */
- size_t insert_length;
+ size_t insert_length, insert_name_length;
/* Length of additional dir element to be added. */
- if (insert == NULL)
+ if (insert == NULL) {
+ insert_name_length = 0;
insert_length = 0;
- else
+ } else {
+ insert_name_length = strlen(insert);
/* +2 here allows for '/' before and after the insert. */
- insert_length = strlen(insert) + 2;
+ insert_length = insert_name_length + 2;
+ }
/* Step 0: Quick bailout in a common case. */
if (src_length < 100 && insert == NULL) {
- strncpy(dest, src, src_length);
+ memcpy(dest, src, src_length);
dest[src_length] = '\0';
return (dest);
}
@@ -1605,6 +1735,26 @@ build_ustar_entry_name(char *dest, const char *src, size_t src_length,
}
break;
}
+
+ /*
+ * Pathological case: after trimming trailing '/' characters and
+ * '/.' path elements, there is no filename component left. This
+ * happens for pathnames made entirely of '/' characters. Do not
+ * attempt to compute filename_end - 1 in that case, which would
+ * move the filename pointer in front of the input buffer and read
+ * one byte out of bounds. Emit a root-like ustar name instead.
+ */
+ if (filename_end == src) {
+ p = dest;
+ if (insert != NULL) {
+ strcpy(p, insert);
+ p += strlen(insert);
+ }
+ *p++ = '/';
+ *p = '\0';
+ return (dest);
+ }
+
if (need_slash)
suffix_length--;
/* Find start of filename. */
@@ -1645,24 +1795,22 @@ build_ustar_entry_name(char *dest, const char *src, size_t src_length,
suffix_end++;
/* Step 4: Build the new name. */
- /* The OpenBSD strlcpy function is safer, but less portable. */
- /* Rather than maintain two versions, just use the strncpy version. */
p = dest;
if (prefix_end > prefix) {
- strncpy(p, prefix, prefix_end - prefix);
+ memcpy(p, prefix, (size_t)(prefix_end - prefix));
p += prefix_end - prefix;
}
if (suffix_end > suffix) {
- strncpy(p, suffix, suffix_end - suffix);
+ memcpy(p, suffix, (size_t)(suffix_end - suffix));
p += suffix_end - suffix;
}
if (insert != NULL) {
/* Note: assume insert does not have leading or trailing '/' */
- strcpy(p, insert);
- p += strlen(insert);
+ memcpy(p, insert, insert_name_length);
+ p += insert_name_length;
*p++ = '/';
}
- strncpy(p, filename, filename_end - filename);
+ memcpy(p, filename, (size_t)(filename_end - filename));
p += filename_end - filename;
if (need_slash)
*p++ = '/';
@@ -1792,7 +1940,12 @@ build_gnu_sparse_name(char *dest, const char *src)
}
/* General case: build a ustar-compatible name adding
- * "/GNUSparseFile/". */
+ * "/GNUSparseFile.0/". */
+
+ if (p == src) {
+ strcpy(dest, "/GNUSparseFile.0/rootdir");
+ return (dest);
+ }
build_ustar_entry_name(dest, src, p - src, "GNUSparseFile.0");
return (dest);
@@ -1808,9 +1961,8 @@ archive_write_pax_close(struct archive_write *a)
static int
archive_write_pax_free(struct archive_write *a)
{
- struct pax *pax;
+ struct pax *pax = a->format_data;
- pax = (struct pax *)a->format_data;
if (pax == NULL)
return (ARCHIVE_OK);
@@ -1826,11 +1978,10 @@ archive_write_pax_free(struct archive_write *a)
static int
archive_write_pax_finish_entry(struct archive_write *a)
{
- struct pax *pax;
+ struct pax *pax = a->format_data;
uint64_t remaining;
int ret;
- pax = (struct pax *)a->format_data;
remaining = pax->entry_bytes_remaining;
if (remaining == 0) {
while (pax->sparse_list) {
@@ -1842,7 +1993,7 @@ archive_write_pax_finish_entry(struct archive_write *a)
pax->sparse_list = sb;
}
}
- ret = __archive_write_nulls(a, (size_t)(remaining + pax->entry_padding));
+ ret = __archive_write_nulls(a, remaining + pax->entry_padding);
pax->entry_bytes_remaining = pax->entry_padding = 0;
return (ret);
}
@@ -1850,13 +2001,11 @@ archive_write_pax_finish_entry(struct archive_write *a)
static ssize_t
archive_write_pax_data(struct archive_write *a, const void *buff, size_t s)
{
- struct pax *pax;
+ struct pax *pax = a->format_data;
size_t ws;
size_t total;
int ret;
- pax = (struct pax *)a->format_data;
-
/*
* According to GNU PAX format 1.0, write a sparse map
* before the body.
@@ -1934,17 +2083,17 @@ url_encode(const char *in)
for (s = in; *s != '\0'; s++) {
if (*s < 33 || *s > 126 || *s == '%' || *s == '=') {
- if (SIZE_MAX - out_len < 4)
+ if (archive_ckd_add_size(&out_len, out_len, 3))
return (NULL);
- out_len += 3;
} else {
- if (SIZE_MAX - out_len < 2)
+ if (archive_ckd_add_size(&out_len, out_len, 1))
return (NULL);
- out_len++;
}
}
- out = malloc(out_len + 1);
+ if (archive_ckd_add_size(&out_len, out_len, 1))
+ return (NULL);
+ out = malloc(out_len);
if (out == NULL)
return (NULL);
@@ -1978,20 +2127,27 @@ base64_encode(const char *s, size_t len)
'e','f','g','h','i','j','k','l','m','n','o','p','q','r','s',
't','u','v','w','x','y','z','0','1','2','3','4','5','6','7',
'8','9','+','/' };
- int v;
+ uint32_t v;
char *d, *out;
+ size_t out_len;
/* 3 bytes becomes 4 chars, but round up and allow for trailing NUL */
- out = malloc((len * 4 + 2) / 3 + 1);
+ if (archive_ckd_mul_size(&out_len, len, 4) ||
+ archive_ckd_add_size(&out_len, out_len, 2))
+ return (NULL);
+ out_len = out_len / 3;
+ if (archive_ckd_add_size(&out_len, out_len, 1))
+ return (NULL);
+ out = malloc(out_len);
if (out == NULL)
return (NULL);
d = out;
/* Convert each group of 3 bytes into 4 characters. */
while (len >= 3) {
- v = (((int)s[0] << 16) & 0xff0000)
- | (((int)s[1] << 8) & 0xff00)
- | (((int)s[2]) & 0x00ff);
+ v = ((uint32_t)(unsigned char)s[0] << 16)
+ | ((uint32_t)(unsigned char)s[1] << 8)
+ | (uint32_t)(unsigned char)s[2];
s += 3;
len -= 3;
*d++ = digits[(v >> 18) & 0x3f];
@@ -2003,13 +2159,13 @@ base64_encode(const char *s, size_t len)
switch (len) {
case 0: break;
case 1:
- v = (((int)s[0] << 16) & 0xff0000);
+ v = ((uint32_t)(unsigned char)s[0] << 16);
*d++ = digits[(v >> 18) & 0x3f];
*d++ = digits[(v >> 12) & 0x3f];
break;
case 2:
- v = (((int)s[0] << 16) & 0xff0000)
- | (((int)s[1] << 8) & 0xff00);
+ v = ((uint32_t)(unsigned char)s[0] << 16)
+ | ((uint32_t)(unsigned char)s[1] << 8);
*d++ = digits[(v >> 18) & 0x3f];
*d++ = digits[(v >> 12) & 0x3f];
*d++ = digits[(v >> 6) & 0x3f];
diff --git a/contrib/libarchive/libarchive/archive_write_set_format_raw.c b/contrib/libarchive/libarchive/archive_write_set_format_raw.c
index ff3e9ae0ebdb..20c42e3d30f7 100644
--- a/contrib/libarchive/libarchive/archive_write_set_format_raw.c
+++ b/contrib/libarchive/libarchive/archive_write_set_format_raw.c
@@ -55,8 +55,7 @@ archive_write_set_format_raw(struct archive *_a)
ARCHIVE_STATE_NEW, "archive_write_set_format_raw");
/* If someone else was already registered, unregister them. */
- if (a->format_free != NULL)
- (a->format_free)(a);
+ (void)__archive_write_unregister_format(a);
raw = calloc(1, sizeof(*raw));
if (raw == NULL) {
@@ -82,7 +81,7 @@ archive_write_set_format_raw(struct archive *_a)
static int
archive_write_raw_header(struct archive_write *a, struct archive_entry *entry)
{
- struct raw *raw = (struct raw *)a->format_data;
+ struct raw *raw = a->format_data;
if (archive_entry_filetype(entry) != AE_IFREG) {
archive_set_error(&a->archive, ERANGE,
@@ -116,9 +115,8 @@ archive_write_raw_data(struct archive_write *a, const void *buff, size_t s)
static int
archive_write_raw_free(struct archive_write *a)
{
- struct raw *raw;
+ struct raw *raw = a->format_data;
- raw = (struct raw *)a->format_data;
free(raw);
a->format_data = NULL;
return (ARCHIVE_OK);
diff --git a/contrib/libarchive/libarchive/archive_write_set_format_shar.c b/contrib/libarchive/libarchive/archive_write_set_format_shar.c
index f6f28debdfa9..ef4b3d907c08 100644
--- a/contrib/libarchive/libarchive/archive_write_set_format_shar.c
+++ b/contrib/libarchive/libarchive/archive_write_set_format_shar.c
@@ -38,6 +38,7 @@
#endif
#include "archive.h"
+#include "archive_endian.h"
#include "archive_entry.h"
#include "archive_private.h"
#include "archive_write_private.h"
@@ -97,11 +98,8 @@ shar_quote(struct archive_string *buf, const char *str, int in_shell)
}
}
-/*
- * Set output format to 'shar' format.
- */
-int
-archive_write_set_format_shar(struct archive *_a)
+static int
+shar_set_format(struct archive *_a, int dump)
{
struct archive_write *a = (struct archive_write *)_a;
struct shar *shar;
@@ -110,8 +108,7 @@ archive_write_set_format_shar(struct archive *_a)
ARCHIVE_STATE_NEW, "archive_write_set_format_shar");
/* If someone else was already registered, unregister them. */
- if (a->format_free != NULL)
- (a->format_free)(a);
+ (void)__archive_write_unregister_format(a);
shar = calloc(1, sizeof(*shar));
if (shar == NULL) {
@@ -120,50 +117,54 @@ archive_write_set_format_shar(struct archive *_a)
}
archive_string_init(&shar->work);
archive_string_init(&shar->quoted_name);
+ if (dump) {
+ shar->dump = 1;
+ a->format_write_data = archive_write_shar_data_uuencode;
+ a->archive.archive_format = ARCHIVE_FORMAT_SHAR_DUMP;
+ a->archive.archive_format_name = "shar dump";
+ } else {
+ a->format_write_data = archive_write_shar_data_sed;
+ a->archive.archive_format = ARCHIVE_FORMAT_SHAR_BASE;
+ a->archive.archive_format_name = "shar";
+ }
a->format_data = shar;
a->format_name = "shar";
a->format_write_header = archive_write_shar_header;
a->format_close = archive_write_shar_close;
a->format_free = archive_write_shar_free;
- a->format_write_data = archive_write_shar_data_sed;
a->format_finish_entry = archive_write_shar_finish_entry;
- a->archive.archive_format = ARCHIVE_FORMAT_SHAR_BASE;
- a->archive.archive_format_name = "shar";
return (ARCHIVE_OK);
}
/*
+ * Set output format to 'shar' format.
+ */
+int
+archive_write_set_format_shar(struct archive *a)
+{
+ return shar_set_format(a, 0);
+}
+
+/*
* An alternate 'shar' that uses uudecode instead of 'sed' to encode
* file contents and can therefore be used to archive binary files.
* In addition, this variant also attempts to restore ownership, file modes,
* and other extended file information.
*/
int
-archive_write_set_format_shar_dump(struct archive *_a)
+archive_write_set_format_shar_dump(struct archive *a)
{
- struct archive_write *a = (struct archive_write *)_a;
- struct shar *shar;
-
- int ret = archive_write_set_format_shar(&a->archive);
- if (ret != ARCHIVE_OK)
- return ret;
- shar = (struct shar *)a->format_data;
- shar->dump = 1;
- a->format_write_data = archive_write_shar_data_uuencode;
- a->archive.archive_format = ARCHIVE_FORMAT_SHAR_DUMP;
- a->archive.archive_format_name = "shar dump";
- return (ARCHIVE_OK);
+ return shar_set_format(a, 1);
}
static int
archive_write_shar_header(struct archive_write *a, struct archive_entry *entry)
{
+ struct shar *shar = a->format_data;
const char *linkname;
const char *name;
char *p, *pp;
- struct shar *shar;
- shar = (struct shar *)a->format_data;
if (!shar->wrote_header) {
archive_strcat(&shar->work, "#!/bin/sh\n");
archive_strcat(&shar->work, "# This is a shell archive\n");
@@ -173,6 +174,10 @@ archive_write_shar_header(struct archive_write *a, struct archive_entry *entry)
/* Save the entry for the closing. */
archive_entry_free(shar->entry);
shar->entry = archive_entry_clone(entry);
+ if (shar->entry == NULL) {
+ archive_set_error(&a->archive, ENOMEM, "Out of memory");
+ return (ARCHIVE_FATAL);
+ }
name = archive_entry_pathname(entry);
/* Handle some preparatory issues. */
@@ -338,14 +343,13 @@ archive_write_shar_header(struct archive_write *a, struct archive_entry *entry)
static ssize_t
archive_write_shar_data_sed(struct archive_write *a, const void *buff, size_t n)
{
+ struct shar *shar = a->format_data;
static const size_t ensured = 65533;
- struct shar *shar;
const char *src;
char *buf, *buf_end;
int ret;
size_t written = n;
- shar = (struct shar *)a->format_data;
if (!shar->has_data || n == 0)
return (0);
@@ -408,9 +412,9 @@ static void
uuencode_group(const char _in[3], char out[4])
{
const unsigned char *in = (const unsigned char *)_in;
- int t;
+ uint32_t t;
- t = (in[0] << 16) | (in[1] << 8) | in[2];
+ t = archive_be24dec(in);
out[0] = UUENC( 0x3f & (t >> 18) );
out[1] = UUENC( 0x3f & (t >> 12) );
out[2] = UUENC( 0x3f & (t >> 6) );
@@ -470,12 +474,11 @@ static ssize_t
archive_write_shar_data_uuencode(struct archive_write *a, const void *buff,
size_t length)
{
- struct shar *shar;
+ struct shar *shar = a->format_data;
const char *src;
size_t n;
int ret;
- shar = (struct shar *)a->format_data;
if (!shar->has_data)
return (ARCHIVE_OK);
src = (const char *)buff;
@@ -519,13 +522,12 @@ archive_write_shar_data_uuencode(struct archive_write *a, const void *buff,
static int
archive_write_shar_finish_entry(struct archive_write *a)
{
+ struct shar *shar = a->format_data;
const char *g, *p, *u;
- struct shar *shar;
int ret;
- shar = (struct shar *)a->format_data;
if (shar->entry == NULL)
- return (0);
+ return (ARCHIVE_OK);
if (shar->dump) {
/* Finish uuencoded data. */
@@ -597,7 +599,7 @@ archive_write_shar_finish_entry(struct archive_write *a)
static int
archive_write_shar_close(struct archive_write *a)
{
- struct shar *shar;
+ struct shar *shar = a->format_data;
int ret;
/*
@@ -605,8 +607,6 @@ archive_write_shar_close(struct archive_write *a)
* fix them all up at end-of-archive.
*/
- shar = (struct shar *)a->format_data;
-
/*
* Only write the end-of-archive markers if the archive was
* actually started. This avoids problems if someone sets
@@ -635,9 +635,8 @@ archive_write_shar_close(struct archive_write *a)
static int
archive_write_shar_free(struct archive_write *a)
{
- struct shar *shar;
+ struct shar *shar = a->format_data;
- shar = (struct shar *)a->format_data;
if (shar == NULL)
return (ARCHIVE_OK);
diff --git a/contrib/libarchive/libarchive/archive_write_set_format_ustar.c b/contrib/libarchive/libarchive/archive_write_set_format_ustar.c
index 97724c1588b3..a55cbb75b0f7 100644
--- a/contrib/libarchive/libarchive/archive_write_set_format_ustar.c
+++ b/contrib/libarchive/libarchive/archive_write_set_format_ustar.c
@@ -172,8 +172,7 @@ archive_write_set_format_ustar(struct archive *_a)
ARCHIVE_STATE_NEW, "archive_write_set_format_ustar");
/* If someone else was already registered, unregister them. */
- if (a->format_free != NULL)
- (a->format_free)(a);
+ (void)__archive_write_unregister_format(a);
/* Basic internal sanity test. */
if (sizeof(template_header) != 512) {
@@ -206,7 +205,7 @@ static int
archive_write_ustar_options(struct archive_write *a, const char *key,
const char *val)
{
- struct ustar *ustar = (struct ustar *)a->format_data;
+ struct ustar *ustar = a->format_data;
int ret = ARCHIVE_FAILED;
if (strcmp(key, "hdrcharset") == 0) {
@@ -234,14 +233,12 @@ archive_write_ustar_options(struct archive_write *a, const char *key,
static int
archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
{
+ struct ustar *ustar = a->format_data;
char buff[512];
int ret, ret2;
- struct ustar *ustar;
struct archive_entry *entry_main;
struct archive_string_conv *sconv;
- ustar = (struct ustar *)a->format_data;
-
/* Setup default string conversion. */
if (ustar->opt_sconv == NULL) {
if (!ustar->init_default_conversion) {
@@ -281,7 +278,8 @@ archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
const wchar_t *wp;
wp = archive_entry_pathname_w(entry);
- if (wp != NULL && wp[wcslen(wp) -1] != L'/') {
+ if (wp != NULL && wp[0] != L'\0' &&
+ wp[wcslen(wp) - 1] != L'/') {
struct archive_wstring ws;
archive_string_init(&ws);
@@ -735,9 +733,8 @@ archive_write_ustar_close(struct archive_write *a)
static int
archive_write_ustar_free(struct archive_write *a)
{
- struct ustar *ustar;
+ struct ustar *ustar = a->format_data;
- ustar = (struct ustar *)a->format_data;
free(ustar);
a->format_data = NULL;
return (ARCHIVE_OK);
@@ -746,12 +743,11 @@ archive_write_ustar_free(struct archive_write *a)
static int
archive_write_ustar_finish_entry(struct archive_write *a)
{
- struct ustar *ustar;
+ struct ustar *ustar = a->format_data;
int ret;
- ustar = (struct ustar *)a->format_data;
ret = __archive_write_nulls(a,
- (size_t)(ustar->entry_bytes_remaining + ustar->entry_padding));
+ ustar->entry_bytes_remaining + ustar->entry_padding);
ustar->entry_bytes_remaining = ustar->entry_padding = 0;
return (ret);
}
@@ -759,10 +755,9 @@ archive_write_ustar_finish_entry(struct archive_write *a)
static ssize_t
archive_write_ustar_data(struct archive_write *a, const void *buff, size_t s)
{
- struct ustar *ustar;
+ struct ustar *ustar = a->format_data;
int ret;
- ustar = (struct ustar *)a->format_data;
if (s > ustar->entry_bytes_remaining)
s = (size_t)ustar->entry_bytes_remaining;
ret = __archive_write_output(a, buff, s);
diff --git a/contrib/libarchive/libarchive/archive_write_set_format_v7tar.c b/contrib/libarchive/libarchive/archive_write_set_format_v7tar.c
index 37ba73a1320a..74875547b089 100644
--- a/contrib/libarchive/libarchive/archive_write_set_format_v7tar.c
+++ b/contrib/libarchive/libarchive/archive_write_set_format_v7tar.c
@@ -149,8 +149,7 @@ archive_write_set_format_v7tar(struct archive *_a)
ARCHIVE_STATE_NEW, "archive_write_set_format_v7tar");
/* If someone else was already registered, unregister them. */
- if (a->format_free != NULL)
- (a->format_free)(a);
+ (void)__archive_write_unregister_format(a);
/* Basic internal sanity test. */
if (sizeof(template_header) != 512) {
@@ -183,7 +182,7 @@ static int
archive_write_v7tar_options(struct archive_write *a, const char *key,
const char *val)
{
- struct v7tar *v7tar = (struct v7tar *)a->format_data;
+ struct v7tar *v7tar = a->format_data;
int ret = ARCHIVE_FAILED;
if (strcmp(key, "hdrcharset") == 0) {
@@ -211,14 +210,12 @@ archive_write_v7tar_options(struct archive_write *a, const char *key,
static int
archive_write_v7tar_header(struct archive_write *a, struct archive_entry *entry)
{
+ struct v7tar *v7tar = a->format_data;
char buff[512];
int ret, ret2;
- struct v7tar *v7tar;
struct archive_entry *entry_main;
struct archive_string_conv *sconv;
- v7tar = (struct v7tar *)a->format_data;
-
/* Setup default string conversion. */
if (v7tar->opt_sconv == NULL) {
if (!v7tar->init_default_conversion) {
@@ -259,7 +256,8 @@ archive_write_v7tar_header(struct archive_write *a, struct archive_entry *entry)
const wchar_t *wp;
wp = archive_entry_pathname_w(entry);
- if (wp != NULL && wp[wcslen(wp) -1] != L'/') {
+ if (wp != NULL && wp[0] != L'\0' &&
+ wp[wcslen(wp) - 1] != L'/') {
struct archive_wstring ws;
archive_string_init(&ws);
@@ -615,9 +613,8 @@ archive_write_v7tar_close(struct archive_write *a)
static int
archive_write_v7tar_free(struct archive_write *a)
{
- struct v7tar *v7tar;
+ struct v7tar *v7tar = a->format_data;
- v7tar = (struct v7tar *)a->format_data;
free(v7tar);
a->format_data = NULL;
return (ARCHIVE_OK);
@@ -626,12 +623,11 @@ archive_write_v7tar_free(struct archive_write *a)
static int
archive_write_v7tar_finish_entry(struct archive_write *a)
{
- struct v7tar *v7tar;
+ struct v7tar *v7tar = a->format_data;
int ret;
- v7tar = (struct v7tar *)a->format_data;
ret = __archive_write_nulls(a,
- (size_t)(v7tar->entry_bytes_remaining + v7tar->entry_padding));
+ v7tar->entry_bytes_remaining + v7tar->entry_padding);
v7tar->entry_bytes_remaining = v7tar->entry_padding = 0;
return (ret);
}
@@ -639,10 +635,9 @@ archive_write_v7tar_finish_entry(struct archive_write *a)
static ssize_t
archive_write_v7tar_data(struct archive_write *a, const void *buff, size_t s)
{
- struct v7tar *v7tar;
+ struct v7tar *v7tar = a->format_data;
int ret;
- v7tar = (struct v7tar *)a->format_data;
if (s > v7tar->entry_bytes_remaining)
s = (size_t)v7tar->entry_bytes_remaining;
ret = __archive_write_output(a, buff, s);
diff --git a/contrib/libarchive/libarchive/archive_write_set_format_warc.c b/contrib/libarchive/libarchive/archive_write_set_format_warc.c
index 3d22e1f4ba57..d06abdb372db 100644
--- a/contrib/libarchive/libarchive/archive_write_set_format_warc.c
+++ b/contrib/libarchive/libarchive/archive_write_set_format_warc.c
@@ -49,68 +49,81 @@
#include "archive_write_private.h"
#include "archive_write_set_format_private.h"
-struct warc_s {
+/*
+ * Overview of the WARC writer:
+ *
+ * This writer emits WARC/1.0 resource records for regular files. It
+ * writes a warcinfo record once by default, unless the omit-warcinfo
+ * option is used. Each resource record gets a WARC-Target-URI from
+ * the entry pathname, a generated WARC-Record-ID, and a mandatory
+ * Content-Length header.
+ */
+
+struct warc {
unsigned int omit_warcinfo:1;
time_t now;
- mode_t typ;
- unsigned int rng;
- /* populated size */
- uint64_t populz;
+ mode_t filetype;
+ /* Remaining bytes to write for the current entry */
+ uint64_t entry_bytes_remaining;
};
-static const char warcinfo[] =
+#define WARC_HEADER_MAX_SIZE 512
+
+static const char warcinfo_payload[] =
"software: libarchive/" ARCHIVE_VERSION_ONLY_STRING "\r\n"
"format: WARC file version 1.0\r\n";
-typedef enum {
- WT_NONE,
- /* warcinfo */
- WT_INFO,
- /* metadata */
- WT_META,
- /* resource */
- WT_RSRC,
- /* request, unsupported */
- WT_REQ,
- /* response, unsupported */
- WT_RSP,
- /* revisit, unsupported */
- WT_RVIS,
- /* conversion, unsupported */
- WT_CONV,
- /* continuation, unsupported at the moment */
- WT_CONT,
- /* invalid type */
- LAST_WT
-} warc_type_t;
+enum warc_type {
+ WARC_TYPE_NONE,
+ /* WARC info */
+ WARC_TYPE_INFO,
+ /* Metadata */
+ WARC_TYPE_METADATA,
+ /* Resource */
+ WARC_TYPE_RESOURCE,
+ /* Request, unsupported */
+ WARC_TYPE_REQUEST,
+ /* Response, unsupported by this writer */
+ WARC_TYPE_RESPONSE,
+ /* Revisit, unsupported */
+ WARC_TYPE_REVISIT,
+ /* Conversion, unsupported */
+ WARC_TYPE_CONVERSION,
+ /* Continuation, currently unsupported */
+ WARC_TYPE_CONTINUATION,
+ WARC_TYPE_LAST
+};
-typedef struct {
- warc_type_t type;
- const char *tgturi;
- const char *recid;
- time_t rtime;
- time_t mtime;
- const char *cnttyp;
- uint64_t cntlen;
-} warc_essential_hdr_t;
+struct warc_header {
+ enum warc_type type;
+ const char *target_uri;
+ const char *record_id;
+ time_t record_time;
+ time_t modification_time;
+ const char *content_type;
+ uint64_t content_length;
+};
-typedef struct {
- unsigned int u[4U];
-} warc_uuid_t;
+struct warc_uuid {
+ unsigned int value[4U];
+};
-static int _warc_options(struct archive_write*, const char *key, const char *v);
-static int _warc_header(struct archive_write *a, struct archive_entry *entry);
-static ssize_t _warc_data(struct archive_write *a, const void *buf, size_t sz);
-static int _warc_finish_entry(struct archive_write *a);
-static int _warc_close(struct archive_write *a);
-static int _warc_free(struct archive_write *a);
+static int archive_write_warc_options(struct archive_write *,
+ const char *, const char *);
+static int archive_write_warc_header(struct archive_write *,
+ struct archive_entry *);
+static ssize_t archive_write_warc_data(struct archive_write *, const void *,
+ size_t);
+static int archive_write_warc_finish_entry(struct archive_write *);
+static int archive_write_warc_close(struct archive_write *);
+static int archive_write_warc_free(struct archive_write *);
-/* private routines */
-static ssize_t _popul_ehdr(struct archive_string *t, size_t z, warc_essential_hdr_t);
-static int _gen_uuid(warc_uuid_t *tgt);
+static void warc_format_time(struct archive_string *, const char *, time_t);
+static ssize_t warc_populate_header(struct archive_string *, size_t,
+ struct warc_header);
+static void warc_generate_uuid(struct warc_uuid *);
-
/*
* Set output format to ISO 28500 (aka WARC) format.
*/
@@ -118,103 +131,110 @@ int
archive_write_set_format_warc(struct archive *_a)
{
struct archive_write *a = (struct archive_write *)_a;
- struct warc_s *w;
+ struct warc *warc;
archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_set_format_warc");
/* If another format was already registered, unregister it. */
- if (a->format_free != NULL) {
- (a->format_free)(a);
- }
+ (void)__archive_write_unregister_format(a);
- w = malloc(sizeof(*w));
- if (w == NULL) {
+ warc = malloc(sizeof(*warc));
+ if (warc == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate warc data");
return (ARCHIVE_FATAL);
}
- /* by default we're emitting a file wide header */
- w->omit_warcinfo = 0U;
- /* obtain current time for date fields */
- w->now = time(NULL);
- /* reset file type info */
- w->typ = 0;
- /* also initialise our rng */
- w->rng = (unsigned int)w->now;
+ /* Emit a warcinfo record by default. */
+ warc->omit_warcinfo = 0U;
+ /* Use the current time for WARC-Date values. */
+ warc->now = time(NULL);
+ /* Reset file type information. */
+ warc->filetype = 0;
- a->format_data = w;
+ a->format_data = warc;
a->format_name = "WARC/1.0";
- a->format_options = _warc_options;
- a->format_write_header = _warc_header;
- a->format_write_data = _warc_data;
- a->format_close = _warc_close;
- a->format_free = _warc_free;
- a->format_finish_entry = _warc_finish_entry;
+ a->format_options = archive_write_warc_options;
+ a->format_write_header = archive_write_warc_header;
+ a->format_write_data = archive_write_warc_data;
+ a->format_close = archive_write_warc_close;
+ a->format_free = archive_write_warc_free;
+ a->format_finish_entry = archive_write_warc_finish_entry;
a->archive.archive_format = ARCHIVE_FORMAT_WARC;
a->archive.archive_format_name = "WARC/1.0";
return (ARCHIVE_OK);
}
-
-/* archive methods */
static int
-_warc_options(struct archive_write *a, const char *key, const char *val)
+archive_write_warc_options(struct archive_write *a, const char *key,
+ const char *val)
{
- struct warc_s *w = a->format_data;
+ struct warc *warc = a->format_data;
if (strcmp(key, "omit-warcinfo") == 0) {
if (val == NULL || strcmp(val, "true") == 0) {
- /* great */
- w->omit_warcinfo = 1U;
+ /* Option accepted. */
+ warc->omit_warcinfo = 1U;
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. */
+ /* ARCHIVE_WARN tells the options supervisor that this option was not
+ * handled here. It will report an error if no module uses it. */
return (ARCHIVE_WARN);
}
static int
-_warc_header(struct archive_write *a, struct archive_entry *entry)
+archive_write_warc_header(struct archive_write *a, struct archive_entry *entry)
{
- struct warc_s *w = a->format_data;
- struct archive_string hdr;
-#define MAX_HDR_SIZE 512
+ struct warc *warc = a->format_data;
+ struct archive_string header;
- /* check whether warcinfo record needs outputting */
- if (!w->omit_warcinfo) {
- ssize_t r;
- warc_essential_hdr_t wi = {
- WT_INFO,
- /*uri*/NULL,
- /*urn*/NULL,
- /*rtm*/0,
- /*mtm*/0,
- /*cty*/"application/warc-fields",
- /*len*/sizeof(warcinfo) - 1U,
+ /* Emit the warcinfo record if needed. */
+ if (!warc->omit_warcinfo) {
+ ssize_t header_size;
+ int ret;
+ struct warc_header warcinfo_header = {
+ WARC_TYPE_INFO,
+ /* URI */NULL,
+ /* Record ID */NULL,
+ /* Record time */0,
+ /* Modified time */0,
+ /* Content type */"application/warc-fields",
+ /* Content length */sizeof(warcinfo_payload) - 1U,
};
- wi.rtime = w->now;
- wi.mtime = w->now;
+ warcinfo_header.record_time = warc->now;
+ warcinfo_header.modification_time = warc->now;
+
+ archive_string_init(&header);
+ header_size = warc_populate_header(&header,
+ WARC_HEADER_MAX_SIZE, warcinfo_header);
+ if (header_size < 0) {
+ archive_string_free(&header);
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Cannot archive warcinfo record");
+ return (ARCHIVE_FAILED);
+ }
- archive_string_init(&hdr);
- r = _popul_ehdr(&hdr, MAX_HDR_SIZE, wi);
- if (r >= 0) {
- /* jackpot! */
- /* now also use HDR buffer for the actual warcinfo */
- archive_strncat(&hdr, warcinfo, sizeof(warcinfo) -1);
+ /* Reuse the header buffer for the warcinfo payload. */
+ archive_strncat(&header, warcinfo_payload,
+ sizeof(warcinfo_payload) - 1);
- /* append end-of-record indicator */
- archive_strncat(&hdr, "\r\n\r\n", 4);
+ /* Append the end-of-record indicator. */
+ archive_strncat(&header, "\r\n\r\n", 4);
- /* write to output stream */
- __archive_write_output(a, hdr.s, archive_strlen(&hdr));
+ /* Write the warcinfo record to the output stream. */
+ ret = __archive_write_output(a, header.s,
+ archive_strlen(&header));
+ if (ret != ARCHIVE_OK) {
+ archive_string_free(&header);
+ return (ret);
}
- /* indicate we're done with file header writing */
- w->omit_warcinfo = 1U;
- archive_string_free(&hdr);
+
+ /* Mark the file header as written. */
+ warc->omit_warcinfo = 1U;
+ archive_string_free(&header);
}
if (archive_entry_pathname(entry) == NULL) {
@@ -223,221 +243,249 @@ _warc_header(struct archive_write *a, struct archive_entry *entry)
return (ARCHIVE_WARN);
}
- w->typ = archive_entry_filetype(entry);
- w->populz = 0U;
- if (w->typ == AE_IFREG) {
- warc_essential_hdr_t rh = {
- WT_RSRC,
- /*uri*/NULL,
- /*urn*/NULL,
- /*rtm*/0,
- /*mtm*/0,
- /*cty*/NULL,
- /*len*/0,
+ warc->filetype = archive_entry_filetype(entry);
+ warc->entry_bytes_remaining = 0U;
+ if (warc->filetype == AE_IFREG) {
+ struct warc_header resource_header = {
+ WARC_TYPE_RESOURCE,
+ /* URI */NULL,
+ /* Record ID */NULL,
+ /* Record time */0,
+ /* Modified time */0,
+ /* Content type */NULL,
+ /* Content length */0,
};
- ssize_t r;
- rh.tgturi = archive_entry_pathname(entry);
- rh.rtime = w->now;
- rh.mtime = archive_entry_mtime(entry);
- rh.cntlen = (size_t)archive_entry_size(entry);
+ ssize_t header_size;
+ int ret;
+ int64_t size;
- archive_string_init(&hdr);
- r = _popul_ehdr(&hdr, MAX_HDR_SIZE, rh);
- if (r < 0) {
- /* don't bother */
- archive_set_error(
- &a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "cannot archive file");
- return (ARCHIVE_WARN);
+ resource_header.target_uri = archive_entry_pathname(entry);
+ resource_header.record_time = warc->now;
+ resource_header.modification_time = archive_entry_mtime(entry);
+ if (!archive_entry_size_is_set(entry)) {
+ archive_set_error(&a->archive, -1,
+ "Size required");
+ return (ARCHIVE_FAILED);
+ }
+ size = archive_entry_size(entry);
+ if (size < 0) {
+ archive_set_error(&a->archive, -1,
+ "Size required");
+ return (ARCHIVE_FAILED);
+ }
+ resource_header.content_length = (uint64_t)size;
+
+ archive_string_init(&header);
+ header_size = warc_populate_header(&header,
+ WARC_HEADER_MAX_SIZE, resource_header);
+ if (header_size < 0) {
+ /* Header generation failed. */
+ archive_string_free(&header);
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "WARC resource header is too large");
+ return (ARCHIVE_FATAL);
+ }
+ /* Append the header to the output stream. */
+ ret = __archive_write_output(a, header.s, header_size);
+ if (ret != ARCHIVE_OK) {
+ archive_string_free(&header);
+ return (ret);
}
- /* otherwise append to output stream */
- __archive_write_output(a, hdr.s, r);
- /* and let subsequent calls to _data() know about the size */
- w->populz = rh.cntlen;
- archive_string_free(&hdr);
+ /* Save the remaining size for subsequent data callbacks. */
+ warc->entry_bytes_remaining = resource_header.content_length;
+ archive_string_free(&header);
return (ARCHIVE_OK);
}
- /* just resort to erroring as per Tim's advice */
+ /* Report unsupported file types through the common helper. */
__archive_write_entry_filetype_unsupported(
&a->archive, entry, "WARC");
return (ARCHIVE_FAILED);
}
static ssize_t
-_warc_data(struct archive_write *a, const void *buf, size_t len)
+archive_write_warc_data(struct archive_write *a, const void *buf, size_t len)
{
- struct warc_s *w = a->format_data;
+ struct warc *warc = a->format_data;
- if (w->typ == AE_IFREG) {
- int rc;
+ if (warc->filetype == AE_IFREG) {
+ int ret;
- /* never write more bytes than announced */
- if (len > w->populz) {
- len = (size_t)w->populz;
+ /* Never write more bytes than announced. */
+ if ((uint64_t)len > warc->entry_bytes_remaining) {
+ len = (size_t)warc->entry_bytes_remaining;
}
- /* now then, out we put the whole shebang */
- rc = __archive_write_output(a, buf, len);
- if (rc != ARCHIVE_OK) {
- return rc;
+ /* Write the entry data. */
+ ret = __archive_write_output(a, buf, len);
+ if (ret != ARCHIVE_OK) {
+ return (ret);
}
+ warc->entry_bytes_remaining -= len;
}
- return len;
+ return (len);
}
static int
-_warc_finish_entry(struct archive_write *a)
+archive_write_warc_finish_entry(struct archive_write *a)
{
- static const char _eor[] = "\r\n\r\n";
- struct warc_s *w = a->format_data;
+ static const char end_of_record[] = "\r\n\r\n";
+ struct warc *warc = a->format_data;
- if (w->typ == AE_IFREG) {
- int rc = __archive_write_output(a, _eor, sizeof(_eor) - 1U);
+ if (warc->filetype == AE_IFREG) {
+ int ret;
- if (rc != ARCHIVE_OK) {
- return rc;
+ if (warc->entry_bytes_remaining != 0U) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "WARC entry is shorter than Content-Length");
+ return (ARCHIVE_FATAL);
+ }
+
+ ret = __archive_write_output(a, end_of_record,
+ sizeof(end_of_record) - 1U);
+ if (ret != ARCHIVE_OK) {
+ return (ret);
}
}
- /* reset type info */
- w->typ = 0;
+ /* Reset file type information. */
+ warc->filetype = 0;
return (ARCHIVE_OK);
}
static int
-_warc_close(struct archive_write *a)
+archive_write_warc_close(struct archive_write *a)
{
(void)a; /* UNUSED */
return (ARCHIVE_OK);
}
static int
-_warc_free(struct archive_write *a)
+archive_write_warc_free(struct archive_write *a)
{
- struct warc_s *w = a->format_data;
+ struct warc *warc = a->format_data;
- free(w);
+ free(warc);
a->format_data = NULL;
return (ARCHIVE_OK);
}
-
-/* private routines */
+/* Like strftime(3), but for time_t objects. */
static void
-xstrftime(struct archive_string *as, const char *fmt, time_t t)
+warc_format_time(struct archive_string *str, const char *format, time_t t)
{
-/** like strftime(3) but for time_t objects */
- struct tm *rt;
+ struct tm *tm;
#if defined(HAVE_GMTIME_R) || defined(HAVE_GMTIME_S)
- struct tm timeHere;
+ struct tm tm_storage;
#endif
- char strtime[100];
+ char time_string[100];
size_t len;
#if defined(HAVE_GMTIME_S)
- rt = gmtime_s(&timeHere, &t) ? NULL : &timeHere;
+ tm = gmtime_s(&tm_storage, &t) ? NULL : &tm_storage;
#elif defined(HAVE_GMTIME_R)
- rt = gmtime_r(&t, &timeHere);
+ tm = gmtime_r(&t, &tm_storage);
#else
- rt = gmtime(&t);
+ tm = gmtime(&t);
#endif
- if (!rt)
+ if (tm == NULL)
return;
- /* leave the hard yacker to our role model strftime() */
- len = strftime(strtime, sizeof(strtime)-1, fmt, rt);
- archive_strncat(as, strtime, len);
+ /* Let strftime() handle the actual formatting. */
+ len = strftime(time_string, sizeof(time_string) - 1, format, tm);
+ archive_strncat(str, time_string, len);
}
static ssize_t
-_popul_ehdr(struct archive_string *tgt, size_t tsz, warc_essential_hdr_t hdr)
+warc_populate_header(struct archive_string *header_string, size_t max_size,
+ struct warc_header header)
{
- static const char _ver[] = "WARC/1.0\r\n";
- static const char * const _typ[LAST_WT] = {
+ static const char version[] = "WARC/1.0\r\n";
+ static const char * const record_types[WARC_TYPE_LAST] = {
NULL, "warcinfo", "metadata", "resource", NULL
};
- char std_uuid[48U];
+ char generated_record_id[48U];
- if (hdr.type == WT_NONE || hdr.type > WT_RSRC) {
- /* brilliant, how exactly did we get here? */
- return -1;
+ if (header.type == WARC_TYPE_NONE || header.type > WARC_TYPE_RESOURCE) {
+ /* Invalid record type for this writer. */
+ return (-1);
}
- archive_strcpy(tgt, _ver);
+ archive_strcpy(header_string, version);
- archive_string_sprintf(tgt, "WARC-Type: %s\r\n", _typ[hdr.type]);
+ archive_string_sprintf(header_string, "WARC-Type: %s\r\n",
+ record_types[header.type]);
- if (hdr.tgturi != NULL) {
- /* check if there's a xyz:// */
- static const char _uri[] = "";
- static const char _fil[] = "file://";
- const char *u;
- char *chk = strchr(hdr.tgturi, ':');
+ if (header.target_uri != NULL) {
+ const char *uri_prefix;
+ const char *scheme = strchr(header.target_uri, ':');
- if (chk != NULL && chk[1U] == '/' && chk[2U] == '/') {
- /* yep, it's definitely a URI */
- u = _uri;
+ /* Check whether the value already contains ://. */
+ if (scheme != NULL && scheme[1U] == '/' && scheme[2U] == '/') {
+ /* Already has a scheme-style :// prefix. */
+ uri_prefix = "";
} else {
- /* hm, best to prepend file:// then */
- u = _fil;
+ /* Prepend file:// for local paths. */
+ uri_prefix = "file://";
}
- archive_string_sprintf(tgt,
- "WARC-Target-URI: %s%s\r\n", u, hdr.tgturi);
+ archive_string_sprintf(header_string,
+ "WARC-Target-URI: %s%s\r\n", uri_prefix,
+ header.target_uri);
}
- /* record time is usually when the http is sent off,
- * just treat the archive writing as such for a moment */
- xstrftime(tgt, "WARC-Date: %Y-%m-%dT%H:%M:%SZ\r\n", hdr.rtime);
+ /* Write WARC-Date from header.record_time. */
+ warc_format_time(header_string,
+ "WARC-Date: %Y-%m-%dT%H:%M:%SZ\r\n", header.record_time);
- /* while we're at it, record the mtime */
- xstrftime(tgt, "Last-Modified: %Y-%m-%dT%H:%M:%SZ\r\n", hdr.mtime);
+ /* Also write Last-Modified from header.modification_time. */
+ warc_format_time(header_string,
+ "Last-Modified: %Y-%m-%dT%H:%M:%SZ\r\n",
+ header.modification_time);
- if (hdr.recid == NULL) {
- /* generate one, grrrr */
- warc_uuid_t u;
+ if (header.record_id == NULL) {
+ /* Generate a record ID when one was not provided. */
+ struct warc_uuid uuid;
- _gen_uuid(&u);
- /* Unfortunately, archive_string_sprintf does not
- * handle the minimum number following '%'.
- * So we have to use snprintf function here instead
- * of archive_string_snprintf function. */
-#if defined(_WIN32) && !defined(__CYGWIN__) && !( defined(_MSC_VER) && _MSC_VER >= 1900)
+ warc_generate_uuid(&uuid);
+ /* archive_string_sprintf() does not support minimum field widths, so
+ * use snprintf() for UUID formatting. */
+#if defined(_WIN32) && !defined(__CYGWIN__) && \
+ !(defined(_MSC_VER) && _MSC_VER >= 1900)
#define snprintf _snprintf
#endif
- snprintf(
- std_uuid, sizeof(std_uuid),
- "<urn:uuid:%08x-%04x-%04x-%04x-%04x%08x>",
- u.u[0U],
- u.u[1U] >> 16U, u.u[1U] & 0xffffU,
- u.u[2U] >> 16U, u.u[2U] & 0xffffU,
- u.u[3U]);
- hdr.recid = std_uuid;
+ snprintf(generated_record_id, sizeof(generated_record_id),
+ "<urn:uuid:%08x-%04x-%04x-%04x-%04x%08x>",
+ uuid.value[0U],
+ uuid.value[1U] >> 16U, uuid.value[1U] & 0xffffU,
+ uuid.value[2U] >> 16U, uuid.value[2U] & 0xffffU,
+ uuid.value[3U]);
+ header.record_id = generated_record_id;
}
- /* record-id is mandatory, fingers crossed we won't fail */
- archive_string_sprintf(tgt, "WARC-Record-ID: %s\r\n", hdr.recid);
+ /* WARC-Record-ID is mandatory. */
+ archive_string_sprintf(header_string, "WARC-Record-ID: %s\r\n",
+ header.record_id);
- if (hdr.cnttyp != NULL) {
- archive_string_sprintf(tgt, "Content-Type: %s\r\n", hdr.cnttyp);
+ if (header.content_type != NULL) {
+ archive_string_sprintf(header_string, "Content-Type: %s\r\n",
+ header.content_type);
}
- /* next one is mandatory */
- archive_string_sprintf(tgt, "Content-Length: %ju\r\n", (uintmax_t)hdr.cntlen);
- /**/
- archive_strncat(tgt, "\r\n", 2);
+ /* Content-Length is mandatory. */
+ archive_string_sprintf(header_string, "Content-Length: %ju\r\n",
+ (uintmax_t)header.content_length);
+ /* End of header. */
+ archive_strncat(header_string, "\r\n", 2);
- return (archive_strlen(tgt) >= tsz)? -1: (ssize_t)archive_strlen(tgt);
+ return (archive_strlen(header_string) >= max_size) ?
+ -1 : (ssize_t)archive_strlen(header_string);
}
-static int
-_gen_uuid(warc_uuid_t *tgt)
+static void
+warc_generate_uuid(struct warc_uuid *uuid)
{
- archive_random(tgt->u, sizeof(tgt->u));
- /* obey uuid version 4 rules */
- tgt->u[1U] &= 0xffff0fffU;
- tgt->u[1U] |= 0x4000U;
- tgt->u[2U] &= 0x3fffffffU;
- tgt->u[2U] |= 0x80000000U;
- return 0;
+ archive_random(uuid->value, sizeof(uuid->value));
+ /* Apply UUID version 4 rules. */
+ uuid->value[1U] &= 0xffff0fffU;
+ uuid->value[1U] |= 0x4000U;
+ uuid->value[2U] &= 0x3fffffffU;
+ uuid->value[2U] |= 0x80000000U;
}
-
-/* archive_write_set_format_warc.c ends here */
diff --git a/contrib/libarchive/libarchive/archive_write_set_format_xar.c b/contrib/libarchive/libarchive/archive_write_set_format_xar.c
index 6ecccdef6499..0058693792c1 100644
--- a/contrib/libarchive/libarchive/archive_write_set_format_xar.c
+++ b/contrib/libarchive/libarchive/archive_write_set_format_xar.c
@@ -111,7 +111,7 @@ static int xml_writer_start_element(struct xml_writer *ctx,
static int xml_writer_write_attribute(struct xml_writer *ctx, const char *key,
const char *value);
static int xml_writer_write_attributef(struct xml_writer *ctx, const char *key,
- const char *format, ...);
+ const char *format, ...) __LA_PRINTF(3, 4);
static int xml_writer_write_string(struct xml_writer *ctx, const char *string);
static int xml_writer_write_base64(struct xml_writer* ctx,
const char *data, size_t start, size_t len);
@@ -129,14 +129,20 @@ static int xml_writer_destroy(struct xml_writer *ctx);
enum sumalg {
CKSUM_NONE = 0,
CKSUM_SHA1 = 1,
- CKSUM_MD5 = 2
+ CKSUM_MD5 = 2,
+ CKSUM_SHA256 = 3,
+ CKSUM_SHA512 = 4
};
#define MD5_SIZE 16
#define SHA1_SIZE 20
-#define MAX_SUM_SIZE 20
+#define SHA256_SIZE 32
+#define SHA512_SIZE 64
+#define MAX_SUM_SIZE 64
#define MD5_NAME "md5"
#define SHA1_NAME "sha1"
+#define SHA256_NAME "sha256"
+#define SHA512_NAME "sha512"
enum enctype {
NONE,
@@ -154,6 +160,12 @@ struct chksumwork {
#ifdef ARCHIVE_HAS_SHA1
archive_sha1_ctx sha1ctx;
#endif
+#ifdef ARCHIVE_HAS_SHA256
+ archive_sha256_ctx sha256ctx;
+#endif
+#ifdef ARCHIVE_HAS_SHA512
+ archive_sha512_ctx sha512ctx;
+#endif
};
enum la_zaction {
@@ -366,8 +378,7 @@ archive_write_set_format_xar(struct archive *_a)
ARCHIVE_STATE_NEW, "archive_write_set_format_xar");
/* If another format was already registered, unregister it. */
- if (a->format_free != NULL)
- (a->format_free)(a);
+ (void)__archive_write_unregister_format(a);
xar = calloc(1, sizeof(*xar));
if (xar == NULL) {
@@ -380,22 +391,19 @@ archive_write_set_format_xar(struct archive *_a)
file_init_hardlinks(xar);
archive_string_init(&(xar->tstr));
archive_string_init(&(xar->vstr));
+ archive_string_init(&(xar->cur_dirstr));
/*
* Create the root directory.
*/
xar->root = file_create_virtual_dir(a, xar, "");
- if (xar->root == NULL) {
- free(xar);
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate xar data");
- return (ARCHIVE_FATAL);
- }
+ if (xar->root == NULL)
+ goto memerr;
xar->root->parent = xar->root;
file_register(xar, xar->root);
xar->cur_dirent = xar->root;
- archive_string_init(&(xar->cur_dirstr));
- archive_string_ensure(&(xar->cur_dirstr), 1);
+ if (archive_string_ensure(&(xar->cur_dirstr), 1) == NULL)
+ goto memerr;
xar->cur_dirstr.s[0] = 0;
/*
@@ -422,14 +430,23 @@ archive_write_set_format_xar(struct archive *_a)
a->archive.archive_format_name = "xar";
return (ARCHIVE_OK);
+
+memerr:
+ archive_string_free(&(xar->cur_dirstr));
+ archive_string_free(&(xar->tstr));
+ archive_string_free(&(xar->vstr));
+ file_free_hardlinks(xar);
+ file_free_register(xar);
+ free(xar);
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate xar data");
+ return (ARCHIVE_FATAL);
}
static int
xar_options(struct archive_write *a, const char *key, const char *value)
{
- struct xar *xar;
-
- xar = (struct xar *)a->format_data;
+ struct xar *xar = a->format_data;
if (strcmp(key, "checksum") == 0) {
if (value == NULL)
@@ -440,6 +457,14 @@ xar_options(struct archive_write *a, const char *key, const char *value)
xar->opt_sumalg = CKSUM_SHA1;
else if (strcmp(value, "md5") == 0)
xar->opt_sumalg = CKSUM_MD5;
+#ifdef ARCHIVE_HAS_SHA256
+ else if (strcmp(value, "sha256") == 0)
+ xar->opt_sumalg = CKSUM_SHA256;
+#endif
+#ifdef ARCHIVE_HAS_SHA512
+ else if (strcmp(value, "sha512") == 0)
+ xar->opt_sumalg = CKSUM_SHA512;
+#endif
else {
archive_set_error(&(a->archive),
ARCHIVE_ERRNO_MISC,
@@ -515,6 +540,14 @@ xar_options(struct archive_write *a, const char *key, const char *value)
xar->opt_toc_sumalg = CKSUM_SHA1;
else if (strcmp(value, "md5") == 0)
xar->opt_toc_sumalg = CKSUM_MD5;
+#ifdef ARCHIVE_HAS_SHA256
+ else if (strcmp(value, "sha256") == 0)
+ xar->opt_toc_sumalg = CKSUM_SHA256;
+#endif
+#ifdef ARCHIVE_HAS_SHA512
+ else if (strcmp(value, "sha512") == 0)
+ xar->opt_toc_sumalg = CKSUM_SHA512;
+#endif
else {
archive_set_error(&(a->archive),
ARCHIVE_ERRNO_MISC,
@@ -559,12 +592,11 @@ xar_options(struct archive_write *a, const char *key, const char *value)
static int
xar_write_header(struct archive_write *a, struct archive_entry *entry)
{
- struct xar *xar;
+ struct xar *xar = a->format_data;
struct file *file;
struct archive_entry *file_entry;
int r, r2;
- xar = (struct xar *)a->format_data;
xar->cur_file = NULL;
xar->bytes_remaining = 0;
@@ -582,8 +614,10 @@ xar_write_header(struct archive_write *a, struct archive_entry *entry)
return (ARCHIVE_FATAL);
}
r2 = file_gen_utility_names(a, file);
- if (r2 < ARCHIVE_WARN)
+ if (r2 < ARCHIVE_WARN) {
+ file_free(file);
return (r2);
+ }
/*
* Ignore a path which looks like the top of directory name
@@ -672,20 +706,25 @@ xar_write_header(struct archive_write *a, struct archive_entry *entry)
checksum_init(&(xar->e_sumwrk), xar->opt_sumalg);
r = xar_compression_init_encoder(a);
- if (r != ARCHIVE_OK)
+ if (r != ARCHIVE_OK) {
+ struct chksumval sumval;
+
+ checksum_final(&(xar->a_sumwrk), &sumval);
+ checksum_final(&(xar->e_sumwrk), &sumval);
+ xar->a_sumwrk.alg = CKSUM_NONE;
+ xar->e_sumwrk.alg = CKSUM_NONE;
return (r);
- else
+ } else
return (r2);
}
static int
write_to_temp(struct archive_write *a, const void *buff, size_t s)
{
- struct xar *xar;
+ struct xar *xar = a->format_data;
const unsigned char *p;
ssize_t ws;
- xar = (struct xar *)a->format_data;
p = (const unsigned char *)buff;
while (s) {
ws = write(xar->temp_fd, p, s);
@@ -704,14 +743,12 @@ write_to_temp(struct archive_write *a, const void *buff, size_t s)
static ssize_t
xar_write_data(struct archive_write *a, const void *buff, size_t s)
{
- struct xar *xar;
+ struct xar *xar = a->format_data;
enum la_zaction run;
size_t size = 0;
size_t rsize;
int r;
- xar = (struct xar *)a->format_data;
-
if (s > xar->bytes_remaining)
s = (size_t)xar->bytes_remaining;
if (s == 0 || xar->cur_file == NULL)
@@ -805,12 +842,11 @@ xar_write_data(struct archive_write *a, const void *buff, size_t s)
static int
xar_finish_entry(struct archive_write *a)
{
- struct xar *xar;
+ struct xar *xar = a->format_data;
struct file *file;
size_t s;
ssize_t w;
- xar = (struct xar *)a->format_data;
if (xar->cur_file == NULL)
return (ARCHIVE_OK);
@@ -819,9 +855,7 @@ xar_finish_entry(struct archive_write *a)
if (s > a->null_length)
s = a->null_length;
w = xar_write_data(a, a->nulls, s);
- if (w > 0)
- xar->bytes_remaining -= w;
- else
+ if (w <= 0)
return ((int)w);
}
file = xar->cur_file;
@@ -909,14 +943,13 @@ xmlwrite_string(struct archive_write *a, struct xml_writer *writer,
return (ARCHIVE_OK);
}
-static int
+static int __LA_PRINTF(4, 5)
xmlwrite_fstring(struct archive_write *a, struct xml_writer *writer,
const char *key, const char *fmt, ...)
{
- struct xar *xar;
+ struct xar *xar = a->format_data;
va_list ap;
- xar = (struct xar *)a->format_data;
va_start(ap, fmt);
archive_string_empty(&xar->vstr);
archive_string_vsprintf(&xar->vstr, fmt, ap);
@@ -1110,30 +1143,27 @@ make_fflags_entry(struct archive_write *a, struct xml_writer *writer,
{ NULL, NULL}
};
const struct flagentry *fe, *flagentry;
-#define FLAGENTRY_MAXSIZE ((sizeof(flagbsd)+sizeof(flagext2))/sizeof(flagbsd))
- const struct flagentry *avail[FLAGENTRY_MAXSIZE];
const char *p;
- int i, n, r;
+ int r, started;
if (strcmp(element, "ext2") == 0)
flagentry = flagext2;
else
flagentry = flagbsd;
- n = 0;
p = fflags_text;
+ started = 0;
do {
- const char *cp;
+ const char *cp, *name = NULL;
cp = strchr(p, ',');
if (cp == NULL)
cp = p + strlen(p);
for (fe = flagentry; fe->name != NULL; fe++) {
- if (fe->name[cp - p] != '\0'
- || p[0] != fe->name[0])
- continue;
if (strncmp(p, fe->name, cp - p) == 0) {
- avail[n++] = fe;
+ if (fe->name[cp - p] != '\0')
+ continue;
+ name = fe->xarname;
break;
}
}
@@ -1141,23 +1171,26 @@ make_fflags_entry(struct archive_write *a, struct xml_writer *writer,
p = cp + 1;
else
p = NULL;
- } while (p != NULL);
- if (n > 0) {
- r = xml_writer_start_element(writer, element);
- if (r < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "xml_writer_start_element() failed: %d", r);
- return (ARCHIVE_FATAL);
- }
- for (i = 0; i < n; i++) {
- r = xmlwrite_string(a, writer,
- avail[i]->xarname, NULL);
+ if (name != NULL) {
+ if (!started) {
+ r = xml_writer_start_element(writer, element);
+ if (r < 0) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "xml_writer_start_element()"
+ " failed: %d", r);
+ return (ARCHIVE_FATAL);
+ }
+ started = 1;
+ }
+ r = xmlwrite_string(a, writer, name, NULL);
if (r != ARCHIVE_OK)
return (r);
}
+ } while (p != NULL);
+ if (started) {
r = xml_writer_end_element(writer);
if (r < 0) {
archive_set_error(&a->archive,
@@ -1204,7 +1237,7 @@ static int
make_file_entry(struct archive_write *a, struct xml_writer *writer,
struct file *file)
{
- struct xar *xar;
+ struct xar *xar = a->format_data;
const char *filetype, *filelink, *fflags;
struct archive_string linkto;
struct heap_data *heap;
@@ -1212,7 +1245,6 @@ make_file_entry(struct archive_write *a, struct xml_writer *writer,
size_t len;
int r, r2;
- xar = (struct xar *)a->format_data;
r2 = ARCHIVE_OK;
/*
@@ -1335,11 +1367,11 @@ make_file_entry(struct archive_write *a, struct xml_writer *writer,
return (ARCHIVE_FATAL);
}
r = xmlwrite_fstring(a, writer, "major",
- "%d", archive_entry_rdevmajor(file->entry));
+ "%ld", (long)archive_entry_rdevmajor(file->entry));
if (r < 0)
return (ARCHIVE_FATAL);
r = xmlwrite_fstring(a, writer, "minor",
- "%d", archive_entry_rdevminor(file->entry));
+ "%ld", (long)archive_entry_rdevminor(file->entry));
if (r < 0)
return (ARCHIVE_FATAL);
r = xml_writer_end_element(writer);
@@ -1363,7 +1395,7 @@ make_file_entry(struct archive_write *a, struct xml_writer *writer,
return (ARCHIVE_FATAL);
if (archive_entry_dev(file->entry) != 0) {
r = xmlwrite_fstring(a, writer, "deviceno",
- "%d", archive_entry_dev(file->entry));
+ "%ld", (long)archive_entry_dev(file->entry));
if (r < 0)
return (ARCHIVE_FATAL);
}
@@ -1439,7 +1471,7 @@ make_file_entry(struct archive_write *a, struct xml_writer *writer,
}
/*
- * Make a mtime entry, "<mtime>".
+ * Make an mtime entry, "<mtime>".
*/
if (archive_entry_mtime_is_set(file->entry)) {
r = xmlwrite_time(a, writer, "mtime",
@@ -1574,7 +1606,7 @@ make_file_entry(struct archive_write *a, struct xml_writer *writer,
static int
make_toc(struct archive_write *a)
{
- struct xar *xar;
+ struct xar *xar = a->format_data;
struct file *np;
struct xml_writer *writer;
const char* content;
@@ -1582,8 +1614,6 @@ make_toc(struct archive_write *a)
int algsize;
int r, ret;
- xar = (struct xar *)a->format_data;
-
ret = ARCHIVE_FATAL;
/*
@@ -1824,11 +1854,10 @@ exit_toc:
static int
flush_wbuff(struct archive_write *a)
{
- struct xar *xar;
+ struct xar *xar = a->format_data;
int r;
size_t s;
- xar = (struct xar *)a->format_data;
s = sizeof(xar->wbuff) - xar->wbuff_remaining;
r = __archive_write_output(a, xar->wbuff, s);
if (r != ARCHIVE_OK)
@@ -1840,10 +1869,9 @@ flush_wbuff(struct archive_write *a)
static int
copy_out(struct archive_write *a, uint64_t offset, uint64_t length)
{
- struct xar *xar;
+ struct xar *xar = a->format_data;
int r;
- xar = (struct xar *)a->format_data;
if (lseek(xar->temp_fd, offset, SEEK_SET) < 0) {
archive_set_error(&(a->archive), errno, "lseek failed");
return (ARCHIVE_FATAL);
@@ -1866,7 +1894,8 @@ copy_out(struct archive_write *a, uint64_t offset, uint64_t length)
return (ARCHIVE_FATAL);
}
if (rs == 0) {
- archive_set_error(&(a->archive), 0,
+ archive_set_error(&(a->archive),
+ ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated xar archive");
return (ARCHIVE_FATAL);
}
@@ -1884,13 +1913,11 @@ copy_out(struct archive_write *a, uint64_t offset, uint64_t length)
static int
xar_close(struct archive_write *a)
{
- struct xar *xar;
+ struct xar *xar = a->format_data;
unsigned char *wb;
uint64_t length;
int r;
- xar = (struct xar *)a->format_data;
-
/* Empty! */
if (xar->root->children.first == NULL)
return (ARCHIVE_OK);
@@ -1950,9 +1977,7 @@ xar_close(struct archive_write *a)
static int
xar_free(struct archive_write *a)
{
- struct xar *xar;
-
- xar = (struct xar *)a->format_data;
+ struct xar *xar = a->format_data;
/* Close the temporary file. */
if (xar->temp_fd >= 0)
@@ -2110,13 +2135,12 @@ cleanup_backslash(char *utf8, size_t len)
static int
file_gen_utility_names(struct archive_write *a, struct file *file)
{
- struct xar *xar;
+ struct xar *xar = a->format_data;
const char *pp;
char *p, *dirname, *slash;
size_t len;
int r = ARCHIVE_OK;
- xar = (struct xar *)a->format_data;
archive_string_empty(&(file->parentdir));
archive_string_empty(&(file->basename));
archive_string_empty(&(file->symlink));
@@ -2205,20 +2229,29 @@ file_gen_utility_names(struct archive_write *a, struct file *file)
* --> 'dir/dir2/'
*/
char *rp = p -1;
+ size_t off;
+ for (off = 4; p[off] == '/'; off++)
+ ;
while (rp >= dirname) {
if (*rp == '/')
break;
--rp;
}
if (rp > dirname) {
- strcpy(rp, p+3);
+ memmove(rp + 1, p + off, strlen(p + off) + 1);
p = rp;
} else {
- strcpy(dirname, p+4);
+ memmove(dirname, p + off, strlen(p + off) + 1);
p = dirname;
}
} else
p++;
+ } else if (p == dirname && p[0] == '.' && p[1] == '.' && p[2] == '/') {
+ size_t off;
+ for (off = 3; p[off] == '/'; off++)
+ ;
+ memmove(dirname, p + off, strlen(p + off) + 1);
+ p = dirname;
} else
p++;
}
@@ -2272,7 +2305,7 @@ file_gen_utility_names(struct archive_write *a, struct file *file)
static int
get_path_component(char *name, int n, const char *fn)
{
- char *p;
+ const char *p;
int l;
p = strchr(fn, '/');
@@ -2295,6 +2328,7 @@ get_path_component(char *name, int n, const char *fn)
static int
file_tree(struct archive_write *a, struct file **filepp)
{
+ struct xar *xar = a->format_data;
#if defined(_WIN32) && !defined(__CYGWIN__)
char name[_MAX_FNAME];/* Included null terminator size. */
#elif defined(NAME_MAX) && NAME_MAX >= 255
@@ -2302,7 +2336,6 @@ file_tree(struct archive_write *a, struct file **filepp)
#else
char name[256];
#endif
- struct xar *xar = (struct xar *)a->format_data;
struct file *dent, *file, *np;
struct archive_entry *ent;
const char *fn, *p;
@@ -2378,10 +2411,24 @@ file_tree(struct archive_write *a, struct file **filepp)
archive_string_init(&as);
archive_strncat(&as, p, fn - p + l);
- if (as.s[as.length-1] == '/') {
+ if (as.length > 0 && as.s[as.length-1] == '/') {
as.s[as.length-1] = '\0';
as.length--;
}
+ if (as.length == 0) {
+ archive_string_free(&as);
+ fn += strspn(fn, "/");
+ l = get_path_component(name, sizeof(name), fn);
+ if (l < 0) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "A name buffer is too small");
+ file_free(file);
+ *filepp = NULL;
+ return (ARCHIVE_FATAL);
+ }
+ continue;
+ }
vp = file_create_virtual_dir(a, xar, as.s);
if (vp == NULL) {
archive_string_free(&as);
@@ -2392,8 +2439,12 @@ file_tree(struct archive_write *a, struct file **filepp)
return (ARCHIVE_FATAL);
}
archive_string_free(&as);
- if (file_gen_utility_names(a, vp) <= ARCHIVE_FAILED)
+ if (file_gen_utility_names(a, vp) <= ARCHIVE_FAILED) {
+ file_free(vp);
+ file_free(file);
+ *filepp = NULL;
return (ARCHIVE_FATAL);
+ }
file_add_child_tail(dent, vp);
file_register(xar, vp);
np = vp;
@@ -2504,7 +2555,7 @@ file_free_register(struct xar *xar)
static int
file_register_hardlink(struct archive_write *a, struct file *file)
{
- struct xar *xar = (struct xar *)a->format_data;
+ struct xar *xar = a->format_data;
struct hardlink *hl;
const char *pathname;
@@ -2626,6 +2677,16 @@ checksum_init(struct chksumwork *sumwrk, enum sumalg sum_alg)
case CKSUM_MD5:
archive_md5_init(&(sumwrk->md5ctx));
break;
+#ifdef ARCHIVE_HAS_SHA256
+ case CKSUM_SHA256:
+ archive_sha256_init(&(sumwrk->sha256ctx));
+ break;
+#endif
+#ifdef ARCHIVE_HAS_SHA512
+ case CKSUM_SHA512:
+ archive_sha512_init(&(sumwrk->sha512ctx));
+ break;
+#endif
}
}
@@ -2642,6 +2703,16 @@ checksum_update(struct chksumwork *sumwrk, const void *buff, size_t size)
case CKSUM_MD5:
archive_md5_update(&(sumwrk->md5ctx), buff, size);
break;
+#ifdef ARCHIVE_HAS_SHA256
+ case CKSUM_SHA256:
+ archive_sha256_update(&(sumwrk->sha256ctx), buff, size);
+ break;
+#endif
+#ifdef ARCHIVE_HAS_SHA512
+ case CKSUM_SHA512:
+ archive_sha512_update(&(sumwrk->sha512ctx), buff, size);
+ break;
+#endif
}
}
@@ -2661,6 +2732,18 @@ checksum_final(struct chksumwork *sumwrk, struct chksumval *sumval)
archive_md5_final(&(sumwrk->md5ctx), sumval->val);
sumval->len = MD5_SIZE;
break;
+#ifdef ARCHIVE_HAS_SHA256
+ case CKSUM_SHA256:
+ archive_sha256_final(&(sumwrk->sha256ctx), sumval->val);
+ sumval->len = SHA256_SIZE;
+ break;
+#endif
+#ifdef ARCHIVE_HAS_SHA512
+ case CKSUM_SHA512:
+ archive_sha512_final(&(sumwrk->sha512ctx), sumval->val);
+ sumval->len = SHA512_SIZE;
+ break;
+#endif
}
sumval->alg = sumwrk->alg;
}
@@ -3110,10 +3193,9 @@ compression_init_encoder_xz(struct archive *a,
static int
xar_compression_init_encoder(struct archive_write *a)
{
- struct xar *xar;
+ struct xar *xar = a->format_data;
int r;
- xar = (struct xar *)a->format_data;
switch (xar->opt_compression) {
case GZIP:
r = compression_init_encoder_gzip(
@@ -3170,14 +3252,13 @@ compression_end(struct archive *a, struct la_zstream *lastrm)
static int
save_xattrs(struct archive_write *a, struct file *file)
{
- struct xar *xar;
+ struct xar *xar = a->format_data;
const char *name;
const void *value;
struct heap_data *heap;
size_t size;
int count, r;
- xar = (struct xar *)a->format_data;
count = archive_entry_xattr_reset(file->entry);
if (count == 0)
return (ARCHIVE_OK);
@@ -3189,6 +3270,12 @@ save_xattrs(struct archive_write *a, struct file *file)
heap = calloc(1, sizeof(*heap));
if (heap == NULL) {
+ struct chksumval sumval;
+
+ checksum_final(&(xar->a_sumwrk), &sumval);
+ checksum_final(&(xar->e_sumwrk), &sumval);
+ xar->a_sumwrk.alg = CKSUM_NONE;
+ xar->e_sumwrk.alg = CKSUM_NONE;
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory for xattr");
return (ARCHIVE_FATAL);
@@ -3226,6 +3313,10 @@ save_xattrs(struct archive_write *a, struct file *file)
*/
r = xar_compression_init_encoder(a);
if (r != ARCHIVE_OK) {
+ struct chksumval sumval;
+
+ checksum_final(&(xar->a_sumwrk), &sumval);
+ xar->a_sumwrk.alg = CKSUM_NONE;
free(heap);
return (ARCHIVE_FATAL);
}
@@ -3280,6 +3371,10 @@ getalgsize(enum sumalg sumalg)
return (SHA1_SIZE);
case CKSUM_MD5:
return (MD5_SIZE);
+ case CKSUM_SHA256:
+ return (SHA256_SIZE);
+ case CKSUM_SHA512:
+ return (SHA512_SIZE);
}
}
@@ -3294,6 +3389,10 @@ getalgname(enum sumalg sumalg)
return (SHA1_NAME);
case CKSUM_MD5:
return (MD5_NAME);
+ case CKSUM_SHA256:
+ return (SHA256_NAME);
+ case CKSUM_SHA512:
+ return (SHA512_NAME);
}
}
diff --git a/contrib/libarchive/libarchive/archive_write_set_format_zip.c b/contrib/libarchive/libarchive/archive_write_set_format_zip.c
index 81d3db0db038..9c7073fb76bd 100644
--- a/contrib/libarchive/libarchive/archive_write_set_format_zip.c
+++ b/contrib/libarchive/libarchive/archive_write_set_format_zip.c
@@ -68,6 +68,7 @@
#include "archive_entry.h"
#include "archive_entry_locale.h"
#include "archive_hmac_private.h"
+#include "archive_integer.h"
#include "archive_private.h"
#include "archive_random_private.h"
#include "archive_time_private.h"
@@ -154,7 +155,6 @@ struct zip {
enum compression entry_compression;
enum encryption entry_encryption;
int entry_flags;
- int experiments;
struct trad_enc_ctx tctx;
char tctx_valid;
unsigned char trad_chkdat;
@@ -235,7 +235,6 @@ static int archive_write_zip_header(struct archive_write *,
struct archive_entry *);
static int archive_write_zip_options(struct archive_write *,
const char *, const char *);
-static size_t path_length(struct archive_entry *);
static int write_path(struct archive_entry *, struct archive_write *);
static void copy_path(struct archive_entry *, unsigned char *);
static struct archive_string_conv *get_sconv(struct archive_write *, struct zip *);
@@ -730,8 +729,7 @@ archive_write_set_format_zip(struct archive *_a)
ARCHIVE_STATE_NEW, "archive_write_set_format_zip");
/* If another format was already registered, unregister it. */
- if (a->format_free != NULL)
- (a->format_free)(a);
+ (void)__archive_write_unregister_format(a);
zip = calloc(1, sizeof(*zip));
if (zip == NULL) {
@@ -791,12 +789,13 @@ is_all_ascii(const char *p)
static int
archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
{
+ struct zip *zip = a->format_data;
unsigned char local_header[32];
unsigned char local_extra[144];
- struct zip *zip = a->format_data;
unsigned char *e;
unsigned char *cd_extra;
size_t filename_length;
+ const char *path;
const char *slink = NULL;
size_t slink_size = 0;
struct archive_string_conv *sconv = get_sconv(a, zip);
@@ -958,7 +957,22 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
#endif
}
}
- filename_length = path_length(zip->entry);
+ /* Reject empty or overlong pathnames */
+ path = archive_entry_pathname(zip->entry);
+ if (path == NULL || path[0] == '\0') {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "ZIP format requires a non-empty pathname");
+ return (ARCHIVE_FAILED);
+ }
+ filename_length = strlen(path);
+ /* Include the trailing slash added to directories. */
+ if (type == AE_IFDIR && path[filename_length - 1] != '/')
+ filename_length++;
+ if (filename_length > 0xffff) {
+ archive_set_error(&a->archive, ENAMETOOLONG,
+ "Pathname too long for ZIP format");
+ return (ARCHIVE_FAILED);
+ }
/* Determine appropriate compression and size for this entry. */
if (type == AE_IFLNK) {
@@ -1052,8 +1066,13 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
default:
break;
}
- if (zip->entry_compression == COMPRESSION_STORE)
- zip->entry_compressed_size += additional_size;
+ if (zip->entry_compression == COMPRESSION_STORE &&
+ archive_ckd_add_i64(&zip->entry_compressed_size,
+ zip->entry_compressed_size, additional_size)) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "File size too large for encrypted ZIP entry");
+ return (ARCHIVE_FAILED);
+ }
}
/*
@@ -1067,7 +1086,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
* (compression might make file larger)
*/
if ((zip->flags & ZIP_FLAG_FORCE_ZIP64)
- || (zip->entry_uncompressed_size + additional_size > ZIP_4GB_MAX)
+ || (zip->entry_uncompressed_size > ZIP_4GB_MAX - additional_size)
|| (zip->entry_uncompressed_size > ZIP_4GB_MAX_UNCOMPRESSED
&& zip->entry_compression != COMPRESSION_STORE)) {
MIN_VERSION_NEEDED(45);
@@ -1501,8 +1520,8 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
static ssize_t
archive_write_zip_data(struct archive_write *a, const void *buff, size_t s)
{
- int ret;
struct zip *zip = a->format_data;
+ int ret;
if ((int64_t)s > zip->entry_uncompressed_limit)
s = (size_t)zip->entry_uncompressed_limit;
@@ -2170,9 +2189,9 @@ archive_write_zip_finish_entry(struct archive_write *a)
static int
archive_write_zip_close(struct archive_write *a)
{
+ struct zip *zip = a->format_data;
uint8_t buff[64];
int64_t offset_start, offset_end;
- struct zip *zip = a->format_data;
struct cd_segment *segment;
int ret;
@@ -2242,10 +2261,9 @@ archive_write_zip_close(struct archive_write *a)
static int
archive_write_zip_free(struct archive_write *a)
{
- struct zip *zip;
+ struct zip *zip = a->format_data;
struct cd_segment *segment;
- zip = a->format_data;
while (zip->central_directory != NULL) {
segment = zip->central_directory;
zip->central_directory = segment->next;
@@ -2265,24 +2283,6 @@ archive_write_zip_free(struct archive_write *a)
return (ARCHIVE_OK);
}
-static size_t
-path_length(struct archive_entry *entry)
-{
- mode_t type;
- const char *path;
- size_t len;
-
- type = archive_entry_filetype(entry);
- path = archive_entry_pathname(entry);
-
- if (path == NULL)
- return (0);
- len = strlen(path);
- if (type == AE_IFDIR && (path[0] == '\0' || path[len - 1] != '/'))
- ++len; /* Space for the trailing / */
- return len;
-}
-
static int
write_path(struct archive_entry *entry, struct archive_write *archive)
{
@@ -2304,7 +2304,7 @@ write_path(struct archive_entry *entry, struct archive_write *archive)
written_bytes += strlen(path);
/* Folders are recognized by a trailing slash. */
- if ((type == AE_IFDIR) & (path[strlen(path) - 1] != '/')) {
+ if ((type == AE_IFDIR) && (path[strlen(path) - 1] != '/')) {
ret = __archive_write_output(archive, "/", 1);
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
diff --git a/contrib/libarchive/libarchive/archive_write_set_options.3 b/contrib/libarchive/libarchive/archive_write_set_options.3
index c3de50c8fe91..e03b5175771d 100644
--- a/contrib/libarchive/libarchive/archive_write_set_options.3
+++ b/contrib/libarchive/libarchive/archive_write_set_options.3
@@ -555,6 +555,20 @@ used when translating file names.
.El
.It Format pax
.Bl -tag -compact -width indent
+.It Cm align
+Pad the extended header of each regular file so that the file data that
+follows begins on a multiple of the given number of bytes within the
+uncompressed archive stream.
+The value must be a power of two and a multiple of 512.
+Because the alignment is applied to the uncompressed stream, it is
+independent of any compression filter: the decompressed archive is
+aligned regardless of whether the archive is compressed.
+This allows tools to share file contents out of an
+uncompressed archive (or an uncompressed copy of one) using
+reflinks or
+.Xr copy_file_range 2 ,
+at the cost of some extra padding.
+Files shorter than the alignment are not padded.
.It Cm hdrcharset
The value is used as a character set name that will be
used when translating file, group and user names.
@@ -608,9 +622,11 @@ as file checksum method.
Supported values are
.Dq none ,
.Dq md5 ,
-and
.Dq sha1
-.Pq default .
+.Pq default ,
+.Dq sha256 ,
+and
+.Dq sha512 .
.It Cm compression Ns = Ns Ar type
Use
.Ar type
@@ -631,10 +647,12 @@ Use
as table of contents checksum method.
Supported values are
.Dq none ,
-.Dq md5
-and
+.Dq md5 ,
.Dq sha1
-.Pq default .
+.Pq default ,
+.Dq sha256 ,
+and
+.Dq sha512 .
.El
.It Format zip
.Bl -tag -compact -width indent
diff --git a/contrib/libarchive/libarchive/libarchive-formats.5 b/contrib/libarchive/libarchive/libarchive-formats.5
index 1b057b4da0d8..eb720eb740f5 100644
--- a/contrib/libarchive/libarchive/libarchive-formats.5
+++ b/contrib/libarchive/libarchive/libarchive-formats.5
@@ -210,7 +210,7 @@ values of varying byte order and length.
.Bl -tag -width indent
.It Cm binary
The libarchive library transparently reads both big-endian and
-little-endian variants of the the two binary cpio formats; the
+little-endian variants of the two binary cpio formats; the
original one from PWB/UNIX, and the later, more widely used, variant.
This format used 32-bit binary values for file size and mtime, and
16-bit binary values for the other fields. The formats support only
diff --git a/contrib/libarchive/libarchive/test/read_open_memory.c b/contrib/libarchive/libarchive/test/read_open_memory.c
index 9262ab9d30b3..0c714a31e809 100644
--- a/contrib/libarchive/libarchive/test/read_open_memory.c
+++ b/contrib/libarchive/libarchive/test/read_open_memory.c
@@ -86,6 +86,7 @@ read_open_memory_internal(struct archive *a, const void *buff,
size_t size, size_t read_size, int level)
{
struct read_memory_data *mine = NULL;
+ int r;
switch (level) {
case 3:
@@ -112,7 +113,12 @@ read_open_memory_internal(struct archive *a, const void *buff,
archive_read_set_read_callback(a, memory_read);
archive_read_set_close_callback(a, memory_read_close);
- archive_read_set_callback_data(a, mine);
+ r = archive_read_set_callback_data(a, mine);
+ if (r < 0)
+ return (r);
+ __LA_FALLTHROUGH;
+ default:
+ break;
}
return archive_read_open1(a);
}
diff --git a/contrib/libarchive/libarchive/test/test_acl_from_text_overread.c b/contrib/libarchive/libarchive/test/test_acl_from_text_overread.c
new file mode 100644
index 000000000000..ecf6cc78eb87
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_acl_from_text_overread.c
@@ -0,0 +1,98 @@
+/*-
+ * Copyright (c) 2026 Kaif Khan
+ * 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"
+
+#define __LIBARCHIVE_TEST
+#include "archive_acl_private.h"
+
+/*
+ * archive_acl_from_text_nl() takes a pointer and a length and does not
+ * require the buffer to be NUL terminated. An entry that is only
+ * whitespace, or trailing whitespace after a valid entry, must not make
+ * the parser read past the end of the buffer.
+ *
+ * Each input is copied into a buffer sized to exactly its length so that
+ * a read past the end is out of bounds.
+ */
+static void
+parse_nl(const char *text, int type)
+{
+ size_t len = strlen(text);
+ char *buf = malloc(len);
+ struct archive_acl acl;
+
+ assert(buf != NULL);
+ memcpy(buf, text, len);
+ memset(&acl, 0, sizeof(acl));
+ /* Must not read buf[len]. */
+ archive_acl_from_text_nl(&acl, buf, len, type, NULL);
+ archive_acl_clear(&acl);
+ free(buf);
+}
+
+DEFINE_TEST(test_acl_from_text_overread)
+{
+ static const char *whitespace[] = {
+ " ", " ", "\t", "\n\n", "user::rwx, "
+ };
+ size_t i;
+
+ for (i = 0; i < sizeof(whitespace) / sizeof(whitespace[0]); i++) {
+ parse_nl(whitespace[i], ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+ parse_nl(whitespace[i], ARCHIVE_ENTRY_ACL_TYPE_NFS4);
+ }
+
+ /*
+ * Trailing whitespace after a valid entry must not change the parse:
+ * the count matches the same text without the trailing spaces.
+ */
+ {
+ static const char clean[] = "user:100:rwx";
+ static const char padded[] = "user:100:rwx ";
+ struct archive_acl acl1, acl2;
+ char *b1 = malloc(sizeof(clean) - 1);
+ char *b2 = malloc(sizeof(padded) - 1);
+
+ assert(b1 != NULL);
+ assert(b2 != NULL);
+ memcpy(b1, clean, sizeof(clean) - 1);
+ memcpy(b2, padded, sizeof(padded) - 1);
+ memset(&acl1, 0, sizeof(acl1));
+ memset(&acl2, 0, sizeof(acl2));
+ archive_acl_from_text_nl(&acl1, b1, sizeof(clean) - 1,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, NULL);
+ archive_acl_from_text_nl(&acl2, b2, sizeof(padded) - 1,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, NULL);
+ assertEqualInt(
+ archive_acl_count(&acl1, ARCHIVE_ENTRY_ACL_TYPE_ACCESS),
+ archive_acl_count(&acl2, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ assert(archive_acl_count(&acl2,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS) > 0);
+ archive_acl_clear(&acl1);
+ archive_acl_clear(&acl2);
+ free(b1);
+ free(b2);
+ }
+}
diff --git a/contrib/libarchive/libarchive/test/test_acl_nfs4_null_id_overflow.c b/contrib/libarchive/libarchive/test/test_acl_nfs4_null_id_overflow.c
new file mode 100644
index 000000000000..590c704595ce
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_acl_nfs4_null_id_overflow.c
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 2026 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"
+
+/*
+ * A USER NFSv4 ACL entry with a NULL name and a large numeric qualifier
+ * triggers a heap buffer overflow in archive_acl_to_text_l().
+ *
+ * archive_acl_text_len() only reserves space for the trailing ":id" digits
+ * when ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID is set, but the serializer always
+ * writes them for USER/GROUP entries when the name is NULL. With a 7-digit
+ * ID the allocated buffer is too short and append_id() writes past its end.
+ *
+ * Without the fix, libarchive's own post-write guard fires:
+ * "Fatal Internal Error: Buffer overrun"
+ * (or under AddressSanitizer a heap-buffer-overflow is reported at
+ * archive_acl.c in append_id / append_entry).
+ */
+DEFINE_TEST(test_acl_nfs4_null_id_overflow)
+{
+ struct archive_entry *ae;
+ char *text;
+ ssize_t len;
+
+ ae = archive_entry_new();
+ assert(ae != NULL);
+ archive_entry_set_pathname(ae, "file");
+ archive_entry_set_mode(ae, AE_IFREG | 0644);
+
+ /* NULL name + 7-digit id: the missing ":9999999" overflows the buffer */
+ archive_entry_acl_add_entry(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_DENY,
+ 0,
+ ARCHIVE_ENTRY_ACL_USER,
+ 9999999,
+ NULL);
+
+ text = archive_entry_acl_to_text(ae, &len,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4);
+ assert(text != NULL);
+ /* The numeric id must appear in the output as the user name */
+ assert(strstr(text, "9999999") != NULL);
+ free(text);
+
+ archive_entry_free(ae);
+}
+
+/*
+ * The wide (wchar_t) serializer has a related bug: when the name is NULL
+ * it passes id=-1 to append_entry_w() instead of the actual numeric id,
+ * so the id is never written and a garbage character appears in the name
+ * slot instead.
+ *
+ * The wide estimator has the same missing-id-digits gap as the narrow one,
+ * and both must be fixed together with the wide serializer.
+ */
+DEFINE_TEST(test_acl_nfs4_null_id_overflow_w)
+{
+ struct archive_entry *ae;
+ wchar_t *wtext;
+ ssize_t len;
+
+ ae = archive_entry_new();
+ assert(ae != NULL);
+ archive_entry_set_pathname(ae, "file");
+ archive_entry_set_mode(ae, AE_IFREG | 0644);
+
+ archive_entry_acl_add_entry(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_DENY,
+ 0,
+ ARCHIVE_ENTRY_ACL_USER,
+ 9999999,
+ NULL);
+
+ wtext = archive_entry_acl_to_text_w(ae, &len,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4);
+ assert(wtext != NULL);
+ /* The numeric id must appear in the output as the user name */
+ assert(wcsstr(wtext, L"9999999") != NULL);
+ free(wtext);
+
+ archive_entry_free(ae);
+}
diff --git a/contrib/libarchive/libarchive/test/test_acl_nfs4_text.c b/contrib/libarchive/libarchive/test/test_acl_nfs4_text.c
new file mode 100644
index 000000000000..165d18ed8f1c
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_acl_nfs4_text.c
@@ -0,0 +1,426 @@
+/*-
+ * Copyright (c) 2026 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"
+#include <limits.h>
+
+/*
+ * Focused tests for NFSv4 ACL text parsing and serialization.
+ *
+ * test_acl_text.c already covers basic round-trips with well-formed input.
+ * These tests probe areas not reached there: all four ACL types, numeric IDs,
+ * extra-ID field override, isint() overflow, malformed entries, compact mode,
+ * and the wide-char path.
+ */
+
+/* NFSv4 text in standard (no extra ID), extra-ID, and compact+extra-ID forms.
+ * These are the same strings used in test_acl_text.c acltext[9..11]. */
+static const char *nfs4_std =
+ "user:user77:rw-p--a-R-c-o-:-------:allow\n"
+ "user:user101:-w-pdD--------:fdin---:deny\n"
+ "group:group78:r-----a-R-c---:------I:allow\n"
+ "owner@:rwxp--aARWcCo-:-------:allow\n"
+ "group@:rw-p--a-R-c---:-------:allow\n"
+ "everyone@:r-----a-R-c--s:-------:allow";
+
+static const char *nfs4_extra_id =
+ "user:user77:rw-p--a-R-c-o-:-------:allow:77\n"
+ "user:user101:-w-pdD--------:fdin---:deny:101\n"
+ "group:group78:r-----a-R-c---:------I:allow:78\n"
+ "owner@:rwxp--aARWcCo-:-------:allow\n"
+ "group@:rw-p--a-R-c---:-------:allow\n"
+ "everyone@:r-----a-R-c--s:-------:allow";
+
+static const char *nfs4_compact =
+ "user:user77:rwpaRco::allow:77\n"
+ "user:user101:wpdD:fdin:deny:101\n"
+ "group:group78:raRc:I:allow:78\n"
+ "owner@:rwxpaARWcCo::allow\n"
+ "group@:rwpaRc::allow\n"
+ "everyone@:raRcs::allow";
+
+static wchar_t *
+s_to_ws(const char *s)
+{
+ size_t len = strlen(s) + 1;
+ wchar_t *ws = malloc(len * sizeof(wchar_t));
+ assert(ws != NULL);
+ assert(mbstowcs(ws, s, len) != (size_t)-1);
+ return (ws);
+}
+
+/*
+ * Round-trip: parse NFS4 text → serialize → compare.
+ * Covers standard, extra-ID, and compact+extra-ID formats,
+ * for both the narrow and wide serializers.
+ */
+DEFINE_TEST(test_acl_nfs4_text_roundtrip)
+{
+ struct archive_entry *ae;
+ char *text;
+ wchar_t *wtext, *ws;
+ ssize_t len;
+
+ ae = archive_entry_new();
+ assert(ae != NULL);
+ archive_entry_set_pathname(ae, "file");
+ archive_entry_set_mode(ae, AE_IFREG | 0644);
+
+ /* Standard format */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae, nfs4_std,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ text = archive_entry_acl_to_text(ae, &len,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4);
+ assertEqualString(nfs4_std, text);
+ free(text);
+ archive_entry_acl_clear(ae);
+
+ /* Extra-ID format: trailing :id must be preserved */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae, nfs4_extra_id,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ text = archive_entry_acl_to_text(ae, &len,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4 | ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID);
+ assertEqualString(nfs4_extra_id, text);
+ free(text);
+ archive_entry_acl_clear(ae);
+
+ /* Compact format: empty perm/flag fields must round-trip */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae, nfs4_compact,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ text = archive_entry_acl_to_text(ae, &len,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4 |
+ ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID |
+ ARCHIVE_ENTRY_ACL_STYLE_COMPACT);
+ assertEqualString(nfs4_compact, text);
+ free(text);
+ archive_entry_acl_clear(ae);
+
+ /* Wide: standard format */
+ ws = s_to_ws(nfs4_std);
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text_w(ae, ws,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ wtext = archive_entry_acl_to_text_w(ae, &len,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4);
+ assertEqualWString(ws, wtext);
+ free(wtext);
+ free(ws);
+ archive_entry_acl_clear(ae);
+
+ /* Wide: compact+extra-ID format */
+ ws = s_to_ws(nfs4_compact);
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text_w(ae, ws,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ wtext = archive_entry_acl_to_text_w(ae, &len,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4 |
+ ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID |
+ ARCHIVE_ENTRY_ACL_STYLE_COMPACT);
+ assertEqualWString(ws, wtext);
+ free(wtext);
+ free(ws);
+ archive_entry_acl_clear(ae);
+
+ archive_entry_free(ae);
+}
+
+/*
+ * All four ACL entry types: allow, deny, audit, alarm.
+ * test_acl_text.c only exercises allow and deny.
+ */
+DEFINE_TEST(test_acl_nfs4_text_types)
+{
+ struct archive_entry *ae;
+ char *text;
+ wchar_t *wtext, *ws;
+ ssize_t len;
+ int type, permset, tag, qual;
+ const char *name;
+ static const char *audit_alarm_text =
+ "user:alice:rw-p--aARWcCos:-------:audit\n"
+ "group:staff:rw-p--aARWcCos:-------:alarm";
+
+ ae = archive_entry_new();
+ assert(ae != NULL);
+
+ /* Parse and verify both audit and alarm entries are stored */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae, audit_alarm_text,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(2,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_next(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(ARCHIVE_ENTRY_ACL_TYPE_AUDIT, type);
+ assertEqualString("alice", name);
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_next(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(ARCHIVE_ENTRY_ACL_TYPE_ALARM, type);
+ assertEqualString("staff", name);
+
+ /* Round-trip: serialize then compare */
+ text = archive_entry_acl_to_text(ae, &len,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4);
+ assertEqualString(audit_alarm_text, text);
+
+ /* Verify same round-trip via wide path */
+ ws = s_to_ws(audit_alarm_text);
+ wtext = archive_entry_acl_to_text_w(ae, &len,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4);
+ assertEqualWString(ws, wtext);
+ free(ws);
+ free(wtext);
+ free(text);
+
+ archive_entry_free(ae);
+}
+
+/*
+ * Numeric IDs in the name field and the extra-ID override field.
+ *
+ * 1. "user:1000:..." — the name field is a pure number; id is set from it.
+ * 2. "user:name:...:42" — the trailing id field overrides any id derived
+ * from the name.
+ * 3. "user:1000:...:42" — trailing id overrides even a numeric name.
+ * 4. isint() overflow: a field with more than 10 digits is clamped to INT_MAX.
+ */
+DEFINE_TEST(test_acl_nfs4_text_numeric_id)
+{
+ struct archive_entry *ae;
+ char *text;
+ ssize_t len;
+ int type, permset, tag, qual;
+ const char *name;
+
+ ae = archive_entry_new();
+ assert(ae != NULL);
+
+ /* 1. Numeric-only name → id derived from name field */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae,
+ "user:1000:rw-p--a-R-c-o-:-------:allow",
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(1,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_next(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(1000, qual);
+ assertEqualString("1000", name);
+ /* Without EXTRA_ID the id is carried by the name string, not :id */
+ text = archive_entry_acl_to_text(ae, &len,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4);
+ assertEqualString("user:1000:rw-p--a-R-c-o-:-------:allow", text);
+ free(text);
+ /* With EXTRA_ID the id is appended */
+ text = archive_entry_acl_to_text(ae, &len,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4 | ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID);
+ assertEqualString("user:1000:rw-p--a-R-c-o-:-------:allow:1000", text);
+ free(text);
+ archive_entry_acl_clear(ae);
+
+ /* 2. Trailing extra-ID field overrides name-derived id */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae,
+ "user:user77:rw-p--a-R-c-o-:-------:allow:42",
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(1,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_next(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(42, qual);
+ assertEqualString("user77", name);
+ archive_entry_acl_clear(ae);
+
+ /* 3. Trailing extra-ID also overrides a numeric name */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae,
+ "user:1000:rw-p--a-R-c-o-:-------:allow:42",
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(1,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_next(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(42, qual);
+ archive_entry_acl_clear(ae);
+
+ /* 4. isint() overflow: extra-ID field too large → entry rejected */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text(ae,
+ "user:name:rw-p--a-R-c-o-:-------:allow:99999999999",
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ archive_entry_acl_clear(ae);
+
+ /* 5. INT_MAX (2147483647) in the extra-ID field → also rejected */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text(ae,
+ "user:name:rw-p--a-R-c-o-:-------:allow:2147483647",
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ archive_entry_acl_clear(ae);
+
+ /* 6. INT_MAX - 1 (2147483646) is the largest accepted id */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae,
+ "user:name:rw-p--a-R-c-o-:-------:allow:2147483646",
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(1,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_next(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(2147483646, qual);
+ archive_entry_acl_clear(ae);
+
+ /* 7. Overflow in the name field (numeric name too large) → rejected */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text(ae,
+ "user:99999999999:rw-p--a-R-c-o-:-------:allow",
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ archive_entry_acl_clear(ae);
+
+ archive_entry_free(ae);
+}
+
+/*
+ * Malformed NFS4 ACL entries — each should return ARCHIVE_WARN without
+ * crashing. Also verifies that valid entries before an invalid one are
+ * still stored.
+ */
+DEFINE_TEST(test_acl_nfs4_text_invalid)
+{
+ struct archive_entry *ae;
+ int type, permset, tag, qual;
+ const char *name;
+
+ ae = archive_entry_new();
+ assert(ae != NULL);
+
+ /* Unknown tag */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text(ae,
+ "bogus:name:rw-p--a-R-c-o-:-------:allow",
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ archive_entry_acl_clear(ae);
+
+ /* Unknown type string */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text(ae,
+ "user:name:rw-p--a-R-c-o-:-------:bogus",
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ archive_entry_acl_clear(ae);
+
+ /* Invalid character in perms field */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text(ae,
+ "user:name:rq-p--a-R-c-o-:-------:allow",
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ archive_entry_acl_clear(ae);
+
+ /* Invalid character in flags field */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text(ae,
+ "user:name:rw-p--a-R-c-o-:q------:allow",
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ archive_entry_acl_clear(ae);
+
+ /* Just a tag with no colon-separated fields */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text(ae, "user",
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ archive_entry_acl_clear(ae);
+
+ /* Valid entry followed by an invalid one: valid entry must be stored
+ * and ARCHIVE_WARN returned (not ARCHIVE_FATAL). */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text(ae,
+ "user:alice:rw-p--a-R-c-o-:-------:allow\n"
+ "bogus:bob:rw-p--a-R-c-o-:-------:deny",
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(1,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_next(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(ARCHIVE_ENTRY_ACL_TYPE_ALLOW, type);
+ assertEqualString("alice", name);
+ archive_entry_acl_clear(ae);
+
+ /* Same tests via the wide parser */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text_w(ae,
+ L"bogus:name:rw-p--a-R-c-o-:-------:allow",
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ archive_entry_acl_clear(ae);
+
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text_w(ae,
+ L"user:name:rw-p--a-R-c-o-:-------:bogus",
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ archive_entry_acl_clear(ae);
+
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text_w(ae,
+ L"user:name:rq-p--a-R-c-o-:-------:allow",
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ archive_entry_acl_clear(ae);
+
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text_w(ae,
+ L"user:name:rw-p--a-R-c-o-:q------:allow",
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ archive_entry_acl_clear(ae);
+
+ archive_entry_free(ae);
+}
diff --git a/contrib/libarchive/libarchive/test/test_acl_posix1e_text.c b/contrib/libarchive/libarchive/test/test_acl_posix1e_text.c
new file mode 100644
index 000000000000..57084465d59e
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_acl_posix1e_text.c
@@ -0,0 +1,530 @@
+/*-
+ * Copyright (c) 2026 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"
+#include <limits.h>
+
+/*
+ * Focused tests for POSIX.1e ACL text parsing and serialization.
+ *
+ * test_acl_text.c covers basic POSIX.1e round-trips but does not exercise:
+ * the mask entry, the Solaris two-field format for mask and other, uppercase
+ * mode letters (R/W/X), isint() overflow on the POSIX path, and various
+ * invalid-input error paths. These tests fill those gaps.
+ *
+ * Note: archive_entry_acl_reset(ae, TYPE_ACCESS) always returns the count
+ * of extended ACL entries PLUS 3 synthesized base entries (USER_OBJ,
+ * GROUP_OBJ, OTHER) derived from the mode bits. Tests below account for
+ * this by adding 3 to the expected count and skipping those 3 entries
+ * before iterating over the named/mask entries of interest.
+ */
+
+/* ACCESS-only ACL including a mask entry. */
+static const char *posix1e_access =
+ "user::rwx\n"
+ "group::r-x\n"
+ "other::r-x\n"
+ "user:alice:r-x\n"
+ "group:staff:rwx\n"
+ "mask::r-x";
+
+/* Combined ACCESS + DEFAULT ACL, with mask in both sections. */
+static const char *posix1e_full =
+ "user::rwx\n"
+ "group::r-x\n"
+ "other::r-x\n"
+ "user:alice:r-x\n"
+ "group:staff:rwx\n"
+ "mask::r-x\n"
+ "default:user::r-x\n"
+ "default:group::r-x\n"
+ "default:other::---\n"
+ "default:user:alice:r-x\n"
+ "default:group:staff:--x\n"
+ "default:mask::r-x";
+
+/* posix1e_full with numeric IDs appended to named user/group entries. */
+static const char *posix1e_extra_id =
+ "user::rwx\n"
+ "group::r-x\n"
+ "other::r-x\n"
+ "user:alice:r-x:77\n"
+ "group:staff:rwx:78\n"
+ "mask::r-x\n"
+ "default:user::r-x\n"
+ "default:group::r-x\n"
+ "default:other::---\n"
+ "default:user:alice:r-x:77\n"
+ "default:group:staff:--x:78\n"
+ "default:mask::r-x";
+
+/*
+ * Solaris-style ACCESS ACL: mask and other use one colon (no empty name
+ * field between tag and permission string).
+ */
+static const char *posix1e_solaris =
+ "user::rwx\n"
+ "group::r-x\n"
+ "other:r-x\n"
+ "user:alice:r-x\n"
+ "mask:r-x";
+
+static wchar_t *
+s_to_ws(const char *s)
+{
+ size_t len = strlen(s) + 1;
+ wchar_t *ws = malloc(len * sizeof(wchar_t));
+ assert(ws != NULL);
+ assert(mbstowcs(ws, s, len) != (size_t)-1);
+ return (ws);
+}
+
+/*
+ * Skip the three base entries (USER_OBJ, GROUP_OBJ, OTHER) that
+ * archive_entry_acl_reset() synthesises from mode bits and that
+ * archive_entry_acl_next() always returns first for ACCESS ACLs.
+ */
+static void
+skip_base_entries(struct archive_entry *ae)
+{
+ int type, permset, tag, qual;
+ const char *name;
+ int i;
+
+ for (i = 0; i < 3; i++)
+ archive_entry_acl_next(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ &type, &permset, &tag, &qual, &name);
+}
+
+/*
+ * Round-trip: parse POSIX.1e text → serialize → compare.
+ * Covers ACCESS-only, combined ACCESS+DEFAULT, and the EXTRA_ID style,
+ * for both the narrow and wide serializers.
+ */
+DEFINE_TEST(test_acl_posix1e_text_roundtrip)
+{
+ struct archive_entry *ae;
+ char *text;
+ wchar_t *wtext, *ws;
+ ssize_t len;
+
+ ae = archive_entry_new();
+ assert(ae != NULL);
+ archive_entry_set_pathname(ae, "file");
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /* ACCESS-only with mask entry */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae, posix1e_access,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ text = archive_entry_acl_to_text(ae, &len,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+ assertEqualString(posix1e_access, text);
+ free(text);
+ archive_entry_acl_clear(ae);
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /* Combined ACCESS + DEFAULT — serializer auto-adds MARK_DEFAULT */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae, posix1e_full,
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
+ text = archive_entry_acl_to_text(ae, &len, 0);
+ assertEqualString(posix1e_full, text);
+ free(text);
+ archive_entry_acl_clear(ae);
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /* EXTRA_ID format */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae, posix1e_extra_id,
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
+ text = archive_entry_acl_to_text(ae, &len,
+ ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID);
+ assertEqualString(posix1e_extra_id, text);
+ free(text);
+ archive_entry_acl_clear(ae);
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /* Wide: ACCESS-only round-trip */
+ ws = s_to_ws(posix1e_access);
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text_w(ae, ws,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ wtext = archive_entry_acl_to_text_w(ae, &len,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+ assertEqualWString(ws, wtext);
+ free(wtext);
+ free(ws);
+ archive_entry_acl_clear(ae);
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /* Wide: combined ACCESS + DEFAULT */
+ ws = s_to_ws(posix1e_full);
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text_w(ae, ws,
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
+ wtext = archive_entry_acl_to_text_w(ae, &len, 0);
+ assertEqualWString(ws, wtext);
+ free(wtext);
+ free(ws);
+
+ archive_entry_free(ae);
+}
+
+/*
+ * Solaris two-field format: "mask:rwx" and "other:rwx" omit the empty
+ * name field, so each has only two colon-separated tokens instead of three.
+ * The parser recognises this form; the serializer reproduces it when
+ * ARCHIVE_ENTRY_ACL_STYLE_SOLARIS is set.
+ */
+DEFINE_TEST(test_acl_posix1e_text_solaris)
+{
+ struct archive_entry *ae;
+ char *text;
+ int type, permset, tag, qual;
+ const char *name;
+ ssize_t len;
+
+ ae = archive_entry_new();
+ assert(ae != NULL);
+ archive_entry_set_pathname(ae, "file");
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /*
+ * Parse Solaris-format text. Extended entries are: named user alice
+ * and mask — 2 extended + 3 base = 5 total.
+ */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae, posix1e_solaris,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ assertEqualInt(5,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ skip_base_entries(ae);
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_next(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(ARCHIVE_ENTRY_ACL_USER, tag);
+ assertEqualString("alice", name);
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_next(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(ARCHIVE_ENTRY_ACL_MASK, tag);
+ assertEqualInt(ARCHIVE_ENTRY_ACL_READ | ARCHIVE_ENTRY_ACL_EXECUTE,
+ permset);
+
+ /* Serialize with STYLE_SOLARIS and compare */
+ text = archive_entry_acl_to_text(ae, &len,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS | ARCHIVE_ENTRY_ACL_STYLE_SOLARIS);
+ assertEqualString(posix1e_solaris, text);
+ free(text);
+ archive_entry_acl_clear(ae);
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /* Solaris style with non-empty name on other field → ARCHIVE_WARN */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text(ae,
+ "user::rwx\ngroup::r-x\nother:nobody:r-x\n",
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ archive_entry_acl_clear(ae);
+
+ archive_entry_free(ae);
+}
+
+/*
+ * ismode() accepts uppercase R, W, X as well as lowercase; the serializer
+ * always emits lowercase. Both narrow and wide parsers share this
+ * behaviour.
+ */
+DEFINE_TEST(test_acl_posix1e_text_ismode)
+{
+ struct archive_entry *ae;
+ char *text;
+ int type, permset, tag, qual;
+ const char *name;
+ ssize_t len;
+
+ ae = archive_entry_new();
+ assert(ae != NULL);
+ archive_entry_set_pathname(ae, "file");
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /*
+ * Uppercase R/W/X treated identically to r/w/x.
+ * 1 extended entry (alice) + 3 base = 4 total.
+ */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae,
+ "user::RWX\ngroup::R-X\nother::---\nuser:alice:RwX",
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ assertEqualInt(4,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ skip_base_entries(ae);
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_next(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(ARCHIVE_ENTRY_ACL_USER, tag);
+ assertEqualString("alice", name);
+ assertEqualInt(
+ ARCHIVE_ENTRY_ACL_READ | ARCHIVE_ENTRY_ACL_WRITE |
+ ARCHIVE_ENTRY_ACL_EXECUTE, permset);
+
+ /* Serializer always emits lowercase */
+ text = archive_entry_acl_to_text(ae, &len,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+ assertEqualString(
+ "user::rwx\ngroup::r-x\nother::---\nuser:alice:rwx", text);
+ free(text);
+ archive_entry_acl_clear(ae);
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /* Same via the wide parser */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text_w(ae,
+ L"user::RWX\ngroup::R-X\nother::---\nuser:alice:RwX",
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ assertEqualInt(4,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ skip_base_entries(ae);
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_next(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(
+ ARCHIVE_ENTRY_ACL_READ | ARCHIVE_ENTRY_ACL_WRITE |
+ ARCHIVE_ENTRY_ACL_EXECUTE, permset);
+
+ archive_entry_free(ae);
+}
+
+/*
+ * Numeric IDs in the name field and the extra-ID override field,
+ * including the isint() overflow boundary now enforced on the POSIX path.
+ */
+DEFINE_TEST(test_acl_posix1e_text_numeric_id)
+{
+ struct archive_entry *ae;
+ char *text;
+ ssize_t len;
+ int type, permset, tag, qual;
+ const char *name;
+
+ ae = archive_entry_new();
+ assert(ae != NULL);
+ archive_entry_set_pathname(ae, "file");
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /* 1. Numeric-only name → id derived from name field */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae,
+ "user::rwx\ngroup::r-x\nother::r-x\nuser:1000:rwx",
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ /* 1 extended + 3 base = 4 */
+ assertEqualInt(4,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ skip_base_entries(ae);
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_next(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(1000, qual);
+ assertEqualString("1000", name);
+ /* Without EXTRA_ID the id is carried by the name string */
+ text = archive_entry_acl_to_text(ae, &len,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+ assert(strstr(text, "user:1000:rwx") != NULL);
+ free(text);
+ /* With EXTRA_ID the id is also appended */
+ text = archive_entry_acl_to_text(ae, &len,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS | ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID);
+ assert(strstr(text, "user:1000:rwx:1000") != NULL);
+ free(text);
+ archive_entry_acl_clear(ae);
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /* 2. Trailing extra-ID field overrides name-derived id */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae,
+ "user::rwx\ngroup::r-x\nother::r-x\nuser:alice:r-x:42",
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ assertEqualInt(4,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ skip_base_entries(ae);
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_next(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(42, qual);
+ assertEqualString("alice", name);
+ archive_entry_acl_clear(ae);
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /* 3. Overflow in extra-ID field → extended entry rejected, no ext entries */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text(ae,
+ "user::rwx\ngroup::r-x\nother::r-x\nuser:alice:r-x:99999999999",
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ archive_entry_acl_clear(ae);
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /* 4. INT_MAX (2147483647) in the extra-ID field → also rejected */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text(ae,
+ "user::rwx\ngroup::r-x\nother::r-x\nuser:alice:r-x:2147483647",
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ archive_entry_acl_clear(ae);
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /* 5. INT_MAX - 1 (2147483646) is the largest accepted id */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae,
+ "user::rwx\ngroup::r-x\nother::r-x\nuser:alice:r-x:2147483646",
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ assertEqualInt(4,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ skip_base_entries(ae);
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_next(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(2147483646, qual);
+ archive_entry_acl_clear(ae);
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /* 6. Overflow in the name field (all-digit name too large) → rejected */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text(ae,
+ "user::rwx\ngroup::r-x\nother::r-x\nuser:99999999999:r-x",
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ archive_entry_acl_clear(ae);
+
+ archive_entry_free(ae);
+}
+
+/*
+ * Malformed POSIX.1e ACL entries — each should return ARCHIVE_WARN without
+ * crashing and without storing invalid data.
+ */
+DEFINE_TEST(test_acl_posix1e_text_invalid)
+{
+ struct archive_entry *ae;
+ int type, permset, tag, qual;
+ const char *name;
+
+ ae = archive_entry_new();
+ assert(ae != NULL);
+ archive_entry_set_pathname(ae, "file");
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /* Invalid character in permission field */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text(ae,
+ "user:alice:rqx",
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ archive_entry_acl_clear(ae);
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /* Unknown tag */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text(ae,
+ "bogus:alice:rwx",
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ archive_entry_acl_clear(ae);
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /* NFSv4 "everyone@" tag is not recognised by the POSIX parser */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text(ae,
+ "everyone@:r-----a-R-c--s:-------:allow",
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ archive_entry_acl_clear(ae);
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /* Bare tag with no colon-separated fields */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text(ae, "user",
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ archive_entry_acl_clear(ae);
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /*
+ * Valid entry followed by invalid — valid entry must be stored.
+ * 1 extended (alice) + 3 base = 4 total.
+ */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text(ae,
+ "user::rwx\ngroup::r-x\nother::r-x\n"
+ "user:alice:r-x\n"
+ "bogus:bob:rwx",
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ assertEqualInt(4,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ skip_base_entries(ae);
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_next(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(ARCHIVE_ENTRY_ACL_USER, tag);
+ assertEqualString("alice", name);
+ archive_entry_acl_clear(ae);
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /* Wide parser: invalid permission character */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text_w(ae,
+ L"user:alice:rqx",
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ archive_entry_acl_clear(ae);
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /* Wide parser: unknown tag */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text_w(ae,
+ L"bogus:alice:rwx",
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ archive_entry_acl_clear(ae);
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+
+ /* Wide parser: NFSv4 tag rejected by POSIX parser */
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_acl_from_text_w(ae,
+ L"everyone@:r-----a-R-c--s:-------:allow",
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ assertEqualInt(0,
+ archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+
+ archive_entry_free(ae);
+}
diff --git a/contrib/libarchive/libarchive/test/test_archive_match_path.c b/contrib/libarchive/libarchive/test/test_archive_match_path.c
index ce48263f7614..527413db7992 100644
--- a/contrib/libarchive/libarchive/test/test_archive_match_path.c
+++ b/contrib/libarchive/libarchive/test/test_archive_match_path.c
@@ -233,8 +233,8 @@ test_inclusion_mbs(void)
return;
}
- /* Test for pattern "^aa*" */
- assertEqualIntA(m, 0, archive_match_include_pattern(m, "^aa*"));
+ /* Test for pattern "aa*" */
+ assertEqualIntA(m, 0, archive_match_include_pattern(m, "aa*"));
/* Test with 'aa1234', which should not be excluded. */
archive_entry_copy_pathname(ae, "aa1234");
@@ -282,8 +282,8 @@ test_inclusion_wcs(void)
return;
}
- /* Test for pattern "^aa*" */
- assertEqualIntA(m, 0, archive_match_include_pattern_w(m, L"^aa*"));
+ /* Test for pattern "aa*" */
+ assertEqualIntA(m, 0, archive_match_include_pattern_w(m, L"aa*"));
/* Test with 'aa1234', which should not be excluded. */
archive_entry_copy_pathname(ae, "aa1234");
@@ -383,8 +383,8 @@ test_exclusion_and_inclusion(void)
}
assertEqualIntA(m, 0, archive_match_exclude_pattern(m, "^aaa*"));
- assertEqualIntA(m, 0, archive_match_include_pattern_w(m, L"^aa*"));
- assertEqualIntA(m, 0, archive_match_include_pattern(m, "^a1*"));
+ assertEqualIntA(m, 0, archive_match_include_pattern_w(m, L"aa*"));
+ assertEqualIntA(m, 0, archive_match_include_pattern(m, "a1*"));
/* Test with 'aa1234', which should not be excluded. */
archive_entry_copy_pathname(ae, "aa1234");
@@ -413,13 +413,13 @@ test_exclusion_and_inclusion(void)
/* Verify unmatched inclusion patterns. */
assertEqualIntA(m, ARCHIVE_OK,
archive_match_path_unmatched_inclusions_next(m, &mp));
- assertEqualString("^a1*", mp);
+ assertEqualString("a1*", mp);
assertEqualIntA(m, ARCHIVE_EOF,
archive_match_path_unmatched_inclusions_next(m, &mp));
/* Verify unmatched inclusion patterns again in Wide-Char. */
assertEqualIntA(m, ARCHIVE_OK,
archive_match_path_unmatched_inclusions_next_w(m, &wp));
- assertEqualWString(L"^a1*", wp);
+ assertEqualWString(L"a1*", wp);
assertEqualIntA(m, ARCHIVE_EOF,
archive_match_path_unmatched_inclusions_next_w(m, &wp));
diff --git a/contrib/libarchive/libarchive/test/test_archive_parse_date.c b/contrib/libarchive/libarchive/test/test_archive_parse_date.c
index 5251b3393999..03e628913633 100644
--- a/contrib/libarchive/libarchive/test/test_archive_parse_date.c
+++ b/contrib/libarchive/libarchive/test/test_archive_parse_date.c
@@ -35,65 +35,72 @@
DEFINE_TEST(test_archive_parse_date)
{
time_t now = time(NULL);
+ long long expected;
- assertEqualInt(get_date(now, "Jan 1, 1970 UTC"), 0);
- assertEqualInt(get_date(now, "7:12:18-0530 4 May 1983"), 420900138);
- assertEqualInt(get_date(now, "2004/01/29 513 mest"), 1075345980);
- assertEqualInt(get_date(now, "2038-06-01 00:01:02 UTC"),
+ assertEqualInt(archive_parse_date(now, "Jan 1, 1970 UTC"), 0);
+ assertEqualInt(archive_parse_date(now, "7:12:18-0530 4 May 1983"), 420900138);
+ assertEqualInt(archive_parse_date(now, "2004/01/29 513 mest"), 1075345980);
+ assertEqualInt(archive_parse_date(now, "2038-06-01 00:01:02 UTC"),
sizeof(time_t) <= 4 ? -1 : 2158963262);
- assertEqualInt(get_date(now, "99/02/17 7pm utc"), 919278000);
- assertEqualInt(get_date(now, "02/17/99 7:11am est"), 919253460);
- assertEqualInt(get_date(now, "now - 2 hours"),
- get_date(now, "2 hours ago"));
- assertEqualInt(get_date(now, "2 hours ago"),
- get_date(now, "+2 hours ago"));
- assertEqualInt(get_date(now, "now - 2 hours"),
- get_date(now, "-2 hours"));
+ assertEqualInt(archive_parse_date(now, "99/02/17 7pm utc"), 919278000);
+ assertEqualInt(archive_parse_date(now, "02/17/99 7:11am est"), 919253460);
+ assertEqualInt(archive_parse_date(now, "now - 2 hours"),
+ archive_parse_date(now, "2 hours ago"));
+ assertEqualInt(archive_parse_date(now, "2 hours ago"),
+ archive_parse_date(now, "+2 hours ago"));
+ assertEqualInt(archive_parse_date(now, "now - 2 hours"),
+ archive_parse_date(now, "-2 hours"));
/* It's important that we handle ctime() format. */
- assertEqualInt(get_date(now, "Sun Feb 22 17:38:26 PST 2009"),
+ assertEqualInt(archive_parse_date(now, "Sun Feb 22 17:38:26 PST 2009"),
1235353106);
/* Basic relative offsets. */
/* If we use the actual current time as the reference, then
* these tests break around DST changes, so it's actually
* important to use a specific reference time here. */
- assertEqualInt(get_date(0, "tomorrow"), 24 * 60 * 60);
- assertEqualInt(get_date(0, "yesterday"), - 24 * 60 * 60);
- assertEqualInt(get_date(0, "now + 1 hour"), 60 * 60);
- assertEqualInt(get_date(0, "now + 1 hour + 1 minute"), 60 * 60 + 60);
+ assertEqualInt(archive_parse_date(0, "tomorrow"), 24 * 60 * 60);
+ assertEqualInt(archive_parse_date(0, "yesterday"), - 24 * 60 * 60);
+ assertEqualInt(archive_parse_date(0, "now + 1 hour"), 60 * 60);
+ assertEqualInt(archive_parse_date(0, "now + 1 hour + 1 minute"), 60 * 60 + 60);
/* Repeat the above for a different start time. */
now = 1231113600; /* Jan 5, 2009 00:00 UTC */
- assertEqualInt(get_date(0, "Jan 5, 2009 00:00 UTC"), now);
- assertEqualInt(get_date(now, "tomorrow"), now + 24 * 60 * 60);
- assertEqualInt(get_date(now, "yesterday"), now - 24 * 60 * 60);
- assertEqualInt(get_date(now, "now + 1 hour"), now + 60 * 60);
- assertEqualInt(get_date(now, "now + 1 hour + 1 minute"),
+ assertEqualInt(archive_parse_date(0, "Jan 5, 2009 00:00 UTC"), now);
+ assertEqualInt(archive_parse_date(now, "tomorrow"), now + 24 * 60 * 60);
+ assertEqualInt(archive_parse_date(now, "yesterday"), now - 24 * 60 * 60);
+ assertEqualInt(archive_parse_date(now, "now + 1 hour"), now + 60 * 60);
+ assertEqualInt(archive_parse_date(now, "now + 1 hour + 1 minute"),
now + 60 * 60 + 60);
- assertEqualInt(get_date(now, "tomorrow 5:16am UTC"),
+ assertEqualInt(archive_parse_date(now, "tomorrow 5:16am UTC"),
now + 24 * 60 * 60 + 5 * 60 * 60 + 16 * 60);
- assertEqualInt(get_date(now, "UTC 5:16am tomorrow"),
+ assertEqualInt(archive_parse_date(now, "UTC 5:16am tomorrow"),
now + 24 * 60 * 60 + 5 * 60 * 60 + 16 * 60);
/* Jan 5, 2009 was a Monday. */
- assertEqualInt(get_date(now, "monday UTC"), now);
- assertEqualInt(get_date(now, "sunday UTC"), now + 6 * 24 * 60 * 60);
- assertEqualInt(get_date(now, "tuesday UTC"), now + 24 * 60 * 60);
+ assertEqualInt(archive_parse_date(now, "monday UTC"), now);
+ assertEqualInt(archive_parse_date(now, "sunday UTC"), now + 6 * 24 * 60 * 60);
+ assertEqualInt(archive_parse_date(now, "tuesday UTC"), now + 24 * 60 * 60);
/* "next tuesday" is one week after "tuesday" */
- assertEqualInt(get_date(now, "UTC next tuesday"),
+ assertEqualInt(archive_parse_date(now, "UTC next tuesday"),
now + 8 * 24 * 60 * 60);
/* "last tuesday" is one week before "tuesday" */
- assertEqualInt(get_date(now, "last tuesday UTC"),
+ assertEqualInt(archive_parse_date(now, "last tuesday UTC"),
now - 6 * 24 * 60 * 60);
/* Unix epoch timestamps */
- assertEqualInt(get_date(now, "@0"), 0);
- assertEqualInt(get_date(now, "@100"), 100);
- assertEqualInt(get_date(now, "@+100"), 100);
+ assertEqualInt(archive_parse_date(now, "@0"), 0);
+ assertEqualInt(archive_parse_date(now, "@100"), 100);
+ assertEqualInt(archive_parse_date(now, "@1000000000"), 1000000000);
+ assertEqualInt(archive_parse_date(now, "@+100"), 100);
- assertEqualInt(get_date(now, "@"), -1);
- assertEqualInt(get_date(now, "@-"), -1);
- assertEqualInt(get_date(now, "@+"), -1);
- assertEqualInt(get_date(now, "@tenth"), -1);
- assertEqualInt(get_date(now, "@100 tomorrow"), -1);
+ assertEqualInt(archive_parse_date(now, "@"), -1);
+ assertEqualInt(archive_parse_date(now, "@-"), -1);
+ assertEqualInt(archive_parse_date(now, "@+"), -1);
+ assertEqualInt(archive_parse_date(now, "@tenth"), -1);
+ assertEqualInt(archive_parse_date(now, "@100 tomorrow"), -1);
- /* TODO: Lots more tests here. */
+ /* Verify handling of overlarge numbers */
+ expected = sizeof(time_t) == 4 ? -1 : 253375948800LL;
+ assertEqualInt(archive_parse_date(now, "Jan 1, 9999 UTC"), expected);
+ assertEqualInt(archive_parse_date(now, "Jan 1, 10000 UTC"), -1);
+ assertEqualInt(archive_parse_date(now, "Jan 1, 99999 UTC"), -1);
+ assertEqualInt(archive_parse_date(time(NULL), "2147483647-01-01 00:00:00"), -1);
}
diff --git a/contrib/libarchive/libarchive/test/test_archive_pathmatch.c b/contrib/libarchive/libarchive/test/test_archive_pathmatch.c
index 3b212aca9d94..ea75851dbe64 100644
--- a/contrib/libarchive/libarchive/test/test_archive_pathmatch.c
+++ b/contrib/libarchive/libarchive/test/test_archive_pathmatch.c
@@ -56,6 +56,10 @@ DEFINE_TEST(test_archive_pathmatch)
assertEqualInt(0, archive_pathmatch_w(L"a/b/c", NULL, 0));
/* Empty pattern only matches empty string. */
+ assertEqualInt(1, archive_pathmatch(NULL,NULL, 0));
+ assertEqualInt(1, archive_pathmatch(NULL,"", 0));
+ assertEqualInt(0, archive_pathmatch(NULL,"a", 0));
+ assertEqualInt(1, archive_pathmatch("",NULL, 0));
assertEqualInt(1, archive_pathmatch("","", 0));
assertEqualInt(0, archive_pathmatch("","a", 0));
assertEqualInt(1, archive_pathmatch("*","", 0));
@@ -76,11 +80,15 @@ DEFINE_TEST(test_archive_pathmatch)
assertEqualInt(0, archive_pathmatch("a", "ab", 0));
assertEqualInt(0, archive_pathmatch("a", "ab", 0));
assertEqualInt(1, archive_pathmatch("a?c", "abc", 0));
+ assertEqualInt(1, archive_pathmatch("*a", "/a", 0));
+ assertEqualInt(1, archive_pathmatch("*a", "a", 0));
/* SUSv2: ? matches / */
assertEqualInt(1, archive_pathmatch("a?c", "a/c", 0));
assertEqualInt(1, archive_pathmatch("a?*c*", "a/c", 0));
assertEqualInt(1, archive_pathmatch("*a*", "a/c", 0));
assertEqualInt(1, archive_pathmatch("*a*", "/a/c", 0));
+ assertEqualInt(0, archive_pathmatch("*a", "/a/c", 0));
+ assertEqualInt(0, archive_pathmatch("*a", "a/c", 0));
assertEqualInt(1, archive_pathmatch("*a*", "defaaaaaaa", 0));
assertEqualInt(0, archive_pathmatch("a*", "defghi", 0));
assertEqualInt(0, archive_pathmatch("*a*", "defghi", 0));
@@ -201,6 +209,14 @@ DEFINE_TEST(test_archive_pathmatch)
failure("Trailing '/.' is still the same directory.");
assertEqualInt(1, archive_pathmatch("./abc*/./def", "abc/def/.", 0));
+ /* Anchor characters without flags not special. */
+ assertEqualInt(0, archive_pathmatch("^abc", "abc", 0));
+ assertEqualInt(1, archive_pathmatch("^abc", "^abc", 0));
+ assertEqualInt(0, archive_pathmatch("abc$", "abc", 0));
+ assertEqualInt(1, archive_pathmatch("abc$", "abc$", 0));
+ assertEqualInt(0, archive_pathmatch("^abc$", "abc", 0));
+ assertEqualInt(1, archive_pathmatch("^abc$", "^abc$", 0));
+
/* Matches not anchored at beginning. */
assertEqualInt(0,
archive_pathmatch("bcd", "abcd", PATHMATCH_NO_ANCHOR_START));
diff --git a/contrib/libarchive/libarchive/test/test_archive_pathmatch_oob.c b/contrib/libarchive/libarchive/test/test_archive_pathmatch_oob.c
new file mode 100644
index 000000000000..a3885e44447d
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_archive_pathmatch_oob.c
@@ -0,0 +1,156 @@
+/*-
+ * Copyright (c) 2025 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"
+
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+/*
+ * Regression test: malformed bracket expressions in patterns caused
+ * heap-buffer-overflow reads in pm() (BUG-003) and strchr OOB via
+ * archive_match (BUG-007).
+ *
+ * To reproduce under ASan, we must allocate tight heap buffers for the
+ * pattern and string (just like the fuzzer does), so that ASan's
+ * redzones detect overreads.
+ */
+
+/* Declare the internal functions we want to test. */
+int __archive_pathmatch(const char *pattern, const char *string, int flags);
+int __archive_pathmatch_w(const wchar_t *pattern, const wchar_t *string,
+ int flags);
+
+/*
+ * Replay a fuzzer repro file through __archive_pathmatch().
+ * Format: byte 0 = flags, then rest is split at first '\0' into
+ * pattern and string, each copied into tight malloc'd buffers.
+ */
+static void
+replay_pathmatch_repro(const char *refname)
+{
+ FILE *f;
+ unsigned char buf[4096];
+ size_t size, split, rest_len, str_start, str_len;
+ const unsigned char *rest;
+ char *pattern, *string;
+ int flags;
+ size_t i;
+
+ extract_reference_file(refname);
+
+ f = fopen(refname, "rb");
+ if (!assert(f != NULL))
+ return;
+ size = fread(buf, 1, sizeof(buf), f);
+ fclose(f);
+ if (!assert(size >= 4))
+ return;
+
+ flags = buf[0] % 8;
+ rest = buf + 1;
+ rest_len = size - 1;
+
+ /* Find split point (first null byte in rest). */
+ split = 0;
+ for (i = 0; i < rest_len; i++) {
+ if (rest[i] == 0) {
+ split = i;
+ break;
+ }
+ }
+ if (split == 0)
+ split = rest_len / 2;
+
+ /* Allocate tight buffers so ASan can detect overreads. */
+ pattern = (char *)malloc(split + 1);
+ if (!assert(pattern != NULL))
+ return;
+ memcpy(pattern, rest, split);
+ pattern[split] = '\0';
+
+ str_start = (split < rest_len && rest[split] == 0)
+ ? split + 1 : split;
+ str_len = rest_len - str_start;
+ string = (char *)malloc(str_len + 1);
+ if (!assert(string != NULL)) {
+ free(pattern);
+ return;
+ }
+ memcpy(string, rest + str_start, str_len);
+ string[str_len] = '\0';
+
+ /* This must not read past the allocated buffers. */
+ __archive_pathmatch(pattern, string, flags);
+
+ free(pattern);
+ free(string);
+}
+
+DEFINE_TEST(test_archive_pathmatch_oob_bracket)
+{
+ replay_pathmatch_repro("test_archive_pathmatch_oob_bracket.bin");
+}
+
+DEFINE_TEST(test_archive_pathmatch_oob_strchr)
+{
+ replay_pathmatch_repro("test_archive_pathmatch_oob_strchr.bin");
+}
+
+/*
+ * Wide-character twin of the bracket over-read. pm_w() matched a [...]
+ * class without first checking whether the subject string was already
+ * exhausted, so a negated class ([!...]/[^...]) at end-of-string reported
+ * a match and advanced the subject pointer past its terminator. Allocate
+ * tight wide buffers so ASan's redzones catch the over-read.
+ */
+static void
+check_pathmatch_w_oob(const wchar_t *pat, const wchar_t *str, int flags)
+{
+ size_t plen = wcslen(pat) + 1;
+ size_t slen = wcslen(str) + 1;
+ wchar_t *pattern = (wchar_t *)malloc(plen * sizeof(wchar_t));
+ wchar_t *string = (wchar_t *)malloc(slen * sizeof(wchar_t));
+
+ if (assert(pattern != NULL) && assert(string != NULL)) {
+ wmemcpy(pattern, pat, plen);
+ wmemcpy(string, str, slen);
+ /* This must not read past the allocated buffers. */
+ __archive_pathmatch_w(pattern, string, flags);
+ }
+ free(pattern);
+ free(string);
+}
+
+DEFINE_TEST(test_archive_pathmatch_oob_bracket_w)
+{
+ /* PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END, as used by
+ * archive_match() exclusion patterns. */
+ int flags = 1 | 2;
+
+ check_pathmatch_w_oob(L"abc[!x]", L"abc", flags);
+ check_pathmatch_w_oob(L"[!a]", L"", flags);
+ check_pathmatch_w_oob(L"[^a]", L"", flags);
+}
diff --git a/contrib/libarchive/libarchive/test/test_archive_pathmatch_oob_bracket.bin.uu b/contrib/libarchive/libarchive/test/test_archive_pathmatch_oob_bracket.bin.uu
new file mode 100644
index 000000000000..5984a0d34c94
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_archive_pathmatch_oob_bracket.bin.uu
@@ -0,0 +1,4 @@
+begin 644 test_archive_pathmatch_oob_bracket.bin
+,6ULAC"&,*HPJ73\`
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_archive_pathmatch_oob_strchr.bin.uu b/contrib/libarchive/libarchive/test/test_archive_pathmatch_oob_strchr.bin.uu
new file mode 100644
index 000000000000..b961b0a08827
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_archive_pathmatch_oob_strchr.bin.uu
@@ -0,0 +1,8 @@
+begin 644 test_archive_pathmatch_oob_strchr.bin
+M`2H_*C];(0(M7%@K,`+;725S871U<F1A>5SX*@`!*ELI+2]=`0!A$``!9(`!
+M*BI;(0(J72KEY>7EY>7EY>7EY>7EY>7EY>7EY>7EY>7EY>7EY>7EY>7EY>7E
+MY>7EY>7EY>7EY>7EY>7EY>7EY>7EY>7EY>7EY>4``0@"`0`0&@``*@`J*BH`
+M`2HJ*@``)```&P`!*"HJ``$`"#\D```J`"JJ``(`T@(J*@`#`"H``2HJ*@`!
+'*@"3`5L``@``
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_archive_read_close_twice.c b/contrib/libarchive/libarchive/test/test_archive_read_close_twice.c
index 2f5ee77f117e..5f5beb01db9b 100644
--- a/contrib/libarchive/libarchive/test/test_archive_read_close_twice.c
+++ b/contrib/libarchive/libarchive/test/test_archive_read_close_twice.c
@@ -29,13 +29,55 @@ DEFINE_TEST(test_archive_read_close_twice)
{
struct archive* a = archive_read_new();
- assertEqualInt(0, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(0, archive_errno(a));
assertEqualString(NULL, archive_error_string(a));
- assertEqualInt(0, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(0, archive_errno(a));
assertEqualString(NULL, archive_error_string(a));
archive_read_free(a);
}
+
+DEFINE_TEST(test_archive_read_close_twice_open_fd)
+{
+ struct archive* a = archive_read_new();
+
+ assertEqualInt(ARCHIVE_OK, archive_read_support_format_empty(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_open_fd(a, 0, 0));
+ assertEqualInt(0, archive_errno(a));
+ assertEqualString(NULL, archive_error_string(a));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(0, archive_errno(a));
+ assertEqualString(NULL, archive_error_string(a));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(0, archive_errno(a));
+ assertEqualString(NULL, archive_error_string(a));
+
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
+DEFINE_TEST(test_archive_read_close_twice_open_filename)
+{
+ const char *filename = "empty.file";
+ struct archive* a = archive_read_new();
+
+ assertMakeFile(filename, 0644, "");
+ assertEqualInt(ARCHIVE_OK, archive_read_support_format_empty(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_open_filename(a, filename, 0));
+ assertEqualInt(0, archive_errno(a));
+ assertEqualString(NULL, archive_error_string(a));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(0, archive_errno(a));
+ assertEqualString(NULL, archive_error_string(a));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(0, archive_errno(a));
+ assertEqualString(NULL, archive_error_string(a));
+
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/contrib/libarchive/libarchive/test/test_archive_read_set_option.c b/contrib/libarchive/libarchive/test/test_archive_read_set_option.c
deleted file mode 100644
index 195c1eaa3e13..000000000000
--- a/contrib/libarchive/libarchive/test/test_archive_read_set_option.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*-
- * Copyright (c) 2011 Tim Kientzle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "test.h"
-
-#define should(__a, __code, __m, __o, __v) \
-assertEqualInt(__code, archive_read_set_option(__a, __m, __o, __v))
-
-static void
-test(int pristine)
-{
- struct archive* a = archive_read_new();
- int known_option_rv = pristine ? ARCHIVE_FAILED : ARCHIVE_OK;
-
- if (!pristine) {
- archive_read_support_filter_all(a);
- archive_read_support_format_all(a);
- }
-
- /* NULL and "" denote `no option', so they're ok no matter
- * what, if any, formats are registered */
- should(a, ARCHIVE_OK, NULL, NULL, NULL);
- should(a, ARCHIVE_OK, "", "", "");
-
- /* unknown modules and options */
- should(a, ARCHIVE_FAILED, "fubar", "snafu", NULL);
- should(a, ARCHIVE_FAILED, "fubar", "snafu", "betcha");
-
- /* unknown modules and options */
- should(a, ARCHIVE_FAILED, NULL, "snafu", NULL);
- should(a, ARCHIVE_FAILED, NULL, "snafu", "betcha");
-
- /* ARCHIVE_OK with iso9660 loaded, ARCHIVE_WARN otherwise */
- should(a, known_option_rv, "iso9660", "joliet", NULL);
- should(a, known_option_rv, "iso9660", "joliet", NULL);
- should(a, known_option_rv, NULL, "joliet", NULL);
- should(a, known_option_rv, NULL, "joliet", NULL);
-
- archive_read_free(a);
-}
-
-DEFINE_TEST(test_archive_read_set_option)
-{
- test(1);
- test(0);
-}
diff --git a/contrib/libarchive/libarchive/test/test_archive_read_set_options.c b/contrib/libarchive/libarchive/test/test_archive_read_set_options.c
index 2f1f344eaad3..4405be8f96eb 100644
--- a/contrib/libarchive/libarchive/test/test_archive_read_set_options.c
+++ b/contrib/libarchive/libarchive/test/test_archive_read_set_options.c
@@ -25,11 +25,121 @@
#include "test.h"
-#define should(__a, __code, __opts) \
+#define should_read_set_filter_option(__a, __code, __m, __o, __v) \
+assertEqualInt(__code, archive_read_set_filter_option(__a, __m, __o, __v))
+
+static void
+read_set_filter_option_test(int pristine)
+{
+ struct archive* a = archive_read_new();
+
+ if (!pristine)
+ archive_read_support_filter_all(a);
+
+ should_read_set_filter_option(a, ARCHIVE_OK, NULL, NULL, NULL);
+ should_read_set_filter_option(a, ARCHIVE_OK, "", "", "");
+
+ should_read_set_filter_option(a, ARCHIVE_FAILED, NULL, "fubar", NULL);
+ should_read_set_filter_option(a, ARCHIVE_FAILED, NULL, "fubar", "snafu");
+ should_read_set_filter_option(a, ARCHIVE_FAILED, "fubar", "snafu", NULL);
+ should_read_set_filter_option(a, ARCHIVE_FAILED, "fubar", "snafu", "betcha");
+
+ archive_read_free(a);
+}
+
+DEFINE_TEST(test_archive_read_set_filter_option)
+{
+ read_set_filter_option_test(1);
+ read_set_filter_option_test(0);
+}
+
+#define should_read_set_format_option(__a, __code, __m, __o, __v) \
+assertEqualInt(__code, archive_read_set_format_option(__a, __m, __o, __v))
+
+static void
+read_set_format_option_test(int pristine)
+{
+ struct archive* a = archive_read_new();
+ int known_option_rv = pristine ? ARCHIVE_FAILED : ARCHIVE_OK;
+
+ if (!pristine)
+ archive_read_support_format_all(a);
+
+ /* NULL and "" denote `no option', so they're ok no matter
+ * what, if any, formats are registered */
+ should_read_set_format_option(a, ARCHIVE_OK, NULL, NULL, NULL);
+ should_read_set_format_option(a, ARCHIVE_OK, "", "", "");
+
+ /* unknown modules and options */
+ should_read_set_format_option(a, ARCHIVE_FAILED, "fubar", "snafu", NULL);
+ should_read_set_format_option(a, ARCHIVE_FAILED, "fubar", "snafu", "betcha");
+
+ /* unknown modules and options */
+ should_read_set_format_option(a, ARCHIVE_FAILED, NULL, "snafu", NULL);
+ should_read_set_format_option(a, ARCHIVE_FAILED, NULL, "snafu", "betcha");
+
+ /* ARCHIVE_OK with iso9660 loaded, ARCHIVE_WARN otherwise */
+ should_read_set_format_option(a, known_option_rv, "iso9660", "joliet", NULL);
+ should_read_set_format_option(a, known_option_rv, "iso9660", "joliet", NULL);
+ should_read_set_format_option(a, known_option_rv, NULL, "joliet", NULL);
+ should_read_set_format_option(a, known_option_rv, NULL, "joliet", NULL);
+
+ archive_read_free(a);
+}
+
+DEFINE_TEST(test_archive_read_set_format_option)
+{
+ read_set_format_option_test(1);
+ read_set_format_option_test(0);
+}
+
+#define should_read_set_option(__a, __code, __m, __o, __v) \
+assertEqualInt(__code, archive_read_set_option(__a, __m, __o, __v))
+
+static void
+read_set_option_test(int pristine)
+{
+ struct archive* a = archive_read_new();
+ int known_option_rv = pristine ? ARCHIVE_FAILED : ARCHIVE_OK;
+
+ if (!pristine) {
+ archive_read_support_filter_all(a);
+ archive_read_support_format_all(a);
+ }
+
+ /* NULL and "" denote `no option', so they're ok no matter
+ * what, if any, formats are registered */
+ should_read_set_option(a, ARCHIVE_OK, NULL, NULL, NULL);
+ should_read_set_option(a, ARCHIVE_OK, "", "", "");
+
+ /* unknown modules and options */
+ should_read_set_option(a, ARCHIVE_FAILED, "fubar", "snafu", NULL);
+ should_read_set_option(a, ARCHIVE_FAILED, "fubar", "snafu", "betcha");
+
+ /* unknown modules and options */
+ should_read_set_option(a, ARCHIVE_FAILED, NULL, "snafu", NULL);
+ should_read_set_option(a, ARCHIVE_FAILED, NULL, "snafu", "betcha");
+
+ /* ARCHIVE_OK with iso9660 loaded, ARCHIVE_WARN otherwise */
+ should_read_set_option(a, known_option_rv, "iso9660", "joliet", NULL);
+ should_read_set_option(a, known_option_rv, "iso9660", "joliet", NULL);
+ should_read_set_option(a, known_option_rv, NULL, "joliet", NULL);
+ should_read_set_option(a, known_option_rv, NULL, "joliet", NULL);
+
+ archive_read_free(a);
+}
+
+DEFINE_TEST(test_archive_read_set_option)
+{
+ read_set_option_test(1);
+ read_set_option_test(0);
+}
+
+#define should_read_set_options(__a, __code, __opts) \
assertEqualInt(__code, archive_read_set_options(__a, __opts))
static void
-test(int pristine)
+read_set_options_test(int pristine)
{
struct archive* a = archive_read_new();
int halfempty_options_rv = pristine ? ARCHIVE_FAILED : ARCHIVE_OK;
@@ -42,62 +152,62 @@ test(int pristine)
/* NULL and "" denote `no option', so they're ok no matter
* what, if any, formats are registered */
- should(a, ARCHIVE_OK, NULL);
- should(a, ARCHIVE_OK, "");
+ should_read_set_options(a, ARCHIVE_OK, NULL);
+ should_read_set_options(a, ARCHIVE_OK, "");
/* unknown modules and options */
- should(a, ARCHIVE_FAILED, "fubar:snafu");
+ should_read_set_options(a, ARCHIVE_FAILED, "fubar:snafu");
assertEqualString("Unknown module name: `fubar'",
archive_error_string(a));
- should(a, ARCHIVE_FAILED, "fubar:snafu=betcha");
+ should_read_set_options(a, ARCHIVE_FAILED, "fubar:snafu=betcha");
assertEqualString("Unknown module name: `fubar'",
archive_error_string(a));
/* unknown modules and options */
- should(a, ARCHIVE_FAILED, "snafu");
+ should_read_set_options(a, ARCHIVE_FAILED, "snafu");
assertEqualString("Undefined option: `snafu'",
archive_error_string(a));
- should(a, ARCHIVE_FAILED, "snafu=betcha");
+ should_read_set_options(a, ARCHIVE_FAILED, "snafu=betcha");
assertEqualString("Undefined option: `snafu'",
archive_error_string(a));
/* ARCHIVE_OK with iso9660 loaded, ARCHIVE_FAILED otherwise */
- should(a, known_option_rv, "iso9660:joliet");
+ should_read_set_options(a, known_option_rv, "iso9660:joliet");
if (pristine) {
assertEqualString("Unknown module name: `iso9660'",
archive_error_string(a));
}
- should(a, known_option_rv, "iso9660:joliet");
+ should_read_set_options(a, known_option_rv, "iso9660:joliet");
if (pristine) {
assertEqualString("Unknown module name: `iso9660'",
archive_error_string(a));
}
- should(a, known_option_rv, "joliet");
+ should_read_set_options(a, known_option_rv, "joliet");
if (pristine) {
assertEqualString("Undefined option: `joliet'",
archive_error_string(a));
}
- should(a, known_option_rv, "!joliet");
+ should_read_set_options(a, known_option_rv, "!joliet");
if (pristine) {
assertEqualString("Undefined option: `joliet'",
archive_error_string(a));
}
- should(a, ARCHIVE_OK, ",");
- should(a, ARCHIVE_OK, ",,");
+ should_read_set_options(a, ARCHIVE_OK, ",");
+ should_read_set_options(a, ARCHIVE_OK, ",,");
- should(a, halfempty_options_rv, ",joliet");
+ should_read_set_options(a, halfempty_options_rv, ",joliet");
if (pristine) {
assertEqualString("Undefined option: `joliet'",
archive_error_string(a));
}
- should(a, halfempty_options_rv, "joliet,");
+ should_read_set_options(a, halfempty_options_rv, "joliet,");
if (pristine) {
assertEqualString("Undefined option: `joliet'",
archive_error_string(a));
}
- should(a, ARCHIVE_FAILED, "joliet,snafu");
+ should_read_set_options(a, ARCHIVE_FAILED, "joliet,snafu");
if (pristine) {
assertEqualString("Undefined option: `joliet'",
archive_error_string(a));
@@ -106,7 +216,7 @@ test(int pristine)
archive_error_string(a));
}
- should(a, ARCHIVE_FAILED, "iso9660:snafu");
+ should_read_set_options(a, ARCHIVE_FAILED, "iso9660:snafu");
if (pristine) {
assertEqualString("Unknown module name: `iso9660'",
archive_error_string(a));
@@ -120,6 +230,6 @@ test(int pristine)
DEFINE_TEST(test_archive_read_set_options)
{
- test(1);
- test(0);
+ read_set_options_test(1);
+ read_set_options_test(0);
}
diff --git a/contrib/libarchive/libarchive/test/test_archive_seek_data_unsupported.c b/contrib/libarchive/libarchive/test/test_archive_seek_data_unsupported.c
new file mode 100644
index 000000000000..e10e811fcb4c
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_archive_seek_data_unsupported.c
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 2026 tbontb-iaq
+ * 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"
+
+/*
+ * archive_seek_data() returns ARCHIVE_FAILED when the active format
+ * does not implement a seek_data hook. Such "no seeking for this
+ * format" is a capability gap, not stream corruption, and the archive
+ * must remain usable for subsequent reads. See #3323.
+ */
+
+DEFINE_TEST(test_archive_seek_data_unsupported)
+{
+ char buff[8192];
+ size_t used = 0;
+ struct archive *a;
+ struct archive_entry *ae;
+ char rbuf[64];
+ la_ssize_t rd;
+ la_int64_t probe;
+
+ /* Build a small ustar archive in memory. ustar has no seek_data. */
+ assert((a = archive_write_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_none(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_write_open_memory(a, buff, sizeof(buff), &used));
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "hello.txt");
+ archive_entry_set_mode(ae, S_IFREG | 0644);
+ archive_entry_set_size(ae, 11);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
+ archive_entry_free(ae);
+ assertEqualIntA(a, 11, archive_write_data(a, "hello world", 11));
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+
+ /* Read it back. */
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_tar(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("hello.txt", archive_entry_pathname(ae));
+
+ /*
+ * Capability probe. Must report the missing capability with
+ * ARCHIVE_FAILED and set an error string. 3.8.7 and 3.8.8 both
+ * returned ARCHIVE_FATAL here; ARCHIVE_FAILED is the new
+ * contract, because a missing hook is recoverable.
+ */
+ probe = archive_seek_data(a, 0, SEEK_CUR);
+ failure("archive_seek_data() on a format without a seek_data hook "
+ "must report ARCHIVE_FAILED (return value contract)");
+ assertEqualInt(ARCHIVE_FAILED, probe);
+ failure("archive_seek_data() must set an error string when "
+ "the format has no seek_data hook");
+ assert(archive_error_string(a) != NULL);
+
+ /*
+ * The probe must NOT have poisoned the archive. Subsequent reads
+ * from the current entry must still succeed and return the real
+ * entry content. This is the 3.8.8 regression.
+ */
+ rd = archive_read_data(a, rbuf, sizeof(rbuf));
+ failure("archive_read_data() after a non-fatal capability probe "
+ "must still return the entry data (regression in 3.8.8, "
+ "see GitHub issue #3323)");
+ assertEqualInt(11, rd);
+ assertEqualMem(rbuf, "hello world", 11);
+
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/contrib/libarchive/libarchive/test/test_archive_string.c b/contrib/libarchive/libarchive/test/test_archive_string.c
index bf822c0d5e82..c9c5c195a9a7 100644
--- a/contrib/libarchive/libarchive/test/test_archive_string.c
+++ b/contrib/libarchive/libarchive/test/test_archive_string.c
@@ -388,6 +388,7 @@ test_archive_string_dirname(void)
archive_string_dirname(&s);
assertEqualString(pair->exp, s.s);
}
+ archive_string_free(&s);
}
DEFINE_TEST(test_archive_string)
diff --git a/contrib/libarchive/libarchive/test/test_archive_string_conversion.c b/contrib/libarchive/libarchive/test/test_archive_string_conversion.c
index ecc39dffea7f..4bf17185cc01 100644
--- a/contrib/libarchive/libarchive/test/test_archive_string_conversion.c
+++ b/contrib/libarchive/libarchive/test/test_archive_string_conversion.c
@@ -338,13 +338,13 @@ test_archive_string_normalization_nfc(const char *testdata)
nfd[sizeof(nfd)-1] = '\0';
/*
- * Get an NFC patterns.
+ * Get an NFC pattern.
*/
scan_unicode_pattern(utf8_nfc, wc_nfc, utf16be_nfc, utf16le_nfc,
nfc, 0);
/*
- * Get an NFD patterns.
+ * Get an NFD pattern.
*/
scan_unicode_pattern(utf8_nfd, wc_nfd, utf16be_nfd, utf16le_nfd,
nfd, 0);
@@ -550,7 +550,7 @@ test_archive_string_normalization_mac_nfd(const char *testdata)
nfd[sizeof(nfd)-1] = '\0';
/*
- * Get an NFC patterns.
+ * Get an NFC pattern.
*/
should_be_nfc = scan_unicode_pattern(utf8_nfc, wc_nfc,
utf16be_nfc, utf16le_nfc, nfc, 1);
@@ -966,6 +966,10 @@ test_archive_string_conversion_fail_utf8_mbs(struct archive *a,
DEFINE_TEST(test_archive_string_conversion_fail_c)
{
struct archive *a;
+#if defined(__sun)
+ skipping("Solaris iconv substitutes unrepresentable UTF-8 characters");
+ return;
+#endif
/* Test the C locale by not calling setlocale. */
@@ -983,6 +987,10 @@ DEFINE_TEST(test_archive_string_conversion_fail_latin1)
{
struct archive *a;
struct archive_string_conv *sconv;
+#if defined(__sun)
+ skipping("Solaris iconv substitutes unrepresentable UTF-8 characters");
+ return;
+#endif
/* Test a Latin-1 locale. */
if (
diff --git a/contrib/libarchive/libarchive/test/test_archive_string_conversion_overread.c b/contrib/libarchive/libarchive/test/test_archive_string_conversion_overread.c
new file mode 100644
index 000000000000..cb7a49123f8a
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_archive_string_conversion_overread.c
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2026 Kaif Khan
+ * 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"
+
+#define __LIBARCHIVE_TEST
+#include "archive_string.h"
+
+/*
+ * archive_strncpy_l() passes a pointer and a byte count to the string
+ * conversion converter and does not require the buffer to be NUL
+ * terminated: the readers hand it a __archive_read_ahead() window sized
+ * exactly to the field length (mbsnbytes() returns that length when no
+ * NUL is present). The best-effort converter must therefore stop after
+ * the declared number of bytes.
+ *
+ * Requesting a conversion from a charset iconv cannot open selects
+ * best_effort_strncat_in_locale() with sc->same == 0. If a platform's
+ * iconv unexpectedly accepts the name the conversion still succeeds and
+ * the assertions hold, so this never yields a false failure.
+ */
+DEFINE_TEST(test_archive_string_conversion_overread)
+{
+ struct archive *a;
+ struct archive_string_conv *sc;
+
+ assert((a = archive_read_new()) != NULL);
+ sc = archive_string_conversion_from_charset(a, "NO-SUCH-CHARSET-8859", 1);
+ assert(sc != NULL);
+
+ /*
+ * The buffer declares 8 bytes but is followed by 4 more non-NUL
+ * bytes and then a NUL. A converter that honors the declared length
+ * copies 8 bytes; the over-read walks on to the NUL and copies 12.
+ */
+ {
+ struct archive_string as;
+ static const char data[] = "AAAAAAAABBBB"; /* 8 + 4, then NUL */
+
+ archive_string_init(&as);
+ assertEqualInt(0, archive_strncpy_l(&as, data, 8, sc));
+ assertEqualInt(8, (int)as.length);
+ assertEqualMem(as.s, "AAAAAAAA", 8);
+ archive_string_free(&as);
+ }
+
+ /*
+ * Exact-length heap buffer with no trailing NUL: any read past the
+ * end is out of bounds and observable to AddressSanitizer.
+ */
+ {
+ struct archive_string as;
+ size_t n = 8;
+ char *buf = malloc(n);
+
+ assert(buf != NULL);
+ memset(buf, 'A', n);
+ archive_string_init(&as);
+ assertEqualInt(0, archive_strncpy_l(&as, buf, n, sc)); /* must not read buf[n] */
+ assertEqualInt(8, (int)as.length);
+ archive_string_free(&as);
+ free(buf);
+ }
+
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/contrib/libarchive/libarchive/test/test_archive_write_add_filter.c b/contrib/libarchive/libarchive/test/test_archive_write_add_filter.c
new file mode 100644
index 000000000000..3a549d57230b
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_archive_write_add_filter.c
@@ -0,0 +1,208 @@
+/*-
+ * Copyright (c) 2012 Michihiro NAKAJIMA
+ * Copyright (c) 2026 i1011
+ * 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"
+
+static void
+test_add_filter_by_code(int filter_code,
+ int (*can_filter_prog)(void))
+{
+ struct archive_entry *ae;
+ struct archive *a;
+ size_t used;
+ size_t buffsize = 1024 * 128;
+ char *buff;
+ int r;
+
+ assert((buff = calloc(buffsize, sizeof(*buff))) != NULL);
+ if (buff == NULL)
+ return;
+
+ /* Create a new archive in memory. */
+ assert((a = archive_write_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a));
+ r = archive_write_add_filter(a, filter_code);
+ if (r == ARCHIVE_WARN) {
+ if (!can_filter_prog()) {
+ skipping("Filter code \"%d\" not supported on this platform",
+ filter_code);
+ assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+ free(buff);
+ return;
+ }
+ } else if (r == ARCHIVE_FATAL &&
+ (strcmp(archive_error_string(a),
+ "lzma compression not supported on this platform") == 0 ||
+ strcmp(archive_error_string(a),
+ "xz compression not supported on this platform") == 0)) {
+ skipping("Filter code \"%d\" not supported on this platform",
+ filter_code);
+ assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+ free(buff);
+ return;
+ } else {
+ if (!assertEqualIntA(a, ARCHIVE_OK, r)) {
+ assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+ free(buff);
+ return;
+ }
+ }
+ if (filter_code == ARCHIVE_FILTER_LRZIP)
+ {
+ /*
+ * There's a bug in lrzip (as of release 0.612) where 2nd stage
+ * compression can't be performed on smaller files. Set lrzip to
+ * use no 2nd stage compression.
+ */
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_write_set_options(a, "lrzip:compression=none"));
+ }
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_per_block(a, 10));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_write_open_memory(a, buff, buffsize, &used));
+
+ /*
+ * Write a file to it.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(ae, 1, 0);
+ assertEqualInt(1, archive_entry_mtime(ae));
+ archive_entry_set_ctime(ae, 1, 0);
+ assertEqualInt(1, archive_entry_ctime(ae));
+ archive_entry_set_atime(ae, 1, 0);
+ assertEqualInt(1, archive_entry_atime(ae));
+ archive_entry_copy_pathname(ae, "file");
+ assertEqualString("file", archive_entry_pathname(ae));
+ archive_entry_set_mode(ae, AE_IFREG | 0755);
+ assertEqualInt((AE_IFREG | 0755), archive_entry_mode(ae));
+ archive_entry_set_size(ae, 8);
+ assertEqualInt(0, archive_write_header(a, ae));
+ archive_entry_free(ae);
+ assertEqualInt(8, archive_write_data(a, "12345678", 8));
+
+ /* Close out the archive. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+
+ /*
+ * Now, read the data back.
+ */
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+
+ /*
+ * Read and verify the file.
+ */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualInt(1, archive_entry_mtime(ae));
+ assertEqualString("file", archive_entry_pathname(ae));
+ assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
+ assertEqualInt(8, archive_entry_size(ae));
+
+ /* Verify the end of the archive. */
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+
+ /* Verify archive format. */
+ assertEqualIntA(a, filter_code, archive_filter_code(a, 0));
+ assertEqualIntA(a, ARCHIVE_FORMAT_TAR_USTAR, archive_format(a));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+ free(buff);
+}
+
+static int
+canAlways(void)
+{
+ return 1;
+}
+
+DEFINE_TEST(test_archive_write_add_filter_none)
+{
+ test_add_filter_by_code(ARCHIVE_FILTER_NONE, canAlways);
+}
+
+DEFINE_TEST(test_archive_write_add_filter_gzip)
+{
+ test_add_filter_by_code(ARCHIVE_FILTER_GZIP, canGzip);
+}
+
+DEFINE_TEST(test_archive_write_add_filter_bzip2)
+{
+ test_add_filter_by_code(ARCHIVE_FILTER_BZIP2, canBzip2);
+}
+
+DEFINE_TEST(test_archive_write_add_filter_compress)
+{
+ test_add_filter_by_code(ARCHIVE_FILTER_COMPRESS, canAlways);
+}
+
+DEFINE_TEST(test_archive_write_add_filter_grzip)
+{
+ test_add_filter_by_code(ARCHIVE_FILTER_GRZIP, canGrzip);
+}
+
+DEFINE_TEST(test_archive_write_add_filter_lrzip)
+{
+ test_add_filter_by_code(ARCHIVE_FILTER_LRZIP, canLrzip);
+}
+
+DEFINE_TEST(test_archive_write_add_filter_lz4)
+{
+ test_add_filter_by_code(ARCHIVE_FILTER_LZ4, canLz4);
+}
+
+DEFINE_TEST(test_archive_write_add_filter_lzip)
+{
+ test_add_filter_by_code(ARCHIVE_FILTER_LZIP, canLzip);
+}
+
+DEFINE_TEST(test_archive_write_add_filter_lzma)
+{
+ test_add_filter_by_code(ARCHIVE_FILTER_LZMA, canLzma);
+}
+
+DEFINE_TEST(test_archive_write_add_filter_lzop)
+{
+ test_add_filter_by_code(ARCHIVE_FILTER_LZOP, canLzop);
+}
+
+DEFINE_TEST(test_archive_write_add_filter_uuencode)
+{
+ test_add_filter_by_code(ARCHIVE_FILTER_UU, canAlways);
+}
+
+DEFINE_TEST(test_archive_write_add_filter_xz)
+{
+ test_add_filter_by_code(ARCHIVE_FILTER_XZ, canXz);
+}
+
+DEFINE_TEST(test_archive_write_add_filter_zstd)
+{
+ test_add_filter_by_code(ARCHIVE_FILTER_ZSTD, canZstd);
+}
diff --git a/contrib/libarchive/libarchive/test/test_archive_write_add_filter_by_name.c b/contrib/libarchive/libarchive/test/test_archive_write_add_filter_by_name.c
index 9d7e58d6f635..f0785203039b 100644
--- a/contrib/libarchive/libarchive/test/test_archive_write_add_filter_by_name.c
+++ b/contrib/libarchive/libarchive/test/test_archive_write_add_filter_by_name.c
@@ -129,7 +129,7 @@ test_filter_by_name(const char *filter_name, int filter_code,
assertEqualIntA(a, filter_code, archive_filter_code(a, 0));
assertEqualIntA(a, ARCHIVE_FORMAT_TAR_USTAR, archive_format(a));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
free(buff);
}
diff --git a/contrib/libarchive/libarchive/test/test_archive_write_set_format_by_name.c b/contrib/libarchive/libarchive/test/test_archive_write_set_format_by_name.c
index 07942f6bffc8..f8ca04db36e4 100644
--- a/contrib/libarchive/libarchive/test/test_archive_write_set_format_by_name.c
+++ b/contrib/libarchive/libarchive/test/test_archive_write_set_format_by_name.c
@@ -130,7 +130,7 @@ test_format_by_name(const char *format_name, const char *compression_type,
archive_filter_code(a, 0));
assertEqualIntA(a, format_id, archive_format(a));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
free(buff);
diff --git a/contrib/libarchive/libarchive/test/test_archive_write_set_format_filter_by_ext.c b/contrib/libarchive/libarchive/test/test_archive_write_set_format_filter_by_ext.c
index fe6c350e48e7..849a9c5a078d 100644
--- a/contrib/libarchive/libarchive/test/test_archive_write_set_format_filter_by_ext.c
+++ b/contrib/libarchive/libarchive/test/test_archive_write_set_format_filter_by_ext.c
@@ -137,7 +137,7 @@ test_format_filter_by_ext(const char *output_file,
archive_filter_code(a, 0));
assertEqualIntA(a, format_id, archive_format(a) & ARCHIVE_FORMAT_BASE_MASK );
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
free(buff);
diff --git a/contrib/libarchive/libarchive/test/test_archive_write_set_format_option.c b/contrib/libarchive/libarchive/test/test_archive_write_set_format_option.c
deleted file mode 100644
index 38f83aba2ede..000000000000
--- a/contrib/libarchive/libarchive/test/test_archive_write_set_format_option.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*-
- * Copyright (c) 2011 Tim Kientzle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "test.h"
-
-#define should(__a, __code, __m, __o, __v) \
-assertEqualInt(__code, archive_write_set_format_option(__a, __m, __o, __v))
-
-static void
-test(int pristine)
-{
- struct archive* a = archive_write_new();
- int known_option_rv = pristine ? ARCHIVE_FAILED : ARCHIVE_OK;
-
- if (!pristine)
- archive_write_set_format_iso9660(a);
-
- /* NULL and "" denote `no option', so they're ok no matter
- * what, if any, formats are registered */
- should(a, ARCHIVE_OK, NULL, NULL, NULL);
- should(a, ARCHIVE_OK, "", "", "");
-
- /* unknown modules and options */
- should(a, ARCHIVE_FAILED, "fubar", "snafu", NULL);
- should(a, ARCHIVE_FAILED, "fubar", "snafu", "betcha");
-
- /* unknown modules and options */
- should(a, ARCHIVE_FAILED, NULL, "snafu", NULL);
- should(a, ARCHIVE_FAILED, NULL, "snafu", "betcha");
-
- /* ARCHIVE_OK with iso9660 loaded, ARCHIVE_WARN otherwise */
- should(a, known_option_rv, "iso9660", "joliet", NULL);
- should(a, known_option_rv, "iso9660", "joliet", NULL);
- should(a, known_option_rv, NULL, "joliet", NULL);
- should(a, known_option_rv, NULL, "joliet", NULL);
-
- archive_write_free(a);
-}
-
-DEFINE_TEST(test_archive_write_set_format_option)
-{
- test(1);
- test(0);
-}
diff --git a/contrib/libarchive/libarchive/test/test_archive_write_set_option.c b/contrib/libarchive/libarchive/test/test_archive_write_set_option.c
deleted file mode 100644
index aa44edad653d..000000000000
--- a/contrib/libarchive/libarchive/test/test_archive_write_set_option.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*-
- * Copyright (c) 2011 Tim Kientzle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "test.h"
-
-#define should(__a, __code, __m, __o, __v) \
-assertEqualInt(__code, archive_write_set_option(__a, __m, __o, __v))
-
-static void
-test(int pristine)
-{
- struct archive* a = archive_write_new();
- int known_option_rv = pristine ? ARCHIVE_FAILED : ARCHIVE_OK;
-
- if (!pristine) {
- archive_write_add_filter_gzip(a);
- archive_write_set_format_iso9660(a);
- }
-
- /* NULL and "" denote `no option', so they're ok no matter
- * what, if any, formats are registered */
- should(a, ARCHIVE_OK, NULL, NULL, NULL);
- should(a, ARCHIVE_OK, "", "", "");
-
- /* unknown modules and options */
- should(a, ARCHIVE_FAILED, "fubar", "snafu", NULL);
- should(a, ARCHIVE_FAILED, "fubar", "snafu", "betcha");
-
- /* unknown modules and options */
- should(a, ARCHIVE_FAILED, NULL, "snafu", NULL);
- should(a, ARCHIVE_FAILED, NULL, "snafu", "betcha");
-
- /* ARCHIVE_OK with iso9660 loaded, ARCHIVE_WARN otherwise */
- should(a, known_option_rv, "iso9660", "joliet", NULL);
- should(a, known_option_rv, "iso9660", "joliet", NULL);
- should(a, known_option_rv, NULL, "joliet", NULL);
- should(a, known_option_rv, NULL, "joliet", NULL);
-
- archive_write_free(a);
-}
-
-DEFINE_TEST(test_archive_write_set_option)
-{
- test(1);
- test(0);
-}
diff --git a/contrib/libarchive/libarchive/test/test_archive_write_set_options.c b/contrib/libarchive/libarchive/test/test_archive_write_set_options.c
index 6a0198de35e1..c35c87185041 100644
--- a/contrib/libarchive/libarchive/test/test_archive_write_set_options.c
+++ b/contrib/libarchive/libarchive/test/test_archive_write_set_options.c
@@ -25,11 +25,121 @@
#include "test.h"
-#define should(__a, __code, __opts) \
+#define should_write_set_filter_option(__a, __code, __m, __o, __v) \
+assertEqualInt(__code, archive_write_set_filter_option(__a, __m, __o, __v))
+
+static void
+write_set_filter_option_test(int pristine)
+{
+ struct archive* a = archive_write_new();
+
+ if (!pristine)
+ archive_write_add_filter_gzip(a);
+
+ should_write_set_filter_option(a, ARCHIVE_OK, NULL, NULL, NULL);
+ should_write_set_filter_option(a, ARCHIVE_OK, "", "", "");
+
+ should_write_set_filter_option(a, ARCHIVE_FAILED, NULL, "fubar", NULL);
+ should_write_set_filter_option(a, ARCHIVE_FAILED, NULL, "fubar", "snafu");
+ should_write_set_filter_option(a, ARCHIVE_FAILED, "fubar", "snafu", NULL);
+ should_write_set_filter_option(a, ARCHIVE_FAILED, "fubar", "snafu", "betcha");
+
+ archive_write_free(a);
+}
+
+DEFINE_TEST(test_archive_write_set_filter_option)
+{
+ write_set_filter_option_test(1);
+ write_set_filter_option_test(0);
+}
+
+#define should_write_set_format_option(__a, __code, __m, __o, __v) \
+assertEqualInt(__code, archive_write_set_format_option(__a, __m, __o, __v))
+
+static void
+write_set_format_option_test(int pristine)
+{
+ struct archive* a = archive_write_new();
+ int known_option_rv = pristine ? ARCHIVE_FAILED : ARCHIVE_OK;
+
+ if (!pristine)
+ archive_write_set_format_iso9660(a);
+
+ /* NULL and "" denote `no option', so they're ok no matter
+ * what, if any, formats are registered */
+ should_write_set_format_option(a, ARCHIVE_OK, NULL, NULL, NULL);
+ should_write_set_format_option(a, ARCHIVE_OK, "", "", "");
+
+ /* unknown modules and options */
+ should_write_set_format_option(a, ARCHIVE_FAILED, "fubar", "snafu", NULL);
+ should_write_set_format_option(a, ARCHIVE_FAILED, "fubar", "snafu", "betcha");
+
+ /* unknown modules and options */
+ should_write_set_format_option(a, ARCHIVE_FAILED, NULL, "snafu", NULL);
+ should_write_set_format_option(a, ARCHIVE_FAILED, NULL, "snafu", "betcha");
+
+ /* ARCHIVE_OK with iso9660 loaded, ARCHIVE_WARN otherwise */
+ should_write_set_format_option(a, known_option_rv, "iso9660", "joliet", NULL);
+ should_write_set_format_option(a, known_option_rv, "iso9660", "joliet", NULL);
+ should_write_set_format_option(a, known_option_rv, NULL, "joliet", NULL);
+ should_write_set_format_option(a, known_option_rv, NULL, "joliet", NULL);
+
+ archive_write_free(a);
+}
+
+DEFINE_TEST(test_archive_write_set_format_option)
+{
+ write_set_format_option_test(1);
+ write_set_format_option_test(0);
+}
+
+#define should_write_set_option(__a, __code, __m, __o, __v) \
+assertEqualInt(__code, archive_write_set_option(__a, __m, __o, __v))
+
+static void
+write_set_option_test(int pristine)
+{
+ struct archive* a = archive_write_new();
+ int known_option_rv = pristine ? ARCHIVE_FAILED : ARCHIVE_OK;
+
+ if (!pristine) {
+ archive_write_add_filter_gzip(a);
+ archive_write_set_format_iso9660(a);
+ }
+
+ /* NULL and "" denote `no option', so they're ok no matter
+ * what, if any, formats are registered */
+ should_write_set_option(a, ARCHIVE_OK, NULL, NULL, NULL);
+ should_write_set_option(a, ARCHIVE_OK, "", "", "");
+
+ /* unknown modules and options */
+ should_write_set_option(a, ARCHIVE_FAILED, "fubar", "snafu", NULL);
+ should_write_set_option(a, ARCHIVE_FAILED, "fubar", "snafu", "betcha");
+
+ /* unknown modules and options */
+ should_write_set_option(a, ARCHIVE_FAILED, NULL, "snafu", NULL);
+ should_write_set_option(a, ARCHIVE_FAILED, NULL, "snafu", "betcha");
+
+ /* ARCHIVE_OK with iso9660 loaded, ARCHIVE_WARN otherwise */
+ should_write_set_option(a, known_option_rv, "iso9660", "joliet", NULL);
+ should_write_set_option(a, known_option_rv, "iso9660", "joliet", NULL);
+ should_write_set_option(a, known_option_rv, NULL, "joliet", NULL);
+ should_write_set_option(a, known_option_rv, NULL, "joliet", NULL);
+
+ archive_write_free(a);
+}
+
+DEFINE_TEST(test_archive_write_set_option)
+{
+ write_set_option_test(1);
+ write_set_option_test(0);
+}
+
+#define should_write_set_options(__a, __code, __opts) \
assertEqualInt(__code, archive_write_set_options(__a, __opts))
static void
-test(int pristine)
+write_set_options_test(int pristine)
{
struct archive* a = archive_write_new();
int halfempty_options_rv = pristine ? ARCHIVE_FAILED : ARCHIVE_OK;
@@ -42,62 +152,62 @@ test(int pristine)
/* NULL and "" denote `no option', so they're ok no matter
* what, if any, formats are registered */
- should(a, ARCHIVE_OK, NULL);
- should(a, ARCHIVE_OK, "");
+ should_write_set_options(a, ARCHIVE_OK, NULL);
+ should_write_set_options(a, ARCHIVE_OK, "");
/* unknown modules and options */
- should(a, ARCHIVE_FAILED, "fubar:snafu");
+ should_write_set_options(a, ARCHIVE_FAILED, "fubar:snafu");
assertEqualString("Unknown module name: `fubar'",
archive_error_string(a));
- should(a, ARCHIVE_FAILED, "fubar:snafu=betcha");
+ should_write_set_options(a, ARCHIVE_FAILED, "fubar:snafu=betcha");
assertEqualString("Unknown module name: `fubar'",
archive_error_string(a));
/* unknown modules and options */
- should(a, ARCHIVE_FAILED, "snafu");
+ should_write_set_options(a, ARCHIVE_FAILED, "snafu");
assertEqualString("Undefined option: `snafu'",
archive_error_string(a));
- should(a, ARCHIVE_FAILED, "snafu=betcha");
+ should_write_set_options(a, ARCHIVE_FAILED, "snafu=betcha");
assertEqualString("Undefined option: `snafu'",
archive_error_string(a));
/* ARCHIVE_OK with iso9660 loaded, ARCHIVE_FAILED otherwise */
- should(a, known_option_rv, "iso9660:joliet");
+ should_write_set_options(a, known_option_rv, "iso9660:joliet");
if (pristine) {
assertEqualString("Unknown module name: `iso9660'",
archive_error_string(a));
}
- should(a, known_option_rv, "iso9660:joliet");
+ should_write_set_options(a, known_option_rv, "iso9660:joliet");
if (pristine) {
assertEqualString("Unknown module name: `iso9660'",
archive_error_string(a));
}
- should(a, known_option_rv, "joliet");
+ should_write_set_options(a, known_option_rv, "joliet");
if (pristine) {
assertEqualString("Undefined option: `joliet'",
archive_error_string(a));
}
- should(a, known_option_rv, "!joliet");
+ should_write_set_options(a, known_option_rv, "!joliet");
if (pristine) {
assertEqualString("Undefined option: `joliet'",
archive_error_string(a));
}
- should(a, ARCHIVE_OK, ",");
- should(a, ARCHIVE_OK, ",,");
+ should_write_set_options(a, ARCHIVE_OK, ",");
+ should_write_set_options(a, ARCHIVE_OK, ",,");
- should(a, halfempty_options_rv, ",joliet");
+ should_write_set_options(a, halfempty_options_rv, ",joliet");
if (pristine) {
assertEqualString("Undefined option: `joliet'",
archive_error_string(a));
}
- should(a, halfempty_options_rv, "joliet,");
+ should_write_set_options(a, halfempty_options_rv, "joliet,");
if (pristine) {
assertEqualString("Undefined option: `joliet'",
archive_error_string(a));
}
- should(a, ARCHIVE_FAILED, "joliet,snafu");
+ should_write_set_options(a, ARCHIVE_FAILED, "joliet,snafu");
if (pristine) {
assertEqualString("Undefined option: `joliet'",
archive_error_string(a));
@@ -106,7 +216,7 @@ test(int pristine)
archive_error_string(a));
}
- should(a, ARCHIVE_FAILED, "iso9660:snafu");
+ should_write_set_options(a, ARCHIVE_FAILED, "iso9660:snafu");
if (pristine) {
assertEqualString("Unknown module name: `iso9660'",
archive_error_string(a));
@@ -120,6 +230,6 @@ test(int pristine)
DEFINE_TEST(test_archive_write_set_options)
{
- test(1);
- test(0);
+ write_set_options_test(1);
+ write_set_options_test(0);
}
diff --git a/contrib/libarchive/libarchive/test/test_compat_bzip2.c b/contrib/libarchive/libarchive/test/test_compat_bzip2.c
index e126e6f7d329..8fd04a7dad15 100644
--- a/contrib/libarchive/libarchive/test/test_compat_bzip2.c
+++ b/contrib/libarchive/libarchive/test/test_compat_bzip2.c
@@ -48,6 +48,7 @@ compat_bzip2(const char *name)
assert((a = archive_read_new()) != NULL);
if (ARCHIVE_OK != archive_read_support_filter_bzip2(a)) {
skipping("Unsupported bzip2");
+ archive_read_free(a);
return;
}
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
diff --git a/contrib/libarchive/libarchive/test/test_compat_cpio.c b/contrib/libarchive/libarchive/test/test_compat_cpio.c
index 12512881112b..1c139c77f955 100644
--- a/contrib/libarchive/libarchive/test/test_compat_cpio.c
+++ b/contrib/libarchive/libarchive/test/test_compat_cpio.c
@@ -92,7 +92,7 @@ test_compat_cpio_1(void)
assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_NONE);
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_CPIO_SVR4_NOCRC);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_compat_gtar.c b/contrib/libarchive/libarchive/test/test_compat_gtar.c
index ba42e726cf78..fe3cfec9077d 100644
--- a/contrib/libarchive/libarchive/test/test_compat_gtar.c
+++ b/contrib/libarchive/libarchive/test/test_compat_gtar.c
@@ -101,7 +101,7 @@ test_compat_gtar_1(void)
assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_NONE);
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_GNUTAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -141,7 +141,7 @@ test_compat_gtar_2(void)
assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_NONE);
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_GNUTAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_compat_gtar_large.c b/contrib/libarchive/libarchive/test/test_compat_gtar_large.c
index 633b20c0a9f8..b9a467b1c95f 100644
--- a/contrib/libarchive/libarchive/test/test_compat_gtar_large.c
+++ b/contrib/libarchive/libarchive/test/test_compat_gtar_large.c
@@ -218,7 +218,7 @@ DEFINE_TEST(test_compat_gtar_large)
/* Verify that the reader actually read to the end of data */
assertEqualInt(reader.zero_blocks_remaining, 0);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
free(reader.zero_block);
}
diff --git a/contrib/libarchive/libarchive/test/test_compat_gzip.c b/contrib/libarchive/libarchive/test/test_compat_gzip.c
index 20fce7af432d..475c13674575 100644
--- a/contrib/libarchive/libarchive/test/test_compat_gzip.c
+++ b/contrib/libarchive/libarchive/test/test_compat_gzip.c
@@ -77,7 +77,7 @@ verify(const char *name)
assertEqualString(archive_filter_name(a, 0), "gzip");
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_compat_lz4.c b/contrib/libarchive/libarchive/test/test_compat_lz4.c
index 8ab9208b0918..d053155694d1 100644
--- a/contrib/libarchive/libarchive/test/test_compat_lz4.c
+++ b/contrib/libarchive/libarchive/test/test_compat_lz4.c
@@ -31,7 +31,7 @@
* In particular:
* * lz4 -d will read multiple lz4 streams, concatenating the output
* * lz4 -d will stop at the end of a stream if the following data
- * doesn't start with a lz4 signature.
+ * doesn't start with an lz4 signature.
*/
/*
@@ -78,7 +78,7 @@ verify(const char *name, const char *n[])
assertEqualString(archive_filter_name(a, 0), "lz4");
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_compat_lzip.c b/contrib/libarchive/libarchive/test/test_compat_lzip.c
index cd246b943b22..9a8196f61d49 100644
--- a/contrib/libarchive/libarchive/test/test_compat_lzip.c
+++ b/contrib/libarchive/libarchive/test/test_compat_lzip.c
@@ -124,7 +124,7 @@ compat_lzip(const char *name)
assertEqualString(archive_filter_name(a, 0), "lzip");
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -165,7 +165,7 @@ compat_lzip_3(const char *name)
assertEqualString(archive_filter_name(a, 0), "lzip");
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_RAW);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -202,7 +202,7 @@ compat_lzip_4(const char *name)
assertEqualString(archive_filter_name(a, 0), "lzip");
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_compat_lzma.c b/contrib/libarchive/libarchive/test/test_compat_lzma.c
index b9cad55514a1..af988e1f2b54 100644
--- a/contrib/libarchive/libarchive/test/test_compat_lzma.c
+++ b/contrib/libarchive/libarchive/test/test_compat_lzma.c
@@ -133,7 +133,7 @@ compat_lzma(const char *name)
assertEqualString(archive_filter_name(a, 0), "lzma");
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_compat_lzop.c b/contrib/libarchive/libarchive/test/test_compat_lzop.c
index 2da4e8eb6dc2..a70d658244c4 100644
--- a/contrib/libarchive/libarchive/test/test_compat_lzop.c
+++ b/contrib/libarchive/libarchive/test/test_compat_lzop.c
@@ -70,7 +70,7 @@ DEFINE_TEST(test_compat_lzop)
assertEqualString(archive_filter_name(a, 0), "lzop");
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
/*
@@ -101,7 +101,7 @@ DEFINE_TEST(test_compat_lzop)
assertEqualString(archive_filter_name(a, 0), "lzop");
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
/*
@@ -125,6 +125,6 @@ DEFINE_TEST(test_compat_lzop)
assertEqualString(archive_filter_name(a, 0), "lzop");
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_compat_mac.c b/contrib/libarchive/libarchive/test/test_compat_mac.c
index 976f04a473f6..9532d079affc 100644
--- a/contrib/libarchive/libarchive/test/test_compat_mac.c
+++ b/contrib/libarchive/libarchive/test/test_compat_mac.c
@@ -130,7 +130,7 @@ test_compat_mac_1(void)
assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_COMPRESS);
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_GNUTAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -201,7 +201,7 @@ test_compat_mac_2(void)
assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_COMPRESS);
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_compat_perl_archive_tar.c b/contrib/libarchive/libarchive/test/test_compat_perl_archive_tar.c
index 94abe3f056a3..1574f7bc8ffb 100644
--- a/contrib/libarchive/libarchive/test/test_compat_perl_archive_tar.c
+++ b/contrib/libarchive/libarchive/test/test_compat_perl_archive_tar.c
@@ -60,6 +60,6 @@ DEFINE_TEST(test_compat_perl_archive_tar)
assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_NONE);
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_compat_plexus_archiver_tar.c b/contrib/libarchive/libarchive/test/test_compat_plexus_archiver_tar.c
index 419e84b1c4c9..8346fb555e53 100644
--- a/contrib/libarchive/libarchive/test/test_compat_plexus_archiver_tar.c
+++ b/contrib/libarchive/libarchive/test/test_compat_plexus_archiver_tar.c
@@ -63,6 +63,6 @@ DEFINE_TEST(test_compat_plexus_archiver_tar)
assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_NONE);
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_compat_solaris_pax_sparse.c b/contrib/libarchive/libarchive/test/test_compat_solaris_pax_sparse.c
index 94e3e9189bc2..1d3c2beb5579 100644
--- a/contrib/libarchive/libarchive/test/test_compat_solaris_pax_sparse.c
+++ b/contrib/libarchive/libarchive/test/test_compat_solaris_pax_sparse.c
@@ -100,7 +100,7 @@ test_compat_solaris_pax_sparse_1(void)
assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_COMPRESS);
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -172,7 +172,7 @@ test_compat_solaris_pax_sparse_2(void)
assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_COMPRESS);
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_compat_tar_directory.c b/contrib/libarchive/libarchive/test/test_compat_tar_directory.c
index 3d086f1da7bc..92278fdc6c43 100644
--- a/contrib/libarchive/libarchive/test/test_compat_tar_directory.c
+++ b/contrib/libarchive/libarchive/test/test_compat_tar_directory.c
@@ -64,7 +64,7 @@ test_compat_tar_directory_1(void)
assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_NONE);
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_compat_tar_hardlink.c b/contrib/libarchive/libarchive/test/test_compat_tar_hardlink.c
index b8517440aea5..4f4c8904ac5b 100644
--- a/contrib/libarchive/libarchive/test/test_compat_tar_hardlink.c
+++ b/contrib/libarchive/libarchive/test/test_compat_tar_hardlink.c
@@ -91,7 +91,7 @@ test_compat_tar_hardlink_1(void)
assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_NONE);
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_compat_xz.c b/contrib/libarchive/libarchive/test/test_compat_xz.c
index f904583782d2..3170b149c605 100644
--- a/contrib/libarchive/libarchive/test/test_compat_xz.c
+++ b/contrib/libarchive/libarchive/test/test_compat_xz.c
@@ -72,7 +72,7 @@ compat_xz(const char *name)
assertEqualString(archive_filter_name(a, 0), "xz");
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_compat_zip.c b/contrib/libarchive/libarchive/test/test_compat_zip.c
index e2d41cc9b439..1f120692eccc 100644
--- a/contrib/libarchive/libarchive/test/test_compat_zip.c
+++ b/contrib/libarchive/libarchive/test/test_compat_zip.c
@@ -58,7 +58,7 @@ DEFINE_TEST(test_compat_zip_1)
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_ZIP);
finish:
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -89,7 +89,7 @@ DEFINE_TEST(test_compat_zip_2)
assertEqualString("file2", archive_entry_pathname(ae));
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -140,7 +140,7 @@ DEFINE_TEST(test_compat_zip_3)
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));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
/**
@@ -188,7 +188,7 @@ DEFINE_TEST(test_compat_zip_4)
assertEqualInt(0644, archive_entry_perm(ae));
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
- assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
/* Try reading without seek support and watch it fail. */
assert((a = archive_read_new()) != NULL);
@@ -196,7 +196,7 @@ DEFINE_TEST(test_compat_zip_4)
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
assertEqualIntA(a, ARCHIVE_FATAL, read_open_memory(a, p, s, 3));
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
- assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
free(p);
}
/**
@@ -273,7 +273,7 @@ DEFINE_TEST(test_compat_zip_5)
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));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
/* Try reading without seek support. */
assert((a = archive_read_new()) != NULL);
@@ -332,7 +332,7 @@ DEFINE_TEST(test_compat_zip_5)
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));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
free(p);
}
@@ -376,14 +376,14 @@ DEFINE_TEST(test_compat_zip_6)
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
assertEqualIntA(a, ARCHIVE_OK, read_open_memory_seek(a, p, s, 7));
compat_zip_6_verify(a);
- assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
assert((a = archive_read_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
assertEqualIntA(a, ARCHIVE_OK, read_open_memory(a, p, s, 7));
compat_zip_6_verify(a);
- assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
free(p);
}
@@ -417,7 +417,7 @@ DEFINE_TEST(test_compat_zip_7)
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualIntA(a, ARCHIVE_OK, archive_read_data_skip(a));
- assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
free(p);
}
@@ -444,6 +444,6 @@ DEFINE_TEST(test_compat_zip_8)
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
/* This file is in the archive as arc\test */
assertEqualString("arc/test", archive_entry_pathname(ae));
- assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
free(p);
}
diff --git a/contrib/libarchive/libarchive/test/test_compat_zstd.c b/contrib/libarchive/libarchive/test/test_compat_zstd.c
index 34b8edeb924d..8785aa39e2c3 100644
--- a/contrib/libarchive/libarchive/test/test_compat_zstd.c
+++ b/contrib/libarchive/libarchive/test/test_compat_zstd.c
@@ -67,7 +67,7 @@ compat_zstd(const char *name)
assertEqualString(archive_filter_name(a, 0), "zstd");
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_entry.c b/contrib/libarchive/libarchive/test/test_entry.c
index cff9c5c86efc..d852b9c1fde6 100644
--- a/contrib/libarchive/libarchive/test/test_entry.c
+++ b/contrib/libarchive/libarchive/test/test_entry.c
@@ -988,3 +988,31 @@ DEFINE_TEST(test_entry)
/* Release the experimental entry. */
archive_entry_free(e);
}
+
+DEFINE_TEST(test_entry_mac_metadata_self_copy)
+{
+ static const unsigned char metadata[64] = {
+ 0x41, 0x42, 0x43, 0x44
+ };
+ struct archive_entry *entry;
+ const void *copy;
+ size_t copy_size;
+
+ assert((entry = archive_entry_new()) != NULL);
+ archive_entry_copy_mac_metadata(entry, metadata, sizeof(metadata));
+ copy = archive_entry_mac_metadata(entry, &copy_size);
+ assertEqualInt(sizeof(metadata), copy_size);
+
+ archive_entry_copy_mac_metadata(entry, copy, copy_size);
+ copy = archive_entry_mac_metadata(entry, &copy_size);
+ assertEqualInt(sizeof(metadata), copy_size);
+ assertEqualMem(metadata, copy, sizeof(metadata));
+
+ archive_entry_copy_mac_metadata(entry,
+ (const unsigned char *)copy + 1, copy_size - 1);
+ copy = archive_entry_mac_metadata(entry, &copy_size);
+ assertEqualInt(sizeof(metadata) - 1, copy_size);
+ assertEqualMem(metadata + 1, copy, sizeof(metadata) - 1);
+
+ archive_entry_free(entry);
+}
diff --git a/contrib/libarchive/libarchive/test/test_fuzz.c b/contrib/libarchive/libarchive/test/test_fuzz.c
index dcb4f73ca372..ff6b9d9b70b8 100644
--- a/contrib/libarchive/libarchive/test/test_fuzz.c
+++ b/contrib/libarchive/libarchive/test/test_fuzz.c
@@ -31,7 +31,7 @@
*
* This test simply reads each archive image into memory, pokes
* random values into it and runs it through libarchive. It tries
- * to damage about 1% of each file and repeats the exercise 100 times
+ * to damage about 1% of each file and repeats the exercise 1000 times
* with each file.
*
* Unlike most other tests, this test does not verify libarchive's
diff --git a/contrib/libarchive/libarchive/test/test_fuzz_consumer.h b/contrib/libarchive/libarchive/test/test_fuzz_consumer.h
new file mode 100644
index 000000000000..450b97273eb9
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_fuzz_consumer.h
@@ -0,0 +1,143 @@
+/*-
+ * Copyright (c) 2025 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.
+ */
+
+/*
+ * C99 equivalent of the DataConsumer class used by the C++ fuzzers.
+ * Consumes bytes sequentially from a buffer, matching the fuzzer protocol.
+ * Not all consumers use every function, so suppress unused warnings.
+ */
+#ifndef TEST_FUZZ_CONSUMER_H
+#define TEST_FUZZ_CONSUMER_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+
+#if defined(__GNUC__) || defined(__clang__)
+#define FUZZ_UNUSED __attribute__((unused))
+#else
+#define FUZZ_UNUSED
+#endif
+
+struct fuzz_consumer {
+ const uint8_t *data;
+ size_t size;
+ size_t pos;
+ char string_buf[512];
+};
+
+FUZZ_UNUSED static void
+fuzz_consumer_init(struct fuzz_consumer *c, const uint8_t *data, size_t size)
+{
+ c->data = data;
+ c->size = size;
+ c->pos = 0;
+}
+
+FUZZ_UNUSED static size_t
+fuzz_consumer_remaining(const struct fuzz_consumer *c)
+{
+ return c->size - c->pos;
+}
+
+FUZZ_UNUSED static uint8_t
+fuzz_consume_byte(struct fuzz_consumer *c)
+{
+ if (c->pos >= c->size)
+ return 0;
+ return c->data[c->pos++];
+}
+
+FUZZ_UNUSED static uint16_t
+fuzz_consume_u16(struct fuzz_consumer *c)
+{
+ uint16_t val = 0;
+ if (c->pos + 2 <= c->size) {
+ val = (uint16_t)c->data[c->pos]
+ | ((uint16_t)c->data[c->pos + 1] << 8);
+ c->pos += 2;
+ }
+ return val;
+}
+
+FUZZ_UNUSED static uint32_t
+fuzz_consume_u32(struct fuzz_consumer *c)
+{
+ uint32_t val = 0;
+ if (c->pos + 4 <= c->size) {
+ val = (uint32_t)c->data[c->pos]
+ | ((uint32_t)c->data[c->pos + 1] << 8)
+ | ((uint32_t)c->data[c->pos + 2] << 16)
+ | ((uint32_t)c->data[c->pos + 3] << 24);
+ c->pos += 4;
+ }
+ return val;
+}
+
+FUZZ_UNUSED static int64_t
+fuzz_consume_i64(struct fuzz_consumer *c)
+{
+ uint64_t val = 0;
+ if (c->pos + 8 <= c->size) {
+ int i;
+ for (i = 0; i < 8; i++)
+ val |= (uint64_t)c->data[c->pos + i] << (8 * i);
+ c->pos += 8;
+ }
+ return (int64_t)val;
+}
+
+FUZZ_UNUSED static const char *
+fuzz_consume_string(struct fuzz_consumer *c, size_t max_len)
+{
+ size_t avail, len, actual_len;
+ if (max_len > sizeof(c->string_buf) - 1)
+ max_len = sizeof(c->string_buf) - 1;
+ avail = c->size - c->pos;
+ len = (avail < max_len) ? avail : max_len;
+ actual_len = 0;
+ while (actual_len < len && c->pos < c->size) {
+ char ch = (char)c->data[c->pos++];
+ if (ch == '\0')
+ break;
+ c->string_buf[actual_len++] = ch;
+ }
+ c->string_buf[actual_len] = '\0';
+ return c->string_buf;
+}
+
+FUZZ_UNUSED static size_t
+fuzz_consume_bytes(struct fuzz_consumer *c, void *out, size_t len)
+{
+ size_t avail = c->size - c->pos;
+ size_t to_copy = (avail < len) ? avail : len;
+ if (to_copy > 0) {
+ memcpy(out, c->data + c->pos, to_copy);
+ c->pos += to_copy;
+ }
+ return to_copy;
+}
+
+#endif /* TEST_FUZZ_CONSUMER_H */
diff --git a/contrib/libarchive/libarchive/test/test_gnutar_filename_encoding.c b/contrib/libarchive/libarchive/test/test_gnutar_filename_encoding.c
index 830b3884f829..f53523a198f8 100644
--- a/contrib/libarchive/libarchive/test/test_gnutar_filename_encoding.c
+++ b/contrib/libarchive/libarchive/test/test_gnutar_filename_encoding.c
@@ -157,7 +157,7 @@ DEFINE_TEST(test_gnutar_filename_encoding_CP1251_UTF8)
if (NULL == setlocale(LC_ALL, "Russian_Russia") &&
NULL == setlocale(LC_ALL, "ru_RU.CP1251")) {
- skipping("KOI8-R locale not available on this system.");
+ skipping("CP1251 locale not available on this system.");
return;
}
@@ -169,7 +169,7 @@ DEFINE_TEST(test_gnutar_filename_encoding_CP1251_UTF8)
assertEqualInt(ARCHIVE_OK, archive_write_set_format_gnutar(a));
if (archive_write_set_options(a, "hdrcharset=UTF-8") != ARCHIVE_OK) {
skipping("This system cannot convert character-set"
- " from KOI8-R to UTF-8.");
+ " from CP1251 to UTF-8.");
archive_write_free(a);
return;
}
@@ -177,7 +177,7 @@ DEFINE_TEST(test_gnutar_filename_encoding_CP1251_UTF8)
archive_write_open_memory(a, buff, sizeof(buff), &used));
entry = archive_entry_new2(a);
- /* Set a KOI8-R filename. */
+ /* Set a CP1251 filename. */
archive_entry_set_pathname(entry, "\xEF\xF0\xE8");
archive_entry_set_filetype(entry, AE_IFREG);
archive_entry_set_size(entry, 0);
@@ -201,7 +201,7 @@ DEFINE_TEST(test_gnutar_filename_encoding_ru_RU_CP1251)
size_t used;
if (NULL == setlocale(LC_ALL, "ru_RU.CP1251")) {
- skipping("KOI8-R locale not available on this system.");
+ skipping("CP1251 locale not available on this system.");
return;
}
@@ -215,7 +215,7 @@ DEFINE_TEST(test_gnutar_filename_encoding_ru_RU_CP1251)
archive_write_open_memory(a, buff, sizeof(buff), &used));
entry = archive_entry_new2(a);
- /* Set a KOI8-R filename. */
+ /* Set a CP1251 filename. */
archive_entry_set_pathname(entry, "\xEF\xF0\xE8");
archive_entry_set_filetype(entry, AE_IFREG);
archive_entry_set_size(entry, 0);
@@ -389,6 +389,55 @@ DEFINE_TEST(test_gnutar_filename_encoding_CP932_UTF8)
assertEqualMem(buff, "\xE8\xA1\xA8.txt", 7);
}
+/*
+ * A group name whose converted byte length exceeds the 32-byte gname
+ * field used to clamp on strlen() of the converted string instead of its
+ * byte length. With a header charset that embeds NUL bytes (UTF-16),
+ * strlen() stops at the first NUL while the memcpy still used the full
+ * byte length, writing past the 512-byte header buffer.
+ */
+DEFINE_TEST(test_gnutar_filename_encoding_long_gname_utf16)
+{
+ struct archive *a;
+ struct archive_entry *entry;
+ char buff[4096];
+ char gname[256];
+ size_t used;
+
+ a = archive_write_new();
+ assertEqualInt(ARCHIVE_OK, archive_write_set_format_gnutar(a));
+ if (archive_write_set_options(a, "hdrcharset=UTF-16LE") != ARCHIVE_OK) {
+ skipping("This system cannot convert character-set"
+ " to UTF-16LE.");
+ archive_write_free(a);
+ return;
+ }
+ assertEqualInt(ARCHIVE_OK,
+ archive_write_open_memory(a, buff, sizeof(buff), &used));
+
+ memset(gname, 'A', sizeof(gname) - 1);
+ gname[sizeof(gname) - 1] = '\0';
+
+ entry = archive_entry_new2(a);
+ archive_entry_set_pathname(entry, "file");
+ archive_entry_set_filetype(entry, AE_IFREG);
+ archive_entry_set_size(entry, 0);
+ archive_entry_set_gname(entry, gname);
+ assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
+ archive_entry_free(entry);
+ assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+
+ /* The archive is still well-formed; the gname field is truncated to
+ * the 32-byte field, which reads back as "A" (the first UTF-16 unit
+ * before the embedded NUL). */
+ a = archive_read_new();
+ assertEqualInt(ARCHIVE_OK, archive_read_support_format_tar(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_open_memory(a, buff, used));
+ assertEqualInt(ARCHIVE_OK, archive_read_next_header(a, &entry));
+ assertEqualString("A", archive_entry_gname(entry));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
DEFINE_TEST(test_gnutar_filename_encoding_UTF16_win)
{
#if !defined(_WIN32) || defined(__CYGWIN__)
diff --git a/contrib/libarchive/libarchive/test/test_open_filename.c b/contrib/libarchive/libarchive/test/test_open_filename.c
index 09a83690be0d..41e0ff0ee3df 100644
--- a/contrib/libarchive/libarchive/test/test_open_filename.c
+++ b/contrib/libarchive/libarchive/test/test_open_filename.c
@@ -24,6 +24,8 @@
*/
#include "test.h"
+#include <locale.h>
+
static void
test_open_filename_mbs(void)
{
@@ -197,3 +199,24 @@ DEFINE_TEST(test_open_filename)
test_open_filename_mbs();
test_open_filename_wcs();
}
+
+DEFINE_TEST(test_open_filename_wcs_oob)
+{
+ struct archive *a;
+
+ /* Continue even if not available for best test coverage. */
+ setlocale(LC_ALL, "en_US.UTF-8");
+
+ /*
+ * Try to open file with filename which might use more bytes in
+ * MBS representation than in wchar_t if platform uses 16 bit wchar_t,
+ * e.g. Cygwin (3 times a Euro sign, i.e. 3*2+2=8 vs 3*3+1=10 bytes).
+ */
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_FATAL,
+ archive_read_open_filename_w(a, L"\u20AC\u20AC\u20AC", 512));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/contrib/libarchive/libarchive/test/test_pax_filename_encoding.c b/contrib/libarchive/libarchive/test/test_pax_filename_encoding.c
index 27e10eaffc6c..db506c95f7eb 100644
--- a/contrib/libarchive/libarchive/test/test_pax_filename_encoding.c
+++ b/contrib/libarchive/libarchive/test/test_pax_filename_encoding.c
@@ -389,7 +389,7 @@ DEFINE_TEST(test_pax_filename_encoding_CP1251)
if (NULL == setlocale(LC_ALL, "Russian_Russia") &&
NULL == setlocale(LC_ALL, "ru_RU.CP1251")) {
- skipping("KOI8-R locale not available on this system.");
+ skipping("CP1251 locale not available on this system.");
return;
}
@@ -398,7 +398,7 @@ DEFINE_TEST(test_pax_filename_encoding_CP1251)
assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a));
if (archive_write_set_options(a, "hdrcharset=UTF-8") != ARCHIVE_OK) {
skipping("This system cannot convert character-set"
- " from KOI8-R to UTF-8.");
+ " from CP1251 to UTF-8.");
archive_write_free(a);
return;
}
@@ -419,7 +419,7 @@ DEFINE_TEST(test_pax_filename_encoding_CP1251)
archive_entry_free(entry);
assertEqualInt(ARCHIVE_OK, archive_write_free(a));
- /* Above three characters in KOI8-R should translate to the following
+ /* Above three characters in CP1251 should translate to the following
* three characters (two bytes each) in UTF-8. */
assertEqualMem(buff + 512, "15 path=\xD0\xBF\xD1\x80\xD0\xB8\x0A", 15);
}
@@ -483,7 +483,7 @@ DEFINE_TEST(test_pax_filename_encoding_CP932)
if (NULL == setlocale(LC_ALL, "Japanese_Japan") &&
NULL == setlocale(LC_ALL, "ja_JP.SJIS")) {
- skipping("eucJP locale not available on this system.");
+ skipping("CP932/SJIS locale not available on this system.");
return;
}
diff --git a/contrib/libarchive/libarchive/test/test_pax_xattr_header.c b/contrib/libarchive/libarchive/test/test_pax_xattr_header.c
index 8af81079ea7e..ce002b3171bf 100644
--- a/contrib/libarchive/libarchive/test/test_pax_xattr_header.c
+++ b/contrib/libarchive/libarchive/test/test_pax_xattr_header.c
@@ -67,7 +67,7 @@ DEFINE_TEST(test_pax_xattr_header)
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));
+ assertEqualInt(ARCHIVE_OK, archive_write_free(a));
assertEqualFile("test1.tar","test_pax_xattr_header_all.tar");
@@ -86,7 +86,7 @@ DEFINE_TEST(test_pax_xattr_header)
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));
+ assertEqualInt(ARCHIVE_OK, archive_write_free(a));
assertEqualFile("test2.tar","test_pax_xattr_header_schily.tar");
@@ -105,7 +105,7 @@ DEFINE_TEST(test_pax_xattr_header)
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));
+ assertEqualInt(ARCHIVE_OK, archive_write_free(a));
assertEqualFile("test3.tar","test_pax_xattr_header_libarchive.tar");
@@ -123,7 +123,7 @@ DEFINE_TEST(test_pax_xattr_header)
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));
+ assertEqualInt(ARCHIVE_OK, archive_write_free(a));
assertEqualFile("test4.tar","test_pax_xattr_header_all.tar");
}
diff --git a/contrib/libarchive/libarchive/test/test_read_data_into_fd_size_exceeds_declared.c b/contrib/libarchive/libarchive/test/test_read_data_into_fd_size_exceeds_declared.c
new file mode 100644
index 000000000000..a711a380dd0c
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_data_into_fd_size_exceeds_declared.c
@@ -0,0 +1,119 @@
+/*-
+ * Copyright (c) 2026 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"
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#define open _open
+#define close _close
+#endif
+
+/*
+ * archive_read_data_into_fd() writes archive_read_data_block() output
+ * straight to an fd with no notion of the entry's declared size -- it's
+ * used directly by callers like bsdtar's "-O" (stdout) extraction and
+ * bsdcat, which bypass archive_write_disk (and the size-truncation
+ * safeguard archive_write_disk already has). This is a format-agnostic
+ * backstop for that gap: it must never write more than the entry's
+ * declared size, regardless of which format reader produced the data
+ * or whether that reader independently enforces its own size boundary.
+ *
+ * The reference archives are crafted ZIP files (a stored entry whose
+ * physical body is longer than its declared size, and a deflate entry
+ * whose real inflated output exceeds 256KiB so it can't complete within
+ * a single internal decode call -- see zip_read_data_deflate()'s
+ * internal output buffer). Each has two entries: "first" declares
+ * uncompressed_size=10 but its real content is longer, and "second" is
+ * a well-formed 11-byte "hello world" file, read right after "first"
+ * fails to confirm the mis-declared entry doesn't disrupt the rest of
+ * the archive. This test is deliberately independent of the ZIP reader
+ * itself enforcing this boundary -- archive_read_data_into_fd() must
+ * cap its own output regardless of whether the format reader does.
+ */
+static void
+verify(const char *refname)
+{
+ struct archive *a;
+ struct archive_entry *ae;
+ char tmpfilename[] = "data_into_fd_test";
+ int fd;
+ char buff[32];
+ size_t n;
+ FILE *f;
+
+ extract_reference_file(refname);
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_filename(a, refname, 10240));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("first", archive_entry_pathname(ae));
+ assertEqualInt(10, archive_entry_size(ae));
+
+ fd = open(tmpfilename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+ assert(fd >= 0);
+ failure("archive_read_data_into_fd() must report an error when the "
+ "entry's actual data exceeds its declared size");
+ assert(archive_read_data_into_fd(a, fd) != ARCHIVE_OK);
+ close(fd);
+
+ f = fopen(tmpfilename, "rb");
+ assert(f != NULL);
+ n = fread(buff, 1, sizeof(buff), f);
+ fclose(f);
+ failure("archive_read_data_into_fd() must never write more bytes "
+ "than the entry's declared size");
+ assert(n <= 10);
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("second", archive_entry_pathname(ae));
+ assertEqualInt(11, archive_entry_size(ae));
+
+ fd = open(tmpfilename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+ assert(fd >= 0);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_data_into_fd(a, fd));
+ close(fd);
+
+ f = fopen(tmpfilename, "rb");
+ assert(f != NULL);
+ n = fread(buff, 1, sizeof(buff), f);
+ fclose(f);
+ assertEqualInt(11, (int)n);
+ assertEqualMem(buff, "hello world", 11);
+
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
+DEFINE_TEST(test_read_data_into_fd_size_exceeds_declared_stored)
+{
+ verify("test_read_data_into_fd_size_exceeds_declared_stored.zip");
+}
+
+DEFINE_TEST(test_read_data_into_fd_size_exceeds_declared_deflate)
+{
+ verify("test_read_data_into_fd_size_exceeds_declared_deflate.zip");
+}
diff --git a/contrib/libarchive/libarchive/test/test_read_data_into_fd_size_exceeds_declared_deflate.zip.uu b/contrib/libarchive/libarchive/test/test_read_data_into_fd_size_exceeds_declared_deflate.zip.uu
new file mode 100644
index 000000000000..12f633e45b6a
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_data_into_fd_size_exceeds_declared_deflate.zip.uu
@@ -0,0 +1,23 @@
+begin 644 test_read_data_into_fd_size_exceeds_declared_deflate.zip
+M4$L#!!0````(``````#"V8Q_D`(```H````%````9FER<W3MR#$!```(P*!P
+MLW\F+TT!)W7FY9QSSCGGG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGG
+MG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGG
+MG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGG
+MG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGG
+MG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGG
+MG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGG
+MG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGG
+MG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGG
+MG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGG
+MG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGG
+MG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGG
+MG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGG
+MG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGG
+MG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGGG'/..>><<\XYYYQSSCGG
+MG'/..>><<\XYYYQSSCG7`E!+`P04````````````A1%*#0L````+````!@``
+M`'-E8V]N9&AE;&QO('=O<FQD4$L!`A0`%`````@``````,+9C'^0`@``"@``
+M``4``````````````````````&9I<G-T4$L!`A0`%````````````(412@T+
+M````"P````8`````````````````LP(``'-E8V]N9%!+!08``````@`"`&<`
+(``#B`@``````
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_data_into_fd_size_exceeds_declared_stored.zip.uu b/contrib/libarchive/libarchive/test/test_read_data_into_fd_size_exceeds_declared_stored.zip.uu
new file mode 100644
index 000000000000..228ca983f0b6
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_data_into_fd_size_exceeds_declared_stored.zip.uu
@@ -0,0 +1,9 @@
+begin 644 test_read_data_into_fd_size_exceeds_declared_stored.zip
+M4$L#!!0```````````#-F1X3%`````H````%````9FER<W1!04%!04%!04%!
+M0D)"0D)"0D)"0E!+`P04````````````A1%*#0L````+````!@```'-E8V]N
+M9&AE;&QO('=O<FQD4$L!`A0`%````````````,V9'A,4````"@````4`````
+M`````````````````&9I<G-T4$L!`A0`%````````````(412@T+````"P``
+M``8`````````````````-P```'-E8V]N9%!+!08``````@`"`&<```!F````
+"````
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_data_large.c b/contrib/libarchive/libarchive/test/test_read_data_large.c
index 59cbfd496ca9..37182349cc42 100644
--- a/contrib/libarchive/libarchive/test/test_read_data_large.c
+++ b/contrib/libarchive/libarchive/test/test_read_data_large.c
@@ -35,6 +35,7 @@
#if defined(_WIN32) && !defined(__CYGWIN__)
#define open _open
#define close _close
+#define ftruncate _chsize
#endif
static char buff1[11000000];
@@ -108,3 +109,94 @@ DEFINE_TEST(test_read_data_large)
fclose(f);
assertEqualMem(buff2, buff3, sizeof(buff3));
}
+
+#define FILE_SIZE 0x90000 /* 576 KiB total logical size */
+
+static char sparse_buff[0x10000]; /* Holds the (small) stored archive. */
+static char sparse_data[FILE_SIZE];
+static char sparse_expected[FILE_SIZE];
+
+/*
+ * Regression test for archive_read_data_into_fd() extracting a sparse
+ * file that ends in a hole. For a sparse entry libarchive seeks the
+ * destination descriptor forward to recreate holes. The trailing hole
+ * is created from the EOF handling after the last data block.
+ */
+DEFINE_TEST(test_read_data_into_fd_sparse)
+{
+ struct archive *a;
+ struct archive_entry *ae;
+ size_t archive_size = 0;
+ const char *skip_sparse_tests;
+ int fd;
+
+ skip_sparse_tests = getenv("SKIP_TEST_SPARSE");
+ if (skip_sparse_tests != NULL) {
+ skipping("Skipping sparse tests due to SKIP_TEST_SPARSE "
+ "environment variable");
+ return;
+ }
+
+ /*
+ * The logical file is all 'a', and the sparse map marks two data
+ * regions, everything else (including the tail) is a hole that
+ * must read back as zero. The last data region ends at 0x81000
+ * while the file size is 0x90000, so the file ends in a hole.
+ */
+ memset(sparse_data, 'a', sizeof(sparse_data));
+ memset(sparse_expected, 0, sizeof(sparse_expected));
+ memset(sparse_expected + 0x10000, 'a', 0x1000);
+ memset(sparse_expected + 0x80000, 'a', 0x1000);
+
+ /* Create a sparse pax archive in memory. */
+ assert((a = archive_write_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_pax(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_none(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, sparse_buff,
+ sizeof(sparse_buff), &archive_size));
+
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "file");
+ archive_entry_set_mode(ae, S_IFREG | 0644);
+ archive_entry_set_size(ae, FILE_SIZE);
+ archive_entry_sparse_add_entry(ae, 0x10000, 0x1000);
+ archive_entry_sparse_add_entry(ae, 0x80000, 0x1000);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
+ archive_entry_free(ae);
+ assertEqualIntA(a, FILE_SIZE,
+ archive_write_data(a, sparse_data, sizeof(sparse_data)));
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+
+ /* Read it back and extract it into a real file descriptor. */
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_memory(a, sparse_buff, archive_size));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualInt(FILE_SIZE, archive_entry_size(ae));
+
+ fd = open("file", O_WRONLY | O_CREAT | O_BINARY, 0644);
+ assert(fd >= 0);
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_data_into_fd(a, fd));
+
+ /*
+ * archive_read_data_into_fd() seeks over the trailing hole but, like
+ * a regular extraction, leaves the on-disk size short. Truncate up
+ * to the full size to realize the final hole, as a consumer does.
+ */
+ assert(ftruncate(fd, FILE_SIZE) != -1);
+ close(fd);
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+
+ /*
+ * The reconstructed file must match byte for byte: data regions
+ * are 'a', every hole (including the trailing one) is zero.
+ */
+ assertFileSize("file", FILE_SIZE);
+ assertFileContents(sparse_expected, FILE_SIZE, "file");
+}
diff --git a/contrib/libarchive/libarchive/test/test_read_disk_directory_traversals.c b/contrib/libarchive/libarchive/test/test_read_disk_directory_traversals.c
index 7597f4b6f6eb..718818c36b53 100644
--- a/contrib/libarchive/libarchive/test/test_read_disk_directory_traversals.c
+++ b/contrib/libarchive/libarchive/test/test_read_disk_directory_traversals.c
@@ -230,7 +230,7 @@ test_basic(void)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
/* Close the disk object. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
/*
* Test that call archive_read_disk_open_w, wchar_t version.
@@ -358,7 +358,7 @@ test_basic(void)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
/* Close the disk object. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
/*
* Test that call archive_read_disk_open with a regular file.
@@ -381,7 +381,7 @@ test_basic(void)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
/* Close the disk object. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
#if defined(_WIN32) && !defined(__CYGWIN__)
@@ -427,7 +427,7 @@ test_basic(void)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
/* Close the disk object. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
/*
* Test for a full-path beginning with "//?/"
@@ -458,7 +458,7 @@ test_basic(void)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
/* Close the disk object. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
free(fullpath);
/*
@@ -515,7 +515,7 @@ test_basic(void)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
/* Close the disk object. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
free(fullpath);
#endif
@@ -658,7 +658,7 @@ test_symlink_hybrid(void)
/* There is no entry. */
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
/* Close the disk object. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
/*
* Specified file is a directory and it has symbolic files.
@@ -722,7 +722,7 @@ test_symlink_hybrid(void)
/* There is no entry. */
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
/* Close the disk object. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
/* Destroy the disk object. */
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
archive_entry_free(ae);
@@ -827,7 +827,7 @@ test_symlink_logical(void)
/* There is no entry. */
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
/* Close the disk object. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
/*
* Specified file is a directory and it has symbolic files.
@@ -953,7 +953,7 @@ test_symlink_logical(void)
/* There is no entry. */
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
/* Close the disk object. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
/* Destroy the disk object. */
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -1131,7 +1131,7 @@ test_restore_atime(void)
assertFileAtime("at/fe", 886611, 0);
/* Close the disk object. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
/*
* Test2: Traversals with archive_read_disk_set_atime_restored().
@@ -1197,7 +1197,7 @@ test_restore_atime(void)
assertFileAtime("at/fe", 886611, 0);
/* Close the disk object. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
/*
* Test3: Traversals with archive_read_disk_set_atime_restored() but
@@ -1254,7 +1254,7 @@ test_restore_atime(void)
}
/* Close the disk object. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
/*
* Test4: Traversals with ARCHIVE_READDISK_RESTORE_ATIME and
@@ -1406,7 +1406,7 @@ test_callbacks(void)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
/* Close the disk object. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
/* Reset name filter */
assertEqualIntA(a, ARCHIVE_OK,
@@ -1539,7 +1539,7 @@ test_nodump(void)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
/* Close the disk object. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
/*
* Test2: Traversals with ARCHIVE_READDISK_HONOR_NODUMP
@@ -1671,7 +1671,7 @@ test_parent(void)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
/* Close the disk object. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertChdir("../..");
@@ -1720,7 +1720,7 @@ test_parent(void)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
/* Close the disk object. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
/*
* Test3: Traverse lock/dir1/.
@@ -1767,7 +1767,7 @@ test_parent(void)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
/* Close the disk object. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
/*
* Test4: Traverse lock/lock2/dir1 from inside lock.
@@ -1842,7 +1842,7 @@ test_parent(void)
archive_read_next_header2(a, ae));
/* Close the disk object. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
}
assertChdir("..");
diff --git a/contrib/libarchive/libarchive/test/test_archive_write_set_filter_option.c b/contrib/libarchive/libarchive/test/test_read_files_compressed.c
index 6b90a831b469..4795d750baa3 100644
--- a/contrib/libarchive/libarchive/test/test_archive_write_set_filter_option.c
+++ b/contrib/libarchive/libarchive/test/test_read_files_compressed.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2011 Tim Kientzle
+ * Copyright (c) 2026 Tobias Stoeckmann
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -22,33 +22,27 @@
* (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"
-#define should(__a, __code, __m, __o, __v) \
-assertEqualInt(__code, archive_write_set_filter_option(__a, __m, __o, __v))
-
-static void
-test(int pristine)
+DEFINE_TEST(test_read_files_compressed)
{
- struct archive* a = archive_write_new();
-
- if (!pristine)
- archive_write_add_filter_gzip(a);
+ const char *reffiles[] =
+ {
+ "test_read_files_compressed.part01",
+ "test_read_files_compressed.part02",
+ NULL
+ };
- should(a, ARCHIVE_OK, NULL, NULL, NULL);
- should(a, ARCHIVE_OK, "", "", "");
+ struct archive *a;
+ struct archive_entry *entry = NULL;
- should(a, ARCHIVE_FAILED, NULL, "fubar", NULL);
- should(a, ARCHIVE_FAILED, NULL, "fubar", "snafu");
- should(a, ARCHIVE_FAILED, "fubar", "snafu", NULL);
- should(a, ARCHIVE_FAILED, "fubar", "snafu", "betcha");
+ extract_reference_files(reffiles);
+ assert((a = archive_read_new()) != NULL);
+ assertA(0 == archive_read_support_filter_all(a));
+ assertA(0 == archive_read_support_format_all(a));
+ assertA(0 == archive_read_open_filenames(a, reffiles, 10240));
- archive_write_free(a);
-}
-
-DEFINE_TEST(test_archive_write_set_filter_option)
-{
- test(1);
- test(0);
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &entry));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_files_compressed.part01.uu b/contrib/libarchive/libarchive/test/test_read_files_compressed.part01.uu
new file mode 100644
index 000000000000..346545a0dc8d
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_files_compressed.part01.uu
@@ -0,0 +1,4 @@
+begin 644 test_read_files_compressed.part01
+"'YT`
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_files_compressed.part02.uu b/contrib/libarchive/libarchive/test/test_read_files_compressed.part02.uu
new file mode 100644
index 000000000000..41e440391ae8
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_files_compressed.part02.uu
@@ -0,0 +1,4 @@
+begin 644 test_read_files_compressed.part02
+!````
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_filter_compress.c b/contrib/libarchive/libarchive/test/test_read_filter_compress.c
index 03a1d5fbe9c0..d03fdc9d6344 100644
--- a/contrib/libarchive/libarchive/test/test_read_filter_compress.c
+++ b/contrib/libarchive/libarchive/test/test_read_filter_compress.c
@@ -35,7 +35,7 @@ DEFINE_TEST(test_read_filter_compress_truncated)
assertEqualIntA(a, ARCHIVE_FATAL,
archive_read_open_memory(a, data, sizeof(data)));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -59,7 +59,7 @@ DEFINE_TEST(test_read_filter_compress_empty2)
assertEqualString(archive_filter_name(a, 0), "compress (.Z)");
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_EMPTY);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -75,6 +75,6 @@ DEFINE_TEST(test_read_filter_compress_invalid)
assertEqualIntA(a, ARCHIVE_FATAL,
archive_read_open_memory(a, data, sizeof(data)));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_filter_grzip.c b/contrib/libarchive/libarchive/test/test_read_filter_grzip.c
index 43bd5bca2658..7e58a621007f 100644
--- a/contrib/libarchive/libarchive/test/test_read_filter_grzip.c
+++ b/contrib/libarchive/libarchive/test/test_read_filter_grzip.c
@@ -62,6 +62,6 @@ DEFINE_TEST(test_read_filter_grzip)
assertEqualString(archive_filter_name(a, 0), "grzip");
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_filter_gzip_recursive.c b/contrib/libarchive/libarchive/test/test_read_filter_gzip_recursive.c
index 51b614b6c023..56889820e666 100644
--- a/contrib/libarchive/libarchive/test/test_read_filter_gzip_recursive.c
+++ b/contrib/libarchive/libarchive/test/test_read_filter_gzip_recursive.c
@@ -45,6 +45,6 @@ DEFINE_TEST(test_read_filter_gzip_recursive)
assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_GZIP);
assertEqualString(archive_filter_name(a, 0), "gzip");
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_filter_lrzip.c b/contrib/libarchive/libarchive/test/test_read_filter_lrzip.c
index 47388da0fb89..5caeb0fe5781 100644
--- a/contrib/libarchive/libarchive/test/test_read_filter_lrzip.c
+++ b/contrib/libarchive/libarchive/test/test_read_filter_lrzip.c
@@ -62,6 +62,6 @@ DEFINE_TEST(test_read_filter_lrzip)
assertEqualString(archive_filter_name(a, 0), "lrzip");
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_GNUTAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_archive_read_set_filter_option.c b/contrib/libarchive/libarchive/test/test_read_filter_lz4_raw.c
index 68494abbc1e9..9cbb561e570d 100644
--- a/contrib/libarchive/libarchive/test/test_archive_read_set_filter_option.c
+++ b/contrib/libarchive/libarchive/test/test_read_filter_lz4_raw.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2011 Tim Kientzle
+ * Copyright (c) 2026 Tobias Stoeckmann
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -22,33 +22,19 @@
* (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"
-#define should(__a, __code, __m, __o, __v) \
-assertEqualInt(__code, archive_read_set_filter_option(__a, __m, __o, __v))
-
-static void
-test(int pristine)
+DEFINE_TEST(test_read_filter_lz4_raw_skip)
{
- struct archive* a = archive_read_new();
-
- if (!pristine)
- archive_read_support_filter_all(a);
-
- should(a, ARCHIVE_OK, NULL, NULL, NULL);
- should(a, ARCHIVE_OK, "", "", "");
+ struct archive *a;
- should(a, ARCHIVE_FAILED, NULL, "fubar", NULL);
- should(a, ARCHIVE_FAILED, NULL, "fubar", "snafu");
- should(a, ARCHIVE_FAILED, "fubar", "snafu", NULL);
- should(a, ARCHIVE_FAILED, "fubar", "snafu", "betcha");
+ const char *name = "test_read_filter_lz4_raw_skip";
- archive_read_free(a);
-}
-
-DEFINE_TEST(test_archive_read_set_filter_option)
-{
- test(1);
- test(0);
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_raw(a));
+ extract_reference_file(name);
+ assertEqualIntA(a, ARCHIVE_FATAL,
+ archive_read_open_filename(a, name, 200));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_filter_lz4_raw_skip.uu b/contrib/libarchive/libarchive/test/test_read_filter_lz4_raw_skip.uu
new file mode 100644
index 000000000000..aaff306b80bf
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_filter_lz4_raw_skip.uu
@@ -0,0 +1,4 @@
+begin 644 test_read_filter_lz4_raw_skip.uu
+<!")-&&1`IP$``(`*`````%+3R8%0*DT8_/___P``
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_filter_lzop.c b/contrib/libarchive/libarchive/test/test_read_filter_lzop.c
index acce6a4c2052..1d4d4f9352a5 100644
--- a/contrib/libarchive/libarchive/test/test_read_filter_lzop.c
+++ b/contrib/libarchive/libarchive/test/test_read_filter_lzop.c
@@ -72,6 +72,6 @@ DEFINE_TEST(test_read_filter_lzop)
assertEqualString(archive_filter_name(a, 0), "lzop");
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_filter_lzop_multiple_parts.c b/contrib/libarchive/libarchive/test/test_read_filter_lzop_multiple_parts.c
index 82eaf3539473..677f729a7133 100644
--- a/contrib/libarchive/libarchive/test/test_read_filter_lzop_multiple_parts.c
+++ b/contrib/libarchive/libarchive/test/test_read_filter_lzop_multiple_parts.c
@@ -71,6 +71,6 @@ DEFINE_TEST(test_read_filter_lzop_multiple_parts)
assertEqualString(archive_filter_name(a, 0), "lzop");
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_filter_program.c b/contrib/libarchive/libarchive/test/test_read_filter_program.c
index 18b42121cc22..bd584f5086f7 100644
--- a/contrib/libarchive/libarchive/test/test_read_filter_program.c
+++ b/contrib/libarchive/libarchive/test/test_read_filter_program.c
@@ -77,6 +77,8 @@ DEFINE_TEST(test_read_filter_program)
archive_read_next_header(a, &ae));
assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_PROGRAM);
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR);
+ assertEqualString("Program: gzip -d", archive_filter_name(a, 0));
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualString("Program: gzip -d", archive_filter_name(a, 0));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_filter_uudecode_raw.c b/contrib/libarchive/libarchive/test/test_read_filter_uudecode_raw.c
index 6f02dc5de147..99f5b43f60cb 100644
--- a/contrib/libarchive/libarchive/test/test_read_filter_uudecode_raw.c
+++ b/contrib/libarchive/libarchive/test/test_read_filter_uudecode_raw.c
@@ -41,7 +41,7 @@ DEFINE_TEST(test_read_filter_uudecode_raw)
assertEqualInt((AE_IFREG | 0755), archive_entry_mode(ae));
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -62,6 +62,6 @@ DEFINE_TEST(test_read_filter_uudecode_base64_raw)
assertEqualInt((AE_IFREG | 0600), archive_entry_mode(ae));
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_archive_read_close_twice_open_fd.c b/contrib/libarchive/libarchive/test/test_read_filter_zstd_raw.c
index 62a6a90df1fa..5a4ea91c6e1f 100644
--- a/contrib/libarchive/libarchive/test/test_archive_read_close_twice_open_fd.c
+++ b/contrib/libarchive/libarchive/test/test_read_filter_zstd_raw.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2011 Tim Kientzle
+ * Copyright (c) 2026 Tobias Stoeckmann
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -22,25 +22,25 @@
* (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"
-DEFINE_TEST(test_archive_read_close_twice_open_fd)
+DEFINE_TEST(test_read_filter_zstd_raw_loop)
{
- struct archive* a = archive_read_new();
+ struct archive *a;
- assertEqualInt(ARCHIVE_OK, archive_read_support_format_empty(a));
- assertEqualInt(ARCHIVE_OK, archive_read_open_fd(a, 0, 0));
- assertEqualInt(0, archive_errno(a));
- assertEqualString(NULL, archive_error_string(a));
+ const char *name = "test_read_filter_zstd_raw_loop";
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
- assertEqualInt(0, archive_errno(a));
- assertEqualString(NULL, archive_error_string(a));
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_raw(a));
+ extract_reference_file(name);
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_filename(a, name, 200));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
- assertEqualInt(0, archive_errno(a));
- assertEqualString(NULL, archive_error_string(a));
+ /* Verify that the filter detection did NOT work. */
+ assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_NONE);
+ assertEqualString(archive_filter_name(a, 0), "none");
+ assertEqualInt(ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_filter_zstd_raw_loop.uu b/contrib/libarchive/libarchive/test/test_read_filter_zstd_raw_loop.uu
new file mode 100644
index 000000000000..932715669aa7
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_filter_zstd_raw_loop.uu
@@ -0,0 +1,4 @@
+begin 644 test_read_filter_zstd_raw_loop
+,4"I-&/C___\HM2_]
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_7zip.c b/contrib/libarchive/libarchive/test/test_read_format_7zip.c
index 6d71f80d12ed..66b5930e4319 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_7zip.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_7zip.c
@@ -82,7 +82,7 @@ test_copy(int use_open_fd)
assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
if (fd != -1)
close(fd);
@@ -115,7 +115,7 @@ test_empty_archive(void)
assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -156,7 +156,33 @@ test_empty_file(void)
assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
+DEFINE_TEST(test_read_format_7zip_archive_properties)
+{
+ const char *refname = "test_read_format_7zip_archive_properties.7z";
+ struct archive_entry *ae;
+ struct archive *a;
+
+ extract_reference_file(refname);
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_filename(a, refname, 10240));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("empty", archive_entry_pathname(ae));
+ assertEqualInt(0, archive_entry_size(ae));
+ assertEqualInt(1, archive_file_count(a));
+
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+ assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -199,7 +225,7 @@ test_plain_header(const char *refname)
assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -284,7 +310,7 @@ test_extract_all_files(const char *refname)
assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -369,7 +395,7 @@ test_extract_all_files_zstd(const char *refname)
assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -419,7 +445,7 @@ test_extract_file_zstd_bcj_nobjc(const char *refname)
assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -498,7 +524,7 @@ test_extract_last_file(const char *refname)
assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -629,7 +655,7 @@ test_extract_all_files2(const char *refname)
assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -685,7 +711,7 @@ test_delta_lzma(const char *refname)
assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -741,7 +767,7 @@ test_bcj(const char *refname)
assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -798,7 +824,7 @@ test_ppmd(void)
assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -847,7 +873,7 @@ test_symname(void)
assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -1081,7 +1107,7 @@ test_arm_filter(const char *refname)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -1155,7 +1181,7 @@ test_arm64_filter(const char *refname)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -1383,6 +1409,47 @@ DEFINE_TEST(test_read_format_7zip_sfx_elf)
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
+static void
+test_sfx_boundary_empty_7z(const char *refname)
+{
+ struct archive_entry *ae = NULL;
+ struct archive *a;
+ const int bs = 10240;
+
+ extract_reference_file(refname);
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_filename(a, refname, bs));
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+ assertEqualInt(0, archive_file_count(a));
+ assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
+DEFINE_TEST(test_read_format_7zip_sfx_boundary_pe)
+{
+ /*
+ * The embedded empty 7z archive starts at the final exact
+ * 32-byte scan window after the PE overlay offset.
+ */
+ test_sfx_boundary_empty_7z(
+ "test_read_format_7zip_sfx_boundary_pe.exe");
+}
+
+DEFINE_TEST(test_read_format_7zip_sfx_boundary_elf)
+{
+ /*
+ * The ELF section string table contains "\0.data\0", so
+ * ".data\0" starts at the final valid string-table position.
+ */
+ test_sfx_boundary_empty_7z(
+ "test_read_format_7zip_sfx_boundary_elf.elf");
+}
+
/*
* A truncated ELF 64-bit MSB file.
*/
@@ -1404,7 +1471,7 @@ DEFINE_TEST(test_read_format_7zip_sfx_elf64trunc)
assertEqualIntA(a, ARCHIVE_FATAL, archive_read_next_header(a, &ae));
assertEqualInt(0, archive_file_count(a));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -1476,8 +1543,8 @@ test_riscv_filter(const char *refname)
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualInt((AE_IFREG | 0775), archive_entry_mode(ae));
assertEqualString("hw-riscv64", archive_entry_pathname(ae));
- assertEqualInt(sizeof(buff), archive_entry_size(ae));
- assertEqualInt(sizeof(buff), archive_read_data(a, buff, sizeof(buff)));
+ assertEqualIntA(a, sizeof(buff), archive_entry_size(ae));
+ assertEqualIntA(a, sizeof(buff), archive_read_data(a, buff, sizeof(buff)));
computed_crc = bitcrc32(computed_crc, buff, sizeof(buff));
assertEqualInt(computed_crc, expected_crc);
@@ -1486,7 +1553,7 @@ test_riscv_filter(const char *refname)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
#endif
@@ -1500,9 +1567,12 @@ DEFINE_TEST(test_read_format_7zip_lzma2_riscv)
if (ARCHIVE_OK != archive_read_support_filter_lzma(a)) {
skipping("7zip:lzma decoding is not supported on this platform");
+ } else if (!lzma_filter_decoder_is_supported(LZMA_FILTER_RISCV)) {
+ skipping("liblzma does not support RISC-V BCJ filter at runtime");
} else {
test_riscv_filter("test_read_format_7zip_lzma2_riscv.7z");
}
+ archive_read_free(a);
#else
skipping("This version of liblzma does not support LZMA_FILTER_RISCV");
#endif
@@ -1543,7 +1613,7 @@ test_sparc_filter(const char *refname)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
free(buff);
@@ -1616,7 +1686,7 @@ test_powerpc_filter(const char *refname)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
free(buff);
diff --git a/contrib/libarchive/libarchive/test/test_read_format_7zip_archive_properties.7z.uu b/contrib/libarchive/libarchive/test/test_read_format_7zip_archive_properties.7z.uu
new file mode 100644
index 000000000000..b5759d932401
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_7zip_archive_properties.7z.uu
@@ -0,0 +1,5 @@
+begin 644 test_read_format_7zip_archive_properties.7z
+M-WJ\KR<< ,=YJHC S '@@J#,! @$!J@ % 0X!@ \!
+F@!$- &4 ;0!P '0 >0 !0* 0" UD J+*= 14& 0 @@*2!
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_7zip_encryption_data.c b/contrib/libarchive/libarchive/test/test_read_format_7zip_encryption_data.c
index 653044a46317..c8c8ff06b153 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_7zip_encryption_data.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_7zip_encryption_data.c
@@ -51,7 +51,7 @@ DEFINE_TEST(test_read_format_7zip_encryption_data)
assertEqualInt(1, archive_entry_is_data_encrypted(ae));
assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));
assertEqualIntA(a, 1, archive_read_has_encrypted_entries(a));
- assertEqualInt(ARCHIVE_FATAL, archive_read_data(a, buff, sizeof(buff)));
+ assertEqualInt(ARCHIVE_FAILED, archive_read_data(a, buff, sizeof(buff)));
assertEqualInt(1, archive_file_count(a));
@@ -63,7 +63,7 @@ DEFINE_TEST(test_read_format_7zip_encryption_data)
assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_7zip_encryption_header.c b/contrib/libarchive/libarchive/test/test_read_format_7zip_encryption_header.c
index d0c48044ea5e..409c11e1aae0 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_7zip_encryption_header.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_7zip_encryption_header.c
@@ -65,7 +65,7 @@ DEFINE_TEST(test_read_format_7zip_encryption_header)
assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_7zip_encryption_partially.c b/contrib/libarchive/libarchive/test/test_read_format_7zip_encryption_partially.c
index 51a6c06116d7..ac168a35343b 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_7zip_encryption_partially.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_7zip_encryption_partially.c
@@ -63,12 +63,12 @@ DEFINE_TEST(test_read_format_7zip_encryption_partially)
assertEqualInt(1, archive_entry_is_data_encrypted(ae));
assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));
assertEqualIntA(a, 1, archive_read_has_encrypted_entries(a));
- assertEqualInt(ARCHIVE_FATAL, archive_read_data(a, buff, sizeof(buff)));
+ assertEqualInt(ARCHIVE_FAILED, archive_read_data(a, buff, sizeof(buff)));
assertEqualInt(2, archive_file_count(a));
/* End of archive. */
- assertEqualIntA(a, ARCHIVE_FATAL, archive_read_next_header(a, &ae));
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
}
/* Verify archive format. */
@@ -76,6 +76,6 @@ DEFINE_TEST(test_read_format_7zip_encryption_partially)
assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_7zip_entries_oom.7z.uu b/contrib/libarchive/libarchive/test/test_read_format_7zip_entries_oom.7z.uu
new file mode 100644
index 000000000000..3339d0367c31
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_7zip_entries_oom.7z.uu
@@ -0,0 +1,8 @@
+begin 644 test_read_format_7zip_entries_oom.7z
+M-WJ\KR<<``,%;\HA```````````N`````````,Z^!W,!!>'AX>'AX>'AX>'A
+MX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'A
+MX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'A
+MX>'AX>'AX>'AX0$.`8`/`8`1#0!E`&T`<`!T`'D````4"@$`@-9``*BRG0$5
+)!@$`(("D@0``
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_7zip_entries_oom.c b/contrib/libarchive/libarchive/test/test_read_format_7zip_entries_oom.c
new file mode 100644
index 000000000000..8c7a77992469
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_7zip_entries_oom.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2026 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"
+
+/*
+ * A 7z archive whose FilesInfo section declares far more files than the
+ * remaining header bytes can structurally support previously caused
+ * libarchive to attempt a ~2.5 GiB calloc(). The fix rejects the file
+ * count before allocating: empty-file entries require a kEmptyStream
+ * bitmap of ceil(numFiles/8) bytes, so numFiles beyond the known stream
+ * count cannot exceed 8 * header_bytes_remaining.
+ */
+DEFINE_TEST(test_read_format_7zip_entries_oom)
+{
+ const char *refname = "test_read_format_7zip_entries_oom.7z";
+ struct archive *a;
+ struct archive_entry *ae;
+
+ extract_reference_file(refname);
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_filename(a, refname, 10240));
+
+ /*
+ * Header parsing must fail gracefully rather than attempting a
+ * multi-gigabyte allocation for the entry array.
+ */
+ assertEqualIntA(a, ARCHIVE_FATAL, archive_read_next_header(a, &ae));
+
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_7zip_folders_oom.7z.uu b/contrib/libarchive/libarchive/test/test_read_format_7zip_folders_oom.7z.uu
new file mode 100644
index 000000000000..682ffb8ce422
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_7zip_folders_oom.7z.uu
@@ -0,0 +1,8 @@
+begin 644 test_read_format_7zip_folders_oom.7z
+M-WJ\KR<< *^Y_3?$ !E &/C(9T! -A86$* $ V)B
+M8@H 00& ()" @* 5\J+KLX07WL <+XR&= 0 #86%A"@ ! -B8F(* $$
+M!@ ""0@( @ !(2$!%@$A,@$6# 0$"@&57?ASX1\F3 ( % A,9 &$ +@!T
+M '@ = #_ !X '0 4 0 #80 &/C(9T! -A86$* $
+0 V+<MM4!@)N8]-RVU0$
+
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_7zip_folders_oom.c b/contrib/libarchive/libarchive/test/test_read_format_7zip_folders_oom.c
new file mode 100644
index 000000000000..53342dfc0375
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_7zip_folders_oom.c
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 2026 Kaif Khan
+ * 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"
+
+/*
+ * The NumFolders field in a 7-Zip StreamsInfo/CodersInfo header is used to
+ * size the folders allocation before any folder is read. A crafted archive
+ * that declares a huge NumFolders must be rejected instead of attempting a
+ * multi-gigabyte allocation.
+ */
+DEFINE_TEST(test_read_format_7zip_folders_oom)
+{
+ const char *refname = "test_read_format_7zip_folders_oom.7z";
+ struct archive *a;
+ struct archive_entry *ae;
+
+ extract_reference_file(refname);
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_filename(a, refname, 10240));
+
+ assertEqualIntA(a, ARCHIVE_FATAL, archive_read_next_header(a, &ae));
+
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_7zip_issue2765.c b/contrib/libarchive/libarchive/test/test_read_format_7zip_issue2765.c
index 7c45c313b315..3232a87ef9f2 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_7zip_issue2765.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_7zip_issue2765.c
@@ -46,6 +46,6 @@ DEFINE_TEST(test_read_format_7zip_issue2765)
assertEqualInt(0, archive_file_count(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_7zip_malformed.c b/contrib/libarchive/libarchive/test/test_read_format_7zip_malformed.c
index bd3452c00aad..22c258fd03c7 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_7zip_malformed.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_7zip_malformed.c
@@ -39,7 +39,7 @@ test_malformed1(void)
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240));
assertEqualIntA(a, ARCHIVE_FATAL, archive_read_next_header(a, &ae));
- assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
static void
@@ -56,7 +56,7 @@ test_malformed2(void)
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240));
assertEqualIntA(a, ARCHIVE_FATAL, archive_read_next_header(a, &ae));
- assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -72,7 +72,42 @@ test_malformed3(void)
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
assertEqualIntA(a, ARCHIVE_FATAL, archive_read_open_filename(a, refname, 10240));
- assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
+
+static void
+test_malformed4(void)
+{
+ const char *refname = "test_read_format_7zip_malformed4.7z";
+ struct archive *a;
+ struct archive_entry *ae;
+
+ extract_reference_file(refname);
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240));
+ assertEqualIntA(a, ARCHIVE_FATAL, archive_read_next_header(a, &ae));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
+static void
+test_malformed_numfiles_oom(void)
+{
+ const char *refname = "test_read_format_7zip_malformed_numfiles_oom.7z";
+ struct archive *a;
+ struct archive_entry *ae;
+
+ extract_reference_file(refname);
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240));
+ assertEqualIntA(a, ARCHIVE_FATAL, archive_read_next_header(a, &ae));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
DEFINE_TEST(test_read_format_7zip_malformed)
@@ -80,4 +115,6 @@ DEFINE_TEST(test_read_format_7zip_malformed)
test_malformed1();
test_malformed2();
test_malformed3();
+ test_malformed4();
+ test_malformed_numfiles_oom();
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_7zip_malformed4.7z.uu b/contrib/libarchive/libarchive/test/test_read_format_7zip_malformed4.7z.uu
new file mode 100644
index 000000000000..45597aa13ac4
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_7zip_malformed4.7z.uu
@@ -0,0 +1,5 @@
+begin 644 test_read_format_7zip_malformed4.7z
+M-WJ\KR<<``0N^]EU```````````9`````````&WKXL4!!`8``0D```<+`0`!
+,`0`,```(#0(`````
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_7zip_malformed_numfiles_oom.7z.uu b/contrib/libarchive/libarchive/test/test_read_format_7zip_malformed_numfiles_oom.7z.uu
new file mode 100644
index 000000000000..bb1f75efa163
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_7zip_malformed_numfiles_oom.7z.uu
@@ -0,0 +1,5 @@
+begin 644 test_read_format_7zip_malformed_numfiles_oom.7z
+M-WJ\KR<<``,%;\HA```````````N`````````,Z^!W,!!>,.`8`/`8`1#0!E
+A`&T`<`!T`'D````4"@$`@-9``*BRG0$5!@$`(("D@0``
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_7zip_packinfo_digests.c b/contrib/libarchive/libarchive/test/test_read_format_7zip_packinfo_digests.c
index e46a17b3b1da..75f90f2df899 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_7zip_packinfo_digests.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_7zip_packinfo_digests.c
@@ -82,7 +82,7 @@ DEFINE_TEST(test_read_format_7zip_packinfo_digests)
archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
}
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_7zip_sfx_boundary_elf.elf.uu b/contrib/libarchive/libarchive/test/test_read_format_7zip_sfx_boundary_elf.elf.uu
new file mode 100644
index 000000000000..1d396baf8a44
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_7zip_sfx_boundary_elf.elf.uu
@@ -0,0 +1,22 @@
+begin 644 test_read_format_7zip_sfx_boundary_elf.elf
+M?T5,1@(!`0````````````(`/@`!```````````````````````````"````
+M`````````$```````$```P`!```N9&%T80``````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````````````,`````
+M````````````````````0``````````'````````````````````````````
+M``````````````$````!```````````````````````````#````````(```
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````-WJ\KR<<``2-F]4/````````````````````````````````````````
+6````````````````````````````````
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_7zip_sfx_boundary_pe.exe.uu b/contrib/libarchive/libarchive/test/test_read_format_7zip_sfx_boundary_pe.exe.uu
new file mode 100644
index 000000000000..a4895655b281
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_7zip_sfx_boundary_pe.exe.uu
@@ -0,0 +1,22 @@
+begin 644 test_read_format_7zip_sfx_boundary_pe.exe
+M35H`````````````````````````````````````````````````````````
+M````````````````````0````%!%``!,`0$`````````````````X``"````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````+G1E
+M>'0````````````````!`````@``````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````04%!04%!04%!04%!04%!04%!04%!04%!04%!04%!04$W>KRO)QP`!(V;
+6U0\`````````````````````````````
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_cab.c b/contrib/libarchive/libarchive/test/test_read_format_cab.c
index f5ce21cbf19b..0adf24c7c67f 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_cab.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_cab.c
@@ -266,7 +266,7 @@ verify(const char *refname, enum comp_type comp)
/* Close the archive. */
finish:
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -332,7 +332,7 @@ verify2(const char *refname, enum comp_type comp)
assertEqualIntA(a, ARCHIVE_FORMAT_CAB, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -387,7 +387,7 @@ verify3(const char *refname, enum comp_type comp)
assertEqualIntA(a, ARCHIVE_FORMAT_CAB, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_cab_filename.c b/contrib/libarchive/libarchive/test/test_read_format_cab_filename.c
index efab3ccd69f1..8c0d17042896 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_cab_filename.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_cab_filename.c
@@ -79,7 +79,7 @@ test_read_format_cab_filename_CP932_eucJP(const char *refname)
/* Close the archive. */
cleanup:
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -157,7 +157,7 @@ test_read_format_cab_filename_CP932_UTF8(const char *refname)
/* Close the archive. */
cleanup:
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_cab_lzx_16bit.c b/contrib/libarchive/libarchive/test/test_read_format_cab_lzx_16bit.c
new file mode 100644
index 000000000000..6efc3801fc1c
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_cab_lzx_16bit.c
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2026 Tobias Stoeckmann
+ * 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"
+
+DEFINE_TEST(test_read_format_cab_lzx_16bit)
+{
+ const char *refname = "test_read_format_cab_lzx_16bit.cab";
+ struct archive *a;
+ struct archive_entry *ae;
+ char buff[16];
+
+ extract_reference_file(refname);
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_cab(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_filename(a, refname, 10240));
+
+ /* Read entry. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString(archive_entry_pathname(ae), "lzx16.bin");
+ assertEqualInt(archive_entry_size(ae), 16);
+ assertEqualIntA(a, sizeof(buff),
+ archive_read_data(a, buff, sizeof(buff)));
+ assertEqualMem(buff, "ABABABABABABABAB", 16);
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_cab_lzx_16bit.cab.uu b/contrib/libarchive/libarchive/test/test_read_format_cab_lzx_16bit.cab.uu
new file mode 100644
index 000000000000..c1e6330a47ee
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_cab_lzx_16bit.cab.uu
@@ -0,0 +1,6 @@
+begin 644 test_read_format_cab_lzx_16bit.cab
+M35-#1@````""`````````"P``````````P$!``$`````````1@````$``P\0
+M````````````(0```"``;'IX,38N8FEN```````T`!```!`#`6=%JXGOS0+P
+H"R(%[??[`.@``````````'^(__\`X`````````(`_R'__ZK*`*@`````
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_cab_lzx_e8.c b/contrib/libarchive/libarchive/test/test_read_format_cab_lzx_e8.c
new file mode 100644
index 000000000000..8ebe09033438
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_cab_lzx_e8.c
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2026 Tobias Stoeckmann
+ * 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"
+
+DEFINE_TEST(test_read_format_cab_lzx_e8)
+{
+ const char *refname = "test_read_format_cab_lzx_e8.cab";
+ struct archive *a;
+ struct archive_entry *ae;
+ char buff[30];
+
+ extract_reference_file(refname);
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_cab(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_filename(a, refname, 10240));
+
+ /* Read first entry. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString(archive_entry_pathname(ae), "e8.bin");
+ assertEqualInt(archive_entry_size(ae), 30);
+
+ /* Verify that E8 translation works. */
+ assertEqualIntA(a, sizeof(buff),
+ archive_read_data(a, buff, sizeof(buff)));
+ assertEqualMem(buff, "\xE8\x00\x00\x00\x00", 5);
+ assertEqualMem(buff + 5, "\xE8\x00\x00\x00\x80", 5);
+ assertEqualMem(buff + 10, "\xE8\xFF\xFF\xFF\x7F", 5);
+ assertEqualMem(buff + 15, "\xE8\xFF\x00\x00\x00", 5);
+ assertEqualMem(buff + 20, "\xE8\x12\x34\x56\x78", 5);
+ assertEqualMem(buff + 25, "\xE8\x87\x65\x43\x21", 5);
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_cab_lzx_e8.cab.uu b/contrib/libarchive/libarchive/test/test_read_format_cab_lzx_e8.cab.uu
new file mode 100644
index 000000000000..f619dac36330
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_cab_lzx_e8.cab.uu
@@ -0,0 +1,6 @@
+begin 644 test_read_format_cab_lzx_e8.cab.uu
+M35-#1@````!]`````````"P``````````P$!``$`````````0P````$``P\>
+M````````````XUQ,BB``93@N8FEN`,J?6J@R`!X`6X"`C0`PX`$/`````0``
+C``4```#H`````.@```"`Z/___W_H#@$``.@2-%9XZ(=E0R$`
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_cab_mszip_oob.c b/contrib/libarchive/libarchive/test/test_read_format_cab_mszip_oob.c
new file mode 100644
index 000000000000..da98a96b2f56
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_cab_mszip_oob.c
@@ -0,0 +1,93 @@
+#include "test.h"
+
+/*
+ * Regression test for OOB read/write in the CAB MSZIP decoder.
+ *
+ * A crafted CFDATA block carries a stored-block deflate header whose LEN
+ * field (0x9000) is larger than the actual compressed payload. Without the
+ * fix, the decoder reads one byte past the end of the input buffer on the
+ * second archive_read_next_header() call (after the first call returns
+ * ARCHIVE_FATAL due to the truncated payload).
+ */
+DEFINE_TEST(test_read_format_cab_mszip_oob)
+{
+ const uint16_t LEN = 0x9000;
+ const uint16_t NLEN = (uint16_t)~LEN;
+ const uint8_t first = 0xFF;
+
+ /*
+ * cbData and cbUncomp are chosen so that the two-byte sequences they
+ * occupy inside the CFDATA header also form a valid deflate stored-block
+ * length / complement pair when the decoder's read pointer is positioned
+ * one field early.
+ */
+ const uint16_t cbData = (LEN >> 8) | ((NLEN & 0xff) << 8);
+ const uint16_t cbUncomp = (NLEN >> 8) | ((uint16_t)first << 8);
+
+ const size_t payload = (size_t)LEN - 1; /* one byte short of LEN */
+ const size_t total = 36 + 8 + 18 + 8 + payload;
+
+ uint8_t *b = (uint8_t *)calloc(1, total);
+ assert(b != NULL);
+
+ /* CFHEADER (36 bytes) */
+ memcpy(b, "MSCF", 4);
+ b[8] = (uint8_t)(total);
+ b[9] = (uint8_t)(total >> 8);
+ b[10] = (uint8_t)(total >> 16);
+ b[11] = (uint8_t)(total >> 24);
+ b[16] = 44; /* coffFiles: first CFFILE at offset 44 */
+ b[24] = 3; b[25] = 1; /* version 1.3 */
+ b[26] = 1; /* cFolders = 1 */
+ b[28] = 1; /* cFiles = 1 */
+
+ /* CFFOLDER (8 bytes at offset 36) */
+ b[36] = 62; /* coffCabStart: first CFDATA at offset 62 */
+ b[40] = 1; /* cCFData = 1 */
+ b[42] = 0x01; /* typeCompress = MSZIP */
+
+ /* CFFILE (18 bytes at offset 44) */
+ b[44] = 0x00; b[45] = 0x01; /* cbFile = 0x100 */
+ b[54] = 0x21; /* date low */
+ b[58] = 0x20; /* attribs low */
+ b[60] = 'a'; b[61] = 0; /* szName "a" */
+
+ /* CFDATA header (8 bytes at offset 62) */
+ b[62] = 0x43; b[63] = 0x4B; /* checksum bytes (also MSZIP "CK" marker) */
+ b[64] = 0x01;
+ b[65] = (uint8_t)(LEN & 0xff);
+ b[66] = (uint8_t)(cbData);
+ b[67] = (uint8_t)(cbData >> 8);
+ b[68] = (uint8_t)(cbUncomp);
+ b[69] = (uint8_t)(cbUncomp >> 8);
+
+ /* Compressed payload: one byte short of what the stored-block LEN claims */
+ memset(b + 70, first, payload);
+
+ /* Open the crafted archive from memory */
+ struct archive *a = archive_read_new();
+ assert(a != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_cab(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a, b, total));
+
+ struct archive_entry *ae;
+ char buf[4096];
+
+ /* The single CFFILE header is well-formed and should read cleanly. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("a", archive_entry_pathname(ae));
+
+ /*
+ * Reading data must fail: cbUncomp (0xFF6F) exceeds the decoder's
+ * uncompressed buffer (0x8000), so the bounds check returns FATAL
+ * rather than writing past the buffer end.
+ */
+ assertEqualInt(ARCHIVE_FATAL, archive_read_data(a, buf, sizeof(buf)));
+
+ /* The archive is in FATAL state and should remain that way. */
+ assertEqualIntA(a, ARCHIVE_FATAL, archive_read_next_header(a, &ae));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+ free(b);
+}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_cab_multi.c b/contrib/libarchive/libarchive/test/test_read_format_cab_multi.c
new file mode 100644
index 000000000000..f911f2187a9b
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_cab_multi.c
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2026 Tobias Stoeckmann
+ * 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"
+
+DEFINE_TEST(test_read_format_cab_multi)
+{
+ /* Reference to multi volume CAB files */
+ const char *refname1 = "test_read_format_cab_multi.p1.cab";
+ const char *refname2 = "test_read_format_cab_multi.p2.cab";
+ struct archive *a;
+ struct archive_entry *ae;
+
+ /* Extract the reference files into the test sandbox */
+ extract_reference_file(refname1);
+ extract_reference_file(refname2);
+
+ /* Initialize the archive reader for first part */
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_filename(a, refname1, 10));
+
+ /* Read entry */
+ assertEqualIntA(a, ARCHIVE_WARN, archive_read_next_header(a, &ae));
+ assertEqualString(archive_entry_pathname(ae), "ones");
+ assertEqualInt(archive_entry_size(ae), 512);
+
+ /* Clean up reader */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+
+ /* Initialize the archive reader for second part */
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_filename(a, refname2, 10));
+
+ /* Read entry */
+ assertEqualIntA(a, ARCHIVE_WARN, archive_read_next_header(a, &ae));
+ assertEqualString(archive_entry_pathname(ae), "ones");
+ assertEqualInt(archive_entry_size(ae), 512);
+
+ /* Clean up reader */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+} \ No newline at end of file
diff --git a/contrib/libarchive/libarchive/test/test_read_format_cab_multi.p1.cab.uu b/contrib/libarchive/libarchive/test/test_read_format_cab_multi.p1.cab.uu
new file mode 100644
index 000000000000..babd7a330dca
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_cab_multi.p1.cab.uu
@@ -0,0 +1,15 @@
+begin 644 test_read_format_cab_multi.p1.cab
+M35-#1@```````@```````$\``````````P$!``$``@"U`0``=&5S=%]R96%D
+M7V9O<FUA=%]C86)?;75L=&DN<#(N8V%B``!D`````0`````"````````_O_0
+M7(6J(`!O;F5S`)4``0&4`0```0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!
+M`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!
+M`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!
+M`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!
+M`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!
+M`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!
+M`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!
+M`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!
+M`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!
+1`0$!`0$!`0$!`0$!`0$!`0$`
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_cab_multi.p2.cab.uu b/contrib/libarchive/libarchive/test/test_read_format_cab_multi.p2.cab.uu
new file mode 100644
index 000000000000..8361c3d68435
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_cab_multi.p2.cab.uu
@@ -0,0 +1,8 @@
+begin 644 test_read_format_cab_multi.p2.cab
+M35-#1@````#8`````````$\``````````P$!``$``0"U`0$`=&5S=%]R96%D
+M7V9O<FUA=%]C86)?;75L=&DN<#$N8V%B``!D`````0`````"````````_?_0
+M7(6J(`!O;F5S`&T!`0-L```"`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!
+M`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!
+D`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_cpio_afio.c b/contrib/libarchive/libarchive/test/test_read_format_cpio_afio.c
index 5d2b4b4c8134..a1fb683e38d4 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_cpio_afio.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_cpio_afio.c
@@ -102,7 +102,7 @@ DEFINE_TEST(test_read_format_cpio_afio)
assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED);
assertA(archive_filter_code(a, 0) == ARCHIVE_FILTER_NONE);
assertA(archive_format(a) == ARCHIVE_FORMAT_CPIO_AFIO_LARGE);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
free(p);
@@ -125,3 +125,27 @@ DEFINE_TEST(test_read_format_cpio_afio_broken)
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_CPIO_AFIO_LARGE);
archive_read_free(a);
}
+
+DEFINE_TEST(test_read_format_cpio_afio_header)
+{
+ const char *reffiles[] =
+ {
+ "test_read_format_cpio_afio_header.part1.cpio",
+ "test_read_format_cpio_afio_header.part2.cpio",
+ NULL
+ };
+ struct archive_entry *ae;
+ struct archive *a;
+
+ extract_reference_files(reffiles);
+ assert((a = archive_read_new()) != NULL);
+ assertA(0 == archive_read_support_format_cpio(a));
+ assertA(0 == archive_read_open_filenames(a, reffiles, 10240));
+
+ /* File "a" */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("a", archive_entry_pathname(ae));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_cpio_afio_header.part1.cpio.uu b/contrib/libarchive/libarchive/test/test_read_format_cpio_afio_header.part1.cpio.uu
new file mode 100644
index 000000000000..0d06cb299948
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_cpio_afio_header.part1.cpio.uu
@@ -0,0 +1,5 @@
+begin 644 test_read_format_cpio_afio_header.part1.cpio
+M,#<P-S(W,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P;3`P,#`P,#`P,#`P,#`P
+?,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,```
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_cpio_afio_header.part2.cpio.uu b/contrib/libarchive/libarchive/test/test_read_format_cpio_afio_header.part2.cpio.uu
new file mode 100644
index 000000000000..0a3d59597641
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_cpio_afio_header.part2.cpio.uu
@@ -0,0 +1,4 @@
+begin 644 test_read_format_cpio_afio_header.part2.cpio
+I,#`P,#`P,#`P;C`P,#$P,#`P,#`P,',P,#`P,#`P,#`P,#`P,#`P.F$`
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_cpio_bin_bz2.c b/contrib/libarchive/libarchive/test/test_read_format_cpio_bin_bz2.c
index b1a994bc5359..c34ed8b67a31 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_cpio_bin_bz2.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_cpio_bin_bz2.c
@@ -41,7 +41,7 @@ DEFINE_TEST(test_read_format_cpio_bin_bz2)
r = archive_read_support_filter_bzip2(a);
if (r != ARCHIVE_OK) {
skipping("bzip2 support unavailable");
- archive_read_close(a);
+ archive_read_free(a);
return;
}
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
diff --git a/contrib/libarchive/libarchive/test/test_read_format_cpio_bin_gz.c b/contrib/libarchive/libarchive/test/test_read_format_cpio_bin_gz.c
index 47545f913248..1372a7b5111c 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_cpio_bin_gz.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_cpio_bin_gz.c
@@ -55,7 +55,7 @@ DEFINE_TEST(test_read_format_cpio_bin_gz)
assertEqualInt(archive_entry_is_encrypted(ae), 0);
assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED);
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_CPIO_BIN_LE);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_cpio_filename.c b/contrib/libarchive/libarchive/test/test_read_format_cpio_filename.c
index c5aa9a7f52a0..011fdf0027d3 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_cpio_filename.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_cpio_filename.c
@@ -76,11 +76,64 @@ DEFINE_TEST(test_read_format_cpio_filename_eucJP_UTF8)
assertEqualIntA(a, ARCHIVE_FORMAT_CPIO_POSIX, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
cleanup:
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
+DEFINE_TEST(test_read_format_cpio_newc_large_pathname)
+{
+ const size_t namesize = 1024 * 1024 + 1;
+ const size_t name_pad = (2 - namesize) & 3;
+ char header[111];
+ const size_t header_size = sizeof(header) - 1;
+ const size_t buffsize = header_size + namesize + name_pad;
+ char *buff;
+ struct archive *a;
+ struct archive_entry *ae;
+ int header_len;
+
+ assert((buff = calloc(1, buffsize)) != NULL);
+ if (buff == NULL)
+ return;
+
+ header_len = snprintf(header, sizeof(header),
+ "070701" /* magic */
+ "%08x" /* c_ino */
+ "%08x" /* c_mode */
+ "%08x" /* c_uid */
+ "%08x" /* c_gid */
+ "%08x" /* c_nlink */
+ "%08x" /* c_mtime */
+ "%08x" /* c_filesize */
+ "%08x" /* c_devmajor */
+ "%08x" /* c_devminor */
+ "%08x" /* c_rdevmajor */
+ "%08x" /* c_rdevminor */
+ "%08x" /* c_namesize */
+ "%08x", /* c_check */
+ 1, 0100644, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ (unsigned int)namesize, 0);
+ assertEqualInt((int)header_size, header_len);
+
+ memcpy(buff, header, header_size);
+ memset(buff + header_size, 'a', namesize);
+ buff[header_size + namesize - 1] = '\0';
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_memory(a, buff, buffsize));
+ assertEqualIntA(a, ARCHIVE_FATAL, archive_read_next_header(a, &ae));
+ assertEqualInt(ENOMEM, archive_errno(a));
+ assertEqualString("Rejecting malformed cpio archive: "
+ "pathname exceeds 1 megabyte", archive_error_string(a));
+
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+ free(buff);
+}
+
DEFINE_TEST(test_read_format_cpio_filename_UTF8_eucJP)
{
const char *refname = "test_read_format_cpio_filename_utf8_jp.cpio";
@@ -129,7 +182,7 @@ DEFINE_TEST(test_read_format_cpio_filename_UTF8_eucJP)
assertEqualIntA(a, ARCHIVE_FORMAT_CPIO_POSIX, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
cleanup:
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -182,7 +235,7 @@ DEFINE_TEST(test_read_format_cpio_filename_UTF8_UTF8_jp)
assertEqualIntA(a, ARCHIVE_FORMAT_CPIO_POSIX, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
#endif
}
@@ -235,7 +288,7 @@ DEFINE_TEST(test_read_format_cpio_filename_CP866_KOI8R)
assertEqualIntA(a, ARCHIVE_FORMAT_CPIO_POSIX, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
cleanup:
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -287,7 +340,7 @@ DEFINE_TEST(test_read_format_cpio_filename_CP866_UTF8)
assertEqualIntA(a, ARCHIVE_FORMAT_CPIO_POSIX, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
cleanup:
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -340,7 +393,7 @@ DEFINE_TEST(test_read_format_cpio_filename_KOI8R_CP866)
assertEqualIntA(a, ARCHIVE_FORMAT_CPIO_POSIX, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
cleanup:
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -392,7 +445,7 @@ DEFINE_TEST(test_read_format_cpio_filename_KOI8R_UTF8)
assertEqualIntA(a, ARCHIVE_FORMAT_CPIO_POSIX, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
cleanup:
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -445,7 +498,7 @@ DEFINE_TEST(test_read_format_cpio_filename_UTF8_KOI8R)
assertEqualIntA(a, ARCHIVE_FORMAT_CPIO_POSIX, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
cleanup:
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -498,7 +551,7 @@ DEFINE_TEST(test_read_format_cpio_filename_UTF8_CP866)
assertEqualIntA(a, ARCHIVE_FORMAT_CPIO_POSIX, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
cleanup:
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -550,7 +603,7 @@ DEFINE_TEST(test_read_format_cpio_filename_UTF8_UTF8_ru)
assertEqualIntA(a, ARCHIVE_FORMAT_CPIO_POSIX, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
#endif
}
@@ -601,7 +654,7 @@ DEFINE_TEST(test_read_format_cpio_filename_eucJP_CP932)
assertEqualIntA(a, ARCHIVE_FORMAT_CPIO_POSIX, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
cleanup:
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -653,7 +706,7 @@ DEFINE_TEST(test_read_format_cpio_filename_UTF8_CP932)
assertEqualIntA(a, ARCHIVE_FORMAT_CPIO_POSIX, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
cleanup:
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -706,7 +759,7 @@ DEFINE_TEST(test_read_format_cpio_filename_CP866_CP1251)
assertEqualIntA(a, ARCHIVE_FORMAT_CPIO_POSIX, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
cleanup:
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -759,7 +812,7 @@ DEFINE_TEST(test_read_format_cpio_filename_CP866_CP1251_win)
assertEqualIntA(a, ARCHIVE_FORMAT_CPIO_POSIX, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -811,7 +864,7 @@ DEFINE_TEST(test_read_format_cpio_filename_KOI8R_CP1251)
assertEqualIntA(a, ARCHIVE_FORMAT_CPIO_POSIX, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
cleanup:
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -864,8 +917,7 @@ DEFINE_TEST(test_read_format_cpio_filename_UTF8_CP1251)
assertEqualIntA(a, ARCHIVE_FORMAT_CPIO_POSIX, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
cleanup:
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
-
diff --git a/contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_bzip2_rpm.c b/contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_bzip2_rpm.c
index cff64d72c1ed..1c421df1e329 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_bzip2_rpm.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_bzip2_rpm.c
@@ -123,7 +123,7 @@ DEFINE_TEST(test_read_format_cpio_svr4_bzip2_rpm)
assertEqualString(archive_filter_name(a, 0), "bzip2");
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_CPIO_SVR4_NOCRC);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_gzip.c b/contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_gzip.c
index ae201de00f68..7fa22611e5e9 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_gzip.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_gzip.c
@@ -55,7 +55,7 @@ DEFINE_TEST(test_read_format_cpio_svr4_gzip)
ARCHIVE_FORMAT_CPIO_SVR4_NOCRC);
assertEqualInt(archive_entry_is_encrypted(ae), 0);
assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_gzip_rpm.c b/contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_gzip_rpm.c
index 345760c1014f..6062c48cd127 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_gzip_rpm.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_cpio_svr4_gzip_rpm.c
@@ -123,7 +123,7 @@ DEFINE_TEST(test_read_format_cpio_svr4_gzip_rpm)
assertEqualString(archive_filter_name(a, 0), "gzip");
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_CPIO_SVR4_NOCRC);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_cpio_symlink_trailer.c b/contrib/libarchive/libarchive/test/test_read_format_cpio_symlink_trailer.c
new file mode 100644
index 000000000000..5c520a783bb3
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_cpio_symlink_trailer.c
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2026 Kaif Khan
+ * 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"
+
+/*
+ * The cpio reader reads an entry's name into a read-ahead buffer and holds
+ * that pointer to compare the name against "TRAILER!!!" (end of archive).
+ * For a symlink entry the link body is read first, and a large body can grow
+ * (and free) the read-ahead buffer, leaving the name pointer dangling before
+ * the trailer comparison.
+ *
+ * The reference archive is a single newc entry: a symlink named "TRAILER!!!"
+ * with a 128 KiB body. Reading it in small blocks assembles the name in the
+ * reader's copy buffer, which the symlink body read then reallocates; the
+ * trailer must still be detected without touching freed memory.
+ */
+DEFINE_TEST(test_read_format_cpio_symlink_trailer)
+{
+ const char *name = "test_read_format_cpio_symlink_trailer.cpio";
+ struct archive_entry *ae;
+ struct archive *a;
+
+ extract_reference_file(name);
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_cpio(a));
+ /* Small block size so the name is assembled in the reader's copy
+ * buffer, which the symlink body read then reallocates. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name, 13));
+
+ /* The "TRAILER!!!" entry ends the archive. */
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_cpio_symlink_trailer.cpio.uu b/contrib/libarchive/libarchive/test/test_read_format_cpio_symlink_trailer.cpio.uu
new file mode 100644
index 000000000000..1ac44473d3f2
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_cpio_symlink_trailer.cpio.uu
@@ -0,0 +1,2919 @@
+begin 644 test_read_format_cpio_symlink_trailer.cpio
+M,#<P-S`Q,#`P,#`P,#$P,#`P03%&1C`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P
+M,3`P,#`P,#`P,#`P,C`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P
+M,#`P,#`P,#`P,#!",#`P,#`P,#!44D%)3$52(2$A`````'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+M>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+5>'AX>'AX>'AX>'AX>'AX>'AX>'AX
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_gtar_filename.c b/contrib/libarchive/libarchive/test/test_read_format_gtar_filename.c
index cf9c30991b28..75cc2b6af237 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_gtar_filename.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_gtar_filename.c
@@ -74,7 +74,7 @@ DEFINE_TEST(test_read_format_gtar_filename_eucJP_UTF8)
assertEqualIntA(a, ARCHIVE_FORMAT_TAR_GNUTAR, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
cleanup:
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -127,7 +127,7 @@ DEFINE_TEST(test_read_format_gtar_filename_CP866_KOI8R)
assertEqualIntA(a, ARCHIVE_FORMAT_TAR_GNUTAR, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
cleanup:
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -179,7 +179,7 @@ DEFINE_TEST(test_read_format_gtar_filename_CP866_UTF8)
assertEqualIntA(a, ARCHIVE_FORMAT_TAR_GNUTAR, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
cleanup:
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -232,7 +232,7 @@ DEFINE_TEST(test_read_format_gtar_filename_KOI8R_CP866)
assertEqualIntA(a, ARCHIVE_FORMAT_TAR_GNUTAR, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
cleanup:
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -284,7 +284,7 @@ DEFINE_TEST(test_read_format_gtar_filename_KOI8R_UTF8)
assertEqualIntA(a, ARCHIVE_FORMAT_TAR_GNUTAR, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
cleanup:
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -335,7 +335,7 @@ DEFINE_TEST(test_read_format_gtar_filename_eucJP_CP932)
assertEqualIntA(a, ARCHIVE_FORMAT_TAR_GNUTAR, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
cleanup:
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -388,7 +388,7 @@ DEFINE_TEST(test_read_format_gtar_filename_CP866_CP1251)
assertEqualIntA(a, ARCHIVE_FORMAT_TAR_GNUTAR, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
cleanup:
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -441,7 +441,7 @@ DEFINE_TEST(test_read_format_gtar_filename_CP866_CP1251_win)
assertEqualIntA(a, ARCHIVE_FORMAT_TAR_GNUTAR, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -493,7 +493,7 @@ DEFINE_TEST(test_read_format_gtar_filename_KOI8R_CP1251)
assertEqualIntA(a, ARCHIVE_FORMAT_TAR_GNUTAR, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
cleanup:
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_gtar_gz.c b/contrib/libarchive/libarchive/test/test_read_format_gtar_gz.c
index bc712b9e6e44..8d99e493b0ca 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_gtar_gz.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_gtar_gz.c
@@ -55,7 +55,7 @@ DEFINE_TEST(test_read_format_gtar_gz)
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_GNUTAR);
assertEqualInt(archive_entry_is_encrypted(ae), 0);
assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED);
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_gtar_redundant_L.c b/contrib/libarchive/libarchive/test/test_read_format_gtar_redundant_L.c
index 167445c074f3..24bdead35230 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_gtar_redundant_L.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_gtar_redundant_L.c
@@ -35,6 +35,6 @@ DEFINE_TEST(test_read_format_gtar_redundant_L)
assertEqualIntA(a, ARCHIVE_FORMAT_TAR_GNUTAR, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_gtar_sparse.c b/contrib/libarchive/libarchive/test/test_read_format_gtar_sparse.c
index fdb4be31a170..06fcffef4057 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_gtar_sparse.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_gtar_sparse.c
@@ -169,6 +169,58 @@ static struct archive_contents {
{ NULL, NULL }
};
+/* Reuse one callback buffer so the sparse extension overwrites the main header. */
+struct sparse_reuse_data {
+ FILE *file;
+ unsigned char block[512];
+};
+
+static la_ssize_t
+sparse_reuse_read(struct archive *a, void *client_data, const void **buffer)
+{
+ struct sparse_reuse_data *data = client_data;
+ size_t size;
+
+ (void)a;
+ size = fread(data->block, 1, sizeof(data->block), data->file);
+ if (size == 0 && ferror(data->file))
+ return (-1);
+ *buffer = data->block;
+ return ((la_ssize_t)size);
+}
+
+static void
+verify_sparse_header_reuse(void)
+{
+ const char *name = "test_read_format_gtar_sparse_reuse.tar";
+ struct sparse_reuse_data data;
+ struct archive_entry *ae;
+ struct archive *a;
+
+ extract_reference_file(name);
+ memset(&data, 0, sizeof(data));
+ data.file = fopen(name, "rb");
+ if (!assert(data.file != NULL))
+ return;
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_tar(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open(a, &data, NULL, sparse_reuse_read, NULL));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+
+ assertEqualString("sparse", archive_entry_pathname(ae));
+ assertEqualInt(0644, archive_entry_perm(ae));
+ assertEqualInt(123, archive_entry_uid(ae));
+ assertEqualInt(456, archive_entry_gid(ae));
+ assertEqualInt(123456789, archive_entry_mtime(ae));
+
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+ assertEqualInt(0, fclose(data.file));
+}
+
static void
verify_archive_file(const char *name, struct archive_contents *ac)
{
@@ -262,6 +314,8 @@ verify_archive_file(const char *name, struct archive_contents *ac)
DEFINE_TEST(test_read_format_gtar_sparse)
{
+ verify_sparse_header_reuse();
+
/* Two archives that use the "GNU tar sparse format". */
verify_archive_file("test_read_format_gtar_sparse_1_13.tar", files);
verify_archive_file("test_read_format_gtar_sparse_1_17.tar", files);
diff --git a/contrib/libarchive/libarchive/test/test_read_format_gtar_sparse_reuse.tar.uu b/contrib/libarchive/libarchive/test/test_read_format_gtar_sparse_reuse.tar.uu
new file mode 100644
index 000000000000..72df7c720d15
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_gtar_sparse_reuse.tar.uu
@@ -0,0 +1,48 @@
+begin 644 test_read_format_gtar_sparse_reuse.tar
+M<W!A<G-E````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````#`P,#`V-#0`,#`P,#$W,P`P,#`P-S$P`#`P,#`P,#`P,#`P
+M`#`P-S(V-S0V-#(U`#`R,#8S,0`@4P``````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````!U<W1A<B`@`'5S97(`
+M````````````````````````````````````9W)O=7``````````````````
+M```````````````````P,#`P,#`P`#`P,#`P,#``,#`P,#`P,#`P,#``,#`P
+M,#`P,#`P,#``,#`P,#`P,#`P,#`````````P,#`P,#`P,#`P,``P,#`P,#`P
+M,#`P,```````````````````````````````````````````````````````
+M```````````````````````````````````````````!,#`P,#`P,#`P,#``
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+7````````````````````````````````
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_gtar_sparse_skip_entry.c b/contrib/libarchive/libarchive/test/test_read_format_gtar_sparse_skip_entry.c
index d592c466f76b..6479cdc7d74c 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_gtar_sparse_skip_entry.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_gtar_sparse_skip_entry.c
@@ -86,7 +86,7 @@ DEFINE_TEST(test_read_format_gtar_sparse_skip_entry)
archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
@@ -133,7 +133,7 @@ DEFINE_TEST(test_read_format_gtar_sparse_skip_entry)
archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_huge_rpm.c b/contrib/libarchive/libarchive/test/test_read_format_huge_rpm.c
index 729c1e188d28..51208c7caea2 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_huge_rpm.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_huge_rpm.c
@@ -26,7 +26,6 @@
DEFINE_TEST(test_read_format_huge_rpm)
{
- struct archive_entry *ae;
struct archive *a;
const char *name = "test_read_format_huge_rpm.rpm";
@@ -34,17 +33,13 @@ DEFINE_TEST(test_read_format_huge_rpm)
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
extract_reference_file(name);
- assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name, 2));
+ /* This archive is truncated -- if it has data, the bid has screwed up */
+ assertEqualIntA(a, ARCHIVE_FATAL, archive_read_open_filename(a, name, 2));
+ assertEqualStringA(a, "Truncated input file "
+ "(needed 34359738384 bytes, only 10256 available)",
+ archive_error_string(a));
- /* This archive should have no entries -- if it has entries, the bid has screwed up */
- assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
-
- /* Verify that the format detection worked. */
- assertEqualInt(ARCHIVE_FILTER_RPM, archive_filter_code(a, 0));
- assertEqualString("rpm", archive_filter_name(a, 0));
- assertEqualInt(ARCHIVE_FORMAT_EMPTY, archive_format(a));
-
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_iso_joliet_utf16be_overflow.c b/contrib/libarchive/libarchive/test/test_read_format_iso_joliet_utf16be_overflow.c
new file mode 100644
index 000000000000..6635fbefeef4
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_iso_joliet_utf16be_overflow.c
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2026 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"
+
+/*
+ * A Joliet ISO with deeply nested directories whose UTF-16BE path
+ * exactly fills the 1024-byte buffer in build_pathname_utf16be().
+ * The next recursive call then writes a 2-byte separator past the
+ * end of the allocation (heap-buffer-overflow).
+ *
+ * Under AddressSanitizer the unfixed code crashes at
+ * archive_read_support_format_iso9660.c:3496; with the fix the
+ * bounds check before the separator write causes
+ * archive_read_next_header() to return ARCHIVE_FATAL.
+ */
+DEFINE_TEST(test_read_format_iso_joliet_utf16be_overflow)
+{
+ const char *refname = "test_read_format_iso_joliet_utf16be_overflow.iso";
+ struct archive *a;
+ struct archive_entry *ae;
+ int r;
+
+ extract_reference_file(refname);
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_filename(a, refname, 10240));
+
+ /* Read through entries until the overflow path is reached.
+ * With the fix this returns ARCHIVE_FATAL ("Pathname is too long")
+ * instead of writing two bytes past the end of the path buffer. */
+ while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK)
+ archive_read_data_skip(a);
+ assertEqualInt(ARCHIVE_FATAL, r);
+
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_iso_joliet_utf16be_overflow.iso.uu b/contrib/libarchive/libarchive/test/test_read_format_iso_joliet_utf16be_overflow.iso.uu
new file mode 100644
index 000000000000..92dd832bfe41
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_iso_joliet_utf16be_overflow.iso.uu
@@ -0,0 +1,1278 @@
+begin 644 test_read_format_iso_joliet_utf16be_overflow.iso
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````!0T0P,#$!`"`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("```````````!P`
+M```````<```````````````````````````````````````````!```!`0``
+M`0`("``*````````"A,````````````````````B`!4````````5``@`````
+M"`!\`0$``````@```0```0$`("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`P,#`P,#`P,#`P,#`P,#`P`#`P,#`P,#`P,#`P,#`P,#``
+M,#`P,#`P,#`P,#`P,#`P,``P,#`P,#`P,#`P,#`P,#`P``$`````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````)#1#`P,0$`````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````'````````!PE+T4`````````````````
+M``````````````````````````````````@(````````````$P``````````
+M`````````"(`%````````!0`"``````(`'P!`0`````"```!```!`0``````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````0``````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````_T-$,#`Q`0``````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````"(`%````````!0`"``````(`'P!`0`````"```!```!`0`B
+M`!0````````4``@`````"`!\`0$``````@```0```0$!\``6````````%@`(
+M``````@`?`$!``````(```$```'.`$$`00!!`$$`00!!`$$`00!!`$$`00!!
+M`$$`00!!`$$`00!!`$$`00!!`$$`00!!`$$`00!!`$$`00!!`$$`00!!`$$`
+M00!!`$$`00!!`$$`00!!`$$`00!!`$$`00!!`$$`00!!`$$`00!!`$$`00!!
+M`$$`00!!`$$`00!!`$$`00!!`$$`00!!`$$`00!!`$$`00!!`$$`00!!`$$`
+M00!!`$$`00!!`$$`00!!`$$`00!!`$$`00!!`$$`00!!`$$`00!!`$$`00!!
+M`$$`````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````(@`5````````%0`(
+M``````@`?`$!``````(```$```$!`"(`%0```````!4`"``````(`'P!`0``
+M```"```!```!`0$`````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````B`!8````````6``@`````"`!\`0$``````@```0```0$`
+M(@`4````````%``(``````@`?`$!``````(```$```$!`?``%P```````!<`
+M"``````(`'P!`0`````"```!```!S@!"`$(`0@!"`$(`0@!"`$(`0@!"`$(`
+M0@!"`$(`0@!"`$(`0@!"`$(`0@!"`$(`0@!"`$(`0@!"`$(`0@!"`$(`0@!"
+M`$(`0@!"`$(`0@!"`$(`0@!"`$(`0@!"`$(`0@!"`$(`0@!"`$(`0@!"`$(`
+M0@!"`$(`0@!"`$(`0@!"`$(`0@!"`$(`0@!"`$(`0@!"`$(`0@!"`$(`0@!"
+M`$(`0@!"`$(`0@!"`$(`0@!"`$(`0@!"`$(`0@!"`$(`0@!"`$(`0@!"`$(`
+M0@!"````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````"(`%P```````!<`
+M"``````(`'P!`0`````"```!```!`0`B`!8````````6``@`````"`!\`0$`
+M`````@```0```0$!\``8````````&``(``````@`?`$!``````(```$```'.
+M`$,`0P!#`$,`0P!#`$,`0P!#`$,`0P!#`$,`0P!#`$,`0P!#`$,`0P!#`$,`
+M0P!#`$,`0P!#`$,`0P!#`$,`0P!#`$,`0P!#`$,`0P!#`$,`0P!#`$,`0P!#
+M`$,`0P!#`$,`0P!#`$,`0P!#`$,`0P!#`$,`0P!#`$,`0P!#`$,`0P!#`$,`
+M0P!#`$,`0P!#`$,`0P!#`$,`0P!#`$,`0P!#`$,`0P!#`$,`0P!#`$,`0P!#
+M`$,`0P!#`$,`0P!#`$,`0P!#`$,`0P!#`$,`````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````(@`8````````&``(``````@`?`$!``````(```$```$!
+M`"(`%P```````!<`"``````(`'P!`0`````"```!```!`0'P`!D````````9
+M``@`````"`!\`0$``````@```0```<X`1`!$`$0`1`!$`$0`1`!$`$0`1`!$
+M`$0`1`!$`$0`1`!$`$0`1`!$`$0`1`!$`$0`1`!$`$0`1`!$`$0`1`!$`$0`
+M1`!$`$0`1`!$`$0`1`!$`$0`1`!$`$0`1`!$`$0`1`!$`$0`1`!$`$0`1`!$
+M`$0`1`!$`$0`1`!$`$0`1`!$`$0`1`!$`$0`1`!$`$0`1`!$`$0`1`!$`$0`
+M1`!$`$0`1`!$`$0`1`!$`$0`1`!$`$0`1`!$`$0`1`!$`$0`1`!$`$0`1`!$
+M`$0`1```````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````B`!D````````9
+M``@`````"`!\`0$``````@```0```0$`(@`8````````&``(``````@`?`$!
+M``````(```$```$!`>(`&@```````!H`"``````(`'P!`0`````"```!```!
+MP`!%`$4`10!%`$4`10!%`$4`10!%`$4`10!%`$4`10!%`$4`10!%`$4`10!%
+M`$4`10!%`$4`10!%`$4`10!%`$4`10!%`$4`10!%`$4`10!%`$4`10!%`$4`
+M10!%`$4`10!%`$4`10!%`$4`10!%`$4`10!%`$4`10!%`$4`10!%`$4`10!%
+M`$4`10!%`$4`10!%`$4`10!%`$4`10!%`$4`10!%`$4`10!%`$4`10!%`$4`
+M10!%`$4`10!%`$4`10``````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````"(`&@```````!H`"``````(`'P!`0`````"```!```!
+M`0`B`!D````````9``@`````"`!\`0$``````@```0```0$!)```````````
+M````````````?`$!``````````$```$"`$8`````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+.````````````````````
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_iso_rockridge_ce_loop.iso.Z.uu b/contrib/libarchive/libarchive/test/test_read_format_iso_rockridge_ce_loop.iso.Z.uu
new file mode 100644
index 000000000000..20e08d3569fe
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_iso_rockridge_ce_loop.iso.Z.uu
@@ -0,0 +1,61 @@
+begin 644 test_read_format_iso_rockridge_ce_loop.iso.Z
+M'YV0``(*'$BPH,&#"!,J7,BPH<.'$"-*G$BQHL6+&#-JW,BQH\>/($.*'$FR
+MI,F3*%.J7,FRI<N7,&/*G$FSILV;.'/JW,FSI\^?0(,*'4JTJ-&C2),J7<JT
+MJ=.G4*-*G4JUJM6K6+-JW<JUJ]>O8,.*'4NVK-FS:-.J7<NVK=NW<./*G4NW
+MKMV[>//JW<NWK]^_@`,+'DRXL.'#B!,K7LRXL>/'D"-+GDRYLN7+F#-KWLRY
+ML^?/H$.+'DVZM.G3J%.K7LVZM>O7L&/+GDV[MNW;N'/KWLV[M^_?P(,+'TZ\
+MN/'CR),K7\Z\N?/GT*-+GTZ]NO7KV+-KW\Z]N_?OX,.+'T^^O/GSZ-.K7\^^
+MO?OW\./+GT^_OOW[^//KW\^_O_^_`0Q!!`PPQ!```$;(44890DQ!!`@01BCA
+MA!1***`43S11X88<1GC0+06!Z-&!``1`XH$((`"`!059,$%"%0PD`@`7%%2C
+MB@*I:$0``B10(@D"!'3B@1T6:>212":IY)),-NGDDU!&*>645%9I991-+)'$
+M%$\8,04(6SX!0@XVV`##"TAX"8(123!1Q!193$%%$1H*446;1!0A!0@F@'!A
+M$4,\(<6#`K8@Q0M$6$&H%$4$086@(*`P1`H@Q)!##C.`4(0+63Q1A1-'$!&$
+MFY%.6NFE-X"@A`M0-"H%ETZ\L.H40R#1)A-)@'KEKKSN*@.!.<10H`PQR%##
+MKV;"0,*O,`0[;+''PI`L"016:^VU!`+`K+/%0HLL@200V>NXY)9K[KGHIJON
+MNNRVZ^Z2_\6[V#\"$FB@O/CFJ^^^_/9;799)@-#$&VZ`\,08=%0J@\(Z'*N#
+MM"!LJX`,+A18<0QAV)"IH2"T4$<:9%3:\1D@1PR""RB_D,8<;_CK\LLPQRSS
+MS&G=0L^!-0HIT```9"#0@40D(07-1!=M]-%()ZWTTDPW[?334+]&8D`UDLBS
+M0#X'$/3047?M]==@ARWVV&27;?;9:"<-"8TV`H!C0#KRZ&,`0.I<XH%30'%`
+M`+Z\`X`44A000"!08,%"`.T$,5`0[5P]T`!3_QPD00+D/-`%5!BA00`.[-CC
+MCVTHP``#-!A`0NBCET["$$5P$(`&!<%N4#L%M>,&VP3=.%#<G],]^9`!`"XX
+MX88CKKA`C#N^<^1"3CY0Y39FOGGG<H,N.NFFHXX]"0"0`\`&!6V@SP,#/:"/
+MYW-S;W<`"P3AOOO5NK!##,('D(@335QB8AC\]^___P`,H``'2,`"&O"`"$R@
+M`@G(.M=AH"`/-`@*"H("[W6@(!T87_G.5SVZ_4Q([7M?$.PE/_H%SG[XTU\`
+M%LC"%KKPA3",(0`;&(`(#@0#7!N(%*)0D"AX[P,%^8`&!6(^]/WH@R4*H0C=
+M5\+ZW2]_^Y.A%*=(Q2HFD(8V%`@&2%$04D"A(%#`0\\*XK.WN0U!':Q;B80T
+M@*TY$7\(.!`9TB"'PATN<8MKA_,$(@#FE6B/`1&`SPB2`>EQSHAT0^3IKJ<Z
+M`(`#`/#XAR0G"8^#*!*)`3@`G)H0@R:>L!'X2\"!YI"'-L3`CH@+Q4!"T0X_
+MFJ@@/"J(`"(Y24G"8PI,$(.)`K`%*_KREV'`(@3I41!Z=*$@77CD.VHI2;\9
+MY)+KTV06FD"Q^=4/E$T0)0!(V089H+(=JA0(*UWI2D`"0`#+9.8[<*E+$_42
+MF/"4HC`)@L/(!<\+!?'"(]W!S'^XPY)IQ*0TFS`#3PH.F]KDY@R^&<Z`C!.6
+MY90E/YGI#G;N\IWQS*@+YWE#6-@3%E\H2$C3%A'\,2"*_^.H%@\R08*@P)P"
+M`!]!-F!(ZO6.!(K4GNKPMX`#`1"5I`C$0`)!"G+"$J87)$@':JK(G#+2=`#`
+MGP)\ZC^@"E4@1#4J06)).2`2Y`-,3:-34V<Z7`Z!1#S0J`S#.@`?"6"19(7K
+M]@"`2R*0J`=J7:OF#AF`MIY3KJK3:5G=1"(?Y%6OT]N17]\J6,!"E:20C:QD
+M)YN0VPUR(&7<'1IO^CLA':A^Q+OC\0+".)A&E'*7Q5I8;]K8Q@+@=I83B.YR
+MM-GT=?9NP3MA:(V71^4%!')'E65LJ;;:]+7VJ>JCK'*7R]SFBDU/K50`%0Z1
+MVR1`X0N6"I:CD%`$$&!H"$OP;A*(<(3NYFI.4JA5$$#572A@Z%&!8@((W/L$
+M*XSW32"80A6@``5!46%-D.KO%)*`A36UJ;MPDA.=\DNG]5(A"4/(FYN",(7N
+M!LH)5`C"$/X;-%K-MPI"P-44N+LG(T`J;X!*`IN&X*@D/,$)^?54>C<%H0JW
+M%\0B)C&8\H1A%2=!3V""L7N3T(0@2"$+(+#"$YA0A29T-T^TDH)U'U5B2%TX
+MPQL.LHFE4.0'O]@%S@VSF,=,9OV@H0QL8,,;*E6#&2B@S'".LYSG3.<ZV_G.
+M>,ZSGM]SYC2O.0;'>O.>!TWH0AOZT(A.M*(7S>A&>Z7/:F9S#`3MZ$I;^M*8
+MSK2F-\WI3GOZTZ`.M:A'3>I2F_K4J$ZUJE?-ZE:[^M6PCK6L9TWK6MOZUKC.
+MM:YWS>M>^_K7P`ZVL(=-[&(;^]C(3K:RE\WL9CO[V=".MK2G3>UJ6_O:V,ZV
+MMK?-[6Y[^]O@#K>XQTWN<IO[W.A.M[K7S>YVN_O=\(ZWO.=-[WK;^][XSK>^
+M]\WO?OO[WP`/N,`'3O""&_S@"$^XPA?.\(8[_.$0C[C$)T[QBEO\XAC/N,8W
+MSO&.>_SC(`^YR$=.\I*;_.0H3[G*5\[REKO\Y3"/N<QG3O.:V_SF.,^YSG?.
+M\Y[[_.=`#[K0AT[THAO]Z$A/NM*7SO2F._WI4(^ZU*=.]:I;_>I8S[K6M\[U
+MKGO]ZV`/N]C'3O:RF_WL:$^[VM?.]K:[_>UPC[O<YT[WNMO][GC/N][WSO>^
+M^_WO@`^\X`=/^,(;_O"(3[SB%\_XQCO^\9"/O.0G3_G*6_[RF,^\YC?/^<Y[
+M_O.@#[WH1T_ZTIO^]*A/O>I7S_K6N_[UL(^][&=/^]K;_O:XS[WN=\_[WOO^
+M]\`/OO"'3_SB&__XR$^^\I?/_.8[__G0C[[TIT_]ZEO_^MC/OO:WS_WN>__[
+MX`^_^,=/_O*;__SH3[_ZU\_^]KO__?"/O_SG3__ZV__^^,^__O?/__[[__\`
+M&(`".(`$6(`&>(`(F(`*N(`,V(`.^(`0&($2.($46($6>($8F($:N($<V($>
+M^($@&((B.((D6((F>((HF((JN((LV((N^((P&(,R.(,T6(,V>(,XF(,ZN(,\
+MV(,^^(-`&(1".(1$6(1&>(1(F(1*N(1,V(1.^(10&(52.(546(56>(58F(5:
+MN(5<V(5>^(5@&(9B.(9D6(9F>(9HF(9JN(9LV(9N^(9P&(=R.(=T6(=V>(=X
+MF(=ZN(=\V(=^^(>`&(B".(B$6(B&>(B(F(B*N(B,V(B.^(B0&(F2.(F46(F6
+*>(F8F(F:N(D_`0``
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_iso_rockridge_zf_overflow.c b/contrib/libarchive/libarchive/test/test_read_format_iso_rockridge_zf_overflow.c
new file mode 100644
index 000000000000..3768669e6ddf
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_iso_rockridge_zf_overflow.c
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2026 Kaif Khan
+ * 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"
+
+/*
+ * parse_rockridge_ZF1() reads data[0] and data[1] before checking that the
+ * "ZF" entry is long enough (the data_length == 12 test was the last term of
+ * the condition). A "ZF" entry with a length byte of 5 yields data_length 1,
+ * so data[1] reads one byte past the SUSP area validated by parse_rockridge().
+ *
+ * The reference image carries the "ZF" entry in a "CE" continuation block that
+ * is the final logical block of the image, so the over-read lands one byte
+ * past the end of the buffer that holds the block. Reading the image from an
+ * exactly-sized memory buffer makes the over-read observable to AddressSanitizer
+ * (a padded buffer would hide it). With the fix the short entry is rejected and
+ * the read completes.
+ */
+DEFINE_TEST(test_read_format_iso_rockridge_zf_overflow)
+{
+ const char *refname = "test_read_format_iso_rockridge_zf_overflow.iso";
+ struct archive *a;
+ struct archive_entry *ae;
+ char *buff, *exact;
+ size_t used;
+ int r;
+
+ extract_reference_file(refname);
+
+ /* slurpfile() over-allocates by one byte; copy into an exactly-sized
+ * buffer so a single-byte over-read is not masked. */
+ buff = slurpfile(&used, "%s", refname);
+ assert(buff != NULL);
+ assert(used > 0);
+ assert((exact = malloc(used)) != NULL);
+ memcpy(exact, buff, used);
+ free(buff);
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_memory(a, exact, used));
+
+ /* Walk the image to completion. The malformed "ZF" entry is parsed
+ * while reading the root directory's continuation block; before the
+ * fix this over-reads the block buffer. */
+ while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK ||
+ r == ARCHIVE_WARN)
+ archive_read_data_skip(a);
+ assert(r == ARCHIVE_EOF || r == ARCHIVE_FATAL);
+
+ assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+ free(exact);
+}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_iso_rockridge_zf_overflow.iso.uu b/contrib/libarchive/libarchive/test/test_read_format_iso_rockridge_zf_overflow.iso.uu
new file mode 100644
index 000000000000..1ca39dfe7859
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_iso_rockridge_zf_overflow.iso.uu
@@ -0,0 +1,1096 @@
+begin 664 test_read_format_iso_rockridge_zf_overflow.iso
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````!0T0P,#$!`"`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
+M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("```````````!@`
+M```````8```````````````````````````````````````````!```!`0``
+M`0`("```"``````(`!(````````````````````B`!8````````6``@`````
+M"`!Z`0$``````@```0```0$`````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````$`````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````/]#1#`P,0$`````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````N`!8````````6``@`````"`!Z`0$``````@```0```0$`
+M4U`'`;[O`%!$!0$`(@`6````````%@`(``````@`>@$!``````(```$```$!
+M`3X`%P```````!<``````````'H!`0`````"```!```!`4%#11P!%P``````
+M`!<````````````(``````@`````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+M"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$"0$``````%!$
+,"0$``````%I&!0%P
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_isojoliet_bz2.c b/contrib/libarchive/libarchive/test/test_read_format_isojoliet_compress.c
index 68a9486e7aac..9e509fc62b9c 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_isojoliet_bz2.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_isojoliet_compress.c
@@ -2,7 +2,7 @@
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
- * Based on libarchive/test/test_read_format_isorr_bz2.c with
+ * Based on libarchive/test/test_read_format_isorr_compress.c with
* bugs introduced by Andreas Henriksson <andreas@fatal.se> for
* testing ISO9660 image with Joliet extension.
*
@@ -30,7 +30,7 @@
/*
Execute the following to rebuild the data for this program:
- tail -n +35 test_read_format_isojoliet_bz2.c | /bin/sh
+ tail -n +35 test_read_format_isojoliet_compress.c | /bin/sh
rm -rf /tmp/iso
mkdir /tmp/iso
@@ -51,7 +51,7 @@ uuencode $F $F > $F.uu
exit 1
*/
-DEFINE_TEST(test_read_format_isojoliet_bz2)
+DEFINE_TEST(test_read_format_isojoliet_compress)
{
const char *refname = "test_read_format_iso_joliet.iso.Z";
struct archive_entry *ae;
diff --git a/contrib/libarchive/libarchive/test/test_read_format_isorr_ce_loop.c b/contrib/libarchive/libarchive/test/test_read_format_isorr_ce_loop.c
new file mode 100644
index 000000000000..b1cdd6e82aa8
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_isorr_ce_loop.c
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2026 Zhihan Zheng
+ * 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"
+
+/*
+ * A malformed Rock Ridge ISO whose first CE continuation area contains
+ * another CE entry that points back to the same area. The parser should
+ * reject this self-referential continuation chain with ARCHIVE_FATAL
+ * instead of looping while reading headers.
+ */
+
+DEFINE_TEST(test_read_format_isorr_ce_loop)
+{
+ const char *refname = "test_read_format_iso_rockridge_ce_loop.iso.Z";
+ struct archive *a;
+ struct archive_entry *ae;
+ int r;
+
+ extract_reference_file(refname);
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240));
+
+ /* Read entries until the self-referential CE is reached. */
+ while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK)
+ archive_read_data_skip(a);
+
+ /* The parser should reject the self-referential CE with ARCHIVE_FATAL. */
+ assertEqualIntA(a, ARCHIVE_FATAL, r);
+ assert(archive_errno(a) != 0);
+ assert(archive_error_string(a) != NULL);
+
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_isorr_bz2.c b/contrib/libarchive/libarchive/test/test_read_format_isorr_compress.c
index c1accea78792..f1164bce1ae4 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_isorr_bz2.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_isorr_compress.c
@@ -29,7 +29,7 @@ PLEASE use old cdrtools; mkisofs version is 2.01.
This version mkisofs made wrong "SL" System Use Entry of RRIP.
Execute the following command to rebuild the data for this program:
- tail -n +34 test_read_format_isorr_bz2.c | /bin/sh
+ tail -n +34 test_read_format_isorr_compress.c | /bin/sh
rm -rf /tmp/iso
mkdir /tmp/iso
@@ -51,7 +51,7 @@ uuencode $F $F > $F.uu
exit 1
*/
-DEFINE_TEST(test_read_format_isorr_bz2)
+DEFINE_TEST(test_read_format_isorr_compress)
{
const char *refname = "test_read_format_iso_rockridge.iso.Z";
struct archive_entry *ae;
@@ -68,7 +68,7 @@ DEFINE_TEST(test_read_format_isorr_bz2)
assertEqualInt(ARCHIVE_OK,
archive_read_open_filename(a, refname, 10240));
- /* Retrieve each of the 8 files on the ISO image and
+ /* Retrieve each of the 10 entries on the ISO image and
* verify that each one is what we expect. */
for (i = 0; i < 10; ++i) {
assertEqualInt(0, archive_read_next_header(a, &ae));
diff --git a/contrib/libarchive/libarchive/test/test_read_format_isorr_new_bz2.c b/contrib/libarchive/libarchive/test/test_read_format_isorr_new_compress.c
index 787c1e6301be..43aea982ff48 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_isorr_new_bz2.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_isorr_new_compress.c
@@ -29,7 +29,7 @@ PLEASE use latest cdrtools at least mkisofs version is 2.01.01a63 or later.
Old version mkisofs made wrong "SL" System Use Entry of RRIP.
Execute the following command to rebuild the data for this program:
- tail -n +34 test_read_format_isorr_new_bz2.c | /bin/sh
+ tail -n +34 test_read_format_isorr_new_compress.c | /bin/sh
rm -rf /tmp/iso
mkdir /tmp/iso
@@ -51,7 +51,7 @@ uuencode $F $F > $F.uu
exit 1
*/
-DEFINE_TEST(test_read_format_isorr_new_bz2)
+DEFINE_TEST(test_read_format_isorr_new_compress)
{
const char *refname = "test_read_format_iso_rockridge_new.iso.Z";
struct archive_entry *ae;
@@ -68,7 +68,7 @@ DEFINE_TEST(test_read_format_isorr_new_bz2)
assertEqualInt(ARCHIVE_OK,
archive_read_open_filename(a, refname, 10240));
- /* Retrieve each of the 8 files on the ISO image and
+ /* Retrieve each of the 10 entries on the ISO image and
* verify that each one is what we expect. */
for (i = 0; i < 10; ++i) {
assertEqualInt(0, archive_read_next_header(a, &ae));
diff --git a/contrib/libarchive/libarchive/test/test_read_format_isozisofs_bz2.c b/contrib/libarchive/libarchive/test/test_read_format_isozisofs_compress.c
index 3f059fde08b5..2ca3ff52e21f 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_isozisofs_bz2.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_isozisofs_compress.c
@@ -26,7 +26,7 @@
/*
Execute the following command to rebuild the data for this program:
- tail -n +32 test_read_format_isozisofs_bz2.c | /bin/sh
+ tail -n +32 test_read_format_isozisofs_compress.c | /bin/sh
rm -rf /tmp/iso /tmp/ziso
mkdir /tmp/iso
@@ -50,7 +50,7 @@ exit 1
*/
-DEFINE_TEST(test_read_format_isozisofs_bz2)
+DEFINE_TEST(test_read_format_isozisofs_compress)
{
const char *refname = "test_read_format_iso_zisofs.iso.Z";
struct archive_entry *ae;
diff --git a/contrib/libarchive/libarchive/test/test_read_format_lha.c b/contrib/libarchive/libarchive/test/test_read_format_lha.c
index 93e79183e5c3..b323cb3c86a5 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_lha.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_lha.c
@@ -266,7 +266,7 @@ verify(const char *refname, int posix)
assertEqualIntA(a, ARCHIVE_FORMAT_LHA, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_lha_bugfix_0.c b/contrib/libarchive/libarchive/test/test_read_format_lha_bugfix_0.c
index bbdcb81569b6..342dd1ef3c70 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_lha_bugfix_0.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_lha_bugfix_0.c
@@ -69,7 +69,7 @@ DEFINE_TEST(test_read_format_lha_bugfix_0)
assertEqualIntA(a, ARCHIVE_FORMAT_LHA, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_lha_filename.c b/contrib/libarchive/libarchive/test/test_read_format_lha_filename.c
index d726f6245d7d..22c303aa4b3e 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_lha_filename.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_lha_filename.c
@@ -85,7 +85,7 @@ test_read_format_lha_filename_CP932_eucJP(const char *refname)
assertEqualIntA(a, ARCHIVE_FORMAT_LHA, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -145,7 +145,7 @@ test_read_format_lha_filename_CP932_UTF8(const char *refname)
assertEqualIntA(a, ARCHIVE_FORMAT_LHA, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -195,7 +195,7 @@ test_read_format_lha_filename_CP932_Windows(const char *refname)
assertEqualIntA(a, ARCHIVE_FORMAT_LHA, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
#else
diff --git a/contrib/libarchive/libarchive/test/test_read_format_lha_filename_utf16.c b/contrib/libarchive/libarchive/test/test_read_format_lha_filename_utf16.c
index d0710799bba4..f700ec3c3ebb 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_lha_filename_utf16.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_lha_filename_utf16.c
@@ -127,7 +127,7 @@ test_read_format_lha_filename_UTF16_UTF8(const char *refname)
assertEqualIntA(a, ARCHIVE_FORMAT_LHA, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_lha_symlink_missing_target.c b/contrib/libarchive/libarchive/test/test_read_format_lha_symlink_missing_target.c
new file mode 100644
index 000000000000..4ac38b7a18d0
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_lha_symlink_missing_target.c
@@ -0,0 +1,159 @@
+/*-
+ * Copyright (c) 2026 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"
+#include <fcntl.h>
+
+/*
+ * A malformed symlink entry (one whose pathname lacks the required '|'
+ * separator should FAIL the entry but the client should be able to recover
+ * and read the following entry.
+ *
+ * This was an existing behavior of the LHA reader that was incorrectly
+ * handled by the read core (it got translated into a FATAL archive condition).
+ * Recent fixes to the read core enabled this to work as intended.
+ */
+
+static struct archive *
+open_fixture(const char *refname)
+{
+ struct archive *a;
+
+ extract_reference_file(refname);
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_filename(a, refname, 4096));
+ return a;
+}
+
+static void
+test_recovery(const char *refname)
+{
+ struct archive *a = open_fixture(refname);
+ struct archive_entry *ae;
+ char buff[32];
+
+ failure("LHA's own ARCHIVE_FAILED from read_header must propagate, "
+ "not be silently swallowed or crash");
+ assertEqualIntA(a, ARCHIVE_FAILED, archive_read_next_header(a, &ae));
+
+ failure("archive_read_next_header() must still be able to advance "
+ "past a failed entry to the next one");
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("second", archive_entry_pathname(ae));
+ assertEqualInt(11, (int)archive_read_data(a, buff, sizeof(buff)));
+ assertEqualMem(buff, "hello world", 11);
+
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
+static void
+test_illegal_read_data(const char *refname)
+{
+ struct archive *a = open_fixture(refname);
+ struct archive_entry *ae;
+ char buff[32];
+
+ assertEqualIntA(a, ARCHIVE_FAILED, archive_read_next_header(a, &ae));
+
+ failure("archive_read_data() must refuse content from a failed "
+ "entry, not return real (or garbage) bytes");
+ assert(archive_read_data(a, buff, sizeof(buff)) < 0);
+
+ failure("the archive must stay unusable after that misuse, not "
+ "silently recover");
+ assert(archive_read_next_header(a, &ae) < 0);
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
+static void
+test_illegal_read_data_block(const char *refname)
+{
+ struct archive *a = open_fixture(refname);
+ struct archive_entry *ae;
+ const void *buff;
+ size_t size;
+ int64_t offset;
+
+ assertEqualIntA(a, ARCHIVE_FAILED, archive_read_next_header(a, &ae));
+ failure("archive_read_data_block() must refuse a failed entry");
+ assert(archive_read_data_block(a, &buff, &size, &offset) < 0);
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
+static void
+test_illegal_seek_data(const char *refname)
+{
+ struct archive *a = open_fixture(refname);
+ struct archive_entry *ae;
+
+ assertEqualIntA(a, ARCHIVE_FAILED, archive_read_next_header(a, &ae));
+ failure("archive_seek_data() must refuse a failed entry");
+ assert(archive_seek_data(a, 0, SEEK_SET) < 0);
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
+static void
+test_illegal_read_data_into_fd(const char *refname)
+{
+ struct archive *a = open_fixture(refname);
+ struct archive_entry *ae;
+ int fd;
+
+ assertEqualIntA(a, ARCHIVE_FAILED, archive_read_next_header(a, &ae));
+ fd = open("data_into_fd_lha.out", O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ assert(fd >= 0);
+ failure("archive_read_data_into_fd() must refuse a failed entry");
+ assert(archive_read_data_into_fd(a, fd) < 0);
+ close(fd);
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
+static void
+test_explicit_skip(const char *refname)
+{
+ struct archive *a = open_fixture(refname);
+ struct archive_entry *ae;
+
+ assertEqualIntA(a, ARCHIVE_FAILED, archive_read_next_header(a, &ae));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_data_skip(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("second", archive_entry_pathname(ae));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
+DEFINE_TEST(test_read_format_lha_symlink_missing_target)
+{
+ const char *refname =
+ "test_read_format_lha_symlink_missing_target.lzh";
+
+ test_recovery(refname);
+ test_illegal_read_data(refname);
+ test_illegal_read_data_block(refname);
+ test_illegal_seek_data(refname);
+ test_illegal_read_data_into_fd(refname);
+ test_explicit_skip(refname);
+}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_lha_symlink_missing_target.lzh.uu b/contrib/libarchive/libarchive/test/test_read_format_lha_symlink_missing_target.lzh.uu
new file mode 100644
index 000000000000..9213c54704f0
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_lha_symlink_missing_target.lzh.uu
@@ -0,0 +1,11 @@
+Level-0 LHA archive with two entries: "bad_symlink" is a symlink
+(Unix-extended mode field, S_IFLNK) whose pathname has no '|' separator,
+so lha_parse_linkname() can't extract a link target and read_header()
+returns ARCHIVE_FAILED; "second" is a normal stored file. See
+test_read_format_lha_symlink_missing_target.c.
+
+begin 644 test_read_format_lha_symlink_missing_target.lzh
+M+>LM;&@P+0``````````````````"V)A9%]S>6UL:6YK``!5``````#_H0``
+J```:]BUL:#`M"P````L````````````&<V5C;VYD:&5L;&\@=V]R;&0`
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_mtree.c b/contrib/libarchive/libarchive/test/test_read_format_mtree.c
index b4463298dde2..a38b27038a43 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_mtree.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_mtree.c
@@ -269,7 +269,7 @@ test_read_format_mtree1(void)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
assertEqualInt(30, archive_file_count(a));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -299,7 +299,7 @@ test_read_format_mtree2(void)
assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED);
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
assertEqualInt(1, archive_file_count(a));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -348,7 +348,7 @@ test_read_format_mtree3(void)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
assertEqualInt(3, archive_file_count(a));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
assertChdir("..");
@@ -418,7 +418,7 @@ DEFINE_TEST(test_read_format_mtree_filenames_only)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
assertEqualInt(6, archive_file_count(a));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -477,7 +477,7 @@ DEFINE_TEST(test_read_format_mtree_nochange)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
assertEqualInt(3, archive_file_count(a));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
/*
@@ -518,7 +518,7 @@ DEFINE_TEST(test_read_format_mtree_nochange)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
assertEqualInt(3, archive_file_count(a));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -620,7 +620,7 @@ DEFINE_TEST(test_read_format_mtree_nomagic_v1_form)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
assertEqualInt(12, archive_file_count(a));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -687,7 +687,7 @@ DEFINE_TEST(test_read_format_mtree_nomagic_v2_form)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
assertEqualInt(6, archive_file_count(a));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -754,7 +754,7 @@ DEFINE_TEST(test_read_format_mtree_nomagic_v2_netbsd_form)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
assertEqualInt(6, archive_file_count(a));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -785,7 +785,7 @@ DEFINE_TEST(test_read_format_mtree_nonexistent_contents_file)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
assertEqualInt(1, archive_file_count(a));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -811,7 +811,7 @@ DEFINE_TEST(test_read_format_mtree_noprint)
assertEqualIntA(a, ARCHIVE_FATAL, archive_read_next_header(a, &ae));
assertEqualString("Can't parse line 3", archive_error_string(a));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -840,6 +840,73 @@ DEFINE_TEST(test_read_format_mtree_tab)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
assertEqualInt(1, archive_file_count(a));
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
+DEFINE_TEST(test_read_format_mtree_nano)
+{
+ static char archive[] =
+ "#mtree\n"
+ "a type=file time=1234567890.1000000000000 contents=nonexistent_file\n"
+ "b type=file time=1234567899.-1000000000000 contents=nonexistent_file\n";
+ struct archive_entry *ae;
+ struct archive *a;
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_memory(a, archive, sizeof(archive)));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString(archive_entry_pathname(ae), "a");
+ assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
+ assertEqualIntA(a, archive_entry_mtime(ae), 1234567890);
+ assertEqualIntA(a, archive_entry_mtime_nsec(ae), 999999999);
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString(archive_entry_pathname(ae), "b");
+ assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
+ assertEqualIntA(a, archive_entry_mtime(ae), 1234567899);
+ assertEqualIntA(a, archive_entry_mtime_nsec(ae), 0);
+
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+ assertEqualInt(2, archive_file_count(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
+/*
+ * A /set line whose value-less keyword (no '=') repeats made
+ * process_global_set() compute a bogus length and over-read the option
+ * buffer in remove_option(). Parsing must stay in bounds and succeed.
+ */
+DEFINE_TEST(test_read_format_mtree_global_set_no_value)
+{
+ static char archive[] =
+ "#mtree\n"
+ "/set nochange nochange\n"
+ "a type=file\n";
+ struct archive_entry *ae;
+ struct archive *a;
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_memory(a, archive, sizeof(archive)));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString(archive_entry_pathname(ae), "a");
+ assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
+
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+ assertEqualInt(1, archive_file_count(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_pax_bz2.c b/contrib/libarchive/libarchive/test/test_read_format_pax_bz2.c
index 4f11137b9c6f..1e3cb07919a8 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_pax_bz2.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_pax_bz2.c
@@ -48,8 +48,8 @@ DEFINE_TEST(test_read_format_pax_bz2)
assert((a = archive_read_new()) != NULL);
r = archive_read_support_filter_bzip2(a);
if (r != ARCHIVE_OK) {
- archive_read_close(a);
skipping("Bzip2 unavailable");
+ archive_read_free(a);
return;
}
assertEqualIntA(a,ARCHIVE_OK, archive_read_support_format_all(a));
diff --git a/contrib/libarchive/libarchive/test/test_read_format_rar.c b/contrib/libarchive/libarchive/test/test_read_format_rar.c
index 59e83846c863..b4b16c66ec9c 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_rar.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_rar.c
@@ -592,6 +592,42 @@ DEFINE_TEST(test_read_format_rar_multi_lzss_blocks)
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
+DEFINE_TEST(test_read_format_rar3_lowdist_reset)
+{
+ const char reffile[] = "test_read_format_rar3_lowdist_reset.rar";
+ const unsigned char expected[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x0d, 0x0e,
+ 0x0f, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
+ 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36
+ };
+ unsigned char buff[sizeof(expected)];
+ struct archive_entry *ae;
+ struct archive *a;
+
+ extract_reference_file(reffile);
+ assert((a = archive_read_new()) != NULL);
+ assertA(0 == archive_read_support_filter_all(a));
+ assertA(0 == archive_read_support_format_rar(a));
+ assertA(0 == archive_read_open_filename(a, reffile, 10240));
+
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertEqualString("lowdist-reset.bin", archive_entry_pathname(ae));
+ assertEqualInt(sizeof(expected), archive_entry_size(ae));
+ assertEqualIntA(a, sizeof(expected),
+ archive_read_data(a, buff, sizeof(buff)));
+ assertEqualMem(buff, expected, sizeof(expected));
+
+ assertA(1 == archive_read_next_header(a, &ae));
+ assertEqualInt(1, archive_file_count(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
DEFINE_TEST(test_read_format_rar_compress_best)
{
const char reffile[] = "test_read_format_rar_compress_best.rar";
@@ -3807,7 +3843,7 @@ DEFINE_TEST(test_read_format_rar_multivolume_uncompressed_files)
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
assertEqualIntA(a, 16, archive_file_count(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
- assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
DEFINE_TEST(test_read_format_rar_endarc_huge)
@@ -3882,6 +3918,28 @@ DEFINE_TEST(test_read_format_rar_ppmd_use_after_free2)
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
+DEFINE_TEST(test_read_format_rar_seek_data_cursor0)
+{
+ const char* reffile = "test_read_format_rar_seek_data_cursor0.rar";
+
+ struct archive_entry *ae;
+ struct archive *a;
+
+ extract_reference_file(reffile);
+ assert((a = archive_read_new()) != NULL);
+ assertA(0 == archive_read_support_filter_all(a));
+ assertA(0 == archive_read_support_format_all(a));
+ assertA(0 == archive_read_open_filename(a, reffile, 10240));
+
+ assertA(ARCHIVE_OK == archive_read_next_header(a, &ae));
+
+ failure("RAR seek should reject an invalid cursor state");
+ assert(archive_seek_data(a, -1, SEEK_END) < 0);
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
DEFINE_TEST(test_read_format_rar_newsub_huge)
{
#if SIZE_MAX == UINT64_MAX
@@ -3906,6 +3964,54 @@ DEFINE_TEST(test_read_format_rar_newsub_huge)
#endif
}
+DEFINE_TEST(test_read_format_rar_newsub_rr_over_1m)
+{
+ const char* reffile = "test_read_format_rar_newsub_rr_over_1m.rar";
+ struct archive_entry *ae;
+ struct archive *a;
+
+ extract_reference_file(reffile);
+ assert((a = archive_read_new()) != NULL);
+ assertA(0 == archive_read_support_filter_all(a));
+ assertA(0 == archive_read_support_format_rar(a));
+ assertA(0 == archive_read_open_filename(a, reffile, 10240));
+
+ failure("RAR NEWSUB RR records larger than 1 MiB should be skipped");
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
+DEFINE_TEST(test_read_format_rar_newsub_huge64)
+{
+ static const unsigned char archive[] = {
+ 'R', 'a', 'r', '!', 0x1a, 0x07, 0x00,
+ 0x23, 0x25, 0x7a, 0x00, 0x01, 0x28, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x7f, 0x00, 0x00, 0x00, 0x00
+ };
+ struct archive_entry *ae;
+ struct archive *a;
+
+ assert((a = archive_read_new()) != NULL);
+ assertA(0 == archive_read_support_filter_all(a));
+ assertA(0 == archive_read_support_format_rar(a));
+ assertA(0 == archive_read_open_memory(a, archive, sizeof(archive)));
+
+ failure("Malformed RAR NEWSUB header should be rejected if its "
+ "extended data is missing");
+ assertEqualIntA(a, ARCHIVE_FATAL, archive_read_next_header(a, &ae));
+ assertEqualString("Invalid RAR file: Cannot read extended header data",
+ archive_error_string(a));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
DEFINE_TEST(test_read_format_rar_symlink_huge)
{
#if SIZE_MAX == UINT64_MAX
@@ -3929,3 +4035,24 @@ DEFINE_TEST(test_read_format_rar_symlink_huge)
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
#endif
}
+
+DEFINE_TEST(test_read_format_rar_unbound_staticdata)
+{
+ const char* reffile = "test_read_format_rar_unbound_staticdata.rar";
+
+ struct archive_entry *ae;
+ struct archive *a;
+ char buf[64];
+
+ extract_reference_file(reffile);
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, reffile, 1024));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualIntA(a, ARCHIVE_FAILED, archive_read_data(a, buf, 64));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_rar3_lowdist_reset.rar.uu b/contrib/libarchive/libarchive/test/test_read_format_rar3_lowdist_reset.rar.uu
new file mode 100644
index 000000000000..3bb7ed9cbfb9
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_rar3_lowdist_reset.rar.uu
@@ -0,0 +1,16 @@
+begin 644 test_read_format_rar3_lowdist_reset.rar
+M4F%R(1H' ,^0<P #0 !J470 @#$ Z@$ $ #W#CX;P =
+M-1$ ( &QO=V1I<W0M<F5S970N8FEN$1$1$1$1%55556(B(B(B(B(B(B(B
+M(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B
+M(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B
+M(B(B(B(B9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F
+M9F9F9555F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F1$1$1$1$1$541$5
+M555555555555555 $" P0%!@<("0H+# T.#Q 1$A,4%187&!D:&QP='A\@(
+M2(C)"4F)_(<OD._U8!$1$1$1$155555B(B(B(B(B(B(B(B(B(B(B(B(B(B(B
+M(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B
+M(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(B(F9F9F9F
+M9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F9F5559F9F9F9
+MF9F9F9F9F9F9F9F9F9F9F9F9F9F9F9D1$1$1$1$1%5$1%555555555555555
+:?(<!04E166%I<7F!B9&9H:FW5,0]>P! !P
+
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_rar5.c b/contrib/libarchive/libarchive/test/test_read_format_rar5.c
index 6ab0d236a1ed..01881c1dd3d6 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_rar5.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_rar5.c
@@ -1452,7 +1452,7 @@ DEFINE_TEST(test_read_format_rar5_only_crypt_exfld)
during data extraction. */
assertA(archive_read_next_header(a, &ae) == ARCHIVE_OK);
- assertA(archive_read_data(a, buf, sizeof(buf)) == ARCHIVE_FATAL);
+ assertA(archive_read_data(a, buf, sizeof(buf)) == ARCHIVE_FAILED);
/* The reader should also provide a valid error message. */
assertA(archive_error_string(a) != NULL);
@@ -1494,3 +1494,123 @@ DEFINE_TEST(test_read_format_rar5_invalidhash_and_validhtime_exfld)
EPILOGUE();
}
+
+/*
+ * Regression tests for the RAR5 base-block parser leaving unconsumed body
+ * bytes before returning ARCHIVE_RETRY (GHSA-9h2c-464f-j3hj). Each archive is
+ * the test_read_format_rar5_stored archive with extra, unread bytes appended
+ * to a no-data block's body. Before the fix the reader did not skip those
+ * bytes, so the stream misaligned and the following file entry was lost; with
+ * the fix the trailing bytes are skipped and helloworld.txt is read normally.
+ */
+DEFINE_TEST(test_read_format_rar5_main_block_extra_bytes)
+{
+ const char helloworld_txt[] = "hello libarchive test suite!\n";
+ la_ssize_t file_size = sizeof(helloworld_txt) - 1;
+ char buff[64];
+
+ /* HEAD_MAIN block padded with trailing bytes the parser does not read. */
+ PROLOGUE("test_read_format_rar5_main_block_extra_bytes.rar");
+
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertEqualString("helloworld.txt", archive_entry_pathname(ae));
+ assertEqualInt(file_size, archive_entry_size(ae));
+ assertA(file_size == archive_read_data(a, buff, file_size));
+ assertEqualMem(buff, helloworld_txt, file_size);
+
+ assertA(ARCHIVE_EOF == archive_read_next_header(a, &ae));
+
+ EPILOGUE();
+}
+
+DEFINE_TEST(test_read_format_rar5_skip_block_extra_bytes)
+{
+ const char helloworld_txt[] = "hello libarchive test suite!\n";
+ la_ssize_t file_size = sizeof(helloworld_txt) - 1;
+ char buff[64];
+
+ /* An unknown HFL_SKIP_IF_UNKNOWN block carrying trailing bytes is inserted
+ * before the file entry; the parser must skip the entire block. */
+ PROLOGUE("test_read_format_rar5_skip_block_extra_bytes.rar");
+
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertEqualString("helloworld.txt", archive_entry_pathname(ae));
+ assertEqualInt(file_size, archive_entry_size(ae));
+ assertA(file_size == archive_read_data(a, buff, file_size));
+ assertEqualMem(buff, helloworld_txt, file_size);
+
+ assertA(ARCHIVE_EOF == archive_read_next_header(a, &ae));
+
+ EPILOGUE();
+}
+
+DEFINE_TEST(test_read_format_rar5_bytes_remaining_underflow)
+{
+ /* GH #2986 — CWE-191 signed integer underflow on
+ * rar->file.bytes_remaining in process_block(). A malformed RAR5
+ * archive whose compressed-block to_skip value exceeds the declared
+ * remaining file data drives bytes_remaining negative; the negative
+ * ssize_t later reaches read_ahead() and is implicitly converted to
+ * a near-SIZE_MAX malloc request (CWE-122).
+ *
+ * The patched reader must reject the malformed archive with
+ * ARCHIVE_FATAL before the negative value is reached. */
+
+ char buf[4096];
+ la_ssize_t r;
+ PROLOGUE("test_read_format_rar5_bytes_remaining_underflow.rar");
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("poc.txt", archive_entry_pathname(ae));
+
+ do {
+ r = archive_read_data(a, buf, sizeof(buf));
+ } while (r > 0);
+
+ assertEqualIntA(a, ARCHIVE_FATAL, r);
+ assertA(archive_error_string(a) != NULL);
+
+ EPILOGUE();
+}
+
+DEFINE_TEST(test_read_format_rar5_unpacked_size_exceeds_declared)
+{
+ PROLOGUE("test_read_format_rar5_unpacked_size_exceeds_declared.rar");
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("seed", archive_entry_pathname(ae));
+ assertEqualInt(109, archive_entry_size(ae));
+
+ assertEqualIntA(a, ARCHIVE_FATAL, archive_read_next_header(a, &ae));
+ assertA(archive_error_string(a) != NULL);
+
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
+/*
+ * RAR5 is a streaming unpacker and never implements seeking.
+ * archive_seek_data() on a RAR5 entry must report unsupported via
+ * ARCHIVE_FAILED without poisoning the archive state. See #3323.
+ */
+DEFINE_TEST(test_read_format_rar5_seek_data_unsupported)
+{
+ const int DATA_SIZE = 1200;
+ uint8_t buff[1200];
+
+ PROLOGUE("test_read_format_rar5_compressed.rar");
+
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertEqualString("test.bin", archive_entry_pathname(ae));
+
+ /* Capability probe. */
+ assertEqualIntA(a, ARCHIVE_FAILED,
+ archive_seek_data(a, 0, SEEK_CUR));
+ assertA(archive_error_string(a) != NULL);
+
+ /* Subsequent read must still return the real entry content. */
+ assertA(DATA_SIZE == archive_read_data(a, buff, DATA_SIZE));
+ assertA(ARCHIVE_EOF == archive_read_next_header(a, &ae));
+ assertA(1 == verify_data(buff, 0, DATA_SIZE));
+
+ EPILOGUE();
+}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_rar5_bad_filter.c b/contrib/libarchive/libarchive/test/test_read_format_rar5_bad_filter.c
new file mode 100644
index 000000000000..6f24bc7436c0
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_rar5_bad_filter.c
@@ -0,0 +1,130 @@
+/*-
+ * Copyright (c) 2025 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"
+
+/*
+ * Two-entry RAR5 archive. Entry 1 ("bad.txt") is compressed with a filter
+ * of unsupported type 4 (FILTER_AUDIO). Entry 2 ("ok.txt") is stored.
+ *
+ * Tests that an unsupported filter type in do_uncompress_file returns
+ * ARCHIVE_FAILED (not ARCHIVE_FATAL), so the archive is not aborted and
+ * the second entry is still readable.
+ *
+ * RAR5 outer block format: 4-byte LE CRC32 of (vint(hdr_size)+hdr_body),
+ * then vint(hdr_size), then hdr_body, then optional data area.
+ * Integers are vint: 7 bits per byte, LSB first, high bit = more follows.
+ */
+DEFINE_TEST(test_read_format_rar5_bad_filter)
+{
+ static const uint8_t data[] = {
+ /* RAR5 signature */
+ 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0x00,
+
+ /* Main archive header block (type=1):
+ * CRC32, vint(body_size=3), type=1, block_flags=0,
+ * archive_flags=0 */
+ 0xC5, 0x1A, 0x33, 0x32, 0x03, 0x01, 0x00, 0x00,
+
+ /* File header block for "bad.txt" (type=2, HFL_DATA flag set):
+ * CRC32, vint(body_size=17), type=2, HFL_DATA,
+ * packed_size=23, file_flags=0, unpacked_size=4,
+ * file_attr=0, compression_info=512 (method=GOOD,
+ * version=0, window_factor=0), host_os=1,
+ * name_len=7, "bad.txt" */
+ 0x88, 0xEC, 0xB0, 0x99, 0x11, 0x02, 0x02, 0x17,
+ 0x00, 0x04, 0x00, 0x80, 0x04, 0x01, 0x07, 0x62,
+ 0x61, 0x64, 0x2E, 0x74, 0x78, 0x74,
+
+ /* Compressed data block for "bad.txt" (23 bytes):
+ *
+ * Compressed block header (3 bytes):
+ * block_flags=0xC2: is_table_present, is_last_block,
+ * bf_bit_size=2 (block ends when
+ * in_addr==last_byte && bit_addr>=3)
+ * checksum=0x8C, block_size=20 */
+ 0xC2, 0x8C, 0x14,
+
+ /* Huffman meta-table (20 nibbles packed in 10 bytes):
+ * nibble[2]=1, nibble[19]=1, all others 0.
+ * Two 1-bit meta-symbols:
+ * code 0 -> sym 2 (store bit-length 2 for next entry)
+ * code 1 -> sym 19 (fill N+11 zeros, N in next 7 bits) */
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01,
+
+ /* Huffman main table + compressed data (MSB-first bitstream):
+ *
+ * Main table (ld[], 430 entries, 42 bits total):
+ * skip 97 zeros (sym19, n=86), ld[97]=2 (sym2, 'a'),
+ * skip 138 zeros, skip 20 zeros,
+ * ld[256]=2 (sym2, filter token), skip 138+35 zeros.
+ * Canonical codes: 00->sym97('a'), 01->sym256(filter).
+ *
+ * Compressed data (33 bits):
+ * 01 filter token (sym 256)
+ * 00,00000000 block_start: count=0->1 byte, value=0
+ * 00,00000100 block_length: count=0->1 byte, value=4
+ * 100 filter_type=4 (FILTER_AUDIO, unsupported;
+ * top 3 bits of a 16-bit read, 3 bits consumed)
+ * 00,00,00,00 four 'a' literals (sym 97, code 00 each) */
+ 0xD6, 0x7F, 0xC4, 0xBF, 0xE6, 0x10, 0x00, 0x04,
+ 0x80, 0x00,
+
+ /* File header block for "ok.txt" (type=2, HFL_DATA flag set):
+ * CRC32, vint(body_size=15), type=2, HFL_DATA,
+ * packed_size=3, file_flags=0, unpacked_size=3,
+ * file_attr=0, compression_info=0 (STORE),
+ * host_os=1, name_len=6, "ok.txt", data "ok\n" */
+ 0xB1, 0xC3, 0x30, 0x14, 0x0F, 0x02, 0x02, 0x03,
+ 0x00, 0x03, 0x00, 0x00, 0x01, 0x06, 0x6F, 0x6B,
+ 0x2E, 0x74, 0x78, 0x74, 0x6F, 0x6B, 0x0A,
+
+ /* End of archive block (type=5):
+ * CRC32, vint(body_size=2), type=5, block_flags=0 */
+ 0x39, 0xF9, 0xB2, 0x81, 0x02, 0x05, 0x00,
+ };
+
+ struct archive_entry *ae;
+ struct archive *a;
+ char buf[256];
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_rar5(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_memory(a, data, sizeof(data)));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("bad.txt", archive_entry_pathname(ae));
+ assertA(archive_read_data(a, buf, sizeof(buf)) < 0);
+ assertA(archive_error_string(a) != NULL &&
+ strstr(archive_error_string(a), "Unsupported filter type") != NULL);
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("ok.txt", archive_entry_pathname(ae));
+ assertEqualIntA(a, 3, archive_read_data(a, buf, sizeof(buf)));
+ assertEqualMem(buf, "ok\n", 3);
+
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_rar5_bad_tables.c b/contrib/libarchive/libarchive/test/test_read_format_rar5_bad_tables.c
new file mode 100644
index 000000000000..cb64face6376
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_rar5_bad_tables.c
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2026 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"
+
+/*
+ * The reference archive contains one compressed entry whose HUFF_BC
+ * meta-table has all 20 nibbles set to bit-length 1. This is an
+ * over-subscribed Huffman table (Kraft sum = 10 >> 1), which
+ * create_decode_tables() must reject. Reading the entry data must
+ * therefore fail, not succeed.
+ */
+DEFINE_TEST(test_read_format_rar5_bad_tables)
+{
+ const char *reffile = "test_read_format_rar5_bad_tables.rar";
+ struct archive_entry *ae;
+ struct archive *a;
+ const void *buf;
+ size_t size;
+ la_int64_t offset;
+
+ extract_reference_file(reffile);
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_open_filename(a, reffile, 10240));
+
+ /* The file header is valid; the bad data is in the compressed block. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+
+ /* Reading must fail because the meta-table is over-subscribed. */
+ assertEqualIntA(a, ARCHIVE_FAILED,
+ archive_read_data_block(a, &buf, &size, &offset));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_free(a));
+}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_rar5_bad_tables.rar.uu b/contrib/libarchive/libarchive/test/test_read_format_rar5_bad_tables.rar.uu
new file mode 100644
index 000000000000..eca915f7533b
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_rar5_bad_tables.rar.uu
@@ -0,0 +1,8 @@
+begin 644 test_read_format_rar5_bad_tables.rar
+M4F%R(1H'`0#%&C,R`P$``(C&P1@9`@*$`0!``(`$`0YB861?=&%B;&5S+G1X
+M=,@2@``1$1$1$1$1$1$1````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````````#GY
+%LH$"!0``
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_rar5_block_hdr_fail_loop.c b/contrib/libarchive/libarchive/test/test_read_format_rar5_block_hdr_fail_loop.c
new file mode 100644
index 000000000000..e447a2a8bcef
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_rar5_block_hdr_fail_loop.c
@@ -0,0 +1,37 @@
+#include "test.h"
+
+/*
+ * Regression test for infinite loop when parse_block_header() returns
+ * ARCHIVE_FAILED inside do_uncompress_file()'s while(1) loop.
+ *
+ * The loop only exited on ARCHIVE_EOF or ARCHIVE_FATAL. After converting
+ * per-entry block header errors from ARCHIVE_FATAL to ARCHIVE_FAILED, a
+ * malformed block header caused the loop to spin forever.
+ *
+ * Fuzzer-generated reproducer (37 bytes).
+ */
+DEFINE_TEST(test_read_format_rar5_block_hdr_fail_loop)
+{
+ /* RAR5 archive with a malformed compressed block header */
+ static const uint8_t data[] = {
+ 0x52,0x61,0x72,0x21,0x1a,0x07,0x01,0x00,
+ 0x86,0x7e,0xfa,0xe7,0x03,0x02,0x56,0x20,
+ 0x00,0x20,0x15,0xae,0x21,0x00,0x01,0x08,
+ 0x00,0x00,0x01,0x00,0x00,0x15,0x00,0xbe,
+ 0xc0,0x80,0x00,0xff,0xf4
+ };
+
+ struct archive *a = archive_read_new();
+ assert(a != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_rar5(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_open_memory(a,
+ data, sizeof(data)));
+
+ struct archive_entry *ae;
+ char buf[4096];
+ while (archive_read_next_header(a, &ae) == ARCHIVE_OK)
+ while (archive_read_data(a, buf, sizeof(buf)) > 0)
+ ;
+
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_rar5_bytes_remaining_underflow.rar.uu b/contrib/libarchive/libarchive/test/test_read_format_rar5_bytes_remaining_underflow.rar.uu
new file mode 100644
index 000000000000..2ea589d33874
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_rar5_bytes_remaining_underflow.rar.uu
@@ -0,0 +1,5 @@
+begin 644 test_read_format_rar5_bytes_remaining_underflow.rar
+M4F%R(1H' 0!3*C1% P$ =ANJWT1 A(! H @ $!!W!O8RYT>'1 '@0Y^;*!
+# @4
+
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_rar5_main_block_extra_bytes.rar.uu b/contrib/libarchive/libarchive/test/test_read_format_rar5_main_block_extra_bytes.rar.uu
new file mode 100644
index 000000000000..81533e4fd6e5
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_rar5_main_block_extra_bytes.rar.uu
@@ -0,0 +1,6 @@
+begin 644 test_read_format_rar5_main_block_extra_bytes.rar
+M4F%R(1H' 0 $ .>F$@$%!@ % 0& @ #@P!F,L @,+G0 $G0"D
+M@P*T0Z"5@ !#FAE;&QO=V]R;&0N='AT"@,3?@ZK6U;I#AIH96QL;R!L:6)A
+;<F-H:79E('1E<W0@<W5I=&4A"AUW5E$#!00
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_rar5_skip_block_extra_bytes.rar.uu b/contrib/libarchive/libarchive/test/test_read_format_rar5_skip_block_extra_bytes.rar.uu
new file mode 100644
index 000000000000..1b60edd9988e
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_rar5_skip_block_extra_bytes.rar.uu
@@ -0,0 +1,6 @@
+begin 644 test_read_format_rar5_skip_block_extra_bytes.rar
+M4F%R(1H' 0 SDK7E"@$%!@ % 0& @ ",.6KS"A $ X, 9C+ (#
+M"YT !)T I(,"M$.@E8 0YH96QL;W=O<FQD+G1X= H#$WX.JUM6Z0X::&5L
+B;&\@;&EB87)C:&EV92!T97-T('-U:71E(0H==U91 P4$
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_rar5_unpacked_size_exceeds_declared.rar.uu b/contrib/libarchive/libarchive/test/test_read_format_rar5_unpacked_size_exceeds_declared.rar.uu
new file mode 100644
index 000000000000..df8db2169789
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_rar5_unpacked_size_exceeds_declared.rar.uu
@@ -0,0 +1,10 @@
+begin 644 test_read_format_rar5_unpacked_size_exceeds_declared.rar
+M4F%R(1H'`0!S'-%&"@$%+`8`!0$!@(``PJ.']B("`POG``3M`*2#`E0DF'B`
+M`P$$<V5E9`H#$V0JGU[VYTHYP?]D-50S+Y,[YA3P`1@)46%!68"P&$$H2)$8
+M,V_"7`<'!P<'!P<'!P<'!P<'!P<'!P<'!P<'!P<'!P<'!P<'!P<'!P<'!P<'
+M!P<0R!KGS?_Y1ZGJ/]5[V/WGQV3QS(RALJQ[H%.N$.-9EH-4R%#&),\=!'V$
+MXR:QWL0$Z0'%XQY*.<$4(I44Z>GIZ>GIZ>GIZ>GIZ>GIZ>GIZ>GIZ>GIZ>GI
+MZ>GIZ>GIZ>GIZ>GIZ>GIZ>GIZ>GIZ>GIZ>GIZ>GIZ>GIZ>GIZ>GIZ>GIZ>GI
+;Z>GIZ>G)%78/_6H4^?O2+65;@!UW5E$#!00`
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_read_format_rar_encryption.c b/contrib/libarchive/libarchive/test/test_read_format_rar_encryption.c
index 2355468be809..ae2d6141d17f 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_rar_encryption.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_rar_encryption.c
@@ -47,7 +47,7 @@ static void test_encrypted_rar_archive(const char *filename, int filenamesEncryp
/* We should only ever fail to read the data for "a.txt" and "c.txt" if they are encrypted */
/* NOTE: We'll never attempt this when filenames are encrypted, so we only check for solid here */
- expected_read_data_result = solid ? ARCHIVE_FATAL : expected_file_size;
+ expected_read_data_result = solid ? ARCHIVE_FAILED : expected_file_size;
extract_reference_file(filename);
assert((a = archive_read_new()) != NULL);
@@ -81,7 +81,7 @@ static void test_encrypted_rar_archive(const char *filename, int filenamesEncryp
assertEqualInt(ARCHIVE_FATAL, archive_read_data(a, buff, sizeof(buff)));
/* Additional attempts to read headers are futile */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
return;
}
@@ -96,7 +96,7 @@ static void test_encrypted_rar_archive(const char *filename, int filenamesEncryp
assertEqualInt(1, archive_entry_is_data_encrypted(ae));
assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));
assertEqualInt(1, archive_read_has_encrypted_entries(a));
- assertEqualIntA(a, ARCHIVE_FATAL, archive_read_data(a, buff, sizeof(buff)));
+ assertEqualIntA(a, ARCHIVE_FAILED, archive_read_data(a, buff, sizeof(buff)));
/* Read the header for "c.txt" */
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
@@ -120,13 +120,13 @@ static void test_encrypted_rar_archive(const char *filename, int filenamesEncryp
assertEqualInt(1, archive_entry_is_data_encrypted(ae));
assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));
assertEqualInt(1, archive_read_has_encrypted_entries(a));
- assertEqualIntA(a, ARCHIVE_FATAL, archive_read_data(a, buff, sizeof(buff)));
+ assertEqualIntA(a, ARCHIVE_FAILED, archive_read_data(a, buff, sizeof(buff)));
/* End of archive. */
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_rar_encryption_data.c b/contrib/libarchive/libarchive/test/test_read_format_rar_encryption_data.c
index 540546a8dd8a..6bfcadabe331 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_rar_encryption_data.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_rar_encryption_data.c
@@ -50,7 +50,7 @@ DEFINE_TEST(test_read_format_rar_encryption_data)
assertEqualInt(1, archive_entry_is_data_encrypted(ae));
assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));
assertEqualIntA(a, 1, archive_read_has_encrypted_entries(a));
- assertEqualInt(ARCHIVE_FATAL, archive_read_data(a, buff, sizeof(buff)));
+ assertEqualInt(ARCHIVE_FAILED, archive_read_data(a, buff, sizeof(buff)));
/* Verify encrypted file "bar.txt" */
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
@@ -60,7 +60,7 @@ DEFINE_TEST(test_read_format_rar_encryption_data)
assertEqualInt(1, archive_entry_is_data_encrypted(ae));
assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));
assertEqualIntA(a, 1, archive_read_has_encrypted_entries(a));
- assertEqualInt(ARCHIVE_FATAL, archive_read_data(a, buff, sizeof(buff)));
+ assertEqualInt(ARCHIVE_FAILED, archive_read_data(a, buff, sizeof(buff)));
assertEqualInt(2, archive_file_count(a));
@@ -72,7 +72,7 @@ DEFINE_TEST(test_read_format_rar_encryption_data)
assertEqualIntA(a, ARCHIVE_FORMAT_RAR, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_rar_encryption_header.c b/contrib/libarchive/libarchive/test/test_read_format_rar_encryption_header.c
index e54db5152383..17444a2e2b7c 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_rar_encryption_header.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_rar_encryption_header.c
@@ -65,6 +65,6 @@ DEFINE_TEST(test_read_format_rar_encryption_header)
assertEqualIntA(a, ARCHIVE_FORMAT_RAR, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_rar_encryption_partially.c b/contrib/libarchive/libarchive/test/test_read_format_rar_encryption_partially.c
index e68e78831b37..d117258169e5 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_rar_encryption_partially.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_rar_encryption_partially.c
@@ -51,7 +51,7 @@ DEFINE_TEST(test_read_format_rar_encryption_partially)
assertEqualInt(1, archive_entry_is_data_encrypted(ae));
assertEqualInt(0, archive_entry_is_metadata_encrypted(ae));
assertEqualIntA(a, 1, archive_read_has_encrypted_entries(a));
- assertEqualInt(ARCHIVE_FATAL, archive_read_data(a, buff, sizeof(buff)));
+ assertEqualInt(ARCHIVE_FAILED, archive_read_data(a, buff, sizeof(buff)));
/* Verify unencrypted file "bar.txt". */
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
@@ -73,6 +73,6 @@ DEFINE_TEST(test_read_format_rar_encryption_partially)
assertEqualIntA(a, ARCHIVE_FORMAT_RAR, archive_format(a));
/* Close the archive. */
- assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_rar_invalid1.c b/contrib/libarchive/libarchive/test/test_read_format_rar_invalid1.c
index cac58688ce21..c99201763d4e 100644
--- a/contrib/libarchive/libarchive/test/test_read_format_rar_invalid1.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_rar_invalid1.c
@@ -37,7 +37,7 @@ DEFINE_TEST(test_read_format_rar_invalid1)
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240));
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
- assertEqualIntA(a, ARCHIVE_FATAL, archive_read_data(a, buff, 99));
+ assertEqualIntA(a, ARCHIVE_FAILED, archive_read_data(a, buff, 99));
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
diff --git a/contrib/libarchive/libarchive/test/test_read_format_rar_newsub_rr_over_1m.rar.uu b/contrib/libarchive/libarchive/test/test_read_format_rar_newsub_rr_over_1m.rar.uu
new file mode 100644
index 000000000000..7df22b4d84aa
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_rar_newsub_rr_over_1m.rar.uu
@@ -0,0 +1,23307 @@
+begin 644 test_read_format_rar_newsub_rr_over_1m.rar
+M4F%R(1H' &^7<T #0 !^^WH P"( 0 0 $ $ " 4
+M, ( %)2
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M
+M